diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 3e8ef824b..75f7c82de 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -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 class type. - */ public class TClass extends TObject implements TAnnotatedElement { TString name; TString simpleName; - private TClass componentType; - private boolean componentTypeDirty = true; private PlatformClass platformClass; private TAnnotation[] annotationsCache; private Map, TAnnotation> annotationsByType; @@ -112,17 +105,7 @@ public class TClass 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 voidClass() { - return (TClass) getClass(Platform.getPrimitives().getVoidClass()); + return getClass(platformClass.getMetadata().getArrayItem()); } @SuppressWarnings("unchecked") @@ -145,11 +128,6 @@ public class TClass extends TObject implements TAnnotatedElement { return (TClass) getClass(Platform.getPrimitives().getShortClass()); } - @SuppressWarnings("unchecked") - static TClass intClass() { - return (TClass) getClass(Platform.getPrimitives().getIntClass()); - } - @SuppressWarnings("unchecked") static TClass longClass() { return (TClass) getClass(Platform.getPrimitives().getLongClass()); diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java index 5ff399c0f..439ab3c7a 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java @@ -15,15 +15,11 @@ */ package org.teavm.classlib.java.lang; -/** - * - * @author Alexey Andreev - */ public class TInteger extends TNumber implements TComparable { public static final int SIZE = 32; public static final int MIN_VALUE = 0x80000000; public static final int MAX_VALUE = 0x7FFFFFFF; - public static final TClass TYPE = TClass.intClass(); + public static final Class TYPE = int.class; private static TInteger[] integerCache; private int value; diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TVoid.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TVoid.java index 7d2b75c31..51a2964c0 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TVoid.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TVoid.java @@ -15,10 +15,6 @@ */ package org.teavm.classlib.java.lang; -/** - * - * @author Alexey Andreev - */ public final class TVoid extends TObject { - public static final TClass TYPE = TClass.voidClass(); + public static final Class TYPE = void.class; } diff --git a/core/src/main/java/org/teavm/runtime/RuntimeClass.java b/core/src/main/java/org/teavm/runtime/RuntimeClass.java index 0e8301676..0dd37e943 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeClass.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeClass.java @@ -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; diff --git a/core/src/main/java/org/teavm/wasm/Example.java b/core/src/main/java/org/teavm/wasm/Example.java index 8f29dd39d..a056cdfc9 100644 --- a/core/src/main/java/org/teavm/wasm/Example.java +++ b/core/src/main/java/org/teavm/wasm/Example.java @@ -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 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) { diff --git a/core/src/main/java/org/teavm/wasm/WasmTarget.java b/core/src/main/java/org/teavm/wasm/WasmTarget.java index dfc73d73f..ea16a4649 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -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 getTransformers() { List 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, "", 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); 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 c04da4efc..3be1beb81 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmClassGenerator.java @@ -52,8 +52,12 @@ public class WasmClassGenerator { private List 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 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; 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 dc6811263..cee817eef 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationContext.java @@ -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 intrinsics = new ArrayList<>(); private Map 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; 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 ca8ec3b7e..9847d9d30 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,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); diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java b/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java index 7413748dd..934379881 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java @@ -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); diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/ClassIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/ClassIntrinsic.java new file mode 100644 index 000000000..e35d56450 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/ClassIntrinsic.java @@ -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()); + } + } +} diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/PlatformClassIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/PlatformClassIntrinsic.java new file mode 100644 index 000000000..73101d718 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/PlatformClassIntrinsic.java @@ -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()); + } + } +} diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/PlatformClassMetadataIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/PlatformClassMetadataIntrinsic.java new file mode 100644 index 000000000..41ce79004 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/PlatformClassMetadataIntrinsic.java @@ -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()); + } + } +} diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/PlatformIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/PlatformIntrinsic.java new file mode 100644 index 000000000..b1bdefca4 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/PlatformIntrinsic.java @@ -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()); + } + } +} diff --git a/core/src/main/java/org/teavm/wasm/intrinsics/PlatformObjectIntrinsic.java b/core/src/main/java/org/teavm/wasm/intrinsics/PlatformObjectIntrinsic.java new file mode 100644 index 000000000..3f25f8273 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/intrinsics/PlatformObjectIntrinsic.java @@ -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()); + } + } +} diff --git a/core/src/main/java/org/teavm/wasm/patches/ClassPatch.java b/core/src/main/java/org/teavm/wasm/patches/ClassPatch.java new file mode 100644 index 000000000..16b979a63 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/patches/ClassPatch.java @@ -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); + } + } + } + } + } +} diff --git a/platform/src/main/java/org/teavm/platform/PlatformClass.java b/platform/src/main/java/org/teavm/platform/PlatformClass.java index ab434192e..b469b87cb 100644 --- a/platform/src/main/java/org/teavm/platform/PlatformClass.java +++ b/platform/src/main/java/org/teavm/platform/PlatformClass.java @@ -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(); diff --git a/platform/src/main/java/org/teavm/platform/PlatformPrimitives.java b/platform/src/main/java/org/teavm/platform/PlatformPrimitives.java index 3e338b521..402f1a616 100644 --- a/platform/src/main/java/org/teavm/platform/PlatformPrimitives.java +++ b/platform/src/main/java/org/teavm/platform/PlatformPrimitives.java @@ -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();