wasm gc: fix some issues and implement intrinsics

* properly cast exception type on catch blocks
* generate virtual table structures lazily
* fix calculation of types of a.field values
This commit is contained in:
Alexey Andreev 2024-08-27 13:28:49 +02:00
parent 4823109be5
commit 10c3731c43
9 changed files with 76 additions and 26 deletions

View File

@ -299,6 +299,8 @@ public final class TMath extends TObject {
return randomC(); return randomC();
} else if (PlatformDetector.isWebAssembly()) { } else if (PlatformDetector.isWebAssembly()) {
return WasmSupport.random(); return WasmSupport.random();
} else if (PlatformDetector.isWebAssemblyGC()) {
return randomWasmGC();
} else { } else {
return randomImpl(); return randomImpl();
} }
@ -310,6 +312,9 @@ public final class TMath extends TObject {
@GeneratedBy(MathNativeGenerator.class) @GeneratedBy(MathNativeGenerator.class)
private static native double randomImpl(); private static native double randomImpl();
@Import(module = "teavmMath", name = "random")
private static native double randomWasmGC();
public static int min(int a, int b) { public static int min(int a, int b) {
return a < b ? a : b; return a < b ? a : b;
} }

View File

@ -401,6 +401,7 @@ class StatementGenerator implements InstructionVisitor {
if (insn.getInstance() != null) { if (insn.getInstance() != null) {
AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()),
Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField())); Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField()));
stmt.getRightValue().setVariableIndex(insn.getReceiver().getIndex());
stmt.setLocation(currentLocation); stmt.setLocation(currentLocation);
statements.add(stmt); statements.add(stmt);
} else { } else {

View File

@ -175,7 +175,8 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
} }
@Override @Override
protected void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local) { protected void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local,
String exceptionClass) {
var call = new WasmCall(context.functions().forStaticMethod(CATCH_METHOD)); var call = new WasmCall(context.functions().forStaticMethod(CATCH_METHOD));
if (local != null) { if (local != null) {
var save = new WasmSetLocal(local, call); var save = new WasmSetLocal(local, call);

View File

@ -1300,7 +1300,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
var catchLocal = tryCatch.getExceptionVariable() != null var catchLocal = tryCatch.getExceptionVariable() != null
? localVar(tryCatch.getExceptionVariable()) ? localVar(tryCatch.getExceptionVariable())
: null; : null;
catchException(null, catchBlock.getBody(), catchLocal); catchException(null, catchBlock.getBody(), catchLocal, tryCatch.getExceptionType());
visitMany(tryCatch.getHandler(), catchBlock.getBody()); visitMany(tryCatch.getHandler(), catchBlock.getBody());
if (!catchBlock.isTerminating() && catchBlock != outerCatchBlock) { if (!catchBlock.isTerminating() && catchBlock != outerCatchBlock) {
catchBlock.getBody().add(new WasmBreak(outerCatchBlock)); catchBlock.getBody().add(new WasmBreak(outerCatchBlock));
@ -1313,7 +1313,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
protected abstract WasmExpression peekException(); protected abstract WasmExpression peekException();
protected abstract void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local); protected abstract void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local,
String exceptionClass);
private void visitMany(List<Statement> statements, List<WasmExpression> target) { private void visitMany(List<Statement> statements, List<WasmExpression> target) {
var oldTarget = resultConsumer; var oldTarget = resultConsumer;

View File

@ -129,6 +129,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private WasmFunction arrayLengthObjectFunction; private WasmFunction arrayLengthObjectFunction;
private WasmFunctionType arrayGetType; private WasmFunctionType arrayGetType;
private WasmFunctionType arrayLengthType; private WasmFunctionType arrayLengthType;
private List<WasmStructure> nonInitializedStructures = new ArrayList<>();
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource, public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
WasmFunctionTypes functionTypes, TagRegistry tagRegistry, WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
@ -163,10 +164,22 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
var classInfo = classInfoQueue.remove(); var classInfo = classInfoQueue.remove();
classInfo.initializer.accept(initializerFunctionStatements); classInfo.initializer.accept(initializerFunctionStatements);
classInfo.initializer = null; classInfo.initializer = null;
initStructures();
} }
return true; return true;
} }
private void initStructures() {
if (nonInitializedStructures.isEmpty()) {
return;
}
var copy = List.copyOf(nonInitializedStructures);
nonInitializedStructures.clear();
for (var structure : copy) {
structure.init();
}
}
@Override @Override
public void contributeToInitializerDefinitions(WasmFunction function) { public void contributeToInitializerDefinitions(WasmFunction function) {
fillVirtualTableSupertypes(); fillVirtualTableSupertypes();
@ -269,6 +282,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
classInfo.structure = new WasmStructure(name != null ? names.forClass(name) : null, classInfo.structure = new WasmStructure(name != null ? names.forClass(name) : null,
fields -> fillFields(finalClassInfo, fields, type)); fields -> fillFields(finalClassInfo, fields, type));
module.types.add(classInfo.structure); module.types.add(classInfo.structure);
nonInitializedStructures.add(classInfo.structure);
} }
} }
if (name != null) { if (name != null) {
@ -698,12 +712,14 @@ 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), fields -> {
addSystemFields(fields);
fillSimpleClassFields(fields, "java.lang.Class");
addVirtualTableFields(fields, virtualTable);
});
nonInitializedStructures.add(structure);
structure.setSupertype(standardClasses.classClass().getStructure()); structure.setSupertype(standardClasses.classClass().getStructure());
module.types.add(structure); module.types.add(structure);
addSystemFields(structure.getFields());
fillSimpleClassFields(structure.getFields(), "java.lang.Class");
addVirtualTableFields(structure, virtualTable);
return structure; return structure;
} }
@ -716,46 +732,49 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
fields.add(monitorField); fields.add(monitorField);
} }
private void addVirtualTableFields(WasmStructure structure, WasmGCVirtualTable virtualTable) { private void addVirtualTableFields(List<WasmField> fields, WasmGCVirtualTable virtualTable) {
for (var entry : virtualTable.getEntries()) { for (var entry : virtualTable.getEntries()) {
var functionType = typeMapper.getFunctionType(entry.getOrigin().getClassName(), entry.getMethod(), false); var functionType = typeMapper.getFunctionType(entry.getOrigin().getClassName(), entry.getMethod(), false);
var field = new WasmField(functionType.getReference().asStorage()); var field = new WasmField(functionType.getReference().asStorage());
field.setName(names.forVirtualMethod(entry.getMethod())); field.setName(names.forVirtualMethod(entry.getMethod()));
structure.getFields().add(field); fields.add(field);
} }
} }
@Override @Override
public WasmStructure getArrayVirtualTableStructure() { public WasmStructure getArrayVirtualTableStructure() {
if (arrayVirtualTableStruct == null) { if (arrayVirtualTableStruct == null) {
arrayVirtualTableStruct = new WasmStructure(null); arrayVirtualTableStruct = new WasmStructure(null, fields -> {
addSystemFields(fields);
fillSimpleClassFields(fields, "java.lang.Class");
addVirtualTableFields(fields, virtualTables.lookup("java.lang.Object"));
if (metadataRequirements.hasArrayLength()) {
arrayLengthOffset = fields.size();
var arrayLengthType = getArrayLengthType();
fields.add(new WasmField(arrayLengthType.getReference().asStorage()));
}
if (metadataRequirements.hasArrayGet()) {
arrayGetOffset = fields.size();
var arrayGetType = getArrayGetType();
fields.add(new WasmField(arrayGetType.getReference().asStorage()));
}
});
arrayVirtualTableStruct.setSupertype(standardClasses.objectClass().getVirtualTableStructure()); arrayVirtualTableStruct.setSupertype(standardClasses.objectClass().getVirtualTableStructure());
module.types.add(arrayVirtualTableStruct); module.types.add(arrayVirtualTableStruct);
addSystemFields(arrayVirtualTableStruct.getFields()); nonInitializedStructures.add(arrayVirtualTableStruct);
fillSimpleClassFields(arrayVirtualTableStruct.getFields(), "java.lang.Class");
addVirtualTableFields(arrayVirtualTableStruct, virtualTables.lookup("java.lang.Object"));
if (metadataRequirements.hasArrayLength()) {
arrayLengthOffset = arrayVirtualTableStruct.getFields().size();
var arrayLengthType = getArrayLengthType();
arrayVirtualTableStruct.getFields().add(new WasmField(arrayLengthType.getReference().asStorage()));
}
if (metadataRequirements.hasArrayGet()) {
arrayGetOffset = arrayVirtualTableStruct.getFields().size();
var arrayGetType = getArrayGetType();
arrayVirtualTableStruct.getFields().add(new WasmField(arrayGetType.getReference().asStorage()));
}
} }
return arrayVirtualTableStruct; return arrayVirtualTableStruct;
} }
@Override @Override
public int getArrayLengthOffset() { public int getArrayLengthOffset() {
initStructures();
return arrayLengthOffset; return arrayLengthOffset;
} }
@Override @Override
public int getArrayGetOffset() { public int getArrayGetOffset() {
initStructures();
return arrayGetOffset; return arrayGetOffset;
} }

