Skip to content

Commit 4c737d8

Browse files
committed
[GR-71209] GraalWasm code cleanup following merge of exceptions implementation.
PullRequest: graal/22545
2 parents 4b51d69 + 23db209 commit 4c737d8

File tree

16 files changed

+326
-286
lines changed

16 files changed

+326
-286
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
;;
2+
;; Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
;;
5+
;; The Universal Permissive License (UPL), Version 1.0
6+
;;
7+
;; Subject to the condition set forth below, permission is hereby granted to any
8+
;; person obtaining a copy of this software, associated documentation and/or
9+
;; data (collectively the "Software"), free of charge and under any and all
10+
;; copyright rights in the Software, and any and all patent rights owned or
11+
;; freely licensable by each licensor hereunder covering either (i) the
12+
;; unmodified Software as contributed to or provided by such licensor, or (ii)
13+
;; the Larger Works (as defined below), to deal in both
14+
;;
15+
;; (a) the Software, and
16+
;;
17+
;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
;; one is included with the Software each a "Larger Work" to which the Software
19+
;; is contributed by such licensors),
20+
;;
21+
;; without restriction, including without limitation the rights to copy, create
22+
;; derivative works of, display, perform, and distribute the Software and make,
23+
;; use, sell, offer for sale, import, export, have made, and have sold the
24+
;; Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
;; either these or other terms.
26+
;;
27+
;; This license is subject to the following condition:
28+
;;
29+
;; The above copyright notice and either this complete permission notice or at a
30+
;; minimum a reference to the UPL must be included in all copies or substantial
31+
;; portions of the Software.
32+
;;
33+
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
;; SOFTWARE.
40+
;;
41+
(module
42+
;; A fixed iteration count for the benchmark loop.
43+
(global $iterations i32 (i32.const 1000000))
44+
45+
;; Exception tag with a single i32 payload.
46+
(tag $E (param i32))
47+
48+
;; maybe_throw(x): returns x normally for 1/8 of inputs (when x & 7 == 0),
49+
;; otherwise throws tag $E carrying payload x.
50+
(func $maybe_throw (param $x i32) (result i32)
51+
;; If (x & 7) == 0, return x; else throw $E with payload x.
52+
(i32.eqz (i32.and (local.get $x) (i32.const 7)))
53+
if (result i32)
54+
(local.get $x)
55+
else
56+
(throw $E (local.get $x))
57+
end
58+
)
59+
60+
;; work(x): calls maybe_throw(x) and catches $E locally.
61+
;; - Normal path: returns x
62+
;; - Exception path: returns (payload + 1)
63+
(func $work (param $x i32) (result i32)
64+
(block $h (result i32)
65+
(try_table (result i32) (catch $E $h)
66+
(local.get $x)
67+
(return (call $maybe_throw))
68+
)
69+
)
70+
;; Stack has the payload from the thrown exception.
71+
(i32.const 1)
72+
i32.add
73+
)
74+
75+
;; mid(x): calls maybe_throw(x) inside a try; on exception, transforms the
76+
;; payload by adding 2 and rethrows a new $E with the transformed payload.
77+
(func $mid (param $x i32) (result i32)
78+
(block $h (result i32)
79+
(try_table (result i32) (catch $E $h)
80+
(return (call $maybe_throw (local.get $x)))
81+
)
82+
)
83+
;; Transform payload and throw again with the same tag.
84+
(i32.const 2)
85+
i32.add
86+
(throw $E)
87+
)
88+
89+
;; outer(x): calls mid(x) and catches $E at an outer boundary.
90+
;; - Normal path: returns x
91+
;; - Exception path: returns (payload + 3) where payload came from mid's rethrow.
92+
(func $outer (param $x i32) (result i32)
93+
(block $h (result i32)
94+
(try_table (result i32) (catch $E $h)
95+
(call $mid (local.get $x))
96+
)
97+
)
98+
(i32.const 3)
99+
i32.add
100+
)
101+
102+
;; run(): the exported benchmark entry.
103+
;; Loops for $iterations and alternates between the simple local-catch path (work)
104+
;; and the nested rethrow path (outer). Aggregates results into a checksum to
105+
;; ensure the optimizer cannot dead-code the calls.
106+
(func $run (export "run") (result i32)
107+
(local $i i32)
108+
(local $sum i32)
109+
(local $x i32)
110+
111+
(global.get $iterations)
112+
(local.set $i)
113+
114+
(loop $L
115+
;; Create a varying input argument from the loop index and the running sum.
116+
(local.set $x (i32.xor (local.get $i) (local.get $sum)))
117+
118+
;; Alternate between paths to exercise both local catch and nested rethrow.
119+
(i32.and (local.get $i) (i32.const 1))
120+
if (result i32)
121+
;; Odd iteration: local catch.
122+
(call $work (local.get $x))
123+
else
124+
;; Even iteration: nested rethrow then catch.
125+
(call $outer (local.get $x))
126+
end
127+
128+
;; Accumulate into checksum.
129+
(local.get $sum)
130+
i32.add
131+
(local.set $sum)
132+
133+
;; Decrement counter and loop until zero.
134+
(local.tee $i (i32.sub (local.get $i) (i32.const 1)))
135+
(br_if $L)
136+
)
137+
138+
;; Return checksum to prevent elimination.
139+
(local.get $sum)
140+
)
141+
)

