Add support for array of objects

This commit is contained in:
Alexey Andreev 2016-08-12 23:38:29 +03:00
parent 38aca08993
commit 421eca8a49
14 changed files with 365 additions and 154 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 "

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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