diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 59cc992eb29..28f5e2f44fb 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -144,16 +144,29 @@ function printed(x, y) { // Print bigints in legalized form, which is two 32-bit numbers of the low // and high bits. return (Number(x & 0xffffffffn) | 0) + ' ' + (Number(x >> 32n) | 0) - } else if (typeof x !== 'number') { - // Something that is not a number or string, like a reference. We can't - // print a reference because it could look different after opts - imagine - // that a function gets renamed internally (that is, the problem is that - // JS printing will emit some info about the reference and not a stable - // external representation of it). In those cases just print the type, - // which will be 'object' or 'function'. - return typeof x; + } else if (typeof x === 'object') { + // This may be one of the externref imports, in which case we can print its + // payload. + if (Object.hasOwn(x, 'payload')) { + return 'externref(' + x.payload + ')'; + } + // Or maybe this is a JS error we caught. + if (x instanceof Error) { + return 'jserror'; + } + // If this is a Wasm object, we can't access its type or any of its + // internal structure, which might have been changed by optimizations + // anyway. It might have a configured prototype, though, and that + // prototype may be an imported externref global we can identify by the + // payload we gave it. + return 'object(' + printed(Object.getPrototypeOf(x)) + ')'; + } else if (typeof x === 'function') { + // We cannot print function names because they might have been changed by + // optimizations. + return 'function'; } else { // A number. Print the whole thing. + assert(typeof x === 'number'); return '' + x; } } @@ -469,8 +482,15 @@ function makeImports(module) { baseImports[module] = {}; } if (!baseImports[module][name]) { - // TODO: Use different payloads for different imports. - baseImports[module][name] = {}; + // Compute a payload from the import names. This must be kept in sync + // with execution-results.h. + var payload = 0; + for (var name of [module, name]) { + for (var c of name) { + payload = (payload + c.charCodeAt(0)) % 251; + } + } + baseImports[module][name] = { payload }; } } } diff --git a/src/literal.h b/src/literal.h index 9eb27177d75..21ff1c19688 100644 --- a/src/literal.h +++ b/src/literal.h @@ -737,6 +737,14 @@ class Literal { Literal externalize() const; Literal internalize() const; + // Internalize an externalized value or externalize an internalized value, + // otherwise return the literal unmodified. + Literal unwrap() const; + + // Get the JS prototype configured via this struct's descriptor, if it exists, + // or null. Assumes this is a reference value. + Literal getJSPrototype() const; + private: Literal addSatSI8(const Literal& other) const; Literal addSatUI8(const Literal& other) const; diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index 58613a66aaf..fb618500109 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -21,6 +21,7 @@ #include #include +#include "ir/import-names.h" #include "ir/import-utils.h" #include "shell-interface.h" #include "support/utilities.h" @@ -58,20 +59,9 @@ 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(); - } +constexpr Index jsErrorPayload = 0xbad; +void printValue(Literal value) { // 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 @@ -81,22 +71,32 @@ void printValue(Literal value) { // // 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"; - } + // + // Non-references can be printed in full. + if (!value.type.isRef()) { + std::cout << value; return; } - - // Non-references can be printed in full. - std::cout << value; + value = value.unwrap(); + auto heapType = value.type.getHeapType(); + if (heapType.isMaybeShared(HeapType::ext) && + value.getExternPayload() == jsErrorPayload) { + std::cout << "jserror"; + return; + } + if (heapType.isString() || heapType.isMaybeShared(HeapType::ext) || + heapType.isMaybeShared(HeapType::i31)) { + std::cout << value; + } else if (value.isNull()) { + std::cout << "null"; + } else if (heapType.isFunction()) { + std::cout << "function"; + } else { + // Print 'object' and its JS-visible prototype, which may be null. + std::cout << "object("; + printValue(value.getJSPrototype()); + std::cout << ')'; + } } } // namespace @@ -275,7 +275,7 @@ struct LoggingExternalInterface : public ShellExternalInterface { void throwJSException() { // JS exceptions contain an externref. - Literals arguments = {Literal::makeExtern(0, Unshared)}; + Literals arguments = {Literal::makeExtern(jsErrorPayload, Unshared)}; auto payload = std::make_shared(&jsTag, arguments); throwException(WasmException{Literal(payload)}); } @@ -403,8 +403,18 @@ class FuzzerImportResolver if (mut || !type.isRef() || type.getHeapType() != HeapType::ext) { return nullptr; } - // TODO: Generate a distinct payload for each global. - synthesizedGlobals.emplace_back(Literals{Literal::makeExtern(0, Unshared)}); + // Optimizations may reorder or remove imports, so we need a distinct + // payload that is independent of the import order. Just compute a simple + // payload integer from the import names. This must be kept in sync with + // fuzz_shell.js. + Index payload = 0; + for (auto name : {name.module, name.name}) { + for (auto c : name.str) { + payload = (payload + static_cast(c)) % 251; + } + } + synthesizedGlobals.emplace_back( + Literals{Literal::makeExtern(payload, Unshared)}); return &synthesizedGlobals.back(); } @@ -527,28 +537,56 @@ struct ExecutionResults { } bool areEqual(Literal a, Literal b) { - // Don't compare references. There are several issues here that we can't - // fully handle, see https://github.com/WebAssembly/binaryen/issues/3378, - // but the core issue is that since we optimize assuming a closed world, the - // types and structure of GC data can arbitrarily change after - // optimizations, even in ways that are externally visible from outside - // the module. - // - // We can, however, compare strings as they refer to simple data that has a - // consistent representation (the same reasons as why we can print them in - // printValue(), above). + // Only compare some references. In general the optimizer may change + // identities and structures of functions, types, and GC values in ways that + // are not externally observable. We must therefore limit ourselves to + // comparing information that _is_ externally observable. // - // TODO: Once we support optimizing under some form of open-world - // assumption, we should be able to check that the types and/or structure of - // GC data passed out of the module does not change. - if (a.type.isRef() && !a.type.isString() && - !a.type.getHeapType().isMaybeShared(HeapType::i31)) { - return true; + // TODO: We could compare more information when we know it will be + // externally visible, for example when the type of the value is public. + if (!a.type.isRef() || !b.type.isRef()) { + return a == b; + } + // The environment always sees externalized references and is able to + // observe the difference between external references and externalized + // internal references. Make sure this is accounted for below by unwrapping + // the references. + a = a.unwrap(); + b = b.unwrap(); + auto htA = a.type.getHeapType(); + auto htB = b.type.getHeapType(); + // What type hierarchy a heap type is in is generally observable. + if (htA.getTop() != htB.getTop()) { + return false; } - if (a != b) { - std::cout << "values not identical! " << a << " != " << b << '\n'; + // Null values are observable. + if (htA.isBottom() || htB.isBottom()) { + return a == b; + } + // String values are observable. + if (htA.isString() || htB.isString()) { + return a == b; + } + // i31 values are observable. + if (htA.isMaybeShared(HeapType::i31) || htB.isMaybeShared(HeapType::i31)) { + return a == b; + } + // External references are observable. (These cannot be externalized + // internal references because they've already been unwrapped.) + if (htA.isMaybeShared(HeapType::ext) || htB.isMaybeShared(HeapType::ext)) { + return a == b; + } + // Configured prototypes are observable. Even if they are also opaque Wasm + // references, their having different pointer identities is observable. + // However, we have no way of comparing pointer identities across + // executions, so just recursively look for externally observable + // differences in the prototypes. + if (!areEqual(a.getJSPrototype(), b.getJSPrototype())) { return false; } + + // Other differences are not observable, so conservatively consider the + // values equal. return true; } @@ -559,6 +597,7 @@ struct ExecutionResults { } for (Index i = 0; i < a.size(); i++) { if (!areEqual(a[i], b[i])) { + std::cout << "values not identical! " << a[i] << " != " << b[i] << '\n'; return false; } } @@ -628,7 +667,13 @@ struct ExecutionResults { } catch (const TrapException&) { return Trap{}; } catch (const WasmException& e) { - std::cout << "[exception thrown: " << e << "]" << std::endl; + auto& exn = *e.exn.getExnData(); + std::cout << "[exception thrown: " << exn.tag->name; + for (auto val : exn.payload) { + std::cout << ' '; + printValue(val); + } + std::cout << "]" << std::endl; return Exception{}; } catch (const HostLimitException&) { // This should be ignored and not compared with, as optimizations can diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 9b2800a2d84..749b703bc1a 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -467,7 +467,11 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { void throwException(const WasmException& exn) override { std::stringstream ss; - ss << "exception thrown: " << exn; + auto& data = *exn.exn.getExnData(); + ss << "exception thrown: " << data.tag->name; + if (!data.payload.empty()) { + ss << ' ' << data.payload; + } throw FailToEvalException(ss.str()); } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 2b397dd1672..d7dae5c59ab 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -61,7 +61,6 @@ namespace wasm { struct WasmException { Literal exn; }; -std::ostream& operator<<(std::ostream& o, const WasmException& exn); // An exception thrown when we try to execute non-constant code, that is, code // that we cannot properly evaluate at compile time (e.g. if it refers to an diff --git a/src/wasm/CMakeLists.txt b/src/wasm/CMakeLists.txt index 07e067c49b8..0f4002cd6e4 100644 --- a/src/wasm/CMakeLists.txt +++ b/src/wasm/CMakeLists.txt @@ -7,7 +7,6 @@ set(wasm_SOURCES wasm-binary.cpp wasm-debug.cpp wasm-emscripten.cpp - wasm-interpreter.cpp wasm-io.cpp wasm-ir-builder.cpp wasm-stack.cpp diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index fd3c7fc0f0f..580722fc899 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -19,6 +19,7 @@ #include "emscripten-optimizer/simple_ast.h" #include "ir/bits.h" +#include "ir/js-utils.h" #include "literal.h" #include "pretty_printing.h" #include "support/bits.h" @@ -514,6 +515,12 @@ bool Literal::operator==(const Literal& other) const { return i32 == other.i32; } if (heapType.isMaybeShared(HeapType::ext)) { + if (hasExternPayload()) { + if (!other.hasExternPayload()) { + return false; + } + return getExternPayload() == other.getExternPayload(); + } return internalize() == other.internalize(); } if (heapType.isMaybeShared(HeapType::any)) { @@ -782,7 +789,14 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { assert(literal.isData()); auto data = literal.getGCData(); assert(data); - o << "[ref " << literal.type.getHeapType() << ' ' << data->values << ']'; + o << "[ref " << literal.type.getHeapType() << ' ' << data->values; + if (!data->desc.isNull()) { + if (!data->values.empty()) { + o << ", "; + } + o << "desc=" << data->desc; + } + o << ']'; } } restoreNormalColor(o); @@ -3009,4 +3023,37 @@ Literal Literal::internalize() const { return gcData->values[0]; } +Literal Literal::unwrap() const { + if (!type.isRef()) { + return *this; + } + if (type.getHeapType().isMaybeShared(HeapType::any)) { + // An internalized external reference (possibly a string). + return externalize(); + } + if (type.getHeapType().isMaybeShared(HeapType::ext) && !hasExternPayload()) { + // An externalized internal reference. + return internalize(); + } + // Something other reference that is not wrapped. + return *this; +} + +Literal Literal::getJSPrototype() const { + assert(type.isRef()); + if (auto desc = type.getHeapType().getDescriptorType(); + desc && JSUtils::hasPossibleJSPrototypeField(*desc)) { + auto proto = gcData->desc.getGCData()->values[0].unwrap(); + // Strings and numbers are not valid prototypes, so they appear as null. + // Externref nulls are also converted to nullref. + auto protoType = proto.type.getHeapType(); + if (protoType.isMaybeShared(HeapType::i31) || + protoType.isMaybeShared(HeapType::string) || protoType.isBottom()) { + return Literal::makeNull(HeapType::none); + } + return proto; + } + return Literal::makeNull(HeapType::none); +} + } // namespace wasm diff --git a/src/wasm/wasm-interpreter.cpp b/src/wasm/wasm-interpreter.cpp deleted file mode 100644 index 3af29d2c773..00000000000 --- a/src/wasm/wasm-interpreter.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "wasm-interpreter.h" - -namespace wasm { - -std::ostream& operator<<(std::ostream& o, const WasmException& exn) { - auto exnData = exn.exn.getExnData(); - return o << exnData->tag->name << " " << exnData->payload; -} - -} // namespace wasm diff --git a/test/lit/array-multibyte.wast b/test/lit/array-multibyte.wast index cdeda331bae..1b56a338c54 100644 --- a/test/lit/array-multibyte.wast +++ b/test/lit/array-multibyte.wast @@ -7,13 +7,13 @@ ;; RUN: wasm-opt %s -all -S -o - | wasm-opt -all -S -o - (module + ;; CHECK: (type $0 (func)) ;; CHECK: (type $i8_array (array (mut i8))) ;; RTRIP: (type $0 (func)) ;; RTRIP: (type $i8_array (array (mut i8))) - (type $i8_array (array (mut i8))) ;; CHECK: (global $arr (ref $i8_array) (array.new_default $i8_array diff --git a/test/lit/exec/cont_many_unhandled.wast b/test/lit/exec/cont_many_unhandled.wast index 18d5ad98c0d..8424599faa5 100644 --- a/test/lit/exec/cont_many_unhandled.wast +++ b/test/lit/exec/cont_many_unhandled.wast @@ -16,7 +16,7 @@ ) ;; CHECK: [fuzz-exec] export a - ;; CHECK-NEXT: [exception thrown: tag ()] + ;; CHECK-NEXT: [exception thrown: tag] (func $a (export "a") (resume_throw $cont $tag (cont.new $cont diff --git a/test/lit/exec/eh-print.wast b/test/lit/exec/eh-print.wast index c8ff0d0ffec..b8ecacd7918 100644 --- a/test/lit/exec/eh-print.wast +++ b/test/lit/exec/eh-print.wast @@ -11,11 +11,11 @@ (type $B (struct (field (mut anyref)))) ;; CHECK: [fuzz-exec] export array - ;; CHECK-NEXT: [exception thrown: A [ref (type $array.0 (array (mut i32))) (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0[..])]] + ;; CHECK-NEXT: [exception thrown: A object(null)] (func $array (export "array") (result (ref $A)) ;; Throw a very large array. We should not print all 12K items in it, as that - ;; would be very verbose. Instead we stop after a reasonable amount and - ;; print [..] for the rest. + ;; would be very verbose. Instead we print exactly what fuzz_shel.js would + ;; print. (throw $A (array.new_default $A (i32.const 12345) @@ -24,7 +24,7 @@ ) ;; CHECK: [fuzz-exec] export struct - ;; CHECK-NEXT: [exception thrown: B [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [ref (type $struct.0 (struct (field (mut anyref)))) [..]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] + ;; CHECK-NEXT: [exception thrown: B object(null)] (func $struct (export "struct") (result (ref $B)) (local $x (ref $B)) ;; As above, but now with a recursive struct. diff --git a/test/lit/exec/fuzzing-api-globals.wast b/test/lit/exec/fuzzing-api-globals.wast index 8db04320569..6141cab985a 100644 --- a/test/lit/exec/fuzzing-api-globals.wast +++ b/test/lit/exec/fuzzing-api-globals.wast @@ -18,7 +18,7 @@ ;; CHECK: [fuzz-exec] export global ;; CHECK-NEXT: [LoggingExternalInterface logging 42] ;; CHECK-NEXT: [fuzz-exec] export global-immref -;; CHECK-NEXT: [LoggingExternalInterface logging object] +;; CHECK-NEXT: [LoggingExternalInterface logging object(null)] ;; CHECK-NEXT: [fuzz-exec] export global-v128 ;; CHECK-NEXT: [LoggingExternalInterface logging i32x4 0x0000000c 0x00000000 0x00000022 0x00000000] diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast index c02728106dc..eb3088b5f0d 100644 --- a/test/lit/exec/fuzzing-api.wast +++ b/test/lit/exec/fuzzing-api.wast @@ -39,7 +39,7 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] (func $logging (export "logging") @@ -68,7 +68,7 @@ ) ;; CHECK: [fuzz-exec] export throwing - ;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] + ;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] (func $throwing (export "throwing") ;; Throwing 0 throws a JS ("private") exception. (call $throw @@ -86,7 +86,7 @@ ) ;; CHECK: [fuzz-exec] export table.setting - ;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] + ;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] (func $table.setting (export "table.setting") (call $table.set (i32.const 5) @@ -102,7 +102,7 @@ ;; CHECK: [fuzz-exec] export table.getting ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] - ;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] + ;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] (func $table.getting (export "table.getting") ;; There is a non-null value at 5, and a null at 6. (call $log-i32 @@ -131,10 +131,10 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] + ;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] (func $export.calling (export "export.calling") ;; At index 0 in the exports we have $logging, so we will do those loggings. (call $call.export @@ -153,10 +153,10 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] + ;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] (func $export.calling.rethrow (export "export.calling.rethrow") ;; As above, but the second param is different. (call $call.export @@ -176,7 +176,7 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] @@ -201,10 +201,10 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] + ;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] (func $ref.calling (export "ref.calling") ;; This will emit some logging. (call $call.ref @@ -223,10 +223,10 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] - ;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] + ;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] (func $ref.calling.rethrow (export "ref.calling.rethrow") ;; As with calling an export, when we set the flags to 1 exceptions are ;; caught and rethrown, but there is no noticeable difference here. @@ -245,7 +245,7 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] @@ -481,7 +481,7 @@ ) ;; CHECK: [fuzz-exec] export return-externref-exception - ;; CHECK-NEXT: [fuzz-exec] note result: return-externref-exception => object + ;; CHECK-NEXT: [fuzz-exec] note result: return-externref-exception => jserror ;; CHECK-NEXT: warning: no passes specified, not doing any work (func $return-externref-exception (export "return-externref-exception") (result externref) ;; Call JS table.set in a way that throws (on out of bounds). The JS exception @@ -502,47 +502,47 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK: [fuzz-exec] export throwing -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] export throwing-tag ;; CHECK-NEXT: [exception thrown: imported-wasm-tag 42] ;; CHECK: [fuzz-exec] export table.setting -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] export table.getting ;; CHECK-NEXT: [LoggingExternalInterface logging 0] ;; CHECK-NEXT: [LoggingExternalInterface logging 1] -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] export 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] export 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] export 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] @@ -552,25 +552,25 @@ ;; 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] export 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] export 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 object(null)] ;; CHECK-NEXT: [LoggingExternalInterface logging function] ;; CHECK-NEXT: [LoggingExternalInterface logging null] ;; CHECK-NEXT: [LoggingExternalInterface logging 0] @@ -612,7 +612,7 @@ ;; CHECK-NEXT: [fuzz-exec] note result: do-sleep => 42 ;; CHECK: [fuzz-exec] export return-externref-exception -;; CHECK-NEXT: [fuzz-exec] note result: return-externref-exception => object +;; CHECK-NEXT: [fuzz-exec] note result: return-externref-exception => jserror ;; CHECK-NEXT: [fuzz-exec] comparing catch-js-tag ;; CHECK-NEXT: [fuzz-exec] comparing do-sleep ;; CHECK-NEXT: [fuzz-exec] comparing export.calling diff --git a/test/lit/exec/tag-cross-module.wast b/test/lit/exec/tag-cross-module.wast index 37a390144ea..a6aaf73b25f 100644 --- a/test/lit/exec/tag-cross-module.wast +++ b/test/lit/exec/tag-cross-module.wast @@ -17,10 +17,10 @@ ) ;; CHECK: [fuzz-exec] export func -;; CHECK-NEXT: [exception thrown: tag nullref] +;; CHECK-NEXT: [exception thrown: tag null] ;; CHECK-NEXT: [fuzz-exec] running second module ;; CHECK-NEXT: [fuzz-exec] export func2-internal -;; CHECK-NEXT: [exception thrown: tag nullref] +;; CHECK-NEXT: [exception thrown: tag null] ;; CHECK-NEXT: [fuzz-exec] export func2-imported ;; CHECK-NEXT: func2-imported => null