mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
fix(core/runtime): Fix dynamic imports for already rejected modules (#9559)
This commit is contained in:
parent
4f80587d26
commit
10fb25db63
4 changed files with 65 additions and 34 deletions
11
cli/tests/086_dynamic_import_already_rejected.ts
Normal file
11
cli/tests/086_dynamic_import_already_rejected.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
try {
|
||||||
|
await import("./error_001.ts");
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Caught: ${error.stack}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await import("./error_001.ts");
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Caught: ${error.stack}`);
|
||||||
|
}
|
4
cli/tests/086_dynamic_import_already_rejected.ts.out
Normal file
4
cli/tests/086_dynamic_import_already_rejected.ts.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[WILDCARD]Caught: Error: bad
|
||||||
|
at [WILDCARD]/error_001.ts:[WILDCARD]
|
||||||
|
Caught: Error: bad
|
||||||
|
at [WILDCARD]/error_001.ts:[WILDCARD]
|
|
@ -2787,6 +2787,11 @@ console.log("finish");
|
||||||
output: "085_dynamic_import_async_error.ts.out",
|
output: "085_dynamic_import_async_error.ts.out",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itest!(_086_dynamic_import_already_rejected {
|
||||||
|
args: "run --allow-read 086_dynamic_import_already_rejected.ts",
|
||||||
|
output: "086_dynamic_import_already_rejected.ts.out",
|
||||||
|
});
|
||||||
|
|
||||||
itest!(js_import_detect {
|
itest!(js_import_detect {
|
||||||
args: "run --quiet --reload js_import_detect.ts",
|
args: "run --quiet --reload js_import_detect.ts",
|
||||||
output: "js_import_detect.ts.out",
|
output: "js_import_detect.ts.out",
|
||||||
|
|
|
@ -734,33 +734,51 @@ impl JsRuntime {
|
||||||
/// `AnyError` can be downcast to a type that exposes additional information
|
/// `AnyError` can be downcast to a type that exposes additional information
|
||||||
/// about the V8 exception. By default this type is `JsError`, however it may
|
/// about the V8 exception. By default this type is `JsError`, however it may
|
||||||
/// be a different type if `RuntimeOptions::js_error_create_fn` has been set.
|
/// be a different type if `RuntimeOptions::js_error_create_fn` has been set.
|
||||||
fn mod_instantiate(&mut self, id: ModuleId) -> Result<(), AnyError> {
|
fn mod_instantiate(
|
||||||
|
&mut self,
|
||||||
|
id: ModuleId,
|
||||||
|
dyn_import_id: Option<ModuleLoadId>,
|
||||||
|
) -> Result<(), AnyError> {
|
||||||
let state_rc = Self::state(self.v8_isolate());
|
let state_rc = Self::state(self.v8_isolate());
|
||||||
let context = self.global_context();
|
let context = self.global_context();
|
||||||
|
|
||||||
let scope = &mut v8::HandleScope::with_context(self.v8_isolate(), context);
|
let result = {
|
||||||
let tc_scope = &mut v8::TryCatch::new(scope);
|
let scope =
|
||||||
|
&mut v8::HandleScope::with_context(self.v8_isolate(), context);
|
||||||
|
let tc_scope = &mut v8::TryCatch::new(scope);
|
||||||
|
|
||||||
let module = state_rc
|
let module = state_rc
|
||||||
.borrow()
|
.borrow()
|
||||||
.modules
|
.modules
|
||||||
.get_handle(id)
|
.get_handle(id)
|
||||||
.map(|handle| v8::Local::new(tc_scope, handle))
|
.map(|handle| v8::Local::new(tc_scope, handle))
|
||||||
.expect("ModuleInfo not found");
|
.expect("ModuleInfo not found");
|
||||||
|
|
||||||
if module.get_status() == v8::ModuleStatus::Errored {
|
if module.get_status() == v8::ModuleStatus::Errored {
|
||||||
exception_to_err_result(tc_scope, module.get_exception(), false)?
|
let exception = module.get_exception();
|
||||||
}
|
|
||||||
|
|
||||||
let result =
|
|
||||||
module.instantiate_module(tc_scope, bindings::module_resolve_callback);
|
|
||||||
match result {
|
|
||||||
Some(_) => Ok(()),
|
|
||||||
None => {
|
|
||||||
let exception = tc_scope.exception().unwrap();
|
|
||||||
exception_to_err_result(tc_scope, exception, false)
|
exception_to_err_result(tc_scope, exception, false)
|
||||||
|
.map_err(|err| attach_handle_to_error(tc_scope, err, exception))
|
||||||
|
} else {
|
||||||
|
let instantiate_result = module
|
||||||
|
.instantiate_module(tc_scope, bindings::module_resolve_callback);
|
||||||
|
match instantiate_result {
|
||||||
|
Some(_) => Ok(()),
|
||||||
|
None => {
|
||||||
|
let exception = tc_scope.exception().unwrap();
|
||||||
|
exception_to_err_result(tc_scope, exception, false)
|
||||||
|
.map_err(|err| attach_handle_to_error(tc_scope, err, exception))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(dyn_import_id) = dyn_import_id {
|
||||||
|
if let Err(err) = result {
|
||||||
|
self.dyn_import_error(dyn_import_id, err);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates an already instantiated ES module.
|
/// Evaluates an already instantiated ES module.
|
||||||
|
@ -794,15 +812,10 @@ impl JsRuntime {
|
||||||
// IMPORTANT: Top-level-await is enabled, which means that return value
|
// IMPORTANT: Top-level-await is enabled, which means that return value
|
||||||
// of module evaluation is a promise.
|
// of module evaluation is a promise.
|
||||||
//
|
//
|
||||||
// Because that promise is created internally by V8, when error occurs during
|
// This promise is internal, and not the same one that gets returned to
|
||||||
// module evaluation the promise is rejected, and since the promise has no rejection
|
// the user. We add an empty `.catch()` handler so that it does not result
|
||||||
// handler it will result in call to `bindings::promise_reject_callback` adding
|
// in an exception if it rejects. That will instead happen for the other
|
||||||
// the promise to pending promise rejection table - meaning JsRuntime will return
|
// promise if not handled by the user.
|
||||||
// error on next poll().
|
|
||||||
//
|
|
||||||
// This situation is not desirable as we want to manually return error at the
|
|
||||||
// end of this function to handle it further. It means we need to manually
|
|
||||||
// remove this promise from pending promise rejection table.
|
|
||||||
//
|
//
|
||||||
// For more details see:
|
// For more details see:
|
||||||
// https://github.com/denoland/deno/issues/4908
|
// https://github.com/denoland/deno/issues/4908
|
||||||
|
@ -828,9 +841,7 @@ impl JsRuntime {
|
||||||
let empty_fn = v8::FunctionTemplate::new(scope, empty_fn);
|
let empty_fn = v8::FunctionTemplate::new(scope, empty_fn);
|
||||||
let empty_fn = empty_fn.get_function(scope).unwrap();
|
let empty_fn = empty_fn.get_function(scope).unwrap();
|
||||||
promise.catch(scope, empty_fn);
|
promise.catch(scope, empty_fn);
|
||||||
let promise_global = v8::Global::new(scope, promise);
|
|
||||||
let mut state = state_rc.borrow_mut();
|
let mut state = state_rc.borrow_mut();
|
||||||
state.pending_promise_exceptions.remove(&promise_global);
|
|
||||||
let promise_global = v8::Global::new(scope, promise);
|
let promise_global = v8::Global::new(scope, promise);
|
||||||
let module_global = v8::Global::new(scope, module);
|
let module_global = v8::Global::new(scope, module);
|
||||||
|
|
||||||
|
@ -1094,7 +1105,7 @@ impl JsRuntime {
|
||||||
// The top-level module from a dynamic import has been instantiated.
|
// The top-level module from a dynamic import has been instantiated.
|
||||||
// Load is done.
|
// Load is done.
|
||||||
let module_id = load.root_module_id.unwrap();
|
let module_id = load.root_module_id.unwrap();
|
||||||
self.mod_instantiate(module_id)?;
|
self.mod_instantiate(module_id, Some(dyn_import_id))?;
|
||||||
self.dyn_mod_evaluate(dyn_import_id, module_id)?;
|
self.dyn_mod_evaluate(dyn_import_id, module_id)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1332,7 +1343,7 @@ impl JsRuntime {
|
||||||
}
|
}
|
||||||
|
|
||||||
let root_id = load.root_module_id.expect("Root module id empty");
|
let root_id = load.root_module_id.expect("Root module id empty");
|
||||||
self.mod_instantiate(root_id).map(|_| root_id)
|
self.mod_instantiate(root_id, None).map(|_| root_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_pending_ops(
|
fn poll_pending_ops(
|
||||||
|
@ -2289,11 +2300,11 @@ pub mod tests {
|
||||||
assert_eq!(imports.len(), 0);
|
assert_eq!(imports.len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.mod_instantiate(mod_b).unwrap();
|
runtime.mod_instantiate(mod_b, None).unwrap();
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
|
||||||
assert_eq!(resolve_count.load(Ordering::SeqCst), 1);
|
assert_eq!(resolve_count.load(Ordering::SeqCst), 1);
|
||||||
|
|
||||||
runtime.mod_instantiate(mod_a).unwrap();
|
runtime.mod_instantiate(mod_a, None).unwrap();
|
||||||
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
|
assert_eq!(dispatch_count.load(Ordering::Relaxed), 0);
|
||||||
|
|
||||||
runtime.mod_evaluate_inner(mod_a);
|
runtime.mod_evaluate_inner(mod_a);
|
||||||
|
|
Loading…
Reference in a new issue