wasm gc: add subtyping information to types, fix generation of expressions

This commit is contained in:
Alexey Andreev 2024-07-30 20:57:36 +02:00
parent a1a776ea9b
commit 5572d4b5d7
12 changed files with 81 additions and 36 deletions

View File

@ -33,13 +33,11 @@ import org.teavm.model.MethodReference;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
public class WasmGCModuleGenerator { public class WasmGCModuleGenerator {
private final WasmGCTarget wasmGCTarget;
private WasmGCDeclarationsGenerator declarationsGenerator; private WasmGCDeclarationsGenerator declarationsGenerator;
private WasmFunction initializer; private WasmFunction initializer;
private WasmGlobal initializerRef; private WasmGlobal initializerRef;
public WasmGCModuleGenerator(WasmGCTarget wasmGCTarget, WasmGCDeclarationsGenerator declarationsGenerator) { public WasmGCModuleGenerator(WasmGCDeclarationsGenerator declarationsGenerator) {
this.wasmGCTarget = wasmGCTarget;
this.declarationsGenerator = declarationsGenerator; this.declarationsGenerator = declarationsGenerator;
} }
@ -64,8 +62,7 @@ public class WasmGCModuleGenerator {
var tempVars = new TemporaryVariablePool(mainFunctionCaller); var tempVars = new TemporaryVariablePool(mainFunctionCaller);
var genUtil = new WasmGCGenerationUtil(declarationsGenerator.classInfoProvider(), tempVars); var genUtil = new WasmGCGenerationUtil(declarationsGenerator.classInfoProvider(), tempVars);
var stringArrayType = declarationsGenerator.typeMapper() var stringArrayType = declarationsGenerator.typeMapper()
.mapType(ValueType.parse(String[].class)) .mapType(ValueType.parse(String[].class));
.asUnpackedType();
var arrayVar = tempVars.acquire(stringArrayType); var arrayVar = tempVars.acquire(stringArrayType);
genUtil.allocateArray(ValueType.parse(String.class), new WasmInt32Constant(0), null, genUtil.allocateArray(ValueType.parse(String.class), new WasmInt32Constant(0), null,
arrayVar, mainFunctionCaller.getBody()); arrayVar, mainFunctionCaller.getBody());

View File

@ -118,7 +118,7 @@ public class WasmGCTarget implements TeaVMTarget {
customGenerators customGenerators
); );
declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger()); declarationsGenerator.setFriendlyToDebugger(controller.isFriendlyToDebugger());
var moduleGenerator = new WasmGCModuleGenerator(this, declarationsGenerator); var moduleGenerator = new WasmGCModuleGenerator(declarationsGenerator);
var mainFunction = moduleGenerator.generateMainFunction(controller.getEntryPoint()); var mainFunction = moduleGenerator.generateMainFunction(controller.getEntryPoint());
mainFunction.setExportName(controller.getEntryPointName()); mainFunction.setExportName(controller.getEntryPointName());
mainFunction.setName(controller.getEntryPointName()); mainFunction.setName(controller.getEntryPointName());

View File

@ -761,7 +761,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
var callSiteId = generateCallSiteId(expr.getLocation()); var callSiteId = generateCallSiteId(expr.getLocation());
if (needsCallSiteId() && isManagedCall(expr.getMethod())) { if (needsCallSiteId() && isManagedCall(expr.getMethod())) {
var invocation = generateInvocation(expr, callSiteId); var invocation = generateInvocation(expr, callSiteId);
var type = WasmGeneratorUtil.mapType(expr.getMethod().getReturnType()); var type = mapType(expr.getMethod().getReturnType());
List<WasmExpression> targetList; List<WasmExpression> targetList;
WasmBlock block; WasmBlock block;

View File

@ -182,6 +182,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
? ((ValueType.Object) type).getClassName() ? ((ValueType.Object) type).getClassName()
: null; : null;
classInfo.structure = new WasmStructure(name != null ? names.forClass(name) : null); classInfo.structure = new WasmStructure(name != null ? names.forClass(name) : null);
if (name != null) {
var classReader = classSource.get(name);
if (classReader != null && classReader.getParent() != null) {
classInfo.structure.setSupertype(getClassInfo(classReader.getParent()).structure);
}
} else {
classInfo.structure.setSupertype(standardClasses.objectClass().structure);
}
module.types.add(classInfo.structure); module.types.add(classInfo.structure);
fillFields(classInfo.structure.getFields(), type); fillFields(classInfo.structure.getFields(), type);
} }
@ -318,7 +326,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
call.getArguments().add(new WasmCast(new WasmGetLocal(instanceParam), castTarget)); call.getArguments().add(new WasmCast(new WasmGetLocal(instanceParam), castTarget));
var params = new WasmLocal[method.parameterCount()]; var params = new WasmLocal[method.parameterCount()];
for (var i = 0; i < method.parameterCount(); ++i) { for (var i = 0; i < method.parameterCount(); ++i) {
params[i] = new WasmLocal(typeMapper.mapType(method.parameterType(i)).asUnpackedType()); params[i] = new WasmLocal(typeMapper.mapType(method.parameterType(i)));
call.getArguments().add(new WasmGetLocal(params[i])); call.getArguments().add(new WasmGetLocal(params[i]));
} }
wrapperFunction.getLocalVariables().addAll(List.of(params)); wrapperFunction.getLocalVariables().addAll(List.of(params));
@ -333,6 +341,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private WasmStructure initRegularClassStructure(String className) { private WasmStructure initRegularClassStructure(String className) {
var virtualTable = virtualTables.lookup(className); var virtualTable = virtualTables.lookup(className);
var structure = new WasmStructure(names.forClassClass(className)); var structure = new WasmStructure(names.forClassClass(className));
structure.setSupertype(standardClasses.classClass().getStructure());
module.types.add(structure); module.types.add(structure);
structure.getFields().add(standardClasses.classClass().getType().asStorage()); structure.getFields().add(standardClasses.classClass().getType().asStorage());
structure.getFields().add(WasmType.Reference.ANY.asStorage()); structure.getFields().add(WasmType.Reference.ANY.asStorage());
@ -354,12 +363,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
} }
private WasmFunctionType getFunctionType(String className, MethodDescriptor methodDesc) { private WasmFunctionType getFunctionType(String className, MethodDescriptor methodDesc) {
var returnType = typeMapper.mapType(methodDesc.getResultType()).asUnpackedType(); var returnType = typeMapper.mapType(methodDesc.getResultType());
var javaParamTypes = methodDesc.getParameterTypes(); var javaParamTypes = methodDesc.getParameterTypes();
var paramTypes = new WasmType[javaParamTypes.length + 1]; var paramTypes = new WasmType[javaParamTypes.length + 1];
paramTypes[0] = getClassInfo(className).getType(); paramTypes[0] = getClassInfo(className).getType();
for (var i = 0; i < javaParamTypes.length; ++i) { for (var i = 0; i < javaParamTypes.length; ++i) {
paramTypes[i + 1] = typeMapper.mapType(javaParamTypes[i]).asUnpackedType(); paramTypes[i + 1] = typeMapper.mapType(javaParamTypes[i]);
} }
return functionTypes.of(returnType, paramTypes); return functionTypes.of(returnType, paramTypes);
} }
@ -414,7 +423,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
javaType = ValueType.object("java.lang.Object"); javaType = ValueType.object("java.lang.Object");
} }
var type = typeMapper.mapType(javaType).asUnpackedType(); var type = typeMapper.mapType(javaType);
var global = new WasmGlobal(names.forStaticField(fieldRef), type, WasmExpression.defaultValueOfType(type)); var global = new WasmGlobal(names.forStaticField(fieldRef), type, WasmExpression.defaultValueOfType(type));
module.globals.add(global); module.globals.add(global);
@ -462,7 +471,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
continue; continue;
} }
fieldIndexes.putIfAbsent(field.getReference(), fields.size()); fieldIndexes.putIfAbsent(field.getReference(), fields.size());
fields.add(typeMapper.mapType(field.getType())); fields.add(typeMapper.mapStorageType(field.getType()));
} }
if (className.equals("java.lang.Class")) { if (className.equals("java.lang.Class")) {
classFlagsOffset = fields.size(); classFlagsOffset = fields.size();
@ -483,7 +492,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
} }
private void fillArrayField(List<WasmStorageType> fields, ValueType elementType) { private void fillArrayField(List<WasmStorageType> fields, ValueType elementType) {
var wasmArray = new WasmArray(null, () -> typeMapper.mapType(elementType)); var wasmArray = new WasmArray(null, () -> typeMapper.mapStorageType(elementType));
module.types.add(wasmArray); module.types.add(wasmArray);
fields.add(wasmArray.getReference().asStorage()); fields.add(wasmArray.getReference().asStorage());
} }

