From 03f528a92d11517932cdca23b13698d107f7ad3e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 13:27:26 -0800 Subject: [PATCH 01/11] okgo --- scripts/fuzz_opt.py | 4 ++-- scripts/fuzz_shell.js | 17 +++++++++++++++++ src/tools/execution-results.h | 3 ++- src/tools/fuzzing/fuzzing.cpp | 5 +++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index e90b8fa65d6..eb5c56995b7 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -2689,12 +2689,12 @@ def get_random_opts(): # We can't do this if a.wasm doesn't exist, which can be the # case if we failed to even generate the wasm. if not os.path.exists('a.wasm'): - print('''\ + print(f'''\ ================================================================================ You found a bug in the fuzzer itself! It failed to generate a valid wasm file from the random input. Please report it with - seed: %(seed)d + seed: {seed} and the exact version of Binaryen you found it on, plus the exact Python version (hopefully deterministic random numbers will be identical). diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 47d73a51248..89b4cd3c3dd 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -163,6 +163,21 @@ function logValue(x, y) { console.log('[LoggingExternalInterface logging ' + printed(x, y) + ']'); } +function logRef(ref) { + // Look for VM bugs by doing some basic operations on the reference: + // first, convert it to various things. + +ref; + ref + ''; + JSON.stringify(ref); + // If not null, try to read a property, which might exercise an + // interesting code path. + if (ref) { + ref.foobar; + } + // Finally, log normally as with all other loggers. + logValue(ref); +} + // Track the exports in a map (similar to the Exports object from wasm, i.e., // whose keys are strings and whose values are the corresponding exports). var exports = {}; @@ -290,6 +305,8 @@ var imports = { // we could avoid running JS on code with SIMD in it, but it is useful to // fuzz such code as much as we can.) 'log-v128': logValue, + 'log-anyref': logRef, + 'log-funcref': logRef, // Throw an exception from JS. 'throw': (which) => { diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 7df3e3939da..0d59010e10d 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -447,11 +447,12 @@ struct ExecutionResults { // simple and stable internal structures that optimizations will not alter. auto type = value.type; if (type.isRef()) { + auto heapType = type.getHeapType(); if (type.isString() || type.getHeapType().isMaybeShared(HeapType::i31)) { std::cout << value << '\n'; } else if (value.isNull()) { std::cout << "null\n"; - } else if (type.isFunction()) { + } else if (heapType.getTop() == HeapType::func) { std::cout << "function\n"; } else { std::cout << "object\n"; diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 19c4e00ab35..4c6c5a0a90e 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -50,6 +50,11 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, if (wasm.features.hasSIMD()) { loggableTypes.push_back(Type::v128); } + if (wasm.features.hasGC()) { + loggableTypes.push_back(Type(HeapType::any, Nullable)); + loggableTypes.push_back(Type(HeapType::func, Nullable)); + // TODO: cont, extern (, exn?) + } // Setup params. Start with the defaults. globalParams = std::make_unique(*this); From f83da5a6e4425ff3a88ee0178c1ae274edaca360 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 13:35:31 -0800 Subject: [PATCH 02/11] fix --- src/tools/execution-results.h | 87 ++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 0d59010e10d..f5f55bdaaee 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -52,6 +52,47 @@ Tag& getJsTag() { return tag; } +void printValue(Literal value) { + // Unwrap an externalized GC value to get the actual value, but not strings, + // which are normally a subtype of ext. + if (Type::isSubType(value.type, Type(HeapType::ext, Nullable)) && + !value.type.isString()) { + value = value.internalize(); + } + + // An anyref literal is a string. + if (value.type.isRef() && + value.type.getHeapType().isMaybeShared(HeapType::any)) { + value = value.externalize(); + } + + // Don't print most reference values, as e.g. funcref(N) contains an index, + // which is not guaranteed to remain identical after optimizations. Do not + // print the type in detail (as even that may change due to closed-world + // optimizations); just print a simple type like JS does, 'object' or + // 'function', but also print null for a null (so a null function does not + // get printed as object, as in JS we have typeof null == 'object'). + // + // The only references we print in full are strings and i31s, which have + // simple and stable internal structures that optimizations will not alter. + auto type = value.type; + if (type.isRef()) { + if (type.isString() || type.getHeapType().isMaybeShared(HeapType::i31)) { + std::cout << value; + } else if (value.isNull()) { + std::cout << "null"; + } else if (type.isFunction()) { + std::cout << "function"; + } else { + std::cout << "object"; + } + return; + } + + // Non-references can be printed in full. + std::cout << value; +} + } // namespace // Logs every relevant import call parameter. @@ -127,7 +168,8 @@ struct LoggingExternalInterface : public ShellExternalInterface { std::cout << ' ' << high; loggings.push_back(high); } else { - std::cout << ' ' << argument; + std::cout << ' '; + printValue(argument); loggings.push_back(argument); } } @@ -416,54 +458,13 @@ struct ExecutionResults { std::cout << "[fuzz-exec] note result: " << exp->name << " => "; for (auto value : *values) { printValue(value); + std::cout << '\n'; } } } } } - void printValue(Literal value) { - // Unwrap an externalized GC value to get the actual value, but not strings, - // which are normally a subtype of ext. - if (Type::isSubType(value.type, Type(HeapType::ext, Nullable)) && - !value.type.isString()) { - value = value.internalize(); - } - - // An anyref literal is a string. - if (value.type.isRef() && - value.type.getHeapType().isMaybeShared(HeapType::any)) { - value = value.externalize(); - } - - // Don't print most reference values, as e.g. funcref(N) contains an index, - // which is not guaranteed to remain identical after optimizations. Do not - // print the type in detail (as even that may change due to closed-world - // optimizations); just print a simple type like JS does, 'object' or - // 'function', but also print null for a null (so a null function does not - // get printed as object, as in JS we have typeof null == 'object'). - // - // The only references we print in full are strings and i31s, which have - // simple and stable internal structures that optimizations will not alter. - auto type = value.type; - if (type.isRef()) { - auto heapType = type.getHeapType(); - if (type.isString() || type.getHeapType().isMaybeShared(HeapType::i31)) { - std::cout << value << '\n'; - } else if (value.isNull()) { - std::cout << "null\n"; - } else if (heapType.getTop() == HeapType::func) { - std::cout << "function\n"; - } else { - std::cout << "object\n"; - } - return; - } - - // Non-references can be printed in full. - std::cout << value << '\n'; - } - // get current results and check them against previous ones void check(Module& wasm) { ExecutionResults optimizedResults; From f344732c14da6041b664a05e40acb01318ef44ed Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 13:40:20 -0800 Subject: [PATCH 03/11] test --- test/lit/exec/fuzzing-api.wast | 59 ++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 2595d7e6e60..159e2c57804 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -7,6 +7,8 @@ (module (import "fuzzing-support" "log-i32" (func $log-i32 (param i32))) (import "fuzzing-support" "log-f64" (func $log-f64 (param f64))) + (import "fuzzing-support" "log-anyref" (func $log-anyref (param anyref))) + (import "fuzzing-support" "log-funcref" (func $log-funcref (param funcref))) (import "fuzzing-support" "throw" (func $throw (param i32))) @@ -24,6 +26,8 @@ (import "fuzzing-support" "wasmtag" (tag $imported-wasm-tag (param i32))) (import "fuzzing-support" "jstag" (tag $imported-js-tag (param externref))) + (type $i32 (struct i32)) + (table $table 10 20 funcref) ;; Note that the exported table appears first here, but in the binary and in @@ -33,6 +37,9 @@ ;; CHECK: [fuzz-exec] calling logging ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging object] + ;; CHECK-NEXT: [LoggingExternalInterface logging function] (func $logging (export "logging") (call $log-i32 (i32.const 42) @@ -40,6 +47,19 @@ (call $log-f64 (f64.const 3.14159) ) + (call $log-anyref + (ref.null any) + ) + ;; struct values and func names are not logged, due to differences between + ;; VMs and changes due to optimizations, that make comparisons hard. + (call $log-anyref + (struct.new $i32 + (i32.const 42) + ) + ) + (call $log-funcref + (ref.func $logging) + ) ) ;; CHECK: [fuzz-exec] calling throwing @@ -105,6 +125,9 @@ ;; CHECK: [fuzz-exec] calling export.calling ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging object] + ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $export.calling (export "export.calling") ;; At index 0 in the exports we have $logging, so we will do those loggings. @@ -123,6 +146,9 @@ ;; CHECK: [fuzz-exec] calling export.calling.rethrow ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging object] + ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $export.calling.rethrow (export "export.calling.rethrow") ;; As above, but the second param is different. @@ -142,6 +168,9 @@ ;; CHECK: [fuzz-exec] calling export.calling.catching ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging object] + ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $export.calling.catching (export "export.calling.catching") @@ -163,6 +192,9 @@ ;; CHECK: [fuzz-exec] calling ref.calling ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging object] + ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $ref.calling (export "ref.calling") ;; This will emit some logging. @@ -181,6 +213,9 @@ ;; CHECK: [fuzz-exec] calling ref.calling.rethrow ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging object] + ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $ref.calling.rethrow (export "ref.calling.rethrow") ;; As with calling an export, when we set the flags to 1 exceptions are @@ -199,6 +234,9 @@ ;; CHECK: [fuzz-exec] calling ref.calling.catching ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging object] + ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $ref.calling.catching (export "ref.calling.catching") @@ -409,6 +447,9 @@ ;; CHECK: [fuzz-exec] calling logging ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging object] +;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK: [fuzz-exec] calling throwing ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] @@ -427,32 +468,50 @@ ;; CHECK: [fuzz-exec] calling export.calling ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging object] +;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling export.calling.rethrow ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging object] +;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling export.calling.catching ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging object] +;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] ;; CHECK: [fuzz-exec] calling ref.calling ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging object] +;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling ref.calling.rethrow ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging object] +;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling ref.calling.catching ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging object] +;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] From 93caf1ede969d396d6740f5eb97964c59eea4d45 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 13:42:47 -0800 Subject: [PATCH 04/11] work --- src/tools/fuzzing/fuzzing.cpp | 4 ++- test/lit/exec/fuzzing-api.wast | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 4c6c5a0a90e..218b8d3080d 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -53,7 +53,9 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, if (wasm.features.hasGC()) { loggableTypes.push_back(Type(HeapType::any, Nullable)); loggableTypes.push_back(Type(HeapType::func, Nullable)); - // TODO: cont, extern (, exn?) + loggableTypes.push_back(Type(HeapType::cont, Nullable)); + loggableTypes.push_back(Type(HeapType::ext, Nullable)); + loggableTypes.push_back(Type(HeapType::exn, Nullable)); } // Setup params. Start with the defaults. diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 159e2c57804..8dd3c4dc772 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -9,6 +9,9 @@ (import "fuzzing-support" "log-f64" (func $log-f64 (param f64))) (import "fuzzing-support" "log-anyref" (func $log-anyref (param anyref))) (import "fuzzing-support" "log-funcref" (func $log-funcref (param funcref))) + (import "fuzzing-support" "log-contref" (func $log-contref (param contref))) + (import "fuzzing-support" "log-exnref" (func $log-exnref (param exnref))) + (import "fuzzing-support" "log-externref" (func $log-externref (param externref))) (import "fuzzing-support" "throw" (func $throw (param i32))) @@ -40,6 +43,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] (func $logging (export "logging") (call $log-i32 (i32.const 42) @@ -60,6 +66,15 @@ (call $log-funcref (ref.func $logging) ) + (call $log-contref + (ref.null cont) + ) + (call $log-exnref + (ref.null exn) + ) + (call $log-externref + (ref.null extern) + ) ) ;; CHECK: [fuzz-exec] calling throwing @@ -128,6 +143,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $export.calling (export "export.calling") ;; At index 0 in the exports we have $logging, so we will do those loggings. @@ -149,6 +167,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $export.calling.rethrow (export "export.calling.rethrow") ;; As above, but the second param is different. @@ -171,6 +192,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $export.calling.catching (export "export.calling.catching") @@ -195,6 +219,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $ref.calling (export "ref.calling") ;; This will emit some logging. @@ -216,6 +243,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $ref.calling.rethrow (export "ref.calling.rethrow") ;; As with calling an export, when we set the flags to 1 exceptions are @@ -237,6 +267,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] + ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $ref.calling.catching (export "ref.calling.catching") @@ -450,6 +483,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK: [fuzz-exec] calling throwing ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] @@ -471,6 +507,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling export.calling.rethrow @@ -479,6 +518,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling export.calling.catching @@ -487,6 +529,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] @@ -496,6 +541,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling ref.calling.rethrow @@ -504,6 +552,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling ref.calling.catching @@ -512,6 +563,9 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging object] ;; CHECK-NEXT: [LoggingExternalInterface logging function] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] +;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] From 0a4fd450d4c981420d05aed190470358c57be797 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 13:44:05 -0800 Subject: [PATCH 05/11] okgo --- src/tools/fuzzing/fuzzing.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 218b8d3080d..3dc315bb135 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -53,8 +53,12 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, if (wasm.features.hasGC()) { loggableTypes.push_back(Type(HeapType::any, Nullable)); loggableTypes.push_back(Type(HeapType::func, Nullable)); - loggableTypes.push_back(Type(HeapType::cont, Nullable)); loggableTypes.push_back(Type(HeapType::ext, Nullable)); + } + if (wasm.features.hasStackSwitching()) { + loggableTypes.push_back(Type(HeapType::cont, Nullable)); + } + if (wasm.features.hasExceptionHandling()) { loggableTypes.push_back(Type(HeapType::exn, Nullable)); } From 36198f2116f90bde1c3f0dfac83449e1cf413131 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 14:10:27 -0800 Subject: [PATCH 06/11] shel --- scripts/fuzz_shell.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 89b4cd3c3dd..1939a1dfa08 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -307,6 +307,9 @@ var imports = { 'log-v128': logValue, 'log-anyref': logRef, 'log-funcref': logRef, + 'log-contref': logRef, + 'log-externref': logRef, + 'log-exnref': logRef, // Throw an exception from JS. 'throw': (which) => { From 7d79c6b1e3aeda50d688d7d29f8b202ecc336552 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 14:24:55 -0800 Subject: [PATCH 07/11] work --- scripts/fuzz_shell.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 1939a1dfa08..315a971b863 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -166,8 +166,8 @@ function logValue(x, y) { function logRef(ref) { // Look for VM bugs by doing some basic operations on the reference: // first, convert it to various things. - +ref; - ref + ''; + //+ref; // traps + //ref + ''; // traps JSON.stringify(ref); // If not null, try to read a property, which might exercise an // interesting code path. From 14555249b0e66ff7fe2785ec327bae99fdd9832e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 15:27:22 -0800 Subject: [PATCH 08/11] work --- src/tools/fuzzing/fuzzing.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 3dc315bb135..cdd0b041c28 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -50,16 +50,18 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, if (wasm.features.hasSIMD()) { loggableTypes.push_back(Type::v128); } - if (wasm.features.hasGC()) { - loggableTypes.push_back(Type(HeapType::any, Nullable)); - loggableTypes.push_back(Type(HeapType::func, Nullable)); - loggableTypes.push_back(Type(HeapType::ext, Nullable)); - } - if (wasm.features.hasStackSwitching()) { - loggableTypes.push_back(Type(HeapType::cont, Nullable)); - } - if (wasm.features.hasExceptionHandling()) { - loggableTypes.push_back(Type(HeapType::exn, Nullable)); + if (wasm.features.hasReferenceTypes()) { + if (wasm.features.hasGC()) { + loggableTypes.push_back(Type(HeapType::any, Nullable)); + loggableTypes.push_back(Type(HeapType::func, Nullable)); + loggableTypes.push_back(Type(HeapType::ext, Nullable)); + } + if (wasm.features.hasStackSwitching()) { + loggableTypes.push_back(Type(HeapType::cont, Nullable)); + } + if (wasm.features.hasExceptionHandling()) { + loggableTypes.push_back(Type(HeapType::exn, Nullable)); + } } // Setup params. Start with the defaults. From 2b6c1a7c981cf371e8684e458c3484ad37c17b50 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 10 Feb 2026 15:37:30 -0800 Subject: [PATCH 09/11] finish --- scripts/fuzz_shell.js | 6 +- ...e-to-fuzz_all-features_metrics_noprint.txt | 80 ++++++++++--------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 315a971b863..78cf12ed20b 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -164,10 +164,8 @@ function logValue(x, y) { } function logRef(ref) { - // Look for VM bugs by doing some basic operations on the reference: - // first, convert it to various things. - //+ref; // traps - //ref + ''; // traps + // Look for VM bugs by using the reference in an API (note: we cannot do + // +ref or ref+'' as those trap). JSON.stringify(ref); // If not null, try to read a property, which might exercise an // interesting code path. diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt index 22715bcf9c3..e47ca556bf2 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,49 +1,53 @@ Metrics total - [exports] : 15 - [funcs] : 13 + [exports] : 12 + [funcs] : 8 [globals] : 26 - [imports] : 10 + [imports] : 15 [memories] : 1 [memory-data] : 16 - [table-data] : 5 + [table-data] : 2 [tables] : 2 [tags] : 1 - [total] : 459 - [vars] : 50 - ArrayNewFixed : 9 - AtomicCmpxchg : 1 - AtomicNotify : 1 - Binary : 25 - Block : 68 - Break : 2 - Call : 14 + [total] : 429 + [vars] : 38 + ArrayNewFixed : 10 + AtomicRMW : 1 + Binary : 18 + Block : 65 + BrOn : 3 + Break : 8 + Call : 13 CallIndirect : 2 - CallRef : 1 - Const : 104 - Drop : 2 - GlobalGet : 44 - GlobalSet : 32 - If : 21 - Load : 5 - LocalGet : 15 - LocalSet : 7 - Loop : 3 + CallRef : 2 + Const : 86 + ContNew : 1 + Drop : 5 + GlobalGet : 33 + GlobalSet : 24 + If : 19 + Load : 3 + LocalGet : 19 + LocalSet : 14 + Loop : 4 + MemoryInit : 1 Nop : 6 - Pop : 3 - RefEq : 2 + Pop : 2 + RefAs : 2 + RefCast : 2 + RefEq : 4 RefFunc : 8 - RefI31 : 1 - RefNull : 3 - Return : 7 - SIMDExtract : 3 - Select : 1 - StringConst : 6 - StringMeasure : 2 - StructNew : 4 + RefI31 : 7 + RefIsNull : 1 + RefNull : 6 + Return : 1 + SIMDExtract : 1 + Select : 2 + Store : 1 + StructNew : 5 + Throw : 2 Try : 3 - TryTable : 3 - TupleExtract : 1 - TupleMake : 11 - Unary : 23 - Unreachable : 16 + TryTable : 6 + TupleMake : 7 + Unary : 20 + Unreachable : 12 From da9bfb8b6e0cc2cd05c6160f4ee19a51a89bb34b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 11 Feb 2026 10:26:19 -0800 Subject: [PATCH 10/11] remove exn --- scripts/fuzz_shell.js | 1 - src/tools/fuzzing/fuzzing.cpp | 4 +--- test/lit/exec/fuzzing-api.wast | 4 ---- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 78cf12ed20b..e16dcdd00c9 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -307,7 +307,6 @@ var imports = { 'log-funcref': logRef, 'log-contref': logRef, 'log-externref': logRef, - 'log-exnref': logRef, // Throw an exception from JS. 'throw': (which) => { diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index cdd0b041c28..dc2ea3b90e5 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -59,9 +59,7 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, if (wasm.features.hasStackSwitching()) { loggableTypes.push_back(Type(HeapType::cont, Nullable)); } - if (wasm.features.hasExceptionHandling()) { - loggableTypes.push_back(Type(HeapType::exn, Nullable)); - } + // Note: exnref traps on the JS boundary, so we cannot try to log it. } // Setup params. Start with the defaults. diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index 8dd3c4dc772..b40ea5db0c7 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -10,7 +10,6 @@ (import "fuzzing-support" "log-anyref" (func $log-anyref (param anyref))) (import "fuzzing-support" "log-funcref" (func $log-funcref (param funcref))) (import "fuzzing-support" "log-contref" (func $log-contref (param contref))) - (import "fuzzing-support" "log-exnref" (func $log-exnref (param exnref))) (import "fuzzing-support" "log-externref" (func $log-externref (param externref))) (import "fuzzing-support" "throw" (func $throw (param i32))) @@ -69,9 +68,6 @@ (call $log-contref (ref.null cont) ) - (call $log-exnref - (ref.null exn) - ) (call $log-externref (ref.null extern) ) From 0778bebfe24c9253ae6d0b575300dd88dd60b924 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 11 Feb 2026 10:27:14 -0800 Subject: [PATCH 11/11] update ocmment --- src/tools/fuzzing/fuzzing.cpp | 4 - test/lit/exec/fuzzing-api.wast | 14 ---- ...e-to-fuzz_all-features_metrics_noprint.txt | 77 ++++++++++--------- 3 files changed, 39 insertions(+), 56 deletions(-) diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index dc2ea3b90e5..aa16e2b7833 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -42,10 +42,6 @@ TranslateToFuzzReader::TranslateToFuzzReader(Module& wasm, haveInitialFunctions = !wasm.functions.empty(); - // - funcref cannot be logged because referenced functions can be inlined or - // removed during optimization - // - there's no point in logging anyref because it is opaque - // - don't bother logging tuples loggableTypes = {Type::i32, Type::i64, Type::f32, Type::f64}; if (wasm.features.hasSIMD()) { loggableTypes.push_back(Type::v128); diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index b40ea5db0c7..ef34fc61df8 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -44,7 +44,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [LoggingExternalInterface logging null] (func $logging (export "logging") (call $log-i32 (i32.const 42) @@ -141,7 +140,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $export.calling (export "export.calling") ;; At index 0 in the exports we have $logging, so we will do those loggings. @@ -165,7 +163,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $export.calling.rethrow (export "export.calling.rethrow") ;; As above, but the second param is different. @@ -190,7 +187,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $export.calling.catching (export "export.calling.catching") @@ -217,7 +213,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $ref.calling (export "ref.calling") ;; This will emit some logging. @@ -241,7 +236,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] (func $ref.calling.rethrow (export "ref.calling.rethrow") ;; As with calling an export, when we set the flags to 1 exceptions are @@ -265,7 +259,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] (func $ref.calling.catching (export "ref.calling.catching") @@ -481,7 +474,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK: [fuzz-exec] calling throwing ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] @@ -505,7 +497,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling export.calling.rethrow @@ -516,7 +507,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling export.calling.catching @@ -527,7 +517,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] @@ -539,7 +528,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling ref.calling.rethrow @@ -550,7 +538,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [exception thrown: imported-js-tag externref] ;; CHECK: [fuzz-exec] calling ref.calling.catching @@ -561,7 +548,6 @@ ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt index e47ca556bf2..dc3c5e52c93 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -3,51 +3,52 @@ total [exports] : 12 [funcs] : 8 [globals] : 26 - [imports] : 15 + [imports] : 14 [memories] : 1 [memory-data] : 16 [table-data] : 2 [tables] : 2 [tags] : 1 - [total] : 429 + [total] : 581 [vars] : 38 ArrayNewFixed : 10 - AtomicRMW : 1 - Binary : 18 - Block : 65 - BrOn : 3 - Break : 8 - Call : 13 - CallIndirect : 2 - CallRef : 2 - Const : 86 + AtomicCmpxchg : 1 + Binary : 28 + Block : 86 + BrOn : 2 + Break : 10 + Call : 21 + CallIndirect : 1 + CallRef : 1 + Const : 105 ContNew : 1 - Drop : 5 - GlobalGet : 33 - GlobalSet : 24 - If : 19 - Load : 3 - LocalGet : 19 - LocalSet : 14 - Loop : 4 - MemoryInit : 1 - Nop : 6 + DataDrop : 1 + Drop : 3 + GlobalGet : 44 + GlobalSet : 34 + If : 25 + Load : 7 + LocalGet : 30 + LocalSet : 18 + Loop : 9 + Nop : 9 Pop : 2 - RefAs : 2 - RefCast : 2 - RefEq : 4 - RefFunc : 8 - RefI31 : 7 - RefIsNull : 1 - RefNull : 6 - Return : 1 - SIMDExtract : 1 - Select : 2 - Store : 1 - StructNew : 5 - Throw : 2 + RefAs : 5 + RefCast : 5 + RefEq : 3 + RefFunc : 6 + RefI31 : 4 + RefNull : 10 + Return : 2 + SIMDExtract : 2 + Select : 5 + StringConst : 6 + StringEncode : 1 + StringWTF16Get : 1 + StructNew : 6 Try : 3 - TryTable : 6 - TupleMake : 7 - Unary : 20 - Unreachable : 12 + TryTable : 9 + TupleExtract : 8 + TupleMake : 12 + Unary : 28 + Unreachable : 17