wasm gc: fix issues in generation of types, globals and some expressions

This commit is contained in:
Alexey Andreev 2024-07-29 20:41:58 +02:00
parent ea29208b6c
commit 87aaa0b452
10 changed files with 156 additions and 38 deletions

View File

@ -300,6 +300,11 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
return new WasmInt32Constant(classGenerator.getClassPointer(type)); return new WasmInt32Constant(classGenerator.getClassPointer(type));
} }
@Override
protected WasmExpression nullLiteral() {
return new WasmInt32Constant(0);
}
@Override @Override
public void visit(SubscriptExpr expr) { public void visit(SubscriptExpr expr) {
WasmExpression ptr = getArrayElementPointer(expr); WasmExpression ptr = getArrayElementPointer(expr);

View File

@ -553,7 +553,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
@Override @Override
public void visit(ConstantExpr expr) { public void visit(ConstantExpr expr) {
if (expr.getValue() == null) { if (expr.getValue() == null) {
result = new WasmInt32Constant(0); result = nullLiteral();
} else if (expr.getValue() instanceof Integer) { } else if (expr.getValue() instanceof Integer) {
result = new WasmInt32Constant((Integer) expr.getValue()); result = new WasmInt32Constant((Integer) expr.getValue());
} else if (expr.getValue() instanceof Long) { } else if (expr.getValue() instanceof Long) {
@ -569,8 +569,11 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
} else { } else {
throw new IllegalArgumentException("Constant unsupported: " + expr.getValue()); throw new IllegalArgumentException("Constant unsupported: " + expr.getValue());
} }
result.setLocation(expr.getLocation());
} }
protected abstract WasmExpression nullLiteral();
protected abstract WasmExpression stringLiteral(String s); protected abstract WasmExpression stringLiteral(String s);
protected abstract WasmExpression classLiteral(ValueType type); protected abstract WasmExpression classLiteral(ValueType type);

View File

@ -335,8 +335,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
var virtualTable = virtualTables.lookup(className); var virtualTable = virtualTables.lookup(className);
var structure = new WasmStructure(names.forClassClass(className)); var structure = new WasmStructure(names.forClassClass(className));
module.types.add(structure); module.types.add(structure);
addVirtualTableFields(structure, virtualTable);
fillClassFields(structure.getFields(), "java.lang.Class"); fillClassFields(structure.getFields(), "java.lang.Class");
addVirtualTableFields(structure, virtualTable);
return structure; return structure;
} }

View File