View File

@ -27,7 +27,7 @@ public class WasmGCTypeMapper {
this.classInfoProvider = classInfoProvider; this.classInfoProvider = classInfoProvider;
} }
public WasmStorageType mapType(ValueType type) { public WasmStorageType mapStorageType(ValueType type) {
if (type instanceof ValueType.Primitive) { if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) { switch (((ValueType.Primitive) type).getKind()) {
case BYTE: case BYTE:
@ -51,4 +51,29 @@ public class WasmGCTypeMapper {
return classInfoProvider.getClassInfo(type).getType().asStorage(); return classInfoProvider.getClassInfo(type).getType().asStorage();
} }
} }
public WasmType mapType(ValueType type) {
if (type instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) type).getKind()) {
case BYTE:
case BOOLEAN:
case SHORT:
case CHARACTER:
case INTEGER:
return WasmType.INT32;
case LONG:
return WasmType.INT64;
case FLOAT:
return WasmType.FLOAT32;
case DOUBLE:
return WasmType.FLOAT64;
default:
throw new IllegalArgumentException();
}
} else if (type instanceof ValueType.Void) {
return null;
} else {
return classInfoProvider.getClassInfo(type).getType();
}
}
} }

View File

@ -334,7 +334,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
@Override @Override
protected WasmType mapType(ValueType type) { protected WasmType mapType(ValueType type) {
return context.typeMapper().mapType(type).asUnpackedType(); return context.typeMapper().mapType(type);
} }
@Override @Override

