summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-03-28 10:27:17 +0200
committerGitHub <noreply@github.com>2023-03-28 10:27:17 +0200
commit795ecfa146c7b6c49be4b11f7064b2b5500296ff (patch)
treebbb0ad501db4abafa8dc2a6287162a13c231bd9c
parent86c3c4f34397a29c2bf1847bddfea562a2369a4f (diff)
refactor(runtime): manual serialization of bootstrap data (#18448)
This commit changes how data required to bootstrap main and worker runtime is serialized. Instead of relying on serde_v8 and using JSON object, we're doing manual serialization to a "v8::Array". This limits number of V8 strings that need to be serialized by 16. It also made it clear that some data could be obtained during snapshotting instead of during bootstrap.
-rw-r--r--runtime/js/99_main.js126
-rw-r--r--runtime/web_worker.rs5
-rw-r--r--runtime/worker.rs5
-rw-r--r--runtime/worker_bootstrap.rs156
4 files changed, 230 insertions, 62 deletions
diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js
index d043f485e..9102500bf 100644
--- a/runtime/js/99_main.js
+++ b/runtime/js/99_main.js
@@ -292,20 +292,29 @@ core.registerErrorBuilder(
},
);
-function runtimeStart(runtimeOptions, source) {
+function runtimeStart(
+ denoVersion,
+ v8Version,
+ tsVersion,
+ target,
+ debugFlag,
+ noColor,
+ isTty,
+ source,
+) {
core.setMacrotaskCallback(timers.handleTimerMacrotask);
core.setMacrotaskCallback(promiseRejectMacrotaskCallback);
core.setWasmStreamingCallback(fetch.handleWasmStreaming);
core.setReportExceptionCallback(event.reportException);
ops.op_set_format_exception_callback(formatException);
version.setVersions(
- runtimeOptions.denoVersion,
- runtimeOptions.v8Version,
- runtimeOptions.tsVersion,
+ denoVersion,
+ v8Version,
+ tsVersion,
);
- core.setBuildInfo(runtimeOptions.target);
- util.setLogDebug(runtimeOptions.debugFlag, source);
- colors.setNoColor(runtimeOptions.noColor || !runtimeOptions.isTty);
+ core.setBuildInfo(target);
+ util.setLogDebug(debugFlag, source);
+ colors.setNoColor(noColor || !isTty);
// deno-lint-ignore prefer-primordials
Error.prepareStackTrace = core.prepareStackTrace;
}
@@ -403,6 +412,27 @@ function bootstrapMainRuntime(runtimeOptions) {
if (hasBootstrapped) {
throw new Error("Worker runtime already bootstrapped");
}
+
+ const [
+ args,
+ cpuCount,
+ debugFlag,
+ denoVersion,
+ locale,
+ location_,
+ noColor,
+ isTty,
+ tsVersion,
+ unstableFlag,
+ pid,
+ ppid,
+ target,
+ v8Version,
+ userAgent,
+ inspectFlag,
+ _,
+ ] = runtimeOptions;
+
performance.setTimeOrigin(DateNow());
globalThis_ = globalThis;
@@ -414,15 +444,15 @@ function bootstrapMainRuntime(runtimeOptions) {
// If the `--location` flag isn't set, make `globalThis.location` `undefined` and
// writable, so that they can mock it themselves if they like. If the flag was
// set, define `globalThis.location`, using the provided value.
- if (runtimeOptions.location == null) {
+ if (location_ === undefined) {
mainRuntimeGlobalProperties.location = {
writable: true,
};
} else {
- location.setLocationHref(runtimeOptions.location);
+ location.setLocationHref(location_);
}
- if (runtimeOptions.unstableFlag) {
+ if (unstableFlag) {
ObjectDefineProperties(globalThis, unstableWindowOrWorkerGlobalScope);
}
ObjectDefineProperties(globalThis, mainRuntimeGlobalProperties);
@@ -432,7 +462,7 @@ function bootstrapMainRuntime(runtimeOptions) {
});
ObjectSetPrototypeOf(globalThis, Window.prototype);
- if (runtimeOptions.inspectFlag) {
+ if (inspectFlag) {
const consoleFromV8 = core.console;
const consoleFromDeno = globalThis.console;
wrapConsole(consoleFromDeno, consoleFromV8);
@@ -449,11 +479,19 @@ function bootstrapMainRuntime(runtimeOptions) {
core.setPromiseRejectCallback(promiseRejectCallback);
- runtimeStart(runtimeOptions);
+ runtimeStart(
+ denoVersion,
+ v8Version,
+ tsVersion,
+ target,
+ debugFlag,
+ noColor,
+ isTty,
+ );
- setNumCpus(runtimeOptions.cpuCount);
- setUserAgent(runtimeOptions.userAgent);
- setLanguage(runtimeOptions.locale);
+ setNumCpus(cpuCount);
+ setUserAgent(userAgent);
+ setLanguage(locale);
// These have to initialized here and not in `90_deno_ns.js` because
// the op function that needs to be passed will be invalidated by creating
@@ -477,14 +515,14 @@ function bootstrapMainRuntime(runtimeOptions) {
});
ObjectDefineProperties(finalDenoNs, {
- pid: util.readOnly(runtimeOptions.pid),
- ppid: util.readOnly(runtimeOptions.ppid),
- noColor: util.readOnly(runtimeOptions.noColor),
- args: util.readOnly(ObjectFreeze(runtimeOptions.args)),
+ pid: util.readOnly(pid),
+ ppid: util.readOnly(ppid),
+ noColor: util.readOnly(noColor),
+ args: util.readOnly(ObjectFreeze(args)),
mainModule: util.getterOnly(opMainModule),
});
- if (runtimeOptions.unstableFlag) {
+ if (unstableFlag) {
ObjectAssign(finalDenoNs, denoNsUnstable);
// These have to initialized here and not in `90_deno_ns.js` because
// the op function that needs to be passed will be invalidated by creating
@@ -502,7 +540,7 @@ function bootstrapMainRuntime(runtimeOptions) {
// `Deno` with `Deno` namespace from "./deno.ts".
ObjectDefineProperty(globalThis, "Deno", util.readOnly(finalDenoNs));
- util.log("args", runtimeOptions.args);
+ util.log("args", args);
}
function bootstrapWorkerRuntime(
@@ -514,6 +552,26 @@ function bootstrapWorkerRuntime(
throw new Error("Worker runtime already bootstrapped");
}
+ const [
+ args,
+ cpuCount,
+ debugFlag,
+ denoVersion,
+ locale,
+ location_,
+ noColor,
+ isTty,
+ tsVersion,
+ unstableFlag,
+ pid,
+ _ppid,
+ target,
+ v8Version,
+ _userAgent,
+ _inspectFlag,
+ enableTestingFeaturesFlag,
+ ] = runtimeOptions;
+
performance.setTimeOrigin(DateNow());
globalThis_ = globalThis;
@@ -524,7 +582,7 @@ function bootstrapWorkerRuntime(
delete globalThis.bootstrap;
hasBootstrapped = true;
- if (runtimeOptions.unstableFlag) {
+ if (unstableFlag) {
ObjectDefineProperties(globalThis, unstableWindowOrWorkerGlobalScope);
}
ObjectDefineProperties(globalThis, workerRuntimeGlobalProperties);
@@ -534,7 +592,7 @@ function bootstrapWorkerRuntime(
close: util.nonEnumerable(workerClose),
postMessage: util.writable(postMessage),
});
- if (runtimeOptions.enableTestingFeaturesFlag) {
+ if (enableTestingFeaturesFlag) {
ObjectDefineProperty(
globalThis,
"importScripts",
@@ -562,14 +620,20 @@ function bootstrapWorkerRuntime(
});
runtimeStart(
- runtimeOptions,
+ denoVersion,
+ v8Version,
+ tsVersion,
+ target,
+ debugFlag,
+ noColor,
+ isTty,
internalName ?? name,
);
- location.setLocationHref(runtimeOptions.location);
+ location.setLocationHref(location_);
- setNumCpus(runtimeOptions.cpuCount);
- setLanguage(runtimeOptions.locale);
+ setNumCpus(cpuCount);
+ setLanguage(locale);
globalThis.pollForMessages = pollForMessages;
@@ -594,7 +658,7 @@ function bootstrapWorkerRuntime(
core,
});
- if (runtimeOptions.unstableFlag) {
+ if (unstableFlag) {
ObjectAssign(finalDenoNs, denoNsUnstable);
// These have to initialized here and not in `90_deno_ns.js` because
// the op function that needs to be passed will be invalidated by creating
@@ -608,9 +672,9 @@ function bootstrapWorkerRuntime(
});
}
ObjectDefineProperties(finalDenoNs, {
- pid: util.readOnly(runtimeOptions.pid),
- noColor: util.readOnly(runtimeOptions.noColor),
- args: util.readOnly(ObjectFreeze(runtimeOptions.args)),
+ pid: util.readOnly(pid),
+ noColor: util.readOnly(noColor),
+ args: util.readOnly(ObjectFreeze(args)),
});
// Setup `Deno` global - we're actually overriding already
// existing global `Deno` with `Deno` namespace from "./deno.ts".
diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs
index ab06ab649..b50e91610 100644
--- a/runtime/web_worker.rs
+++ b/runtime/web_worker.rs
@@ -556,8 +556,7 @@ impl WebWorker {
// WebWorkers can have empty string as name.
{
let scope = &mut self.js_runtime.handle_scope();
- let options_v8 =
- deno_core::serde_v8::to_v8(scope, options.as_json()).unwrap();
+ let args = options.as_v8(scope);
let bootstrap_fn = self.bootstrap_fn_global.take().unwrap();
let bootstrap_fn = v8::Local::new(scope, bootstrap_fn);
let undefined = v8::undefined(scope);
@@ -568,7 +567,7 @@ impl WebWorker {
.unwrap()
.into();
bootstrap_fn
- .call(scope, undefined.into(), &[options_v8, name_str, id_str])
+ .call(scope, undefined.into(), &[args.into(), name_str, id_str])
.unwrap();
}
// TODO(bartlomieju): this could be done using V8 API, without calling `execute_script`.
diff --git a/runtime/worker.rs b/runtime/worker.rs
index 42874f209..a8fd6b1da 100644
--- a/runtime/worker.rs
+++ b/runtime/worker.rs
@@ -361,13 +361,12 @@ impl MainWorker {
pub fn bootstrap(&mut self, options: &BootstrapOptions) {
let scope = &mut self.js_runtime.handle_scope();
- let options_v8 =
- deno_core::serde_v8::to_v8(scope, options.as_json()).unwrap();
+ let args = options.as_v8(scope);
let bootstrap_fn = self.bootstrap_fn_global.take().unwrap();
let bootstrap_fn = v8::Local::new(scope, bootstrap_fn);
let undefined = v8::undefined(scope);
bootstrap_fn
- .call(scope, undefined.into(), &[options_v8])
+ .call(scope, undefined.into(), &[args.into()])
.unwrap();
}
diff --git a/runtime/worker_bootstrap.rs b/runtime/worker_bootstrap.rs
index 12abceca6..09725122c 100644
--- a/runtime/worker_bootstrap.rs
+++ b/runtime/worker_bootstrap.rs
@@ -1,7 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
-use deno_core::serde_json;
-use deno_core::serde_json::json;
+use deno_core::v8;
use deno_core::ModuleSpecifier;
use std::thread;
@@ -58,28 +57,135 @@ impl Default for BootstrapOptions {
}
impl BootstrapOptions {
- pub fn as_json(&self) -> serde_json::Value {
- json!({
- // Shared bootstrap args
- "args": self.args,
- "cpuCount": self.cpu_count,
- "debugFlag": self.debug_flag,
- "denoVersion": self.runtime_version,
- "locale": self.locale,
- "location": self.location,
- "noColor": self.no_color,
- "isTty": self.is_tty,
- "tsVersion": self.ts_version,
- "unstableFlag": self.unstable,
- // Web worker only
- "enableTestingFeaturesFlag": self.enable_testing_features,
- // Env values
- "pid": std::process::id(),
- "ppid": ppid(),
- "target": env!("TARGET"),
- "v8Version": deno_core::v8_version(),
- "userAgent": self.user_agent,
- "inspectFlag": self.inspect,
- })
+ pub fn as_v8<'s>(
+ &self,
+ scope: &mut v8::HandleScope<'s>,
+ ) -> v8::Local<'s, v8::Array> {
+ let array = v8::Array::new(scope, 17);
+
+ {
+ 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::Boolean::new(scope, self.debug_flag);
+ 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::Integer::new(scope, ppid() as i32);
+ array.set_index(scope, 11, val.into());
+ }
+
+ {
+ let val = v8::String::new_external_onebyte_static(
+ scope,
+ env!("TARGET").as_bytes(),
+ )
+ .unwrap();
+ array.set_index(scope, 12, 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, 13, val.into());
+ }
+
+ {
+ let val = v8::String::new_from_one_byte(
+ scope,
+ self.user_agent.as_bytes(),
+ v8::NewStringType::Normal,
+ )
+ .unwrap();
+ array.set_index(scope, 14, val.into());
+ }
+
+ {
+ let val = v8::Boolean::new(scope, self.inspect);
+ array.set_index(scope, 15, val.into());
+ }
+
+ {
+ let val = v8::Boolean::new(scope, self.enable_testing_features);
+ array.set_index(scope, 16, val.into());
+ }
+
+ array
}
}