diff options
author | Matt Mastracci <matthew@mastracci.com> | 2023-08-15 13:36:36 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-16 04:36:36 +0900 |
commit | 4380a09a0598c73aa434e2f0f3a34555e0bd55cb (patch) | |
tree | 671bba82325653ed188efb49e099c4d61ec318cc /runtime/worker_bootstrap.rs | |
parent | 41cad2179fb36c2371ab84ce587d3460af64b5fb (diff) |
feat(ext/node): eagerly bootstrap node (#20153)
To fix bugs around detection of when node emulation is required, we will
just eagerly initialize it. The improvements we make to reduce the
impact of the startup time:
- [x] Process stdin/stdout/stderr are lazily created
- [x] node.js global proxy no longer allocates on each access check
- [x] Process checks for `beforeExit` listeners before doing expensive
shutdown work
- [x] Process should avoid adding global event handlers until listeners
are added
Benchmarking this PR (`89de7e1ff`) vs main (`41cad2179`)
```
12:36 $ third_party/prebuilt/mac/hyperfine --warmup 100 -S none './deno-41cad2179 run ./empty.js' './deno-89de7e1ff run ./empty.js'
Benchmark 1: ./deno-41cad2179 run ./empty.js
Time (mean ± σ): 24.3 ms ± 1.6 ms [User: 16.2 ms, System: 6.0 ms]
Range (min … max): 21.1 ms … 29.1 ms 115 runs
Benchmark 2: ./deno-89de7e1ff run ./empty.js
Time (mean ± σ): 24.0 ms ± 1.4 ms [User: 16.3 ms, System: 5.6 ms]
Range (min … max): 21.3 ms … 28.6 ms 126 runs
```
Fixes https://github.com/denoland/deno/issues/20142
Fixes https://github.com/denoland/deno/issues/15826
Fixes https://github.com/denoland/deno/issues/20028
Diffstat (limited to 'runtime/worker_bootstrap.rs')
-rw-r--r-- | runtime/worker_bootstrap.rs | 204 |
1 files changed, 82 insertions, 122 deletions
diff --git a/runtime/worker_bootstrap.rs b/runtime/worker_bootstrap.rs index 9627281a6..0f533344f 100644 --- a/runtime/worker_bootstrap.rs +++ b/runtime/worker_bootstrap.rs @@ -2,6 +2,8 @@ use deno_core::v8; use deno_core::ModuleSpecifier; +use serde::Serialize; +use std::cell::RefCell; use std::thread; use crate::colors; @@ -55,6 +57,8 @@ pub struct BootstrapOptions { pub unstable: bool, pub user_agent: String, pub inspect: bool, + pub has_node_modules_dir: bool, + pub maybe_binary_npm_command_name: Option<String>, } impl Default for BootstrapOptions { @@ -80,135 +84,91 @@ impl Default for BootstrapOptions { unstable: Default::default(), inspect: Default::default(), args: Default::default(), + has_node_modules_dir: Default::default(), + maybe_binary_npm_command_name: None, } } } +/// This is a struct that we use to serialize the contents of the `BootstrapOptions` +/// struct above to a V8 form. While `serde_v8` is not as fast as hand-coding this, +/// it's "fast enough" while serializing a large tuple like this that it doesn't appear +/// on flamegraphs. +/// +/// Note that a few fields in here are derived from the process and environment and +/// are not sourced from the underlying `BootstrapOptions`. +/// +/// Keep this in sync with `99_main.js`. +#[derive(Serialize)] +struct BootstrapV8<'a>( + // args + &'a Vec<String>, + // cpu_count + i32, + // log_level + i32, + // runtime_version + &'a str, + // locale + &'a str, + // location + Option<&'a str>, + // no_color + bool, + // is_tty + bool, + // ts_version + &'a str, + // unstable + bool, + // process_id + i32, + // env!("TARGET") + &'a str, + // v8_version + &'a str, + // user_agent + &'a str, + // inspect + bool, + // enable_testing_features + bool, + // has_node_modules_dir + bool, + // maybe_binary_npm_command_name + Option<&'a str>, +); + impl BootstrapOptions { + /// Return the v8 equivalent of this structure. pub fn as_v8<'s>( &self, scope: &mut v8::HandleScope<'s>, - ) -> v8::Local<'s, v8::Array> { - let array = v8::Array::new(scope, 16); - - { - let args = v8::Array::new(scope, self.args.len() as i32); - for (idx, arg) in self.args.iter().enumerate() { - let arg_str = v8::String::new(scope, arg).unwrap(); - args.set_index(scope, idx as u32, arg_str.into()); - } - array.set_index(scope, 0, args.into()); - } - - { - let val = v8::Integer::new(scope, self.cpu_count as i32); - array.set_index(scope, 1, val.into()); - } - - { - let val = v8::Integer::new(scope, self.log_level as i32); - array.set_index(scope, 2, val.into()); - } - - { - let val = v8::String::new_from_one_byte( - scope, - self.runtime_version.as_bytes(), - v8::NewStringType::Internalized, - ) - .unwrap(); - array.set_index(scope, 3, val.into()); - } - - { - let val = v8::String::new_from_one_byte( - scope, - self.locale.as_bytes(), - v8::NewStringType::Normal, - ) - .unwrap(); - array.set_index(scope, 4, val.into()); - } - - { - let val: v8::Local<v8::Value> = if let Some(location) = &self.location { - v8::String::new(scope, location.as_str()).unwrap().into() - } else { - v8::undefined(scope).into() - }; - - array.set_index(scope, 5, val); - } - - { - let val = v8::Boolean::new(scope, self.no_color); - array.set_index(scope, 6, val.into()); - } - - { - let val = v8::Boolean::new(scope, self.is_tty); - array.set_index(scope, 7, val.into()); - } - - { - let val = v8::String::new_from_one_byte( - scope, - self.ts_version.as_bytes(), - v8::NewStringType::Normal, - ) - .unwrap(); - array.set_index(scope, 8, val.into()); - } - - { - let val = v8::Boolean::new(scope, self.unstable); - array.set_index(scope, 9, val.into()); - } - - { - let val = v8::Integer::new(scope, std::process::id() as i32); - array.set_index(scope, 10, val.into()); - } - - { - let val = v8::String::new_external_onebyte_static( - scope, - env!("TARGET").as_bytes(), - ) - .unwrap(); - array.set_index(scope, 11, val.into()); - } - - { - let val = v8::String::new_from_one_byte( - scope, - deno_core::v8_version().as_bytes(), - v8::NewStringType::Normal, - ) - .unwrap(); - array.set_index(scope, 12, val.into()); - } - - { - let val = v8::String::new_from_one_byte( - scope, - self.user_agent.as_bytes(), - v8::NewStringType::Normal, - ) - .unwrap(); - array.set_index(scope, 13, val.into()); - } - - { - let val = v8::Boolean::new(scope, self.inspect); - array.set_index(scope, 14, val.into()); - } - - { - let val = v8::Boolean::new(scope, self.enable_testing_features); - array.set_index(scope, 15, val.into()); - } - - array + ) -> v8::Local<'s, v8::Value> { + let scope = RefCell::new(scope); + let ser = deno_core::serde_v8::Serializer::new(&scope); + + let bootstrap = BootstrapV8( + &self.args, + self.cpu_count as _, + self.log_level as _, + &self.runtime_version, + &self.locale, + self.location.as_ref().map(|l| l.as_str()), + self.no_color, + self.is_tty, + &self.ts_version, + self.unstable, + std::process::id() as _, + env!("TARGET"), + deno_core::v8_version(), + &self.user_agent, + self.inspect, + self.enable_testing_features, + self.has_node_modules_dir, + self.maybe_binary_npm_command_name.as_deref(), + ); + + bootstrap.serialize(ser).unwrap() } } |