View File

@ -139,10 +139,10 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
} }
private WasmFunction createStaticFunction(MethodReference methodReference) { private WasmFunction createStaticFunction(MethodReference methodReference) {
var returnType = typeMapper.mapType(methodReference.getReturnType()).asUnpackedType(); var returnType = typeMapper.mapType(methodReference.getReturnType());
var parameterTypes = new WasmType[methodReference.parameterCount()]; var parameterTypes = new WasmType[methodReference.parameterCount()];
for (var i = 0; i < parameterTypes.length; ++i) { for (var i = 0; i < parameterTypes.length; ++i) {
parameterTypes[i] = typeMapper.mapType(methodReference.parameterType(i)).asUnpackedType(); parameterTypes[i] = typeMapper.mapType(methodReference.parameterType(i));
} }
var function = new WasmFunction(functionTypes.of(returnType, parameterTypes)); var function = new WasmFunction(functionTypes.of(returnType, parameterTypes));
function.setName(names.forMethod(methodReference)); function.setName(names.forMethod(methodReference));
@ -166,11 +166,11 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
} }
private WasmFunction createInstanceFunction(MethodReference methodReference) { private WasmFunction createInstanceFunction(MethodReference methodReference) {
var returnType = typeMapper.mapType(methodReference.getReturnType()).asUnpackedType(); var returnType = typeMapper.mapType(methodReference.getReturnType());
var parameterTypes = new WasmType[methodReference.parameterCount() + 1]; var parameterTypes = new WasmType[methodReference.parameterCount() + 1];
parameterTypes[0] = typeMapper.mapType(ValueType.object(methodReference.getClassName())).asUnpackedType(); parameterTypes[0] = typeMapper.mapType(ValueType.object(methodReference.getClassName()));
for (var i = 0; i < methodReference.parameterCount(); ++i) { for (var i = 0; i < methodReference.parameterCount(); ++i) {
parameterTypes[i + 1] = typeMapper.mapType(methodReference.parameterType(i)).asUnpackedType(); parameterTypes[i + 1] = typeMapper.mapType(methodReference.parameterType(i));
} }
var function = new WasmFunction(functionTypes.of(returnType, parameterTypes)); var function = new WasmFunction(functionTypes.of(returnType, parameterTypes));
function.setName(names.forMethod(methodReference)); function.setName(names.forMethod(methodReference));
@ -236,7 +236,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
for (var i = firstVar; i < ast.getVariables().size(); ++i) { for (var i = firstVar; i < ast.getVariables().size(); ++i) {
var localVar = ast.getVariables().get(i); var localVar = ast.getVariables().get(i);
var representative = method.getProgram().variableAt(variableRepresentatives[i]); var representative = method.getProgram().variableAt(variableRepresentatives[i]);
var type = typeMapper.mapType(typeInference.typeOf(representative)).asUnpackedType(); var type = typeMapper.mapType(typeInference.typeOf(representative));
var wasmLocal = new WasmLocal(type, localVar.getName()); var wasmLocal = new WasmLocal(type, localVar.getName());
function.add(wasmLocal); function.add(wasmLocal);
} }

View File

@ -20,6 +20,7 @@ import java.util.List;
public class WasmStructure extends WasmCompositeType { public class WasmStructure extends WasmCompositeType {
private List<WasmStorageType> fields = new ArrayList<>(); private List<WasmStorageType> fields = new ArrayList<>();
private WasmStructure supertype;
public WasmStructure(String name) { public WasmStructure(String name) {
super(name); super(name);
@ -29,6 +30,14 @@ public class WasmStructure extends WasmCompositeType {
return fields; return fields;
} }
public WasmStructure getSupertype() {
return supertype;
}
public void setSupertype(WasmStructure supertype) {
this.supertype = supertype;
}
@Override @Override
public void acceptVisitor(WasmCompositeTypeVisitor visitor) { public void acceptVisitor(WasmCompositeTypeVisitor visitor) {
visitor.visit(this); visitor.visit(this);

View File

@ -42,6 +42,9 @@ final class WasmTypeGraphBuilder {
@Override @Override
public void visit(WasmStructure type) { public void visit(WasmStructure type) {
if (type.getSupertype() != null) {
addEdge(type.getSupertype().getReference());
}
for (var field : type.getFields()) { for (var field : type.getFields()) {
addEdge(field.asUnpackedType()); addEdge(field.asUnpackedType());
} }

View File

@ -1042,7 +1042,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
} }
writer.writeByte(0xfb); writer.writeByte(0xfb);
writer.writeByte(0); writer.writeByte(0);
writer.writeInt32(module.types.indexOf(expression.getType())); writer.writeLEB(module.types.indexOf(expression.getType()));
popLocation(); popLocation();
} }
@ -1051,7 +1051,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
pushLocation(expression); pushLocation(expression);
writer.writeByte(0xfb); writer.writeByte(0xfb);
writer.writeByte(1); writer.writeByte(1);
writer.writeInt32(module.types.indexOf(expression.getType())); writer.writeLEB(module.types.indexOf(expression.getType()));
popLocation(); popLocation();
} }
@ -1072,8 +1072,8 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
break; break;
} }
} }
writer.writeInt32(module.types.indexOf(expression.getType())); writer.writeLEB(module.types.indexOf(expression.getType()));
writer.writeInt32(expression.getFieldIndex()); writer.writeLEB(expression.getFieldIndex());
popLocation(); popLocation();
} }
@ -1084,8 +1084,8 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
expression.getValue().acceptVisitor(this); expression.getValue().acceptVisitor(this);
writer.writeByte(0xfb); writer.writeByte(0xfb);
writer.writeByte(5); writer.writeByte(5);
writer.writeInt32(module.types.indexOf(expression.getType())); writer.writeLEB(module.types.indexOf(expression.getType()));
writer.writeInt32(expression.getFieldIndex()); writer.writeLEB(expression.getFieldIndex());
popLocation(); popLocation();
} }
@ -1095,7 +1095,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
expression.getLength().acceptVisitor(this); expression.getLength().acceptVisitor(this);
writer.writeByte(0xfb); writer.writeByte(0xfb);
writer.writeByte(7); writer.writeByte(7);
writer.writeInt32(module.types.indexOf(expression.getType())); writer.writeLEB(module.types.indexOf(expression.getType()));
popLocation(); popLocation();
} }
@ -1117,7 +1117,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
break; break;
} }
} }
writer.writeInt32(module.types.indexOf(expression.getType())); writer.writeLEB(module.types.indexOf(expression.getType()));
popLocation(); popLocation();
} }
@ -1129,7 +1129,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor {
expression.getValue().acceptVisitor(this); expression.getValue().acceptVisitor(this);
writer.writeByte(0xfb); writer.writeByte(0xfb);
writer.writeByte(14); writer.writeByte(14);
writer.writeInt32(module.types.indexOf(expression.getType())); writer.writeLEB(module.types.indexOf(expression.getType()));
popLocation(); popLocation();
} }

