@@ -490,95 +490,113 @@ public Void visitFunction(FunctionExpression expression) {
490490 }
491491
492492 final JavaNativeMethod methodInfo ;
493- final String className = this .javaMangler .mangleGeneratedLambdaName (interfaces [0 ]);
494493 {
495494 final JavaNativeMethod m = context .getFunctionalInterface (expression .original == null ? expression .type : new FunctionTypeID (expression .original ));
496495 methodInfo = m .withModifiers (m .modifiers & ~JavaModifiers .ABSTRACT );
497496 }
498- final ClassWriter lambdaCW = new JavaClassWriter (ClassWriter .COMPUTE_FRAMES );
499- JavaClass lambdaClass = JavaClass .fromInternalName (className , JavaClass .Kind .CLASS );
500- lambdaCW .visit (Opcodes .V1_8 , Opcodes .ACC_PUBLIC , className , null , "java/lang/Object" , interfaces );
501-
502- JavaCompilingMethod actualCompiling = JavaMemberVisitor .compileBridgeableMethod (
503- context ,
504- expression .position ,
505- lambdaCW ,
506- lambdaClass ,
507- methodInfo ,
508- expression .header ,
509- null
510- );
511- javaWriter .newObject (className );
512- javaWriter .dup ();
513-
514- // ToDo: Is this fine or do we need the actual signature here?
515- // To check: write a test where the ctor desc and signature would differ and make sure the program compiles/executes
516- final String constructorDescriptorAndSignature = calcFunctionDescriptor (expression .closure );
517- JavaNativeMethod constructor = JavaNativeMethod .getConstructor (lambdaClass , constructorDescriptorAndSignature , Opcodes .ACC_PUBLIC );
518- JavaCompilingMethod constructorCompiling = new JavaCompilingMethod (constructor , constructorDescriptorAndSignature );
519- final JavaWriter constructorWriter = new JavaWriter (context .logger , expression .position , lambdaCW , constructorCompiling , null );
520- constructorWriter .start ();
521- constructorWriter .loadObject (0 );
522- constructorWriter .dup ();
523- constructorWriter .invokeSpecial (Object .class , "<init>" , "()V" );
524497
525- int i = 0 ;
526- for (CapturedExpression capture : expression .closure .captures ) {
527- constructorWriter .dup ();
528- Type type = context .getType (capture .type );
529- i ++;
530- String name = this .javaMangler .mangleCapturedParameter (i , capture instanceof CapturedThisExpression );
531- lambdaCW .visitField (Opcodes .ACC_FINAL | Opcodes .ACC_PRIVATE , name , type .getDescriptor (), null , null ).visitEnd ();
532-
533- capture .accept (new JavaCapturedExpressionVisitorToPutCapturesOnTheStackBeforeCallingTheCtor (this ));
498+ final JavaClass thisClass = javaWriter .method .class_ ;
499+ final String lambdaName = this .javaMangler .mangleLambdaMethod (javaWriter .method .compiled .name , interfaces [0 ]);
500+ final LambdaClosureInfo closureInfo = LambdaClosureInfo .from (context , expression .closure , thisClass );
501+ final String lambdaDescriptor = calcFunctionDescriptor (thisClass , closureInfo , expression .header );
502+ final JavaNativeMethod lambdaMethod = JavaNativeMethod .getStatic (thisClass , lambdaName , lambdaDescriptor , Opcodes .ACC_PRIVATE | Opcodes .ACC_STATIC );
503+ final JavaCompilingMethod lambdaMethodCompiling = JavaMemberVisitor .compileBridgeableMethodNoSideEffect (lambdaMethod , lambdaDescriptor ); // TODO("Restore signatures")
504+ final JavaWriter lambdaWriter = new JavaWriter (context .logger , expression .position , javaWriter .clazzVisitor , lambdaMethodCompiling , null );
505+ final CapturedExpressionVisitor <Void > lambdaCapturesVisitor = new JavaCapturedExpressionVisitorLocalRedirectionVisitor (lambdaWriter , expression , closureInfo );
506+ final JavaCompiledModule lambdaModule = new ShiftingJavaCompiledModule (module , closureInfo , context );
507+ final JavaExpressionVisitor lambdaExpressionVisitor = new JavaExpressionVisitor (context , lambdaModule , lambdaWriter , javaMangler , lambdaCapturesVisitor );
508+ final JavaStatementVisitor lambdaStatementVisitor = new JavaStatementVisitor (context , lambdaExpressionVisitor , javaMangler );
509+
510+ lambdaWriter .start ();
511+ expression .body .accept (lambdaStatementVisitor );
512+ lambdaWriter .ret ();
513+ lambdaWriter .end ();
514+
515+ if (java .lang .reflect .Modifier .isStatic (javaWriter .method .compiled .modifiers ) || thisClass .kind == JavaClass .Kind .EXPANSION ) {
516+ javaWriter .aConstNull ();
517+ } else {
518+ javaWriter .loadObject (0 );
519+ }
534520
535- constructorWriter .load (type , i );
536- constructorWriter .putField (className , name , type .getDescriptor ());
521+ if (closureInfo .isDifferentThis ()) {
522+ for (final CapturedExpression capture : expression .closure .captures ) {
523+ capture .accept (new JavaCapturedExpressionVisitorLoadIndyCapturesVisitor (this , true ));
524+ }
525+ }
526+ for (final CapturedExpression capture : expression .closure .captures ) {
527+ capture .accept (new JavaCapturedExpressionVisitorLoadIndyCapturesVisitor (this , false ));
537528 }
538529
539- constructorWriter .pop ();
540-
541- javaWriter .invokeSpecial (className , "<init>" , constructorDescriptorAndSignature );
542-
543- constructorWriter .ret ();
544- constructorWriter .end ();
545-
546- JavaWriter functionWriter = new JavaWriter (context .logger , expression .position , lambdaCW , actualCompiling , null );
547- functionWriter .clazzVisitor .visitSource (expression .position .getFilename (), null );
548- functionWriter .start ();
549-
550- JavaExpressionVisitor withCapturedExpressionVisitor = new JavaExpressionVisitor (
551- context ,
552- module ,
553- functionWriter ,
554- javaMangler ,
555- new JavaCapturedExpressionVisitorToAccessCapturesInsideTheLambda (
556- context ,
557- functionWriter ,
558- javaMangler ,
559- className ,
560- expression
561- )
530+ // TODO("Have this in JavaWriter")
531+ javaWriter .getVisitor ().visitInvokeDynamicInsn (
532+ methodInfo .name ,
533+ calcIndyDescriptor (thisClass , closureInfo , interfaces [0 ]),
534+ new org .objectweb .asm .Handle (
535+ Opcodes .H_INVOKESTATIC ,
536+ Type .getInternalName (org .openzen .zenscript .javart .factory .LambdaFactory .class ),
537+ "buildLambda" ,
538+ Type .getMethodDescriptor (
539+ Type .getType (java .lang .invoke .CallSite .class ),
540+ Type .getType (java .lang .invoke .MethodHandles .Lookup .class ),
541+ Type .getType (String .class ),
542+ Type .getType (java .lang .invoke .MethodType .class ),
543+ Type .getType (java .lang .invoke .MethodHandle .class ),
544+ Type .getType (java .lang .invoke .MethodType .class ),
545+ Type .INT_TYPE ,
546+ Type .getType (java .lang .invoke .MethodType .class )
547+ ),
548+ false
549+ ),
550+ new org .objectweb .asm .Handle (
551+ Opcodes .H_INVOKESTATIC ,
552+ thisClass .internalName ,
553+ lambdaName ,
554+ lambdaDescriptor ,
555+ false
556+ ),
557+ Type .getMethodType (JavaMemberVisitor .compileBridgeableMethodNoSideEffect (methodInfo , context .getMethodDescriptor (expression .header )).compiled .descriptor ),
558+ org .openzen .zenscript .javart .factory .LambdaFactory .FLAG_GENERATE_BRIDGE | (closureInfo .isDifferentThis ()? org .openzen .zenscript .javart .factory .LambdaFactory .FLAG_DIFFERENTIATE_RECEIVER : 0 ),
559+ Type .getMethodType (methodInfo .descriptor )
562560 );
563- expression .body .accept (new JavaStatementVisitor (context , withCapturedExpressionVisitor , javaMangler ));
564561
565- functionWriter . ret () ;
566- functionWriter . end ();
562+ return null ;
563+ }
567564
568- lambdaCW .visitEnd ();
565+ private String calcFunctionDescriptor (final JavaClass thisClass , final LambdaClosureInfo closureInfo , final FunctionHeader header ) {
566+ final StringJoiner joiner = new StringJoiner ("" );
567+ for (final CapturedExpression capture : closureInfo .closure ().captures ) {
568+ if (!(capture instanceof CapturedThisExpression )) {
569+ final String descriptor = context .getDescriptor (capture .type );
570+ joiner .add (descriptor );
571+ }
572+ }
569573
570- context . register ( className , lambdaCW . toByteArray ()) ;
574+ final String thisDescriptor = closureInfo . isDifferentThis ()? context . getDescriptor ( closureInfo . thisType ()) : "" ;
571575
572- return null ;
576+ final StringBuilder builder = new StringBuilder (context .getMethodDescriptor (header ));
577+ builder .insert (builder .indexOf ("(" ) + 1 , 'L' + thisClass .internalName + ';' + thisDescriptor );
578+ builder .insert (builder .lastIndexOf (")" ), joiner );
579+ return builder .toString ();
573580 }
574581
575- private String calcFunctionDescriptor (LambdaClosure closure ) {
576- StringJoiner joiner = new StringJoiner ("" , "(" , ")V" );
577- for (CapturedExpression capture : closure .captures ) {
578- String descriptor = context .getDescriptor (capture .type );
579- joiner .add (descriptor );
582+ private String calcIndyDescriptor (final JavaClass thisClass , final LambdaClosureInfo closureInfo , final String targetInterface ) {
583+ final StringBuilder builder = new StringBuilder ("(L" );
584+ builder .append (thisClass .internalName ).append (';' );
585+
586+ if (closureInfo .isDifferentThis ()) {
587+ builder .append (context .getDescriptor (closureInfo .thisType ()));
588+ }
589+
590+ final StringJoiner joiner = new StringJoiner ("" );
591+ for (final CapturedExpression capture : closureInfo .closure ().captures ) {
592+ if (!(capture instanceof CapturedThisExpression )) {
593+ final String descriptor = context .getDescriptor (capture .type );
594+ joiner .add (descriptor );
595+ }
580596 }
581- return joiner .toString ();
597+
598+ builder .append (joiner ).append (")L" ).append (targetInterface ).append (';' );
599+ return builder .toString ();
582600 }
583601
584602 @ Override
@@ -1069,6 +1087,13 @@ public Void visitSetStaticField(SetStaticFieldExpression expression) {
10691087 }
10701088
10711089 private void visitFunctionalInterfaceWrapping (JavaFunctionInterfaceCastExpression expression ) {
1090+ // TODO("Move to LambdaFactory")
1091+ // To do the above, we simply need to be able to "extract" this into a lambda form.
1092+ // In other words, if we have to convert (OurThing -> Function), as of now:
1093+ // 1. Generate a lambda method with the signature (ThisClass, ..., OurThing)
1094+ // 2. Fill the lambda method with simply $capture.invoke(...)
1095+ // 3. Invoke LambdaFactory passing the current OurThing instance as a capture; ThisClass can be simply always loaded as null as we always ignore it
1096+ // In the above, ... denotes parameters, **never** captures
10721097 final FunctionCastWrapperClass wrapper = generateFunctionCastWrapperClass (
10731098 expression .position ,
10741099 (FunctionTypeID ) expression .value .type ,
0 commit comments