Skip to content

Commit

Permalink
Move FunctionalInterface conversion to Indy too
Browse files Browse the repository at this point in the history
Signed-off-by: TheSilkMiner <[email protected]>
  • Loading branch information
TheSilkMiner committed Feb 27, 2025
1 parent b276a68 commit ee69630
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 216 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,42 +153,6 @@ public int hashCode() {
return "$lambda$" + sanitizedMethodName + '$' + canonicalInterfaceTarget + '$' + this.mangleCounters.get(id);
}

public String mangleGeneratedLambdaName(final String interfaceName) {
final class LambdaId {
final String target;

LambdaId(final String target) {
this.target = target;
}

@Override
public boolean equals(final Object o) {
return this == o || o instanceof LambdaId && this.target.equals(((LambdaId) o).target);
}

@Override
public int hashCode() {
return 17 * this.target.hashCode();
}
}

final String interfaceTarget = interfaceName.replace('/', '_').replace('.', '_');
// TODO("Rework package structure")
return "zsynthetic/$Lambda$" + interfaceTarget + '$' + this.mangleCounters.get(new LambdaId(interfaceTarget));
}

public String mangleGeneratedLambdaName(final FunctionHeader header) {
return this.mangleGeneratedLambdaName("$Generated" + EXP_TAR_MANGLE_FUNCTION_ID + this.encodeLengthNameFormat(this.mangleFunctionHeader(header)));
}

public String mangleCapturedParameter(final int parameterId, final boolean isThis) {
if (isThis) {
return "$this";
} else {
return "$" + parameterId;
}
}