View File

@ -30,10 +30,6 @@ public class WasmBinaryWriter {
} }
public void writeType(WasmType type, WasmModule module) { public void writeType(WasmType type, WasmModule module) {
writeType(type, module, false);
}
public void writeType(WasmType type, WasmModule module, boolean isRecursiveMember) {
if (type == null) { if (type == null) {
writeByte(0x40); writeByte(0x40);
return; return;

View File

@ -25,7 +25,6 @@ import org.teavm.backend.wasm.model.WasmStructure;
public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor { public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor {
private WasmModule module; private WasmModule module;
private WasmBinaryWriter section; private WasmBinaryWriter section;
private boolean reference;
public WasmCompositeTypeBinaryRenderer(WasmModule module, WasmBinaryWriter section) { public WasmCompositeTypeBinaryRenderer(WasmModule module, WasmBinaryWriter section) {
this.module = module; this.module = module;
@ -34,6 +33,13 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
@Override @Override
public void visit(WasmStructure type) { public void visit(WasmStructure type) {
section.writeByte(0x50);
if (type.getSupertype() != null) {
section.writeLEB(1); // number of supertypes
section.writeLEB(module.types.indexOf(type.getSupertype()));
} else {
section.writeLEB(0);
}
section.writeByte(0x5F); section.writeByte(0x5F);
section.writeLEB(type.getFields().size()); section.writeLEB(type.getFields().size());
for (var fieldType : type.getFields()) { for (var fieldType : type.getFields()) {
@ -75,7 +81,7 @@ public class WasmCompositeTypeBinaryRenderer implements WasmCompositeTypeVisitor
break; break;
} }
} else { } else {
section.writeType(storageType.asUnpackedType(), module, true); section.writeType(storageType.asUnpackedType(), module);
} }
} }
} }