wasm gc: support type nullability and global mutability

This commit is contained in:
Alexey Andreev 2024-08-31 20:16:09 +02:00
parent 9b601ac002
commit 1dc7bc653d
21 changed files with 209 additions and 128 deletions

View File

@ -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,

View File

@ -69,7 +69,9 @@ public abstract class BaseDisassemblyListener {
break;
}
} else if (type instanceof WasmHollowType.SpecialReference) {
switch (((WasmHollowType.SpecialReference) type).kind) {
var refType = (WasmHollowType.SpecialReference) type;
if (refType.isNullable()) {
switch (refType.kind) {
case ANY:
writer.write("anyref");
return;
@ -91,9 +93,38 @@ public abstract class BaseDisassemblyListener {
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;
}

View File

@ -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

View File

@ -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),

View File

@ -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);

View File

@ -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);
});

View File

@ -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());

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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) {

View File

@ -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) {

View File

@ -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:

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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);
}
}