Skip to content

Commit

Permalink
feat: Show the URL of streaming WASM modules in stack traces
Browse files Browse the repository at this point in the history
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://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.

Closes denoland#12151.
  • Loading branch information
Andreu Botella committed Sep 29, 2021
1 parent 3ab6829 commit 4d0e399
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 9 deletions.
8 changes: 2 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions cli/tests/integration/run_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,12 @@ itest!(wasm_unreachable {
exit_code: 1,
});

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

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.
2 changes: 2 additions & 0 deletions cli/tests/testdata/wasm_unreachable.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,6 @@ const binary = Uint8Array.from([
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();
2 changes: 1 addition & 1 deletion 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://wasm/[WILDCARD])
at <anonymous> (wasm://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("http://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> (http://localhost:4545/unreachable.wasm:1:41)
at [WILDCARD]/wasm_url.js:[WILDCARD]
4 changes: 2 additions & 2 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ lazy_static = "1.4.0"
log = "0.4.14"
parking_lot = "0.11.1"
pin-project = "1.0.7"
rusty_v8 = "0.30.0"
rusty_v8 = { version = "0.31.0", path = "../../rusty_v8" }
serde = { version = "1.0.129", features = ["derive"] }
serde_json = { version = "1.0.66", features = ["preserve_order"] }
serde_v8 = "0.13.0"
serde_v8 = { version = "0.14.0", path = "../../serde_v8" }
url = { version = "2.2.2", features = ["serde"] }

[[example]]
Expand Down
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 4d0e399

Please sign in to comment.