Wasm: fix bugs

This commit is contained in:
Alexey Andreev 2019-05-23 23:38:10 +03:00
parent 871e9a0113
commit 28c0cc6ef2
7 changed files with 120 additions and 49 deletions

View File

@ -518,7 +518,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
for (String className : classes.getClassNames()) { for (String className : classes.getClassNames()) {
ClassHolder cls = classes.get(className); ClassHolder cls = classes.get(className);
for (MethodHolder method : cls.getMethods()) { for (MethodHolder method : cls.getMethods()) {
if (context.getIntrinsic(method.getReference()) != null) { if (method.hasModifier(ElementModifier.ABSTRACT)
|| context.getIntrinsic(method.getReference()) != null) {
continue; continue;
} }
module.add(generator.generateDefinition(method.getReference())); module.add(generator.generateDefinition(method.getReference()));

View File

@ -15,10 +15,11 @@
*/ */
package org.teavm.backend.wasm.generate; package org.teavm.backend.wasm.generate;
import com.carrotsearch.hppc.ObjectIntHashMap;
import com.carrotsearch.hppc.ObjectIntMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; 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.BinaryWriter;
import org.teavm.backend.wasm.binary.DataPrimitives; import org.teavm.backend.wasm.binary.DataPrimitives;
import org.teavm.backend.wasm.binary.DataStructure; import org.teavm.backend.wasm.binary.DataStructure;
@ -29,28 +30,31 @@ import org.teavm.model.lowlevel.CallSiteLocation;
import org.teavm.model.lowlevel.ExceptionHandlerDescriptor; import org.teavm.model.lowlevel.ExceptionHandlerDescriptor;
public class CallSiteBinaryGenerator { public class CallSiteBinaryGenerator {
private static final int CALL_SITE_HANDLER_COUNT = 0; private static final int CALL_SITE_FIRST_HANDLER = 0;
private static final int CALL_SITE_FIRST_HANDLER = 1; private static final int CALL_SITE_LOCATION = 1;
private static final int CALL_SITE_LOCATION = 2;
private static final int EXCEPTION_HANDLER_ID = 0; private static final int EXCEPTION_HANDLER_ID = 0;
private static final int EXCEPTION_HANDLER_CLASS = 1; private static final int EXCEPTION_HANDLER_CLASS = 1;
private static final int LOCATION_FILE = 0; private static final int EXCEPTION_HANDLER_NEXT = 2;
private static final int LOCATION_CLASS = 1; private static final int LOCATION_METHOD = 0;
private static final int LOCATION_METHOD = 2; private static final int LOCATION_LINE = 1;
private static final int LOCATION_LINE_NUMBER = 3; 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, private DataStructure callSiteStructure = new DataStructure((byte) 0,
DataPrimitives.INT,
DataPrimitives.ADDRESS, DataPrimitives.ADDRESS,
DataPrimitives.ADDRESS); DataPrimitives.ADDRESS);
private DataStructure exceptionHandlerStructure = new DataStructure((byte) 0, private DataStructure exceptionHandlerStructure = new DataStructure((byte) 0,
DataPrimitives.INT, DataPrimitives.INT,
DataPrimitives.ADDRESS,
DataPrimitives.ADDRESS); DataPrimitives.ADDRESS);
private DataStructure locationStructure = new DataStructure((byte) 0, private DataStructure locationStructure = new DataStructure((byte) 0,
DataPrimitives.ADDRESS,
DataPrimitives.ADDRESS,
DataPrimitives.ADDRESS, DataPrimitives.ADDRESS,
DataPrimitives.INT); DataPrimitives.INT);
private DataStructure methodLocationStructure = new DataStructure((byte) 0,
DataPrimitives.ADDRESS,
DataPrimitives.ADDRESS,
DataPrimitives.ADDRESS);
private BinaryWriter writer; private BinaryWriter writer;
private WasmClassGenerator classGenerator; private WasmClassGenerator classGenerator;
@ -78,12 +82,12 @@ public class CallSiteBinaryGenerator {
binaryCallSites.add(binaryCallSite); binaryCallSites.add(binaryCallSite);
} }
Map<CallSiteLocation, Integer> locationCache = new HashMap<>(); ObjectIntMap<CallSiteLocation> locationCache = new ObjectIntHashMap<>();
ObjectIntMap<MethodLocation> methodLocationCache = new ObjectIntHashMap<>();
for (int callSiteId = 0; callSiteId < callSites.size(); ++callSiteId) { for (int callSiteId = 0; callSiteId < callSites.size(); ++callSiteId) {
DataValue binaryCallSite = binaryCallSites.get(callSiteId); DataValue binaryCallSite = binaryCallSites.get(callSiteId);
CallSiteDescriptor callSite = callSites.get(callSiteId); CallSiteDescriptor callSite = callSites.get(callSiteId);
binaryCallSite.setInt(CALL_SITE_HANDLER_COUNT, callSite.getHandlers().size());
boolean firstHandlerSet = false; boolean firstHandlerSet = false;
List<DataValue> binaryExceptionHandlers = new ArrayList<>(); List<DataValue> binaryExceptionHandlers = new ArrayList<>();
@ -98,6 +102,9 @@ public class CallSiteBinaryGenerator {
binaryCallSite.setAddress(CALL_SITE_FIRST_HANDLER, address); binaryCallSite.setAddress(CALL_SITE_FIRST_HANDLER, address);
firstHandlerSet = true; firstHandlerSet = true;
} }
if (i > 0) {
binaryExceptionHandlers.get(i - 1).setAddress(EXCEPTION_HANDLER_NEXT, address);
}
} }
for (int i = 0; i < callSite.getHandlers().size(); ++i) { 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(); DataValue binaryLocation = locationStructure.createValue();
int address = writer.append(binaryLocation); locationAddress = writer.append(binaryLocation);
if (location.getFileName() != null) { locationCache.put(location, locationAddress);
binaryLocation.setAddress(LOCATION_FILE, stringPool.getStringPointer(location.getFileName())); 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())); binaryLocation.setAddress(LOCATION_METHOD, methodLocationAddress);
} binaryLocation.setInt(LOCATION_LINE, location.getLineNumber());
if (location.getMethodName() != null) { }
binaryLocation.setAddress(LOCATION_METHOD, stringPool.getStringPointer(location.getMethodName()));
}
binaryLocation.setInt(LOCATION_LINE_NUMBER, location.getLineNumber());
return address;
});
binaryCallSite.setAddress(CALL_SITE_LOCATION, locationAddress); binaryCallSite.setAddress(CALL_SITE_LOCATION, locationAddress);
} }
return firstCallSite; 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);
}
}
} }

