From 28c0cc6ef20706672c25cf198d5ed8ec6f2d469d Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 23 May 2019 23:38:10 +0300 Subject: [PATCH] Wasm: fix bugs --- .../org/teavm/backend/wasm/WasmTarget.java | 3 +- .../generate/CallSiteBinaryGenerator.java | 107 +++++++++++++----- .../wasm/generate/WasmClassGenerator.java | 18 +-- .../wasm/generate/WasmGenerationVisitor.java | 25 ++-- .../wasm/render/WasmBinaryRenderer.java | 5 +- .../org/teavm/backend/wasm/wasm-runtime.c | 9 ++ samples/benchmark/pom.xml | 2 - 7 files changed, 120 insertions(+), 49 deletions(-) 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 7d81dbd0b..ac7d12848 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -518,7 +518,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { for (String className : classes.getClassNames()) { ClassHolder cls = classes.get(className); for (MethodHolder method : cls.getMethods()) { - if (context.getIntrinsic(method.getReference()) != null) { + if (method.hasModifier(ElementModifier.ABSTRACT) + || context.getIntrinsic(method.getReference()) != null) { continue; } module.add(generator.generateDefinition(method.getReference())); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/CallSiteBinaryGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/CallSiteBinaryGenerator.java index b256bf22f..0495684e8 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/CallSiteBinaryGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/CallSiteBinaryGenerator.java @@ -15,10 +15,11 @@ */ package org.teavm.backend.wasm.generate; +import com.carrotsearch.hppc.ObjectIntHashMap; +import com.carrotsearch.hppc.ObjectIntMap; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.Objects; import org.teavm.backend.wasm.binary.BinaryWriter; import org.teavm.backend.wasm.binary.DataPrimitives; import org.teavm.backend.wasm.binary.DataStructure; @@ -29,28 +30,31 @@ import org.teavm.model.lowlevel.CallSiteLocation; import org.teavm.model.lowlevel.ExceptionHandlerDescriptor; public class CallSiteBinaryGenerator { - private static final int CALL_SITE_HANDLER_COUNT = 0; - private static final int CALL_SITE_FIRST_HANDLER = 1; - private static final int CALL_SITE_LOCATION = 2; + private static final int CALL_SITE_FIRST_HANDLER = 0; + private static final int CALL_SITE_LOCATION = 1; private static final int EXCEPTION_HANDLER_ID = 0; private static final int EXCEPTION_HANDLER_CLASS = 1; - private static final int LOCATION_FILE = 0; - private static final int LOCATION_CLASS = 1; - private static final int LOCATION_METHOD = 2; - private static final int LOCATION_LINE_NUMBER = 3; + private static final int EXCEPTION_HANDLER_NEXT = 2; + private static final int LOCATION_METHOD = 0; + private static final int LOCATION_LINE = 1; + private static final int METHOD_LOCATION_FILE = 0; + private static final int METHOD_LOCATION_CLASS = 1; + private static final int METHOD_LOCATION_METHOD = 2; private DataStructure callSiteStructure = new DataStructure((byte) 0, - DataPrimitives.INT, DataPrimitives.ADDRESS, DataPrimitives.ADDRESS); private DataStructure exceptionHandlerStructure = new DataStructure((byte) 0, DataPrimitives.INT, + DataPrimitives.ADDRESS, DataPrimitives.ADDRESS); private DataStructure locationStructure = new DataStructure((byte) 0, - DataPrimitives.ADDRESS, - DataPrimitives.ADDRESS, DataPrimitives.ADDRESS, DataPrimitives.INT); + private DataStructure methodLocationStructure = new DataStructure((byte) 0, + DataPrimitives.ADDRESS, + DataPrimitives.ADDRESS, + DataPrimitives.ADDRESS); private BinaryWriter writer; private WasmClassGenerator classGenerator; @@ -78,12 +82,12 @@ public class CallSiteBinaryGenerator { binaryCallSites.add(binaryCallSite); } - Map locationCache = new HashMap<>(); + ObjectIntMap locationCache = new ObjectIntHashMap<>(); + ObjectIntMap methodLocationCache = new ObjectIntHashMap<>(); for (int callSiteId = 0; callSiteId < callSites.size(); ++callSiteId) { DataValue binaryCallSite = binaryCallSites.get(callSiteId); CallSiteDescriptor callSite = callSites.get(callSiteId); - binaryCallSite.setInt(CALL_SITE_HANDLER_COUNT, callSite.getHandlers().size()); boolean firstHandlerSet = false; List binaryExceptionHandlers = new ArrayList<>(); @@ -98,6 +102,9 @@ public class CallSiteBinaryGenerator { binaryCallSite.setAddress(CALL_SITE_FIRST_HANDLER, address); firstHandlerSet = true; } + if (i > 0) { + binaryExceptionHandlers.get(i - 1).setAddress(EXCEPTION_HANDLER_NEXT, address); + } } for (int i = 0; i < callSite.getHandlers().size(); ++i) { @@ -110,24 +117,70 @@ public class CallSiteBinaryGenerator { } } - int locationAddress = locationCache.computeIfAbsent(callSite.getLocation(), location -> { + CallSiteLocation location = callSite.getLocation(); + int locationAddress = locationCache.getOrDefault(location, -1); + if (locationAddress < 0) { DataValue binaryLocation = locationStructure.createValue(); - int address = writer.append(binaryLocation); - if (location.getFileName() != null) { - binaryLocation.setAddress(LOCATION_FILE, stringPool.getStringPointer(location.getFileName())); + locationAddress = writer.append(binaryLocation); + locationCache.put(location, locationAddress); + MethodLocation methodLocation = new MethodLocation(location.getFileName(), location.getClassName(), + location.getMethodName()); + int methodLocationAddress = methodLocationCache.getOrDefault(methodLocation, -1); + if (methodLocationAddress < 0) { + DataValue binaryMethodLocation = methodLocationStructure.createValue(); + methodLocationAddress = writer.append(binaryMethodLocation); + methodLocationCache.put(methodLocation, methodLocationAddress); + if (location.getFileName() != null) { + binaryMethodLocation.setAddress(METHOD_LOCATION_FILE, + stringPool.getStringPointer(location.getFileName())); + } + if (location.getClassName() != null) { + binaryMethodLocation.setAddress(METHOD_LOCATION_CLASS, + stringPool.getStringPointer(location.getClassName())); + } + if (location.getMethodName() != null) { + binaryMethodLocation.setAddress(METHOD_LOCATION_METHOD, + stringPool.getStringPointer(location.getMethodName())); + } } - if (location.getClassName() != null) { - binaryLocation.setAddress(LOCATION_CLASS, stringPool.getStringPointer(location.getClassName())); - } - if (location.getMethodName() != null) { - binaryLocation.setAddress(LOCATION_METHOD, stringPool.getStringPointer(location.getMethodName())); - } - binaryLocation.setInt(LOCATION_LINE_NUMBER, location.getLineNumber()); - return address; - }); + + binaryLocation.setAddress(LOCATION_METHOD, methodLocationAddress); + binaryLocation.setInt(LOCATION_LINE, location.getLineNumber()); + } binaryCallSite.setAddress(CALL_SITE_LOCATION, locationAddress); } return firstCallSite; } + + final static class MethodLocation { + final String file; + final String className; + final String methodName; + + MethodLocation(String file, String className, String methodName) { + this.file = file; + this.className = className; + this.methodName = methodName; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof MethodLocation)) { + return false; + } + MethodLocation that = (MethodLocation) o; + return Objects.equals(file, that.file) + && Objects.equals(className, that.className) + && Objects.equals(methodName, that.methodName); + } + + @Override + public int hashCode() { + return Objects.hash(file, className, methodName); + } + } } 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 5d50cf5a3..6dfa9b317 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 @@ -76,6 +76,8 @@ public class WasmClassGenerator { DataPrimitives.INT, /* isInstance function */ DataPrimitives.INT, /* init function */ DataPrimitives.ADDRESS, /* parent */ + DataPrimitives.INT, /* interface count */ + DataPrimitives.ADDRESS, /* interfaces */ DataPrimitives.ADDRESS, /* enum values */ DataPrimitives.ADDRESS, /* layout */ DataPrimitives.ADDRESS /* simple name */); @@ -92,9 +94,9 @@ public class WasmClassGenerator { private static final int CLASS_IS_INSTANCE = 8; private static final int CLASS_INIT = 9; private static final int CLASS_PARENT = 10; - private static final int CLASS_ENUM_VALUES = 11; - private static final int CLASS_LAYOUT = 12; - private static final int CLASS_SIMPLE_NAME = 13; + private static final int CLASS_ENUM_VALUES = 13; + private static final int CLASS_LAYOUT = 14; + private static final int CLASS_SIMPLE_NAME = 15; public WasmClassGenerator(ClassReaderSource processedClassSource, ClassReaderSource classSource, VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter, @@ -377,13 +379,13 @@ public class WasmClassGenerator { private void fillVirtualTable(VirtualTable vtable, DataValue array) { int index = 0; List tables = new ArrayList<>(); - while (vtable != null) { - tables.add(vtable); - vtable = vtable.getParent(); + VirtualTable vt = vtable; + while (vt != null) { + tables.add(vt); + vt = vt.getParent(); } for (int i = tables.size() - 1; i >= 0; --i) { - vtable = tables.get(i); - for (MethodDescriptor method : vtable.getMethods()) { + for (MethodDescriptor method : tables.get(i).getMethods()) { int methodIndex = -1; if (method != null) { VirtualTableEntry entry = vtable.getEntry(method); 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 3f479ad36..e1e008aa6 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 @@ -110,10 +110,11 @@ import org.teavm.backend.wasm.render.WasmTypeInference; import org.teavm.diagnostics.Diagnostics; import org.teavm.interop.Address; import org.teavm.model.FieldReference; +import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.TextLocation; import org.teavm.model.ValueType; -import org.teavm.model.classes.VirtualTableEntry; +import org.teavm.model.classes.VirtualTable; import org.teavm.runtime.Allocator; import org.teavm.runtime.RuntimeArray; import org.teavm.runtime.RuntimeClass; @@ -909,10 +910,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { } if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) { - String methodName = context.names.forMethod(expr.getMethod()); + MethodReader method = context.getClassSource().resolve(expr.getMethod()); + MethodReference reference = method != null ? method.getReference() : expr.getMethod(); + String methodName = context.names.forMethod(reference); WasmCall call = new WasmCall(methodName); - if (context.getImportedMethod(expr.getMethod()) != null) { + if (context.getImportedMethod(reference) != null) { call.setImported(true); } for (Expr argument : expr.getArguments()) { @@ -942,23 +945,31 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor { result = block; } else { + MethodReference reference = expr.getMethod(); accept(expr.getArguments().get(0)); WasmExpression instance = result; WasmBlock block = new WasmBlock(false); - block.setType(WasmGeneratorUtil.mapType(expr.getMethod().getReturnType())); + block.setType(WasmGeneratorUtil.mapType(reference.getReturnType())); WasmLocal instanceVar = getTemporary(WasmType.INT32); 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) { + VirtualTable vtable = context.getVirtualTableProvider().lookup(reference.getClassName()); + if (vtable != null) { + vtable = vtable.findMethodContainer(reference.getDescriptor()); + } + if (vtable == null) { result = new WasmUnreachable(); return; } + int vtableIndex = vtable.getMethods().indexOf(reference.getDescriptor()); + if (vtable.getParent() != null) { + vtableIndex += vtable.getParent().size(); + } WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, - getReferenceToClass(instance), new WasmInt32Constant(vtableEntry.getIndex() * 4 + vtableOffset)); + getReferenceToClass(instance), new WasmInt32Constant(vtableIndex * 4 + vtableOffset)); methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32); WasmIndirectCall call = new WasmIndirectCall(methodIndex); diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java index 4d65cef39..e6215a99a 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java @@ -333,13 +333,10 @@ public class WasmBinaryRenderer { WasmBinaryWriter functionsSubsection = new WasmBinaryWriter(); Collection functions = module.getFunctions().values(); - + functions = functions.stream().filter(f -> f.getImportName() != null).collect(Collectors.toList()); functionsSubsection.writeLEB(functions.size()); for (WasmFunction function : functions) { - if (function.getImportName() != null) { - continue; - } functionsSubsection.writeLEB(functionIndexes.get(function.getName())); functionsSubsection.writeAsciiString(function.getName()); } diff --git a/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c b/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c index 8b6c34ab9..251bcd8db 100644 --- a/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c +++ b/core/src/main/resources/org/teavm/backend/wasm/wasm-runtime.c @@ -40,4 +40,13 @@ inline static int32_t reinterpret_float32(double v) { inline static float reinterpret_int32(int32_t v) { reinterpret_union_32.i = v; return reinterpret_union_32.f; +} + +static void logOutOfMemory() { + abort(); +} + +static void logString(int32_t v) { +} +static void logInt(int32_t v) { } \ No newline at end of file diff --git a/samples/benchmark/pom.xml b/samples/benchmark/pom.xml index 307562bba..f1ab7abb7 100644 --- a/samples/benchmark/pom.xml +++ b/samples/benchmark/pom.xml @@ -154,7 +154,6 @@ FULL - native-client