Skip to content

Commit

Permalink
feat: Show the URL of streaming WASM modules in stack traces (denolan…
Browse files Browse the repository at this point in the history
…d#12268)

WebAssembly modules compiled through `WebAssembly.compile()` and similar
non-streaming APIs don't have a URL associated to them, because they
have been compiled from a buffer source. In stack traces, V8 will use
a URL such as `wasm:https://wasm/d1c677ea`, with a hash of the module.

However, wasm modules compiled through streaming APIs, like
`WebAssembly.compileStreaming()`, do have a known URL, which can be
obtained from the `Response` object passed into the streaming APIs. And
as per the developer-facing display conventions in the WebAssembly
Web API spec, this URL should be used in stack traces. This change
implements that.
  • Loading branch information
Andreu Botella committed Oct 10, 2021
1 parent 6ac0337 commit 5edd277
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 47 deletions.
9 changes: 8 additions & 1 deletion cli/tests/integration/run_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -856,11 +856,18 @@ itest!(wasm_async {
});

itest!(wasm_unreachable {
args: "run wasm_unreachable.js",
args: "run --allow-read wasm_unreachable.js",
output: "wasm_unreachable.out",
exit_code: 1,
});

itest!(wasm_url {
args: "run --quiet --allow-net=localhost:4545 wasm_url.js",
output: "wasm_url.out",
exit_code: 1,
http_server: true,
});

itest!(weakref {
args: "run --quiet --reload weakref.ts",
output: "weakref.ts.out",
Expand Down
Binary file added cli/tests/testdata/unreachable.wasm
Binary file not shown.
47 changes: 3 additions & 44 deletions cli/tests/testdata/wasm_unreachable.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,9 @@
// WebAssembly module containing a single function with an unreachable instruction
const binary = Uint8Array.from([
0x00,
0x61,
0x73,
0x6d,
0x01,
0x00,
0x00,
0x00,
0x01,
0x04,
0x01,
0x60,
0x00,
0x00,
0x03,
0x02,
0x01,
0x00,
0x07,
0x0f,
0x01,
0x0b,
0x75,
0x6e,
0x72,
0x65,
0x61,
0x63,
0x68,
0x61,
0x62,
0x6c,
0x65,
0x00,
0x00,
0x0a,
0x05,
0x01,
0x03,
0x00,
0x00,
0x0b,
]);
const binary = await Deno.readFile("./unreachable.wasm");

const module = new WebAssembly.Module(binary);
const instance = new WebAssembly.Instance(module);

// Compare the stack trace with wasm_url.js, which compiles the WASM module with
// streaming APIs.
instance.exports.unreachable();
4 changes: 2 additions & 2 deletions cli/tests/testdata/wasm_unreachable.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
error: Uncaught RuntimeError: unreachable
at <anonymous> (wasm:https://wasm/[WILDCARD])
error: Uncaught (in promise) RuntimeError: unreachable
at <anonymous> (wasm:https://wasm/d1c677ea:1:41)
at [WILDCARD]/wasm_unreachable.js:[WILDCARD]
8 changes: 8 additions & 0 deletions cli/tests/testdata/wasm_url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const module = await WebAssembly.compileStreaming(
fetch("https://localhost:4545/unreachable.wasm"),
);
const instance = new WebAssembly.Instance(module);

// Compare the stack trace with wasm_unreachable.js, which compiles the WASM
// module with synchronous APIs.
instance.exports.unreachable();
3 changes: 3 additions & 0 deletions cli/tests/testdata/wasm_url.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
error: Uncaught (in promise) RuntimeError: unreachable
at <anonymous> (https://localhost:4545/unreachable.wasm:1:41)
at [WILDCARD]/wasm_url.js:[WILDCARD]
2 changes: 2 additions & 0 deletions core/lib.deno_core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ declare namespace Deno {
* compiler. Takes the rid and a `Uint8Array`.
* - `op_wasm_streaming_abort`. Aborts the wasm compilation. Takes the rid
* and an exception. Invalidates the resource.
* - `op_wasm_streaming_set_url`. Sets a source URL for the wasm module.
* Takes the rid and a string.
* - To indicate the end of the resource, use `Deno.core.close()` with the
* rid.
*/
Expand Down
17 changes: 17 additions & 0 deletions core/ops_builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ pub(crate) fn init_builtins() -> Extension {
("op_resources", op_sync(op_resources)),
("op_wasm_streaming_feed", op_sync(op_wasm_streaming_feed)),
("op_wasm_streaming_abort", op_sync(op_wasm_streaming_abort)),
(
"op_wasm_streaming_set_url",
op_sync(op_wasm_streaming_set_url),
),
])
.build()
}
Expand Down Expand Up @@ -137,3 +141,16 @@ pub fn op_wasm_streaming_abort(

Ok(())
}

pub fn op_wasm_streaming_set_url(
state: &mut OpState,
rid: ResourceId,
url: String,
) -> Result<(), AnyError> {
let wasm_streaming =
state.resource_table.get::<WasmStreamingResource>(rid)?;

wasm_streaming.0.borrow_mut().set_url(&url);

Ok(())
}
3 changes: 3 additions & 0 deletions ext/fetch/26_fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,9 @@
throw new TypeError(`HTTP status code ${res.status}`);
}

// Pass the resolved URL to v8.
core.opSync("op_wasm_streaming_set_url", rid, res.url);

// 2.6.
// Rather than consuming the body as an ArrayBuffer, this passes each
// chunk to the feed as soon as it's available.
Expand Down

0 comments on commit 5edd277

Please sign in to comment.