wasm/mx.wasm/mx_wasm.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ def build(self):
321321

322322
wat2wasm_cmd = os.path.join(wabt_dir, "wat2wasm")
323323
out = mx.OutputCapture()
324-
bulk_memory_option = None
324+
wat2wasm_options = ["--enable-exceptions"]
325325
if mx.run([wat2wasm_cmd, "--version"], nonZeroIsFatal=False, out=out) != 0:
326326
if not wabt_dir:
327327
mx.warn("No WABT_DIR specified.")
@@ -332,7 +332,7 @@ def build(self):
332332

333333
major, minor, build = wat2wasm_version
334334
if int(major) == 1 and int(minor) == 0 and int(build) <= 24:
335-
bulk_memory_option = "--enable-bulk-memory"
335+
wat2wasm_options += ["--enable-bulk-memory"]
336336
except:
337337
mx.warn(f"Could not parse wat2wasm version. Output: '{out.data}'")
338338

@@ -350,9 +350,7 @@ def build(self):
350350
must_rebuild = timestamped_source.isNewerThan(timestamped_output) or not timestamped_output.exists()
351351

352352
if must_rebuild:
353-
build_cmd_line = [wat2wasm_cmd] + [source_path, "-o", output_wasm_path]
354-
if bulk_memory_option is not None:
355-
build_cmd_line += [bulk_memory_option]
353+
build_cmd_line = [wat2wasm_cmd] + [source_path, "-o", output_wasm_path] + wat2wasm_options
356354
if mx.run(build_cmd_line, nonZeroIsFatal=False) != 0:
357355
mx.abort("Could not build the wasm binary of '" + filename + "' with wat2wasm.")
358356
shutil.copyfile(source_path, output_wat_path)

