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+ )
0 commit comments