Further development of WASM backend

This commit is contained in:
Alexey Andreev 2016-08-19 18:43:23 +03:00
parent b83c33bcc6
commit 3f02cad9e7
18 changed files with 417 additions and 69 deletions

View File

@ -26,16 +26,9 @@ import org.teavm.platform.PlatformClass;
import org.teavm.platform.metadata.ClassResource;
import org.teavm.platform.metadata.ClassScopedMetadataProvider;
/**
*
* @author Alexey Andreev
* @param <T> class type.
*/
public class TClass<T> extends TObject implements TAnnotatedElement {
TString name;
TString simpleName;
private TClass<?> componentType;
private boolean componentTypeDirty = true;
private PlatformClass platformClass;
private TAnnotation[] annotationsCache;
private Map<TClass<?>, TAnnotation> annotationsByType;
@ -112,17 +105,7 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
}
public TClass<?> getComponentType() {
if (componentTypeDirty) {
PlatformClass arrayItem = platformClass.getMetadata().getArrayItem();
componentType = arrayItem != null ? getClass(arrayItem) : null;
componentTypeDirty = false;
}
return componentType;
}
@SuppressWarnings("unchecked")
static TClass<TVoid> voidClass() {
return (TClass<TVoid>) getClass(Platform.getPrimitives().getVoidClass());
return getClass(platformClass.getMetadata().getArrayItem());
}
@SuppressWarnings("unchecked")
@ -145,11 +128,6 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
return (TClass<TShort>) getClass(Platform.getPrimitives().getShortClass());
}
@SuppressWarnings("unchecked")
static TClass<TInteger> intClass() {
return (TClass<TInteger>) getClass(Platform.getPrimitives().getIntClass());
}
@SuppressWarnings("unchecked")
static TClass<TLong> longClass() {
return (TClass<TLong>) getClass(Platform.getPrimitives().getLongClass());

View File

@ -15,15 +15,11 @@
*/
package org.teavm.classlib.java.lang;
/**
*
* @author Alexey Andreev
*/
public class TInteger extends TNumber implements TComparable<TInteger> {
public static final int SIZE = 32;
public static final int MIN_VALUE = 0x80000000;
public static final int MAX_VALUE = 0x7FFFFFFF;
public static final TClass<TInteger> TYPE = TClass.intClass();
public static final Class<Integer> TYPE = int.class;
private static TInteger[] integerCache;
private int value;

View File

@ -15,10 +15,6 @@
*/
package org.teavm.classlib.java.lang;
/**
*
* @author Alexey Andreev
*/
public final class TVoid extends TObject {
public static final TClass<TVoid> TYPE = TClass.voidClass();
public static final Class<Void> TYPE = void.class;
}

View File

@ -15,11 +15,9 @@
*/
package org.teavm.runtime;
import org.teavm.interop.Structure;
public class RuntimeClass extends Structure {
public class RuntimeClass extends RuntimeJavaObject {
public static int INITIALIZED = 1;
public static int PRIMITIVE = 1;
public static int PRIMITIVE = 2;
public int size;
public int flags;

View File

@ -15,6 +15,10 @@
*/
package org.teavm.wasm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public final class Example {
private Example() {
}
@ -66,6 +70,14 @@ public final class Example {
WasmRuntime.print(o.hashCode());
WasmRuntime.print(new Object().hashCode());
WasmRuntime.print(new Object().hashCode());
/*List<Integer> list = new ArrayList<>(Arrays.asList(333, 444, 555));
list.add(1234);
list.remove(444);
for (int item : list) {
WasmRuntime.print(item);
}*/
}
private static Base instance(int index) {

View File

@ -27,6 +27,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.teavm.ast.decompilation.Decompiler;
import org.teavm.dependency.ClassDependency;
import org.teavm.dependency.DependencyChecker;
import org.teavm.interop.Address;
import org.teavm.interop.Import;
@ -37,6 +38,7 @@ import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReader;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReader;
import org.teavm.model.FieldReference;
import org.teavm.model.Instruction;
import org.teavm.model.ListableClassHolderSource;
@ -52,7 +54,10 @@ import org.teavm.model.classes.VirtualTableProvider;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.runtime.Allocator;
import org.teavm.runtime.RuntimeArray;
import org.teavm.runtime.RuntimeClass;
import org.teavm.runtime.RuntimeJavaObject;
import org.teavm.runtime.RuntimeObject;
import org.teavm.vm.BuildTarget;
import org.teavm.vm.TeaVM;
import org.teavm.vm.TeaVMBuilder;
@ -67,6 +72,11 @@ import org.teavm.wasm.generate.WasmGenerator;
import org.teavm.wasm.generate.WasmMangling;
import org.teavm.wasm.generate.WasmStringPool;
import org.teavm.wasm.intrinsics.AllocatorIntrinsic;
import org.teavm.wasm.intrinsics.ClassIntrinsic;
import org.teavm.wasm.intrinsics.PlatformClassIntrinsic;
import org.teavm.wasm.intrinsics.PlatformClassMetadataIntrinsic;
import org.teavm.wasm.intrinsics.PlatformIntrinsic;
import org.teavm.wasm.intrinsics.PlatformObjectIntrinsic;
import org.teavm.wasm.intrinsics.WasmAddressIntrinsic;
import org.teavm.wasm.intrinsics.WasmRuntimeIntrinsic;
import org.teavm.wasm.intrinsics.WasmStructureIntrinsic;
@ -86,6 +96,7 @@ import org.teavm.wasm.model.expression.WasmIntType;
import org.teavm.wasm.model.expression.WasmLoadInt32;
import org.teavm.wasm.model.expression.WasmReturn;
import org.teavm.wasm.model.expression.WasmStoreInt32;
import org.teavm.wasm.patches.ClassPatch;
import org.teavm.wasm.patches.ObjectPatch;
import org.teavm.wasm.render.WasmRenderer;
@ -111,6 +122,7 @@ public class WasmTarget implements TeaVMTarget {
public List<ClassHolderTransformer> getTransformers() {
List<ClassHolderTransformer> transformers = new ArrayList<>();
transformers.add(new ObjectPatch());
transformers.add(new ClassPatch());
return transformers;
}
@ -138,6 +150,17 @@ public class WasmTarget implements TeaVMTarget {
dependencyChecker.linkMethod(new MethodReference(Allocator.class, "<clinit>", void.class), null).use();
dependencyChecker.linkField(new FieldReference("java.lang.Object", "monitor"), null);
ClassDependency runtimeClassDep = dependencyChecker.linkClass(RuntimeClass.class.getName(), null);
ClassDependency runtimeObjectDep = dependencyChecker.linkClass(RuntimeObject.class.getName(), null);
ClassDependency runtimeJavaObjectDep = dependencyChecker.linkClass(RuntimeJavaObject.class.getName(), null);
ClassDependency runtimeArrayDep = dependencyChecker.linkClass(RuntimeArray.class.getName(), null);
for (ClassDependency classDep : Arrays.asList(runtimeClassDep, runtimeObjectDep, runtimeJavaObjectDep,
runtimeArrayDep)) {
for (FieldReader field : classDep.getClassReader().getFields()) {
dependencyChecker.linkField(field.getReference(), null);
}
}
}
@Override
@ -154,12 +177,18 @@ public class WasmTarget implements TeaVMTarget {
Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(),
new HashSet<>());
WasmStringPool stringPool = new WasmStringPool(classGenerator, binaryWriter);
WasmGenerationContext context = new WasmGenerationContext(classes, vtableProvider, tagRegistry, stringPool);
WasmGenerationContext context = new WasmGenerationContext(classes, controller.getDiagnostics(),
vtableProvider, tagRegistry, stringPool);
context.addIntrinsic(new WasmAddressIntrinsic());
context.addIntrinsic(new WasmStructureIntrinsic(classGenerator));
context.addIntrinsic(new WasmRuntimeIntrinsic());
context.addIntrinsic(new AllocatorIntrinsic());
context.addIntrinsic(new PlatformIntrinsic());
context.addIntrinsic(new PlatformClassIntrinsic());
context.addIntrinsic(new PlatformClassMetadataIntrinsic());
context.addIntrinsic(new PlatformObjectIntrinsic(classGenerator));
context.addIntrinsic(new ClassIntrinsic());
WasmGenerator generator = new WasmGenerator(decompiler, classes, context, classGenerator);
@ -180,7 +209,7 @@ public class WasmTarget implements TeaVMTarget {
if (context.getImportedMethod(method.getReference()) == null) {
CallLocation location = new CallLocation(method.getReference());
controller.getDiagnostics().error(location, "Method {{m0}} is native but "
+ "has no {{c1}} annotation on it", method.getReference(), Import.class);
+ "has no {{c1}} annotation on it", method.getReference(), Import.class.getName());
}
module.add(generator.generateNative(method.getReference()));
continue;
@ -195,6 +224,8 @@ public class WasmTarget implements TeaVMTarget {
}
}
classGenerator.postProcess();
WasmMemorySegment dataSegment = new WasmMemorySegment();
dataSegment.setData(binaryWriter.getData());
dataSegment.setOffset(256);

View File

@ -52,8 +52,12 @@ public class WasmClassGenerator {
private List<String> functionTable = new ArrayList<>();
private VirtualTableProvider vtableProvider;
private TagRegistry tagRegistry;
private DataStructure objectStructure = new DataStructure((byte) 0,
DataPrimitives.INT, /* class */
DataPrimitives.ADDRESS /* monitor/hash code */);
private DataStructure classStructure = new DataStructure(
(byte) 8,
objectStructure,
DataPrimitives.INT, /* size */
DataPrimitives.INT, /* flags */
DataPrimitives.INT, /* tag */
@ -119,18 +123,18 @@ public class WasmClassGenerator {
binaryData.size = 4;
binaryData.data = classStructure.createValue();
binaryData.data.setInt(0, 4);
binaryData.data.setAddress(4, itemBinaryData.start);
binaryData.data.setInt(1, 4);
binaryData.data.setAddress(5, itemBinaryData.start);
binaryData.start = binaryWriter.append(binaryData.data);
itemBinaryData.data.setAddress(5, binaryData.start);
itemBinaryData.data.setAddress(6, binaryData.start);
}
}
private DataValue createPrimitiveClassData(int size) {
DataValue value = classStructure.createValue();
value.setInt(0, size);
value.setInt(1, RuntimeClass.PRIMITIVE);
value.setInt(1, size);
value.setInt(2, RuntimeClass.PRIMITIVE);
return value;
}
@ -150,11 +154,11 @@ public class WasmClassGenerator {
DataValue header = wrapper.getValue(0);
binaryData.data = header;
header.setInt(0, binaryData.size);
header.setInt(1, binaryData.size);
List<TagRegistry.Range> ranges = tagRegistry.getRanges(name);
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
header.setInt(2, tag);
header.setInt(3, RuntimeClass.computeCanary(binaryData.size, tag));
header.setInt(3, tag);
header.setInt(4, RuntimeClass.computeCanary(binaryData.size, tag));
if (vtable == null) {
return header;
}
@ -282,6 +286,18 @@ public class WasmClassGenerator {
return 4;
}
public void postProcess() {
ClassBinaryData classClassData = binaryDataMap.get(ValueType.object("java.lang.Class"));
if (classClassData != null) {
int tag = classClassData.start >> 3;
for (ClassBinaryData classData : binaryDataMap.values()) {
if (classData.data != null) {
classData.data.getValue(0).setInt(0, tag);
}
}
}
}
public boolean hasClinit(String className) {
if (isStructure(className)) {
return false;

View File

@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.Import;
import org.teavm.model.AnnotationReader;
import org.teavm.model.AnnotationValue;
@ -31,12 +32,11 @@ 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.binary.BinaryWriter;
import org.teavm.wasm.intrinsics.WasmIntrinsic;
import org.teavm.wasm.model.expression.WasmExpression;
public class WasmGenerationContext {
private ClassReaderSource classSource;
private Diagnostics diagnostics;
private VirtualTableProvider vtableProvider;
private TagRegistry tagRegistry;
private WasmStringPool stringPool;
@ -44,9 +44,10 @@ public class WasmGenerationContext {
private List<WasmIntrinsic> intrinsics = new ArrayList<>();
private Map<MethodReference, WasmIntrinsic> intrinsicCache = new HashMap<>();
public WasmGenerationContext(ClassReaderSource classSource, VirtualTableProvider vtableProvider,
TagRegistry tagRegistry, WasmStringPool stringPool) {
public WasmGenerationContext(ClassReaderSource classSource, Diagnostics diagnostics,
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, WasmStringPool stringPool) {
this.classSource = classSource;
this.diagnostics = diagnostics;
this.vtableProvider = vtableProvider;
this.tagRegistry = tagRegistry;
this.stringPool = stringPool;
@ -109,6 +110,10 @@ public class WasmGenerationContext {
return stringPool;
}
public Diagnostics getDiagnostics() {
return diagnostics;
}
public class ImportedMethod {
public final String name;
public final String module;

View File

@ -62,7 +62,9 @@ import org.teavm.ast.UnwrapArrayExpr;
import org.teavm.ast.VariableExpr;
import org.teavm.ast.WhileStatement;
import org.teavm.interop.Address;
import org.teavm.model.CallLocation;
import org.teavm.model.FieldReference;
import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.classes.TagRegistry;
@ -115,6 +117,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private WasmGenerationContext context;
private WasmClassGenerator classGenerator;
private WasmFunction function;
private MethodReference method;
private int firstVariable;
private IdentifiedStatement currentContinueTarget;
private IdentifiedStatement currentBreakTarget;
@ -125,10 +128,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
WasmExpression result;
WasmGenerationVisitor(WasmGenerationContext context, WasmClassGenerator classGenerator,
WasmFunction function, int firstVariable) {
WasmFunction function, MethodReference method, int firstVariable) {
this.context = context;
this.classGenerator = classGenerator;
this.function = function;
this.method = method;
this.firstVariable = firstVariable;
}
@ -759,9 +763,22 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
block.getBody().add(new WasmSetLocal(instanceVar, instance));
instance = new WasmGetLocal(instanceVar);
int vtableOffset = classGenerator.getClassSize(RuntimeClass.class.getName());
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod());
if (vtableEntry == null) {
result = new WasmInt32Constant(0);
InstructionLocation insnLocation = null;
if (expr.getLocation() != null) {
insnLocation = new InstructionLocation(expr.getLocation().getFileName(),
expr.getLocation().getLine());
}
CallLocation location = new CallLocation(method, insnLocation);
context.getDiagnostics().error(location, "Can't generate WebAssembly to call {{m0}} method",
expr.getMethod());
return;
}
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4 + 24));
getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4 + vtableOffset));
methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32);
WasmIndirectCall call = new WasmIndirectCall(methodIndex);

View File

@ -28,6 +28,7 @@ import org.teavm.model.ValueType;
import org.teavm.runtime.RuntimeClass;
import org.teavm.wasm.model.WasmFunction;
import org.teavm.wasm.model.WasmLocal;
import org.teavm.wasm.model.WasmType;
import org.teavm.wasm.model.expression.WasmCall;
import org.teavm.wasm.model.expression.WasmConditional;
import org.teavm.wasm.model.expression.WasmExpression;
@ -61,7 +62,10 @@ public class WasmGenerator {
int firstVariable = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
for (int i = firstVariable; i < methodAst.getVariables().size(); ++i) {
VariableNode variable = methodAst.getVariables().get(i);
function.add(new WasmLocal(WasmGeneratorUtil.mapType(variable.getType())));
WasmType type = variable.getType() != null
? WasmGeneratorUtil.mapType(variable.getType())
: WasmType.INT32;
function.add(new WasmLocal(type));
}
for (int i = firstVariable; i <= methodReference.parameterCount(); ++i) {
@ -85,7 +89,8 @@ public class WasmGenerator {
function.getBody().add(conditional);
}
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function, firstVariable);
WasmGenerationVisitor visitor = new WasmGenerationVisitor(context, classGenerator, function, methodReference,
firstVariable);
methodAst.getBody().acceptVisitor(visitor);
function.getBody().add(visitor.result);

View File

@ -0,0 +1,43 @@
/*
* 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.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.wasm.model.expression.WasmExpression;
public class ClassIntrinsic implements WasmIntrinsic {
@Override
public boolean isApplicable(MethodReference methodReference) {
return methodReference.getClassName().equals("java.lang.Class")
&& isApplicableToMethod(methodReference.getDescriptor());
}
private boolean isApplicableToMethod(MethodDescriptor method) {
return method.getName().equals("getClass") && method.parameterCount() == 1;
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) {
case "getClass":
return manager.generate(invocation.getArguments().get(0));
default:
throw new IllegalArgumentException(invocation.getMethod().toString());
}
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.wasm.model.expression.WasmBlock;
import org.teavm.wasm.model.expression.WasmExpression;
public class PlatformClassIntrinsic implements WasmIntrinsic {
private static final String PLATFORM_CLASS_NAME = "org.teavm.platform.PlatformClass";
@Override
public boolean isApplicable(MethodReference methodReference) {
return methodReference.getClassName().equals(PLATFORM_CLASS_NAME);
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) {
case "getMetadata":
case "getJavaClass":
return manager.generate(invocation.getArguments().get(0));
case "setJavaClass":
return new WasmBlock(false);
default:
throw new IllegalArgumentException(invocation.getMethod().toString());
}
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.ast.QualificationExpr;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
import org.teavm.runtime.RuntimeClass;
import org.teavm.wasm.model.expression.WasmExpression;
public class PlatformClassMetadataIntrinsic implements WasmIntrinsic {
private static final String PLATFORM_CLASS_METADATA_NAME = "org.teavm.platform.PlatformClassMetadata";
@Override
public boolean isApplicable(MethodReference methodReference) {
return methodReference.getClassName().equals(PLATFORM_CLASS_METADATA_NAME);
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) {
case "getArrayItem": {
QualificationExpr expr = new QualificationExpr();
expr.setQualified(invocation.getArguments().get(0));
expr.setField(new FieldReference(RuntimeClass.class.getName(), "itemType"));
expr.setLocation(invocation.getLocation());
return manager.generate(expr);
}
default:
throw new IllegalArgumentException(invocation.getMethod().toString());
}
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.wasm.model.expression.WasmExpression;
public class PlatformIntrinsic implements WasmIntrinsic {
private static final String PLATFORM = "org.teavm.platform.Platform";
@Override
public boolean isApplicable(MethodReference methodReference) {
return methodReference.getClassName().equals(PLATFORM);
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) {
case "getPlatformObject":
case "asJavaClass":
return manager.generate(invocation.getArguments().get(0));
default:
throw new IllegalArgumentException(invocation.getMethod().toString());
}
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.FieldReference;
import org.teavm.model.MethodReference;
import org.teavm.runtime.RuntimeObject;
import org.teavm.wasm.generate.WasmClassGenerator;
import org.teavm.wasm.model.expression.WasmExpression;
import org.teavm.wasm.model.expression.WasmInt32Constant;
import org.teavm.wasm.model.expression.WasmInt32Subtype;
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.WasmLoadInt32;
public class PlatformObjectIntrinsic implements WasmIntrinsic {
private static final String PLATFORM_OBJECT = "org.teavm.platform.PlatformObject";
private static final FieldReference classField = new FieldReference(RuntimeObject.class.getName(),
"classReference");
private WasmClassGenerator classGenerator;
public PlatformObjectIntrinsic(WasmClassGenerator classGenerator) {
this.classGenerator = classGenerator;
}
@Override
public boolean isApplicable(MethodReference methodReference) {
return methodReference.getClassName().equals(PLATFORM_OBJECT);
}
@Override
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
switch (invocation.getMethod().getName()) {
case "getPlatformClass": {
int offset = classGenerator.getFieldOffset(classField);
WasmExpression object = manager.generate(invocation.getArguments().get(0));
if (offset > 0) {
object = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, object,
new WasmInt32Constant(offset));
}
WasmExpression classPtr = new WasmLoadInt32(4, object, WasmInt32Subtype.INT32);
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL,
classPtr, new WasmInt32Constant(3));
}
default:
throw new IllegalArgumentException(invocation.getMethod().toString());
}
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.patches;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.BasicBlock;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.FieldReference;
import org.teavm.model.Instruction;
import org.teavm.model.MethodHolder;
import org.teavm.model.Program;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.EmptyInstruction;
import org.teavm.model.instructions.GetFieldInstruction;
import org.teavm.model.instructions.PutFieldInstruction;
public class ClassPatch implements ClassHolderTransformer {
private FieldReference platformClassField = new FieldReference("java.lang.Class", "platformClass");
@Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
if (!cls.getName().equals("java.lang.Class")) {
return;
}
for (MethodHolder method : cls.getMethods()) {
patchProgram(method.getProgram());
}
}
private void patchProgram(Program program) {
for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlock block = program.basicBlockAt(i);
for (int j = 0; j < block.getInstructions().size(); ++j) {
Instruction instruction = block.getInstructions().get(j);
if (instruction instanceof GetFieldInstruction) {
GetFieldInstruction getField = (GetFieldInstruction) instruction;
if (getField.getField().equals(platformClassField)) {
AssignInstruction replacement = new AssignInstruction();
replacement.setReceiver(getField.getReceiver());
replacement.setAssignee(getField.getInstance());
replacement.setLocation(instruction.getLocation());
block.getInstructions().set(j, replacement);
}
} else if (instruction instanceof PutFieldInstruction) {
PutFieldInstruction putField = (PutFieldInstruction) instruction;
if (putField.getField().equals(platformClassField)) {
EmptyInstruction replacement = new EmptyInstruction();
replacement.setLocation(instruction.getLocation());
block.getInstructions().set(j, replacement);
}
}
}
}
}
}

View File

@ -18,10 +18,6 @@ package org.teavm.platform;
import org.teavm.jso.JSObject;
import org.teavm.jso.JSProperty;
/**
*
* @author Alexey Andreev
*/
public interface PlatformClass extends JSObject {
@JSProperty("$meta")
PlatformClassMetadata getMetadata();

View File

@ -18,14 +18,7 @@ package org.teavm.platform;
import org.teavm.jso.JSMethod;
import org.teavm.jso.JSObject;
/**
*
* @author Alexey Andreev
*/
public interface PlatformPrimitives extends JSObject {
@JSMethod("$rt_voidcls")
PlatformClass getVoidClass();
@JSMethod("$rt_booleancls")
PlatformClass getBooleanClass();
@ -38,9 +31,6 @@ public interface PlatformPrimitives extends JSObject {
@JSMethod("$rt_charcls")
PlatformClass getCharClass();
@JSMethod("$rt_intcls")
PlatformClass getIntClass();
@JSMethod("$rt_longcls")
PlatformClass getLongClass();