mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-03-09 21:47:00 -04:00
feat: v8::Module::get_stalled_top_level_await_message (#1123)
This commit adds "v8::Module::get_stalled_top_level_await_message" API that allows to retrieve a vector of tuples with handles to v8::Module and v8::Message. This information can be used to display a nice error when event loop runs out of work to do but there are still unresolved promises.
This commit is contained in:
parent
cc7183d09f
commit
3d30e7cc82
3 changed files with 132 additions and 0 deletions
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
|
@ -2690,6 +2691,26 @@ const v8::UnboundModuleScript* v8__Module__GetUnboundModuleScript(
|
||||||
return local_to_ptr(ptr_to_local(&self)->GetUnboundModuleScript());
|
return local_to_ptr(ptr_to_local(&self)->GetUnboundModuleScript());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StalledTopLevelAwaitMessage {
|
||||||
|
const v8::Module* module;
|
||||||
|
const v8::Message* message;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
size_t v8__Module__GetStalledTopLevelAwaitMessage(
|
||||||
|
const v8::Module& self, v8::Isolate* isolate,
|
||||||
|
StalledTopLevelAwaitMessage* out_vec, size_t out_len) {
|
||||||
|
auto messages = ptr_to_local(&self)->GetStalledTopLevelAwaitMessage(isolate);
|
||||||
|
auto len = std::min(messages.size(), out_len);
|
||||||
|
for (size_t i = 0; i < len; i += 1) {
|
||||||
|
StalledTopLevelAwaitMessage stalled_message;
|
||||||
|
stalled_message.module = local_to_ptr(std::get<0>(messages[i]));
|
||||||
|
stalled_message.message = local_to_ptr(std::get<1>(messages[i]));
|
||||||
|
out_vec[i] = stalled_message;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
const v8::String* v8__ModuleRequest__GetSpecifier(
|
const v8::String* v8__ModuleRequest__GetSpecifier(
|
||||||
const v8::ModuleRequest& self) {
|
const v8::ModuleRequest& self) {
|
||||||
return local_to_ptr(self.GetSpecifier());
|
return local_to_ptr(self.GetSpecifier());
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::FixedArray;
|
||||||
use crate::HandleScope;
|
use crate::HandleScope;
|
||||||
use crate::Isolate;
|
use crate::Isolate;
|
||||||
use crate::Local;
|
use crate::Local;
|
||||||
|
use crate::Message;
|
||||||
use crate::Module;
|
use crate::Module;
|
||||||
use crate::ModuleRequest;
|
use crate::ModuleRequest;
|
||||||
use crate::String;
|
use crate::String;
|
||||||
|
@ -195,6 +196,18 @@ extern "C" {
|
||||||
fn v8__ModuleRequest__GetImportAssertions(
|
fn v8__ModuleRequest__GetImportAssertions(
|
||||||
this: *const ModuleRequest,
|
this: *const ModuleRequest,
|
||||||
) -> *const FixedArray;
|
) -> *const FixedArray;
|
||||||
|
fn v8__Module__GetStalledTopLevelAwaitMessage(
|
||||||
|
this: *const Module,
|
||||||
|
isolate: *const Isolate,
|
||||||
|
out_vec: *mut StalledTopLevelAwaitMessage,
|
||||||
|
vec_len: usize,
|
||||||
|
) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct StalledTopLevelAwaitMessage {
|
||||||
|
pub module: *const Module,
|
||||||
|
pub message: *const Message,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A location in JavaScript source.
|
/// A location in JavaScript source.
|
||||||
|
@ -413,6 +426,44 @@ impl Module {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Search the modules requested directly or indirectly by the module for
|
||||||
|
/// any top-level await that has not yet resolved. If there is any, the
|
||||||
|
/// returned vector contains a tuple of the unresolved module and a message
|
||||||
|
/// with the pending top-level await.
|
||||||
|
/// An embedder may call this before exiting to improve error messages.
|
||||||
|
pub fn get_stalled_top_level_await_message(
|
||||||
|
&self,
|
||||||
|
scope: &mut HandleScope,
|
||||||
|
) -> Vec<(Local<Module>, Local<Message>)> {
|
||||||
|
let mut out_vec: Vec<StalledTopLevelAwaitMessage> = Vec::with_capacity(16);
|
||||||
|
for _i in 0..16 {
|
||||||
|
out_vec.push(StalledTopLevelAwaitMessage {
|
||||||
|
module: std::ptr::null(),
|
||||||
|
message: std::ptr::null(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let returned_len = unsafe {
|
||||||
|
v8__Module__GetStalledTopLevelAwaitMessage(
|
||||||
|
&*self,
|
||||||
|
scope.get_isolate_ptr(),
|
||||||
|
out_vec.as_mut_ptr(),
|
||||||
|
out_vec.len(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ret_vec = Vec::with_capacity(returned_len);
|
||||||
|
for item in out_vec.iter().take(returned_len) {
|
||||||
|
unsafe {
|
||||||
|
ret_vec.push((
|
||||||
|
Local::from_raw(item.module).unwrap(),
|
||||||
|
Local::from_raw(item.message).unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret_vec
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleRequest {
|
impl ModuleRequest {
|
||||||
|
|
|
@ -3506,6 +3506,66 @@ fn module_evaluation() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn module_stalled_top_level_await() {
|
||||||
|
let _setup_guard = setup();
|
||||||
|
let isolate = &mut v8::Isolate::new(Default::default());
|
||||||
|
{
|
||||||
|
let scope = &mut v8::HandleScope::new(isolate);
|
||||||
|
let context = v8::Context::new(scope);
|
||||||
|
let scope = &mut v8::ContextScope::new(scope, context);
|
||||||
|
|
||||||
|
let source_text =
|
||||||
|
v8::String::new(scope, "await new Promise((_resolve, _reject) => {});")
|
||||||
|
.unwrap();
|
||||||
|
let origin = mock_script_origin(scope, "foo.js");
|
||||||
|
let source = v8::script_compiler::Source::new(source_text, Some(&origin));
|
||||||
|
|
||||||
|
let module = v8::script_compiler::compile_module(scope, source).unwrap();
|
||||||
|
assert!(module.script_id().is_some());
|
||||||
|
assert!(module.is_source_text_module());
|
||||||
|
assert!(!module.is_synthetic_module());
|
||||||
|
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
|
||||||
|
module.hash(&mut DefaultHasher::new()); // Should not crash.
|
||||||
|
|
||||||
|
let result = module
|
||||||
|
.instantiate_module(scope, compile_specifier_as_module_resolve_callback);
|
||||||
|
assert!(result.unwrap());
|
||||||
|
assert_eq!(v8::ModuleStatus::Instantiated, module.get_status());
|
||||||
|
|
||||||
|
let result = module.evaluate(scope);
|
||||||
|
assert!(result.is_some());
|
||||||
|
assert_eq!(v8::ModuleStatus::Evaluated, module.get_status());
|
||||||
|
|
||||||
|
let promise: v8::Local<v8::Promise> = result.unwrap().try_into().unwrap();
|
||||||
|
scope.perform_microtask_checkpoint();
|
||||||
|
assert_eq!(promise.state(), v8::PromiseState::Pending);
|
||||||
|
let stalled = module.get_stalled_top_level_await_message(scope);
|
||||||
|
assert_eq!(stalled.len(), 1);
|
||||||
|
let (_module, message) = stalled[0];
|
||||||
|
let message_str = message.get(scope);
|
||||||
|
assert_eq!(
|
||||||
|
message_str.to_rust_string_lossy(scope),
|
||||||
|
"Top-level await promise never resolved"
|
||||||
|
);
|
||||||
|
assert_eq!(Some(1), message.get_line_number(scope));
|
||||||
|
assert_eq!(
|
||||||
|
message
|
||||||
|
.get_script_resource_name(scope)
|
||||||
|
.unwrap()
|
||||||
|
.to_rust_string_lossy(scope),
|
||||||
|
"foo.js"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
message
|
||||||
|
.get_source_line(scope)
|
||||||
|
.unwrap()
|
||||||
|
.to_rust_string_lossy(scope),
|
||||||
|
"await new Promise((_resolve, _reject) => {});"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn import_assertions() {
|
fn import_assertions() {
|
||||||
let _setup_guard = setup();
|
let _setup_guard = setup();
|
||||||
|
|
Loading…
Add table
Reference in a new issue