mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
feat(core): support initializing extensions with and without JS (#16789)
This commit allows to execute more JS code from extensions when creating a snapshot from an existing snapshot. "deno_core::RuntimeOptions::extensions_with_js" field was added that is used to pass a list of extensions whose both "ops" and associated JS source should be executed upon start. Co-authored-by: crowlkats <crowlkats@toaxl.com>
This commit is contained in:
parent
d4f659d1d3
commit
28b5a7e2ec
5 changed files with 82 additions and 30 deletions
|
@ -9,7 +9,7 @@ use crate::profiling::is_profiling;
|
||||||
|
|
||||||
pub fn create_js_runtime(setup: impl FnOnce() -> Vec<Extension>) -> JsRuntime {
|
pub fn create_js_runtime(setup: impl FnOnce() -> Vec<Extension>) -> JsRuntime {
|
||||||
JsRuntime::new(RuntimeOptions {
|
JsRuntime::new(RuntimeOptions {
|
||||||
extensions: setup(),
|
extensions_with_js: setup(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,6 +243,7 @@ mod ts {
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.build()],
|
.build()],
|
||||||
|
extensions_with_js: vec![],
|
||||||
additional_files: files,
|
additional_files: files,
|
||||||
compression_cb: Some(Box::new(|vec, snapshot_slice| {
|
compression_cb: Some(Box::new(|vec, snapshot_slice| {
|
||||||
vec.extend_from_slice(
|
vec.extend_from_slice(
|
||||||
|
@ -304,6 +305,7 @@ fn create_cli_snapshot(snapshot_path: PathBuf, files: Vec<PathBuf>) {
|
||||||
snapshot_path,
|
snapshot_path,
|
||||||
startup_snapshot: Some(deno_runtime::js::deno_isolate_init()),
|
startup_snapshot: Some(deno_runtime::js::deno_isolate_init()),
|
||||||
extensions,
|
extensions,
|
||||||
|
extensions_with_js: vec![],
|
||||||
additional_files: files,
|
additional_files: files,
|
||||||
compression_cb: Some(Box::new(|vec, snapshot_slice| {
|
compression_cb: Some(Box::new(|vec, snapshot_slice| {
|
||||||
lzzzz::lz4_hc::compress_to_vec(
|
lzzzz::lz4_hc::compress_to_vec(
|
||||||
|
|
101
core/runtime.rs
101
core/runtime.rs
|
@ -87,6 +87,7 @@ pub struct JsRuntime {
|
||||||
built_from_snapshot: bool,
|
built_from_snapshot: bool,
|
||||||
allocations: IsolateAllocations,
|
allocations: IsolateAllocations,
|
||||||
extensions: Vec<Extension>,
|
extensions: Vec<Extension>,
|
||||||
|
extensions_with_js: Vec<Extension>,
|
||||||
event_loop_middlewares: Vec<Box<OpEventLoopFn>>,
|
event_loop_middlewares: Vec<Box<OpEventLoopFn>>,
|
||||||
// Marks if this is considered the top-level runtime. Used only be inspector.
|
// Marks if this is considered the top-level runtime. Used only be inspector.
|
||||||
is_main: bool,
|
is_main: bool,
|
||||||
|
@ -240,10 +241,23 @@ pub struct RuntimeOptions {
|
||||||
/// executed tries to load modules.
|
/// executed tries to load modules.
|
||||||
pub module_loader: Option<Rc<dyn ModuleLoader>>,
|
pub module_loader: Option<Rc<dyn ModuleLoader>>,
|
||||||
|
|
||||||
/// JsRuntime extensions, not to be confused with ES modules
|
/// JsRuntime extensions, not to be confused with ES modules.
|
||||||
/// these are sets of ops and other JS code to be initialized.
|
/// Only ops registered by extensions will be initialized. If you need
|
||||||
|
/// to execute JS code from extensions, use `extensions_with_js` options
|
||||||
|
/// instead.
|
||||||
pub extensions: Vec<Extension>,
|
pub extensions: Vec<Extension>,
|
||||||
|
|
||||||
|
/// JsRuntime extensions, not to be confused with ES modules.
|
||||||
|
/// Ops registered by extensions will be initialized and JS code will be
|
||||||
|
/// executed. If you don't need to execute JS code from extensions, use
|
||||||
|
/// `extensions` option instead.
|
||||||
|
///
|
||||||
|
/// This is useful when creating snapshots, in such case you would pass
|
||||||
|
/// extensions using `extensions_with_js`, later when creating a runtime
|
||||||
|
/// from the snapshot, you would pass these extensions using `extensions`
|
||||||
|
/// option.
|
||||||
|
pub extensions_with_js: Vec<Extension>,
|
||||||
|
|
||||||
/// V8 snapshot that should be loaded on startup.
|
/// V8 snapshot that should be loaded on startup.
|
||||||
///
|
///
|
||||||
/// Currently can't be used with `will_snapshot`.
|
/// Currently can't be used with `will_snapshot`.
|
||||||
|
@ -339,11 +353,20 @@ impl JsRuntime {
|
||||||
let has_startup_snapshot = options.startup_snapshot.is_some();
|
let has_startup_snapshot = options.startup_snapshot.is_some();
|
||||||
|
|
||||||
// Add builtins extension
|
// Add builtins extension
|
||||||
options
|
if !has_startup_snapshot {
|
||||||
.extensions
|
options
|
||||||
.insert(0, crate::ops_builtin::init_builtins());
|
.extensions_with_js
|
||||||
|
.insert(0, crate::ops_builtin::init_builtins());
|
||||||
|
} else {
|
||||||
|
options
|
||||||
|
.extensions
|
||||||
|
.insert(0, crate::ops_builtin::init_builtins());
|
||||||
|
}
|
||||||
|
|
||||||
let ops = Self::collect_ops(&mut options.extensions);
|
let ops = Self::collect_ops(
|
||||||
|
&mut options.extensions,
|
||||||
|
&mut options.extensions_with_js,
|
||||||
|
);
|
||||||
let mut op_state = OpState::new(ops.len());
|
let mut op_state = OpState::new(ops.len());
|
||||||
|
|
||||||
if let Some(get_error_class_fn) = options.get_error_class_fn {
|
if let Some(get_error_class_fn) = options.get_error_class_fn {
|
||||||
|
@ -539,6 +562,7 @@ impl JsRuntime {
|
||||||
allocations: IsolateAllocations::default(),
|
allocations: IsolateAllocations::default(),
|
||||||
event_loop_middlewares: Vec::with_capacity(options.extensions.len()),
|
event_loop_middlewares: Vec::with_capacity(options.extensions.len()),
|
||||||
extensions: options.extensions,
|
extensions: options.extensions,
|
||||||
|
extensions_with_js: options.extensions_with_js,
|
||||||
state: state_rc,
|
state: state_rc,
|
||||||
module_map: Some(module_map_rc),
|
module_map: Some(module_map_rc),
|
||||||
is_main: options.is_main,
|
is_main: options.is_main,
|
||||||
|
@ -547,12 +571,8 @@ impl JsRuntime {
|
||||||
// Init resources and ops before extensions to make sure they are
|
// Init resources and ops before extensions to make sure they are
|
||||||
// available during the initialization process.
|
// available during the initialization process.
|
||||||
js_runtime.init_extension_ops().unwrap();
|
js_runtime.init_extension_ops().unwrap();
|
||||||
// TODO(@AaronO): diff extensions inited in snapshot and those provided
|
let realm = js_runtime.global_realm();
|
||||||
// for now we assume that snapshot and extensions always match
|
js_runtime.init_extension_js(&realm).unwrap();
|
||||||
if !has_startup_snapshot {
|
|
||||||
let realm = js_runtime.global_realm();
|
|
||||||
js_runtime.init_extension_js(&realm).unwrap();
|
|
||||||
}
|
|
||||||
// Init callbacks (opresolve)
|
// Init callbacks (opresolve)
|
||||||
js_runtime.init_cbs();
|
js_runtime.init_cbs();
|
||||||
|
|
||||||
|
@ -682,7 +702,8 @@ impl JsRuntime {
|
||||||
/// Initializes JS of provided Extensions in the given realm
|
/// Initializes JS of provided Extensions in the given realm
|
||||||
fn init_extension_js(&mut self, realm: &JsRealm) -> Result<(), Error> {
|
fn init_extension_js(&mut self, realm: &JsRealm) -> Result<(), Error> {
|
||||||
// Take extensions to avoid double-borrow
|
// Take extensions to avoid double-borrow
|
||||||
let mut extensions: Vec<Extension> = std::mem::take(&mut self.extensions);
|
let mut extensions: Vec<Extension> =
|
||||||
|
std::mem::take(&mut self.extensions_with_js);
|
||||||
for m in extensions.iter_mut() {
|
for m in extensions.iter_mut() {
|
||||||
let js_files = m.init_js();
|
let js_files = m.init_js();
|
||||||
for (filename, source) in js_files {
|
for (filename, source) in js_files {
|
||||||
|
@ -691,15 +712,22 @@ impl JsRuntime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Restore extensions
|
// Restore extensions
|
||||||
self.extensions = extensions;
|
self.extensions_with_js = extensions;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collects ops from extensions & applies middleware
|
/// Collects ops from extensions & applies middleware
|
||||||
fn collect_ops(extensions: &mut [Extension]) -> Vec<OpDecl> {
|
fn collect_ops(
|
||||||
|
extensions: &mut [Extension],
|
||||||
|
extensions_with_js: &mut [Extension],
|
||||||
|
) -> Vec<OpDecl> {
|
||||||
|
let mut exts = vec![];
|
||||||
|
exts.extend(extensions);
|
||||||
|
exts.extend(extensions_with_js);
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
let middleware: Vec<Box<OpMiddlewareFn>> = extensions
|
let middleware: Vec<Box<OpMiddlewareFn>> = exts
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(|e| e.init_middleware())
|
.filter_map(|e| e.init_middleware())
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -708,7 +736,7 @@ impl JsRuntime {
|
||||||
let macroware = move |d| middleware.iter().fold(d, |d, m| m(d));
|
let macroware = move |d| middleware.iter().fold(d, |d, m| m(d));
|
||||||
|
|
||||||
// Flatten ops, apply middlware & override disabled ops
|
// Flatten ops, apply middlware & override disabled ops
|
||||||
extensions
|
exts
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(|e| e.init_ops())
|
.filter_map(|e| e.init_ops())
|
||||||
.flatten()
|
.flatten()
|
||||||
|
@ -733,22 +761,41 @@ impl JsRuntime {
|
||||||
fn init_extension_ops(&mut self) -> Result<(), Error> {
|
fn init_extension_ops(&mut self) -> Result<(), Error> {
|
||||||
let op_state = self.op_state();
|
let op_state = self.op_state();
|
||||||
// Take extensions to avoid double-borrow
|
// Take extensions to avoid double-borrow
|
||||||
let mut extensions: Vec<Extension> = std::mem::take(&mut self.extensions);
|
{
|
||||||
|
let mut extensions: Vec<Extension> = std::mem::take(&mut self.extensions);
|
||||||
|
|
||||||
// Setup state
|
// Setup state
|
||||||
for e in extensions.iter_mut() {
|
for e in extensions.iter_mut() {
|
||||||
// ops are already registered during in bindings::initialize_context();
|
// ops are already registered during in bindings::initialize_context();
|
||||||
e.init_state(&mut op_state.borrow_mut())?;
|
e.init_state(&mut op_state.borrow_mut())?;
|
||||||
|
|
||||||
// Setup event-loop middleware
|
// Setup event-loop middleware
|
||||||
if let Some(middleware) = e.init_event_loop_middleware() {
|
if let Some(middleware) = e.init_event_loop_middleware() {
|
||||||
self.event_loop_middlewares.push(middleware);
|
self.event_loop_middlewares.push(middleware);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore extensions
|
||||||
|
self.extensions = extensions;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let mut extensions: Vec<Extension> =
|
||||||
|
std::mem::take(&mut self.extensions_with_js);
|
||||||
|
|
||||||
// Restore extensions
|
// Setup state
|
||||||
self.extensions = extensions;
|
for e in extensions.iter_mut() {
|
||||||
|
// ops are already registered during in bindings::initialize_context();
|
||||||
|
e.init_state(&mut op_state.borrow_mut())?;
|
||||||
|
|
||||||
|
// Setup event-loop middleware
|
||||||
|
if let Some(middleware) = e.init_event_loop_middleware() {
|
||||||
|
self.event_loop_middlewares.push(middleware);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore extensions
|
||||||
|
self.extensions_with_js = extensions;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub struct CreateSnapshotOptions {
|
||||||
pub snapshot_path: PathBuf,
|
pub snapshot_path: PathBuf,
|
||||||
pub startup_snapshot: Option<Snapshot>,
|
pub startup_snapshot: Option<Snapshot>,
|
||||||
pub extensions: Vec<Extension>,
|
pub extensions: Vec<Extension>,
|
||||||
|
pub extensions_with_js: Vec<Extension>,
|
||||||
pub additional_files: Vec<PathBuf>,
|
pub additional_files: Vec<PathBuf>,
|
||||||
pub compression_cb: Option<Box<CompressionCb>>,
|
pub compression_cb: Option<Box<CompressionCb>>,
|
||||||
}
|
}
|
||||||
|
@ -21,6 +22,7 @@ pub fn create_snapshot(create_snapshot_options: CreateSnapshotOptions) {
|
||||||
will_snapshot: true,
|
will_snapshot: true,
|
||||||
startup_snapshot: create_snapshot_options.startup_snapshot,
|
startup_snapshot: create_snapshot_options.startup_snapshot,
|
||||||
extensions: create_snapshot_options.extensions,
|
extensions: create_snapshot_options.extensions,
|
||||||
|
extensions_with_js: create_snapshot_options.extensions_with_js,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ mod not_docs {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_runtime_snapshot(snapshot_path: PathBuf, files: Vec<PathBuf>) {
|
fn create_runtime_snapshot(snapshot_path: PathBuf, files: Vec<PathBuf>) {
|
||||||
let extensions: Vec<Extension> = vec![
|
let extensions_with_js: Vec<Extension> = vec![
|
||||||
deno_webidl::init(),
|
deno_webidl::init(),
|
||||||
deno_console::init(),
|
deno_console::init(),
|
||||||
deno_url::init(),
|
deno_url::init(),
|
||||||
|
@ -154,7 +154,8 @@ mod not_docs {
|
||||||
cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
|
cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
|
||||||
snapshot_path,
|
snapshot_path,
|
||||||
startup_snapshot: None,
|
startup_snapshot: None,
|
||||||
extensions,
|
extensions: vec![],
|
||||||
|
extensions_with_js,
|
||||||
additional_files: files,
|
additional_files: files,
|
||||||
compression_cb: Some(Box::new(|vec, snapshot_slice| {
|
compression_cb: Some(Box::new(|vec, snapshot_slice| {
|
||||||
lzzzz::lz4_hc::compress_to_vec(
|
lzzzz::lz4_hc::compress_to_vec(
|
||||||
|
|
Loading…
Add table
Reference in a new issue