private String mangleScriptName(final String rawName) {
if (rawName == null) {
class GeneratedBlock {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package org.openzen.zenscript.javabytecode.compiler;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.openzen.zencode.shared.CodePosition;
import org.openzen.zenscript.codemodel.CompareType;
import org.openzen.zenscript.codemodel.FunctionHeader;
import org.openzen.zenscript.codemodel.OperatorType;
Expand All @@ -25,12 +22,9 @@
import org.openzen.zenscript.javabytecode.compiler.lambda.LambdaIndyCompiler;
import org.openzen.zenscript.javabytecode.compiler.lambda.capturing.JavaInvalidCapturedExpressionVisitor;
import org.openzen.zenscript.javashared.*;
import org.openzen.zenscript.javashared.compiling.JavaCompilingMethod;
import org.openzen.zenscript.javashared.expressions.JavaFunctionInterfaceCastExpression;
import org.openzen.zenscript.javashared.types.JavaFunctionalInterfaceTypeID;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

import static org.openzen.zenscript.javabytecode.compiler.JavaMethodBytecodeCompiler.OBJECT_HASHCODE;
Expand All @@ -50,6 +44,7 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
private final JavaUnboxingTypeVisitor optionalUnwrappingTypeVisitor;
private final JavaFieldBytecodeCompiler fieldCompiler;
public final JavaMethodBytecodeCompiler methodCompiler;
private final LambdaIndyCompiler lambdaIndyCompiler;
private final CapturedExpressionVisitor<Void> capturedExpressionVisitor;

public JavaExpressionVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter, JavaMangler javaMangler) {
Expand All @@ -67,6 +62,7 @@ public JavaExpressionVisitor(JavaBytecodeContext context, JavaCompiledModule mod
optionalUnwrappingTypeVisitor = JavaUnboxingTypeVisitor.forOptionalUnwrapping(javaWriter);
fieldCompiler = new JavaFieldBytecodeCompiler(javaWriter, this, true);
methodCompiler = new JavaMethodBytecodeCompiler(javaWriter, this, context, module);
this.lambdaIndyCompiler = LambdaIndyCompiler.of(this.javaWriter, this.javaMangler, this.context, this.module, this);
this.capturedExpressionVisitor = capturedExpressionVisitor;
}

Expand Down Expand Up @@ -488,8 +484,7 @@ public Void visitFunction(FunctionExpression expression) {
final JavaNativeMethod functionalMethod = context.getFunctionalInterface(expression.original == null ? expression.type : new FunctionTypeID(expression.original));
final JavaNativeMethod methodInfo = functionalMethod.withModifiers(functionalMethod.modifiers & ~JavaModifiers.ABSTRACT);

final LambdaIndyCompiler lambdaCompiler = LambdaIndyCompiler.of(this.javaWriter, this.javaMangler, this.context, this.module, this);
lambdaCompiler.compileFunctionExpressionViaIndy(expression, interfaceName, methodInfo);
this.lambdaIndyCompiler.compileFunctionExpressionViaIndy(expression, interfaceName, methodInfo);

return null;
}
Expand Down Expand Up @@ -869,16 +864,17 @@ private void modify(ModifiableExpression source, Runnable modification, PushOpti

@Override
public Void visitPlatformSpecific(Expression expression) {
if (expression instanceof JavaFunctionInterfaceCastExpression) {
JavaFunctionInterfaceCastExpression jficExpression = (JavaFunctionInterfaceCastExpression) expression;
if (jficExpression.value.type instanceof JavaFunctionalInterfaceTypeID) {
jficExpression.value.accept(this);
} else {
visitFunctionalInterfaceWrapping(jficExpression);
}
} else {
throw new AssertionError("Unrecognized platform expression: " + expression);
if (!(expression instanceof JavaFunctionInterfaceCastExpression)) {
throw new AssertionError("Unrecognized platform expression " + expression.getClass().getName() + ": " + expression);
}

final JavaFunctionInterfaceCastExpression jficExpression = (JavaFunctionInterfaceCastExpression) expression;

if (jficExpression.value.type instanceof JavaFunctionalInterfaceTypeID) {
return jficExpression.value.accept(this);
}

this.lambdaIndyCompiler.convertTypeOfFunctionExpressionViaIndy(jficExpression);
return null;
}

Expand Down Expand Up @@ -906,9 +902,11 @@ public void modify(ModificationExpression expression, PushOption pushOption) {
BuiltinMethodSymbol builtin = (BuiltinMethodSymbol) expression.method.method;
modify(expression.target, builtin, pushOption);
} else {
modify(expression.target, () -> {
context.getJavaMethod(expression.method).compileVirtualWithTargetOnTopOfStack(methodCompiler, expression.type, CallArguments.EMPTY);
}, pushOption);
modify(
expression.target,
() -> context.getJavaMethod(expression.method).compileVirtualWithTargetOnTopOfStack(methodCompiler, expression.type, CallArguments.EMPTY),
pushOption
);
}
}

Expand Down Expand Up @@ -981,148 +979,6 @@ public Void visitSetStaticField(SetStaticFieldExpression expression) {
return null;
}

private void visitFunctionalInterfaceWrapping(JavaFunctionInterfaceCastExpression expression) {
// TODO("Move to LambdaFactory")
// To do the above, we simply need to be able to "extract" this into a lambda form.
// In other words, if we have to convert (OurThing -> Function), as of now:
// 1. Generate a lambda method with the signature (ThisClass, ..., OurThing)
// 2. Fill the lambda method with simply $capture.invoke(...)
// 3. Invoke LambdaFactory passing the current OurThing instance as a capture; ThisClass can be simply always loaded as null as we always ignore it
// In the above, ... denotes parameters, **never** captures
final FunctionCastWrapperClass wrapper = generateFunctionCastWrapperClass(
expression.position,
(FunctionTypeID) expression.value.type,
expression.functionType);

expression.value.accept(this);
javaWriter.newObject(wrapper.className);
javaWriter.dupX1();
javaWriter.swap();
javaWriter.invokeSpecial(wrapper.className, "<init>", wrapper.constructorDesc);
}

private FunctionCastWrapperClass generateFunctionCastWrapperClass(CodePosition position, FunctionTypeID fromType, FunctionTypeID toType) {
final String className = this.javaMangler.mangleGeneratedLambdaName(fromType.header);
final JavaClass classInfo = JavaClass.fromInternalName(className, JavaClass.Kind.CLASS);

String[] interfaces;
String wrappedFromSignature = context.getDescriptor(fromType);
String methodDescriptor;
String methodSignature;
Type[] methodParameterTypes;
JavaNativeMethod implementationMethod;
if (toType instanceof JavaFunctionalInterfaceTypeID) {
JavaNativeMethod javaMethod = ((JavaFunctionalInterfaceTypeID) toType).method;
implementationMethod = new JavaNativeMethod(
classInfo,
JavaNativeMethod.Kind.COMPILED,
javaMethod.name,
true,
javaMethod.descriptor,
javaMethod.modifiers & ~JavaModifiers.ABSTRACT,
javaMethod.genericResult,
javaMethod.typeParameterArguments);

final Method functionalInterfaceMethod = ((JavaFunctionalInterfaceTypeID) toType).functionalInterfaceMethod;

methodDescriptor = Type.getMethodDescriptor(functionalInterfaceMethod);
// ToDo: Is signature===descriptor fine here or do we need the actual signature here?
methodSignature = methodDescriptor;
interfaces = new String[]{Type.getInternalName(functionalInterfaceMethod.getDeclaringClass())};

final Class<?>[] methodParameterClasses = functionalInterfaceMethod.getParameterTypes();
methodParameterTypes = new Type[methodParameterClasses.length];
for (int i = 0; i < methodParameterClasses.length; i++) {
final Class<?> methodParameterType = methodParameterClasses[i];
methodParameterTypes[i] = Type.getType(methodParameterType);
}
} else {
wrappedFromSignature = context.getMethodSignature(toType.header, true);
methodDescriptor = context.getMethodDescriptor(toType.header);
methodSignature = context.getMethodSignature(toType.header);
interfaces = new String[]{context.getInternalName(toType)};

JavaSynthesizedFunctionInstance function = context.getFunction(toType);

implementationMethod = new JavaNativeMethod(
classInfo,
JavaNativeMethod.Kind.COMPILED,
function.getMethod(),
true,
methodDescriptor,
JavaModifiers.PUBLIC,
false // TODO: generic result or not
);

methodParameterTypes = new Type[toType.header.parameters.length];
for (int i = 0; i < methodParameterTypes.length; i++) {
methodParameterTypes[i] = context.getType(toType.header.parameters[i].type);
}
}

final JavaNativeMethod wrappedMethod = context.getFunctionalInterface(fromType);
final String constructorDescriptor = "(" + wrappedFromSignature + ")V";
// ToDo: Is signature===descriptor fine here or do we need the actual signature here?
final String constructorSignature = "(" + wrappedFromSignature + ")V";

final ClassWriter lambdaCW = new JavaClassWriter(ClassWriter.COMPUTE_FRAMES);
lambdaCW.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", interfaces);

//The field storing the wrapped object
{
lambdaCW.visitField(Modifier.PRIVATE | Modifier.FINAL, "wrapped", wrappedFromSignature, null, null).visitEnd();
}

//Constructor
{
JavaNativeMethod constructor = JavaNativeMethod.getConstructor(classInfo, constructorDescriptor, Opcodes.ACC_PUBLIC);
JavaCompilingMethod compiling = new JavaCompilingMethod(constructor, constructorSignature);
final JavaWriter constructorWriter = new JavaWriter(context.logger, position, lambdaCW, compiling, null);
constructorWriter.start();
constructorWriter.loadObject(0);
constructorWriter.dup();
constructorWriter.invokeSpecial(Object.class, "<init>", "()V");

constructorWriter.loadObject(1);
constructorWriter.putField(className, "wrapped", wrappedFromSignature);

constructorWriter.ret();
constructorWriter.end();
}

//The actual method
{
JavaCompilingMethod compiling = new JavaCompilingMethod(implementationMethod, methodSignature);
final JavaWriter functionWriter = new JavaWriter(context.logger, position, lambdaCW, compiling, null);
functionWriter.start();

//this.wrapped
functionWriter.loadObject(0);
functionWriter.getField(className, "wrapped", wrappedFromSignature);

//Load all function parameters
for (int i = 0, currentLocalPosition = 1; i < methodParameterTypes.length; i++) {
functionWriter.load(methodParameterTypes[i], currentLocalPosition);
currentLocalPosition += methodParameterTypes[i].getSize();
}

//Invokes the wrapped interface's method and returns the result
functionWriter.invokeInterface(wrappedMethod);
final TypeID returnType = fromType.header.getReturnType();
final Type rtype = context.getType(returnType);
if (!CompilerUtils.isPrimitive(returnType)) {
functionWriter.checkCast(rtype);
}
functionWriter.returnType(rtype);
functionWriter.end();
}

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

return new FunctionCastWrapperClass(className, constructorDescriptor);
}

@Override
public Void visitSupertypeCast(SupertypeCastExpression expression) {
expression.value.accept(this);
Expand Down Expand Up @@ -1261,14 +1117,4 @@ private Void tagVariableAndUpdateLastUsage(VariableID id) {
public JavaWriter getJavaWriter() {
return javaWriter;
}

private static class FunctionCastWrapperClass {
final String className;
final String constructorDesc;

FunctionCastWrapperClass(String className, String constructorDesc) {
this.className = className;
this.constructorDesc = constructorDesc;
}
}
}
Loading

0 comments on commit ee69630

Please sign in to comment.