Skip to content

Commit 6b4c963

Browse files
committed
Improve compilation of lambdas so we remember the original header and use that when compiling the lambda bridge method
1 parent a29b19f commit 6b4c963

File tree

17 files changed

+96
-14
lines changed

17 files changed

+96
-14
lines changed

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/CastedEval.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,31 @@ public static CastedEval implicit(ExpressionCompiler compiler, CodePosition posi
1313
return new CastedEval(compiler, position, type, false, false);
1414
}
1515

16+
public static CastedEval implicit(ExpressionCompiler compiler, CodePosition position, TypeID type, TypeID original) {
17+
return new CastedEval(compiler, position, type, original, false, false);
18+
}
19+
1620
private final ExpressionCompiler compiler;
1721
private final CodePosition position;
1822
public final TypeID type;
23+
public final TypeID original; // used for lambdas
1924
private final boolean explicit;
2025
private final boolean optional;
2126

2227
public CastedEval(ExpressionCompiler compiler, CodePosition position, TypeID type, boolean explicit, boolean optional) {
2328
this.compiler = compiler;
2429
this.position = position;
2530
this.type = type;
31+
this.original = type;
32+
this.explicit = explicit;
33+
this.optional = optional;
34+
}
35+
36+
public CastedEval(ExpressionCompiler compiler, CodePosition position, TypeID type, TypeID original, boolean explicit, boolean optional) {
37+
this.compiler = compiler;
38+
this.position = position;
39+
this.type = type;
40+
this.original = original;
2641
this.explicit = explicit;
2742
this.optional = optional;
2843
}

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/ExpressionBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ public interface ExpressionBuilder {
6767

6868
Expression lambda(LambdaClosure closure, FunctionHeader header, Statement body);
6969

70+
Expression lambda(LambdaClosure closure, FunctionHeader header, FunctionHeader original, Statement body);
71+
7072
Expression newArray(ArrayTypeID type, Expression[] values);
7173

7274
Expression newAssoc(AssocTypeID type, List<Expression> keys, List<Expression> values);

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/MatchedCallArguments.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ private static <T extends AnyMethod> MatchedCallArguments<T> matchNormal(
247247
// invalid
248248
return CastedExpression.invalid(position, CompileErrors.missingParameter(header.getParameter(false, i).name));
249249
}
250-
return argument.cast(CastedEval.implicit(compiler, position, header.getParameterType(false, i)));
250+
TypeID originalType = method.getHeader().getParameterType(false, i);
251+
return argument.cast(CastedEval.implicit(compiler, position, header.getParameterType(false, i), originalType));
251252
})
252253
.toArray(CastedExpression[]::new);
253254

@@ -293,7 +294,12 @@ private static <T extends AnyMethod> Optional<MatchedCallArguments<T>> matchVarA
293294
}
294295

295296
CastedExpression[] castedExpressions = IntStream.range(0, arguments.length)
296-
.mapToObj(i -> arguments[i].cast(CastedEval.implicit(compiler, position, header.getParameterType(true, i))))
297+
.mapToObj(i -> arguments[i].cast(CastedEval.implicit(
298+
compiler,
299+
position,
300+
header.getParameterType(true, i),
301+
method.getHeader().getParameterType(true, i)
302+
)))
297303
.toArray(CastedExpression[]::new);
298304

299305
Expression[] expressions = new Expression[header.parameters.length];

CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/impl/compiler/ExpressionCompilerImpl.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,12 @@ public Expression is(Expression value, TypeID type) {
324324

325325
@Override
326326
public Expression lambda(LambdaClosure closure, FunctionHeader header, Statement body) {
327-
return new FunctionExpression(position, closure, header, body);
327+
return lambda(closure, header, null, body);
328+
}
329+
330+
@Override
331+
public Expression lambda(LambdaClosure closure, FunctionHeader header, FunctionHeader original, Statement body) {
332+
return new FunctionExpression(position, closure, header, original, body);
328333
}
329334

330335
@Override

CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/Expression.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public final Expression transform(StatementTransformer transformer) {
7878
if (body == function.body)
7979
return function;
8080

81-
return new FunctionExpression(function.position, function.closure, function.header, body);
81+
return new FunctionExpression(function.position, function.closure, function.header, function.original, body);
8282
} else {
8383
return expression;
8484
}

CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/FunctionExpression.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,20 @@ public class FunctionExpression extends Expression {
1818
public final FunctionHeader header;
1919
public final LambdaClosure closure;
2020
public final Statement body;
21+
public final FunctionHeader original;
2122

2223
public FunctionExpression(
2324
CodePosition position,
2425
LambdaClosure closure,
2526
FunctionHeader header,
27+
FunctionHeader original,
2628
Statement body) {
2729
super(position, new FunctionTypeID(header), body.getThrownType());
2830

2931
this.header = header;
3032
this.closure = closure;
3133
this.body = body;
34+
this.original = original;
3235
}
3336

3437
@Override
@@ -44,7 +47,7 @@ public <C, R> R accept(C context, ExpressionVisitorWithContext<C, R> visitor) {
4447
@Override
4548
public FunctionExpression transform(ExpressionTransformer transformer) {
4649
Statement tBody = body.transform(transformer, ConcatMap.empty(LoopStatement.class, LoopStatement.class));
47-
return tBody == body ? this : new FunctionExpression(position, closure, header, tBody);
50+
return tBody == body ? this : new FunctionExpression(position, closure, header, original, tBody);
4851
}
4952

5053
@Override

JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaBoxingTypeVisitor.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ public Void visitRange(TypeID context, RangeTypeID range) {
134134

135135
@Override
136136
public Void visitOptional(TypeID context, OptionalTypeID type) {
137+
if (type.baseType == BasicTypeID.USIZE) {
138+
writer.invokeStatic(INTEGER_VALUEOF);
139+
}
137140
//NO-OP
138141
return null;
139142
}

JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.objectweb.asm.Type;
77
import org.openzen.zencode.shared.CodePosition;
88
import org.openzen.zenscript.codemodel.CompareType;
9+
import org.openzen.zenscript.codemodel.FunctionHeader;
910
import org.openzen.zenscript.codemodel.OperatorType;
1011
import org.openzen.zenscript.codemodel.definition.ExpansionDefinition;
1112
import org.openzen.zenscript.codemodel.expression.captured.CapturedExpression;
@@ -474,6 +475,7 @@ public Void visitFunction(FunctionExpression expression) {
474475
}*/
475476

476477
final String[] interfaces;
478+
FunctionHeader header = expression.original == null ? expression.header : expression.original;
477479

478480
if (expression.type instanceof JavaFunctionalInterfaceTypeID) {
479481
//Let's implement the functional Interface instead
@@ -484,19 +486,18 @@ public Void visitFunction(FunctionExpression expression) {
484486
interfaces = new String[]{Type.getInternalName(functionalInterfaceMethod.getDeclaringClass())};
485487
} else {
486488
//Normal way, no casting to functional interface
487-
interfaces = new String[]{context.getInternalName(new FunctionTypeID(expression.header))};
489+
interfaces = new String[]{context.getInternalName(new FunctionTypeID(header))};
488490
}
489491

490492
final JavaNativeMethod methodInfo;
491493
final String className = this.javaMangler.mangleGeneratedLambdaName(interfaces[0]);
492494
{
493-
final JavaNativeMethod m = context.getFunctionalInterface(expression.type);
495+
final JavaNativeMethod m = context.getFunctionalInterface(expression.original == null ? expression.type : new FunctionTypeID(expression.original));
494496
methodInfo = m.withModifiers(m.modifiers & ~JavaModifiers.ABSTRACT);
495497
}
496498
final ClassWriter lambdaCW = new JavaClassWriter(ClassWriter.COMPUTE_FRAMES);
497499
JavaClass lambdaClass = JavaClass.fromInternalName(className, JavaClass.Kind.CLASS);
498500
lambdaCW.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", interfaces);
499-
final JavaWriter functionWriter;
500501

501502
JavaCompilingMethod actualCompiling = JavaMemberVisitor.compileBridgeableMethod(
502503
context,
@@ -507,8 +508,6 @@ public Void visitFunction(FunctionExpression expression) {
507508
expression.header,
508509
null
509510
);
510-
functionWriter = new JavaWriter(context.logger, expression.position, lambdaCW, actualCompiling, null);
511-
functionWriter.clazzVisitor.visitSource(expression.position.getFilename(), null);
512511
javaWriter.newObject(className);
513512
javaWriter.dup();
514513

@@ -544,7 +543,8 @@ public Void visitFunction(FunctionExpression expression) {
544543
constructorWriter.ret();
545544
constructorWriter.end();
546545

547-
546+
JavaWriter functionWriter = new JavaWriter(context.logger, expression.position, lambdaCW, actualCompiling, null);
547+
functionWriter.clazzVisitor.visitSource(expression.position.getFilename(), null);
548548
functionWriter.start();
549549

550550
JavaExpressionVisitor withCapturedExpressionVisitor = new JavaExpressionVisitor(
@@ -564,6 +564,7 @@ public Void visitFunction(FunctionExpression expression) {
564564

565565
functionWriter.ret();
566566
functionWriter.end();
567+
567568
lambdaCW.visitEnd();
568569

569570
context.register(className, lambdaCW.toByteArray());

JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,12 @@ public static JavaCompilingMethod compileBridgeableMethod(
468468
bridgeWriter.invokeVirtual(new JavaNativeMethod(localClass, JavaNativeMethod.Kind.INSTANCE, overriddenMethodInfo.name, overriddenMethodInfo.compile, implementationDescriptor, overriddenMethodInfo.modifiers, overriddenMethodInfo.genericResult));
469469
final TypeID returnType = implementationHeader.getReturnType();
470470
if (returnType != BasicTypeID.VOID) {
471-
final Type returnTypeASM = context.getType(returnType);
471+
Type returnTypeASM = context.getType(returnType);
472472
if (!CompilerUtils.isPrimitive(returnType)) {
473473
bridgeWriter.checkCast(returnTypeASM);
474+
} else if (!isPrimitiveReturnType(overriddenMethodInfo.descriptor)) {
475+
returnType.accept(returnType, JavaBoxingTypeVisitor.forJavaBoxing(bridgeWriter));
476+
returnTypeASM = Type.getReturnType(overriddenMethodInfo.descriptor);
474477
}
475478
bridgeWriter.returnType(returnTypeASM);
476479
}
@@ -484,4 +487,20 @@ public static JavaCompilingMethod compileBridgeableMethod(
484487
return new JavaCompilingMethod(overriddenMethodInfo, implementationSignature);
485488
}
486489
}
490+
491+
private static boolean isPrimitiveReturnType(String descriptor) {
492+
switch (Type.getReturnType(descriptor).getSort()) {
493+
case Type.BYTE:
494+
case Type.SHORT:
495+
case Type.INT:
496+
case Type.LONG:
497+
case Type.FLOAT:
498+
case Type.DOUBLE:
499+
case Type.BOOLEAN:
500+
case Type.CHAR:
501+
return true;
502+
default:
503+
return false;
504+
}
505+
}
487506
}

Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionFunction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ public CastedExpression cast(CastedEval cast) {
113113
thatOtherHeader.setReturnType(header.getReturnType());
114114
}*/
115115

116-
return cast.of(CastedExpression.Level.EXACT, compiler.at(position).lambda(closure, header, statement));
116+
FunctionHeader originalHeader = cast.original.asFunction().map(f -> f.header).orElse(null);
117+
return cast.of(CastedExpression.Level.EXACT, compiler.at(position).lambda(closure, header, originalHeader, statement));
117118
} else {
118119
return cast.of(eval());
119120
}

0 commit comments

Comments
 (0)