Skip to content

Commit e724742

Browse files
committed
[GR-57593] Implement WebAssembly exception handling proposal.
PullRequest: graal/22177
2 parents 32c0fc2 + bd252e2 commit e724742

File tree

103 files changed

+4389
-1662
lines changed

Some content is hidden

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

103 files changed

+4389
-1662
lines changed

ci/common.jsonnet

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ local common_json = import "../common.json";
316316

317317
wasm:: {
318318
downloads+: {
319-
WABT_DIR: {name: 'wabt', version: '1.0.36', platformspecific: true},
319+
WABT_DIR: {name: 'wabt', version: '1.0.37', platformspecific: true},
320320
},
321321
environment+: {
322322
WABT_DIR: '$WABT_DIR/bin',
@@ -325,7 +325,7 @@ local common_json = import "../common.json";
325325

326326
wasm_ol8:: {
327327
downloads+: {
328-
WABT_DIR: {name: 'wabt', version: '1.0.36-ol8', platformspecific: true},
328+
WABT_DIR: {name: 'wabt', version: '1.0.37-ol8', platformspecific: true},
329329
},
330330
environment+: {
331331
WABT_DIR: '$WABT_DIR/bin',

wasm/CHANGELOG.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
This changelog summarizes major changes to the WebAssembly engine implemented in GraalVM (GraalWasm).
44

5+
## Version 25.1.0
6+
7+
* Implemented the [exception handling](https://github.com/WebAssembly/exception-handling) proposal. This feature can be enabled with the experimental option `wasm.Exceptions=true`.
8+
59
## Version 25.0.0
610

711
* BREAKING: Changed Context.eval of _wasm_ sources to return a compiled, but not yet instantiated, module object instead of the module instance.
@@ -27,14 +31,13 @@ This changelog summarizes major changes to the WebAssembly engine implemented in
2731
* Added an implementation of the [SIMD](https://github.com/WebAssembly/simd) proposal using the JDK's Vector API. This improves peak performance when running WebAssembly code which makes heavy use of the new instructions in the SIMD proposal. This new implementation is always used in native image. On the JVM, it is opt-in and requires setting `--add-modules=jdk.incubator.vector`. Use of the incubating Vector API will result in the following warning message being printed to stderr:
2832
```
2933
WARNING: Using incubator modules: jdk.incubator.vector
30-
```
31-
34+
```
3235

3336
## Version 24.2.0
3437

3538
* Updated developer metadata of Maven artifacts.
3639
* Deprecated the `--wasm.AsyncParsingBinarySize` and `--wasm.AsyncParsingStackSize` options. These options no longer have any effect and will be removed in a future release.
37-
* Implemented the [Relaxed SIMD](https://github.com/WebAssembly/relaxed-simd) proposal. This feature can be enabled with the options `--wasm.RelaxedSIMD`.
40+
* Implemented the [Relaxed SIMD](https://github.com/WebAssembly/relaxed-simd) proposal. This feature can be enabled with the option `--wasm.RelaxedSIMD`.
3841

3942
## Version 24.1.0
4043

wasm/docs/contributor/TestsAndBenchmarks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Building GraalWasm using the `mx build` command will also create the `wasm-tests.jar`, which contains the main test cases.
66
To run these tests, the WebAssembly binary toolkit is needed.
77

8-
1. Download the binary of the [WebAssembly binary toolkit(wabt)](https://github.com/WebAssembly/wabt) and extract it.
8+
1. Download the binary of the [WebAssembly binary toolkit(wabt)](https://github.com/WebAssembly/wabt) (**1.0.37** or higher) and extract it.
99

1010
2. Set `WABT_DIR`:
1111
```bash

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,29 @@ private byte[] generateGlobalSection() {
339339
}
340340
}
341341

342+
private static final class BinaryTags {
343+
private final ByteArrayList attributes = new ByteArrayList();
344+
private final ByteArrayList typeIndices = new ByteArrayList();
345+
346+
private void add(byte attribute, byte typeIndex) {
347+
attributes.add(attribute);
348+
typeIndices.add(typeIndex);
349+
}
350+
351+
private byte[] generateTagSection() {
352+
ByteArrayList b = new ByteArrayList();
353+
b.add(getByte("0d"));
354+
b.add((byte) 0); // length is patched at the end
355+
b.add((byte) attributes.size());
356+
for (int i = 0; i < attributes.size(); i++) {
357+
b.add(attributes.get(i));
358+
b.add(typeIndices.get(i));
359+
}
360+
b.set(1, (byte) (b.size() - 2));
361+
return b.toArray();
362+
}
363+
}
364+
342365
private static final class BinaryCustomSections {
343366
private final List<byte[]> names = new ArrayList<>();
344367
private final List<byte[]> sections = new ArrayList<>();
@@ -373,6 +396,7 @@ protected static class BinaryBuilder {
373396
private final BinaryElements binaryElements = new BinaryElements();
374397
private final BinaryDatas binaryDatas = new BinaryDatas();
375398
private final BinaryGlobals binaryGlobals = new BinaryGlobals();
399+
private final BinaryTags binaryTags = new BinaryTags();
376400

377401
private final BinaryCustomSections binaryCustomSections = new BinaryCustomSections();
378402

@@ -416,6 +440,11 @@ public BinaryBuilder addGlobal(byte mutability, byte valueType, String hexCode)
416440
return this;
417441
}
418442

443+
public BinaryBuilder addTag(byte attribute, byte typeIndex) {
444+
binaryTags.add(attribute, typeIndex);
445+
return this;
446+
}
447+
419448
public BinaryBuilder addCustomSection(String name, byte[] section) {
420449
binaryCustomSections.add(name, section);
421450
return this;
@@ -443,8 +472,9 @@ public byte[] build() {
443472
final byte[] codeSection = binaryFunctions.generateCodeSection();
444473
final byte[] dataSection = binaryDatas.generateDataSection();
445474
final byte[] customSections = binaryCustomSections.generateCustomSections();
475+
final byte[] tagSection = binaryTags.generateTagSection();
446476
final int totalLength = preamble.length + typeSection.length + functionSection.length + tableSection.length + memorySection.length + globalSection.length + exportSection.length +
447-
elementSection.length + dataCountSection.length + codeSection.length + dataSection.length + customSections.length;
477+
elementSection.length + dataCountSection.length + codeSection.length + dataSection.length + customSections.length + tagSection.length;
448478
final byte[] binary = new byte[totalLength];
449479
int length = 0;
450480
System.arraycopy(preamble, 0, binary, length, preamble.length);
@@ -457,6 +487,8 @@ public byte[] build() {
457487
length += tableSection.length;
458488
System.arraycopy(memorySection, 0, binary, length, memorySection.length);
459489
length += memorySection.length;
490+
System.arraycopy(tagSection, 0, binary, length, tagSection.length);
491+
length += tagSection.length;
460492
System.arraycopy(globalSection, 0, binary, length, globalSection.length);
461493
length += globalSection.length;
462494
System.arraycopy(exportSection, 0, binary, length, exportSection.length);

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,13 +399,17 @@ private WasmTestStatus runTestCase(WasmCase testCase, Engine sharedEngine) {
399399

400400
EnumSet<WasmBinaryTools.WabtOption> options = EnumSet.noneOf(WasmBinaryTools.WabtOption.class);
401401
String threadsOption = testCase.options().getProperty("wasm.Threads");
402-
if (threadsOption != null && threadsOption.equals("true")) {
402+
if ("true".equals(threadsOption)) {
403403
options.add(WasmBinaryTools.WabtOption.THREADS);
404404
}
405405
String multiMemoryOption = testCase.options().getProperty("wasm.MultiMemory");
406-
if (multiMemoryOption != null && multiMemoryOption.equals("true")) {
406+
if ("true".equals(multiMemoryOption)) {
407407
options.add(WasmBinaryTools.WabtOption.MULTI_MEMORY);
408408
}
409+
String exceptionsOption = testCase.options().getProperty("wasm.Exceptions");
410+
if ("true".equals(exceptionsOption)) {
411+
options.add(WasmBinaryTools.WabtOption.EXCEPTIONS);
412+
}
409413
ArrayList<Source> sources = testCase.getSources(options);
410414

411415
runInContexts(testCase, contextBuilder, sources, sharedEngine, testOut);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -854,11 +854,11 @@ public void testExportCountsLimit() throws IOException {
854854
context.readModule(binaryWithMixedExports, limits);
855855

856856
final int noLimit = Integer.MAX_VALUE;
857-
limits = new ModuleLimits(noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, 6, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit);
857+
limits = new ModuleLimits(noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, 6, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit);
858858
context.readModule(binaryWithMixedExports, limits);
859859

860860
try {
861-
limits = new ModuleLimits(noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, 5, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit);
861+
limits = new ModuleLimits(noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, 5, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit, noLimit);
862862
context.readModule(binaryWithMixedExports, limits);
863863
Assert.fail("Should have failed - export count exceeds the limit");
864864
} catch (WasmException ex) {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -50,6 +50,7 @@
5050
import org.graalvm.wasm.test.suites.bytecode.MultiInstantiationSuite;
5151
import org.graalvm.wasm.test.suites.control.BlockWithLocalsSuite;
5252
import org.graalvm.wasm.test.suites.control.BranchBlockSuite;
53+
import org.graalvm.wasm.test.suites.control.ExceptionSuite;
5354
import org.graalvm.wasm.test.suites.control.IfThenElseSuite;
5455
import org.graalvm.wasm.test.suites.control.LoopBlockSuite;
5556
import org.graalvm.wasm.test.suites.control.MultiValueSuite;
@@ -62,9 +63,9 @@
6263
import org.graalvm.wasm.test.suites.memory.MemorySuite;
6364
import org.graalvm.wasm.test.suites.memory.MultiMemorySuite;
6465
import org.graalvm.wasm.test.suites.memory.ThreadsSuite;
65-
import org.graalvm.wasm.test.suites.validation.ReferenceTypesValidationSuite;
6666
import org.graalvm.wasm.test.suites.table.TableSuite;
6767
import org.graalvm.wasm.test.suites.validation.MultiValueValidationSuite;
68+
import org.graalvm.wasm.test.suites.validation.ReferenceTypesValidationSuite;
6869
import org.graalvm.wasm.test.suites.validation.ValidationSuite;
6970
import org.graalvm.wasm.test.suites.wasi.WasiSuite;
7071
import org.graalvm.wasm.test.suites.webassembly.EmscriptenSuite;
@@ -105,6 +106,7 @@
105106
MultiInstantiationSuite.class,
106107
MultiMemorySuite.class,
107108
ThreadsSuite.class,
109+
ExceptionSuite.class,
108110
DebugValidationSuite.class,
109111
DebugObjectFactorySuite.class
110112
})

wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/BytecodeSuite.java

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
import org.graalvm.wasm.WasmType;
4747
import org.graalvm.wasm.constants.Bytecode;
48+
import org.graalvm.wasm.constants.ExceptionHandlerType;
4849
import org.graalvm.wasm.constants.SegmentMode;
4950
import org.graalvm.wasm.parser.bytecode.RuntimeBytecodeGen;
5051
import org.junit.Assert;
@@ -168,7 +169,7 @@ public void testBrU8Max() {
168169
expected[255] = (byte) 0xFF;
169170
test(b -> {
170171
for (int i = 0; i < 254; i++) {
171-
b.add(0);
172+
b.addOp(0);
172173
}
173174
b.addBranch(0);
174175
}, expected);
@@ -194,7 +195,7 @@ public void testBrI32MinBackward() {
194195
expected[259] = (byte) 0xFF;
195196
test(b -> {
196197
for (int i = 0; i < 255; i++) {
197-
b.add(0);
198+
b.addOp(0);
198199
}
199200
b.addBranch(0);
200201
}, expected);
@@ -212,7 +213,7 @@ public void testBrIfU8Max() {
212213
expected[255] = (byte) 0xFF;
213214
test(b -> {
214215
for (int i = 0; i < 254; i++) {
215-
b.add(0);
216+
b.addOp(0);
216217
}
217218
b.addBranchIf(0);
218219
}, expected);
@@ -238,7 +239,7 @@ public void testBrIfI32MinBackward() {
238239
expected[259] = (byte) 0xFF;
239240
test(b -> {
240241
for (int i = 0; i < 255; i++) {
241-
b.add(0);
242+
b.addOp(0);
242243
}
243244
b.addBranchIf(0);
244245
}, expected);
@@ -448,52 +449,52 @@ public void testMemoryInstructionInvalidOpcodeI32() {
448449

449450
@Test
450451
public void testAddMin() {
451-
test(b -> b.add(0x00), new byte[]{0x00});
452+
test(b -> b.addOp(0x00), new byte[]{0x00});
452453
}
453454

454455
@Test
455456
public void testAddMax() {
456-
test(b -> b.add(0xFF), new byte[]{(byte) 0xFF});
457+
test(b -> b.addOp(0xFF), new byte[]{(byte) 0xFF});
457458
}
458459

459460
@Test
460461
public void testInvalidAdd() {
461-
testAssertion(b -> b.add(256), "opcode does not fit into byte");
462+
testAssertion(b -> b.addOp(256), "opcode does not fit into byte");
462463
}
463464

464465
@Test
465466
public void testAddImmediateMin() {
466-
test(b -> b.add(0x01, 0), new byte[]{0x01, 0x00, 0x00, 0x00, 0x00});
467+
test(b -> b.addOp(0x01, 0), new byte[]{0x01, 0x00, 0x00, 0x00, 0x00});
467468
}
468469

469470
@Test
470471
public void testAddImmediateMax() {
471-
test(b -> b.add(0x01, 0xFFFFFFFF), new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF});
472+
test(b -> b.addOp(0x01, 0xFFFFFFFF), new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF});
472473
}
473474

474475
@Test
475476
public void testInvalidAddImmediate() {
476-
testAssertion(b -> b.add(256, 0), "opcode does not fit into byte");
477+
testAssertion(b -> b.addOp(256, 0), "opcode does not fit into byte");
477478
}
478479

479480
@Test
480481
public void testAddImmediate64Max() {
481-
test(b -> b.add(0x01, 0xFFFFFFFFFFFFFFFFL), new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF});
482+
test(b -> b.addOp(0x01, 0xFFFFFFFFFFFFFFFFL), new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF});
482483
}
483484

484485
@Test
485486
public void testInvalidAddImmediate64() {
486-
testAssertion(b -> b.add(256, 0xFFL), "opcode does not fit into byte");
487+
testAssertion(b -> b.addOp(256, 0xFFL), "opcode does not fit into byte");
487488
}
488489

489490
@Test
490491
public void testAddImmediateMax2() {
491-
test(b -> b.add(0x01, 0, 0xFFFFFFFF), new byte[]{0x01, 0x00, 0x00, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF});
492+
test(b -> b.addOp(0x01, 0, 0xFFFFFFFF), new byte[]{0x01, 0x00, 0x00, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF});
492493
}
493494

494495
@Test
495496
public void testInvalidAddImmediate2() {
496-
testAssertion(b -> b.add(256, 0, 0), "opcode does not fit into byte");
497+
testAssertion(b -> b.addOp(256, 0, 0), "opcode does not fit into byte");
497498
}
498499

499500
@Test
@@ -686,6 +687,11 @@ public void testElemHeaderExternref() {
686687
test(b -> b.addElemHeader(SegmentMode.ACTIVE, 8, WasmType.EXTERNREF_TYPE, 0, null, -1), new byte[]{0x40, 0x20, 0x08});
687688
}
688689

690+
@Test
691+
public void testElemHeaderExnref() {
692+
test(b -> b.addElemHeader(SegmentMode.ACTIVE, 8, WasmType.EXNREF_TYPE, 0, null, -1), new byte[]{0x40, 0x30, 0x08});
693+
}
694+
689695
@Test
690696
public void testElemHeaderMinU8TableIndex() {
691697
test(b -> b.addElemHeader(SegmentMode.ACTIVE, 0, WasmType.FUNCREF_TYPE, 1, null, -1), new byte[]{0x50, 0x10, 0x00, 0x01});
@@ -915,4 +921,15 @@ public void testCodeEntryLocals() {
915921
public void testCodeEntryResults() {
916922
test(b -> b.addCodeEntry(0, 0, 0, 0, 1), new byte[]{0x05, 0x00});
917923
}
924+
925+
@Test
926+
public void testCatchExceptionHandler() {
927+
test(b -> b.addExceptionHandler(5, 10, ExceptionHandlerType.CATCH, 0, 10), new byte[]{0x05, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00});
928+
}
929+
930+
@Test
931+
public void testCatchRefExceptionHandler() {
932+
test(b -> b.addExceptionHandler(0, 12, ExceptionHandlerType.CATCH_REF, 1, 256),
933+
new byte[]{0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00});
934+
}
918935
}

0 commit comments

Comments
 (0)