Skip to content

Commit 3d4eb2a

Browse files
committed
[GR-48908] Implement the Typed Function References proposal in GraalWasm.
PullRequest: graal/22210
2 parents dcf89ad + a1962e6 commit 3d4eb2a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+3155
-2141
lines changed

wasm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This changelog summarizes major changes to the WebAssembly engine implemented in
55
## Version 25.1.0
66

77
* Implemented the [exception handling](https://github.com/WebAssembly/exception-handling) proposal. This feature can be enabled with the experimental option `wasm.Exceptions=true`.
8+
* Implemented the [typed function references](https://github.com/WebAssembly/function-references) proposal. This feature can be enabled with the experimental option `wasm.TypedFunctionReferences=true`.
89

910
## Version 25.0.0
1011

wasm/src/org.graalvm.wasm.benchmark/src/org/graalvm/wasm/benchmark/MemoryFootprintBenchmarkRunner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ static double getHeapSize() {
169169

170170
static void sleep() {
171171
try {
172-
Thread.sleep(2000);
172+
Thread.sleep(5000);
173173
} catch (InterruptedException e) {
174174
Thread.currentThread().interrupt();
175175
}

wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/AbstractBinarySuite.java

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@
5353
import org.graalvm.polyglot.io.ByteSequence;
5454
import org.graalvm.wasm.WasmLanguage;
5555
import org.graalvm.wasm.collection.ByteArrayList;
56+
import org.graalvm.wasm.collection.IntArrayList;
5657

5758
public abstract class AbstractBinarySuite {
58-
protected static final byte[] EMPTY_BYTES = {};
59+
protected static final int[] EMPTY_INTS = {};
5960

6061
protected static void runRuntimeTest(byte[] binary, Consumer<Context.Builder> options, Consumer<Value> testCase) throws IOException {
6162
final Context.Builder contextBuilder = Context.newBuilder(WasmLanguage.ID);
@@ -100,10 +101,10 @@ private static byte getByte(String hexString) {
100101

101102
private static final class BinaryTypes {
102103

103-
private final List<byte[]> paramEntries = new ArrayList<>();
104-
private final List<byte[]> resultEntries = new ArrayList<>();
104+
private final List<int[]> paramEntries = new ArrayList<>();
105+
private final List<int[]> resultEntries = new ArrayList<>();
105106

106-
private void add(byte[] params, byte[] results) {
107+
private void add(int[] params, int[] results) {
107108
paramEntries.add(params);
108109
resultEntries.add(results);
109110
}
@@ -112,18 +113,18 @@ private byte[] generateTypeSection() {
112113
ByteArrayList b = new ByteArrayList();
113114
b.add(getByte("01"));
114115
b.add((byte) 0); // length is patched in the end
115-
b.add((byte) paramEntries.size());
116+
b.addUnsignedInt32(paramEntries.size());
116117
for (int i = 0; i < paramEntries.size(); i++) {
117118
b.add(getByte("60"));
118-
byte[] params = paramEntries.get(i);
119-
byte[] results = resultEntries.get(i);
120-
b.add((byte) params.length);
121-
for (byte param : params) {
122-
b.add(param);
119+
int[] params = paramEntries.get(i);
120+
int[] results = resultEntries.get(i);
121+
b.addUnsignedInt32(params.length);
122+
for (int param : params) {
123+
b.addSignedInt32(param);
123124
}
124-
b.add((byte) results.length);
125-
for (byte result : results) {
126-
b.add(result);
125+
b.addUnsignedInt32(results.length);
126+
for (int result : results) {
127+
b.addSignedInt32(result);
127128
}
128129
}
129130
b.set(1, (byte) (b.size() - 2));
@@ -132,9 +133,9 @@ private byte[] generateTypeSection() {
132133
}
133134

134135
private static final class BinaryTables {
135-
private final ByteArrayList tables = new ByteArrayList();
136+
private final IntArrayList tables = new IntArrayList();
136137

137-
private void add(byte initSize, byte maxSize, byte elemType) {
138+
private void add(int initSize, int maxSize, int elemType) {
138139
tables.add(initSize);
139140
tables.add(maxSize);
140141
tables.add(elemType);
@@ -147,20 +148,20 @@ private byte[] generateTableSection() {
147148
final int tableCount = tables.size() / 3;
148149
b.add((byte) tableCount);
149150
for (int i = 0; i < tables.size(); i += 3) {
150-
b.add(tables.get(i + 2));
151+
b.addSignedInt32(tables.get(i + 2));
151152
b.add(getByte("01"));
152-
b.add(tables.get(i));
153-
b.add(tables.get(i + 1));
153+
b.addUnsignedInt32(tables.get(i));
154+
b.addUnsignedInt32(tables.get(i + 1));
154155
}
155156
b.set(1, (byte) (b.size() - 2));
156157
return b.toArray();
157158
}
158159
}
159160

160161
private static final class BinaryMemories {
161-
private final ByteArrayList memories = new ByteArrayList();
162+
private final IntArrayList memories = new IntArrayList();
162163

163-
private void add(byte initSize, byte maxSize) {
164+
private void add(int initSize, int maxSize) {
164165
memories.add(initSize);
165166
memories.add(maxSize);
166167
}
@@ -173,20 +174,20 @@ private byte[] generateMemorySection() {
173174
b.add((byte) memoryCount);
174175
for (int i = 0; i < memories.size(); i += 2) {
175176
b.add(getByte("01"));
176-
b.add(memories.get(i));
177-
b.add(memories.get(i + 1));
177+
b.addUnsignedInt32(memories.get(i));
178+
b.addUnsignedInt32(memories.get(i + 1));
178179
}
179180
b.set(1, (byte) (b.size() - 2));
180181
return b.toArray();
181182
}
182183
}
183184

184185
private static final class BinaryFunctions {
185-
private final ByteArrayList types = new ByteArrayList();
186-
private final List<byte[]> localEntries = new ArrayList<>();
186+
private final IntArrayList types = new IntArrayList();
187+
private final List<int[]> localEntries = new ArrayList<>();
187188
private final List<byte[]> codeEntries = new ArrayList<>();
188189

189-
private void add(byte typeIndex, byte[] locals, byte[] code) {
190+
private void add(int typeIndex, int[] locals, byte[] code) {
190191
types.add(typeIndex);
191192
localEntries.add(locals);
192193
codeEntries.add(code);
@@ -197,9 +198,9 @@ private byte[] generateFunctionSection() {
197198
b.add(getByte("03"));
198199
b.add((byte) 0); // length is patched at the end
199200
final int functionCount = types.size();
200-
b.add((byte) functionCount);
201+
b.addUnsignedInt32(functionCount);
201202
for (int i = 0; i < functionCount; i++) {
202-
b.add(types.get(i));
203+
b.addUnsignedInt32(types.get(i));
203204
}
204205
b.set(1, (byte) (b.size() - 2));
205206
return b.toArray();
@@ -210,15 +211,15 @@ private byte[] generateCodeSection() {
210211
b.add(getByte("0A"));
211212
b.add((byte) 0); // length is patched at the end
212213
final int functionCount = types.size();
213-
b.add((byte) functionCount);
214+
b.addUnsignedInt32(functionCount);
214215
for (int i = 0; i < functionCount; i++) {
215-
byte[] locals = localEntries.get(i);
216+
int[] locals = localEntries.get(i);
216217
byte[] code = codeEntries.get(i);
217218
int length = 1 + locals.length + code.length;
218-
b.add((byte) length);
219-
b.add((byte) locals.length);
220-
for (byte l : locals) {
221-
b.add(l);
219+
b.addUnsignedInt32(length);
220+
b.addUnsignedInt32(locals.length);
221+
for (int l : locals) {
222+
b.addSignedInt32(l);
222223
}
223224
for (byte op : code) {
224225
b.add(op);
@@ -231,10 +232,10 @@ private byte[] generateCodeSection() {
231232

232233
private static final class BinaryExports {
233234
private final ByteArrayList types = new ByteArrayList();
234-
private final ByteArrayList indices = new ByteArrayList();
235+
private final IntArrayList indices = new IntArrayList();
235236
private final List<byte[]> names = new ArrayList<>();
236237

237-
private void addFunctionExport(byte functionIndex, String name) {
238+
private void addFunctionExport(int functionIndex, String name) {
238239
types.add(getByte("00"));
239240
indices.add(functionIndex);
240241
names.add(name.getBytes(StandardCharsets.UTF_8));
@@ -244,15 +245,15 @@ private byte[] generateExportSection() {
244245
ByteArrayList b = new ByteArrayList();
245246
b.add(getByte("07"));
246247
b.add((byte) 0); // length is patched at the end
247-
b.add((byte) types.size());
248+
b.addUnsignedInt32(types.size());
248249
for (int i = 0; i < types.size(); i++) {
249250
final byte[] name = names.get(i);
250-
b.add((byte) name.length);
251+
b.addUnsignedInt32(name.length);
251252
for (byte value : name) {
252253
b.add(value);
253254
}
254255
b.add(types.get(i));
255-
b.add(indices.get(i));
256+
b.addUnsignedInt32(indices.get(i));
256257
}
257258
b.set(1, (byte) (b.size() - 2));
258259
return b.toArray();
@@ -313,10 +314,10 @@ private byte[] generateDataSection() {
313314

314315
private static final class BinaryGlobals {
315316
private final ByteArrayList mutabilities = new ByteArrayList();
316-
private final ByteArrayList valueTypes = new ByteArrayList();
317+
private final IntArrayList valueTypes = new IntArrayList();
317318
private final List<byte[]> expressions = new ArrayList<>();
318319

319-
private void add(byte mutability, byte valueType, byte[] expression) {
320+
private void add(byte mutability, int valueType, byte[] expression) {
320321
mutabilities.add(mutability);
321322
valueTypes.add(valueType);
322323
expressions.add(expression);
@@ -328,7 +329,7 @@ private byte[] generateGlobalSection() {
328329
b.add((byte) 0); // length is patched at the end
329330
b.add((byte) mutabilities.size());
330331
for (int i = 0; i < mutabilities.size(); i++) {
331-
b.add(valueTypes.get(i));
332+
b.addSignedInt32(valueTypes.get(i));
332333
b.add(mutabilities.get(i));
333334
for (byte e : expressions.get(i)) {
334335
b.add(e);
@@ -378,8 +379,8 @@ private byte[] generateCustomSections() {
378379
final byte[] name = names.get(i);
379380
final byte[] section = sections.get(i);
380381
final int size = 1 + name.length + section.length;
381-
b.add((byte) size); // length is patched at the end
382-
b.add((byte) name.length);
382+
b.addUnsignedInt32(size);
383+
b.addUnsignedInt32(name.length);
383384
b.addRange(name, 0, name.length);
384385
b.addRange(section, 0, section.length);
385386
}
@@ -400,27 +401,27 @@ protected static class BinaryBuilder {
400401

401402
private final BinaryCustomSections binaryCustomSections = new BinaryCustomSections();
402403

403-
public BinaryBuilder addType(byte[] params, byte[] results) {
404+
public BinaryBuilder addType(int[] params, int[] results) {
404405
binaryTypes.add(params, results);
405406
return this;
406407
}
407408

408-
public BinaryBuilder addTable(byte initSize, byte maxSize, byte elemType) {
409+
public BinaryBuilder addTable(int initSize, int maxSize, int elemType) {
409410
binaryTables.add(initSize, maxSize, elemType);
410411
return this;
411412
}
412413

413-
public BinaryBuilder addMemory(byte initSize, byte maxSize) {
414+
public BinaryBuilder addMemory(int initSize, int maxSize) {
414415
binaryMemories.add(initSize, maxSize);
415416
return this;
416417
}
417418

418-
public BinaryBuilder addFunction(byte typeIndex, byte[] locals, String hexCode) {
419+
public BinaryBuilder addFunction(int typeIndex, int[] locals, String hexCode) {
419420
binaryFunctions.add(typeIndex, locals, WasmTestUtils.hexStringToByteArray(hexCode));
420421
return this;
421422
}
422423

423-
public BinaryBuilder addFunctionExport(byte functionIndex, String name) {
424+
public BinaryBuilder addFunctionExport(int functionIndex, String name) {
424425
binaryExports.addFunctionExport(functionIndex, name);
425426
return this;
426427
}
@@ -435,7 +436,7 @@ public BinaryBuilder addData(String hexCode) {
435436
return this;
436437
}
437438

438-
public BinaryBuilder addGlobal(byte mutability, byte valueType, String hexCode) {
439+
public BinaryBuilder addGlobal(byte mutability, int valueType, String hexCode) {
439440
binaryGlobals.add(mutability, valueType, WasmTestUtils.hexStringToByteArray(hexCode));
440441
return this;
441442
}

wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
public class WasmJsApiSuite {
103103
private static final String REF_TYPES_OPTION = "wasm.BulkMemoryAndRefTypes";
104104

105-
private static WasmFunctionInstance createWasmFunctionInstance(WasmContext context, byte[] paramTypes, byte[] resultTypes, RootNode functionRootNode) {
105+
private static WasmFunctionInstance createWasmFunctionInstance(WasmContext context, int[] paramTypes, int[] resultTypes, RootNode functionRootNode) {
106106
WasmModule module = WasmModule.createBuiltin("dummyModule");
107107
module.allocateFunctionType(paramTypes, resultTypes, context.getContextOptions().supportMultiValue());
108108
WasmFunction func = module.declareFunction(0);
@@ -111,7 +111,6 @@ private static WasmFunctionInstance createWasmFunctionInstance(WasmContext conte
111111
// Perform normal linking steps, incl. assignTypeEquivalenceClasses().
112112
// Functions need to have type equivalence classes assigned for indirect calls.
113113
moduleInstance.store().linker().tryLink(moduleInstance);
114-
assert func.typeEquivalenceClass() >= 0 : "type equivalence class must be assigned";
115114
return new WasmFunctionInstance(moduleInstance, func, functionRootNode.getCallTarget());
116115
}
117116

@@ -503,7 +502,7 @@ public void testGlobalWriteNull() throws IOException {
503502
public void testGlobalWriteAnyfuncRefTypesDisabled() throws IOException {
504503
runTest(WasmJsApiSuite::disableRefTypes, context -> {
505504
final WebAssembly wasm = new WebAssembly(context);
506-
final WasmGlobal global = new WasmGlobal(ValueType.anyfunc, true, WasmConstant.NULL);
505+
final WasmGlobal global = WasmGlobal.allocRef(ValueType.anyfunc, true, WasmConstant.NULL);
507506
try {
508507
wasm.globalWrite(global, WasmConstant.NULL);
509508
Assert.fail("Should have failed - ref types not enabled");
@@ -517,7 +516,7 @@ public void testGlobalWriteAnyfuncRefTypesDisabled() throws IOException {
517516
public void testGlobalWriteExternrefRefTypesDisabled() throws IOException {
518517
runTest(WasmJsApiSuite::disableRefTypes, context -> {
519518
final WebAssembly wasm = new WebAssembly(context);
520-
final WasmGlobal global = new WasmGlobal(ValueType.externref, true, WasmConstant.NULL);
519+
final WasmGlobal global = WasmGlobal.allocRef(ValueType.externref, true, WasmConstant.NULL);
521520
try {
522521
wasm.globalWrite(global, WasmConstant.NULL);
523522
Assert.fail("Should have failed - ref types not enabled");
@@ -1412,7 +1411,14 @@ public void testFuncTypeMultiValue() throws IOException, InterruptedException {
14121411

14131412
@Test
14141413
public void testMultiValueReferencePassThrough() throws IOException, InterruptedException {
1415-
final byte[] source = compileWat("data", """
1414+
final byte[] source1 = compileWat("data", """
1415+
(module
1416+
(type (func (result i32)))
1417+
(func (export "func") (type 0)
1418+
i32.const 42
1419+
))
1420+
""");
1421+
final byte[] source2 = compileWat("data", """
14161422
(module
14171423
(type (func (result funcref externref)))
14181424
(import "m" "f" (func (type 0)))
@@ -1422,16 +1428,17 @@ public void testMultiValueReferencePassThrough() throws IOException, Interrupted
14221428
""");
14231429
runTest(context -> {
14241430
final WebAssembly wasm = new WebAssembly(context);
1425-
final var func = new Executable((args) -> 0);
1431+
final WasmInstance instance1 = moduleInstantiate(wasm, source1, null);
1432+
final Object func = WebAssembly.instanceExport(instance1, "func");
14261433
final var f = new Executable((args) -> {
14271434
final Object[] result = new Object[2];
14281435
result[0] = func;
14291436
result[1] = "foo";
14301437
return InteropArray.create(result);
14311438
});
14321439
final Dictionary importObject = Dictionary.create(new Object[]{"m", Dictionary.create(new Object[]{"f", f})});
1433-
final WasmInstance instance = moduleInstantiate(wasm, source, importObject);
1434-
final Object main = WebAssembly.instanceExport(instance, "main");
1440+
final WasmInstance instance2 = moduleInstantiate(wasm, source2, importObject);
1441+
final Object main = WebAssembly.instanceExport(instance2, "main");
14351442
final InteropLibrary lib = InteropLibrary.getUncached();
14361443
try {
14371444
Object result = lib.execute(main);

0 commit comments

Comments
 (0)