Skip to content

Commit 3d9dc03

Browse files
committed
[indystructural] Prototype structural calls using invokedynamic
See also: https://github.com/retronym/indy-structural ``` qscalac -target:jvm-1.8 -Ybackend:GenBCode sandbox/structural.scala && qscala Test && javap -v 'Test$' | cat -v warning: there was one feature warning; re-run with -feature for details one warning found QUACK! A QUICK! A Classfile /Users/jason/code/scala2/Test$.class { public static final Test$ MODULE$; descriptor: LTest$; flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL public void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC Code: stack=4, locals=2, args_size=2 0: getstatic #19 // Field scala/Predef$.MODULE$:Lscala/Predef$; 3: aload_0 4: new #21 // class C 7: dup 8: invokespecial #22 // Method C."<init>":()V 11: invokevirtual #26 // Method duckduck:(Ljava/lang/Object;)Ljava/lang/String; 14: invokevirtual #30 // Method scala/Predef$.println:(Ljava/lang/Object;)V 17: getstatic #19 // Field scala/Predef$.MODULE$:Lscala/Predef$; 20: aload_0 21: new #32 // class D 24: dup 25: invokespecial #33 // Method D."<init>":()V 28: invokevirtual #26 // Method duckduck:(Ljava/lang/Object;)Ljava/lang/String; 31: invokevirtual #30 // Method scala/Predef$.println:(Ljava/lang/Object;)V 34: return public java.lang.String duckduck(java.lang.Object); descriptor: (Ljava/lang/Object;)Ljava/lang/String; flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_1 1: ldc #38 // String A 3: invokedynamic #49, 0 // InvokeDynamic #0:"dyn:callMethod:quack":(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String; 8: checkcast #51 // class java/lang/String 11: areturn } BootstrapMethods: 0: #45 invokestatic jdk/internal/dynalink/DefaultBootstrapper.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: ```
1 parent 1d8c632 commit 3d9dc03

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,16 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
311311
case app : Apply =>
312312
generatedType = genApply(app, expectedType)
313313

314-
case ApplyDynamic(qual, args) => sys.error("No invokedynamic support yet.")
314+
case app @ ApplyDynamic(qual, args) =>
315+
genLoad(qual)
316+
val symbol = app.symbol
317+
val paramTypes = symbol.info.paramTypes map toTypeKind
318+
genLoadArguments(args, paramTypes)
319+
val argAsmTypes = symbol.info.params.map(symInfoTK).map(_.toASMType)
320+
val returnAsmType = toTypeKind(symbol.info.resultType).toASMType
321+
val invokedType = asm.Type.getMethodType(returnAsmType, toTypeKind(qual.tpe).toASMType +: argAsmTypes : _*)
322+
val name = "dyn:callMethod:" + symbol.name
323+
mnode.visitInvokeDynamicInsn(name, invokedType.getDescriptor, dynalinkBoostrapHandle)
315324

316325
case This(qual) =>
317326
val symIsModuleClass = tree.symbol.isModuleClass
@@ -1324,4 +1333,11 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
13241333
definitions.LambdaMetaFactory.fullName('/'), sn.AltMetafactory.toString,
13251334
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;")
13261335

1336+
// TODO use custom boostrap method in our runtime that employs ChainedCallSite to cache recently used linkage results
1337+
// TODO use "org.dynalang" % "dynalink" rather than relying on Nashorn internals
1338+
lazy val dynalinkBoostrapHandle =
1339+
new asm.Handle(asm.Opcodes.H_INVOKESTATIC,
1340+
"jdk/internal/dynalink/DefaultBootstrapper", "bootstrap",
1341+
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;")
1342+
13271343
}

src/compiler/scala/tools/nsc/transform/CleanUp.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ abstract class CleanUp extends Statics with Transform with ast.TreeDSL {
446446
* refinement, where the refinement defines a parameter based on a
447447
* type variable. */
448448

449-
case tree: ApplyDynamic =>
449+
case tree: ApplyDynamic if !(settings.isBCodeActive && settings.target.value == "jvm-1.8") =>
450450
transformApplyDynamic(tree)
451451

452452
/* Some cleanup transformations add members to templates (classes, traits, etc).

0 commit comments

Comments
 (0)