diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-02-14 00:43:53 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-14 00:43:53 +0100 |
commit | bd6ddd9b469b01b3663bbd275b7b11f7ac6e1ec2 (patch) | |
tree | 653285454e444f17b00f000c2e6c5bb72015c260 | |
parent | f917d2e2c10e0a94e564a9016217e7ce27c8bbee (diff) |
feat(core): allow to specify entry point for snapshotted ES modules (#17771)
This commit adds "ExtensionBuilder::esm_entry_point()" function that
allows to specify which of the extension files should be treated as an
entry point. If the entry point is not provided all modules are loaded
and evaluated, but if it is provided then only the entry point is explicitly
loaded and evaluated.
Co-authored-by: Leo Kettmeir <crowlkats@toaxl.com>
-rw-r--r-- | core/extensions.rs | 12 | ||||
-rw-r--r-- | core/modules.rs | 30 | ||||
-rw-r--r-- | core/runtime.rs | 51 | ||||
-rw-r--r-- | core/snapshot_util.rs | 20 |
4 files changed, 83 insertions, 30 deletions
diff --git a/core/extensions.rs b/core/extensions.rs index 16cca924d..e497b8003 100644 --- a/core/extensions.rs +++ b/core/extensions.rs @@ -43,6 +43,7 @@ impl OpDecl { pub struct Extension { js_files: Option<Vec<ExtensionFileSource>>, esm_files: Option<Vec<ExtensionFileSource>>, + esm_entry_point: Option<&'static str>, ops: Option<Vec<OpDecl>>, opstate_fn: Option<Box<OpStateFn>>, middleware_fn: Option<Box<OpMiddlewareFn>>, @@ -100,6 +101,10 @@ impl Extension { } } + pub fn get_esm_entry_point(&self) -> Option<&'static str> { + self.esm_entry_point + } + /// Called at JsRuntime startup to initialize ops in the isolate. pub fn init_ops(&mut self) -> Option<Vec<OpDecl>> { // TODO(@AaronO): maybe make op registration idempotent @@ -158,6 +163,7 @@ impl Extension { pub struct ExtensionBuilder { js: Vec<ExtensionFileSource>, esm: Vec<ExtensionFileSource>, + esm_entry_point: Option<&'static str>, ops: Vec<OpDecl>, state: Option<Box<OpStateFn>>, middleware: Option<Box<OpMiddlewareFn>>, @@ -197,6 +203,11 @@ impl ExtensionBuilder { self } + pub fn esm_entry_point(&mut self, entry_point: &'static str) -> &mut Self { + self.esm_entry_point = Some(entry_point); + self + } + pub fn ops(&mut self, ops: Vec<OpDecl>) -> &mut Self { self.ops.extend(ops); self @@ -234,6 +245,7 @@ impl ExtensionBuilder { Extension { js_files, esm_files, + esm_entry_point: self.esm_entry_point.take(), ops, opstate_fn: self.state.take(), middleware_fn: self.middleware.take(), diff --git a/core/modules.rs b/core/modules.rs index b604e8c13..1f427508a 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -275,21 +275,27 @@ pub struct NoopModuleLoader; impl ModuleLoader for NoopModuleLoader { fn resolve( &self, - _specifier: &str, - _referrer: &str, + specifier: &str, + referrer: &str, _kind: ResolutionKind, ) -> Result<ModuleSpecifier, Error> { - Err(generic_error("Module loading is not supported")) + Err(generic_error( + format!("Module loading is not supported; attempted to resolve: \"{specifier}\" from \"{referrer}\"") + )) } fn load( &self, - _module_specifier: &ModuleSpecifier, - _maybe_referrer: Option<ModuleSpecifier>, + module_specifier: &ModuleSpecifier, + maybe_referrer: Option<ModuleSpecifier>, _is_dyn_import: bool, ) -> Pin<Box<ModuleSourceFuture>> { - async { Err(generic_error("Module loading is not supported")) } - .boxed_local() + let err = generic_error( + format!( + "Module loading is not supported; attempted to load: \"{module_specifier}\" from \"{maybe_referrer:?}\"", + ) + ); + async move { Err(err) }.boxed_local() } } @@ -2720,14 +2726,20 @@ if (import.meta.url != 'file:///main_with_code.js') throw Error(); .resolve("file://foo", "file://bar", ResolutionKind::Import) .err() .map(|e| e.to_string()), - Some("Module loading is not supported".to_string()) + Some( + "Module loading is not supported; attempted to resolve: \"file://foo\" from \"file://bar\"" + .to_string() + ) ); assert_eq!( loader .resolve("file://foo", "internal:bar", ResolutionKind::Import) .err() .map(|e| e.to_string()), - Some("Module loading is not supported".to_string()) + Some( + "Module loading is not supported; attempted to resolve: \"file://foo\" from \"internal:bar\"" + .to_string() + ) ); assert_eq!( resolve_helper( diff --git a/core/runtime.rs b/core/runtime.rs index d922d0ca5..0127e80e6 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -829,26 +829,39 @@ impl JsRuntime { /// Initializes JS of provided Extensions in the given realm fn init_extension_js(&mut self, realm: &JsRealm) -> Result<(), Error> { + fn load_and_evaluate_module( + runtime: &mut JsRuntime, + file_source: &ExtensionFileSource, + ) -> Result<(), Error> { + futures::executor::block_on(async { + let id = runtime + .load_side_module( + &ModuleSpecifier::parse(&file_source.specifier)?, + None, + ) + .await?; + let receiver = runtime.mod_evaluate(id); + runtime.run_event_loop(false).await?; + receiver.await? + }) + .with_context(|| format!("Couldn't execute '{}'", file_source.specifier)) + } + // Take extensions to avoid double-borrow let extensions = std::mem::take(&mut self.extensions_with_js); for ext in &extensions { { let esm_files = ext.get_esm_sources(); - for file_source in esm_files { - futures::executor::block_on(async { - let id = self - .load_side_module( - &ModuleSpecifier::parse(&file_source.specifier)?, - None, - ) - .await?; - let receiver = self.mod_evaluate(id); - self.run_event_loop(false).await?; - receiver.await? - }) - .with_context(|| { - format!("Couldn't execute '{}'", file_source.specifier) - })?; + if let Some(entry_point) = ext.get_esm_entry_point() { + let file_source = esm_files + .iter() + .find(|file| file.specifier == entry_point) + .unwrap(); + load_and_evaluate_module(self, file_source)?; + } else { + for file_source in esm_files { + load_and_evaluate_module(self, file_source)?; + } } } @@ -1770,7 +1783,11 @@ impl JsRuntime { .map(|handle| v8::Local::new(tc_scope, handle)) .expect("ModuleInfo not found"); let mut status = module.get_status(); - assert_eq!(status, v8::ModuleStatus::Instantiated); + assert_eq!( + status, + v8::ModuleStatus::Instantiated, + "Module not instantiated {id}" + ); let (sender, receiver) = oneshot::channel(); @@ -4974,7 +4991,7 @@ Deno.core.ops.op_async_serialize_object_with_numbers_as_keys({ _is_dyn_import: bool, ) -> Pin<Box<ModuleSourceFuture>> { let source = r#" - // This module doesn't really exist, just verifying that we'll get + // This module doesn't really exist, just verifying that we'll get // an error when specifier starts with "internal:". import { core } from "internal:core.js"; "#; diff --git a/core/snapshot_util.rs b/core/snapshot_util.rs index 0a1793b51..7e22395e0 100644 --- a/core/snapshot_util.rs +++ b/core/snapshot_util.rs @@ -22,6 +22,7 @@ pub struct CreateSnapshotOptions { } pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) { + let start = std::time::Instant::now(); let js_runtime = JsRuntime::new(RuntimeOptions { will_snapshot: true, startup_snapshot: create_snapshot_options.startup_snapshot, @@ -33,7 +34,12 @@ pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) { let snapshot = js_runtime.snapshot(); let snapshot_slice: &[u8] = &snapshot; - println!("Snapshot size: {}", snapshot_slice.len()); + println!( + "Snapshot size: {}, took {}s ({})", + snapshot_slice.len(), + start.elapsed().as_secs_f64(), + create_snapshot_options.snapshot_path.display() + ); let maybe_compressed_snapshot: Box<dyn AsRef<[u8]>> = if let Some(compression_cb) = create_snapshot_options.compression_cb { @@ -47,7 +53,12 @@ pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) { (compression_cb)(&mut vec, snapshot_slice); - println!("Snapshot compressed size: {}", vec.len()); + println!( + "Snapshot compressed size: {}, took {}s ({})", + vec.len(), + start.elapsed().as_secs_f64(), + create_snapshot_options.snapshot_path.display() + ); Box::new(vec) } else { @@ -60,8 +71,9 @@ pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) { ) .unwrap(); println!( - "Snapshot written to: {} ", - create_snapshot_options.snapshot_path.display() + "Snapshot written to: {}, took: {}s", + create_snapshot_options.snapshot_path.display(), + start.elapsed().as_secs_f64() ); } |