Add support for instanceof expressions

This commit is contained in:
Alexey Andreev 2016-08-12 22:25:26 +03:00
parent 1aacbea4d0
commit 38aca08993
6 changed files with 106 additions and 16 deletions

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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) {

View File

@ -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);

View File

@ -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<MethodReference, ImportedMethod> importedMethods = new HashMap<>();
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
private Map<MethodReference, WasmIntrinsic> 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;

View File

@ -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<TagRegistry.Range> 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));
}
}