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 d83bf3a96..7afde31fe 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 @@ -21,10 +21,14 @@ import java.util.Map; import org.teavm.classlib.impl.DeclaringClassMetadataGenerator; import org.teavm.classlib.java.lang.annotation.TAnnotation; import org.teavm.classlib.java.lang.reflect.TAnnotatedElement; +import org.teavm.interop.Address; +import org.teavm.interop.DelegateTo; import org.teavm.platform.Platform; import org.teavm.platform.PlatformClass; import org.teavm.platform.metadata.ClassResource; import org.teavm.platform.metadata.ClassScopedMetadataProvider; +import org.teavm.runtime.RuntimeClass; +import org.teavm.runtime.RuntimeObject; public class TClass extends TObject implements TAnnotatedElement { TString name; @@ -93,11 +97,11 @@ public class TClass extends TObject implements TAnnotatedElement { } public boolean isPrimitive() { - return platformClass.getMetadata().isPrimitive(); + return Platform.isPrimitive(platformClass); } public boolean isArray() { - return platformClass.getMetadata().getArrayItem() != null; + return Platform.getArrayItem(platformClass) != null; } public boolean isEnum() { @@ -105,7 +109,7 @@ public class TClass extends TObject implements TAnnotatedElement { } public TClass getComponentType() { - return getClass(platformClass.getMetadata().getArrayItem()); + return getClass(Platform.getArrayItem(platformClass)); } public boolean desiredAssertionStatus() { diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java index af7e4c67f..100e18f86 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java @@ -80,7 +80,7 @@ public final class TSystem extends TObject { private static native void doArrayCopy(Object src, int srcPos, Object dest, int destPos, int length); static void doArrayCopyLowLevel(RuntimeArray src, int srcPos, RuntimeArray dest, int destPos, int length) { - RuntimeClass type = Address.fromInt(src.classReference << 3).toStructure(); + RuntimeClass type = RuntimeClass.getClass(src); int itemSize = type.itemType.size; if ((type.itemType.flags & RuntimeClass.PRIMITIVE) == 0) { itemSize = Address.sizeOf(); diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java index 1b0781a25..db4d58827 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java @@ -21,14 +21,26 @@ import org.teavm.interop.DelegateTo; import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.platform.PlatformClass; import org.teavm.runtime.Allocator; +import org.teavm.runtime.RuntimeArray; import org.teavm.runtime.RuntimeClass; import org.teavm.runtime.RuntimeObject; public final class TArray extends TObject { @GeneratedBy(ArrayNativeGenerator.class) @PluggableDependency(ArrayNativeGenerator.class) + @DelegateTo("getLengthLowLevel") public static native int getLength(TObject array) throws TIllegalArgumentException; + @SuppressWarnings("unused") + private static int getLengthLowLevel(RuntimeObject obj) { + RuntimeClass cls = RuntimeClass.getClass(obj); + if (cls.itemType == null) { + throw new TIllegalArgumentException(); + } + RuntimeArray array = (RuntimeArray) obj; + return array.size; + } + public static TObject newInstance(TClass componentType, int length) throws TNegativeArraySizeException { if (componentType == null) { throw new TNullPointerException(); diff --git a/core/src/main/java/org/teavm/backend/wasm/Example.java b/core/src/main/java/org/teavm/backend/wasm/Example.java index aad1a5e25..2cf6e3039 100644 --- a/core/src/main/java/org/teavm/backend/wasm/Example.java +++ b/core/src/main/java/org/teavm/backend/wasm/Example.java @@ -32,7 +32,7 @@ public final class Example { testLazyInitialization(); testHashCode(); testArrayList(); - //testArrayCopy(); + testArrayCopy(); } private static void testFibonacci() { diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index 73d23ced0..76679829c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -36,12 +36,12 @@ import org.teavm.backend.wasm.generate.WasmStringPool; import org.teavm.backend.wasm.intrinsics.AddressIntrinsic; import org.teavm.backend.wasm.intrinsics.AllocatorIntrinsic; import org.teavm.backend.wasm.intrinsics.ClassIntrinsic; +import org.teavm.backend.wasm.intrinsics.FunctionIntrinsic; import org.teavm.backend.wasm.intrinsics.PlatformClassIntrinsic; -import org.teavm.backend.wasm.intrinsics.PlatformClassMetadataIntrinsic; import org.teavm.backend.wasm.intrinsics.PlatformIntrinsic; import org.teavm.backend.wasm.intrinsics.PlatformObjectIntrinsic; +import org.teavm.backend.wasm.intrinsics.StructureIntrinsic; import org.teavm.backend.wasm.intrinsics.WasmRuntimeIntrinsic; -import org.teavm.backend.wasm.intrinsics.WasmStructureIntrinsic; import org.teavm.backend.wasm.model.WasmFunction; import org.teavm.backend.wasm.model.WasmMemorySegment; import org.teavm.backend.wasm.model.WasmModule; @@ -88,6 +88,7 @@ import org.teavm.model.Program; import org.teavm.model.ValueType; import org.teavm.model.classes.TagRegistry; import org.teavm.model.classes.VirtualTableProvider; +import org.teavm.model.instructions.CloneArrayInstruction; import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvokeInstruction; import org.teavm.runtime.Allocator; @@ -125,6 +126,7 @@ public class WasmTarget implements TeaVMTarget { List transformers = new ArrayList<>(); transformers.add(new ObjectPatch()); transformers.add(new ClassPatch()); + transformers.add(new WasmDependencyListener()); return transformers; } @@ -158,6 +160,8 @@ public class WasmTarget implements TeaVMTarget { Address.class, void.class), null).use(); dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "fillZero", Address.class, int.class, void.class), null).use(); + dependencyChecker.linkMethod(new MethodReference(WasmRuntime.class, "moveMemoryBlock", Address.class, + Address.class, int.class, void.class), null).use(); dependencyChecker.linkMethod(new MethodReference(Allocator.class, "allocate", RuntimeClass.class, Address.class), null).use(); @@ -188,7 +192,8 @@ public class WasmTarget implements TeaVMTarget { VirtualTableProvider vtableProvider = createVirtualTableProvider(classes); TagRegistry tagRegistry = new TagRegistry(classes); BinaryWriter binaryWriter = new BinaryWriter(256); - WasmClassGenerator classGenerator = new WasmClassGenerator(classes, vtableProvider, tagRegistry, binaryWriter); + WasmClassGenerator classGenerator = new WasmClassGenerator( + classes, vtableProvider, tagRegistry, binaryWriter); Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), new HashSet<>()); @@ -197,12 +202,12 @@ public class WasmTarget implements TeaVMTarget { vtableProvider, tagRegistry, stringPool); context.addIntrinsic(new AddressIntrinsic(classGenerator)); - context.addIntrinsic(new WasmStructureIntrinsic(classGenerator)); + context.addIntrinsic(new StructureIntrinsic(classGenerator)); + context.addIntrinsic(new FunctionIntrinsic(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()); @@ -393,6 +398,8 @@ public class WasmTarget implements TeaVMTarget { if (invoke.getType() == InvocationType.VIRTUAL) { virtualMethods.add(invoke.getMethod()); } + } else if (insn instanceof CloneArrayInstruction) { + virtualMethods.add(new MethodReference(Object.class, "clone", Object.class)); } } } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java index bea2780c6..037422ff8 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java @@ -29,6 +29,7 @@ import org.teavm.backend.wasm.binary.DataStructure; import org.teavm.backend.wasm.binary.DataType; import org.teavm.backend.wasm.binary.DataValue; import org.teavm.interop.Address; +import org.teavm.interop.Function; import org.teavm.interop.Structure; import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; @@ -63,7 +64,8 @@ public class WasmClassGenerator { DataPrimitives.INT, /* tag */ DataPrimitives.INT, /* canary */ DataPrimitives.ADDRESS, /* item type */ - DataPrimitives.ADDRESS /* array type */); + DataPrimitives.ADDRESS, /* array type */ + DataPrimitives.INT /* isInstance function */); public WasmClassGenerator(ClassReaderSource classSource, VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter) { @@ -216,10 +218,22 @@ public class WasmClassGenerator { return data.start < 0; } + public boolean isFunctionClass(String className) { + ValueType type = ValueType.object(className); + addClass(type); + return binaryDataMap.get(type).function; + } + private void calculateLayout(ClassReader cls, ClassBinaryData data) { if (cls.getName().equals(Structure.class.getName()) || cls.getName().equals(Address.class.getName())) { data.size = 0; data.start = -1; + return; + } else if (cls.getName().equals(Function.class.getName())) { + data.size = 0; + data.start = -1; + data.function = true; + return; } else if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { addClass(ValueType.object(cls.getParent())); ClassBinaryData parentData = binaryDataMap.get(ValueType.object(cls.getParent())); @@ -228,6 +242,10 @@ public class WasmClassGenerator { if (parentData.start == -1) { data.start = -1; } + if (parentData.function) { + data.function = true; + return; + } } else { data.size = 4; data.alignment = 4; @@ -328,5 +346,6 @@ public class WasmClassGenerator { int start; ObjectIntMap fieldLayout = new ObjectIntOpenHashMap<>(); DataValue data; + boolean function; } } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmDependencyListener.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmDependencyListener.java index c929edbaa..dfb21fd15 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmDependencyListener.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmDependencyListener.java @@ -18,13 +18,19 @@ package org.teavm.backend.wasm.generate; import org.teavm.dependency.AbstractDependencyListener; import org.teavm.dependency.DependencyAgent; import org.teavm.dependency.MethodDependency; +import org.teavm.diagnostics.Diagnostics; import org.teavm.interop.DelegateTo; import org.teavm.model.AnnotationReader; import org.teavm.model.CallLocation; +import org.teavm.model.ClassHolder; +import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.ElementModifier; +import org.teavm.model.MethodHolder; import org.teavm.model.MethodReader; -public class WasmDependencyListener extends AbstractDependencyListener { +public class WasmDependencyListener extends AbstractDependencyListener implements ClassHolderTransformer { @Override public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) { AnnotationReader delegateAnnot = method.getMethod().getAnnotations().get(DelegateTo.class.getName()); @@ -40,4 +46,15 @@ public class WasmDependencyListener extends AbstractDependencyListener { } } } + + @Override + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { + for (MethodHolder method : cls.getMethods()) { + AnnotationReader delegateAnnot = method.getAnnotations().get(DelegateTo.class.getName()); + if (delegateAnnot != null) { + method.setProgram(null); + method.getModifiers().add(ElementModifier.NATIVE); + } + } + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java index 0caf3b8f8..8dcbab07e 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerationVisitor.java @@ -572,6 +572,9 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { } else if (expr.getValue() instanceof String) { String str = (String) expr.getValue(); result = new WasmInt32Constant(context.getStringPool().getStringPointer(str)); + } else if (expr.getValue() instanceof ValueType) { + int pointer = classGenerator.getClassPointer((ValueType) expr.getValue()); + result = new WasmInt32Constant(pointer); } else { throw new IllegalArgumentException("Constant unsupported: " + expr.getValue()); } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java index 24ea059fa..af5d0c6d1 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmGenerator.java @@ -109,13 +109,16 @@ public class WasmGenerator { public WasmFunction generateNative(MethodReference methodReference) { WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference)); for (int i = 0; i < methodReference.parameterCount(); ++i) { - function.getParameters().add(WasmGeneratorUtil.mapType(methodReference.parameterType(i))); + WasmType paramType = WasmGeneratorUtil.mapType(methodReference.parameterType(i)); + function.getParameters().add(paramType); } WasmGenerationContext.ImportedMethod importedMethod = context.getImportedMethod(methodReference); if (importedMethod != null) { function.setImportName(importedMethod.name); function.setImportModule(importedMethod.module); + } else { + function.setImportName(""); } return function; diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/AllocatorIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/AllocatorIntrinsic.java index fa5ce0707..ae1119532 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/AllocatorIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/AllocatorIntrinsic.java @@ -27,8 +27,16 @@ import org.teavm.runtime.Allocator; public class AllocatorIntrinsic implements WasmIntrinsic { @Override public boolean isApplicable(MethodReference methodReference) { - return methodReference.getClassName().equals(Allocator.class.getName()) - && methodReference.getName().equals("fillZero"); + if (!methodReference.getClassName().equals(Allocator.class.getName())) { + return false; + } + switch (methodReference.getName()) { + case "fillZero": + case "moveMemoryBlock": + return true; + default: + return false; + } } @Override @@ -39,7 +47,8 @@ public class AllocatorIntrinsic implements WasmIntrinsic { MethodReference delegateMetod = new MethodReference(WasmRuntime.class.getName(), invocation.getMethod().getDescriptor()); WasmCall call = new WasmCall(WasmMangling.mangleMethod(delegateMetod)); - call.getArguments().addAll(invocation.getArguments().stream().map(manager::generate) + call.getArguments().addAll(invocation.getArguments().stream() + .map(manager::generate) .collect(Collectors.toList())); return call; } diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/FunctionIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/FunctionIntrinsic.java new file mode 100644 index 000000000..0326cd3b1 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/FunctionIntrinsic.java @@ -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.backend.wasm.intrinsics; + +import org.teavm.ast.InvocationExpr; +import org.teavm.backend.wasm.generate.WasmClassGenerator; +import org.teavm.backend.wasm.generate.WasmGeneratorUtil; +import org.teavm.backend.wasm.model.expression.WasmExpression; +import org.teavm.backend.wasm.model.expression.WasmIndirectCall; +import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; + +public class FunctionIntrinsic implements WasmIntrinsic { + private WasmClassGenerator classGenerator; + + public FunctionIntrinsic(WasmClassGenerator classGenerator) { + this.classGenerator = classGenerator; + } + + @Override + public boolean isApplicable(MethodReference methodReference) { + return classGenerator.isFunctionClass(methodReference.getClassName()); + } + + @Override + public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) { + WasmExpression selector = manager.generate(invocation.getArguments().get(0)); + WasmIndirectCall call = new WasmIndirectCall(selector); + + for (ValueType type : invocation.getMethod().getParameterTypes()) { + call.getParameterTypes().add(WasmGeneratorUtil.mapType(type)); + } + if (invocation.getMethod().getReturnType() != ValueType.VOID) { + call.setReturnType(WasmGeneratorUtil.mapType(invocation.getMethod().getReturnType())); + } + for (int i = 1; i < invocation.getArguments().size(); ++i) { + call.getArguments().add(manager.generate(invocation.getArguments().get(i))); + } + + return call; + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformClassMetadataIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformClassMetadataIntrinsic.java deleted file mode 100644 index 4b25e33cd..000000000 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformClassMetadataIntrinsic.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.backend.wasm.intrinsics; - -import org.teavm.ast.InvocationExpr; -import org.teavm.ast.QualificationExpr; -import org.teavm.backend.wasm.model.expression.WasmExpression; -import org.teavm.model.FieldReference; -import org.teavm.model.MethodReference; -import org.teavm.runtime.RuntimeClass; - -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/backend/wasm/intrinsics/PlatformIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformIntrinsic.java index de9444c03..ae7826cc1 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/PlatformIntrinsic.java @@ -17,6 +17,7 @@ package org.teavm.backend.wasm.intrinsics; import org.teavm.ast.InvocationExpr; import org.teavm.backend.wasm.model.expression.WasmExpression; +import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReference; public class PlatformIntrinsic implements WasmIntrinsic { @@ -24,7 +25,18 @@ public class PlatformIntrinsic implements WasmIntrinsic { @Override public boolean isApplicable(MethodReference methodReference) { - return methodReference.getClassName().equals(PLATFORM); + return methodReference.getClassName().equals(PLATFORM) + && isApplicableToMethod(methodReference.getDescriptor()); + } + + private boolean isApplicableToMethod(MethodDescriptor methodDescriptor) { + switch (methodDescriptor.getName()) { + case "getPlatformObject": + case "asJavaClass": + return true; + default: + return false; + } } @Override diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmStructureIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/StructureIntrinsic.java similarity index 84% rename from core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmStructureIntrinsic.java rename to core/src/main/java/org/teavm/backend/wasm/intrinsics/StructureIntrinsic.java index 92d6894aa..5eca87ded 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/WasmStructureIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/StructureIntrinsic.java @@ -20,21 +20,20 @@ import org.teavm.ast.InvocationExpr; import org.teavm.backend.wasm.generate.WasmClassGenerator; import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmInt32Constant; -import org.teavm.interop.Address; +import org.teavm.interop.Structure; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; -public class WasmStructureIntrinsic implements WasmIntrinsic { +public class StructureIntrinsic implements WasmIntrinsic { private WasmClassGenerator classGenerator; - public WasmStructureIntrinsic(WasmClassGenerator classGenerator) { + public StructureIntrinsic(WasmClassGenerator classGenerator) { this.classGenerator = classGenerator; } @Override public boolean isApplicable(MethodReference methodReference) { - return !methodReference.getClassName().equals(Address.class.getName()) - && classGenerator.getClassPointer(ValueType.object(methodReference.getClassName())) < 0; + return methodReference.getClassName().equals(Structure.class.getName()); } @Override diff --git a/core/src/main/java/org/teavm/runtime/IsSupertypeFunction.java b/core/src/main/java/org/teavm/runtime/IsSupertypeFunction.java new file mode 100644 index 000000000..748f286c8 --- /dev/null +++ b/core/src/main/java/org/teavm/runtime/IsSupertypeFunction.java @@ -0,0 +1,22 @@ +/* + * Copyright 2016 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.runtime; + +import org.teavm.interop.Function; + +public abstract class IsSupertypeFunction extends Function { + public abstract boolean apply(RuntimeClass superType); +} diff --git a/core/src/main/java/org/teavm/runtime/RuntimeArray.java b/core/src/main/java/org/teavm/runtime/RuntimeArray.java index d4cb7bad4..f06d15d85 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeArray.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeArray.java @@ -16,5 +16,5 @@ package org.teavm.runtime; public class RuntimeArray extends RuntimeJavaObject { - int size; + public int size; } diff --git a/core/src/main/java/org/teavm/runtime/RuntimeClass.java b/core/src/main/java/org/teavm/runtime/RuntimeClass.java index 4f2f7089f..7c638324d 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeClass.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeClass.java @@ -15,6 +15,8 @@ */ package org.teavm.runtime; +import org.teavm.interop.Address; + public class RuntimeClass extends RuntimeJavaObject { public static final int INITIALIZED = 1; public static final int PRIMITIVE = 2; @@ -25,6 +27,7 @@ public class RuntimeClass extends RuntimeJavaObject { public int canary; public RuntimeClass itemType; public RuntimeClass arrayType; + public IsSupertypeFunction isSupertypeOf; public static int computeCanary(int size, int tag) { return size ^ (tag << 8) ^ (tag >>> 24) ^ 0xAAAAAAAA; @@ -33,4 +36,8 @@ public class RuntimeClass extends RuntimeJavaObject { public int computeCanary() { return computeCanary(size, tag); } + + public static RuntimeClass getClass(RuntimeObject object) { + return Address.fromInt(object.classReference << 3).toStructure(); + } } diff --git a/interop/core/src/main/java/org/teavm/interop/Function.java b/interop/core/src/main/java/org/teavm/interop/Function.java new file mode 100644 index 000000000..74d54ff93 --- /dev/null +++ b/interop/core/src/main/java/org/teavm/interop/Function.java @@ -0,0 +1,19 @@ +/* + * 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.interop; + +public abstract class Function { +} diff --git a/platform/src/main/java/org/teavm/platform/Platform.java b/platform/src/main/java/org/teavm/platform/Platform.java index 8e0c314b3..d46b1831c 100644 --- a/platform/src/main/java/org/teavm/platform/Platform.java +++ b/platform/src/main/java/org/teavm/platform/Platform.java @@ -19,12 +19,15 @@ import java.lang.annotation.Annotation; import org.teavm.backend.javascript.spi.GeneratedBy; import org.teavm.backend.javascript.spi.InjectedBy; import org.teavm.dependency.PluggableDependency; +import org.teavm.interop.DelegateTo; import org.teavm.jso.JSBody; import org.teavm.jso.JSObject; import org.teavm.jso.browser.Window; import org.teavm.platform.metadata.ClassResource; import org.teavm.platform.metadata.StaticFieldResource; import org.teavm.platform.plugin.PlatformGenerator; +import org.teavm.runtime.RuntimeClass; +import org.teavm.runtime.RuntimeObject; public final class Platform { private Platform() { @@ -37,14 +40,21 @@ public final class Platform { @PluggableDependency(PlatformGenerator.class) public static native Object clone(Object obj); + @DelegateTo("isInstanceLowLevel") public static boolean isInstance(PlatformObject obj, PlatformClass cls) { return obj != null && !isUndefined(obj.getPlatformClass().getMetadata()) && isAssignable(obj.getPlatformClass(), cls); } + @SuppressWarnings("unused") + private static boolean isInstanceLowLevel(RuntimeClass self, RuntimeObject object) { + return isAssignableLowLevel(RuntimeClass.getClass(object), self); + } + @JSBody(params = "object", script = "return typeof object === 'undefined';") private static native boolean isUndefined(JSObject object); + @DelegateTo("isAssignableLowLevel") public static boolean isAssignable(PlatformClass from, PlatformClass to) { if (from == to) { return true; @@ -58,6 +68,11 @@ public final class Platform { return false; } + @SuppressWarnings("unused") + private static boolean isAssignableLowLevel(RuntimeClass from, RuntimeClass to) { + return to.isSupertypeOf.apply(from); + } + @InjectedBy(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class) public static native Class asJavaClass(PlatformObject obj); @@ -131,4 +146,24 @@ public final class Platform { public static PlatformString stringFromCharCode(int charCode) { return ((PlatformHelper) Window.current()).getStringClass().fromCharCode(charCode); } + + @DelegateTo("isPrimitiveLowLevel") + public static boolean isPrimitive(PlatformClass cls) { + return cls.getMetadata().isPrimitive(); + } + + @SuppressWarnings("unused") + private static boolean isPrimitiveLowLevel(RuntimeClass cls) { + return (cls.flags & RuntimeClass.PRIMITIVE) != 0; + } + + @DelegateTo("getArrayItemLowLevel") + public static PlatformClass getArrayItem(PlatformClass cls) { + return cls.getMetadata().getArrayItem(); + } + + @SuppressWarnings("unused") + private static RuntimeClass getArrayItemLowLevel(RuntimeClass cls) { + return cls.itemType; + } } diff --git a/platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java b/platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java index d9f1e64b1..bd937db9c 100644 --- a/platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java +++ b/platform/src/main/java/org/teavm/platform/PlatformClassMetadata.java @@ -18,10 +18,6 @@ package org.teavm.platform; import org.teavm.jso.JSObject; import org.teavm.jso.JSProperty; -/** - * - * @author Alexey Andreev - */ public interface PlatformClassMetadata extends JSObject { @JSProperty("item") PlatformClass getArrayItem();