wasm/mx.wasm/mx_wasm_benchmark.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,8 @@ def wasm_polybench_runner(polybench_run: mx_polybench.PolybenchRunFunction, tags
343343
polybench_run(["--native", "interpreter/*.wasm"])
344344
polybench_run(["--jvm", "simd/*.wasm", "--vm-args", "--add-modules=jdk.incubator.vector"])
345345
polybench_run(["--native", "simd/*.wasm", "--vm-args", "--add-modules=jdk.incubator.vector"])
346+
polybench_run(["--jvm", "exceptions/*.wasm", "--experimental-options", "--wasm.Exceptions=true"])
347+
polybench_run(["--native", "exceptions/*.wasm", "--experimental-options", "--wasm.Exceptions=true"])
346348
polybench_run(["--jvm", "interpreter/*.wasm", "--metric=metaspace-memory"])
347349
polybench_run(["--jvm", "interpreter/*.wasm", "--metric=application-memory"])
348350
polybench_run(["--jvm", "interpreter/*.wasm", "--metric=allocated-bytes", "-w", "40", "-i", "10", "--experimental-options", "--engine.Compilation=false"])

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676
import org.graalvm.polyglot.Value;
7777
import org.graalvm.polyglot.io.IOAccess;
7878
import org.graalvm.wasm.GlobalRegistry;
79-
import org.graalvm.wasm.MemoryRegistry;
8079
import org.graalvm.wasm.RuntimeState;
8180
import org.graalvm.wasm.WasmContext;
8281
import org.graalvm.wasm.WasmFunctionInstance;
@@ -216,7 +215,6 @@ private void runInContext(WasmCase testCase, Context context, List<Source> sourc
216215
}
217216

218217
final WasmContext wasmContext = WasmContext.get(null);
219-
final List<WasmInstance> instanceList = moduleInstances.stream().map(i -> toWasmInstance(i)).toList();
220218

221219
final Value testFunction;
222220
final String entryPoint = testCase.options().getProperty("entry-point");
@@ -261,6 +259,7 @@ private void runInContext(WasmCase testCase, Context context, List<Source> sourc
261259
} finally {
262260
// Context may have already been closed, e.g. by __wasi_proc_exit.
263261
if (!wasmContext.environment().getContext().isClosed()) {
262+
Collection<WasmInstance> instanceList = wasmContext.contextStore().moduleInstances().values();
264263
// Save context state, and check that it's consistent with the previous one.
265264
if (iterationNeedsStateCheck(i)) {
266265
final ContextState contextState = saveContext(wasmContext, instanceList);
@@ -275,11 +274,11 @@ private void runInContext(WasmCase testCase, Context context, List<Source> sourc
275274
final boolean reinitMemory = requiresZeroMemory || iterationNeedsStateCheck(i + 1);
276275
if (reinitMemory) {
277276
for (WasmInstance instance : instanceList) {
278-
for (int j = 0; j < instance.store().memories().count(); ++j) {
279-
WasmMemoryLibrary.getUncached().reset(instance.store().memories().memory(j));
277+
for (int j = 0; j < instance.module().memoryCount(); ++j) {
278+
WasmMemoryLibrary.getUncached().reset(instance.memory(j));
280279
}
281-
for (int j = 0; j < instance.store().tables().tableCount(); ++j) {
282-
instance.store().tables().table(j).reset();
280+
for (int j = 0; j < instance.module().tableCount(); ++j) {
281+
instance.table(j).reset();
283282
}
284283
}
285284
}
@@ -637,25 +636,28 @@ protected String suiteName() {
637636
}
638637

639638
private static InstanceState saveInstanceState(WasmInstance instance) {
640-
final MemoryRegistry memories = instance.store().memories().duplicate();
639+
final WasmMemory[] memories = new WasmMemory[instance.module().memoryCount()];
640+
for (int i = 0; i < memories.length; i++) {
641+
memories[i] = WasmMemoryLibrary.getUncached().duplicate(instance.memory(i));
642+
}
641643
final GlobalRegistry globals = instance.globals().duplicate();
642644
return new InstanceState(memories, globals);
643645
}
644646

645-
private static ContextState saveContext(WasmContext context, List<WasmInstance> instances) {
647+
private static ContextState saveContext(WasmContext context, Collection<WasmInstance> instances) {
646648
return new ContextState(
647649
instances.stream().map(instance -> saveInstanceState(instance)).toList(),
648650
context.fdManager().size());
649651
}
650652

651653
private static void assertInstanceEqual(InstanceState expectedState, InstanceState actualState) {
652654
// Compare memories
653-
final MemoryRegistry expectedMemories = expectedState.memories();
654-
final MemoryRegistry actualMemories = actualState.memories();
655-
Assert.assertEquals("Mismatch in memory counts.", expectedMemories.count(), actualMemories.count());
656-
for (int i = 0; i < expectedMemories.count(); i++) {
657-
final WasmMemory expectedMemory = expectedMemories.memory(i);
658-
final WasmMemory actualMemory = actualMemories.memory(i);
655+
final WasmMemory[] expectedMemories = expectedState.memories();
656+
final WasmMemory[] actualMemories = actualState.memories();
657+
Assert.assertEquals("Mismatch in memory counts.", expectedMemories.length, actualMemories.length);
658+
for (int i = 0; i < expectedMemories.length; i++) {
659+
final WasmMemory expectedMemory = expectedMemories[i];
660+
final WasmMemory actualMemory = actualMemories[i];
659661
if (expectedMemory == null) {
660662
Assert.assertNull("Memory should be null", actualMemory);
661663
} else {
@@ -690,7 +692,7 @@ private static void assertContextEqual(ContextState expectedState, ContextState
690692
Assert.assertEquals("Mismatch in file descriptor counts.", expectedState.openedFdCount, actualState.openedFdCount);
691693
}
692694

693-
private record InstanceState(MemoryRegistry memories, GlobalRegistry globals) {
695+
private record InstanceState(WasmMemory[] memories, GlobalRegistry globals) {
694696
}
695697

696698
private record ContextState(List<InstanceState> instanceState, int openedFdCount) {

0 commit comments

Comments
 (0)