summaryrefslogtreecommitdiff
path: root/core/realm.rs
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-04-19 00:52:12 +0200
committerGitHub <noreply@github.com>2023-04-19 00:52:12 +0200
commit40e157c005be192d6f241d5ee149d980d6b808aa (patch)
tree3b92ce14f9671ea788524735557aac567df44069 /core/realm.rs
parentedca01c35e7f3f76ec98dd912314db16995e2a4f (diff)
refactor(core): store v8::Global<v8::Context> in an Rc (#18749)
Alternative to https://github.com/denoland/deno/pull/18726. This was suggested by @piscisaureus. It's a bit ugly, but it does the work and makes cloning `JsRealm` very cheap, while not requiring invasive changes. Also managed to remove some vector and `v8::Global` clones which yields about 5% improvement in the "async_ops_deferred.js" benchmark. This PR: ``` time 1689 ms rate 592066 time 1722 ms rate 580720 time 1629 ms rate 613873 time 1578 ms rate 633713 time 1585 ms rate 630914 time 1574 ms rate 635324 ``` `main` branch: ``` time 1687 ms rate 592768 time 1676 ms rate 596658 time 1651 ms rate 605693 time 1652 ms rate 605326 time 1638 ms rate 610500 ```
Diffstat (limited to 'core/realm.rs')
-rw-r--r--core/realm.rs73
1 files changed, 61 insertions, 12 deletions
diff --git a/core/realm.rs b/core/realm.rs
index 1595d9160..8e2d932b5 100644
--- a/core/realm.rs
+++ b/core/realm.rs
@@ -8,21 +8,43 @@ use anyhow::Error;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::HashSet;
+use std::hash::BuildHasherDefault;
+use std::hash::Hasher;
+use std::marker::PhantomData;
use std::option::Option;
use std::rc::Rc;
use v8::HandleScope;
use v8::Local;
+// Hasher used for `unrefed_ops`. Since these are rolling i32, there's no
+// need to actually hash them.
+#[derive(Default)]
+pub(crate) struct IdentityHasher(u64, PhantomData<i32>);
+
+impl Hasher for IdentityHasher {
+ fn write_i32(&mut self, i: i32) {
+ self.0 = i as u64;
+ }
+
+ fn finish(&self) -> u64 {
+ self.0
+ }
+
+ fn write(&mut self, _bytes: &[u8]) {
+ unreachable!()
+ }
+}
+
#[derive(Default)]
pub(crate) struct ContextState {
- pub(crate) js_event_loop_tick_cb: Option<v8::Global<v8::Function>>,
- pub(crate) js_build_custom_error_cb: Option<v8::Global<v8::Function>>,
- pub(crate) js_promise_reject_cb: Option<v8::Global<v8::Function>>,
- pub(crate) js_format_exception_cb: Option<v8::Global<v8::Function>>,
- pub(crate) js_wasm_streaming_cb: Option<v8::Global<v8::Function>>,
+ pub(crate) js_event_loop_tick_cb: Option<Rc<v8::Global<v8::Function>>>,
+ pub(crate) js_build_custom_error_cb: Option<Rc<v8::Global<v8::Function>>>,
+ pub(crate) js_promise_reject_cb: Option<Rc<v8::Global<v8::Function>>>,
+ pub(crate) js_format_exception_cb: Option<Rc<v8::Global<v8::Function>>>,
+ pub(crate) js_wasm_streaming_cb: Option<Rc<v8::Global<v8::Function>>>,
pub(crate) pending_promise_rejections:
HashMap<v8::Global<v8::Promise>, v8::Global<v8::Value>>,
- pub(crate) unrefed_ops: HashSet<i32>,
+ pub(crate) unrefed_ops: HashSet<i32, BuildHasherDefault<IdentityHasher>>,
// We don't explicitly re-read this prop but need the slice to live alongside
// the context
pub(crate) op_ctxs: Box<[OpCtx]>,
@@ -73,16 +95,18 @@ pub(crate) struct ContextState {
/// keep the underlying V8 context alive even if it would have otherwise been
/// garbage collected.
#[derive(Clone)]
-pub struct JsRealm(v8::Global<v8::Context>);
+pub struct JsRealm(Rc<v8::Global<v8::Context>>);
impl JsRealm {
pub fn new(context: v8::Global<v8::Context>) -> Self {
- JsRealm(context)
+ JsRealm(Rc::new(context))
}
+ #[inline(always)]
pub fn context(&self) -> &v8::Global<v8::Context> {
&self.0
}
+ #[inline(always)]
pub(crate) fn state(
&self,
isolate: &mut v8::Isolate,
@@ -95,6 +119,7 @@ impl JsRealm {
.clone()
}
+ #[inline(always)]
pub(crate) fn state_from_scope(
scope: &mut v8::HandleScope,
) -> Rc<RefCell<ContextState>> {
@@ -106,11 +131,12 @@ impl JsRealm {
}
/// For info on the [`v8::Isolate`] parameter, check [`JsRealm#panics`].
+ #[inline(always)]
pub fn handle_scope<'s>(
&self,
isolate: &'s mut v8::Isolate,
) -> v8::HandleScope<'s> {
- v8::HandleScope::with_context(isolate, &self.0)
+ v8::HandleScope::with_context(isolate, &*self.0)
}
/// For info on the [`v8::Isolate`] parameter, check [`JsRealm#panics`].
@@ -212,12 +238,36 @@ impl JsRealm {
}
// TODO(andreubotella): `mod_evaluate`, `load_main_module`, `load_side_module`
+}
- pub(crate) fn check_promise_rejections(
+pub struct JsRealmLocal<'s>(v8::Local<'s, v8::Context>);
+impl<'s> JsRealmLocal<'s> {
+ pub fn new(context: v8::Local<'s, v8::Context>) -> Self {
+ JsRealmLocal(context)
+ }
+
+ #[inline(always)]
+ pub fn context(&self) -> v8::Local<v8::Context> {
+ self.0
+ }
+
+ #[inline(always)]
+ pub(crate) fn state(
&self,
isolate: &mut v8::Isolate,
+ ) -> Rc<RefCell<ContextState>> {
+ self
+ .context()
+ .get_slot::<Rc<RefCell<ContextState>>>(isolate)
+ .unwrap()
+ .clone()
+ }
+
+ pub(crate) fn check_promise_rejections(
+ &self,
+ scope: &mut v8::HandleScope,
) -> Result<(), Error> {
- let context_state_rc = self.state(isolate);
+ let context_state_rc = self.state(scope);
let mut context_state = context_state_rc.borrow_mut();
if context_state.pending_promise_rejections.is_empty() {
@@ -238,7 +288,6 @@ impl JsRealm {
.unwrap();
drop(context_state);
- let scope = &mut self.handle_scope(isolate);
let exception = v8::Local::new(scope, handle);
exception_to_err_result(scope, exception, true)
}