diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 745cae7337c..44107a9050d 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; } } @@ -468,8 +481,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 96f67ee196d..b27404bcd87 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(); } @@ -518,28 +528,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 unrapping + // 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; } @@ -550,6 +588,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; } } @@ -619,7 +658,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 5e6b0cb3e51..76938bd3e8d 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 1bf14432c90..5b3fcb7a177 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/struct-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 && StructUtils::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/exec/cont_many_unhandled.wast b/test/lit/exec/cont_many_unhandled.wast index 6bb71c6eb16..bc221315ef0 100644 --- a/test/lit/exec/cont_many_unhandled.wast +++ b/test/lit/exec/cont_many_unhandled.wast @@ -16,7 +16,7 @@ ) ;; CHECK: [fuzz-exec] calling 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 f501646313f..24edab11946 100644 --- a/test/lit/exec/eh-print.wast +++ b/test/lit/exec/eh-print.wast @@ -11,7 +11,7 @@ (type $B (struct (field (mut anyref)))) ;; CHECK: [fuzz-exec] calling 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 @@ -24,7 +24,7 @@ ) ;; CHECK: [fuzz-exec] calling 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.wast b/test/lit/exec/fuzzing-api.wast index ee394ec5bfb..9cde86db162 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] calling 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] calling 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] calling 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] calling 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] calling throwing -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] calling throwing-tag ;; CHECK-NEXT: [exception thrown: imported-wasm-tag 42] ;; CHECK: [fuzz-exec] calling table.setting -;; CHECK-NEXT: [exception thrown: imported-js-tag externref(0)] +;; CHECK-NEXT: [exception thrown: imported-js-tag jserror] ;; CHECK: [fuzz-exec] calling 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] 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 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] 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 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] 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 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] 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 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] 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 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] calling 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 0bb17c97fee..e0c31b848bf 100644 --- a/test/lit/exec/tag-cross-module.wast +++ b/test/lit/exec/tag-cross-module.wast @@ -17,10 +17,10 @@ ) ;; CHECK: [fuzz-exec] calling func -;; CHECK-NEXT: [exception thrown: tag nullref] +;; CHECK-NEXT: [exception thrown: tag null] ;; CHECK-NEXT: [fuzz-exec] running second module ;; CHECK-NEXT: [fuzz-exec] calling func2-internal -;; CHECK-NEXT: [exception thrown: tag nullref] +;; CHECK-NEXT: [exception thrown: tag null] ;; CHECK-NEXT: [fuzz-exec] calling func2-imported ;; CHECK-NEXT: func2-imported => null