View File

@ -372,10 +372,16 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
} }
@Override @Override
protected void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local) { protected void catchException(TextLocation location, List<WasmExpression> target, WasmLocal local,
String exceptionClass) {
var type = context.classInfoProvider().getClassInfo("java.lang.Throwable").getType(); var type = context.classInfoProvider().getClassInfo("java.lang.Throwable").getType();
if (local != null) { if (local != null) {
var save = new WasmSetLocal(local, new WasmGetGlobal(context.exceptionGlobal())); WasmExpression exception = new WasmGetGlobal(context.exceptionGlobal());
if (exceptionClass != null && !exceptionClass.equals("java.lang.Throwable")) {
exception = new WasmCast(exception, context.classInfoProvider().getClassInfo(exceptionClass)
.getStructure().getReference());
}
var save = new WasmSetLocal(local, exception);
save.setLocation(location); save.setLocation(location);
target.add(save); target.add(save);
} }
@ -511,6 +517,9 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
var fieldType = field.getType(); var fieldType = field.getType();
if (fieldType instanceof ValueType.Primitive) { if (fieldType instanceof ValueType.Primitive) {
switch (((ValueType.Primitive) fieldType).getKind()) { switch (((ValueType.Primitive) fieldType).getKind()) {
case BOOLEAN:
structGet.setSignedType(WasmSignedType.UNSIGNED);
break;
case BYTE: case BYTE:
structGet.setSignedType(WasmSignedType.SIGNED); structGet.setSignedType(WasmSignedType.SIGNED);
break; break;

View File

@ -35,6 +35,7 @@ public class SystemArrayCopyIntrinsic implements WasmGCIntrinsic {
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) { public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var result = tryGenerateSpecialCase(invocation, context); var result = tryGenerateSpecialCase(invocation, context);
if (result == null) { if (result == null) {
tryGenerateSpecialCase(invocation, context);
var function = getDefaultFunction(context); var function = getDefaultFunction(context);
result = new WasmCall(function, context.generate(invocation.getArguments().get(0)), result = new WasmCall(function, context.generate(invocation.getArguments().get(0)),
context.generate(invocation.getArguments().get(1)), context.generate(invocation.getArguments().get(1)),

View File

@ -16,7 +16,10 @@
package org.teavm.backend.wasm.transformation.gc; package org.teavm.backend.wasm.transformation.gc;
import org.teavm.backend.wasm.runtime.WasmGCSupport; import org.teavm.backend.wasm.runtime.WasmGCSupport;
import org.teavm.interop.Import;
import org.teavm.model.AccessLevel; import org.teavm.model.AccessLevel;
import org.teavm.model.AnnotationHolder;
import org.teavm.model.AnnotationValue;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassHolderTransformerContext; import org.teavm.model.ClassHolderTransformerContext;
@ -86,6 +89,12 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
method.setProgram(null); method.setProgram(null);
method.getModifiers().add(ElementModifier.NATIVE); method.getModifiers().add(ElementModifier.NATIVE);
break; break;
case "currentTimeMillis": {
var annotation = new AnnotationHolder(Import.class.getName());
annotation.getValues().put("module", new AnnotationValue("teavm"));
annotation.getValues().put("name", new AnnotationValue("currentTimeMillis"));
method.getAnnotations().add(annotation);
}
} }
} }
} }

View File

@ -35,8 +35,12 @@ TeaVM.wasm = function() {
} else { } else {
stdout += String.fromCharCode(c); stdout += String.fromCharCode(c);
} }
},
currentTimeMillis() {
return new Date().getTime();
} }
}; };
imports.teavmMath = Math;
} }
function load(path, options) { function load(path, options) {