diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-04-19 00:52:12 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-19 00:52:12 +0200 |
commit | 40e157c005be192d6f241d5ee149d980d6b808aa (patch) | |
tree | 3b92ce14f9671ea788524735557aac567df44069 /core/realm.rs | |
parent | edca01c35e7f3f76ec98dd912314db16995e2a4f (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.rs | 73 |
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) } |