@@ -87,24 +87,6 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
87
87
88
88
/* ### CREATING THE METHOD CACHE ### */
89
89
90
- def addStaticVariableToClass (forName : TermName , forType : Type , forInit : Tree , isFinal : Boolean ): Symbol = {
91
- val flags = PRIVATE | STATIC | SYNTHETIC | (
92
- if (isFinal) FINAL else 0
93
- )
94
-
95
- val varSym = currentClass.newVariable(mkTerm(" " + forName), ad.pos, flags.toLong) setInfoAndEnter forType
96
- if (! isFinal)
97
- varSym.addAnnotation(VolatileAttr )
98
-
99
- val varDef = typedPos(ValDef (varSym, forInit))
100
- newStaticMembers append transform(varDef)
101
-
102
- val varInit = typedPos( REF (varSym) === forInit )
103
- newStaticInits append transform(varInit)
104
-
105
- varSym
106
- }
107
-
108
90
def addStaticMethodToClass (forBody : (Symbol , Symbol ) => Tree ): Symbol = {
109
91
val methSym = currentClass.newMethod(mkTerm(nme.reflMethodName.toString), ad.pos, STATIC | SYNTHETIC )
110
92
val params = methSym.newSyntheticValueParams(List (ClassClass .tpe))
@@ -115,9 +97,6 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
115
97
methSym
116
98
}
117
99
118
- def fromTypesToClassArrayLiteral (paramTypes : List [Type ]): Tree =
119
- ArrayValue (TypeTree (ClassClass .tpe), paramTypes map LIT )
120
-
121
100
def reflectiveMethodCache (method : String , paramTypes : List [Type ]): Symbol = {
122
101
/* Implementation of the cache is as follows for method "def xyz(a: A, b: B)"
123
102
(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 {
128
107
var reflPoly$Cache: SoftReference[scala.runtime.MethodCache] = new SoftReference(new EmptyMethodCache())
129
108
130
109
def reflMethod$Method(forReceiver: JClass[_]): JMethod = {
131
- var methodCache: MethodCache = reflPoly$Cache.find(forReceiver)
110
+ var methodCache: StructuralCallSite = indy[StructuralCallSite.bootstrap, "(LA;LB;)Ljava/lang/Object;]
132
111
if (methodCache eq null) {
133
112
methodCache = new EmptyMethodCache
134
113
reflPoly$Cache = new SoftReference(methodCache)
@@ -137,41 +116,32 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
137
116
if (method ne null)
138
117
return method
139
118
else {
140
- method = ScalaRunTime.ensureAccessible(forReceiver.getMethod("xyz", reflParams$Cache ))
141
- reflPoly$Cache = new SoftReference( methodCache.add(forReceiver, method) )
119
+ method = ScalaRunTime.ensureAccessible(forReceiver.getMethod("xyz", methodCache.parameterTypes() ))
120
+ methodCache.add(forReceiver, method)
142
121
return method
143
122
}
144
123
}
145
- */
146
-
147
- val reflParamsCacheSym : Symbol =
148
- addStaticVariableToClass(nme.reflParamsCacheName, arrayType(ClassClass .tpe), fromTypesToClassArrayLiteral(paramTypes), true )
149
-
150
- def mkNewPolyCache = gen.mkSoftRef(NEW (TypeTree (EmptyMethodCacheClass .tpe)))
151
- val reflPolyCacheSym : Symbol = addStaticVariableToClass(nme.reflPolyCacheName, SoftReferenceClass .tpe, mkNewPolyCache, false )
152
124
153
- def getPolyCache = gen.mkCast(fn(REF (reflPolyCacheSym), nme.get), MethodCacheClass .tpe)
125
+ invokedynamic is used rather than a static field for the cache to support emitting bodies of methods
126
+ in Java 8 interfaces, which don't support static fields.
127
+ */
154
128
155
129
addStaticMethodToClass((reflMethodSym, forReceiverSym) => {
156
- val methodCache = reflMethodSym.newVariable(mkTerm(" methodCache" ), ad.pos) setInfo MethodCacheClass .tpe
130
+ val methodCache = reflMethodSym.newVariable(mkTerm(" methodCache" ), ad.pos) setInfo StructuralCallSite .tpe
157
131
val methodSym = reflMethodSym.newVariable(mkTerm(" method" ), ad.pos) setInfo MethodClass .tpe
158
132
133
+ val dummyMethodType = MethodType (NoSymbol .newSyntheticValueParams(paramTypes), AnyTpe )
159
134
BLOCK (
160
- ValDef (methodCache, getPolyCache),
161
- IF (REF (methodCache) OBJ_EQ NULL ) THEN BLOCK (
162
- REF (methodCache) === NEW (TypeTree (EmptyMethodCacheClass .tpe)),
163
- REF (reflPolyCacheSym) === gen.mkSoftRef(REF (methodCache))
164
- ) ENDIF ,
165
-
166
- ValDef (methodSym, (REF (methodCache) DOT methodCache_find)(REF (forReceiverSym))),
135
+ ValDef (methodCache, ApplyDynamic (gen.mkAttributedIdent(MethodCacheIndy ), LIT (dummyMethodType) :: Nil ).setType(StructuralCallSite .tpe)),
136
+ ValDef (methodSym, (REF (methodCache) DOT StructuralCallSite_find )(REF (forReceiverSym))),
167
137
IF (REF (methodSym) OBJ_NE NULL ) .
168
138
THEN (Return (REF (methodSym)))
169
139
ELSE {
170
- def methodSymRHS = ((REF (forReceiverSym) DOT Class_getMethod )(LIT (method), REF (reflParamsCacheSym )))
171
- def cacheRHS = ((REF (methodCache) DOT methodCache_add )(REF (forReceiverSym), REF (methodSym)))
140
+ def methodSymRHS = ((REF (forReceiverSym) DOT Class_getMethod )(LIT (method), ( REF (methodCache) DOT StructuralCallSite_getParameterTypes )( )))
141
+ def cacheAdd = ((REF (methodCache) DOT StructuralCallSite_add )(REF (forReceiverSym), REF (methodSym)))
172
142
BLOCK (
173
143
REF (methodSym) === (REF (currentRun.runDefinitions.ensureAccessibleMethod) APPLY (methodSymRHS)),
174
- REF (reflPolyCacheSym) === gen.mkSoftRef(cacheRHS) ,
144
+ cacheAdd ,
175
145
Return (REF (methodSym))
176
146
)
177
147
}
@@ -371,6 +341,8 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
371
341
reporter.error(ad.pos, " Cannot resolve overload." )
372
342
(Nil , NoType )
373
343
}
344
+ case NoType =>
345
+ abort(ad.symbol.toString)
374
346
}
375
347
typedPos {
376
348
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 {
448
420
* refinement, where the refinement defines a parameter based on a
449
421
* type variable. */
450
422
451
- case tree : ApplyDynamic =>
423
+ case tree : ApplyDynamic if tree.symbol.owner.isRefinementClass =>
452
424
transformApplyDynamic(tree)
453
425
454
426
/* Some cleanup transformations add members to templates (classes, traits, etc).
@@ -478,62 +450,23 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
478
450
479
451
/*
480
452
* This transformation should identify Scala symbol invocations in the tree and replace them
481
- * with references to a static member. Also, whenever a class has at least a single symbol invocation
482
- * somewhere in its methods, a new static member should be created and initialized for that symbol.
483
- * For instance, say we have a Scala class:
484
- *
485
- * class Cls {
486
- * def someSymbol1 = 'Symbolic1
487
- * def someSymbol2 = 'Symbolic2
488
- * def sameSymbol1 = 'Symbolic1
489
- * val someSymbol3 = 'Symbolic3
490
- * }
491
- *
492
- * After transformation, this class looks like this:
493
- *
494
- * class Cls {
495
- * private <static> var symbol$1: scala.Symbol
496
- * private <static> var symbol$2: scala.Symbol
497
- * private <static> var symbol$3: scala.Symbol
498
- * private val someSymbol3: scala.Symbol
499
- *
500
- * private <static> def <clinit> = {
501
- * symbol$1 = Symbol.apply("Symbolic1")
502
- * symbol$2 = Symbol.apply("Symbolic2")
503
- * }
504
- *
505
- * private def <init> = {
506
- * someSymbol3 = symbol$3
507
- * }
508
- *
509
- * def someSymbol1 = symbol$1
510
- * def someSymbol2 = symbol$2
511
- * def sameSymbol1 = symbol$1
512
- * val someSymbol3 = someSymbol3
513
- * }
453
+ * with references to a statically cached instance.
514
454
*
515
455
* The reasoning behind this transformation is the following. Symbols get interned - they are stored
516
456
* in a global map which is protected with a lock. The reason for this is making equality checks
517
457
* quicker. But calling Symbol.apply, although it does return a unique symbol, accesses a locked object,
518
458
* making symbol access slow. To solve this, the unique symbol from the global symbol map in Symbol
519
- * is accessed only once during class loading, and after that, the unique symbol is in the static
520
- * member. Hence, it is cheap to both reach the unique symbol and do equality checks on it.
459
+ * is accessed only once during class loading, and after that, the unique symbol is in the statically
460
+ * initialized call site returned by invokedynamic. Hence, it is cheap to both reach the unique symbol
461
+ * and do equality checks on it.
521
462
*
522
463
* And, finally, be advised - Scala's Symbol literal (scala.Symbol) and the Symbol class of the compiler
523
464
* have little in common.
524
465
*/
525
466
case Apply (fn @ Select (qual, _), (arg @ Literal (Constant (symname : String ))) :: Nil )
526
467
if treeInfo.isQualifierSafeToElide(qual) && fn.symbol == Symbol_apply && ! currentClass.isTrait =>
527
468
528
- def transformApply = {
529
- // add the symbol name to a map if it's not there already
530
- val rhs = gen.mkMethodCall(Symbol_apply , arg :: Nil )
531
- val staticFieldSym = getSymbolStaticField(tree.pos, symname, rhs, tree)
532
- // create a reference to a static field
533
- val ntree = typedWithPos(tree.pos)(REF (staticFieldSym))
534
- super .transform(ntree)
535
- }
536
- transformApply
469
+ super .transform(treeCopy.ApplyDynamic (tree, fn, arg :: Nil ))
537
470
538
471
// Replaces `Array(Predef.wrapArray(ArrayValue(...).$asInstanceOf[...]), <tag>)`
539
472
// with just `ArrayValue(...).$asInstanceOf[...]`
@@ -550,32 +483,6 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
550
483
super .transform(tree)
551
484
}
552
485
553
- /* Returns the symbol and the tree for the symbol field interning a reference to a symbol 'synmname'.
554
- * If it doesn't exist, i.e. the symbol is encountered the first time,
555
- * it creates a new static field definition and initialization and returns it.
556
- */
557
- private def getSymbolStaticField (pos : Position , symname : String , rhs : Tree , tree : Tree ): Symbol = {
558
- symbolsStoredAsStatic.getOrElseUpdate(symname, {
559
- val theTyper = typer.atOwner(tree, currentClass)
560
-
561
- // create a symbol for the static field
562
- val stfieldSym = (
563
- currentClass.newVariable(mkTerm(" symbol$" ), pos, PRIVATE | STATIC | SYNTHETIC | FINAL )
564
- setInfoAndEnter SymbolClass .tpe
565
- )
566
-
567
- // create field definition and initialization
568
- val stfieldDef = theTyper.typedPos(pos)(ValDef (stfieldSym, rhs))
569
- val stfieldInit = theTyper.typedPos(pos)(REF (stfieldSym) === rhs)
570
-
571
- // add field definition to new defs
572
- newStaticMembers append stfieldDef
573
- newStaticInits append stfieldInit
574
-
575
- stfieldSym
576
- })
577
- }
578
-
579
486
} // CleanUpTransformer
580
487
581
488
}
0 commit comments