@@ -47,15 +47,6 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
4747
4848 private var localTyper : analyzer.Typer = null
4949
50- private object MethodDispatchType extends scala.Enumeration {
51- val NO_CACHE, MONO_CACHE, POLY_CACHE = Value
52- }
53- import MethodDispatchType .{ NO_CACHE , MONO_CACHE , POLY_CACHE }
54- private def dispatchType () = settings.refinementMethodDispatch.value match {
55- case " no-cache" => NO_CACHE
56- case " mono-cache" => MONO_CACHE
57- case " poly-cache" => POLY_CACHE
58- }
5950 private def typedWithPos (pos : Position )(tree : Tree ) =
6051 localTyper.typedPos(pos)(tree)
6152
@@ -113,133 +104,65 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
113104 def fromTypesToClassArrayLiteral (paramTypes : List [Type ]): Tree =
114105 ArrayValue (TypeTree (ClassClass .tpe), paramTypes map LIT )
115106
116- /* ... */
117- def reflectiveMethodCache (method : String , paramTypes : List [Type ]): Symbol = dispatchType() match {
118- case NO_CACHE =>
119-
120- /* Implementation of the cache is as follows for method "def xyz(a: A, b: B)":
121-
122- var reflParams$Cache: Array[Class[_]] = Array[JClass](classOf[A], classOf[B])
123-
124- def reflMethod$Method(forReceiver: JClass[_]): JMethod =
125- forReceiver.getMethod("xyz", reflParams$Cache)
126-
127- */
128-
129- val reflParamsCacheSym : Symbol =
130- addStaticVariableToClass(nme.reflParamsCacheName, arrayType(ClassClass .tpe), fromTypesToClassArrayLiteral(paramTypes), true )
131-
132- addStaticMethodToClass((_, forReceiverSym) =>
133- gen.mkMethodCall(REF (forReceiverSym), Class_getMethod , Nil , List (LIT (method), REF (reflParamsCacheSym)))
134- )
135-
136- case MONO_CACHE =>
137-
138- /* Implementation of the cache is as follows for method "def xyz(a: A, b: B)"
139- (but with a SoftReference wrapping reflClass$Cache, similarly in the poly Cache) :
140-
141- var reflParams$Cache: Array[Class[_]] = Array[JClass](classOf[A], classOf[B])
142-
143- var reflMethod$Cache: JMethod = null
144-
145- var reflClass$Cache: JClass[_] = null
146-
147- def reflMethod$Method(forReceiver: JClass[_]): JMethod = {
148- if (reflClass$Cache != forReceiver) {
149- reflMethod$Cache = forReceiver.getMethod("xyz", reflParams$Cache)
150- reflClass$Cache = forReceiver
151- }
152- reflMethod$Cache
153- }
154-
155- */
156-
157- val reflParamsCacheSym : Symbol =
158- addStaticVariableToClass(nme.reflParamsCacheName, arrayType(ClassClass .tpe), fromTypesToClassArrayLiteral(paramTypes), true )
159-
160- val reflMethodCacheSym : Symbol =
161- addStaticVariableToClass(nme.reflMethodCacheName, MethodClass .tpe, NULL , false )
162-
163- val reflClassCacheSym : Symbol =
164- addStaticVariableToClass(nme.reflClassCacheName, SoftReferenceClass .tpe, NULL , false )
165-
166- def isCacheEmpty (receiver : Symbol ): Tree =
167- reflClassCacheSym.IS_NULL () OR (reflClassCacheSym.GET () OBJ_NE REF (receiver))
168-
169- addStaticMethodToClass((_, forReceiverSym) =>
170- BLOCK (
171- IF (isCacheEmpty(forReceiverSym)) THEN BLOCK (
172- REF (reflMethodCacheSym) === ((REF (forReceiverSym) DOT Class_getMethod )(LIT (method), REF (reflParamsCacheSym))) ,
173- REF (reflClassCacheSym) === gen.mkSoftRef(REF (forReceiverSym)),
174- UNIT
175- ) ENDIF ,
176- REF (reflMethodCacheSym)
177- )
178- )
179-
180- case POLY_CACHE =>
107+ def reflectiveMethodCache (method : String , paramTypes : List [Type ]): Symbol = {
108+ /* Implementation of the cache is as follows for method "def xyz(a: A, b: B)"
109+ (SoftReference so that it does not interfere with classloader garbage collection,
110+ see ticket #2365 for details):
181111
182- /* Implementation of the cache is as follows for method "def xyz(a: A, b: B)"
183- (SoftReference so that it does not interfere with classloader garbage collection, see ticket
184- #2365 for details):
112+ var reflParams$Cache: Array[Class[_]] = Array[JClass](classOf[A], classOf[B])
185113
186- var reflParams $Cache: Array[Class[_]] = Array[JClass](classOf[A], classOf[B] )
114+ var reflPoly $Cache: SoftReference[scala.runtime.MethodCache] = new SoftReference(new EmptyMethodCache() )
187115
188- var reflPoly$Cache: SoftReference[scala.runtime.MethodCache] = new SoftReference(new EmptyMethodCache())
116+ def reflMethod$Method(forReceiver: JClass[_]): JMethod = {
117+ var methodCache: MethodCache = reflPoly$Cache.find(forReceiver)
118+ if (methodCache eq null) {
119+ methodCache = new EmptyMethodCache
120+ reflPoly$Cache = new SoftReference(methodCache)
121+ }
122+ var method: JMethod = methodCache.find(forReceiver)
123+ if (method ne null)
124+ return method
125+ else {
126+ method = ScalaRunTime.ensureAccessible(forReceiver.getMethod("xyz", reflParams$Cache))
127+ reflPoly$Cache = new SoftReference(methodCache.add(forReceiver, method))
128+ return method
129+ }
130+ }
131+ */
189132
190- def reflMethod$Method(forReceiver: JClass[_]): JMethod = {
191- var methodCache: MethodCache = reflPoly$Cache.find(forReceiver)
192- if (methodCache eq null) {
193- methodCache = new EmptyMethodCache
194- reflPoly$Cache = new SoftReference(methodCache)
195- }
196- var method: JMethod = methodCache.find(forReceiver)
197- if (method ne null)
198- return method
199- else {
200- method = ScalaRunTime.ensureAccessible(forReceiver.getMethod("xyz", reflParams$Cache))
201- reflPoly$Cache = new SoftReference(methodCache.add(forReceiver, method))
202- return method
203- }
204- }
133+ val reflParamsCacheSym : Symbol =
134+ addStaticVariableToClass(nme.reflParamsCacheName, arrayType(ClassClass .tpe), fromTypesToClassArrayLiteral(paramTypes), true )
205135
206- */
136+ def mkNewPolyCache = gen.mkSoftRef(NEW (TypeTree (EmptyMethodCacheClass .tpe)))
137+ val reflPolyCacheSym : Symbol = addStaticVariableToClass(nme.reflPolyCacheName, SoftReferenceClass .tpe, mkNewPolyCache, false )
207138
208- val reflParamsCacheSym : Symbol =
209- addStaticVariableToClass(nme.reflParamsCacheName, arrayType(ClassClass .tpe), fromTypesToClassArrayLiteral(paramTypes), true )
139+ def getPolyCache = gen.mkCast(fn(REF (reflPolyCacheSym), nme.get), MethodCacheClass .tpe)
210140
211- def mkNewPolyCache = gen.mkSoftRef(NEW (TypeTree (EmptyMethodCacheClass .tpe)))
212- val reflPolyCacheSym : Symbol = (
213- addStaticVariableToClass(nme.reflPolyCacheName, SoftReferenceClass .tpe, mkNewPolyCache, false )
214- )
215- def getPolyCache = gen.mkCast(fn(REF (reflPolyCacheSym), nme.get), MethodCacheClass .tpe)
141+ addStaticMethodToClass((reflMethodSym, forReceiverSym) => {
142+ val methodCache = reflMethodSym.newVariable(mkTerm(" methodCache" ), ad.pos) setInfo MethodCacheClass .tpe
143+ val methodSym = reflMethodSym.newVariable(mkTerm(" method" ), ad.pos) setInfo MethodClass .tpe
216144
217- addStaticMethodToClass((reflMethodSym, forReceiverSym) => {
218- val methodCache = reflMethodSym.newVariable(mkTerm(" methodCache" ), ad.pos) setInfo MethodCacheClass .tpe
219- val methodSym = reflMethodSym.newVariable(mkTerm(" method" ), ad.pos) setInfo MethodClass .tpe
145+ BLOCK (
146+ VAL (methodCache) === getPolyCache,
147+ IF (REF (methodCache) OBJ_EQ NULL ) THEN BLOCK (
148+ REF (methodCache) === NEW (TypeTree (EmptyMethodCacheClass .tpe)),
149+ REF (reflPolyCacheSym) === gen.mkSoftRef(REF (methodCache))
150+ ) ENDIF ,
220151
152+ VAL (methodSym) === (REF (methodCache) DOT methodCache_find)(REF (forReceiverSym)),
153+ IF (REF (methodSym) OBJ_NE NULL ) .
154+ THEN (Return (REF (methodSym)))
155+ ELSE {
156+ def methodSymRHS = ((REF (forReceiverSym) DOT Class_getMethod )(LIT (method), REF (reflParamsCacheSym)))
157+ def cacheRHS = ((REF (methodCache) DOT methodCache_add)(REF (forReceiverSym), REF (methodSym)))
221158 BLOCK (
222- VAL (methodCache) === getPolyCache,
223- IF (REF (methodCache) OBJ_EQ NULL ) THEN BLOCK (
224- REF (methodCache) === NEW (TypeTree (EmptyMethodCacheClass .tpe)),
225- REF (reflPolyCacheSym) === gen.mkSoftRef(REF (methodCache))
226- ) ENDIF ,
227-
228- VAL (methodSym) === (REF (methodCache) DOT methodCache_find)(REF (forReceiverSym)),
229- IF (REF (methodSym) OBJ_NE NULL ) .
230- THEN (Return (REF (methodSym)))
231- ELSE {
232- def methodSymRHS = ((REF (forReceiverSym) DOT Class_getMethod )(LIT (method), REF (reflParamsCacheSym)))
233- def cacheRHS = ((REF (methodCache) DOT methodCache_add)(REF (forReceiverSym), REF (methodSym)))
234- BLOCK (
235- REF (methodSym) === (REF (ensureAccessibleMethod) APPLY (methodSymRHS)),
236- REF (reflPolyCacheSym) === gen.mkSoftRef(cacheRHS),
237- Return (REF (methodSym))
238- )
239- }
159+ REF (methodSym) === (REF (ensureAccessibleMethod) APPLY (methodSymRHS)),
160+ REF (reflPolyCacheSym) === gen.mkSoftRef(cacheRHS),
161+ Return (REF (methodSym))
240162 )
241- })
242-
163+ }
164+ )
165+ })
243166 }
244167
245168 /* ### HANDLING METHODS NORMALLY COMPILED TO OPERATORS ### */
@@ -394,99 +317,75 @@ abstract class CleanUp extends Transform with ast.TreeDSL {
394317 }
395318 }
396319
397- if (settings.refinementMethodDispatch.value == " invoke-dynamic" ) {
398- /* val guardCallSite: Tree = {
399- val cachedClass = addStaticVariableToClass("cachedClass", definitions.ClassClass.tpe, EmptyTree)
400- val tmpVar = currentOwner.newVariable(ad.pos, unit.freshTermName(ad.pos, "x")).setInfo(definitions.AnyRefClass.tpe)
401- atPos(ad.pos)(Block(List(
402- ValDef(tmpVar, transform(qual))),
403- If(Apply(Select(gen.mkAttributedRef(cachedClass), nme.EQ), List(getClass(Ident(tmpVar)))),
404- Block(List(Assign(gen.mkAttributedRef(cachedClass), getClass(Ident(tmpVar)))),
405- treeCopy.ApplyDynamic(ad, Ident(tmpVar), transformTrees(params))),
406- EmptyTree)))
407- }
408- //println(guardCallSite)
409- */
410- localTyper.typed(treeCopy.ApplyDynamic (ad, transform(qual), transformTrees(params)))
411- }
412- else {
413-
414- /* ### BODY OF THE TRANSFORMATION -> remember we're in case ad@ApplyDynamic(qual, params) ### */
415-
416- /* This creates the tree that does the reflective call (see general comment
417- * on the apply-dynamic tree for its format). This tree is simply composed
418- * of three successive calls, first to getClass on the callee, then to
419- * getMethod on the class, then to invoke on the method.
420- * - getMethod needs an array of classes for choosing one amongst many
421- * overloaded versions of the method. This is provided by paramTypeClasses
422- * and must be done on the static type as Scala's dispatching is static on
423- * the parameters.
424- * - invoke needs an array of AnyRefs that are the method's arguments. The
425- * erasure phase guarantees that any parameter passed to a dynamic apply
426- * is compatible (through boxing). Boxed ints et al. is what invoke expects
427- * when the applied method expects ints, hence no change needed there.
428- * - in the end, the result of invoke must be fixed, again to deal with arrays.
429- * This is provided by fixResult. fixResult will cast the invocation's result
430- * to the method's return type, which is generally ok, except when this type
431- * is a value type (int et al.) in which case it must cast to the boxed version
432- * because invoke only returns object and erasure made sure the result is
433- * expected to be an AnyRef. */
434- val t : Tree = {
435- val (mparams, resType) = ad.symbol.tpe match {
436- case MethodType (mparams, resType) =>
437- assert(params.length == mparams.length, ((params, mparams)))
438- (mparams, resType)
439- case tpe @ OverloadedType (pre, alts) =>
440- unit.warning(ad.pos, s " Overloaded type reached the backend! This is a bug in scalac. \n Symbol: ${ad.symbol}\n Overloads: $tpe\n Arguments: " + ad.args.map(_.tpe))
441- alts filter (_.paramss.flatten.size == params.length) map (_.tpe) match {
442- case mt @ MethodType (mparams, resType) :: Nil =>
443- unit.warning(NoPosition , " Only one overload has the right arity, proceeding with overload " + mt)
444- (mparams, resType)
445- case _ =>
446- unit.error(ad.pos, " Cannot resolve overload." )
447- (Nil , NoType )
448- }
449- }
450- typedPos {
451- val sym = currentOwner.newValue(mkTerm(" qual" ), ad.pos) setInfo qual0.tpe
452- qual = REF (sym)
453-
454- BLOCK (
455- VAL (sym) === qual0,
456- callAsReflective(mparams map (_.tpe), resType)
457- )
458- }
320+ {
321+
322+ /* ### BODY OF THE TRANSFORMATION -> remember we're in case ad@ApplyDynamic(qual, params) ### */
323+
324+ /* This creates the tree that does the reflective call (see general comment
325+ * on the apply-dynamic tree for its format). This tree is simply composed
326+ * of three successive calls, first to getClass on the callee, then to
327+ * getMethod on the class, then to invoke on the method.
328+ * - getMethod needs an array of classes for choosing one amongst many
329+ * overloaded versions of the method. This is provided by paramTypeClasses
330+ * and must be done on the static type as Scala's dispatching is static on
331+ * the parameters.
332+ * - invoke needs an array of AnyRefs that are the method's arguments. The
333+ * erasure phase guarantees that any parameter passed to a dynamic apply
334+ * is compatible (through boxing). Boxed ints et al. is what invoke expects
335+ * when the applied method expects ints, hence no change needed there.
336+ * - in the end, the result of invoke must be fixed, again to deal with arrays.
337+ * This is provided by fixResult. fixResult will cast the invocation's result
338+ * to the method's return type, which is generally ok, except when this type
339+ * is a value type (int et al.) in which case it must cast to the boxed version
340+ * because invoke only returns object and erasure made sure the result is
341+ * expected to be an AnyRef. */
342+ val t : Tree = {
343+ val (mparams, resType) = ad.symbol.tpe match {
344+ case MethodType (mparams, resType) =>
345+ assert(params.length == mparams.length, ((params, mparams)))
346+ (mparams, resType)
347+ case tpe @ OverloadedType (pre, alts) =>
348+ unit.warning(ad.pos, s " Overloaded type reached the backend! This is a bug in scalac. \n Symbol: ${ad.symbol}\n Overloads: $tpe\n Arguments: " + ad.args.map(_.tpe))
349+ alts filter (_.paramss.flatten.size == params.length) map (_.tpe) match {
350+ case mt @ MethodType (mparams, resType) :: Nil =>
351+ unit.warning(NoPosition , " Only one overload has the right arity, proceeding with overload " + mt)
352+ (mparams, resType)
353+ case _ =>
354+ unit.error(ad.pos, " Cannot resolve overload." )
355+ (Nil , NoType )
356+ }
459357 }
358+ typedPos {
359+ val sym = currentOwner.newValue(mkTerm(" qual" ), ad.pos) setInfo qual0.tpe
360+ qual = REF (sym)
460361
461- /* For testing purposes, the dynamic application's condition
462- * can be printed-out in great detail. Remove? */
463- if (settings.debug) {
464- def paramsToString (xs : Any * ) = xs map (_.toString) mkString " , "
465- val mstr = ad.symbol.tpe match {
466- case MethodType (mparams, resType) =>
467- """ | with
468- | - declared parameter types: '%s'
469- | - passed argument types: '%s'
470- | - result type: '%s'""" .
471- stripMargin.format(
472- paramsToString(mparams),
473- paramsToString(params),
474- resType.toString
475- )
476- case _ => " "
477- }
478- log(
479- """ Dynamically application '%s.%s(%s)' %s - resulting code: '%s'""" .format(
480- qual, ad.symbol.name, paramsToString(params), mstr, t
481- )
362+ BLOCK (
363+ VAL (sym) === qual0,
364+ callAsReflective(mparams map (_.tpe), resType)
482365 )
483366 }
367+ }
484368
485- /* We return the dynamic call tree, after making sure no other
486- * clean-up transformation are to be applied on it. */
487- transform(t)
369+ /* For testing purposes, the dynamic application's condition
370+ * can be printed-out in great detail. Remove? */
371+ if (settings.debug) {
372+ def paramsToString (xs : Any * ) = xs map (_.toString) mkString " , "
373+ val mstr = ad.symbol.tpe match {
374+ case MethodType (mparams, resType) =>
375+ sm """ | with
376+ | - declared parameter types: ' ${paramsToString(mparams)}'
377+ | - passed argument types: ' ${paramsToString(params)}'
378+ | - result type: ' ${resType.toString}' """
379+ case _ => " "
380+ }
381+ log(s """ Dynamically application ' $qual. ${ad.symbol.name}( ${paramsToString(params)})' $mstr - resulting code: ' $t' """ )
488382 }
489- /* ### END OF DYNAMIC APPLY TRANSFORM ### */
383+
384+ /* We return the dynamic call tree, after making sure no other
385+ * clean-up transformation are to be applied on it. */
386+ transform(t)
387+ /* ### END OF DYNAMIC APPLY TRANSFORM ### */
388+ }
490389 }
491390
492391 override def transform (tree : Tree ): Tree = tree match {
0 commit comments