From 38aca08993b98b395e4e8bc9ad86a9efb1abde07 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 12 Aug 2016 22:25:26 +0300 Subject: [PATCH] Add support for instanceof expressions --- .../java/org/teavm/runtime/RuntimeArray.java | 21 ++++++ .../java/org/teavm/runtime/RuntimeClass.java | 19 +++--- .../src/main/java/org/teavm/wasm/Example.java | 6 ++ .../main/java/org/teavm/wasm/WasmTarget.java | 2 +- .../wasm/generate/WasmGenerationContext.java | 10 ++- .../wasm/generate/WasmGenerationVisitor.java | 64 +++++++++++++++++-- 6 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 core/src/main/java/org/teavm/runtime/RuntimeArray.java diff --git a/core/src/main/java/org/teavm/runtime/RuntimeArray.java b/core/src/main/java/org/teavm/runtime/RuntimeArray.java new file mode 100644 index 000000000..e53e6dd8f --- /dev/null +++ b/core/src/main/java/org/teavm/runtime/RuntimeArray.java @@ -0,0 +1,21 @@ +/* + * 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.runtime; + +public class RuntimeArray extends RuntimeObject { + public int componentClassReference; + public byte depth; +} diff --git a/core/src/main/java/org/teavm/runtime/RuntimeClass.java b/core/src/main/java/org/teavm/runtime/RuntimeClass.java index b7b4b84ca..3ac164ac7 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeClass.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeClass.java @@ -29,15 +29,14 @@ public class RuntimeClass extends Structure { public static int CANARY_OFFSET = 24; public static int VIRTUAL_TABLE_OFFSET = 28; - public static int ARRAY_CLASS = -1; - public static int BOOLEAN_CLASS = -2; - public static int BYTE_CLASS = -3; - public static int SHORT_CLASS = -4; - public static int CHAR_CLASS = -5; - public static int INT_CLASS = -6; - public static int LONG_CLASS = -7; - public static int FLOAT_CLASS = -8; - public static int DOUBLE_CLASS = -9; + public static int BOOLEAN_CLASS = -1; + public static int BYTE_CLASS = -2; + public static int SHORT_CLASS = -3; + public static int CHAR_CLASS = -4; + public static int INT_CLASS = -5; + public static int LONG_CLASS = -6; + public static int FLOAT_CLASS = -7; + public static int DOUBLE_CLASS = -8; public int size; public int flags; @@ -53,4 +52,6 @@ public class RuntimeClass extends Structure { public int computeCanary() { return computeCanary(size, lowerTag, upperTag); } + + private 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 cb562f902..d69bd5222 100644 --- a/core/src/main/java/org/teavm/wasm/Example.java +++ b/core/src/main/java/org/teavm/wasm/Example.java @@ -33,6 +33,12 @@ public final class Example { for (int i = 0; i < 4; ++i) { WasmRuntime.print(instance(i).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); + WasmRuntime.print((Object) new Derived2() instanceof A ? 1 : 0); + WasmRuntime.print(new A(23) instanceof Base ? 1 : 0); } private static Base instance(int index) { diff --git a/core/src/main/java/org/teavm/wasm/WasmTarget.java b/core/src/main/java/org/teavm/wasm/WasmTarget.java index dacf1ba22..d3106ba61 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -134,7 +134,7 @@ public class WasmTarget implements TeaVMTarget { Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), new HashSet<>()); - WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider); + WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider, tagRegistry); context.addIntrinsic(new WasmRuntimeIntrinsic()); WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator); diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java index a0c3fd033..7e2ad5956 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java @@ -29,19 +29,23 @@ import org.teavm.model.FieldReference; import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; +import org.teavm.model.classes.TagRegistry; import org.teavm.model.classes.VirtualTableProvider; import org.teavm.wasm.intrinsics.WasmIntrinsic; public class WasmGenerationContext { private ClassReaderSource classSource; private VirtualTableProvider vtableProvider; + private TagRegistry tagRegistry; private Map importedMethods = new HashMap<>(); private List intrinsics = new ArrayList<>(); private Map intrinsicCache = new HashMap<>(); - public WasmGenerationContext(ClassReaderSource classSource, VirtualTableProvider vtableProvider) { + public WasmGenerationContext(ClassReaderSource classSource, VirtualTableProvider vtableProvider, + TagRegistry tagRegistry) { this.classSource = classSource; this.vtableProvider = vtableProvider; + this.tagRegistry = tagRegistry; } public void addIntrinsic(WasmIntrinsic intrinsic) { @@ -93,6 +97,10 @@ public class WasmGenerationContext { return vtableProvider; } + public TagRegistry getTagRegistry() { + return tagRegistry; + } + public class ImportedMethod { public final String name; public final String module; 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 eceab771e..6e5aaeda1 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java @@ -16,8 +16,11 @@ package org.teavm.wasm.generate; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import org.teavm.ast.AssignmentStatement; @@ -65,6 +68,7 @@ import org.teavm.model.FieldReference; import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; 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.RuntimeClass; @@ -631,13 +635,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { block.getBody().add(new WasmSetLocal(instanceVar, instance)); instance = new WasmGetLocal(instanceVar); - WasmExpression classIndex = new WasmLoadInt32(4, instance, WasmInt32Subtype.INT32); - classIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classIndex, - new WasmInt32Constant(3)); - VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod()); WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, - classIndex, new WasmInt32Constant(vtableEntry.getIndex() * 4 + getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4 + RuntimeClass.VIRTUAL_TABLE_OFFSET)); methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32); @@ -897,7 +897,55 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(InstanceOfExpr expr) { + expr.getExpr().acceptVisitor(this); + if (expr.getType() instanceof ValueType.Object) { + ValueType.Object cls = (ValueType.Object) expr.getType(); + List ranges = context.getTagRegistry().getRanges(cls.getClassName()); + Collections.sort(ranges, Comparator.comparingInt(range -> range.lower)); + + WasmBlock block = new WasmBlock(false); + WasmLocal tagVar = function.getLocalVariables().get(getTemporaryInt32()); + WasmExpression tagPtr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, + getReferenceToClass(result), new WasmInt32Constant(RuntimeClass.LOWER_TAG_OFFSET)); + block.getBody().add(new WasmSetLocal(tagVar, new WasmLoadInt32(4, tagPtr, WasmInt32Subtype.INT32))); + + WasmExpression lowerThanMinCond = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED, + new WasmGetLocal(tagVar), new WasmInt32Constant(ranges.get(0).lower)); + WasmBranch lowerThanMin = new WasmBranch(lowerThanMinCond, block); + lowerThanMin.setResult(new WasmInt32Constant(0)); + block.getBody().add(lowerThanMin); + + WasmExpression upperThanMaxCond = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GT_SIGNED, + new WasmGetLocal(tagVar), new WasmInt32Constant(ranges.get(ranges.size() - 1).upper)); + WasmBranch upperThanMax = new WasmBranch(upperThanMaxCond, block); + upperThanMax.setResult(new WasmInt32Constant(0)); + block.getBody().add(upperThanMax); + + for (int i = 1; i < ranges.size(); ++i) { + WasmExpression upperThanExcluded = new WasmIntBinary(WasmIntType.INT32, + WasmIntBinaryOperation.GT_SIGNED, new WasmGetLocal(tagVar), + new WasmInt32Constant(ranges.get(i - 1).upper)); + WasmConditional conditional = new WasmConditional(upperThanExcluded); + WasmExpression lowerThanExluded = new WasmIntBinary(WasmIntType.INT32, + WasmIntBinaryOperation.LT_SIGNED, new WasmGetLocal(tagVar), + new WasmInt32Constant(ranges.get(i).lower)); + + WasmBranch branch = new WasmBranch(lowerThanExluded, block); + branch.setResult(new WasmInt32Constant(0)); + conditional.getThenBlock().getBody().add(branch); + + block.getBody().add(conditional); + } + + block.getBody().add(new WasmInt32Constant(1)); + + result = block; + } else if (expr.getType() instanceof ValueType.Array) { + + } else { + throw new AssertionError(); + } } @Override @@ -1075,4 +1123,10 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { } return temporaryInt32; } + + private WasmExpression getReferenceToClass(WasmExpression instance) { + WasmExpression classIndex = new WasmLoadInt32(4, instance, WasmInt32Subtype.INT32); + return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, classIndex, + new WasmInt32Constant(3)); + } }