@ -17,6 +17,7 @@ package org.teavm.backend.wasm.generate.gc.methods;
import java.util.List; import java.util.List;
import org.teavm.ast.ArrayType; import org.teavm.ast.ArrayType;
import org.teavm.ast.BinaryExpr;
import org.teavm.ast.Expr; import org.teavm.ast.Expr;
import org.teavm.ast.InvocationExpr; import org.teavm.ast.InvocationExpr;
import org.teavm.ast.QualificationExpr; import org.teavm.ast.QualificationExpr;
@ -40,7 +41,11 @@ import org.teavm.backend.wasm.model.expression.WasmCast;
import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpression;
import org.teavm.backend.wasm.model.expression.WasmGetGlobal; import org.teavm.backend.wasm.model.expression.WasmGetGlobal;
import org.teavm.backend.wasm.model.expression.WasmGetLocal; import org.teavm.backend.wasm.model.expression.WasmGetLocal;
import org.teavm.backend.wasm.model.expression.WasmIntType;
import org.teavm.backend.wasm.model.expression.WasmIntUnary;
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
import org.teavm.backend.wasm.model.expression.WasmNullConstant; import org.teavm.backend.wasm.model.expression.WasmNullConstant;
import org.teavm.backend.wasm.model.expression.WasmReferencesEqual;
import org.teavm.backend.wasm.model.expression.WasmSetGlobal; import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
import org.teavm.backend.wasm.model.expression.WasmSetLocal; import org.teavm.backend.wasm.model.expression.WasmSetLocal;
import org.teavm.backend.wasm.model.expression.WasmStructGet; import org.teavm.backend.wasm.model.expression.WasmStructGet;
@ -167,11 +172,45 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
return new WasmGetGlobal(classConstant.getPointer()); return new WasmGetGlobal(classConstant.getPointer());
} }
@Override
protected WasmExpression nullLiteral() {
return new WasmNullConstant(WasmType.Reference.STRUCT);
}
@Override @Override
protected CallSiteIdentifier generateCallSiteId(TextLocation location) { protected CallSiteIdentifier generateCallSiteId(TextLocation location) {
return new SimpleCallSite(); return new SimpleCallSite();
} }
@Override
public void visit(BinaryExpr expr) {
if (expr.getType() == null) {
switch (expr.getOperation()) {
case EQUALS: {
accept(expr.getFirstOperand());
var first = result;
accept(expr.getSecondOperand());
var second = result;
result = new WasmReferencesEqual(first, second);
result.setLocation(expr.getLocation());
return;
}
case NOT_EQUALS:
accept(expr.getFirstOperand());
var first = result;
accept(expr.getSecondOperand());
var second = result;
result = new WasmReferencesEqual(first, second);
result = new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, result);
result.setLocation(expr.getLocation());
return;
default:
break;
}
}
super.visit(expr);
}
@Override @Override
protected WasmExpression generateVirtualCall(WasmLocal instance, MethodReference method, protected WasmExpression generateVirtualCall(WasmLocal instance, MethodReference method,
List<WasmExpression> arguments) { List<WasmExpression> arguments) {

View File

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.teavm.common.Graph;
import org.teavm.common.GraphUtils; import org.teavm.common.GraphUtils;
public class WasmModule { public class WasmModule {
@ -93,32 +94,70 @@ public class WasmModule {
} }
public void prepareForRendering() { public void prepareForRendering() {
prepareRecursiveTypes(); prepareTypes();
} }
private void prepareRecursiveTypes() { private void prepareTypes() {
var typeGraph = WasmTypeGraphBuilder.buildTypeGraph(types, types.size()); var typeGraph = WasmTypeGraphBuilder.buildTypeGraph(types, types.size());
var newList = new ArrayList<WasmCompositeType>(); var sccs = GraphUtils.findStronglyConnectedComponents(typeGraph);
var typesInScc = new boolean[types.size()]; var sccStartNode = new int[types.size()];
for (var scc : GraphUtils.findStronglyConnectedComponents(typeGraph)) { for (var i = 0; i < sccStartNode.length; ++i) {
sccStartNode[i] = i;
}
var sccsByIndex = new int[types.size()][];
for (var scc : sccs) {
sccsByIndex[scc[0]] = scc;
var firstType = types.get(scc[0]); var firstType = types.get(scc[0]);
firstType.recursiveTypeCount = scc.length; firstType.recursiveTypeCount = scc.length;
for (var i = 0; i < scc.length; i++) { for (var i = 0; i < scc.length; i++) {
var index = scc[i]; var index = scc[i];
var type = types.get(index); var type = types.get(index);
newList.add(type);
type.indexInRecursiveType = i; type.indexInRecursiveType = i;
typesInScc[index] = true; sccStartNode[scc[i]] = sccStartNode[scc[0]];
} }
} }
for (var type : types) {
if (!typesInScc[type.index]) { var sorting = new TypeSorting();
newList.add(type); sorting.original = types;
} sorting.graph = typeGraph;
sorting.visited = new boolean[types.size()];
sorting.sccMap = sccStartNode;
sorting.sccsByIndex = sccsByIndex;
for (var i = 0; i < types.size(); ++i) {
sorting.visit(i);
} }
types.clear(); types.clear();
for (var type : newList) { for (var type : sorting.sorted) {
types.add(type); types.add(type);
} }
} }
private static class TypeSorting {
WasmCollection<WasmCompositeType> original;
Graph graph;
boolean[] visited;
int[] sccMap;
int[][] sccsByIndex;
List<WasmCompositeType> sorted = new ArrayList<>();
void visit(int typeIndex) {
typeIndex = sccMap[typeIndex];
if (visited[typeIndex]) {
return;
}
visited[typeIndex] = true;
for (var outgoing : graph.outgoingEdges(typeIndex)) {
visit(outgoing);
}
var scc = sccsByIndex[typeIndex];
if (scc == null) {
sorted.add(original.get(typeIndex));
} else {
for (var index : scc) {
sorted.add(original.get(index));
}
}
}
}
} }

View File

@ -72,7 +72,7 @@ public abstract class WasmType {
} }
} }
public static final class SpecialReference extends WasmType { public static final class SpecialReference extends Reference {
public final SpecialReferenceKind kind; public final SpecialReferenceKind kind;
private SpecialReference(SpecialReferenceKind kind) { private SpecialReference(SpecialReferenceKind kind) {

View File

@ -38,6 +38,7 @@ public class WasmBinaryRenderer {
private static final int SECTION_FUNCTION = 3; private static final int SECTION_FUNCTION = 3;
private static final int SECTION_TABLE = 4; private static final int SECTION_TABLE = 4;
private static final int SECTION_MEMORY = 5; private static final int SECTION_MEMORY = 5;
private static final int SECTION_GLOBAL = 6;
private static final int SECTION_EXPORT = 7; private static final int SECTION_EXPORT = 7;
private static final int SECTION_START = 8; private static final int SECTION_START = 8;
private static final int SECTION_ELEMENT = 9; private static final int SECTION_ELEMENT = 9;
@ -88,6 +89,7 @@ public class WasmBinaryRenderer {
renderTable(module); renderTable(module);
renderMemory(module); renderMemory(module);
renderTags(module); renderTags(module);
renderGlobals(module);
renderExport(module); renderExport(module);
renderStart(module); renderStart(module);
renderElement(module); renderElement(module);
@ -205,6 +207,24 @@ public class WasmBinaryRenderer {
writeSection(SECTION_MEMORY, "memory", section.getData()); writeSection(SECTION_MEMORY, "memory", section.getData());
} }
private void renderGlobals(WasmModule module) {
if (module.globals.isEmpty()) {
return;
}
var section = new WasmBinaryWriter();
var visitor = new WasmBinaryRenderingVisitor(section, module, null, null, 0);
section.writeLEB(module.globals.size());
for (var global : module.globals) {
section.writeType(global.getType(), module);
section.writeByte(1); // mutable
global.getInitialValue().acceptVisitor(visitor);
section.writeByte(0x0b);
}
writeSection(SECTION_GLOBAL, "global", section.getData());
}
private void renderExport(WasmModule module) { private void renderExport(WasmModule module) {
// https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#export-section // https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#export-section

View File

@ -253,7 +253,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
public void visit(WasmNullConstant expression) { public void visit(WasmNullConstant expression) {
pushLocation(expression); pushLocation(expression);
writer.writeByte(0xD0); writer.writeByte(0xD0);
writeBlockType(expression.getType()); writer.writeHeapType(expression.getType(), module);
popLocation(); popLocation();
} }
@ -1146,7 +1146,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
public void visit(WasmFunctionReference expression) { public void visit(WasmFunctionReference expression) {
pushLocation(expression); pushLocation(expression);
writer.writeByte(0xd2); writer.writeByte(0xd2);
writer.writeInt32(module.functions.indexOf(expression.getFunction())); writer.writeLEB(module.functions.indexOf(expression.getFunction()));
popLocation(); popLocation();
} }

View File

@ -41,7 +41,27 @@ public class WasmBinaryWriter {
if (type instanceof WasmType.Number) { if (type instanceof WasmType.Number) {
writeType(((WasmType.Number) type).number); writeType(((WasmType.Number) type).number);
} else if (type instanceof WasmType.SpecialReference) { } else if (type instanceof WasmType.SpecialReference) {
switch (((WasmType.SpecialReference) type).kind) { writeSpecialHeapType(((WasmType.SpecialReference) type).kind);
} else if (type instanceof WasmType.CompositeReference) {
writeByte(0x63);
var composite = ((WasmType.CompositeReference) type).composite;
var index = module.types.indexOf(composite);
writeSignedLEB(index);
}
}
public void writeHeapType(WasmType.Reference type, WasmModule module) {
if (type instanceof WasmType.CompositeReference) {
var composite = ((WasmType.CompositeReference) type).composite;
var index = module.types.indexOf(composite);
writeSignedLEB(index);
} else {
writeSpecialHeapType(((WasmType.SpecialReference) type).kind);
}
}
private void writeSpecialHeapType(WasmType.SpecialReferenceKind type) {
switch (type) {
case ANY: case ANY:
writeByte(0x6e); writeByte(0x6e);
break; break;
@ -58,14 +78,6 @@ public class WasmBinaryWriter {
writeByte(0x6a); writeByte(0x6a);
break; break;
} }
} else if (type instanceof WasmType.CompositeReference) {
writeByte(0x63);
var composite = ((WasmType.CompositeReference) type).composite;
var index = isRecursiveMember
? composite.getIndexInRecursiveType()
: module.types.indexOf(composite);
writeSignedLEB(index);
}
} }
public void writeType(WasmNumType type) { public void writeType(WasmNumType type) {

View File

@ -75,7 +75,7 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
break; break;
} }
} else { } else {
section.writeType(storageType.asUnpackedType(), module); section.writeType(storageType.asUnpackedType(), module, true);
} }
} }
} }