View File

@ -76,6 +76,8 @@ public class WasmClassGenerator {
DataPrimitives.INT, /* isInstance function */ DataPrimitives.INT, /* isInstance function */
DataPrimitives.INT, /* init function */ DataPrimitives.INT, /* init function */
DataPrimitives.ADDRESS, /* parent */ DataPrimitives.ADDRESS, /* parent */
DataPrimitives.INT, /* interface count */
DataPrimitives.ADDRESS, /* interfaces */
DataPrimitives.ADDRESS, /* enum values */ DataPrimitives.ADDRESS, /* enum values */
DataPrimitives.ADDRESS, /* layout */ DataPrimitives.ADDRESS, /* layout */
DataPrimitives.ADDRESS /* simple name */); DataPrimitives.ADDRESS /* simple name */);
@ -92,9 +94,9 @@ public class WasmClassGenerator {
private static final int CLASS_IS_INSTANCE = 8; private static final int CLASS_IS_INSTANCE = 8;
private static final int CLASS_INIT = 9; private static final int CLASS_INIT = 9;
private static final int CLASS_PARENT = 10; private static final int CLASS_PARENT = 10;
private static final int CLASS_ENUM_VALUES = 11; private static final int CLASS_ENUM_VALUES = 13;
private static final int CLASS_LAYOUT = 12; private static final int CLASS_LAYOUT = 14;
private static final int CLASS_SIMPLE_NAME = 13; private static final int CLASS_SIMPLE_NAME = 15;
public WasmClassGenerator(ClassReaderSource processedClassSource, ClassReaderSource classSource, public WasmClassGenerator(ClassReaderSource processedClassSource, ClassReaderSource classSource,
VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter, VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter,
@ -377,13 +379,13 @@ public class WasmClassGenerator {
private void fillVirtualTable(VirtualTable vtable, DataValue array) { private void fillVirtualTable(VirtualTable vtable, DataValue array) {
int index = 0; int index = 0;
List<VirtualTable> tables = new ArrayList<>(); List<VirtualTable> tables = new ArrayList<>();
while (vtable != null) { VirtualTable vt = vtable;
tables.add(vtable); while (vt != null) {
vtable = vtable.getParent(); tables.add(vt);
vt = vt.getParent();
} }
for (int i = tables.size() - 1; i >= 0; --i) { for (int i = tables.size() - 1; i >= 0; --i) {
vtable = tables.get(i); for (MethodDescriptor method : tables.get(i).getMethods()) {
for (MethodDescriptor method : vtable.getMethods()) {
int methodIndex = -1; int methodIndex = -1;
if (method != null) { if (method != null) {
VirtualTableEntry entry = vtable.getEntry(method); VirtualTableEntry entry = vtable.getEntry(method);

View File

@ -110,10 +110,11 @@ import org.teavm.backend.wasm.render.WasmTypeInference;
import org.teavm.diagnostics.Diagnostics; import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.Address; import org.teavm.interop.Address;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.TextLocation; import org.teavm.model.TextLocation;
import org.teavm.model.ValueType; 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.Allocator;
import org.teavm.runtime.RuntimeArray; import org.teavm.runtime.RuntimeArray;
import org.teavm.runtime.RuntimeClass; import org.teavm.runtime.RuntimeClass;
@ -909,10 +910,12 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
} }
if (expr.getType() == InvocationType.STATIC || expr.getType() == InvocationType.SPECIAL) { 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); WasmCall call = new WasmCall(methodName);
if (context.getImportedMethod(expr.getMethod()) != null) { if (context.getImportedMethod(reference) != null) {
call.setImported(true); call.setImported(true);
} }
for (Expr argument : expr.getArguments()) { for (Expr argument : expr.getArguments()) {
@ -942,23 +945,31 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
result = block; result = block;
} else { } else {
MethodReference reference = expr.getMethod();
accept(expr.getArguments().get(0)); accept(expr.getArguments().get(0));
WasmExpression instance = result; WasmExpression instance = result;
WasmBlock block = new WasmBlock(false); WasmBlock block = new WasmBlock(false);
block.setType(WasmGeneratorUtil.mapType(expr.getMethod().getReturnType())); block.setType(WasmGeneratorUtil.mapType(reference.getReturnType()));
WasmLocal instanceVar = getTemporary(WasmType.INT32); WasmLocal instanceVar = getTemporary(WasmType.INT32);
block.getBody().add(new WasmSetLocal(instanceVar, instance)); block.getBody().add(new WasmSetLocal(instanceVar, instance));
instance = new WasmGetLocal(instanceVar); instance = new WasmGetLocal(instanceVar);
int vtableOffset = classGenerator.getClassSize(RuntimeClass.class.getName()); int vtableOffset = classGenerator.getClassSize(RuntimeClass.class.getName());
VirtualTableEntry vtableEntry = context.getVirtualTableProvider().lookup(expr.getMethod()); VirtualTable vtable = context.getVirtualTableProvider().lookup(reference.getClassName());
if (vtableEntry == null) { if (vtable != null) {
vtable = vtable.findMethodContainer(reference.getDescriptor());
}
if (vtable == null) {
result = new WasmUnreachable(); result = new WasmUnreachable();
return; return;
} }
int vtableIndex = vtable.getMethods().indexOf(reference.getDescriptor());
if (vtable.getParent() != null) {
vtableIndex += vtable.getParent().size();
}
WasmExpression methodIndex = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, 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); methodIndex = new WasmLoadInt32(4, methodIndex, WasmInt32Subtype.INT32);
WasmIndirectCall call = new WasmIndirectCall(methodIndex); WasmIndirectCall call = new WasmIndirectCall(methodIndex);

View File

@ -333,13 +333,10 @@ public class WasmBinaryRenderer {
WasmBinaryWriter functionsSubsection = new WasmBinaryWriter(); WasmBinaryWriter functionsSubsection = new WasmBinaryWriter();
Collection<WasmFunction> functions = module.getFunctions().values(); Collection<WasmFunction> functions = module.getFunctions().values();
functions = functions.stream().filter(f -> f.getImportName() != null).collect(Collectors.toList());
functionsSubsection.writeLEB(functions.size()); functionsSubsection.writeLEB(functions.size());
for (WasmFunction function : functions) { for (WasmFunction function : functions) {
if (function.getImportName() != null) {
continue;
}
functionsSubsection.writeLEB(functionIndexes.get(function.getName())); functionsSubsection.writeLEB(functionIndexes.get(function.getName()));
functionsSubsection.writeAsciiString(function.getName()); functionsSubsection.writeAsciiString(function.getName());
} }

View File

@ -41,3 +41,12 @@ inline static float reinterpret_int32(int32_t v) {
reinterpret_union_32.i = v; reinterpret_union_32.i = v;
return reinterpret_union_32.f; return reinterpret_union_32.f;
} }
static void logOutOfMemory() {
abort();
}
static void logString(int32_t v) {
}
static void logInt(int32_t v) {
}

View File

@ -154,7 +154,6 @@
<optimizationLevel>FULL</optimizationLevel> <optimizationLevel>FULL</optimizationLevel>
</configuration> </configuration>
</execution> </execution>
<!--
<execution> <execution>
<id>wasm-client</id> <id>wasm-client</id>
<goals> <goals>
@ -169,7 +168,6 @@
<heapSize>8</heapSize> <heapSize>8</heapSize>
</configuration> </configuration>
</execution> </execution>
-->
<execution> <execution>
<id>native-client</id> <id>native-client</id>
<goals> <goals>