From 421eca8a49ae9ed675665b46e2ab5c3b88f1151a Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 12 Aug 2016 23:38:29 +0300 Subject: [PATCH] Add support for array of objects --- .../java/org/teavm/model/ClassHolder.java | 10 +- .../java/org/teavm/runtime/Allocator.java | 15 ++ .../java/org/teavm/runtime/RuntimeArray.java | 2 +- .../java/org/teavm/runtime/RuntimeClass.java | 2 +- .../src/main/java/org/teavm/wasm/Example.java | 6 + .../main/java/org/teavm/wasm/WasmTarget.java | 17 +- .../wasm/generate/WasmClassGenerator.java | 21 ++ .../wasm/generate/WasmGenerationVisitor.java | 202 ++++++------------ .../wasm/intrinsics/WasmAddressIntrinsic.java | 127 +++++++++++ .../wasm/intrinsics/WasmIntrinsicManager.java | 2 + .../intrinsics/WasmRuntimeClassIntrinsic.java | 55 +++++ .../intrinsics/WasmStructureIntrinsic.java | 54 +++++ .../wasm/render/WasmRenderingVisitor.java | 2 + .../java/org/teavm/interop/Structure.java | 4 +- 14 files changed, 365 insertions(+), 154 deletions(-) create mode 100644 core/src/main/java/org/teavm/wasm/intrinsics/WasmAddressIntrinsic.java create mode 100644 core/src/main/java/org/teavm/wasm/intrinsics/WasmRuntimeClassIntrinsic.java create mode 100644 core/src/main/java/org/teavm/wasm/intrinsics/WasmStructureIntrinsic.java diff --git a/core/src/main/java/org/teavm/model/ClassHolder.java b/core/src/main/java/org/teavm/model/ClassHolder.java index 9a964aae0..afe4cd296 100644 --- a/core/src/main/java/org/teavm/model/ClassHolder.java +++ b/core/src/main/java/org/teavm/model/ClassHolder.java @@ -17,15 +17,11 @@ package org.teavm.model; import java.util.*; -/** - * - * @author Alexey Andreev - */ public class ClassHolder extends ElementHolder implements ClassReader { private String parent = Object.class.getName(); - private Set interfaces = new HashSet<>(); - private Map methods = new HashMap<>(); - private Map fields = new HashMap<>(); + private Set interfaces = new LinkedHashSet<>(); + private Map methods = new LinkedHashMap<>(); + private Map fields = new LinkedHashMap<>(); private String ownerName; public ClassHolder(String name) { diff --git a/core/src/main/java/org/teavm/runtime/Allocator.java b/core/src/main/java/org/teavm/runtime/Allocator.java index e307c9f15..24ad57f25 100644 --- a/core/src/main/java/org/teavm/runtime/Allocator.java +++ b/core/src/main/java/org/teavm/runtime/Allocator.java @@ -17,6 +17,7 @@ package org.teavm.runtime; import org.teavm.interop.Address; import org.teavm.interop.StaticInit; +import org.teavm.interop.Structure; @StaticInit public final class Allocator { @@ -31,4 +32,18 @@ public final class Allocator { object.classReference = tag.toAddress().toInt() >> 3; 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; + } } diff --git a/core/src/main/java/org/teavm/runtime/RuntimeArray.java b/core/src/main/java/org/teavm/runtime/RuntimeArray.java index e53e6dd8f..1eca989c5 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeArray.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeArray.java @@ -17,5 +17,5 @@ package org.teavm.runtime; public class RuntimeArray extends RuntimeObject { public int componentClassReference; - public byte depth; + int size; } diff --git a/core/src/main/java/org/teavm/runtime/RuntimeClass.java b/core/src/main/java/org/teavm/runtime/RuntimeClass.java index 3ac164ac7..637e9af18 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeClass.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeClass.java @@ -53,5 +53,5 @@ public class RuntimeClass extends Structure { return computeCanary(size, lowerTag, upperTag); } - private static native RuntimeClass getArrayClass(); + public static native RuntimeClass getArrayClass(); } diff --git a/core/src/main/java/org/teavm/wasm/Example.java b/core/src/main/java/org/teavm/wasm/Example.java index d69bd5222..b6d64ed92 100644 --- a/core/src/main/java/org/teavm/wasm/Example.java +++ b/core/src/main/java/org/teavm/wasm/Example.java @@ -34,6 +34,12 @@ public final class Example { 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 Derived3() instanceof Base ? 1 : 0); WasmRuntime.print((Object) new Derived2() instanceof Derived1 ? 1 : 0); diff --git a/core/src/main/java/org/teavm/wasm/WasmTarget.java b/core/src/main/java/org/teavm/wasm/WasmTarget.java index d3106ba61..836d88d7a 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -30,7 +30,6 @@ import org.teavm.dependency.DependencyChecker; import org.teavm.interop.Address; import org.teavm.interop.Import; import org.teavm.interop.StaticInit; -import org.teavm.interop.Structure; import org.teavm.model.BasicBlock; import org.teavm.model.CallLocation; 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.WasmGenerator; 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.WasmStructureIntrinsic; import org.teavm.wasm.model.WasmFunction; import org.teavm.wasm.model.WasmModule; import org.teavm.wasm.model.WasmType; @@ -110,6 +112,9 @@ public class WasmTarget implements TeaVMTarget { dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate", 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, "", void.class), null).use(); } @@ -130,12 +135,18 @@ public class WasmTarget implements TeaVMTarget { return; } } + classGenerator.addArrayClass(); address = classGenerator.getAddress(); Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), new HashSet<>()); 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()); + WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator); module.setMemorySize(64); @@ -152,10 +163,6 @@ public class WasmTarget implements TeaVMTarget { } 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) { CallLocation location = new CallLocation(method.getReference()); controller.getDiagnostics().error(location, "Method {{m0}} is native but " diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java index ffb5da92a..2cc388bb9 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java @@ -47,6 +47,7 @@ public class WasmClassGenerator { private ClassReaderSource classSource; private int address; private Map binaryDataMap = new LinkedHashMap<>(); + private ClassBinaryData arrayClassData; private List initializer; private Map functions = new HashMap<>(); private List functionTable = new ArrayList<>(); @@ -81,6 +82,17 @@ public class WasmClassGenerator { contributeToInitializer(binaryData); } + public void addArrayClass() { + if (arrayClassData != null) { + return; + } + + arrayClassData = new ClassBinaryData(); + arrayClassData.start = address; + + address += RuntimeClass.VIRTUAL_TABLE_OFFSET; + } + public int getAddress() { return address; } @@ -153,6 +165,15 @@ public class WasmClassGenerator { 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) { ClassBinaryData data = binaryDataMap.get(className); return data.start < 0; diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java index 6e5aaeda1..181b814a5 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java @@ -62,7 +62,6 @@ import org.teavm.ast.UnwrapArrayExpr; import org.teavm.ast.VariableExpr; import org.teavm.ast.WhileStatement; import org.teavm.interop.Address; -import org.teavm.interop.Structure; import org.teavm.model.ClassReader; import org.teavm.model.FieldReference; 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.VirtualTableEntry; import org.teavm.runtime.Allocator; +import org.teavm.runtime.RuntimeArray; import org.teavm.runtime.RuntimeClass; import org.teavm.wasm.WasmRuntime; import org.teavm.wasm.intrinsics.WasmIntrinsic; @@ -336,7 +336,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { result, new WasmInt32Constant(16)); break; case LENGTH: - result = new WasmInt32Constant(0); + expr.getOperand().acceptVisitor(this); + result = generateArrayLength(result); break; case NOT: 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 public void visit(AssignmentStatement statement) { Expr left = statement.getLeftValue(); @@ -383,6 +392,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { } else if (left instanceof QualificationExpr) { QualificationExpr lhs = (QualificationExpr) left; storeField(lhs.getQualified(), lhs.getField(), statement.getRightValue()); + } else if (left instanceof SubscriptExpr) { + SubscriptExpr lhs = (SubscriptExpr) left; + storeArrayItem(lhs.getArray(), lhs.getIndex(), statement.getRightValue()); } else { 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 public void visit(ConditionalExpr expr) { expr.getCondition().acceptVisitor(this); @@ -488,7 +506,22 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override 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 @@ -600,15 +633,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override 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()); if (intrinsic != null) { 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 public void visit(BlockStatement statement) { WasmBlock block = new WasmBlock(false); @@ -856,16 +764,6 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { 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 public void visit(ContinueStatement statement) { IdentifiedStatement target = statement.getTarget(); @@ -877,8 +775,36 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { 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 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 diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/WasmAddressIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/WasmAddressIntrinsic.java new file mode 100644 index 000000000..e0e19028f --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/WasmAddressIntrinsic.java @@ -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()); + } + } +} diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/WasmIntrinsicManager.java b/core/src/main/java/org/teavm/wasm/intrinsics/WasmIntrinsicManager.java index 2bba2adcc..b14fabefa 100644 --- a/core/src/main/java/org/teavm/wasm/intrinsics/WasmIntrinsicManager.java +++ b/core/src/main/java/org/teavm/wasm/intrinsics/WasmIntrinsicManager.java @@ -16,6 +16,8 @@ package org.teavm.wasm.intrinsics; import org.teavm.ast.Expr; +import org.teavm.wasm.generate.WasmClassGenerator; +import org.teavm.wasm.generate.WasmGenerationContext; import org.teavm.wasm.model.expression.WasmExpression; public interface WasmIntrinsicManager { diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/WasmRuntimeClassIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/WasmRuntimeClassIntrinsic.java new file mode 100644 index 000000000..dd4b43137 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/WasmRuntimeClassIntrinsic.java @@ -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()); + } + } +} diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/WasmStructureIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/WasmStructureIntrinsic.java new file mode 100644 index 000000000..ecbd9bddd --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/WasmStructureIntrinsic.java @@ -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()); + } + } +} diff --git a/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java b/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java index 6a6ac8f00..8f8572588 100644 --- a/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java +++ b/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java @@ -448,6 +448,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { case INT8: case UINT8: append("i32.store8"); + break; case INT16: case UINT16: append("i32.store16"); @@ -469,6 +470,7 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { case INT8: case UINT8: append("i64.store8"); + break; case INT16: case UINT16: append("i64.store16"); diff --git a/interop/core/src/main/java/org/teavm/interop/Structure.java b/interop/core/src/main/java/org/teavm/interop/Structure.java index bd9507413..162c55b15 100644 --- a/interop/core/src/main/java/org/teavm/interop/Structure.java +++ b/interop/core/src/main/java/org/teavm/interop/Structure.java @@ -20,7 +20,7 @@ public class Structure { public final native Address toAddress(); - public final native int sizeOf(Class type); + public static native int sizeOf(Class type); - public final native T add(T base, int offset); + public static native T add(T base, int offset); }