From 5479d24a2155705b754975c7249db63da71f3336 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 19 Aug 2016 19:57:03 +0300 Subject: [PATCH] Implementing reflection in WASM --- .../classlib/java/lang/reflect/TArray.java | 14 +++- .../javascript/backend/JavaScriptTarget.java | 6 ++ core/src/main/java/org/teavm/vm/TeaVM.java | 3 + .../main/java/org/teavm/vm/TeaVMTarget.java | 3 + .../src/main/java/org/teavm/wasm/Example.java | 6 +- .../main/java/org/teavm/wasm/WasmTarget.java | 52 ++++++++---- .../wasm/generate/WasmDependencyListener.java | 43 ++++++++++ .../wasm/generate/WasmGenerationVisitor.java | 83 +++++++++++++++---- .../teavm/wasm/generate/WasmGenerator.java | 5 +- .../wasm/model/expression/WasmExpression.java | 12 +++ .../wasm/render/WasmRenderingVisitor.java | 6 +- .../java/org/teavm/interop/DelegateTo.java | 27 ++++++ 12 files changed, 217 insertions(+), 43 deletions(-) create mode 100644 core/src/main/java/org/teavm/wasm/generate/WasmDependencyListener.java create mode 100644 interop/core/src/main/java/org/teavm/interop/DelegateTo.java 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 0f46fbf0f..305860d14 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 @@ -17,13 +17,13 @@ package org.teavm.classlib.java.lang.reflect; import org.teavm.classlib.java.lang.*; import org.teavm.dependency.PluggableDependency; +import org.teavm.interop.DelegateTo; import org.teavm.javascript.spi.GeneratedBy; import org.teavm.platform.PlatformClass; +import org.teavm.runtime.Allocator; +import org.teavm.runtime.RuntimeClass; +import org.teavm.runtime.RuntimeObject; -/** - * - * @author Alexey Andreev - */ public final class TArray extends TObject { @GeneratedBy(ArrayNativeGenerator.class) @PluggableDependency(ArrayNativeGenerator.class) @@ -44,8 +44,14 @@ public final class TArray extends TObject { @GeneratedBy(ArrayNativeGenerator.class) @PluggableDependency(ArrayNativeGenerator.class) + @DelegateTo("newInstanceLowLevel") private static native TObject newInstanceImpl(PlatformClass componentType, int length); + @SuppressWarnings("unused") + private static RuntimeObject newInstanceLowLevel(RuntimeClass cls, int length) { + return Allocator.allocateArray(cls, length).toStructure(); + } + public static TObject get(TObject array, int index) throws TIllegalArgumentException, TArrayIndexOutOfBoundsException { if (index < 0 || index >= getLength(array)) { diff --git a/core/src/main/java/org/teavm/javascript/backend/JavaScriptTarget.java b/core/src/main/java/org/teavm/javascript/backend/JavaScriptTarget.java index 3321ae007..83fff0e7c 100644 --- a/core/src/main/java/org/teavm/javascript/backend/JavaScriptTarget.java +++ b/core/src/main/java/org/teavm/javascript/backend/JavaScriptTarget.java @@ -39,6 +39,7 @@ import org.teavm.codegen.SourceWriterBuilder; import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.SourceLocation; import org.teavm.dependency.DependencyChecker; +import org.teavm.dependency.DependencyListener; import org.teavm.dependency.MethodDependency; import org.teavm.javascript.Renderer; import org.teavm.javascript.RenderingException; @@ -88,6 +89,11 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost { return Collections.emptyList(); } + @Override + public List getDependencyListeners() { + return Collections.emptyList(); + } + @Override public void setController(TeaVMTargetController controller) { this.controller = controller; diff --git a/core/src/main/java/org/teavm/vm/TeaVM.java b/core/src/main/java/org/teavm/vm/TeaVM.java index ab8c06696..69b1f28da 100644 --- a/core/src/main/java/org/teavm/vm/TeaVM.java +++ b/core/src/main/java/org/teavm/vm/TeaVM.java @@ -137,6 +137,9 @@ public class TeaVM implements TeaVMHost, ServiceRepository { for (ClassHolderTransformer transformer : target.getTransformers()) { dependencyChecker.addClassTransformer(transformer); } + for (DependencyListener listener : target.getDependencyListeners()) { + dependencyChecker.addDependencyListener(listener); + } for (TeaVMHostExtension extension : target.getHostExtensions()) { for (Class extensionType : getExtensionTypes(extension)) { diff --git a/core/src/main/java/org/teavm/vm/TeaVMTarget.java b/core/src/main/java/org/teavm/vm/TeaVMTarget.java index 0eea40d64..28253d79e 100644 --- a/core/src/main/java/org/teavm/vm/TeaVMTarget.java +++ b/core/src/main/java/org/teavm/vm/TeaVMTarget.java @@ -18,6 +18,7 @@ package org.teavm.vm; import java.io.OutputStream; import java.util.List; import org.teavm.dependency.DependencyChecker; +import org.teavm.dependency.DependencyListener; import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ListableClassHolderSource; import org.teavm.vm.spi.TeaVMHostExtension; @@ -25,6 +26,8 @@ import org.teavm.vm.spi.TeaVMHostExtension; public interface TeaVMTarget { List getTransformers(); + List getDependencyListeners(); + void setController(TeaVMTargetController controller); List getHostExtensions(); diff --git a/core/src/main/java/org/teavm/wasm/Example.java b/core/src/main/java/org/teavm/wasm/Example.java index a056cdfc9..4bac1d189 100644 --- a/core/src/main/java/org/teavm/wasm/Example.java +++ b/core/src/main/java/org/teavm/wasm/Example.java @@ -71,13 +71,13 @@ public final class Example { WasmRuntime.print(new Object().hashCode()); WasmRuntime.print(new Object().hashCode()); - /*List list = new ArrayList<>(Arrays.asList(333, 444, 555)); + List list = new ArrayList<>(Arrays.asList(333, 444, 555)); list.add(1234); - list.remove(444); + list.remove((Integer) 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 ea16a4649..a271a0fd1 100644 --- a/core/src/main/java/org/teavm/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/wasm/WasmTarget.java @@ -15,7 +15,6 @@ */ package org.teavm.wasm; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -29,9 +28,12 @@ import java.util.Set; import org.teavm.ast.decompilation.Decompiler; import org.teavm.dependency.ClassDependency; import org.teavm.dependency.DependencyChecker; +import org.teavm.dependency.DependencyListener; import org.teavm.interop.Address; +import org.teavm.interop.DelegateTo; import org.teavm.interop.Import; import org.teavm.interop.StaticInit; +import org.teavm.model.AnnotationHolder; import org.teavm.model.BasicBlock; import org.teavm.model.CallLocation; import org.teavm.model.ClassHolder; @@ -59,14 +61,13 @@ 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; import org.teavm.vm.TeaVMEntryPoint; import org.teavm.vm.TeaVMTarget; import org.teavm.vm.TeaVMTargetController; import org.teavm.vm.spi.TeaVMHostExtension; import org.teavm.wasm.binary.BinaryWriter; import org.teavm.wasm.generate.WasmClassGenerator; +import org.teavm.wasm.generate.WasmDependencyListener; import org.teavm.wasm.generate.WasmGenerationContext; import org.teavm.wasm.generate.WasmGenerator; import org.teavm.wasm.generate.WasmMangling; @@ -126,6 +127,13 @@ public class WasmTarget implements TeaVMTarget { return transformers; } + @Override + public List getDependencyListeners() { + List listeners = new ArrayList<>(); + listeners.add(new WasmDependencyListener()); + return listeners; + } + @Override public void contributeDependencies(DependencyChecker dependencyChecker) { for (Class type : Arrays.asList(int.class, long.class, float.class, double.class)) { @@ -171,8 +179,7 @@ public class WasmTarget implements TeaVMTarget { VirtualTableProvider vtableProvider = createVirtualTableProvider(classes); TagRegistry tagRegistry = new TagRegistry(classes); BinaryWriter binaryWriter = new BinaryWriter(256); - WasmClassGenerator classGenerator = new WasmClassGenerator(controller.getUnprocessedClassSource(), - vtableProvider, tagRegistry, binaryWriter); + WasmClassGenerator classGenerator = new WasmClassGenerator(classes, vtableProvider, tagRegistry, binaryWriter); Decompiler decompiler = new Decompiler(classes, controller.getClassLoader(), new HashSet<>(), new HashSet<>()); @@ -205,7 +212,26 @@ public class WasmTarget implements TeaVMTarget { continue; } - if (method.hasModifier(ElementModifier.NATIVE)) { + MethodHolder implementor = method; + AnnotationHolder delegateAnnot = method.getAnnotations().get(DelegateTo.class.getName()); + if (delegateAnnot != null) { + String methodName = delegateAnnot.getValue("value").getString(); + boolean found = false; + for (MethodHolder candidate : cls.getMethods()) { + if (candidate.getName().equals(methodName)) { + if (found) { + controller.getDiagnostics().error(new CallLocation(method.getReference()), + "Method is delegated to " + methodName + " but several implementations " + + "found"); + break; + } + implementor = candidate; + found = true; + } + } + } + + if (implementor.hasModifier(ElementModifier.NATIVE)) { if (context.getImportedMethod(method.getReference()) == null) { CallLocation location = new CallLocation(method.getReference()); controller.getDiagnostics().error(location, "Method {{m0}} is native but " @@ -214,10 +240,10 @@ public class WasmTarget implements TeaVMTarget { module.add(generator.generateNative(method.getReference())); continue; } - if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) { + if (implementor.getProgram() == null || implementor.getProgram().basicBlockCount() == 0) { continue; } - module.add(generator.generate(method.getReference())); + module.add(generator.generate(method.getReference(), implementor)); if (controller.wasCancelled()) { return; } @@ -365,14 +391,4 @@ public class WasmTarget implements TeaVMTarget { return new VirtualTableProvider(classes, virtualMethods); } - - public static void main(String[] args) throws IOException { - TeaVM vm = new TeaVMBuilder(new WasmTarget()).build(); - vm.installPlugins(); - vm.entryPoint("main", new MethodReference(Example.class, "main", String[].class, void.class)); - try (OutputStream output = new FileOutputStream(args[0])) { - vm.build(output, null); - System.err.println("Problems found: " + vm.getProblemProvider().getProblems().size()); - } - } } diff --git a/core/src/main/java/org/teavm/wasm/generate/WasmDependencyListener.java b/core/src/main/java/org/teavm/wasm/generate/WasmDependencyListener.java new file mode 100644 index 000000000..97b3e67a8 --- /dev/null +++ b/core/src/main/java/org/teavm/wasm/generate/WasmDependencyListener.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.generate; + +import org.teavm.dependency.AbstractDependencyListener; +import org.teavm.dependency.DependencyAgent; +import org.teavm.dependency.MethodDependency; +import org.teavm.interop.DelegateTo; +import org.teavm.model.AnnotationReader; +import org.teavm.model.CallLocation; +import org.teavm.model.ClassReader; +import org.teavm.model.MethodReader; + +public class WasmDependencyListener extends AbstractDependencyListener { + @Override + public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) { + AnnotationReader delegateAnnot = method.getMethod().getAnnotations().get(DelegateTo.class.getName()); + if (delegateAnnot != null) { + String delegateMethodName = delegateAnnot.getValue("value").getString(); + ClassReader cls = agent.getClassSource().get(method.getReference().getClassName()); + for (MethodReader delegate : cls.getMethods()) { + if (delegate.getName().equals(delegateMethodName)) { + if (delegate != method.getMethod()) { + agent.linkMethod(delegate.getReference(), location).use(); + } + } + } + } + } +} 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 9847d9d30..0ec1c7729 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerationVisitor.java @@ -45,6 +45,7 @@ import org.teavm.ast.MonitorExitStatement; import org.teavm.ast.NewArrayExpr; import org.teavm.ast.NewExpr; import org.teavm.ast.NewMultiArrayExpr; +import org.teavm.ast.NodeLocation; import org.teavm.ast.OperationType; import org.teavm.ast.PrimitiveCastExpr; import org.teavm.ast.QualificationExpr; @@ -114,6 +115,7 @@ import org.teavm.wasm.model.expression.WasmSwitch; import org.teavm.wasm.model.expression.WasmUnreachable; class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { + private static FieldReference tagField = new FieldReference(RuntimeClass.class.getName(), "tag"); private WasmGenerationContext context; private WasmClassGenerator classGenerator; private WasmFunction function; @@ -165,6 +167,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { call.getArguments().add(result); expr.getSecondOperand().acceptVisitor(this); call.getArguments().add(result); + call.setLocation(expr.getLocation()); result = call; break; } @@ -215,6 +218,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { call.getArguments().add(result); expr.getSecondOperand().acceptVisitor(this); call.getArguments().add(result); + call.setLocation(expr.getLocation()); result = call; break; } @@ -251,6 +255,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { break; } } + result.setLocation(expr.getLocation()); } private void generateBinary(WasmIntBinaryOperation intOp, BinaryExpr expr) { @@ -282,6 +287,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { case DOUBLE: throw new AssertionError("Can't translate operation " + intOp + " for type " + expr.getType()); } + + result.setLocation(expr.getLocation()); } private Class convertType(OperationType type) { @@ -304,11 +311,15 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { expr.getFirstOperand().acceptVisitor(this); WasmBranch branch = new WasmBranch(negate(result), block); branch.setResult(new WasmInt32Constant(0)); + branch.setLocation(expr.getLocation()); + branch.getResult().setLocation(expr.getLocation()); block.getBody().add(branch); expr.getSecondOperand().acceptVisitor(this); block.getBody().add(result); + block.setLocation(expr.getLocation()); + result = block; } @@ -318,11 +329,15 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { expr.getFirstOperand().acceptVisitor(this); WasmBranch branch = new WasmBranch(result, block); branch.setResult(new WasmInt32Constant(1)); + branch.setLocation(expr.getLocation()); + branch.getResult().setLocation(expr.getLocation()); block.getBody().add(branch); expr.getSecondOperand().acceptVisitor(this); block.getBody().add(result); + block.setLocation(expr.getLocation()); + result = block; } @@ -333,22 +348,28 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { expr.getOperand().acceptVisitor(this); result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, result, new WasmInt32Constant(24)); + result.setLocation(expr.getLocation()); result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHR_SIGNED, result, new WasmInt32Constant(24)); + result.setLocation(expr.getLocation()); break; case INT_TO_SHORT: expr.getOperand().acceptVisitor(this); result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, result, new WasmInt32Constant(16)); + result.setLocation(expr.getLocation()); result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHR_SIGNED, result, new WasmInt32Constant(16)); + result.setLocation(expr.getLocation()); break; case INT_TO_CHAR: expr.getOperand().acceptVisitor(this); result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, result, new WasmInt32Constant(16)); + result.setLocation(expr.getLocation()); result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHR_UNSIGNED, result, new WasmInt32Constant(16)); + result.setLocation(expr.getLocation()); break; case LENGTH: expr.getOperand().acceptVisitor(this); @@ -364,18 +385,22 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { case INT: result = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SUB, new WasmInt32Constant(0), result); + result.setLocation(expr.getLocation()); break; case LONG: result = new WasmIntBinary(WasmIntType.INT64, WasmIntBinaryOperation.SUB, new WasmInt64Constant(0), result); + result.setLocation(expr.getLocation()); break; case FLOAT: result = new WasmFloatBinary(WasmFloatType.FLOAT32, WasmFloatBinaryOperation.SUB, new WasmFloat32Constant(0), result); + result.setLocation(expr.getLocation()); break; case DOUBLE: result = new WasmFloatBinary(WasmFloatType.FLOAT64, WasmFloatBinaryOperation.SUB, new WasmFloat64Constant(0), result); + result.setLocation(expr.getLocation()); break; } break; @@ -388,9 +413,13 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { private WasmExpression generateArrayLength(WasmExpression array) { int sizeOffset = classGenerator.getFieldOffset(new FieldReference(RuntimeArray.class.getName(), "size")); - WasmIntBinary ptr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, + WasmExpression ptr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, array, new WasmInt32Constant(sizeOffset)); - return new WasmLoadInt32(4, ptr, WasmInt32Subtype.INT32); + ptr.setLocation(array.getLocation()); + + WasmExpression length = new WasmLoadInt32(4, ptr, WasmInt32Subtype.INT32); + length.setLocation(array.getLocation()); + return length; } @Override @@ -399,14 +428,16 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { if (left == null) { statement.getRightValue().acceptVisitor(this); result = new WasmDrop(result); + result.setLocation(statement.getLocation()); } else if (left instanceof VariableExpr) { VariableExpr varExpr = (VariableExpr) left; WasmLocal local = function.getLocalVariables().get(varExpr.getIndex() - firstVariable); statement.getRightValue().acceptVisitor(this); result = new WasmSetLocal(local, result); + result.setLocation(statement.getLocation()); } else if (left instanceof QualificationExpr) { QualificationExpr lhs = (QualificationExpr) left; - storeField(lhs.getQualified(), lhs.getField(), statement.getRightValue()); + storeField(lhs.getQualified(), lhs.getField(), statement.getRightValue(), statement.getLocation()); } else if (left instanceof SubscriptExpr) { SubscriptExpr lhs = (SubscriptExpr) left; storeArrayItem(lhs, statement.getRightValue()); @@ -415,8 +446,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { } } - private void storeField(Expr qualified, FieldReference field, Expr value) { - WasmExpression address = getAddress(qualified, field); + private void storeField(Expr qualified, FieldReference field, Expr value, NodeLocation location) { + WasmExpression address = getAddress(qualified, field, location); ValueType type = context.getFieldType(field); value.acceptVisitor(this); if (type instanceof ValueType.Primitive) { @@ -447,6 +478,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { } else { result = new WasmStoreInt32(4, address, result, WasmInt32Subtype.INT32); } + result.setLocation(location); } private void storeArrayItem(SubscriptExpr leftValue, Expr rightValue) { @@ -741,7 +773,8 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { } else if (expr.getType() == InvocationType.CONSTRUCTOR) { WasmBlock block = new WasmBlock(false); WasmLocal tmp = function.getLocalVariables().get(getTemporaryInt32()); - block.getBody().add(new WasmSetLocal(tmp, allocateObject(expr.getMethod().getClassName()))); + block.getBody().add(new WasmSetLocal(tmp, allocateObject(expr.getMethod().getClassName(), + expr.getLocation()))); String methodName = WasmMangling.mangleMethod(expr.getMethod()); WasmCall call = new WasmCall(methodName); @@ -825,7 +858,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(QualificationExpr expr) { - WasmExpression address = getAddress(expr.getQualified(), expr.getField()); + WasmExpression address = getAddress(expr.getQualified(), expr.getField(), expr.getLocation()); ValueType type = context.getFieldType(expr.getField()); if (type instanceof ValueType.Primitive) { @@ -858,14 +891,25 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { } } - private WasmExpression getAddress(Expr qualified, FieldReference field) { + private WasmExpression getAddress(Expr qualified, FieldReference field, NodeLocation location) { int offset = classGenerator.getFieldOffset(field); if (qualified == null) { - return new WasmInt32Constant(offset); + WasmExpression result = new WasmInt32Constant(offset); + result.setLocation(location); + return result; } else { qualified.acceptVisitor(this); - return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, result, - new WasmInt32Constant(offset)); + if (offset != 0) { + WasmExpression offsetExpr = new WasmInt32Constant(offset); + offsetExpr.setLocation(qualified.getLocation()); + + WasmExpression address = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, + result, offsetExpr); + address.setLocation(location); + return address; + } else { + return result; + } } } @@ -878,6 +922,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { WasmBlock wasmTarget = breakTargets.get(target); usedBlocks.add(wasmTarget); result = new WasmBreak(wasmTarget); + result.setLocation(statement.getLocation()); } @Override @@ -889,19 +934,21 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { WasmBlock wasmTarget = continueTargets.get(target); usedBlocks.add(wasmTarget); result = new WasmBreak(wasmTarget); + result.setLocation(statement.getLocation()); } @Override public void visit(NewExpr expr) { - result = allocateObject(expr.getConstructedClass()); + result = allocateObject(expr.getConstructedClass(), expr.getLocation()); } - private WasmExpression allocateObject(String className) { + private WasmExpression allocateObject(String className, NodeLocation location) { int tag = classGenerator.getClassPointer(ValueType.object(className)); String allocName = WasmMangling.mangleMethod(new MethodReference(Allocator.class, "allocate", RuntimeClass.class, Address.class)); WasmCall call = new WasmCall(allocName); call.getArguments().add(new WasmInt32Constant(tag)); + call.setLocation(location); return call; } @@ -916,6 +963,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { call.getArguments().add(new WasmInt32Constant(classPointer)); expr.getLength().acceptVisitor(this); call.getArguments().add(result); + call.setLocation(expr.getLocation()); result = call; } @@ -932,6 +980,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { result = null; } result = new WasmReturn(result); + result.setLocation(statement.getLocation()); } @Override @@ -944,9 +993,11 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { Collections.sort(ranges, Comparator.comparingInt(range -> range.lower)); WasmBlock block = new WasmBlock(false); + block.setLocation(expr.getLocation()); WasmLocal tagVar = function.getLocalVariables().get(getTemporaryInt32()); + int tagOffset = classGenerator.getFieldOffset(tagField); WasmExpression tagPtr = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, - getReferenceToClass(result), new WasmInt32Constant(8)); + getReferenceToClass(result), new WasmInt32Constant(tagOffset)); block.getBody().add(new WasmSetLocal(tagVar, new WasmLoadInt32(4, tagPtr, WasmInt32Subtype.INT32))); WasmExpression lowerThanMinCond = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED, @@ -990,6 +1041,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { @Override public void visit(ThrowStatement statement) { WasmBlock block = new WasmBlock(false); + block.setLocation(statement.getLocation()); statement.getException().acceptVisitor(this); block.getBody().add(result); @@ -1007,6 +1059,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { public void visit(InitClassStatement statement) { if (classGenerator.hasClinit(statement.getClassName())) { result = new WasmCall(WasmMangling.mangleInitializer(statement.getClassName())); + result.setLocation(statement.getLocation()); } else { result = null; } @@ -1017,7 +1070,7 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { expr.getValue().acceptVisitor(this); result = new WasmConversion(WasmGeneratorUtil.mapType(expr.getSource()), WasmGeneratorUtil.mapType(expr.getTarget()), true, result); - + result.setLocation(expr.getLocation()); } @Override 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 934379881..2573fcd8c 100644 --- a/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java +++ b/core/src/main/java/org/teavm/wasm/generate/WasmGenerator.java @@ -24,6 +24,7 @@ import org.teavm.model.ElementModifier; import org.teavm.model.FieldReference; import org.teavm.model.MethodHolder; import org.teavm.model.MethodReference; +import org.teavm.model.Program; import org.teavm.model.ValueType; import org.teavm.runtime.RuntimeClass; import org.teavm.wasm.model.WasmFunction; @@ -53,11 +54,11 @@ public class WasmGenerator { this.classGenerator = classGenerator; } - public WasmFunction generate(MethodReference methodReference) { + public WasmFunction generate(MethodReference methodReference, MethodHolder bodyMethod) { ClassHolder cls = classSource.get(methodReference.getClassName()); MethodHolder method = cls.getMethod(methodReference.getDescriptor()); - RegularMethodNode methodAst = decompiler.decompileRegular(method); + RegularMethodNode methodAst = decompiler.decompileRegular(bodyMethod); WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(methodReference)); int firstVariable = method.hasModifier(ElementModifier.STATIC) ? 1 : 0; for (int i = firstVariable; i < methodAst.getVariables().size(); ++i) { diff --git a/core/src/main/java/org/teavm/wasm/model/expression/WasmExpression.java b/core/src/main/java/org/teavm/wasm/model/expression/WasmExpression.java index 10637b38e..fad08ab08 100644 --- a/core/src/main/java/org/teavm/wasm/model/expression/WasmExpression.java +++ b/core/src/main/java/org/teavm/wasm/model/expression/WasmExpression.java @@ -15,9 +15,21 @@ */ package org.teavm.wasm.model.expression; +import org.teavm.ast.NodeLocation; + public abstract class WasmExpression { + private NodeLocation location; + WasmExpression() { } + public NodeLocation getLocation() { + return location; + } + + public void setLocation(NodeLocation location) { + this.location = location; + } + public abstract void acceptVisitor(WasmExpressionVisitor visitor); } diff --git a/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java b/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java index c8b6df58b..635a42f9b 100644 --- a/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java +++ b/core/src/main/java/org/teavm/wasm/render/WasmRenderingVisitor.java @@ -97,7 +97,11 @@ class WasmRenderingVisitor implements WasmExpressionVisitor { } WasmRenderingVisitor line(WasmExpression expression) { - return lf().append(expression); + if (expression.getLocation() != null) { + lf().append(";; " + expression.getLocation().getFileName() + ":" + expression.getLocation().getLine()); + } + lf().append(expression); + return this; } WasmRenderingVisitor indent() { diff --git a/interop/core/src/main/java/org/teavm/interop/DelegateTo.java b/interop/core/src/main/java/org/teavm/interop/DelegateTo.java new file mode 100644 index 000000000..8728389db --- /dev/null +++ b/interop/core/src/main/java/org/teavm/interop/DelegateTo.java @@ -0,0 +1,27 @@ +/* + * 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; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface DelegateTo { + String value(); +}