From f1670e83975ae3152fa5a6560e3049ef67575a84 Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Fri, 2 Jan 2026 22:41:07 +0800 Subject: [PATCH] feat: cache IS_THUNK symbol --- nix-js/src/runtime.rs | 73 +++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/nix-js/src/runtime.rs b/nix-js/src/runtime.rs index 8cbf20f..4e0fc72 100644 --- a/nix-js/src/runtime.rs +++ b/nix-js/src/runtime.rs @@ -20,6 +20,38 @@ pub fn run(script: &str) -> Result { ISOLATE.with_borrow_mut(|isolate| run_impl(script, isolate)) } +struct RuntimeContext<'a, 'b> { + scope: &'a v8::PinnedRef<'a, v8::HandleScope<'b>>, + is_thunk_symbol: Option>, +} + +impl<'a, 'b> RuntimeContext<'a, 'b> { + fn new(scope: &'a v8::PinnedRef<'a, v8::HandleScope<'b>>) -> Self { + let is_thunk_symbol = Self::get_is_thunk_symbol(scope); + Self { + scope, + is_thunk_symbol, + } + } + + fn get_is_thunk_symbol( + scope: &v8::PinnedRef<'a, v8::HandleScope<'b>>, + ) -> Option> { + let global = scope.get_current_context().global(scope); + let nix_key = v8::String::new(scope, "Nix")?; + let nix_obj = global.get(scope, nix_key.into())?.to_object(scope)?; + + let is_thunk_sym_key = v8::String::new(scope, "IS_THUNK")?; + let is_thunk_sym = nix_obj.get(scope, is_thunk_sym_key.into())?; + + if is_thunk_sym.is_symbol() { + is_thunk_sym.try_cast().ok() + } else { + None + } + } +} + fn run_impl(script: &str, isolate: &mut v8::Isolate) -> Result { let handle_scope = std::pin::pin!(v8::HandleScope::new(isolate)); let handle_scope = &mut handle_scope.init(); @@ -60,7 +92,11 @@ fn run_impl(script: &str, isolate: &mut v8::Isolate) -> Result { }; match script.run(try_catch) { - Some(result) => Ok(to_value(result, try_catch)), + Some(result) => { + // Initialize runtime context once before conversion + let ctx = RuntimeContext::new(try_catch); + Ok(to_value(result, &ctx)) + } None => { if let Some(exception) = try_catch.exception() { let exception_string = exception @@ -78,10 +114,8 @@ fn run_impl(script: &str, isolate: &mut v8::Isolate) -> Result { } } -fn to_value<'a>( - val: v8::Local<'a, v8::Value>, - scope: &v8::PinnedRef<'a, v8::HandleScope>, -) -> Value { +fn to_value<'a, 'b>(val: v8::Local<'a, v8::Value>, ctx: &RuntimeContext<'a, 'b>) -> Value { + let scope = ctx.scope; match () { _ if val.is_big_int() => { let (val, lossless) = val.to_big_int(scope).unwrap().i64_value(); @@ -113,14 +147,14 @@ fn to_value<'a>( let list = (0..len) .map(|i| { let val = val.get_index(scope, i).unwrap(); - to_value(val, scope) + to_value(val, ctx) }) .collect(); Value::List(List::new(list)) } _ if val.is_function() => Value::Func, _ if val.is_object() => { - if is_thunk(val, scope) { + if is_thunk(val, ctx) { return Value::Thunk; } @@ -134,7 +168,7 @@ fn to_value<'a>( let key = keys.get_index(scope, i).unwrap(); let val = val.get(scope, key).unwrap(); let key = key.to_rust_string_lossy(scope); - (Symbol::new(key), to_value(val, scope)) + (Symbol::new(key), to_value(val, ctx)) }) .collect(); Value::AttrSet(AttrSet::new(attrs)) @@ -143,29 +177,20 @@ fn to_value<'a>( } } -fn is_thunk<'a>( - val: v8::Local<'a, v8::Value>, - scope: &v8::PinnedRef<'a, v8::HandleScope>, -) -> bool { +fn is_thunk<'a, 'b>(val: v8::Local<'a, v8::Value>, ctx: &RuntimeContext<'a, 'b>) -> bool { if !val.is_object() { return false; } - let global = scope.get_current_context().global(scope); - let nix_key = v8::String::new(scope, "Nix").unwrap(); - let nix_obj = match global.get(scope, nix_key.into()) { - Some(obj) if obj.is_object() => obj.to_object(scope).unwrap(), - _ => return false, - }; - - let is_thunk_sym_key = v8::String::new(scope, "IS_THUNK").unwrap(); - let is_thunk_sym = match nix_obj.get(scope, is_thunk_sym_key.into()) { - Some(sym) if sym.is_symbol() => sym, - _ => return false, + // Use cached IS_THUNK symbol from context + let is_thunk_sym = match ctx.is_thunk_symbol { + Some(sym) => sym, + None => return false, }; + let scope = ctx.scope; let obj = val.to_object(scope).unwrap(); - matches!(obj.get(scope, is_thunk_sym), Some(v) if v.is_true()) + matches!(obj.get(scope, is_thunk_sym.into()), Some(v) if v.is_true()) } #[test]