diff options
author | Aaron O'Mullan <aaron.omullan@gmail.com> | 2022-03-16 09:04:38 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-16 09:04:38 +0100 |
commit | 895e47429578f48d1e245a8889f9be10dc522a4b (patch) | |
tree | 674e13996a0e7e16177640a80d202754e7687a5e | |
parent | 697b60a335cad20f73e568c47d17564a6bd3fab7 (diff) |
cleanup(core): recursive get & ensure helpers (#13972)
-rw-r--r-- | core/bindings.rs | 26 | ||||
-rw-r--r-- | core/runtime.rs | 82 |
2 files changed, 61 insertions, 47 deletions
diff --git a/core/bindings.rs b/core/bindings.rs index 2c879c21a..6e85a57d4 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -153,9 +153,6 @@ pub fn initialize_context<'s>( let scope = &mut v8::ContextScope::new(scope, context); - let deno_key = v8::String::new(scope, "Deno").unwrap(); - let core_key = v8::String::new(scope, "core").unwrap(); - let ops_key = v8::String::new(scope, "ops").unwrap(); // Snapshot already registered `Deno.core.ops` but // extensions may provide ops that aren't part of the snapshot. // @@ -164,30 +161,18 @@ pub fn initialize_context<'s>( // tsc ops are static at snapshot time. if snapshot_loaded { // Grab Deno.core.ops object - let deno_val = global.get(scope, deno_key.into()).unwrap(); - let deno_val = v8::Local::<v8::Object>::try_from(deno_val) - .expect("`Deno` not in global scope."); - let core_val = deno_val.get(scope, core_key.into()).unwrap(); - let core_val = v8::Local::<v8::Object>::try_from(core_val) - .expect("`Deno.core` not in global scope"); - let ops_val = core_val.get(scope, ops_key.into()).unwrap(); - let ops_val = v8::Local::<v8::Object>::try_from(ops_val) - .expect("`Deno.core.ops` not in global scope"); + let ops_obj = JsRuntime::grab_global::<v8::Object>(scope, "Deno.core.ops") + .expect("Deno.core.ops to exist"); let raw_op_state = Rc::as_ptr(&op_state) as *const c_void; for op in ops { - set_func_raw(scope, ops_val, op.name, op.v8_fn_ptr, raw_op_state); + set_func_raw(scope, ops_obj, op.name, op.v8_fn_ptr, raw_op_state); } return scope.escape(context); } - // global.Deno = { core: { ops: {} } }; - let deno_val = v8::Object::new(scope); - global.set(scope, deno_key.into(), deno_val.into()); - let core_val = v8::Object::new(scope); - deno_val.set(scope, core_key.into(), core_val.into()); - let ops_val = v8::Object::new(scope); - core_val.set(scope, ops_key.into(), ops_val.into()); + // global.Deno = { core: { } }; + let core_val = JsRuntime::ensure_objs(scope, global, "Deno.core").unwrap(); // Bind functions to Deno.core.* set_func(scope, core_val, "refOp_", ref_op); @@ -245,6 +230,7 @@ pub fn initialize_context<'s>( set_func(scope, global, "queueMicrotask", queue_microtask); // Bind functions to Deno.core.ops.* + let ops_val = JsRuntime::ensure_objs(scope, global, "Deno.core.ops").unwrap(); let raw_op_state = Rc::as_ptr(&op_state) as *const c_void; for op in ops { set_func_raw(scope, ops_val, op.name, op.v8_fn_ptr, raw_op_state); diff --git a/core/runtime.rs b/core/runtime.rs index 8ec3dfb08..6ca586997 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -507,36 +507,64 @@ impl JsRuntime { Ok(()) } - /// Grab a Global handle to a function returned by the given expression - fn grab_fn( - scope: &mut v8::HandleScope, - code: &str, - ) -> v8::Global<v8::Function> { - let code = v8::String::new(scope, code).unwrap(); - let script = v8::Script::compile(scope, code, None).unwrap(); - let v8_value = script.run(scope).unwrap(); - let cb = v8::Local::<v8::Function>::try_from(v8_value).unwrap(); - v8::Global::new(scope, cb) - } - - fn grab_obj<'s>( + /// Grab a Global handle to a v8 value returned by the expression + pub(crate) fn grab<'s, T>( scope: &mut v8::HandleScope<'s>, - code: &str, - ) -> v8::Local<'s, v8::Object> { - let scope = &mut v8::EscapableHandleScope::new(scope); - let code = v8::String::new(scope, code).unwrap(); - let script = v8::Script::compile(scope, code, None).unwrap(); - let v8_value = script.run(scope).unwrap(); - let obj = v8::Local::<v8::Object>::try_from(v8_value).unwrap(); - scope.escape(obj) + root: v8::Local<'s, v8::Value>, + path: &str, + ) -> Option<v8::Local<'s, T>> + where + v8::Local<'s, T>: TryFrom<v8::Local<'s, v8::Value>, Error = v8::DataError>, + { + path + .split('.') + .fold(Some(root), |p, k| { + let p = v8::Local::<v8::Object>::try_from(p?).ok()?; + let k = v8::String::new(scope, k)?; + p.get(scope, k.into()) + })? + .try_into() + .ok() + } + + pub(crate) fn grab_global<'s, T>( + scope: &mut v8::HandleScope<'s>, + path: &str, + ) -> Option<v8::Local<'s, T>> + where + v8::Local<'s, T>: TryFrom<v8::Local<'s, v8::Value>, Error = v8::DataError>, + { + let context = scope.get_current_context(); + let global = context.global(scope); + Self::grab(scope, global.into(), path) + } + + pub(crate) fn ensure_objs<'s>( + scope: &mut v8::HandleScope<'s>, + root: v8::Local<'s, v8::Object>, + path: &str, + ) -> Option<v8::Local<'s, v8::Object>> { + path.split('.').fold(Some(root), |p, k| { + let k = v8::String::new(scope, k)?.into(); + match p?.get(scope, k) { + Some(v) if !v.is_null_or_undefined() => v.try_into().ok(), + _ => { + let o = v8::Object::new(scope); + p?.set(scope, k, o.into()); + Some(o) + } + } + }) } /// Grabs a reference to core.js' opresolve & syncOpsCache() fn init_cbs(&mut self) { - let mut scope = self.handle_scope(); - let recv_cb = Self::grab_fn(&mut scope, "Deno.core.opresolve"); + let scope = &mut self.handle_scope(); + let recv_cb = + Self::grab_global::<v8::Function>(scope, "Deno.core.opresolve").unwrap(); + let recv_cb = v8::Global::new(scope, recv_cb); // Put global handles in state - let state_rc = JsRuntime::state(&scope); + let state_rc = JsRuntime::state(scope); let mut state = state_rc.borrow_mut(); state.js_recv_cb.replace(recv_cb); } @@ -612,11 +640,11 @@ impl JsRuntime { // TODO(@AaronO): make ops stable across snapshots { let scope = &mut self.handle_scope(); - let obj = Self::grab_obj(scope, "Deno.core.ops"); - let names = obj.get_own_property_names(scope).unwrap(); + let o = Self::grab_global::<v8::Object>(scope, "Deno.core.ops").unwrap(); + let names = o.get_own_property_names(scope).unwrap(); for i in 0..names.length() { let key = names.get_index(scope, i).unwrap(); - obj.delete(scope, key); + o.delete(scope, key); } } |