mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
LambdaMetafactory support
This commit is contained in:
parent
d5f5e2633b
commit
13353d0bde
|
@ -15,7 +15,13 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.classlib.impl;
|
package org.teavm.classlib.impl;
|
||||||
|
|
||||||
|
import java.lang.invoke.CallSite;
|
||||||
|
import java.lang.invoke.LambdaMetafactory;
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
import org.teavm.classlib.impl.lambda.LambdaMetafactorySubstitutor;
|
||||||
import org.teavm.classlib.impl.unicode.CLDRReader;
|
import org.teavm.classlib.impl.unicode.CLDRReader;
|
||||||
import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener;
|
import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -41,5 +47,8 @@ public class JCLPlugin implements TeaVMPlugin {
|
||||||
host.registerService(CLDRReader.class, new CLDRReader(host.getProperties(), host.getClassLoader()));
|
host.registerService(CLDRReader.class, new CLDRReader(host.getProperties(), host.getClassLoader()));
|
||||||
|
|
||||||
host.add(new AnnotationDependencyListener());
|
host.add(new AnnotationDependencyListener());
|
||||||
|
host.add(new MethodReference(LambdaMetafactory.class, "metafactory", MethodHandles.Lookup.class,
|
||||||
|
String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class,
|
||||||
|
CallSite.class), new LambdaMetafactorySubstitutor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,314 @@
|
||||||
|
package org.teavm.classlib.impl.lambda;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import org.teavm.dependency.BootstrapMethodSubstitutor;
|
||||||
|
import org.teavm.dependency.DynamicCallSite;
|
||||||
|
import org.teavm.model.AccessLevel;
|
||||||
|
import org.teavm.model.ClassHolder;
|
||||||
|
import org.teavm.model.ClassReader;
|
||||||
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.FieldHolder;
|
||||||
|
import org.teavm.model.FieldReference;
|
||||||
|
import org.teavm.model.MethodHandle;
|
||||||
|
import org.teavm.model.MethodHolder;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.PrimitiveType;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.model.emit.ProgramEmitter;
|
||||||
|
import org.teavm.model.emit.ValueEmitter;
|
||||||
|
import org.teavm.model.instructions.CastIntegerDirection;
|
||||||
|
import org.teavm.model.instructions.IntegerSubtype;
|
||||||
|
import org.teavm.model.instructions.NumericOperandType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Alexey Andreev
|
||||||
|
*/
|
||||||
|
public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor {
|
||||||
|
private int lambdaIndex = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) {
|
||||||
|
ValueType[] invokedType = callSite.getCalledMethod().getSignature();
|
||||||
|
ValueType[] samMethodType = callSite.getBootstrapArguments().get(0).getMethodType();
|
||||||
|
MethodHandle implMethod = callSite.getBootstrapArguments().get(1).getMethodHandle();
|
||||||
|
ValueType[] instantiatedMethodType = callSite.getBootstrapArguments().get(2).getMethodType();
|
||||||
|
|
||||||
|
String samName = ((ValueType.Object) callSite.getCalledMethod().getResultType()).getClassName();
|
||||||
|
ClassReaderSource classSource = callSite.getAgent().getClassSource();
|
||||||
|
ClassReader samClass = classSource.get(samName);
|
||||||
|
|
||||||
|
ClassHolder implementor = new ClassHolder("$$LAMBDA" + (lambdaIndex++) + "$$");
|
||||||
|
implementor.setLevel(AccessLevel.PUBLIC);
|
||||||
|
if (samClass != null && samClass.hasModifier(ElementModifier.INTERFACE)) {
|
||||||
|
implementor.setParent("java.lang.Object");
|
||||||
|
implementor.getInterfaces().add(samName);
|
||||||
|
} else {
|
||||||
|
implementor.setParent(samName);
|
||||||
|
}
|
||||||
|
|
||||||
|
int capturedVarCount = callSite.getCalledMethod().parameterCount();
|
||||||
|
MethodHolder ctor = createConstructor(implementor, Arrays.copyOfRange(invokedType, 0, capturedVarCount));
|
||||||
|
createBridge(implementor, callSite.getCalledMethod().getName(), instantiatedMethodType, samMethodType);
|
||||||
|
|
||||||
|
MethodHolder worker = new MethodHolder(callSite.getCalledMethod().getName(), instantiatedMethodType);
|
||||||
|
worker.setLevel(AccessLevel.PUBLIC);
|
||||||
|
ProgramEmitter pe = ProgramEmitter.create(worker);
|
||||||
|
ValueEmitter thisVar = pe.newVar();
|
||||||
|
ValueEmitter[] arguments = new ValueEmitter[instantiatedMethodType.length - 1];
|
||||||
|
for (int i = 0; i < arguments.length; ++i) {
|
||||||
|
arguments[i] = pe.newVar();
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueType[] implementorSignature = getSignature(implMethod);
|
||||||
|
ValueEmitter[] passedArguments = new ValueEmitter[implementorSignature.length - 1];
|
||||||
|
for (int i = 0; i < capturedVarCount; ++i) {
|
||||||
|
passedArguments[i] = thisVar.getField(new FieldReference(implementor.getName(), "_" + i), invokedType[i]);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < instantiatedMethodType.length - 1; ++i) {
|
||||||
|
passedArguments[i + capturedVarCount] = tryConvertArgument(arguments[i], instantiatedMethodType[i],
|
||||||
|
implementorSignature[i + capturedVarCount]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueEmitter result = invoke(pe, implMethod, callSite.getInstance(), passedArguments);
|
||||||
|
if (result != null) {
|
||||||
|
ValueType actualResult = implementorSignature[implementorSignature.length - 1];
|
||||||
|
ValueType expectedResult = instantiatedMethodType[instantiatedMethodType.length - 1];
|
||||||
|
tryConvertArgument(result, actualResult, expectedResult).returnValue();
|
||||||
|
} else {
|
||||||
|
pe.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
implementor.addMethod(worker);
|
||||||
|
|
||||||
|
callSite.getAgent().submitClass(implementor);
|
||||||
|
return callerPe.construct(ctor.getReference(), callSite.getArguments().toArray(new ValueEmitter[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValueEmitter invoke(ProgramEmitter pe, MethodHandle handle, ValueEmitter instance,
|
||||||
|
ValueEmitter[] arguments) {
|
||||||
|
switch (handle.getKind()) {
|
||||||
|
case GET_FIELD:
|
||||||
|
return instance.getField(new FieldReference(handle.getClassName(), handle.getName()),
|
||||||
|
handle.getValueType());
|
||||||
|
case GET_STATIC_FIELD:
|
||||||
|
return pe.getField(new FieldReference(handle.getClassName(), handle.getName()),
|
||||||
|
handle.getValueType());
|
||||||
|
case PUT_FIELD:
|
||||||
|
instance.setField(new FieldReference(handle.getClassName(), handle.getName()), handle.getValueType(),
|
||||||
|
arguments[0]);
|
||||||
|
return null;
|
||||||
|
case PUT_STATIC_FIELD:
|
||||||
|
pe.setField(new FieldReference(handle.getClassName(), handle.getName()), handle.getValueType(),
|
||||||
|
arguments[0]);
|
||||||
|
return null;
|
||||||
|
case INVOKE_VIRTUAL:
|
||||||
|
case INVOKE_INTERFACE:
|
||||||
|
case INVOKE_SPECIAL:
|
||||||
|
return instance.invokeVirtual(new MethodReference(handle.getClassName(), handle.getName(),
|
||||||
|
handle.signature()), arguments);
|
||||||
|
case INVOKE_STATIC:
|
||||||
|
return pe.invoke(new MethodReference(handle.getClassName(), handle.getName(),
|
||||||
|
handle.signature()), arguments);
|
||||||
|
case INVOKE_CONSTRUCTOR:
|
||||||
|
return pe.construct(new MethodReference(handle.getClassName(), handle.getName(),
|
||||||
|
handle.signature()), arguments);
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected handle type: " + handle.getKind());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValueEmitter tryConvertArgument(ValueEmitter arg, ValueType from, ValueType to) {
|
||||||
|
if (from.equals(to)) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
if (from instanceof ValueType.Primitive && to instanceof ValueType.Primitive) {
|
||||||
|
PrimitiveType fromType = ((ValueType.Primitive) from).getKind();
|
||||||
|
PrimitiveType toType = ((ValueType.Primitive) to).getKind();
|
||||||
|
IntegerSubtype fromSubtype = convert(fromType);
|
||||||
|
if (fromSubtype != null) {
|
||||||
|
arg = arg.cast(fromSubtype, CastIntegerDirection.TO_INTEGER);
|
||||||
|
}
|
||||||
|
arg = arg.cast(convertNumeric(fromType), convertNumeric(toType));
|
||||||
|
IntegerSubtype toSubtype = convert(toType);
|
||||||
|
if (toSubtype != null) {
|
||||||
|
arg = arg.cast(fromSubtype, CastIntegerDirection.FROM_INTEGER);
|
||||||
|
}
|
||||||
|
return arg;
|
||||||
|
} else if (from instanceof ValueType.Primitive && to instanceof ValueType.Object) {
|
||||||
|
String primitiveClass = ((ValueType.Object) to).getClassName();
|
||||||
|
PrimitiveType toType = getWrappedPrimitive(primitiveClass);
|
||||||
|
if (toType == null) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
arg = tryConvertArgument(arg, from, ValueType.primitive(toType));
|
||||||
|
return arg.getProgramEmitter().invoke(new MethodReference(primitiveClass, "valueOf",
|
||||||
|
ValueType.primitive(toType), to), arg);
|
||||||
|
} else if (from instanceof ValueType.Object && to instanceof ValueType.Primitive) {
|
||||||
|
String primitiveClass = ((ValueType.Object) from).getClassName();
|
||||||
|
PrimitiveType fromType = getWrappedPrimitive(primitiveClass);
|
||||||
|
if (fromType == null) {
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
arg = arg.invokeVirtual(new MethodReference(primitiveClass, primitiveName(fromType) + "Value",
|
||||||
|
ValueType.primitive(fromType)));
|
||||||
|
return tryConvertArgument(arg, ValueType.primitive(fromType), to);
|
||||||
|
} else {
|
||||||
|
return arg.cast(to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntegerSubtype convert(PrimitiveType type) {
|
||||||
|
switch (type) {
|
||||||
|
case BOOLEAN:
|
||||||
|
case BYTE:
|
||||||
|
return IntegerSubtype.BYTE;
|
||||||
|
case SHORT:
|
||||||
|
return IntegerSubtype.SHORT;
|
||||||
|
case CHARACTER:
|
||||||
|
return IntegerSubtype.CHARACTER;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NumericOperandType convertNumeric(PrimitiveType type) {
|
||||||
|
switch (type) {
|
||||||
|
case BOOLEAN:
|
||||||
|
case BYTE:
|
||||||
|
case SHORT:
|
||||||
|
case CHARACTER:
|
||||||
|
case INTEGER:
|
||||||
|
return NumericOperandType.INT;
|
||||||
|
case LONG:
|
||||||
|
return NumericOperandType.LONG;
|
||||||
|
case FLOAT:
|
||||||
|
return NumericOperandType.FLOAT;
|
||||||
|
case DOUBLE:
|
||||||
|
return NumericOperandType.DOUBLE;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected type " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PrimitiveType getWrappedPrimitive(String name) {
|
||||||
|
switch (name) {
|
||||||
|
case "java.lang.Boolean":
|
||||||
|
return PrimitiveType.BOOLEAN;
|
||||||
|
case "java.lang.Byte":
|
||||||
|
return PrimitiveType.BYTE;
|
||||||
|
case "java.lang.Short":
|
||||||
|
return PrimitiveType.SHORT;
|
||||||
|
case "java.lang.Character":
|
||||||
|
return PrimitiveType.CHARACTER;
|
||||||
|
case "java.lang.Integer":
|
||||||
|
return PrimitiveType.INTEGER;
|
||||||
|
case "java.lang.Long":
|
||||||
|
return PrimitiveType.LONG;
|
||||||
|
case "java.lang.Float":
|
||||||
|
return PrimitiveType.FLOAT;
|
||||||
|
case "java.lang.Double":
|
||||||
|
return PrimitiveType.DOUBLE;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String primitiveName(PrimitiveType type) {
|
||||||
|
switch (type) {
|
||||||
|
case BOOLEAN:
|
||||||
|
return "boolean";
|
||||||
|
case BYTE:
|
||||||
|
return "byte";
|
||||||
|
case SHORT:
|
||||||
|
return "short";
|
||||||
|
case CHARACTER:
|
||||||
|
return "char";
|
||||||
|
case INTEGER:
|
||||||
|
return "int";
|
||||||
|
case LONG:
|
||||||
|
return "long";
|
||||||
|
case FLOAT:
|
||||||
|
return "float";
|
||||||
|
case DOUBLE:
|
||||||
|
return "double";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected primitive " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValueType[] getSignature(MethodHandle handle) {
|
||||||
|
switch (handle.getKind()) {
|
||||||
|
case GET_FIELD:
|
||||||
|
case GET_STATIC_FIELD:
|
||||||
|
return new ValueType[] { handle.getValueType() };
|
||||||
|
case PUT_FIELD:
|
||||||
|
case PUT_STATIC_FIELD:
|
||||||
|
return new ValueType[] { handle.getValueType(), ValueType.VOID };
|
||||||
|
default:
|
||||||
|
return handle.signature();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodHolder createConstructor(ClassHolder implementor, ValueType[] types) {
|
||||||
|
ValueType[] signature = Arrays.copyOf(types, types.length + 1);
|
||||||
|
signature[types.length] = ValueType.VOID;
|
||||||
|
MethodHolder ctor = new MethodHolder("<init>", signature);
|
||||||
|
ctor.setLevel(AccessLevel.PUBLIC);
|
||||||
|
|
||||||
|
ProgramEmitter pe = ProgramEmitter.create(ctor);
|
||||||
|
ValueEmitter thisVar = pe.newVar();
|
||||||
|
thisVar.invokeSpecial(new MethodReference(implementor.getParent(), "<init>", ValueType.VOID));
|
||||||
|
|
||||||
|
for (int i = 0; i < types.length; ++i) {
|
||||||
|
FieldHolder field = new FieldHolder("_" + i);
|
||||||
|
field.setLevel(AccessLevel.PRIVATE);
|
||||||
|
field.setType(types[i]);
|
||||||
|
implementor.addField(field);
|
||||||
|
thisVar.setField(field.getReference(), types[i], pe.newVar());
|
||||||
|
}
|
||||||
|
|
||||||
|
pe.exit();
|
||||||
|
implementor.addMethod(ctor);
|
||||||
|
return ctor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createBridge(ClassHolder implementor, String name, ValueType[] types, ValueType[] bridgeTypes) {
|
||||||
|
if (Arrays.equals(types, bridgeTypes)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodHolder bridge = new MethodHolder(name, bridgeTypes);
|
||||||
|
bridge.setLevel(AccessLevel.PUBLIC);
|
||||||
|
bridge.getModifiers().add(ElementModifier.BRIDGE);
|
||||||
|
ProgramEmitter pe = ProgramEmitter.create(bridge);
|
||||||
|
ValueEmitter thisVar = pe.newVar();
|
||||||
|
ValueEmitter[] arguments = new ValueEmitter[bridgeTypes.length - 1];
|
||||||
|
for (int i = 0; i < arguments.length; ++i) {
|
||||||
|
arguments[i] = pe.newVar();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < bridgeTypes.length - 1; ++i) {
|
||||||
|
ValueType type = types[i];
|
||||||
|
ValueType bridgeType = types[i];
|
||||||
|
if (type.equals(bridgeType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
arguments[i] = arguments[i].cast(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueEmitter result = thisVar.invokeVirtual(new MethodReference(implementor.getName(), name, types),
|
||||||
|
arguments);
|
||||||
|
if (result != null) {
|
||||||
|
if (!types[types.length - 1].equals(bridgeTypes[bridgeTypes.length - 1])) {
|
||||||
|
result = result.cast(bridgeTypes[bridgeTypes.length - 1]);
|
||||||
|
}
|
||||||
|
result.returnValue();
|
||||||
|
} else {
|
||||||
|
pe.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
implementor.addMethod(bridge);
|
||||||
|
}
|
||||||
|
}
|
|
@ -188,7 +188,6 @@ class DependencyGraphBuilder {
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
System.out.println(new ListingBuilder().buildListing(program, ""));
|
|
||||||
ProgramEmitter pe = ProgramEmitter.create(program);
|
ProgramEmitter pe = ProgramEmitter.create(program);
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
BasicBlock block = program.basicBlockAt(i);
|
||||||
|
@ -207,17 +206,18 @@ class DependencyGraphBuilder {
|
||||||
nullInsn.setReceiver(indy.getReceiver());
|
nullInsn.setReceiver(indy.getReceiver());
|
||||||
nullInsn.setLocation(indy.getLocation());
|
nullInsn.setLocation(indy.getLocation());
|
||||||
block.getInstructions().set(j, nullInsn);
|
block.getInstructions().set(j, nullInsn);
|
||||||
CallLocation location = new CallLocation(bootstrapMethod, indy.getLocation());
|
CallLocation location = new CallLocation(caller.getMethod(), currentLocation);
|
||||||
dependencyChecker.getDiagnostics().error(location, "Substitutor for this dependency method "
|
dependencyChecker.getDiagnostics().error(location, "Substitutor for bootstrap "
|
||||||
+ "was not found");
|
+ "method {{m0}} was not found", bootstrapMethod);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicBlock splitBlock = program.createBasicBlock();
|
BasicBlock splitBlock = program.createBasicBlock();
|
||||||
List<Instruction> splitInstructions = block.getInstructions().subList(j + 1,
|
List<Instruction> splitInstructions = block.getInstructions().subList(j + 1,
|
||||||
block.getInstructions().size());
|
block.getInstructions().size());
|
||||||
splitBlock.getInstructions().addAll(splitInstructions);
|
List<Instruction> splitInstructionsBackup = new ArrayList<>(splitInstructions);
|
||||||
splitInstructions.clear();
|
splitInstructions.clear();
|
||||||
|
splitBlock.getInstructions().addAll(splitInstructionsBackup);
|
||||||
|
|
||||||
for (int k = 0; k < program.basicBlockCount() - 1; ++k) {
|
for (int k = 0; k < program.basicBlockCount() - 1; ++k) {
|
||||||
BasicBlock replaceBlock = program.basicBlockAt(k);
|
BasicBlock replaceBlock = program.basicBlockAt(k);
|
||||||
|
@ -240,15 +240,13 @@ class DependencyGraphBuilder {
|
||||||
indy.getArguments().stream().map(arg -> pe.var(arg)).collect(Collectors.toList()),
|
indy.getArguments().stream().map(arg -> pe.var(arg)).collect(Collectors.toList()),
|
||||||
indy.getBootstrapMethod(),
|
indy.getBootstrapMethod(),
|
||||||
indy.getBootstrapArguments(),
|
indy.getBootstrapArguments(),
|
||||||
dependencyChecker.getAgent(),
|
dependencyChecker.getAgent());
|
||||||
indy.getInstance() != null ? nodes[indy.getInstance().getIndex()] : null,
|
|
||||||
indy.getArguments().stream().map(arg -> nodes[arg.getIndex()]).collect(Collectors.toList()));
|
|
||||||
ValueEmitter result = substitutor.substitute(callSite, pe);
|
ValueEmitter result = substitutor.substitute(callSite, pe);
|
||||||
if (result.getVariable() != null && result.getVariable() != indy.getReceiver()) {
|
if (result.getVariable() != null && result.getVariable() != indy.getReceiver()) {
|
||||||
AssignInstruction assign = new AssignInstruction();
|
AssignInstruction assign = new AssignInstruction();
|
||||||
assign.setAssignee(result.getVariable());
|
assign.setAssignee(result.getVariable());
|
||||||
assign.setReceiver(indy.getReceiver());
|
assign.setReceiver(indy.getReceiver());
|
||||||
pe.addInstruction(insn);
|
pe.addInstruction(assign);
|
||||||
}
|
}
|
||||||
pe.jump(splitBlock);
|
pe.jump(splitBlock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,20 +34,15 @@ public class DynamicCallSite {
|
||||||
private MethodHandle bootstrapMethod;
|
private MethodHandle bootstrapMethod;
|
||||||
private List<RuntimeConstant> bootstrapArguments;
|
private List<RuntimeConstant> bootstrapArguments;
|
||||||
private DependencyAgent agent;
|
private DependencyAgent agent;
|
||||||
private DependencyNode instanceNode;
|
|
||||||
private List<DependencyNode> argumentNodes = new ArrayList<>();
|
|
||||||
|
|
||||||
DynamicCallSite(MethodDescriptor calledMethod, ValueEmitter instance, List<ValueEmitter> arguments,
|
DynamicCallSite(MethodDescriptor calledMethod, ValueEmitter instance, List<ValueEmitter> arguments,
|
||||||
MethodHandle bootstrapMethod, List<RuntimeConstant> bootstrapArguments, DependencyAgent agent,
|
MethodHandle bootstrapMethod, List<RuntimeConstant> bootstrapArguments, DependencyAgent agent) {
|
||||||
DependencyNode instanceNode, List<DependencyNode> argumentNodes) {
|
|
||||||
this.calledMethod = calledMethod;
|
this.calledMethod = calledMethod;
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
this.arguments = Collections.unmodifiableList(new ArrayList<>(arguments));
|
this.arguments = Collections.unmodifiableList(new ArrayList<>(arguments));
|
||||||
this.bootstrapMethod = bootstrapMethod;
|
this.bootstrapMethod = bootstrapMethod;
|
||||||
this.bootstrapArguments = Collections.unmodifiableList(new ArrayList<>(bootstrapArguments));
|
this.bootstrapArguments = Collections.unmodifiableList(new ArrayList<>(bootstrapArguments));
|
||||||
this.agent = agent;
|
this.agent = agent;
|
||||||
this.instanceNode = instanceNode;
|
|
||||||
this.argumentNodes = Collections.unmodifiableList(new ArrayList<>(argumentNodes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodDescriptor getCalledMethod() {
|
public MethodDescriptor getCalledMethod() {
|
||||||
|
@ -73,12 +68,4 @@ public class DynamicCallSite {
|
||||||
public ValueEmitter getInstance() {
|
public ValueEmitter getInstance() {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DependencyNode getInstanceNode() {
|
|
||||||
return instanceNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<DependencyNode> getArgumentNodes() {
|
|
||||||
return argumentNodes;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ public interface ClassReaderSource {
|
||||||
default Stream<ClassReader> getAncestors(String name) {
|
default Stream<ClassReader> getAncestors(String name) {
|
||||||
return StreamSupport.stream(((Iterable<ClassReader>) () -> {
|
return StreamSupport.stream(((Iterable<ClassReader>) () -> {
|
||||||
return new Iterator<ClassReader>() {
|
return new Iterator<ClassReader>() {
|
||||||
private Deque<Deque<ClassReader>> state = new ArrayDeque<>();
|
Deque<Deque<ClassReader>> state = new ArrayDeque<>();
|
||||||
private Set<ClassReader> visited = new HashSet<>();
|
private Set<ClassReader> visited = new HashSet<>();
|
||||||
{
|
{
|
||||||
state.push(new ArrayDeque<>());
|
state.push(new ArrayDeque<>());
|
||||||
|
@ -72,7 +72,7 @@ public interface ClassReaderSource {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@Override public boolean hasNext() {
|
@Override public boolean hasNext() {
|
||||||
return !state.isEmpty();
|
return !this.state.stream().allMatch(e -> e.isEmpty());
|
||||||
}
|
}
|
||||||
private void follow(ClassReader cls) {
|
private void follow(ClassReader cls) {
|
||||||
state.push(new ArrayDeque<>());
|
state.push(new ArrayDeque<>());
|
||||||
|
@ -112,4 +112,25 @@ public interface ClassReaderSource {
|
||||||
.map(cls -> cls.getMethod(method.getDescriptor()))
|
.map(cls -> cls.getMethod(method.getDescriptor()))
|
||||||
.filter(candidate -> candidate != null);
|
.filter(candidate -> candidate != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default boolean isSuperType(String superType, String subType) {
|
||||||
|
if (superType.equals(subType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ClassReader cls = get(subType);
|
||||||
|
if (subType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
|
||||||
|
if (isSuperType(superType, cls.getParent())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String iface : cls.getInterfaces()) {
|
||||||
|
if (isSuperType(superType, iface)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,6 +228,9 @@ public class ValueEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueEmitter cast(NumericOperandType from, NumericOperandType to) {
|
public ValueEmitter cast(NumericOperandType from, NumericOperandType to) {
|
||||||
|
if (from == to) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
Variable result = pe.getProgram().createVariable();
|
Variable result = pe.getProgram().createVariable();
|
||||||
CastNumberInstruction insn = new CastNumberInstruction(from, to);
|
CastNumberInstruction insn = new CastNumberInstruction(from, to);
|
||||||
insn.setValue(variable);
|
insn.setValue(variable);
|
||||||
|
|
|
@ -1733,31 +1733,31 @@ public class ProgramParser implements VariableDebugInformation {
|
||||||
static MethodHandle parseHandle(Handle handle) {
|
static MethodHandle parseHandle(Handle handle) {
|
||||||
switch (handle.getTag()) {
|
switch (handle.getTag()) {
|
||||||
case Opcodes.H_GETFIELD:
|
case Opcodes.H_GETFIELD:
|
||||||
return MethodHandle.fieldGetter(handle.getOwner(), handle.getName(),
|
return MethodHandle.fieldGetter(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
ValueType.parse(handle.getDesc()));
|
ValueType.parse(handle.getDesc()));
|
||||||
case Opcodes.H_GETSTATIC:
|
case Opcodes.H_GETSTATIC:
|
||||||
return MethodHandle.staticFieldGetter(handle.getOwner(), handle.getName(),
|
return MethodHandle.staticFieldGetter(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
ValueType.parse(handle.getDesc()));
|
ValueType.parse(handle.getDesc()));
|
||||||
case Opcodes.H_PUTFIELD:
|
case Opcodes.H_PUTFIELD:
|
||||||
return MethodHandle.fieldSetter(handle.getOwner(), handle.getName(),
|
return MethodHandle.fieldSetter(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
ValueType.parse(handle.getDesc()));
|
ValueType.parse(handle.getDesc()));
|
||||||
case Opcodes.H_PUTSTATIC:
|
case Opcodes.H_PUTSTATIC:
|
||||||
return MethodHandle.staticFieldSetter(handle.getOwner(), handle.getName(),
|
return MethodHandle.staticFieldSetter(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
ValueType.parse(handle.getDesc()));
|
ValueType.parse(handle.getDesc()));
|
||||||
case Opcodes.H_INVOKEVIRTUAL:
|
case Opcodes.H_INVOKEVIRTUAL:
|
||||||
return MethodHandle.virtualCaller(handle.getOwner(), handle.getName(),
|
return MethodHandle.virtualCaller(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
MethodDescriptor.parseSignature(handle.getDesc()));
|
MethodDescriptor.parseSignature(handle.getDesc()));
|
||||||
case Opcodes.H_INVOKESTATIC:
|
case Opcodes.H_INVOKESTATIC:
|
||||||
return MethodHandle.staticCaller(handle.getOwner(), handle.getName(),
|
return MethodHandle.staticCaller(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
MethodDescriptor.parseSignature(handle.getDesc()));
|
MethodDescriptor.parseSignature(handle.getDesc()));
|
||||||
case Opcodes.H_INVOKESPECIAL:
|
case Opcodes.H_INVOKESPECIAL:
|
||||||
return MethodHandle.specialCaller(handle.getOwner(), handle.getName(),
|
return MethodHandle.specialCaller(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
MethodDescriptor.parseSignature(handle.getDesc()));
|
MethodDescriptor.parseSignature(handle.getDesc()));
|
||||||
case Opcodes.H_NEWINVOKESPECIAL:
|
case Opcodes.H_NEWINVOKESPECIAL:
|
||||||
return MethodHandle.constructorCaller(handle.getOwner(), handle.getName(),
|
return MethodHandle.constructorCaller(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
MethodDescriptor.parseSignature(handle.getDesc()));
|
MethodDescriptor.parseSignature(handle.getDesc()));
|
||||||
case Opcodes.H_INVOKEINTERFACE:
|
case Opcodes.H_INVOKEINTERFACE:
|
||||||
return MethodHandle.interfaceCaller(handle.getOwner(), handle.getName(),
|
return MethodHandle.interfaceCaller(handle.getOwner().replace('/', '.'), handle.getName(),
|
||||||
MethodDescriptor.parseSignature(handle.getDesc()));
|
MethodDescriptor.parseSignature(handle.getDesc()));
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown handle tag: " + handle.getTag());
|
throw new IllegalArgumentException("Unknown handle tag: " + handle.getTag());
|
||||||
|
|
|
@ -127,6 +127,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
methodInjectors.put(methodRef, injector);
|
methodInjectors.put(methodRef, injector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void add(MethodReference methodRef, BootstrapMethodSubstitutor substitutor) {
|
||||||
|
dependencyChecker.addBootstrapMethodSubstitutor(methodRef, substitutor);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(RendererListener listener) {
|
public void add(RendererListener listener) {
|
||||||
rendererListeners.add(listener);
|
rendererListeners.add(listener);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.vm.spi;
|
package org.teavm.vm.spi;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import org.teavm.dependency.BootstrapMethodSubstitutor;
|
||||||
import org.teavm.dependency.DependencyListener;
|
import org.teavm.dependency.DependencyListener;
|
||||||
import org.teavm.javascript.spi.Generator;
|
import org.teavm.javascript.spi.Generator;
|
||||||
import org.teavm.javascript.spi.Injector;
|
import org.teavm.javascript.spi.Injector;
|
||||||
|
@ -39,6 +40,8 @@ public interface TeaVMHost {
|
||||||
|
|
||||||
void add(MethodReference methodRef, Injector injector);
|
void add(MethodReference methodRef, Injector injector);
|
||||||
|
|
||||||
|
void add(MethodReference methodRef, BootstrapMethodSubstitutor substitutor);
|
||||||
|
|
||||||
void add(RendererListener listener);
|
void add(RendererListener listener);
|
||||||
|
|
||||||
<T> void registerService(Class<T> type, T instance);
|
<T> void registerService(Class<T> type, T instance);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user