summaryrefslogtreecommitdiff
path: root/runtime/worker_bootstrap.rs
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2023-08-15 13:36:36 -0600
committerGitHub <noreply@github.com>2023-08-16 04:36:36 +0900
commit4380a09a0598c73aa434e2f0f3a34555e0bd55cb (patch)
tree671bba82325653ed188efb49e099c4d61ec318cc /runtime/worker_bootstrap.rs
parent41cad2179fb36c2371ab84ce587d3460af64b5fb (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.rs204
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()
}
}