mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Add support for array of objects
This commit is contained in:
parent
38aca08993
commit
421eca8a49
|
@ -17,15 +17,11 @@ package org.teavm.model;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class ClassHolder extends ElementHolder implements ClassReader {
|
public class ClassHolder extends ElementHolder implements ClassReader {
|
||||||
private String parent = Object.class.getName();
|
private String parent = Object.class.getName();
|
||||||
private Set<String> interfaces = new HashSet<>();
|
private Set<String> interfaces = new LinkedHashSet<>();
|
||||||
private Map<MethodDescriptor, MethodHolder> methods = new HashMap<>();
|
private Map<MethodDescriptor, MethodHolder> methods = new LinkedHashMap<>();
|
||||||
private Map<String, FieldHolder> fields = new HashMap<>();
|
private Map<String, FieldHolder> fields = new LinkedHashMap<>();
|
||||||
private String ownerName;
|
private String ownerName;
|
||||||
|
|
||||||
public ClassHolder(String name) {
|
public ClassHolder(String name) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.runtime;
|
||||||
|
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.StaticInit;
|
import org.teavm.interop.StaticInit;
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
@StaticInit
|
@StaticInit
|
||||||
public final class Allocator {
|
public final class Allocator {
|
||||||
|
@ -31,4 +32,18 @@ public final class Allocator {
|
||||||
object.classReference = tag.toAddress().toInt() >> 3;
|
object.classReference = tag.toAddress().toInt() >> 3;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Address allocateArray(RuntimeClass tag, int size, byte depth) {
|
||||||
|
Address result = address;
|
||||||
|
int sizeInBytes = (size + 1) * 4 + Structure.sizeOf(RuntimeArray.class);
|
||||||
|
address = result.add(sizeInBytes);
|
||||||
|
|
||||||
|
RuntimeArray array = result.toStructure();
|
||||||
|
array.classReference = RuntimeClass.getArrayClass().toAddress().toInt() >> 3;
|
||||||
|
array.componentClassReference = tag.toAddress().toInt() >> 3;
|
||||||
|
array.size = size;
|
||||||
|
address.add(Structure.sizeOf(RuntimeArray.class)).putByte(depth);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,5 +17,5 @@ package org.teavm.runtime;
|
||||||
|
|
||||||
public class RuntimeArray extends RuntimeObject {
|
public class RuntimeArray extends RuntimeObject {
|
||||||
public int componentClassReference;
|
public int componentClassReference;
|
||||||
public byte depth;
|
int size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,5 +53,5 @@ public class RuntimeClass extends Structure {
|
||||||
return computeCanary(size, lowerTag, upperTag);
|
return computeCanary(size, lowerTag, upperTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native RuntimeClass getArrayClass();
|
public static native RuntimeClass getArrayClass();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,12 @@ public final class Example {
|
||||||
WasmRuntime.print(instance(i).foo());
|
WasmRuntime.print(instance(i).foo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Base[] array = { new Derived1(), new Derived2() };
|
||||||
|
WasmRuntime.print(array.length);
|
||||||
|
for (Base elem : array) {
|
||||||
|
WasmRuntime.print(elem.foo());
|
||||||
|
}
|
||||||
|
|
||||||
WasmRuntime.print(new Derived2() instanceof Base ? 1 : 0);
|
WasmRuntime.print(new Derived2() instanceof Base ? 1 : 0);
|
||||||
WasmRuntime.print(new Derived3() instanceof Base ? 1 : 0);
|
WasmRuntime.print(new Derived3() instanceof Base ? 1 : 0);
|
||||||
WasmRuntime.print((Object) new Derived2() instanceof Derived1 ? 1 : 0);
|
WasmRuntime.print((Object) new Derived2() instanceof Derived1 ? 1 : 0);
|
||||||
|
|
|
@ -30,7 +30,6 @@ import org.teavm.dependency.DependencyChecker;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.Import;
|
import org.teavm.interop.Import;
|
||||||
import org.teavm.interop.StaticInit;
|
import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.Structure;
|
|
||||||
import org.teavm.model.BasicBlock;
|
import org.teavm.model.BasicBlock;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
import org.teavm.model.ClassHolder;
|
import org.teavm.model.ClassHolder;
|
||||||
|
@ -61,7 +60,10 @@ import org.teavm.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.wasm.generate.WasmGenerationContext;
|
import org.teavm.wasm.generate.WasmGenerationContext;
|
||||||
import org.teavm.wasm.generate.WasmGenerator;
|
import org.teavm.wasm.generate.WasmGenerator;
|
||||||
import org.teavm.wasm.generate.WasmMangling;
|
import org.teavm.wasm.generate.WasmMangling;
|
||||||
|
import org.teavm.wasm.intrinsics.WasmAddressIntrinsic;
|
||||||
|
import org.teavm.wasm.intrinsics.WasmRuntimeClassIntrinsic;
|
||||||
import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic;
|
import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic;
|
||||||
|
import org.teavm.wasm.intrinsics.WasmStructureIntrinsic;
|
||||||
import org.teavm.wasm.model.WasmFunction;
|
import org.teavm.wasm.model.WasmFunction;
|
||||||
import org.teavm.wasm.model.WasmModule;
|
import org.teavm.wasm.model.WasmModule;
|
||||||
import org.teavm.wasm.model.WasmType;
|
import org.teavm.wasm.model.WasmType;
|
||||||
|
@ -110,6 +112,9 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
|
|
||||||
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate",
|
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate",
|
||||||
RuntimeClass.class, Address.class), null).use();
|
RuntimeClass.class, Address.class), null).use();
|
||||||
|
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||||
|
RuntimeClass.class, int.class, byte.class, Address.class), null).use();
|
||||||
|
|
||||||
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "<clinit>", void.class), null).use();
|
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "<clinit>", void.class), null).use();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,12 +135,18 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
classGenerator.addArrayClass();
|
||||||
address = classGenerator.getAddress();
|
address = classGenerator.getAddress();
|
||||||
|
|
||||||
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
|
||||||
new HashSet<>());
|
new HashSet<>());
|
||||||
WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider, tagRegistry);
|
WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider, tagRegistry);
|
||||||
|
|
||||||
|
context.addIntrinsic(new WasmAddressIntrinsic());
|
||||||
|
context.addIntrinsic(new WasmRuntimeClassIntrinsic(classGenerator));
|
||||||
|
context.addIntrinsic(new WasmStructureIntrinsic(classGenerator));
|
||||||
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
||||||
|
|
||||||
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
|
||||||
|
|
||||||
module.setMemorySize(64);
|
module.setMemorySize(64);
|
||||||
|
@ -152,10 +163,6 @@ public class WasmTarget implements TeaVMTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method.hasModifier(ElementModifier.NATIVE)) {
|
if (method.hasModifier(ElementModifier.NATIVE)) {
|
||||||
if (method.getOwnerName().equals(Structure.class.getName())
|
|
||||||
|| method.getOwnerName().equals(Address.class.getName())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (context.getImportedMethod(method.getReference()) == null) {
|
if (context.getImportedMethod(method.getReference()) == null) {
|
||||||
CallLocation location = new CallLocation(method.getReference());
|
CallLocation location = new CallLocation(method.getReference());
|
||||||
controller.getDiagnostics().error(location, "Method {{m0}} is native but "
|
controller.getDiagnostics().error(location, "Method {{m0}} is native but "
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class WasmClassGenerator {
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private int address;
|
private int address;
|
||||||
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
private Map<String, ClassBinaryData> binaryDataMap = new LinkedHashMap<>();
|
||||||
|
private ClassBinaryData arrayClassData;
|
||||||
private List<WasmExpression> initializer;
|
private List<WasmExpression> initializer;
|
||||||
private Map<MethodReference, Integer> functions = new HashMap<>();
|
private Map<MethodReference, Integer> functions = new HashMap<>();
|
||||||
private List<String> functionTable = new ArrayList<>();
|
private List<String> functionTable = new ArrayList<>();
|
||||||
|
@ -81,6 +82,17 @@ public class WasmClassGenerator {
|
||||||
contributeToInitializer(binaryData);
|
contributeToInitializer(binaryData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addArrayClass() {
|
||||||
|
if (arrayClassData != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayClassData = new ClassBinaryData();
|
||||||
|
arrayClassData.start = address;
|
||||||
|
|
||||||
|
address += RuntimeClass.VIRTUAL_TABLE_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
public int getAddress() {
|
public int getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
@ -153,6 +165,15 @@ public class WasmClassGenerator {
|
||||||
return data.fieldLayout.get(field.getFieldName());
|
return data.fieldLayout.get(field.getFieldName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getClassSize(String className) {
|
||||||
|
ClassBinaryData data = binaryDataMap.get(className);
|
||||||
|
return data.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getArrayClassPointer() {
|
||||||
|
return arrayClassData.start;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isStructure(String className) {
|
public boolean isStructure(String className) {
|
||||||
ClassBinaryData data = binaryDataMap.get(className);
|
ClassBinaryData data = binaryDataMap.get(className);
|
||||||
return data.start < 0;
|
return data.start < 0;
|
||||||
|
|
|
@ -62,7 +62,6 @@ import org.teavm.ast.UnwrapArrayExpr;
|
||||||
import org.teavm.ast.VariableExpr;
|
import org.teavm.ast.VariableExpr;
|
||||||
import org.teavm.ast.WhileStatement;
|
import org.teavm.ast.WhileStatement;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.Structure;
|
|
||||||
import org.teavm.model.ClassReader;
|
import org.teavm.model.ClassReader;
|
||||||
import org.teavm.model.FieldReference;
|
import org.teavm.model.FieldReference;
|
||||||
import org.teavm.model.MethodDescriptor;
|
import org.teavm.model.MethodDescriptor;
|
||||||
|
@ -71,6 +70,7 @@ import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.classes.TagRegistry;
|
import org.teavm.model.classes.TagRegistry;
|
||||||
import org.teavm.model.classes.VirtualTableEntry;
|
import org.teavm.model.classes.VirtualTableEntry;
|
||||||
import org.teavm.runtime.Allocator;
|
import org.teavm.runtime.Allocator;
|
||||||
|
import org.teavm.runtime.RuntimeArray;
|
||||||
import org.teavm.runtime.RuntimeClass;
|
import org.teavm.runtime.RuntimeClass;
|
||||||
import org.teavm.wasm.WasmRuntime;
|
import org.teavm.wasm.WasmRuntime;
|
||||||
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
import org.teavm.wasm.intrinsics.WasmIntrinsic;
|
||||||
|
@ -336,7 +336,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
result, new WasmInt32Constant(16));
|
result, new WasmInt32Constant(16));
|
||||||
break;
|
break;
|
||||||
case LENGTH:
|
case LENGTH:
|
||||||
result = new WasmInt32Constant(0);
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
result = generateArrayLength(result);
|
||||||
break;
|
break;
|
||||||
case NOT:
|
case NOT:
|
||||||
expr.getOperand().acceptVisitor(this);
|
expr.getOperand().acceptVisitor(this);
|
||||||
|
@ -369,6 +370,14 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmExpression generateArrayLength(WasmExpression array) {
|
||||||
|
int sizeOffset = classGenerator.getFieldOffset(new FieldReference(RuntimeArray.class.getName(), "size"));
|
||||||
|
|
||||||
|
WasmIntBinary ptr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||||
|
array, new WasmInt32Constant(sizeOffset));
|
||||||
|
return new WasmLoadInt32(4, ptr, WasmInt32Subtype.INT32);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(AssignmentStatement statement) {
|
public void visit(AssignmentStatement statement) {
|
||||||
Expr left = statement.getLeftValue();
|
Expr left = statement.getLeftValue();
|
||||||
|
@ -383,6 +392,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
} else if (left instanceof QualificationExpr) {
|
} else if (left instanceof QualificationExpr) {
|
||||||
QualificationExpr lhs = (QualificationExpr) left;
|
QualificationExpr lhs = (QualificationExpr) left;
|
||||||
storeField(lhs.getQualified(), lhs.getField(), statement.getRightValue());
|
storeField(lhs.getQualified(), lhs.getField(), statement.getRightValue());
|
||||||
|
} else if (left instanceof SubscriptExpr) {
|
||||||
|
SubscriptExpr lhs = (SubscriptExpr) left;
|
||||||
|
storeArrayItem(lhs.getArray(), lhs.getIndex(), statement.getRightValue());
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedOperationException("This expression is not supported yet");
|
throw new UnsupportedOperationException("This expression is not supported yet");
|
||||||
}
|
}
|
||||||
|
@ -422,6 +434,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void storeArrayItem(Expr array, Expr index, Expr rightValue) {
|
||||||
|
WasmExpression ptr = getArrayElementPointer(array, index);
|
||||||
|
rightValue.acceptVisitor(this);
|
||||||
|
result = new WasmStoreInt32(4, ptr, result, WasmInt32Subtype.INT32);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ConditionalExpr expr) {
|
public void visit(ConditionalExpr expr) {
|
||||||
expr.getCondition().acceptVisitor(this);
|
expr.getCondition().acceptVisitor(this);
|
||||||
|
@ -488,7 +506,22 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SubscriptExpr expr) {
|
public void visit(SubscriptExpr expr) {
|
||||||
throw new UnsupportedOperationException("Not supported yet");
|
WasmExpression ptr = getArrayElementPointer(expr.getArray(), expr.getIndex());
|
||||||
|
result = new WasmLoadInt32(4, ptr, WasmInt32Subtype.INT32);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression getArrayElementPointer(Expr arrayExpr, Expr indexExpr) {
|
||||||
|
arrayExpr.acceptVisitor(this);
|
||||||
|
WasmExpression array = result;
|
||||||
|
indexExpr.acceptVisitor(this);
|
||||||
|
WasmExpression index = result;
|
||||||
|
|
||||||
|
classGenerator.addClass(RuntimeArray.class.getName());
|
||||||
|
int base = classGenerator.getClassSize(RuntimeArray.class.getName());
|
||||||
|
array = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, new WasmInt32Constant(base));
|
||||||
|
index = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, index, new WasmInt32Constant(2));
|
||||||
|
|
||||||
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -600,15 +633,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InvocationExpr expr) {
|
public void visit(InvocationExpr expr) {
|
||||||
if (expr.getMethod().getClassName().equals(Address.class.getName())) {
|
|
||||||
generateAddressInvocation(expr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (expr.getMethod().getClassName().equals(Structure.class.getName())) {
|
|
||||||
generateStructureInvocation(expr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WasmIntrinsic intrinsic = context.getIntrinsic(expr.getMethod());
|
WasmIntrinsic intrinsic = context.getIntrinsic(expr.getMethod());
|
||||||
if (intrinsic != null) {
|
if (intrinsic != null) {
|
||||||
result = intrinsic.apply(expr, intrinsicManager);
|
result = intrinsic.apply(expr, intrinsicManager);
|
||||||
|
@ -661,122 +685,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateAddressInvocation(InvocationExpr expr) {
|
|
||||||
switch (expr.getMethod().getName()) {
|
|
||||||
case "toInt":
|
|
||||||
case "toStructure":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
break;
|
|
||||||
case "toLong":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmConversion(WasmType.INT32, WasmType.INT64, false, result);
|
|
||||||
break;
|
|
||||||
case "fromInt":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
break;
|
|
||||||
case "fromLong":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmConversion(WasmType.INT64, WasmType.INT32, false, result);
|
|
||||||
break;
|
|
||||||
case "add": {
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
WasmExpression base = result;
|
|
||||||
expr.getArguments().get(1).acceptVisitor(this);
|
|
||||||
WasmExpression offset = result;
|
|
||||||
if (expr.getMethod().parameterType(0) == ValueType.LONG) {
|
|
||||||
offset = new WasmConversion(WasmType.INT64, WasmType.INT32, false, offset);
|
|
||||||
}
|
|
||||||
result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "getByte":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmLoadInt32(1, result, WasmInt32Subtype.INT8);
|
|
||||||
break;
|
|
||||||
case "getShort":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmLoadInt32(2, result, WasmInt32Subtype.INT16);
|
|
||||||
break;
|
|
||||||
case "getChar":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmLoadInt32(2, result, WasmInt32Subtype.UINT16);
|
|
||||||
break;
|
|
||||||
case "getInt":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmLoadInt32(4, result, WasmInt32Subtype.INT32);
|
|
||||||
break;
|
|
||||||
case "getLong":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmLoadInt64(8, result, WasmInt64Subtype.INT64);
|
|
||||||
break;
|
|
||||||
case "getFloat":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmLoadFloat32(4, result);
|
|
||||||
break;
|
|
||||||
case "getDouble":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
result = new WasmLoadFloat64(8, result);
|
|
||||||
break;
|
|
||||||
case "putByte": {
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
WasmExpression address = result;
|
|
||||||
expr.getArguments().get(1).acceptVisitor(this);
|
|
||||||
result = new WasmStoreInt32(1, address, result, WasmInt32Subtype.INT8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "putShort": {
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
WasmExpression address = result;
|
|
||||||
expr.getArguments().get(1).acceptVisitor(this);
|
|
||||||
result = new WasmStoreInt32(2, address, result, WasmInt32Subtype.INT16);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "putChar": {
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
WasmExpression address = result;
|
|
||||||
expr.getArguments().get(1).acceptVisitor(this);
|
|
||||||
result = new WasmStoreInt32(2, address, result, WasmInt32Subtype.UINT16);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "putInt": {
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
WasmExpression address = result;
|
|
||||||
expr.getArguments().get(1).acceptVisitor(this);
|
|
||||||
result = new WasmStoreInt32(4, address, result, WasmInt32Subtype.INT32);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "putLong": {
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
WasmExpression address = result;
|
|
||||||
expr.getArguments().get(1).acceptVisitor(this);
|
|
||||||
result = new WasmStoreInt64(8, address, result, WasmInt64Subtype.INT64);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "putFloat": {
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
WasmExpression address = result;
|
|
||||||
expr.getArguments().get(1).acceptVisitor(this);
|
|
||||||
result = new WasmStoreFloat32(4, address, result);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "putDouble": {
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
WasmExpression address = result;
|
|
||||||
expr.getArguments().get(1).acceptVisitor(this);
|
|
||||||
result = new WasmStoreFloat64(8, address, result);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateStructureInvocation(InvocationExpr expr) {
|
|
||||||
switch (expr.getMethod().getName()) {
|
|
||||||
case "toAddress":
|
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BlockStatement statement) {
|
public void visit(BlockStatement statement) {
|
||||||
WasmBlock block = new WasmBlock(false);
|
WasmBlock block = new WasmBlock(false);
|
||||||
|
@ -856,16 +764,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
result = new WasmBreak(wasmTarget);
|
result = new WasmBreak(wasmTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(NewExpr expr) {
|
|
||||||
int tag = classGenerator.getClassPointer(expr.getConstructedClass());
|
|
||||||
String allocName = WasmMangling.mangleMethod(new MethodReference(Allocator.class, "allocate",
|
|
||||||
RuntimeClass.class, Address.class));
|
|
||||||
WasmCall call = new WasmCall(allocName);
|
|
||||||
call.getArguments().add(new WasmInt32Constant(tag));
|
|
||||||
result = call;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ContinueStatement statement) {
|
public void visit(ContinueStatement statement) {
|
||||||
IdentifiedStatement target = statement.getTarget();
|
IdentifiedStatement target = statement.getTarget();
|
||||||
|
@ -877,8 +775,36 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
|
||||||
result = new WasmBreak(wasmTarget);
|
result = new WasmBreak(wasmTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NewExpr expr) {
|
||||||
|
int tag = classGenerator.getClassPointer(expr.getConstructedClass());
|
||||||
|
String allocName = WasmMangling.mangleMethod(new MethodReference(Allocator.class, "allocate",
|
||||||
|
RuntimeClass.class, Address.class));
|
||||||
|
WasmCall call = new WasmCall(allocName);
|
||||||
|
call.getArguments().add(new WasmInt32Constant(tag));
|
||||||
|
result = call;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NewArrayExpr expr) {
|
public void visit(NewArrayExpr expr) {
|
||||||
|
ValueType type = expr.getType();
|
||||||
|
int depth = 0;
|
||||||
|
while (type instanceof ValueType.Array) {
|
||||||
|
++depth;
|
||||||
|
type = ((ValueType.Array) type).getItemType();
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueType.Object cls = (ValueType.Object) type;
|
||||||
|
int classPointer = classGenerator.getClassPointer(cls.getClassName());
|
||||||
|
String allocName = WasmMangling.mangleMethod(new MethodReference(Allocator.class, "allocateArray",
|
||||||
|
RuntimeClass.class, int.class, byte.class, Address.class));
|
||||||
|
WasmCall call = new WasmCall(allocName);
|
||||||
|
call.getArguments().add(new WasmInt32Constant(classPointer));
|
||||||
|
expr.getLength().acceptVisitor(this);
|
||||||
|
call.getArguments().add(result);
|
||||||
|
call.getArguments().add(new WasmInt32Constant(depth));
|
||||||
|
|
||||||
|
result = call;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.wasm.intrinsics;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.wasm.model.WasmType;
|
||||||
|
import org.teavm.wasm.model.expression.WasmConversion;
|
||||||
|
import org.teavm.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.wasm.model.expression.WasmInt32Subtype;
|
||||||
|
import org.teavm.wasm.model.expression.WasmInt64Subtype;
|
||||||
|
import org.teavm.wasm.model.expression.WasmIntBinary;
|
||||||
|
import org.teavm.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
|
import org.teavm.wasm.model.expression.WasmIntType;
|
||||||
|
import org.teavm.wasm.model.expression.WasmLoadFloat32;
|
||||||
|
import org.teavm.wasm.model.expression.WasmLoadFloat64;
|
||||||
|
import org.teavm.wasm.model.expression.WasmLoadInt32;
|
||||||
|
import org.teavm.wasm.model.expression.WasmLoadInt64;
|
||||||
|
import org.teavm.wasm.model.expression.WasmStoreFloat32;
|
||||||
|
import org.teavm.wasm.model.expression.WasmStoreFloat64;
|
||||||
|
import org.teavm.wasm.model.expression.WasmStoreInt32;
|
||||||
|
import org.teavm.wasm.model.expression.WasmStoreInt64;
|
||||||
|
|
||||||
|
public class WasmAddressIntrinsic implements WasmIntrinsic {
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(MethodReference methodReference) {
|
||||||
|
return methodReference.getClassName().equals(Address.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "toInt":
|
||||||
|
case "toStructure":
|
||||||
|
return manager.generate(invocation.getArguments().get(0));
|
||||||
|
case "toLong": {
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(0));
|
||||||
|
return new WasmConversion(WasmType.INT32, WasmType.INT64, false, value);
|
||||||
|
}
|
||||||
|
case "fromInt":
|
||||||
|
return manager.generate(invocation.getArguments().get(0));
|
||||||
|
case "fromLong": {
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(0));
|
||||||
|
return new WasmConversion(WasmType.INT64, WasmType.INT32, false, value);
|
||||||
|
}
|
||||||
|
case "add": {
|
||||||
|
WasmExpression base = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression offset = manager.generate(invocation.getArguments().get(1));
|
||||||
|
if (invocation.getMethod().parameterType(0) == ValueType.LONG) {
|
||||||
|
offset = new WasmConversion(WasmType.INT64, WasmType.INT32, false, offset);
|
||||||
|
}
|
||||||
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
|
||||||
|
}
|
||||||
|
case "getByte":
|
||||||
|
return new WasmLoadInt32(1, manager.generate(invocation.getArguments().get(0)),
|
||||||
|
WasmInt32Subtype.INT8);
|
||||||
|
case "getShort":
|
||||||
|
return new WasmLoadInt32(2, manager.generate(invocation.getArguments().get(0)),
|
||||||
|
WasmInt32Subtype.INT16);
|
||||||
|
case "getChar":
|
||||||
|
return new WasmLoadInt32(2, manager.generate(invocation.getArguments().get(0)),
|
||||||
|
WasmInt32Subtype.UINT16);
|
||||||
|
case "getInt":
|
||||||
|
return new WasmLoadInt32(4, manager.generate(invocation.getArguments().get(0)),
|
||||||
|
WasmInt32Subtype.INT32);
|
||||||
|
case "getLong":
|
||||||
|
return new WasmLoadInt64(8, manager.generate(invocation.getArguments().get(0)),
|
||||||
|
WasmInt64Subtype.INT64);
|
||||||
|
case "getFloat":
|
||||||
|
return new WasmLoadFloat32(4, manager.generate(invocation.getArguments().get(0)));
|
||||||
|
case "getDouble":
|
||||||
|
return new WasmLoadFloat64(8, manager.generate(invocation.getArguments().get(0)));
|
||||||
|
case "putByte": {
|
||||||
|
WasmExpression address = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(1));
|
||||||
|
return new WasmStoreInt32(1, address, value, WasmInt32Subtype.INT8);
|
||||||
|
}
|
||||||
|
case "putShort": {
|
||||||
|
WasmExpression address = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(1));
|
||||||
|
return new WasmStoreInt32(2, address, value, WasmInt32Subtype.INT16);
|
||||||
|
}
|
||||||
|
case "putChar": {
|
||||||
|
WasmExpression address = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(1));
|
||||||
|
return new WasmStoreInt32(2, address, value, WasmInt32Subtype.UINT16);
|
||||||
|
}
|
||||||
|
case "putInt": {
|
||||||
|
WasmExpression address = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(1));
|
||||||
|
return new WasmStoreInt32(4, address, value, WasmInt32Subtype.INT32);
|
||||||
|
}
|
||||||
|
case "putLong": {
|
||||||
|
WasmExpression address = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(1));
|
||||||
|
return new WasmStoreInt64(8, address, value, WasmInt64Subtype.INT64);
|
||||||
|
}
|
||||||
|
case "putFloat": {
|
||||||
|
WasmExpression address = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(1));
|
||||||
|
return new WasmStoreFloat32(4, address, value);
|
||||||
|
}
|
||||||
|
case "putDouble": {
|
||||||
|
WasmExpression address = manager.generate(invocation.getArguments().get(0));
|
||||||
|
WasmExpression value = manager.generate(invocation.getArguments().get(1));
|
||||||
|
return new WasmStoreFloat64(8, address, value);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,8 @@
|
||||||
package org.teavm.wasm.intrinsics;
|
package org.teavm.wasm.intrinsics;
|
||||||
|
|
||||||
import org.teavm.ast.Expr;
|
import org.teavm.ast.Expr;
|
||||||
|
import org.teavm.wasm.generate.WasmClassGenerator;
|
||||||
|
import org.teavm.wasm.generate.WasmGenerationContext;
|
||||||
import org.teavm.wasm.model.expression.WasmExpression;
|
import org.teavm.wasm.model.expression.WasmExpression;
|
||||||
|
|
||||||
public interface WasmIntrinsicManager {
|
public interface WasmIntrinsicManager {
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.wasm.intrinsics;
|
||||||
|
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.runtime.RuntimeClass;
|
||||||
|
import org.teavm.wasm.generate.WasmClassGenerator;
|
||||||
|
import org.teavm.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||||
|
|
||||||
|
public class WasmRuntimeClassIntrinsic implements WasmIntrinsic {
|
||||||
|
private WasmClassGenerator classGenerator;
|
||||||
|
|
||||||
|
public WasmRuntimeClassIntrinsic(WasmClassGenerator classGenerator) {
|
||||||
|
this.classGenerator = classGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(MethodReference methodReference) {
|
||||||
|
if (!methodReference.getClassName().equals(RuntimeClass.class.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (methodReference.getName()) {
|
||||||
|
case "getArrayClass":
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "getArrayClass":
|
||||||
|
return new WasmInt32Constant(classGenerator.getArrayClassPointer());
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.wasm.intrinsics;
|
||||||
|
|
||||||
|
import org.teavm.ast.ConstantExpr;
|
||||||
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
import org.teavm.wasm.generate.WasmClassGenerator;
|
||||||
|
import org.teavm.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.wasm.model.expression.WasmInt32Constant;
|
||||||
|
|
||||||
|
public class WasmStructureIntrinsic implements WasmIntrinsic {
|
||||||
|
private WasmClassGenerator classGenerator;
|
||||||
|
|
||||||
|
public WasmStructureIntrinsic(WasmClassGenerator classGenerator) {
|
||||||
|
this.classGenerator = classGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isApplicable(MethodReference methodReference) {
|
||||||
|
return !methodReference.getClassName().equals(Address.class.getName())
|
||||||
|
&& classGenerator.getClassPointer(methodReference.getClassName()) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "toAddress":
|
||||||
|
case "cast":
|
||||||
|
return manager.generate(invocation.getArguments().get(0));
|
||||||
|
case "sizeOf": {
|
||||||
|
ValueType.Object type = (ValueType.Object) ((ConstantExpr) invocation.getArguments().get(0)).getValue();
|
||||||
|
return new WasmInt32Constant(classGenerator.getClassSize(type.getClassName()));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -448,6 +448,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
case INT8:
|
case INT8:
|
||||||
case UINT8:
|
case UINT8:
|
||||||
append("i32.store8");
|
append("i32.store8");
|
||||||
|
break;
|
||||||
case INT16:
|
case INT16:
|
||||||
case UINT16:
|
case UINT16:
|
||||||
append("i32.store16");
|
append("i32.store16");
|
||||||
|
@ -469,6 +470,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor {
|
||||||
case INT8:
|
case INT8:
|
||||||
case UINT8:
|
case UINT8:
|
||||||
append("i64.store8");
|
append("i64.store8");
|
||||||
|
break;
|
||||||
case INT16:
|
case INT16:
|
||||||
case UINT16:
|
case UINT16:
|
||||||
append("i64.store16");
|
append("i64.store16");
|
||||||
|
|
|
@ -20,7 +20,7 @@ public class Structure {
|
||||||
|
|
||||||
public final native Address toAddress();
|
public final native Address toAddress();
|
||||||
|
|
||||||
public final native int sizeOf(Class<? extends Structure> type);
|
public static native int sizeOf(Class<? extends Structure> type);
|
||||||
|
|
||||||
public final native <T extends Structure> T add(T base, int offset);
|
public static native <T extends Structure> T add(T base, int offset);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user