From 1dc7bc653dcc9d79ab00462f0a292930b29372c2 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sat, 31 Aug 2024 20:16:09 +0200 Subject: [PATCH] wasm gc: support type nullability and global mutability --- .../backend/wasm/WasmGCModuleGenerator.java | 2 +- .../wasm/disasm/BaseDisassemblyListener.java | 77 +++++++++++++------ .../wasm/disasm/DisassemblyCodeListener.java | 16 ++-- .../DisassemblyGlobalSectionListener.java | 2 +- .../gc/classes/WasmGCClassGenerator.java | 24 +++--- .../gc/methods/WasmGCGenerationVisitor.java | 6 +- .../generate/gc/strings/WasmGCStringPool.java | 3 +- .../wasm/intrinsics/gc/ArrayIntrinsic.java | 2 +- .../wasm/intrinsics/gc/ObjectIntrinsic.java | 15 ++-- .../backend/wasm/model/WasmCompositeType.java | 10 ++- .../teavm/backend/wasm/model/WasmGlobal.java | 9 +++ .../teavm/backend/wasm/model/WasmType.java | 28 ++++++- .../wasm/model/expression/WasmCast.java | 14 ---- .../wasm/model/expression/WasmTest.java | 13 ---- .../backend/wasm/parser/CodeListener.java | 4 +- .../teavm/backend/wasm/parser/CodeParser.java | 10 +-- .../backend/wasm/parser/WasmBinaryReader.java | 33 +++++--- .../backend/wasm/parser/WasmHollowType.java | 51 ++++++++---- .../wasm/render/WasmBinaryRenderer.java | 2 +- .../render/WasmBinaryRenderingVisitor.java | 4 +- .../backend/wasm/render/WasmBinaryWriter.java | 12 ++- 21 files changed, 209 insertions(+), 128 deletions(-) diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmGCModuleGenerator.java b/core/src/main/java/org/teavm/backend/wasm/WasmGCModuleGenerator.java index ab42e2d98..a012ec99b 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmGCModuleGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmGCModuleGenerator.java @@ -180,7 +180,7 @@ public class WasmGCModuleGenerator { initializer = new WasmFunction(functionType); initializer.setReferenced(true); declarationsGenerator.module.functions.add(initializer); - initializerRef = new WasmGlobal("teavm@initializer", functionType.getReference(), + initializerRef = new WasmGlobal("teavm@initializer", functionType.getNonNullReference(), new WasmFunctionReference(initializer)); declarationsGenerator.module.globals.add(initializerRef); initializer.getBody().add(new WasmSetGlobal(initializerRef, diff --git a/core/src/main/java/org/teavm/backend/wasm/disasm/BaseDisassemblyListener.java b/core/src/main/java/org/teavm/backend/wasm/disasm/BaseDisassemblyListener.java index 72cb0dcc0..74514d49e 100644 --- a/core/src/main/java/org/teavm/backend/wasm/disasm/BaseDisassemblyListener.java +++ b/core/src/main/java/org/teavm/backend/wasm/disasm/BaseDisassemblyListener.java @@ -69,31 +69,62 @@ public abstract class BaseDisassemblyListener { break; } } else if (type instanceof WasmHollowType.SpecialReference) { - switch (((WasmHollowType.SpecialReference) type).kind) { - case ANY: - writer.write("anyref"); - return; - case FUNC: - writer.write("funcref"); - return; - case ARRAY: - writer.write("arrayref"); - return; - case EXTERN: - writer.write("externref"); - return; - case STRUCT: - writer.write("structref"); - return; - case I31: - writer.write("i31ref"); - return; - default: - throw new IllegalArgumentException(); + var refType = (WasmHollowType.SpecialReference) type; + if (refType.isNullable()) { + switch (refType.kind) { + case ANY: + writer.write("anyref"); + return; + case FUNC: + writer.write("funcref"); + return; + case ARRAY: + writer.write("arrayref"); + return; + case EXTERN: + writer.write("externref"); + return; + case STRUCT: + writer.write("structref"); + return; + case I31: + writer.write("i31ref"); + return; + default: + throw new IllegalArgumentException(); + } + } else { + writer.write("(ref "); + switch (refType.kind) { + case ANY: + writer.write("any"); + return; + case FUNC: + writer.write("func"); + return; + case ARRAY: + writer.write("array"); + return; + case EXTERN: + writer.write("extern"); + return; + case STRUCT: + writer.write("struct"); + return; + case I31: + writer.write("i31"); + return; + default: + throw new IllegalArgumentException(); + } } } else if (type instanceof WasmHollowType.CompositeReference) { - writer.write("(ref null "); - writeTypeRef(((WasmHollowType.CompositeReference) type).index); + var refType = (WasmHollowType.CompositeReference) type; + writer.write("(ref "); + if (refType.isNullable()) { + writer.write("null"); + } + writeTypeRef(refType.index); writer.write(")"); return; } diff --git a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyCodeListener.java b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyCodeListener.java index 61dbfaa0c..fc3db8228 100644 --- a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyCodeListener.java +++ b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyCodeListener.java @@ -755,23 +755,17 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements } @Override - public void cast(WasmHollowType.Reference type, boolean nullable) { + public void cast(WasmHollowType.Reference type) { writer.address().write("ref.cast (ref "); - if (!nullable) { - writer.write("null "); - } writeType(type); - writer.write(")").eol(); + writer.eol(); } @Override - public void test(WasmHollowType.Reference type, boolean nullable) { - writer.address().write("ref.test (ref "); - if (!nullable) { - writer.write("null "); - } + public void test(WasmHollowType.Reference type) { + writer.address().write("ref.test "); writeType(type); - writer.write(")").eol(); + writer.eol(); } @Override diff --git a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyGlobalSectionListener.java b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyGlobalSectionListener.java index ddeab3e7c..774652126 100644 --- a/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyGlobalSectionListener.java +++ b/core/src/main/java/org/teavm/backend/wasm/disasm/DisassemblyGlobalSectionListener.java @@ -33,7 +33,7 @@ public class DisassemblyGlobalSectionListener extends BaseDisassemblyListener im writer.startLinkTarget("g" + index).write("(; ").write(String.valueOf(index)).write(" ;)"); var name = nameProvider.global(index); if (name != null) { - writer.write("$").write(name); + writer.write(" $").write(name); } writer.endLinkTarget().write(" "); if (mutable) { diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java index 491f5a6e4..adcd15c17 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/classes/WasmGCClassGenerator.java @@ -281,8 +281,9 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit } var classStructure = classInfo.virtualTableStructure; - classInfo.pointer = new WasmGlobal(pointerName, classStructure.getReference(), + classInfo.pointer = new WasmGlobal(pointerName, classStructure.getNonNullReference(), new WasmStructNewDefault(classStructure)); + classInfo.pointer.setImmutable(true); module.globals.add(classInfo.pointer); if (type instanceof ValueType.Primitive) { initPrimitiveClass(classInfo, (ValueType.Primitive) type); @@ -390,10 +391,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit if (cls != null && cls.getMethod(CLINIT_METHOD_DESC) != null) { var clinitType = functionTypes.of(null); var wasmName = names.topLevel(names.suggestForClass(name) + "@initializer"); - var initFunction = functionProvider.forStaticMethod(new MethodReference(name, CLINIT_METHOD_DESC)); - initFunction.setReferenced(true); - var ref = new WasmFunctionReference(initFunction); - classInfo.initializerPointer = new WasmGlobal(wasmName, clinitType.getReference(), ref); + classInfo.initializerPointer = new WasmGlobal(wasmName, clinitType.getReference(), + new WasmNullConstant(clinitType.getReference())); module.globals.add(classInfo.initializerPointer); } } @@ -420,6 +419,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit if (virtualTable != null && virtualTable.isConcrete()) { fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable); } + if (classInfo.initializerPointer != null) { + var initFunction = functionProvider.forStaticMethod(new MethodReference(name, CLINIT_METHOD_DESC)); + initFunction.setReferenced(true); + classInfo.initializerPointer.setInitialValue(new WasmFunctionReference(initFunction)); + } }; } @@ -490,7 +494,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit var objectLocal = new WasmLocal(standardClasses.objectClass().getType(), "object"); function.add(objectLocal); - var castObject = new WasmCast(new WasmGetLocal(objectLocal), objectStructure.getReference()); + var castObject = new WasmCast(new WasmGetLocal(objectLocal), objectStructure.getNonNullReference()); var arrayField = new WasmStructGet(objectStructure, castObject, ARRAY_DATA_FIELD_OFFSET); var result = new WasmArrayLength(arrayField); function.getBody().add(new WasmReturn(result)); @@ -521,7 +525,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit arrayGetObjectFunction.add(objectLocal); arrayGetObjectFunction.add(indexLocal); - var array = new WasmCast(new WasmGetLocal(objectLocal), arrayStruct.getReference()); + var array = new WasmCast(new WasmGetLocal(objectLocal), arrayStruct.getNonNullReference()); var arrayData = new WasmStructGet(arrayStruct, array, ARRAY_DATA_FIELD_OFFSET); var result = new WasmArrayGet(arrayDataType, arrayData, new WasmGetLocal(indexLocal)); arrayGetObjectFunction.getBody().add(new WasmReturn(result)); @@ -545,7 +549,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit function.add(objectLocal); function.add(indexLocal); - var array = new WasmCast(new WasmGetLocal(objectLocal), arrayStruct.getReference()); + var array = new WasmCast(new WasmGetLocal(objectLocal), arrayStruct.getNonNullReference()); var arrayData = new WasmStructGet(arrayStruct, array, ARRAY_DATA_FIELD_OFFSET); var result = new WasmArrayGet(arrayDataType, arrayData, new WasmGetLocal(indexLocal)); Class primitiveType; @@ -626,7 +630,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit var call = new WasmCall(function); var instanceParam = new WasmLocal(getClassInfo(virtualTable.getClassName()).getType()); wrapperFunction.add(instanceParam); - var castTarget = getClassInfo(implementor.getClassName()).getType(); + var castTarget = getClassInfo(implementor.getClassName()).getStructure().getNonNullReference(); call.getArguments().add(new WasmCast(new WasmGetLocal(instanceParam), castTarget)); var params = new WasmLocal[entry.getMethod().parameterCount()]; for (var i = 0; i < entry.getMethod().parameterCount(); ++i) { @@ -664,7 +668,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit function.add(dataCopyLocal); function.getBody().add(new WasmSetLocal(originalLocal, - new WasmCast(new WasmGetLocal(instanceLocal), objectStructure.getReference()))); + new WasmCast(new WasmGetLocal(instanceLocal), objectStructure.getNonNullReference()))); function.getBody().add(new WasmSetLocal(resultLocal, new WasmStructNewDefault(objectStructure))); var classValue = new WasmStructGet(objectStructure, new WasmGetLocal(originalLocal), diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java index 02f86a3ce..7ca417716 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/methods/WasmGCGenerationVisitor.java @@ -279,7 +279,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { var index = context.classInfoProvider().getVirtualMethodsOffset() + entry.getIndex(); var expectedInstanceClassInfo = context.classInfoProvider().getClassInfo(vtable.getClassName()); var vtableStruct = expectedInstanceClassInfo.getVirtualTableStructure(); - classRef = new WasmCast(classRef, vtableStruct.getReference()); + classRef = new WasmCast(classRef, vtableStruct.getNonNullReference()); var functionRef = new WasmStructGet(vtableStruct, classRef, index); var functionTypeRef = (WasmType.CompositeReference) vtableStruct.getFields().get(index).getUnpackedType(); @@ -288,7 +288,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { var instanceType = (WasmType.CompositeReference) instance.getType(); var instanceStruct = (WasmStructure) instanceType.composite; if (!expectedInstanceClassInfo.getStructure().isSupertypeOf(instanceStruct)) { - instanceRef = new WasmCast(instanceRef, expectedInstanceClassInfo.getType()); + instanceRef = new WasmCast(instanceRef, expectedInstanceClassInfo.getStructure().getNonNullReference()); } invoke.getArguments().add(instanceRef); @@ -381,7 +381,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor { WasmExpression exception = new WasmGetGlobal(context.exceptionGlobal()); if (exceptionClass != null && !exceptionClass.equals("java.lang.Throwable")) { exception = new WasmCast(exception, context.classInfoProvider().getClassInfo(exceptionClass) - .getStructure().getReference()); + .getStructure().getNonNullReference()); } var save = new WasmSetLocal(local, exception); save.setLocation(location); diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/gc/strings/WasmGCStringPool.java b/core/src/main/java/org/teavm/backend/wasm/generate/gc/strings/WasmGCStringPool.java index 2687fe02f..16fd0bf2c 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/gc/strings/WasmGCStringPool.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/gc/strings/WasmGCStringPool.java @@ -86,9 +86,10 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer var brief = string.length() > 16 ? string.substring(0, 16) : string; var globalName = names.topLevel("teavm@string<" + stringMap.size() + ">" + WasmGCNameProvider.sanitize(brief)); - var globalType = standardClasses.stringClass().getType(); + var globalType = standardClasses.stringClass().getStructure().getNonNullReference(); var global = new WasmGlobal(globalName, globalType, new WasmStructNewDefault(standardClasses.stringClass().getStructure())); + global.setImmutable(true); module.globals.add(global); return new WasmGCStringConstant(stringMap.size(), global); }); diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ArrayIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ArrayIntrinsic.java index 12f54b429..23e73333d 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ArrayIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ArrayIntrinsic.java @@ -59,7 +59,7 @@ public class ArrayIntrinsic implements WasmGCIntrinsic { var object = context.exprCache().create(originalObject, objectStruct.getReference(), invocation.getLocation(), block.getBody()); var classRef = new WasmStructGet(objectStruct, object.expr(), WasmGCClassInfoProvider.CLASS_FIELD_OFFSET); - var vt = new WasmCast(classRef, vtStruct.getReference()); + var vt = new WasmCast(classRef, vtStruct.getNonNullReference()); var function = new WasmStructGet(vtStruct, vt, offset); var call = new WasmCallReference(function, functionType); call.getArguments().add(object.expr()); diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ObjectIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ObjectIntrinsic.java index 5d84f692e..ee6c8ff48 100644 --- a/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ObjectIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/gc/ObjectIntrinsic.java @@ -66,8 +66,10 @@ public class ObjectIntrinsic implements WasmGCIntrinsic { } private WasmExpression generateGetMonitor(InvocationExpr invocation, WasmGCIntrinsicContext context) { - var monitorType = context.classInfoProvider().getClassInfo(ValueType.object("java.lang.Object$Monitor")) - .getStructure().getReference(); + var monitorStruct = context.classInfoProvider().getClassInfo(ValueType.object("java.lang.Object$Monitor")) + .getStructure(); + var monitorType = monitorStruct.getReference(); + var monitorNotNullType = monitorStruct.getNonNullReference(); var objectStruct = context.classInfoProvider().getClassInfo(ValueType.object("java.lang.Object")) .getStructure(); var block = new WasmBlock(false); @@ -77,13 +79,13 @@ public class ObjectIntrinsic implements WasmGCIntrinsic { block.getBody().add(new WasmSetLocal(tmpVar, new WasmStructGet(objectStruct, instance, WasmGCClassInfoProvider.MONITOR_FIELD_OFFSET))); - WasmExpression test = new WasmTest(new WasmGetLocal(tmpVar), monitorType, false); + WasmExpression test = new WasmTest(new WasmGetLocal(tmpVar), monitorNotNullType); test = new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, test); var branch = new WasmBranch(test, block); branch.setResult(new WasmNullConstant(monitorType)); block.getBody().add(new WasmDrop(branch)); - block.getBody().add(new WasmCast(new WasmGetLocal(tmpVar), monitorType)); + block.getBody().add(new WasmCast(new WasmGetLocal(tmpVar), monitorNotNullType)); context.tempVars().release(tmpVar); return block; } @@ -106,13 +108,14 @@ public class ObjectIntrinsic implements WasmGCIntrinsic { block.getBody().add(new WasmSetLocal(tmpVar, new WasmStructGet(objectStruct, instance, WasmGCClassInfoProvider.MONITOR_FIELD_OFFSET))); - WasmExpression test = new WasmTest(new WasmGetLocal(tmpVar), WasmType.Reference.I31, false); + WasmExpression test = new WasmTest(new WasmGetLocal(tmpVar), + WasmType.SpecialReferenceKind.I31.asNonNullType()); test = new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, test); var branch = new WasmBranch(test, block); branch.setResult(new WasmInt32Constant(-1)); block.getBody().add(new WasmDrop(branch)); - var i31ref = new WasmCast(new WasmGetLocal(tmpVar), WasmType.Reference.I31); + var i31ref = new WasmCast(new WasmGetLocal(tmpVar), WasmType.SpecialReferenceKind.I31.asNonNullType()); block.getBody().add(new WasmInt31Get(i31ref, WasmSignedType.UNSIGNED)); context.tempVars().release(tmpVar); return block; diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmCompositeType.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmCompositeType.java index c2a369fa6..6721ebbbd 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmCompositeType.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmCompositeType.java @@ -18,6 +18,7 @@ package org.teavm.backend.wasm.model; public abstract class WasmCompositeType extends WasmEntity { private String name; private WasmType.CompositeReference reference; + private WasmType.CompositeReference nonNullReference; int recursiveTypeCount = -1; WasmCompositeType(String name) { @@ -30,11 +31,18 @@ public abstract class WasmCompositeType extends WasmEntity { public WasmType.CompositeReference getReference() { if (reference == null) { - reference = new WasmType.CompositeReference(this); + reference = new WasmType.CompositeReference(this, true); } return reference; } + public WasmType.CompositeReference getNonNullReference() { + if (nonNullReference == null) { + nonNullReference = new WasmType.CompositeReference(this, false); + } + return nonNullReference; + } + public int getRecursiveTypeCount() { return recursiveTypeCount; } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmGlobal.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmGlobal.java index 5b89d0983..3d71cad75 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmGlobal.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmGlobal.java @@ -22,6 +22,7 @@ public class WasmGlobal extends WasmEntity { private String name; private WasmType type; private WasmExpression initialValue; + private boolean immutable; public WasmGlobal(String name, WasmType type, WasmExpression initialValue) { this.name = name; @@ -48,4 +49,12 @@ public class WasmGlobal extends WasmEntity { public void setInitialValue(WasmExpression initialValue) { this.initialValue = Objects.requireNonNull(initialValue); } + + public boolean isImmutable() { + return immutable; + } + + public void setImmutable(boolean immutable) { + this.immutable = immutable; + } } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/WasmType.java b/core/src/main/java/org/teavm/backend/wasm/model/WasmType.java index 47f462e01..825ba384a 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/WasmType.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/WasmType.java @@ -63,12 +63,23 @@ public abstract class WasmType { public static final SpecialReference STRUCT = SpecialReferenceKind.STRUCT.asType(); public static final SpecialReference ARRAY = SpecialReferenceKind.ARRAY.asType(); public static final SpecialReference I31 = SpecialReferenceKind.I31.asType(); + + private final boolean nullable; + + public Reference(boolean nullable) { + this.nullable = nullable; + } + + public boolean isNullable() { + return nullable; + } } public static final class CompositeReference extends Reference { public final WasmCompositeType composite; - CompositeReference(WasmCompositeType composite) { + CompositeReference(WasmCompositeType composite, boolean nullable) { + super(nullable); this.composite = composite; } } @@ -76,7 +87,8 @@ public abstract class WasmType { public static final class SpecialReference extends Reference { public final SpecialReferenceKind kind; - private SpecialReference(SpecialReferenceKind kind) { + private SpecialReference(SpecialReferenceKind kind, boolean nullable) { + super(nullable); this.kind = kind; } } @@ -90,12 +102,20 @@ public abstract class WasmType { I31; private SpecialReference type; + private SpecialReference nonNullType; - final SpecialReference asType() { + public final SpecialReference asType() { if (type == null) { - type = new SpecialReference(this); + type = new SpecialReference(this, true); } return type; } + + public final SpecialReference asNonNullType() { + if (nonNullType == null) { + nonNullType = new SpecialReference(this, false); + } + return nonNullType; + } } } diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmCast.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmCast.java index 1ee6fd943..cdc8cc684 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmCast.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmCast.java @@ -21,16 +21,10 @@ import org.teavm.backend.wasm.model.WasmType; public class WasmCast extends WasmExpression { private WasmExpression value; private WasmType.Reference targetType; - private boolean nullable; public WasmCast(WasmExpression value, WasmType.Reference targetType) { - this(value, targetType, true); - } - - public WasmCast(WasmExpression value, WasmType.Reference targetType, boolean nullable) { this.value = Objects.requireNonNull(value); this.targetType = Objects.requireNonNull(targetType); - this.nullable = nullable; } public WasmExpression getValue() { @@ -49,14 +43,6 @@ public class WasmCast extends WasmExpression { this.targetType = Objects.requireNonNull(targetType); } - public boolean isNullable() { - return nullable; - } - - public void setNullable(boolean nullable) { - this.nullable = nullable; - } - @Override public void acceptVisitor(WasmExpressionVisitor visitor) { visitor.visit(this); diff --git a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmTest.java b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmTest.java index 14e1ac055..662561352 100644 --- a/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmTest.java +++ b/core/src/main/java/org/teavm/backend/wasm/model/expression/WasmTest.java @@ -21,16 +21,10 @@ import org.teavm.backend.wasm.model.WasmType; public class WasmTest extends WasmExpression { private WasmExpression value; private WasmType.Reference testType; - private boolean nullable; public WasmTest(WasmExpression value, WasmType.Reference testType) { - this(value, testType, true); - } - - public WasmTest(WasmExpression value, WasmType.Reference testType, boolean nullable) { this.value = Objects.requireNonNull(value); this.testType = Objects.requireNonNull(testType); - this.nullable = nullable; } public WasmExpression getValue() { @@ -49,13 +43,6 @@ public class WasmTest extends WasmExpression { this.testType = Objects.requireNonNull(testType); } - public boolean isNullable() { - return nullable; - } - - public void setNullable(boolean nullable) { - this.nullable = nullable; - } @Override public void acceptVisitor(WasmExpressionVisitor visitor) { diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/CodeListener.java b/core/src/main/java/org/teavm/backend/wasm/parser/CodeListener.java index 4e052da85..f1f065feb 100644 --- a/core/src/main/java/org/teavm/backend/wasm/parser/CodeListener.java +++ b/core/src/main/java/org/teavm/backend/wasm/parser/CodeListener.java @@ -135,10 +135,10 @@ public interface CodeListener { default void nullConstant(WasmHollowType.Reference type) { } - default void cast(WasmHollowType.Reference type, boolean nullable) { + default void cast(WasmHollowType.Reference type) { } - default void test(WasmHollowType.Reference type, boolean nullable) { + default void test(WasmHollowType.Reference type) { } default void structNew(int typeIndex) { diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/CodeParser.java b/core/src/main/java/org/teavm/backend/wasm/parser/CodeParser.java index 58378a4f1..59c496c80 100644 --- a/core/src/main/java/org/teavm/backend/wasm/parser/CodeParser.java +++ b/core/src/main/java/org/teavm/backend/wasm/parser/CodeParser.java @@ -589,7 +589,7 @@ public class CodeParser extends BaseSectionParser { break; case 0xD0: - codeListener.nullConstant(reader.readHeapType()); + codeListener.nullConstant(reader.readHeapType(true)); break; case 0xD2: @@ -684,19 +684,19 @@ public class CodeParser extends BaseSectionParser { return true; case 20: - codeListener.test(reader.readHeapType(), false); + codeListener.test(reader.readHeapType(false)); return true; case 21: - codeListener.test(reader.readHeapType(), true); + codeListener.test(reader.readHeapType(true)); return true; case 22: - codeListener.cast(reader.readHeapType(), false); + codeListener.cast(reader.readHeapType(false)); return true; case 23: - codeListener.cast(reader.readHeapType(), true); + codeListener.cast(reader.readHeapType(true)); return true; case 28: diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/WasmBinaryReader.java b/core/src/main/java/org/teavm/backend/wasm/parser/WasmBinaryReader.java index 4a1e2cdde..e2a2b1ea0 100644 --- a/core/src/main/java/org/teavm/backend/wasm/parser/WasmBinaryReader.java +++ b/core/src/main/java/org/teavm/backend/wasm/parser/WasmBinaryReader.java @@ -16,6 +16,7 @@ package org.teavm.backend.wasm.parser; import java.nio.charset.StandardCharsets; +import org.teavm.backend.wasm.model.WasmType; public class WasmBinaryReader { private final AddressListener addressListener; @@ -63,43 +64,51 @@ public class WasmBinaryReader { case 0x7C: return WasmHollowType.FLOAT64; case 0x63: - return readHeapType(); + return readHeapType(true); + case 0x64: + return readHeapType(false); case 0x40: return null; default: - return readAbsHeapType(typeId); + return readAbsHeapType(typeId, true); } } - public WasmHollowType.Reference readHeapType() { + public WasmHollowType.Reference readHeapType(boolean nullable) { var typeId = data[ptr]; if ((typeId & 0xC0) == 0x40) { - var result = readAbsHeapType(typeId); + var result = readAbsHeapType(typeId, nullable); ++ptr; return result; } - return new WasmHollowType.CompositeReference(readLEB()); + return new WasmHollowType.CompositeReference(readLEB(), nullable); } - public WasmHollowType.SpecialReference readAbsHeapType(int typeId) { + public WasmHollowType.SpecialReference readAbsHeapType(int typeId, boolean nullable) { switch (typeId) { case 0x70: - return WasmHollowType.Reference.FUNC; + return special(WasmType.SpecialReferenceKind.FUNC, nullable); case 0x6F: - return WasmHollowType.Reference.EXTERN; + return special(WasmType.SpecialReferenceKind.EXTERN, nullable); case 0x6E: - return WasmHollowType.Reference.ANY; + return special(WasmType.SpecialReferenceKind.ANY, nullable); case 0x6C: - return WasmHollowType.Reference.I31; + return special(WasmType.SpecialReferenceKind.I31, nullable); case 0x6B: - return WasmHollowType.Reference.STRUCT; + return special(WasmType.SpecialReferenceKind.STRUCT, nullable); case 0x6A: - return WasmHollowType.Reference.ARRAY; + return special(WasmType.SpecialReferenceKind.ARRAY, nullable); default: throw new ParseException("Unknown type", ptr); } } + private static WasmHollowType.SpecialReference special(WasmType.SpecialReferenceKind kind, boolean nullable) { + return nullable + ? WasmHollowType.Reference.special(kind) + : WasmHollowType.SpecialReference.nonNullSpecial(kind); + } + public int readSignedLEB() { var result = 0; var shift = 0; diff --git a/core/src/main/java/org/teavm/backend/wasm/parser/WasmHollowType.java b/core/src/main/java/org/teavm/backend/wasm/parser/WasmHollowType.java index ea4df92b6..4f27a8a1f 100644 --- a/core/src/main/java/org/teavm/backend/wasm/parser/WasmHollowType.java +++ b/core/src/main/java/org/teavm/backend/wasm/parser/WasmHollowType.java @@ -17,7 +17,6 @@ package org.teavm.backend.wasm.parser; import java.util.Objects; import org.teavm.backend.wasm.model.WasmNumType; -import org.teavm.backend.wasm.model.WasmStorageType; import org.teavm.backend.wasm.model.WasmType; public class WasmHollowType { @@ -26,8 +25,6 @@ public class WasmHollowType { public static final Number FLOAT32 = new Number(WasmNumType.FLOAT32); public static final Number FLOAT64 = new Number(WasmNumType.FLOAT64); - private WasmStorageType.Regular storageType; - private WasmHollowType() { } @@ -56,18 +53,45 @@ public class WasmHollowType { public static abstract class Reference extends WasmHollowType { - public static final SpecialReference FUNC = new SpecialReference(WasmType.SpecialReferenceKind.FUNC); - public static final SpecialReference ANY = new SpecialReference(WasmType.SpecialReferenceKind.ANY); - public static final SpecialReference EXTERN = new SpecialReference(WasmType.SpecialReferenceKind.EXTERN); - public static final SpecialReference STRUCT = new SpecialReference(WasmType.SpecialReferenceKind.STRUCT); - public static final SpecialReference ARRAY = new SpecialReference(WasmType.SpecialReferenceKind.ARRAY); - public static final SpecialReference I31 = new SpecialReference(WasmType.SpecialReferenceKind.I31); + private static final SpecialReference[] references = new SpecialReference[ + WasmType.SpecialReferenceKind.values().length]; + private static final SpecialReference[] nonNullReferences = new SpecialReference[ + WasmType.SpecialReferenceKind.values().length]; + + private final boolean nullable; + + public Reference(boolean nullable) { + this.nullable = nullable; + } + + public boolean isNullable() { + return nullable; + } + + public static SpecialReference special(WasmType.SpecialReferenceKind kind) { + var result = references[kind.ordinal()]; + if (result == null) { + result = new SpecialReference(kind, true); + references[kind.ordinal()] = result; + } + return result; + } + + public static SpecialReference nonNullSpecial(WasmType.SpecialReferenceKind kind) { + var result = nonNullReferences[kind.ordinal()]; + if (result == null) { + result = new SpecialReference(kind, false); + nonNullReferences[kind.ordinal()] = result; + } + return result; + } } public static final class CompositeReference extends WasmHollowType.Reference { public final int index; - public CompositeReference(int index) { + public CompositeReference(int index, boolean nullable) { + super(nullable); this.index = index; } @@ -80,19 +104,20 @@ public class WasmHollowType { return false; } CompositeReference that = (CompositeReference) o; - return index == that.index; + return index == that.index && isNullable() == that.isNullable(); } @Override public int hashCode() { - return Objects.hashCode(index); + return Objects.hash(index, isNullable()); } } public static final class SpecialReference extends WasmHollowType.Reference { public final WasmType.SpecialReferenceKind kind; - SpecialReference(WasmType.SpecialReferenceKind kind) { + SpecialReference(WasmType.SpecialReferenceKind kind, boolean nullable) { + super(nullable); this.kind = kind; } } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java index ee2ba2a5b..9104c6df8 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderer.java @@ -219,7 +219,7 @@ public class WasmBinaryRenderer { section.writeLEB(module.globals.size()); for (var global : module.globals) { section.writeType(global.getType(), module); - section.writeByte(1); // mutable + section.writeByte(global.isImmutable() ? 0 : 1); // mutable global.getInitialValue().acceptVisitor(visitor); section.writeByte(0x0b); } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java index 4f2fdd221..bc907bcfe 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryRenderingVisitor.java @@ -1075,7 +1075,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { pushLocation(expression); expression.getValue().acceptVisitor(this); writer.writeByte(0xfb); - writer.writeByte(expression.isNullable() ? 23 : 22); + writer.writeByte(expression.getTargetType().isNullable() ? 23 : 22); writer.writeHeapType(expression.getTargetType(), module); popLocation(); } @@ -1085,7 +1085,7 @@ class WasmBinaryRenderingVisitor implements WasmExpressionVisitor { pushLocation(expression); expression.getValue().acceptVisitor(this); writer.writeByte(0xfb); - writer.writeByte(expression.isNullable() ? 21 : 20); + writer.writeByte(expression.getTestType().isNullable() ? 21 : 20); writer.writeHeapType(expression.getTestType(), module); popLocation(); } diff --git a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryWriter.java b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryWriter.java index 852b9e5a9..a0ac6b624 100644 --- a/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryWriter.java +++ b/core/src/main/java/org/teavm/backend/wasm/render/WasmBinaryWriter.java @@ -37,11 +37,15 @@ public class WasmBinaryWriter { if (type instanceof WasmType.Number) { writeType(((WasmType.Number) type).number); } else if (type instanceof WasmType.SpecialReference) { - writeSpecialHeapType(((WasmType.SpecialReference) type).kind); + var refType = (WasmType.SpecialReference) type; + if (!refType.isNullable()) { + writeByte(0x64); + } + writeSpecialHeapType(refType.kind); } else if (type instanceof WasmType.CompositeReference) { - writeByte(0x63); - var composite = ((WasmType.CompositeReference) type).composite; - var index = module.types.indexOf(composite); + var refType = (WasmType.CompositeReference) type; + writeByte(refType.isNullable() ? 0x63 : 0x64); + var index = module.types.indexOf(refType.composite); writeSignedLEB(index); } }