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));
}
@Override
protected WasmExpression nullLiteral() {
return new WasmInt32Constant(0);
}
@Override
public void visit(SubscriptExpr expr) {
WasmExpression ptr = getArrayElementPointer(expr);

View File

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

View File

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

View File

@ -17,6 +17,7 @@ package org.teavm.backend.wasm.generate.gc.methods;
import java.util.List;
import org.teavm.ast.ArrayType;
import org.teavm.ast.BinaryExpr;
import org.teavm.ast.Expr;
import org.teavm.ast.InvocationExpr;
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.WasmGetGlobal;
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.WasmReferencesEqual;
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
import org.teavm.backend.wasm.model.expression.WasmStructGet;
@ -167,11 +172,45 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
return new WasmGetGlobal(classConstant.getPointer());
}
@Override
protected WasmExpression nullLiteral() {
return new WasmNullConstant(WasmType.Reference.STRUCT);
}
@Override
protected CallSiteIdentifier generateCallSiteId(TextLocation location) {
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
protected WasmExpression generateVirtualCall(WasmLocal instance, MethodReference method,
List<WasmExpression> arguments) {

View File

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.teavm.common.Graph;
import org.teavm.common.GraphUtils;
public class WasmModule {
@ -93,32 +94,70 @@ public class WasmModule {
}
public void prepareForRendering() {
prepareRecursiveTypes();
prepareTypes();
}
private void prepareRecursiveTypes() {
private void prepareTypes() {
var typeGraph = WasmTypeGraphBuilder.buildTypeGraph(types, types.size());
var newList = new ArrayList<WasmCompositeType>();
var typesInScc = new boolean[types.size()];
for (var scc : GraphUtils.findStronglyConnectedComponents(typeGraph)) {
var sccs = GraphUtils.findStronglyConnectedComponents(typeGraph);
var sccStartNode = new int[types.size()];
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]);
firstType.recursiveTypeCount = scc.length;
for (var i = 0; i < scc.length; i++) {
var index = scc[i];
var type = types.get(index);
newList.add(type);
type.indexInRecursiveType = i;
typesInScc[index] = true;
sccStartNode[scc[i]] = sccStartNode[scc[0]];
}
}
for (var type : types) {
if (!typesInScc[type.index]) {
newList.add(type);
}
var sorting = new TypeSorting();
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();
for (var type : newList) {
for (var type : sorting.sorted) {
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;
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_TABLE = 4;
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_START = 8;
private static final int SECTION_ELEMENT = 9;
@ -88,6 +89,7 @@ public class WasmBinaryRenderer {
renderTable(module);
renderMemory(module);
renderTags(module);
renderGlobals(module);
renderExport(module);
renderStart(module);
renderElement(module);
@ -205,6 +207,24 @@ public class WasmBinaryRenderer {
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) {
// 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) {
pushLocation(expression);
writer.writeByte(0xD0);
writeBlockType(expression.getType());
writer.writeHeapType(expression.getType(), module);
popLocation();
}
@ -1146,7 +1146,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
public void visit(WasmFunctionReference expression) {
pushLocation(expression);
writer.writeByte(0xd2);
writer.writeInt32(module.functions.indexOf(expression.getFunction()));
writer.writeLEB(module.functions.indexOf(expression.getFunction()));
popLocation();
}

View File

@ -41,33 +41,45 @@ public class WasmBinaryWriter {
if (type instanceof WasmType.Number) {
writeType(((WasmType.Number) type).number);
} else if (type instanceof WasmType.SpecialReference) {
switch (((WasmType.SpecialReference) type).kind) {
case ANY:
writeByte(0x6e);
break;
case EXTERN:
writeByte(0x6f);
break;
case FUNC:
writeByte(0x70);
break;
case STRUCT:
writeByte(0x6b);
break;
case ARRAY:
writeByte(0x6a);
break;
}
writeSpecialHeapType(((WasmType.SpecialReference) type).kind);
} else if (type instanceof WasmType.CompositeReference) {
writeByte(0x63);
var composite = ((WasmType.CompositeReference) type).composite;
var index = isRecursiveMember
? composite.getIndexInRecursiveType()
: module.types.indexOf(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:
writeByte(0x6e);
break;
case EXTERN:
writeByte(0x6f);
break;
case FUNC:
writeByte(0x70);
break;
case STRUCT:
writeByte(0x6b);
break;
case ARRAY:
writeByte(0x6a);
break;
}
}
public void writeType(WasmNumType type) {
switch (type) {
case INT32:

View File

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