diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/CleanUp.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/CleanUp.scala | 135 |
1 files changed, 21 insertions, 114 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index 1d98b5da31..112dedce81 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -87,24 +87,6 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { /* ### CREATING THE METHOD CACHE ### */ - def addStaticVariableToClass(forName: TermName, forType: Type, forInit: Tree, isFinal: Boolean): Symbol = { - val flags = PRIVATE | STATIC | SYNTHETIC | ( - if (isFinal) FINAL else 0 - ) - - val varSym = currentClass.newVariable(mkTerm("" + forName), ad.pos, flags.toLong) setInfoAndEnter forType - if (!isFinal) - varSym.addAnnotation(VolatileAttr) - - val varDef = typedPos(ValDef(varSym, forInit)) - newStaticMembers append transform(varDef) - - val varInit = typedPos( REF(varSym) === forInit ) - newStaticInits append transform(varInit) - - varSym - } - def addStaticMethodToClass(forBody: (Symbol, Symbol) => Tree): Symbol = { val methSym = currentClass.newMethod(mkTerm(nme.reflMethodName.toString), ad.pos, STATIC | SYNTHETIC) val params = methSym.newSyntheticValueParams(List(ClassClass.tpe)) @@ -115,9 +97,6 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { methSym } - def fromTypesToClassArrayLiteral(paramTypes: List[Type]): Tree = - ArrayValue(TypeTree(ClassClass.tpe), paramTypes map LIT) - def reflectiveMethodCache(method: String, paramTypes: List[Type]): Symbol = { /* Implementation of the cache is as follows for method "def xyz(a: A, b: B)" (SoftReference so that it does not interfere with classloader garbage collection, @@ -128,7 +107,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { var reflPoly$Cache: SoftReference[scala.runtime.MethodCache] = new SoftReference(new EmptyMethodCache()) def reflMethod$Method(forReceiver: JClass[_]): JMethod = { - var methodCache: MethodCache = reflPoly$Cache.find(forReceiver) + var methodCache: StructuralCallSite = indy[StructuralCallSite.bootstrap, "(LA;LB;)Ljava/lang/Object;] if (methodCache eq null) { methodCache = new EmptyMethodCache reflPoly$Cache = new SoftReference(methodCache) @@ -137,41 +116,32 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { if (method ne null) return method else { - method = ScalaRunTime.ensureAccessible(forReceiver.getMethod("xyz", reflParams$Cache)) - reflPoly$Cache = new SoftReference(methodCache.add(forReceiver, method)) + method = ScalaRunTime.ensureAccessible(forReceiver.getMethod("xyz", methodCache.parameterTypes())) + methodCache.add(forReceiver, method) return method } } - */ - - val reflParamsCacheSym: Symbol = - addStaticVariableToClass(nme.reflParamsCacheName, arrayType(ClassClass.tpe), fromTypesToClassArrayLiteral(paramTypes), true) - - def mkNewPolyCache = gen.mkSoftRef(NEW(TypeTree(EmptyMethodCacheClass.tpe))) - val reflPolyCacheSym: Symbol = addStaticVariableToClass(nme.reflPolyCacheName, SoftReferenceClass.tpe, mkNewPolyCache, false) - def getPolyCache = gen.mkCast(fn(REF(reflPolyCacheSym), nme.get), MethodCacheClass.tpe) + invokedynamic is used rather than a static field for the cache to support emitting bodies of methods + in Java 8 interfaces, which don't support private static fields. + */ addStaticMethodToClass((reflMethodSym, forReceiverSym) => { - val methodCache = reflMethodSym.newVariable(mkTerm("methodCache"), ad.pos) setInfo MethodCacheClass.tpe + val methodCache = reflMethodSym.newVariable(mkTerm("methodCache"), ad.pos) setInfo StructuralCallSite.tpe val methodSym = reflMethodSym.newVariable(mkTerm("method"), ad.pos) setInfo MethodClass.tpe + val dummyMethodType = MethodType(NoSymbol.newSyntheticValueParams(paramTypes), AnyTpe) BLOCK( - ValDef(methodCache, getPolyCache), - IF (REF(methodCache) OBJ_EQ NULL) THEN BLOCK( - REF(methodCache) === NEW(TypeTree(EmptyMethodCacheClass.tpe)), - REF(reflPolyCacheSym) === gen.mkSoftRef(REF(methodCache)) - ) ENDIF, - - ValDef(methodSym, (REF(methodCache) DOT methodCache_find)(REF(forReceiverSym))), + ValDef(methodCache, ApplyDynamic(gen.mkAttributedIdent(StructuralCallSite_dummy), LIT(StructuralCallSite_bootstrap) :: LIT(dummyMethodType) :: Nil).setType(StructuralCallSite.tpe)), + ValDef(methodSym, (REF(methodCache) DOT StructuralCallSite_find)(REF(forReceiverSym))), IF (REF(methodSym) OBJ_NE NULL) . THEN (Return(REF(methodSym))) ELSE { - def methodSymRHS = ((REF(forReceiverSym) DOT Class_getMethod)(LIT(method), REF(reflParamsCacheSym))) - def cacheRHS = ((REF(methodCache) DOT methodCache_add)(REF(forReceiverSym), REF(methodSym))) + def methodSymRHS = ((REF(forReceiverSym) DOT Class_getMethod)(LIT(method), (REF(methodCache) DOT StructuralCallSite_getParameterTypes)())) + def cacheAdd = ((REF(methodCache) DOT StructuralCallSite_add)(REF(forReceiverSym), REF(methodSym))) BLOCK( REF(methodSym) === (REF(currentRun.runDefinitions.ensureAccessibleMethod) APPLY (methodSymRHS)), - REF(reflPolyCacheSym) === gen.mkSoftRef(cacheRHS), + cacheAdd, Return(REF(methodSym)) ) } @@ -371,6 +341,8 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { reporter.error(ad.pos, "Cannot resolve overload.") (Nil, NoType) } + case NoType => + abort(ad.symbol.toString) } typedPos { val sym = currentOwner.newValue(mkTerm("qual"), ad.pos) setInfo qual0.tpe @@ -448,7 +420,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { * refinement, where the refinement defines a parameter based on a * type variable. */ - case tree: ApplyDynamic => + case tree: ApplyDynamic if tree.symbol.owner.isRefinementClass => transformApplyDynamic(tree) /* Some cleanup transformations add members to templates (classes, traits, etc). @@ -478,46 +450,15 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { /* * This transformation should identify Scala symbol invocations in the tree and replace them - * with references to a static member. Also, whenever a class has at least a single symbol invocation - * somewhere in its methods, a new static member should be created and initialized for that symbol. - * For instance, say we have a Scala class: - * - * class Cls { - * def someSymbol1 = 'Symbolic1 - * def someSymbol2 = 'Symbolic2 - * def sameSymbol1 = 'Symbolic1 - * val someSymbol3 = 'Symbolic3 - * } - * - * After transformation, this class looks like this: - * - * class Cls { - * private <static> var symbol$1: scala.Symbol - * private <static> var symbol$2: scala.Symbol - * private <static> var symbol$3: scala.Symbol - * private val someSymbol3: scala.Symbol - * - * private <static> def <clinit> = { - * symbol$1 = Symbol.apply("Symbolic1") - * symbol$2 = Symbol.apply("Symbolic2") - * } - * - * private def <init> = { - * someSymbol3 = symbol$3 - * } - * - * def someSymbol1 = symbol$1 - * def someSymbol2 = symbol$2 - * def sameSymbol1 = symbol$1 - * val someSymbol3 = someSymbol3 - * } + * with references to a statically cached instance. * * The reasoning behind this transformation is the following. Symbols get interned - they are stored * in a global map which is protected with a lock. The reason for this is making equality checks * quicker. But calling Symbol.apply, although it does return a unique symbol, accesses a locked object, * making symbol access slow. To solve this, the unique symbol from the global symbol map in Symbol - * is accessed only once during class loading, and after that, the unique symbol is in the static - * member. Hence, it is cheap to both reach the unique symbol and do equality checks on it. + * is accessed only once during class loading, and after that, the unique symbol is in the statically + * initialized call site returned by invokedynamic. Hence, it is cheap to both reach the unique symbol + * and do equality checks on it. * * And, finally, be advised - Scala's Symbol literal (scala.Symbol) and the Symbol class of the compiler * have little in common. @@ -525,15 +466,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { case Apply(fn @ Select(qual, _), (arg @ Literal(Constant(symname: String))) :: Nil) if treeInfo.isQualifierSafeToElide(qual) && fn.symbol == Symbol_apply && !currentClass.isTrait => - def transformApply = { - // add the symbol name to a map if it's not there already - val rhs = gen.mkMethodCall(Symbol_apply, arg :: Nil) - val staticFieldSym = getSymbolStaticField(tree.pos, symname, rhs, tree) - // create a reference to a static field - val ntree = typedWithPos(tree.pos)(REF(staticFieldSym)) - super.transform(ntree) - } - transformApply + super.transform(treeCopy.ApplyDynamic(tree, atPos(fn.pos)(Ident(SymbolLiteral_dummy).setType(SymbolLiteral_dummy.info)), LIT(SymbolLiteral_bootstrap) :: arg :: Nil)) // Replaces `Array(Predef.wrapArray(ArrayValue(...).$asInstanceOf[...]), <tag>)` // with just `ArrayValue(...).$asInstanceOf[...]` @@ -550,32 +483,6 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL { super.transform(tree) } - /* Returns the symbol and the tree for the symbol field interning a reference to a symbol 'synmname'. - * If it doesn't exist, i.e. the symbol is encountered the first time, - * it creates a new static field definition and initialization and returns it. - */ - private def getSymbolStaticField(pos: Position, symname: String, rhs: Tree, tree: Tree): Symbol = { - symbolsStoredAsStatic.getOrElseUpdate(symname, { - val theTyper = typer.atOwner(tree, currentClass) - - // create a symbol for the static field - val stfieldSym = ( - currentClass.newVariable(mkTerm("symbol$"), pos, PRIVATE | STATIC | SYNTHETIC | FINAL) - setInfoAndEnter SymbolClass.tpe - ) - - // create field definition and initialization - val stfieldDef = theTyper.typedPos(pos)(ValDef(stfieldSym, rhs)) - val stfieldInit = theTyper.typedPos(pos)(REF(stfieldSym) === rhs) - - // add field definition to new defs - newStaticMembers append stfieldDef - newStaticInits append stfieldInit - - stfieldSym - }) - } - } // CleanUpTransformer } |