Skip to content

Commit 1c9f8f9

Browse files
committed
Check type equivalence for mutable global imports, clean up global imports
1 parent 20b8d83 commit 1c9f8f9

File tree

4 files changed

+36
-36
lines changed

4 files changed

+36
-36
lines changed

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -327,22 +327,14 @@ private static void checkFailures(ArrayList<Throwable> failures) {
327327
}
328328
}
329329

330-
void resolveGlobalImport(WasmStore store, WasmInstance instance, ImportDescriptor importDescriptor, int globalIndex, int valueType, byte mutability,
331-
ImportValueSupplier imports) {
330+
void resolveGlobalImport(WasmStore store, WasmInstance instance, ImportDescriptor importDescriptor, int globalIndex, int valueType, byte mutability, ImportValueSupplier imports) {
332331
instance.globals().setInitialized(globalIndex, false);
333332
final String importedGlobalName = importDescriptor.memberName();
334333
final String importedModuleName = importDescriptor.moduleName();
335334
final Runnable resolveAction = () -> {
336335
assert instance.module().globalImported(globalIndex) && globalIndex == importDescriptor.targetIndex() : importDescriptor;
337336
WasmGlobal externalGlobal = lookupImportObject(instance, importDescriptor, imports, WasmGlobal.class);
338-
final int exportedValueType;
339-
final SymbolTable.ClosedValueType exportedClosedValueType;
340-
final byte exportedMutability;
341-
if (externalGlobal != null) {
342-
exportedValueType = externalGlobal.getType();
343-
exportedClosedValueType = externalGlobal.getClosedValueType();
344-
exportedMutability = externalGlobal.getMutability();
345-
} else {
337+
if (externalGlobal == null) {
346338
final WasmInstance importedInstance = store.lookupModuleInstance(importedModuleName);
347339
if (importedInstance == null) {
348340
throw WasmException.create(Failure.UNKNOWN_IMPORT, "Module '" + importedModuleName + "', referenced in the import of global variable '" +
@@ -356,21 +348,22 @@ void resolveGlobalImport(WasmStore store, WasmInstance instance, ImportDescripto
356348
"', was not exported in the module '" + importedModuleName + "'.");
357349
}
358350

359-
exportedValueType = importedInstance.symbolTable().globalValueType(exportedGlobalIndex);
360-
exportedClosedValueType = importedInstance.symbolTable().globalClosedValueType(exportedGlobalIndex);
361-
exportedMutability = importedInstance.symbolTable().globalMutability(exportedGlobalIndex);
362-
363351
externalGlobal = importedInstance.externalGlobal(exportedGlobalIndex);
364352
}
365-
if (!instance.symbolTable().closedTypeOf(valueType).isSupertypeOf(exportedClosedValueType)) {
353+
SymbolTable.ClosedValueType importType = instance.symbolTable().closedTypeOf(valueType);
354+
SymbolTable.ClosedValueType exportType = externalGlobal.getClosedType();
355+
if (mutability != externalGlobal.getMutability()) {
366356
throw WasmException.create(Failure.INCOMPATIBLE_IMPORT_TYPE, "Global variable '" + importedGlobalName + "' is imported into module '" + instance.name() +
367-
"' with the type " + WasmType.toString(valueType) + ", " +
368-
"but it was exported in the module '" + importedModuleName + "' with the type " + WasmType.toString(exportedValueType) + ".");
357+
"' with the modifier " + GlobalModifier.asString(mutability) + ", " +
358+
"but it was exported in the module '" + importedModuleName + "' with the modifier " + GlobalModifier.asString(externalGlobal.getMutability()) + ".");
369359
}
370-
if (exportedMutability != mutability) {
360+
// matching for mutable globals does not work by subtyping, but requires equivalent
361+
// types
362+
if (!(externalGlobal.isMutable() ? importType.equals(exportType) : importType.isSupertypeOf(exportType))) {
371363
throw WasmException.create(Failure.INCOMPATIBLE_IMPORT_TYPE, "Global variable '" + importedGlobalName + "' is imported into module '" + instance.name() +
372-
"' with the modifier " + GlobalModifier.asString(mutability) + ", " +
373-
"but it was exported in the module '" + importedModuleName + "' with the modifier " + GlobalModifier.asString(exportedMutability) + ".");
364+
"' with the type " + GlobalModifier.asString(mutability) + " " + WasmType.toString(valueType) + ", " +
365+
"but it was exported in the module '" + importedModuleName + "' with the type " + GlobalModifier.asString(externalGlobal.getMutability()) + " " +
366+
WasmType.toString(externalGlobal.getType()) + ".");
374367
}
375368
instance.setExternalGlobal(globalIndex, externalGlobal);
376369
instance.globals().setInitialized(globalIndex, true);
@@ -391,7 +384,7 @@ private static void initializeGlobal(WasmInstance instance, int globalIndex, Obj
391384
assert !instance.globals().isInitialized(globalIndex) : globalIndex;
392385
SymbolTable symbolTable = instance.symbolTable();
393386
if (symbolTable.globalExternal(globalIndex)) {
394-
var global = new WasmGlobal(symbolTable.globalValueType(globalIndex), symbolTable.isGlobalMutable(globalIndex), instance.symbolTable(), initValue);
387+
var global = new WasmGlobal(globalIndex, symbolTable, initValue);
395388
instance.setExternalGlobal(globalIndex, global);
396389
} else {
397390
instance.globals().store(symbolTable.globalValueType(globalIndex), symbolTable.globalAddress(globalIndex), initValue);
@@ -568,9 +561,8 @@ void resolveTagImport(WasmStore store, WasmInstance instance, ImportDescriptor i
568561
}
569562
importedTag = importedInstance.tag(exportedTagIndex);
570563
}
571-
// matching for tag types does not work by subtyping, but requires equivalent types,
572-
// A <= B and B <= A
573-
Assert.assertTrue(type.isSupertypeOf(importedTag.type()) && importedTag.type().isSupertypeOf(type), Failure.INCOMPATIBLE_IMPORT_TYPE);
564+
// matching for tag types does not work by subtyping, but requires equivalent types
565+
Assert.assertTrue(type.equals(importedTag.type()), Failure.INCOMPATIBLE_IMPORT_TYPE);
574566
instance.setTag(tagIndex, importedTag);
575567
};
576568
resolutionDag.resolveLater(new ImportTagSym(instance.name(), importDescriptor, tagIndex), new Sym[]{new ExportTagSym(importedModuleName, importedTagName)}, resolveAction);

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ public abstract class SymbolTable {
8989
public static final int NO_EQUIVALENCE_CLASS = 0;
9090
public static final int FIRST_EQUIVALENCE_CLASS = NO_EQUIVALENCE_CLASS + 1;
9191

92+
/**
93+
* Represents a WebAssembly value type in its closed form, with all type indices replaced with
94+
* their definitions. You can query the subtyping relation on types using the predicates
95+
* {@link #isSupertypeOf(ClosedValueType)} and {@link #isSubtypeOf(ClosedValueType)}, both of
96+
* which are written to be PE-friendly provided the receiver type is a PE constant.
97+
* <p>
98+
* If you need to check whether two types are equivalent, instead of checking
99+
* {@code A.isSupertypeOf(B) && A.isSubtypeOf(B)}, you can use {@code A.equals(B)}, since, in
100+
* the WebAssembly type system, type equivalence corresponds to structural equality.
101+
* </p>
102+
*/
92103
public abstract static sealed class ClosedValueType {
93104
// This is a workaround until we can use pattern matching in JDK 21+.
94105
public enum Kind {
@@ -1265,10 +1276,6 @@ public int globalValueType(int index) {
12651276
return globalTypes[index];
12661277
}
12671278

1268-
public ClosedValueType globalClosedValueType(int index) {
1269-
return closedTypeOf(globalTypes[index]);
1270-
}
1271-
12721279
private byte globalFlags(int index) {
12731280
return globalFlags[index];
12741281
}

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ public Object globalRead(WasmGlobal global) {
812812
if (!refTypes) {
813813
throw new WasmJsApiException(WasmJsApiException.Kind.TypeError, "Invalid value type. Reference types are not enabled.");
814814
}
815-
if (SymbolTable.closedTypeOf(WasmType.EXNREF_TYPE, null).isSupertypeOf(global.getClosedValueType())) {
815+
if (SymbolTable.closedTypeOf(WasmType.EXNREF_TYPE, null).isSupertypeOf(global.getClosedType())) {
816816
throw new WasmJsApiException(WasmJsApiException.Kind.TypeError, WasmJsApiException.EXNREF_VALUE_ACCESS);
817817
}
818818
yield global.loadAsReference();
@@ -832,7 +832,7 @@ public Object globalWrite(WasmGlobal global, Object value) {
832832
if (!global.isMutable()) {
833833
throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "Global is not mutable.");
834834
}
835-
if (!global.getClosedValueType().matchesValue(value)) {
835+
if (!global.getClosedType().matchesValue(value)) {
836836
throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "Global type %s, value: %s", ValueType.fromValue(global.getType()), value);
837837
}
838838
switch (global.getType()) {
@@ -846,7 +846,7 @@ public Object globalWrite(WasmGlobal global, Object value) {
846846
if (!refTypes) {
847847
throw WasmJsApiException.format(WasmJsApiException.Kind.TypeError, "Invalid value type. Reference types are not enabled.");
848848
}
849-
if (SymbolTable.closedTypeOf(WasmType.EXNREF_TYPE, null).isSupertypeOf(global.getClosedValueType())) {
849+
if (SymbolTable.closedTypeOf(WasmType.EXNREF_TYPE, null).isSupertypeOf(global.getClosedType())) {
850850
throw new WasmJsApiException(WasmJsApiException.Kind.TypeError, WasmJsApiException.EXNREF_VALUE_ACCESS);
851851
}
852852
global.storeReference(value);

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/globals/WasmGlobal.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ public static WasmGlobal allocRef(ValueType valueType, boolean mutable, Object v
9393
return result;
9494
}
9595

96-
public WasmGlobal(int type, boolean mutable, SymbolTable symbolTable, Object value) {
97-
this(type, mutable, symbolTable);
96+
public WasmGlobal(int globalIndex, SymbolTable symbolTable, Object value) {
97+
this(symbolTable.globalValueType(globalIndex), symbolTable.isGlobalMutable(globalIndex), symbolTable);
98+
assert symbolTable.globalExternal(globalIndex);
9899
this.globalValue = switch (type) {
99100
case WasmType.I32_TYPE -> (int) value;
100101
case WasmType.I64_TYPE -> (long) value;
@@ -109,7 +110,7 @@ public int getType() {
109110
return type;
110111
}
111112

112-
public SymbolTable.ClosedValueType getClosedValueType() {
113+
public SymbolTable.ClosedValueType getClosedType() {
113114
return SymbolTable.closedTypeOf(getType(), symbolTable);
114115
}
115116

@@ -225,14 +226,14 @@ void writeMember(String member, Object value,
225226
case WasmType.F32_TYPE -> storeInt(Float.floatToRawIntBits(valueLibrary.asFloat(value)));
226227
case WasmType.F64_TYPE -> storeLong(Double.doubleToRawLongBits(valueLibrary.asDouble(value)));
227228
case WasmType.V128_TYPE -> {
228-
if (!getClosedValueType().matchesValue(value)) {
229+
if (!getClosedType().matchesValue(value)) {
229230
throw UnsupportedMessageException.create();
230231
}
231232
storeVector128((Vector128) value);
232233
}
233234
default -> {
234235
assert WasmType.isReferenceType(type);
235-
if (!getClosedValueType().matchesValue(value)) {
236+
if (!getClosedType().matchesValue(value)) {
236237
throw UnsupportedMessageException.create();
237238
}
238239
storeReference(value);

0 commit comments

Comments
 (0)