diff options
author | Szabolcs Berecz <szabolcs.berecz@gmail.com> | 2012-01-29 01:24:28 +0100 |
---|---|---|
committer | Szabolcs Berecz <szabolcs.berecz@gmail.com> | 2012-02-16 21:36:58 +0100 |
commit | 01ee3de96dcae707fb8fee28e93af0515519c603 (patch) | |
tree | e4dcd0e7ba8ab1036abd92dbfaecc2cb9fa14175 | |
parent | b8b19b1ca1de01083cf0975226a34424bd729a5b (diff) | |
download | scala-01ee3de96dcae707fb8fee28e93af0515519c603.tar.gz scala-01ee3de96dcae707fb8fee28e93af0515519c603.tar.bz2 scala-01ee3de96dcae707fb8fee28e93af0515519c603.zip |
replace methods containing a synchronized body with synchronized methods
The following:
def f = synchronized { ... }
will be rewritten to:
<synchronized> def f = ...
which is then emitted to the classfile with the synchronized flag set.
Inlining of such transformed methods are disabled for now
This transformation is not done on methods defined in a trait.
-rw-r--r-- | src/compiler/scala/reflect/internal/Definitions.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/reflect/internal/Symbols.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/opt/Inliners.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/TailCalls.scala | 25 | ||||
-rw-r--r-- | src/library/scala/annotation/synchronized.scala | 15 | ||||
-rw-r--r-- | test/files/run/tailcalls.check | 1 | ||||
-rw-r--r-- | test/files/run/tailcalls.scala | 13 |
8 files changed, 56 insertions, 6 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index b4b0a7335d..485955c5c4 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -734,6 +734,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val ScalaStrictFPAttr = getRequiredClass("scala.annotation.strictfp") lazy val SerializableAttr = getRequiredClass("scala.annotation.serializable") // @serializable is deprecated lazy val SwitchClass = getRequiredClass("scala.annotation.switch") + lazy val SynchronizedAttr = getRequiredClass("scala.annotation.synchronized") lazy val TailrecClass = getRequiredClass("scala.annotation.tailrec") lazy val VarargsClass = getRequiredClass("scala.annotation.varargs") lazy val uncheckedStableClass = getRequiredClass("scala.annotation.unchecked.uncheckedStable") diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 77ed2f6a1b..25d6192e74 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -557,6 +557,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } def isStrictFP = hasAnnotation(ScalaStrictFPAttr) || (enclClass hasAnnotation ScalaStrictFPAttr) + def isSynchronized = hasAnnotation(SynchronizedAttr) def isSerializable = ( info.baseClasses.exists(p => p == SerializableClass || p == JavaSerializableClass) || hasAnnotation(SerializableAttr) // last part can be removed, @serializable annotation is deprecated diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index b5232fff09..9de0ec6610 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -859,6 +859,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with if (method.native) flags |= ACC_NATIVE + if (m.symbol.isSynchronized) + flags |= ACC_SYNCHRONIZED + jmethod = jclass.addNewMethod(flags, javaName(m.symbol), resTpe, diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 66f802f74f..4598141e8b 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -558,7 +558,7 @@ abstract class Inliners extends SubComponent { } def isStampedForInlining(stack: TypeStack) = - !sameSymbols && inc.m.hasCode && shouldInline && isSafeToInline(stack) + !sameSymbols && inc.m.hasCode && shouldInline && isSafeToInline(stack) && !inc.m.symbol.isSynchronized def logFailure(stack: TypeStack) = log( """|inline failed for %s: @@ -576,6 +576,7 @@ abstract class Inliners extends SubComponent { def failureReason(stack: TypeStack) = if (!inc.m.hasCode) "bytecode was unavailable" else if (!isSafeToInline(stack)) "it is unsafe (target may reference private fields)" + else if (inc.m.symbol.isSynchronized) "method is synchronized" else "of a bug (run with -Ylog:inline -Ydebug for more information)" def canAccess(level: NonPublicRefs.Value) = level match { diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index 1655ad09c4..97b9caaa73 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -173,6 +173,29 @@ abstract class TailCalls extends Transform { trees map (t => transform(t, nctx)) } + /** + * Transforms methods with synchronized body into synchronized methods + */ + private def transformSynchronizedMethods(tree: Tree): Tree = { + def isSelfSynchronized(body: Apply) = body.fun match { + case TypeApply(fun @ Select(This(_), _), List(TypeTree())) + if (fun.symbol == Object_synchronized && + fun.qualifier.symbol == tree.symbol.enclClass && + !tree.symbol.enclClass.isTrait) => true + case _ => false + } + + tree match { + case DefDef(mods, name, tparams, vparamss, tpt, rhs @ Apply(_, List(body))) + if (isSelfSynchronized(rhs)) => + val res = treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, body) + res.symbol withAnnotation AnnotationInfo(SynchronizedAttr.tpe, Nil, Nil) + res + case _ => + tree + } + } + override def transform(tree: Tree): Tree = { /** A possibly polymorphic apply to be considered for tail call transformation. */ @@ -222,7 +245,7 @@ abstract class TailCalls extends Transform { else rewriteTailCall(receiver) } - tree match { + transformSynchronizedMethods(tree) match { case dd @ DefDef(mods, name, tparams, vparams, tpt, rhs) => val newCtx = new Context(dd) diff --git a/src/library/scala/annotation/synchronized.scala b/src/library/scala/annotation/synchronized.scala new file mode 100644 index 0000000000..9470c7173c --- /dev/null +++ b/src/library/scala/annotation/synchronized.scala @@ -0,0 +1,15 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.annotation + +/** + * If this annotation is present on a method, the synchronized flag will be emitted. + * FIXME This should be internal to the compiler + */ +private[scala] class synchronized extends StaticAnnotation diff --git a/test/files/run/tailcalls.check b/test/files/run/tailcalls.check index 7670962db2..e3a70f46ae 100644 --- a/test/files/run/tailcalls.check +++ b/test/files/run/tailcalls.check @@ -43,6 +43,7 @@ test TailCall.g1 was successful test TailCall.g2 was successful test TailCall.g3 was successful test TailCall.h1 was successful +test TailCall.s1 was successful test NonTailCall.f1 0 1 2 was successful test NonTailCall.f2 was successful diff --git a/test/files/run/tailcalls.scala b/test/files/run/tailcalls.scala index 04a1a8ba19..4cf6dd46d3 100644 --- a/test/files/run/tailcalls.scala +++ b/test/files/run/tailcalls.scala @@ -182,6 +182,8 @@ class TailCall[S](s: S) { def h1(n: Int, v: Int): Int = hP(n, v); private def hP(n: Int, v: Int): Int = if (n == 0) v else hP(n - 1, v - 1); + final def s1(n: Int, v: Int): Int = synchronized { if (n == 0) v else s1(n - 1, v - 1) } + // !!! test return in non-tail-call position // !!! test non-same-instance calls // !!! test non-same-type calls @@ -229,11 +231,13 @@ class NonTailCall { Console.print(" " + n) } - final def f2(n: Int): Int = synchronized { - if (n == 0) 0 - else f2(n - 1) + final def f2(n: Int): Int = { + val next = n - 1 + synchronized { + if (n == 0) 0 + else f2(next) + } } - } //############################################################################ @@ -366,6 +370,7 @@ object Test { check_success("TailCall.g2", TailCall.g2(max, max ), 0) check_success("TailCall.g3", TailCall.g3(max, max, Nil), 0) check_success("TailCall.h1", TailCall.h1(max, max ), 0) + check_success("TailCall.s1", TailCall.s1(max, max ), 0) println val NonTailCall = new NonTailCall |