diff options
-rw-r--r-- | cli/tests/integration/run_tests.rs | 5 | ||||
-rw-r--r-- | cli/tests/testdata/followup_dyn_import_resolves/main.ts | 14 | ||||
-rw-r--r-- | cli/tests/testdata/followup_dyn_import_resolves/main.ts.out | 3 | ||||
-rw-r--r-- | cli/tests/testdata/followup_dyn_import_resolves/sub1.ts | 2 | ||||
-rw-r--r-- | cli/tests/testdata/followup_dyn_import_resolves/sub2.ts | 1 | ||||
-rw-r--r-- | core/modules.rs | 6 | ||||
-rw-r--r-- | core/runtime.rs | 31 |
7 files changed, 51 insertions, 11 deletions
diff --git a/cli/tests/integration/run_tests.rs b/cli/tests/integration/run_tests.rs index 09a1ba500..bd27cd8dd 100644 --- a/cli/tests/integration/run_tests.rs +++ b/cli/tests/integration/run_tests.rs @@ -2733,3 +2733,8 @@ itest!(test_and_bench_are_noops_in_run { args: "run test_and_bench_in_run.js", output_str: Some(""), }); + +itest!(followup_dyn_import_resolved { + args: "run --unstable --allow-read followup_dyn_import_resolves/main.ts", + output: "followup_dyn_import_resolves/main.ts.out", +}); diff --git a/cli/tests/testdata/followup_dyn_import_resolves/main.ts b/cli/tests/testdata/followup_dyn_import_resolves/main.ts new file mode 100644 index 000000000..a8508f942 --- /dev/null +++ b/cli/tests/testdata/followup_dyn_import_resolves/main.ts @@ -0,0 +1,14 @@ +// https://github.com/denoland/deno/issues/14726 + +// Any dynamic modules that are only pending on a TLA import should be resolved +// in the same event loop iteration as the imported module. + +// Long-running timer so the event loop doesn't have a next iteration for a +// while. +setTimeout(() => {}, 24 * 60 * 60 * 1000); + +await import("./sub1.ts"); + +// If we reach here, the test is passed. +console.log("Done."); +Deno.exit(); diff --git a/cli/tests/testdata/followup_dyn_import_resolves/main.ts.out b/cli/tests/testdata/followup_dyn_import_resolves/main.ts.out new file mode 100644 index 000000000..a19976d4a --- /dev/null +++ b/cli/tests/testdata/followup_dyn_import_resolves/main.ts.out @@ -0,0 +1,3 @@ +sub2 +sub1 +Done. diff --git a/cli/tests/testdata/followup_dyn_import_resolves/sub1.ts b/cli/tests/testdata/followup_dyn_import_resolves/sub1.ts new file mode 100644 index 000000000..d06c30221 --- /dev/null +++ b/cli/tests/testdata/followup_dyn_import_resolves/sub1.ts @@ -0,0 +1,2 @@ +await import("./sub2.ts"); +console.log("sub1"); diff --git a/cli/tests/testdata/followup_dyn_import_resolves/sub2.ts b/cli/tests/testdata/followup_dyn_import_resolves/sub2.ts new file mode 100644 index 000000000..cce2b524c --- /dev/null +++ b/cli/tests/testdata/followup_dyn_import_resolves/sub2.ts @@ -0,0 +1 @@ +console.log("sub2"); diff --git a/core/modules.rs b/core/modules.rs index 8c4f25d48..e86fdbf73 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -1803,15 +1803,11 @@ import "/a.js"; ) .unwrap(); - // First poll runs `prepare_load` hook. - assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending)); - assert_eq!(prepare_load_count.load(Ordering::Relaxed), 1); - - // Second poll actually loads modules into the isolate. assert!(matches!( runtime.poll_event_loop(cx, false), Poll::Ready(Ok(_)) )); + assert_eq!(prepare_load_count.load(Ordering::Relaxed), 1); assert_eq!(resolve_count.load(Ordering::Relaxed), 7); assert_eq!(load_count.load(Ordering::Relaxed), 1); assert!(matches!( diff --git a/core/runtime.rs b/core/runtime.rs index 97c822848..f82f06207 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -886,13 +886,28 @@ impl JsRuntime { // Dynamic module loading - ie. modules loaded using "import()" { - let poll_imports = self.prepare_dyn_imports(cx)?; - assert!(poll_imports.is_ready()); + // Run in a loop so that dynamic imports that only depend on another + // dynamic import can be resolved in this event loop iteration. + // + // For example, a dynamically imported module like the following can be + // immediately resolved after `dependency.ts` is fully evaluated, but it + // wouldn't if not for this loop. + // + // await delay(1000); + // await import("./dependency.ts"); + // console.log("test") + // + loop { + let poll_imports = self.prepare_dyn_imports(cx)?; + assert!(poll_imports.is_ready()); - let poll_imports = self.poll_dyn_imports(cx)?; - assert!(poll_imports.is_ready()); + let poll_imports = self.poll_dyn_imports(cx)?; + assert!(poll_imports.is_ready()); - self.evaluate_dyn_imports(); + if !self.evaluate_dyn_imports() { + break; + } + } self.check_promise_exceptions()?; } @@ -1505,7 +1520,9 @@ impl JsRuntime { } } - fn evaluate_dyn_imports(&mut self) { + // Returns true if some dynamic import was resolved. + fn evaluate_dyn_imports(&mut self) -> bool { + let mut resolved_any = false; let state_rc = Self::state(self.v8_isolate()); let mut still_pending = vec![]; let pending = @@ -1536,6 +1553,7 @@ impl JsRuntime { }; if let Some(result) = maybe_result { + resolved_any = true; match result { Ok((dyn_import_id, module_id)) => { self.dynamic_import_resolve(dyn_import_id, module_id); @@ -1547,6 +1565,7 @@ impl JsRuntime { } } state_rc.borrow_mut().pending_dyn_mod_evaluate = still_pending; + resolved_any } /// Asynchronously load specified module and all of its dependencies. |