mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04:10 -08:00
Implementing reflection in WASM
This commit is contained in:
parent
3f02cad9e7
commit
5479d24a21
|
@ -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)) {
|
||||
|
|
|
@ -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<DependencyListener> getDependencyListeners() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setController(TeaVMTargetController controller) {
|
||||
this.controller = controller;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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<ClassHolderTransformer> getTransformers();
|
||||
|
||||
List<DependencyListener> getDependencyListeners();
|
||||
|
||||
void setController(TeaVMTargetController controller);
|
||||
|
||||
List<TeaVMHostExtension> getHostExtensions();
|
||||
|
|
|
@ -71,13 +71,13 @@ public final class Example {
|
|||
WasmRuntime.print(new Object().hashCode());
|
||||
WasmRuntime.print(new Object().hashCode());
|
||||
|
||||
/*List<Integer> list = new ArrayList<>(Arrays.asList(333, 444, 555));
|
||||
List<Integer> 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) {
|
||||
|
|
|
@ -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<DependencyListener> getDependencyListeners() {
|
||||
List<DependencyListener> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
27
interop/core/src/main/java/org/teavm/interop/DelegateTo.java
Normal file
27
interop/core/src/main/java/org/teavm/interop/DelegateTo.java
Normal file
|
@ -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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user