mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
Implements transformer that substitutes all invocations of resources
with ResourcesAccessor
This commit is contained in:
parent
7e3d62a85d
commit
8956e8b8d0
|
@ -26,11 +26,11 @@ final class ResourceAccessor {
|
||||||
|
|
||||||
public static native Object get(Object obj, int index);
|
public static native Object get(Object obj, int index);
|
||||||
|
|
||||||
public static native Object add(Object obj, Object elem);
|
public static native void add(Object obj, Object elem);
|
||||||
|
|
||||||
public static native boolean has(Object obj, String key);
|
public static native boolean has(Object obj, String key);
|
||||||
|
|
||||||
public static native boolean size(Object obj);
|
public static native int size(Object obj);
|
||||||
|
|
||||||
public static native int castToInt(Object obj);
|
public static native int castToInt(Object obj);
|
||||||
|
|
||||||
|
|
|
@ -16,14 +16,14 @@
|
||||||
package org.teavm.platform.plugin;
|
package org.teavm.platform.plugin;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
import org.teavm.model.instructions.EmptyInstruction;
|
import org.teavm.model.instructions.*;
|
||||||
import org.teavm.model.instructions.InvocationType;
|
|
||||||
import org.teavm.model.instructions.InvokeInstruction;
|
|
||||||
import org.teavm.model.instructions.StringConstantInstruction;
|
|
||||||
import org.teavm.platform.metadata.Resource;
|
import org.teavm.platform.metadata.Resource;
|
||||||
|
import org.teavm.platform.metadata.ResourceArray;
|
||||||
|
import org.teavm.platform.metadata.ResourceMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -67,21 +67,35 @@ class ResourceTransformer implements ClassHolderTransformer {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
MethodReference method = insn.getMethod();
|
MethodReference method = insn.getMethod();
|
||||||
|
if (method.getClassName().equals(ResourceArray.class.getName()) ||
|
||||||
|
method.getClassName().equals(ResourceMap.class.getName())) {
|
||||||
|
InvokeInstruction accessInsn = new InvokeInstruction();
|
||||||
|
accessInsn.setType(InvocationType.SPECIAL);
|
||||||
|
ValueType[] types = new ValueType[method.getDescriptor().parameterCount() + 2];
|
||||||
|
types[0] = ValueType.object("java.lang.Object");
|
||||||
|
System.arraycopy(method.getDescriptor().getSignature(), 0, types, 1,
|
||||||
|
method.getDescriptor().parameterCount() + 1);
|
||||||
|
accessInsn.setMethod(new MethodReference(ResourceAccessor.class.getName(), method.getName(), types));
|
||||||
|
accessInsn.getArguments().add(insn.getInstance());
|
||||||
|
accessInsn.getArguments().addAll(insn.getArguments());
|
||||||
|
accessInsn.setReceiver(insn.getReceiver());
|
||||||
|
return Arrays.<Instruction>asList(accessInsn);
|
||||||
|
}
|
||||||
ClassReader iface = innerSource.get(method.getClassName());
|
ClassReader iface = innerSource.get(method.getClassName());
|
||||||
if (iface.getAnnotations().get(Resource.class.getName()) == null) {
|
if (iface.getAnnotations().get(Resource.class.getName()) == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (method.getName().startsWith("get")) {
|
if (method.getName().startsWith("get")) {
|
||||||
if (method.getName().length() > 3) {
|
if (method.getName().length() > 3) {
|
||||||
return transformGetterInvocation(insn, method.getName().substring(3));
|
return transformGetterInvocation(insn, getPropertyName(method.getName().substring(3)));
|
||||||
}
|
}
|
||||||
} else if (method.getName().startsWith("is")) {
|
} else if (method.getName().startsWith("is")) {
|
||||||
if (method.getName().length() > 2) {
|
if (method.getName().length() > 2) {
|
||||||
return transformGetterInvocation(insn, method.getName().substring(2));
|
return transformGetterInvocation(insn, getPropertyName(method.getName().substring(2)));
|
||||||
}
|
}
|
||||||
} else if (method.getName().startsWith("set")) {
|
} else if (method.getName().startsWith("set")) {
|
||||||
if (method.getName().length() > 3) {
|
if (method.getName().length() > 3) {
|
||||||
return transformSetterInvocation(insn, method.getName().substring(3));
|
return transformSetterInvocation(insn, getPropertyName(method.getName().substring(3)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -92,13 +106,70 @@ class ResourceTransformer implements ClassHolderTransformer {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
ValueType type = insn.getMethod().getDescriptor().getResultType();
|
ValueType type = insn.getMethod().getDescriptor().getResultType();
|
||||||
Program program = insn.getProgram();
|
|
||||||
List<Instruction> instructions = new ArrayList<>();
|
List<Instruction> instructions = new ArrayList<>();
|
||||||
if (type instanceof ValueType.Primitive) {
|
if (type instanceof ValueType.Primitive) {
|
||||||
switch (((ValueType.Primitive)type).getKind()) {
|
switch (((ValueType.Primitive)type).getKind()) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
|
getAndCastProperty(insn, property, instructions, boolean.class);
|
||||||
|
return instructions;
|
||||||
|
case BYTE:
|
||||||
|
getAndCastProperty(insn, property, instructions, byte.class);
|
||||||
|
return instructions;
|
||||||
|
case SHORT:
|
||||||
|
getAndCastProperty(insn, property, instructions, short.class);
|
||||||
|
return instructions;
|
||||||
|
case INTEGER:
|
||||||
|
getAndCastProperty(insn, property, instructions, int.class);
|
||||||
|
return instructions;
|
||||||
|
case FLOAT:
|
||||||
|
getAndCastProperty(insn, property, instructions, float.class);
|
||||||
|
return instructions;
|
||||||
|
case DOUBLE:
|
||||||
|
getAndCastProperty(insn, property, instructions, double.class);
|
||||||
|
return instructions;
|
||||||
|
case CHARACTER:
|
||||||
|
case LONG:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (type instanceof ValueType.Object) {
|
||||||
|
switch (((ValueType.Object)type).getClassName()) {
|
||||||
|
case "java.lang.Boolean":
|
||||||
|
getAndCastPropertyToWrapper(insn, property, instructions, boolean.class, Boolean.class);
|
||||||
|
return instructions;
|
||||||
|
case "java.lang.Byte":
|
||||||
|
getAndCastPropertyToWrapper(insn, property, instructions, byte.class, Byte.class);
|
||||||
|
return instructions;
|
||||||
|
case "java.lang.Short":
|
||||||
|
getAndCastPropertyToWrapper(insn, property, instructions, short.class, Short.class);
|
||||||
|
return instructions;
|
||||||
|
case "java.lang.Integer":
|
||||||
|
getAndCastPropertyToWrapper(insn, property, instructions, int.class, Integer.class);
|
||||||
|
return instructions;
|
||||||
|
case "java.lang.Float":
|
||||||
|
getAndCastPropertyToWrapper(insn, property, instructions, float.class, Float.class);
|
||||||
|
return instructions;
|
||||||
|
case "java.lang.Double":
|
||||||
|
getAndCastPropertyToWrapper(insn, property, instructions, double.class, Double.class);
|
||||||
|
return instructions;
|
||||||
|
default: {
|
||||||
|
Variable resultVar = insn.getProgram().createVariable();
|
||||||
|
getProperty(insn, property, instructions, resultVar);
|
||||||
|
CastInstruction castInsn = new CastInstruction();
|
||||||
|
castInsn.setReceiver(insn.getReceiver());
|
||||||
|
castInsn.setTargetType(type);
|
||||||
|
castInsn.setValue(resultVar);
|
||||||
|
instructions.add(castInsn);
|
||||||
|
return instructions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
|
||||||
|
Variable resultVar) {
|
||||||
|
Program program = insn.getProgram();
|
||||||
Variable nameVar = program.createVariable();
|
Variable nameVar = program.createVariable();
|
||||||
Variable resultVar = program.createVariable();
|
|
||||||
StringConstantInstruction nameInsn = new StringConstantInstruction();
|
StringConstantInstruction nameInsn = new StringConstantInstruction();
|
||||||
nameInsn.setConstant(property);
|
nameInsn.setConstant(property);
|
||||||
nameInsn.setReceiver(nameVar);
|
nameInsn.setReceiver(nameVar);
|
||||||
|
@ -111,18 +182,40 @@ class ResourceTransformer implements ClassHolderTransformer {
|
||||||
accessorInvoke.getArguments().add(nameVar);
|
accessorInvoke.getArguments().add(nameVar);
|
||||||
accessorInvoke.setReceiver(resultVar);
|
accessorInvoke.setReceiver(resultVar);
|
||||||
instructions.add(accessorInvoke);
|
instructions.add(accessorInvoke);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getAndCastProperty(InvokeInstruction insn, String property, List<Instruction> instructions,
|
||||||
|
Class<?> primitive) {
|
||||||
|
Program program = insn.getProgram();
|
||||||
|
Variable resultVar = program.createVariable();
|
||||||
|
getProperty(insn, property, instructions, resultVar);
|
||||||
InvokeInstruction castInvoke = new InvokeInstruction();
|
InvokeInstruction castInvoke = new InvokeInstruction();
|
||||||
castInvoke.setType(InvocationType.SPECIAL);
|
castInvoke.setType(InvocationType.SPECIAL);
|
||||||
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castToBoolean", Object.class,
|
String primitiveCapitalized = primitive.getName();
|
||||||
boolean.class));
|
primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
|
||||||
|
primitiveCapitalized.substring(1);
|
||||||
|
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized,
|
||||||
|
Object.class, primitive));
|
||||||
castInvoke.getArguments().add(resultVar);
|
castInvoke.getArguments().add(resultVar);
|
||||||
castInvoke.setReceiver(insn.getReceiver());
|
castInvoke.setReceiver(insn.getReceiver());
|
||||||
return instructions;
|
instructions.add(castInvoke);
|
||||||
}
|
}
|
||||||
} else if (type instanceof ValueType.Object) {
|
|
||||||
|
|
||||||
}
|
private void getAndCastPropertyToWrapper(InvokeInstruction insn, String property, List<Instruction> instructions,
|
||||||
return null;
|
Class<?> primitive, Class<?> wrapper) {
|
||||||
|
Program program = insn.getProgram();
|
||||||
|
Variable resultVar = program.createVariable();
|
||||||
|
getProperty(insn, property, instructions, resultVar);
|
||||||
|
InvokeInstruction castInvoke = new InvokeInstruction();
|
||||||
|
castInvoke.setType(InvocationType.SPECIAL);
|
||||||
|
String primitiveCapitalized = primitive.getName();
|
||||||
|
primitiveCapitalized = Character.toUpperCase(primitiveCapitalized.charAt(0)) +
|
||||||
|
primitiveCapitalized.substring(1);
|
||||||
|
castInvoke.setMethod(new MethodReference(ResourceAccessor.class, "castTo" + primitiveCapitalized + "Primitive",
|
||||||
|
Object.class, wrapper));
|
||||||
|
castInvoke.getArguments().add(resultVar);
|
||||||
|
castInvoke.setReceiver(insn.getReceiver());
|
||||||
|
instructions.add(castInvoke);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Instruction> transformSetterInvocation(InvokeInstruction insn, String property) {
|
private List<Instruction> transformSetterInvocation(InvokeInstruction insn, String property) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user