diff options
Diffstat (limited to 'src')
12 files changed, 211 insertions, 165 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 59d584c370..efa97b0d6f 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -310,6 +310,15 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { case app : Apply => generatedType = genApply(app, expectedType) + case app @ ApplyDynamic(qual, Literal(Constant(boostrapMethodRef: Symbol)) :: staticAndDynamicArgs) => + val numStaticArgs = boostrapMethodRef.paramss.head.size - 3 /*JVM provided args*/ + val (staticArgs, dynamicArgs) = staticAndDynamicArgs.splitAt(numStaticArgs) + val boostrapDescriptor = staticHandleFromSymbol(boostrapMethodRef) + val bootstrapArgs = staticArgs.map({case t @ Literal(c: Constant) => bootstrapMethodArg(c, t.pos)}) + val descriptor = methodBTypeFromMethodType(qual.symbol.info, false) + genLoadArguments(dynamicArgs, qual.symbol.info.params.map(param => typeToBType(param.info))) + mnode.visitInvokeDynamicInsn(qual.symbol.name.encoded, descriptor.descriptor, boostrapDescriptor, bootstrapArgs : _*) + case ApplyDynamic(qual, args) => sys.error("No invokedynamic support yet.") case This(qual) => @@ -1327,7 +1336,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { val samName = sam.name.toString val samMethodType = methodBTypeFromSymbol(sam).toASMType - val flags = LambdaMetafactory.FLAG_SERIALIZABLE | LambdaMetafactory.FLAG_MARKERS + val flags = java.lang.invoke.LambdaMetafactory.FLAG_SERIALIZABLE | java.lang.invoke.LambdaMetafactory.FLAG_MARKERS val ScalaSerializable = classBTypeFromSymbol(definitions.SerializableClass).toASMType bc.jmethod.visitInvokeDynamicInsn(samName, invokedType, lambdaMetaFactoryBootstrapHandle, @@ -1342,16 +1351,4 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { indyLambdaHosts += cnode.name } } - - lazy val lambdaMetaFactoryBootstrapHandle = - new asm.Handle(asm.Opcodes.H_INVOKESTATIC, - coreBTypes.jliLambdaMetafactoryRef.internalName, sn.AltMetafactory.toString, - MethodBType( - List( - coreBTypes.jliMethodHandlesLookupRef, - coreBTypes.StringRef, - coreBTypes.jliMethodTypeRef, - ArrayBType(ObjectRef)), - coreBTypes.jliCallSiteRef - ).descriptor) } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala index 9bfa7dae27..3c2ee89b05 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala @@ -130,10 +130,31 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes { */ final def methodBTypeFromSymbol(methodSymbol: Symbol): MethodBType = { assert(methodSymbol.isMethod, s"not a method-symbol: $methodSymbol") + methodBTypeFromMethodType(methodSymbol.info, methodSymbol.isClassConstructor || methodSymbol.isConstructor) + } + + /** + * Builds a [[MethodBType]] for a method type. + */ + final def methodBTypeFromMethodType(tpe: Type, isConstructor: Boolean): MethodBType = { val resultType: BType = - if (methodSymbol.isClassConstructor || methodSymbol.isConstructor) UNIT - else typeToBType(methodSymbol.tpe.resultType) - MethodBType(methodSymbol.tpe.paramTypes map typeToBType, resultType) + if (isConstructor) UNIT + else typeToBType(tpe.resultType) + MethodBType(tpe.paramTypes map typeToBType, resultType) + } + + def bootstrapMethodArg(t: Constant, pos: Position): AnyRef = t match { + case Constant(mt: Type) => methodBTypeFromMethodType(transformedType(mt), isConstructor = false).toASMType + case c @ Constant(sym: Symbol) => staticHandleFromSymbol(sym) + case c @ Constant(value: String) => value + case c @ Constant(value) if c.isNonUnitAnyVal => c.value.asInstanceOf[AnyRef] + case _ => reporter.error(pos, "Unable to convert static argument of ApplyDynamic into a classfile constant: " + t); null + } + + def staticHandleFromSymbol(sym: Symbol): asm.Handle = { + val owner = if (sym.owner.isModuleClass) sym.owner.linkedClassOfClass else sym.owner + val descriptor = methodBTypeFromMethodType(sym.info, isConstructor = false).descriptor + new asm.Handle(asm.Opcodes.H_INVOKESTATIC, classBTypeFromSymbol(owner).internalName, sym.name.encoded, descriptor) } /** diff --git a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala index 8bb71a386f..0e98bddeb1 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/CoreBTypes.scala @@ -1,6 +1,8 @@ package scala.tools.nsc package backend.jvm +import scala.annotation.switch +import scala.tools.asm import scala.tools.nsc.backend.jvm.BTypes.InternalName /** @@ -109,8 +111,10 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) { lazy val jliMethodTypeRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.MethodType]) lazy val jliCallSiteRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.CallSite]) lazy val jliLambdaMetafactoryRef : ClassBType = classBTypeFromSymbol(requiredClass[java.lang.invoke.LambdaMetafactory]) - lazy val srLambdaDeserializerRef : ClassBType = classBTypeFromSymbol(requiredModule[scala.runtime.LambdaDeserializer.type].moduleClass) lazy val srBoxesRunTimeRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxesRunTime]) + lazy val srSymbolLiteral : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.SymbolLiteral]) + lazy val srStructuralCallSite : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.StructuralCallSite]) + lazy val srLambdaDeserialize : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.LambdaDeserialize]) lazy val srBoxedUnitRef : ClassBType = classBTypeFromSymbol(requiredClass[scala.runtime.BoxedUnit]) private def methodNameAndType(cls: Symbol, name: Name, static: Boolean = false, filterOverload: Symbol => Boolean = _ => true): MethodNameAndType = { @@ -263,6 +267,30 @@ class CoreBTypes[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: BTFS) { case _ => false }) } + + lazy val lambdaMetaFactoryBootstrapHandle = + new asm.Handle(asm.Opcodes.H_INVOKESTATIC, + coreBTypes.jliLambdaMetafactoryRef.internalName, sn.AltMetafactory.toString, + MethodBType( + List( + coreBTypes.jliMethodHandlesLookupRef, + coreBTypes.StringRef, + coreBTypes.jliMethodTypeRef, + ArrayBType(ObjectRef)), + coreBTypes.jliCallSiteRef + ).descriptor) + + lazy val lambdaDeserializeBootstrapHandle = + new scala.tools.asm.Handle(scala.tools.asm.Opcodes.H_INVOKESTATIC, + coreBTypes.srLambdaDeserialize.internalName, sn.Bootstrap.toString, + MethodBType( + List( + coreBTypes.jliMethodHandlesLookupRef, + coreBTypes.StringRef, + coreBTypes.jliMethodTypeRef + ), + coreBTypes.jliCallSiteRef + ).descriptor) } /** @@ -290,10 +318,10 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] { def jiSerializableRef : ClassBType def juHashMapRef : ClassBType def juMapRef : ClassBType + def jliCallSiteRef : ClassBType + def jliMethodTypeRef : ClassBType def jliSerializedLambdaRef : ClassBType - def jliMethodHandlesRef : ClassBType def jliMethodHandlesLookupRef : ClassBType - def srLambdaDeserializerRef : ClassBType def srBoxesRunTimeRef : ClassBType def srBoxedUnitRef : ClassBType @@ -314,6 +342,9 @@ trait CoreBTypesProxyGlobalIndependent[BTS <: BTypes] { def tupleClassConstructors : Map[InternalName, MethodNameAndType] def srJFunctionRefs: Set[InternalName] + + def lambdaMetaFactoryBootstrapHandle : asm.Handle + def lambdaDeserializeBootstrapHandle : asm.Handle } /** @@ -356,7 +387,6 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: def jliMethodTypeRef : ClassBType = _coreBTypes.jliMethodTypeRef def jliCallSiteRef : ClassBType = _coreBTypes.jliCallSiteRef def jliLambdaMetafactoryRef : ClassBType = _coreBTypes.jliLambdaMetafactoryRef - def srLambdaDeserializerRef : ClassBType = _coreBTypes.srLambdaDeserializerRef def srBoxesRunTimeRef : ClassBType = _coreBTypes.srBoxesRunTimeRef def srBoxedUnitRef : ClassBType = _coreBTypes.srBoxedUnitRef @@ -378,6 +408,10 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: def srJFunctionRefs: Set[InternalName] = _coreBTypes.srJFunctionRefs + def srSymbolLiteral : ClassBType = _coreBTypes.srSymbolLiteral + def srStructuralCallSite : ClassBType = _coreBTypes.srStructuralCallSite + def srLambdaDeserialize : ClassBType = _coreBTypes.srLambdaDeserialize + def typeOfArrayOp: Map[Int, BType] = _coreBTypes.typeOfArrayOp // Some symbols. These references should probably be moved to Definitions. @@ -390,4 +424,7 @@ final class CoreBTypesProxy[BTFS <: BTypesFromSymbols[_ <: Global]](val bTypes: def BeanInfoAttr: Symbol = _coreBTypes.BeanInfoAttr def String_valueOf: Symbol = _coreBTypes.String_valueOf + + def lambdaMetaFactoryBootstrapHandle = _coreBTypes.lambdaMetaFactoryBootstrapHandle + def lambdaDeserializeBootstrapHandle = _coreBTypes.lambdaDeserializeBootstrapHandle } diff --git a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala index e8630c65d9..0d6ef93a26 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala @@ -64,15 +64,13 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { /** * Add: - * private static java.util.Map $deserializeLambdaCache$ = null * private static Object $deserializeLambda$(SerializedLambda l) { - * var cache = $deserializeLambdaCache$ - * if (cache eq null) { - * cache = new java.util.HashMap() - * $deserializeLambdaCache$ = cache - * } - * return scala.runtime.LambdaDeserializer.deserializeLambda(MethodHandles.lookup(), cache, l); + * return indy[scala.runtime.LambdaDeserialize.bootstrap](l) * } + * + * We use invokedynamic here to enable caching within the deserializer without needing to + * host a static field in the enclosing class. This allows us to add this method to interfaces + * that define lambdas in default methods. */ def addLambdaDeserialize(classNode: ClassNode): Unit = { val cw = classNode @@ -83,37 +81,14 @@ class BackendUtils[BT <: BTypes](val btypes: BT) { // stack map frames and invokes the `getCommonSuperClass` method. This method expects all // ClassBTypes mentioned in the source code to exist in the map. - val mapDesc = juMapRef.descriptor val nilLookupDesc = MethodBType(Nil, jliMethodHandlesLookupRef).descriptor val serlamObjDesc = MethodBType(jliSerializedLambdaRef :: Nil, ObjectRef).descriptor - val lookupMapSerlamObjDesc = MethodBType(jliMethodHandlesLookupRef :: juMapRef :: jliSerializedLambdaRef :: Nil, ObjectRef).descriptor - - { - val fv = cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambdaCache$", mapDesc, null, null) - fv.visitEnd() - } { val mv = cw.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$deserializeLambda$", serlamObjDesc, null, null) mv.visitCode() - // javaBinaryName returns the internal name of a class. Also used in BTypesFromsymbols.classBTypeFromSymbol. - mv.visitFieldInsn(GETSTATIC, classNode.name, "$deserializeLambdaCache$", mapDesc) - mv.visitVarInsn(ASTORE, 1) - mv.visitVarInsn(ALOAD, 1) - val l0 = new Label() - mv.visitJumpInsn(IFNONNULL, l0) - mv.visitTypeInsn(NEW, juHashMapRef.internalName) - mv.visitInsn(DUP) - mv.visitMethodInsn(INVOKESPECIAL, juHashMapRef.internalName, "<init>", "()V", false) - mv.visitVarInsn(ASTORE, 1) - mv.visitVarInsn(ALOAD, 1) - mv.visitFieldInsn(PUTSTATIC, classNode.name, "$deserializeLambdaCache$", mapDesc) - mv.visitLabel(l0) - mv.visitFieldInsn(GETSTATIC, srLambdaDeserializerRef.internalName, "MODULE$", srLambdaDeserializerRef.descriptor) - mv.visitMethodInsn(INVOKESTATIC, jliMethodHandlesRef.internalName, "lookup", nilLookupDesc, false) - mv.visitVarInsn(ALOAD, 1) mv.visitVarInsn(ALOAD, 0) - mv.visitMethodInsn(INVOKEVIRTUAL, srLambdaDeserializerRef.internalName, "deserializeLambda", lookupMapSerlamObjDesc, false) + mv.visitInvokeDynamicInsn("lambdaDeserialize", serlamObjDesc, lambdaDeserializeBootstrapHandle) mv.visitInsn(ARETURN) mv.visitEnd() } 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 } diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 266a422c53..0e44751a3f 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -1150,6 +1150,8 @@ abstract class Erasure extends AddInterfaces case DefDef(_, _, _, _, tpt, _) => try super.transform(tree1).clearType() finally tpt setType specialErasure(tree1.symbol)(tree1.symbol.tpe).resultType + case ApplyDynamic(qual, Literal(Constant(boostrapMethodRef: Symbol)) :: _) => + tree case _ => super.transform(tree1).clearType() } diff --git a/src/library/scala/runtime/LambdaDeserialize.java b/src/library/scala/runtime/LambdaDeserialize.java new file mode 100644 index 0000000000..e239debf25 --- /dev/null +++ b/src/library/scala/runtime/LambdaDeserialize.java @@ -0,0 +1,29 @@ +package scala.runtime; + + +import java.lang.invoke.*; +import java.util.Arrays; +import java.util.HashMap; + +public final class LambdaDeserialize { + + private MethodHandles.Lookup lookup; + private final HashMap<String, MethodHandle> cache = new HashMap<>(); + private final LambdaDeserializer$ l = LambdaDeserializer$.MODULE$; + + private LambdaDeserialize(MethodHandles.Lookup lookup) { + this.lookup = lookup; + } + + public Object deserializeLambda(SerializedLambda serialized) { + return l.deserializeLambda(lookup, cache, serialized); + } + + public static CallSite bootstrap(MethodHandles.Lookup lookup, String invokedName, + MethodType invokedType) throws Throwable { + MethodType type = MethodType.fromMethodDescriptorString("(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object;", lookup.getClass().getClassLoader()); + MethodHandle deserializeLambda = lookup.findVirtual(LambdaDeserialize.class, "deserializeLambda", type); + MethodHandle exact = deserializeLambda.bindTo(new LambdaDeserialize(lookup)).asType(invokedType); + return new ConstantCallSite(exact); + } +} diff --git a/src/library/scala/runtime/StructuralCallSite.java b/src/library/scala/runtime/StructuralCallSite.java new file mode 100644 index 0000000000..f73b4f08e6 --- /dev/null +++ b/src/library/scala/runtime/StructuralCallSite.java @@ -0,0 +1,43 @@ +package scala.runtime; + + +import java.lang.invoke.*; +import java.lang.ref.SoftReference; +import java.lang.reflect.Method; + +public final class StructuralCallSite { + + private Class<?>[] parameterTypes; + private SoftReference<MethodCache> cache = new SoftReference<>(new EmptyMethodCache()); + + private StructuralCallSite(MethodType callType) { + parameterTypes = callType.parameterArray(); + } + + public MethodCache get() { + MethodCache cache = this.cache.get(); + if (cache == null) { + cache = new EmptyMethodCache(); + this.cache = new SoftReference<>(cache); + } + return cache; + } + + public Method find(Class<?> receiver) { + return get().find(receiver); + } + + public Method add(Class<?> receiver, Method m) { + cache = new SoftReference<MethodCache>(get().add(receiver, m)); + return m; + } + public Class<?>[] parameterTypes() { + return parameterTypes; + } + + public static CallSite bootstrap(MethodHandles.Lookup lookup, String invokedName, + MethodType invokedType, MethodType reflectiveCallType) throws Throwable { + StructuralCallSite structuralCallSite = new StructuralCallSite(reflectiveCallType); + return new ConstantCallSite(MethodHandles.constant(StructuralCallSite.class, structuralCallSite)); + } +} diff --git a/src/library/scala/runtime/SymbolLiteral.java b/src/library/scala/runtime/SymbolLiteral.java new file mode 100644 index 0000000000..09a66c83d5 --- /dev/null +++ b/src/library/scala/runtime/SymbolLiteral.java @@ -0,0 +1,20 @@ +package scala.runtime; + +import java.lang.invoke.*; +import java.util.regex.Pattern; + +public final class SymbolLiteral { + private SymbolLiteral() { + } + + public static CallSite bootstrap(MethodHandles.Lookup lookup, String invokedName, + MethodType invokedType, + String value) throws Throwable { + ClassLoader classLoader = lookup.lookupClass().getClassLoader(); + MethodType type = MethodType.fromMethodDescriptorString("(Ljava/lang/Object;)Ljava/lang/Object;", classLoader); + Class<?> symbolClass = Class.forName("scala.Symbol", false, classLoader); + MethodHandle factoryMethod = lookup.findStatic(symbolClass, "apply", type); + Object symbolValue = factoryMethod.invokeWithArguments(value); + return new ConstantCallSite(MethodHandles.constant(symbolClass, symbolValue)); + } +} diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index ba6c363918..6b015df6b4 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -459,6 +459,16 @@ trait Definitions extends api.StandardDefinitions { lazy val MethodCacheClass = requiredClass[scala.runtime.MethodCache] def methodCache_find = getMemberMethod(MethodCacheClass, nme.find_) def methodCache_add = getMemberMethod(MethodCacheClass, nme.add_) + lazy val StructuralCallSite = getClassIfDefined("scala.runtime.StructuralCallSite") + def StructuralCallSite_bootstrap = getMemberMethod(StructuralCallSite.linkedClassOfClass, sn.Bootstrap) + // Marker for invokedynamic runtime.StructuralCall.bootstrap + lazy val StructuralCallSite_dummy = NoSymbol.newMethodSymbol(nme.apply).setInfo(NullaryMethodType(StructuralCallSite.tpe)) + def StructuralCallSite_find = getMemberIfDefined(StructuralCallSite, nme.find_) + def StructuralCallSite_add = getMemberIfDefined(StructuralCallSite, nme.add_) + def StructuralCallSite_getParameterTypes = getMemberIfDefined(StructuralCallSite, nme.parameterTypes) + lazy val SymbolLiteral = getClassIfDefined("scala.runtime.SymbolLiteral") + def SymbolLiteral_bootstrap = getMemberIfDefined(SymbolLiteral.linkedClassOfClass, sn.Bootstrap) + def SymbolLiteral_dummy = NoSymbol.newMethodSymbol(nme.apply).setInfo(NullaryMethodType(SymbolModule.companionClass.tpe)) // XML lazy val ScalaXmlTopScope = getModuleIfDefined("scala.xml.TopScope") diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 80ed597fb7..48e912d291 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -696,6 +696,7 @@ trait StdNames { val freshTermName: NameType = "freshTermName" val freshTypeName: NameType = "freshTypeName" val get: NameType = "get" + val parameterTypes: NameType = "parameterTypes" val hashCode_ : NameType = "hashCode" val hash_ : NameType = "hash" val head : NameType = "head" @@ -1170,6 +1171,7 @@ trait StdNames { final val InvokeExact: TermName = newTermName("invokeExact") final val AltMetafactory: TermName = newTermName("altMetafactory") + final val Bootstrap: TermName = newTermName("bootstrap") val Boxed = immutable.Map[TypeName, TypeName]( tpnme.Boolean -> BoxedBoolean, diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index d6b611a3f4..ba85630dbc 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -282,6 +282,9 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => definitions.MethodClass definitions.EmptyMethodCacheClass definitions.MethodCacheClass + definitions.StructuralCallSite + definitions.StructuralCallSite_dummy + definitions.SymbolLiteral definitions.ScalaXmlTopScope definitions.ScalaXmlPackage definitions.ReflectPackage |