feat: cache IS_THUNK symbol

This commit is contained in:
2026-01-02 22:41:07 +08:00
parent 210923fd92
commit f1670e8397

View File

@@ -20,6 +20,38 @@ pub fn run(script: &str) -> Result<Value> {
ISOLATE.with_borrow_mut(|isolate| run_impl(script, isolate)) 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<v8::Local<'a, v8::Symbol>>,
}
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<v8::Local<'a, v8::Symbol>> {
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<Value> { fn run_impl(script: &str, isolate: &mut v8::Isolate) -> Result<Value> {
let handle_scope = std::pin::pin!(v8::HandleScope::new(isolate)); let handle_scope = std::pin::pin!(v8::HandleScope::new(isolate));
let handle_scope = &mut handle_scope.init(); let handle_scope = &mut handle_scope.init();
@@ -60,7 +92,11 @@ fn run_impl(script: &str, isolate: &mut v8::Isolate) -> Result<Value> {
}; };
match script.run(try_catch) { 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 => { None => {
if let Some(exception) = try_catch.exception() { if let Some(exception) = try_catch.exception() {
let exception_string = exception let exception_string = exception
@@ -78,10 +114,8 @@ fn run_impl(script: &str, isolate: &mut v8::Isolate) -> Result<Value> {
} }
} }
fn to_value<'a>( fn to_value<'a, 'b>(val: v8::Local<'a, v8::Value>, ctx: &RuntimeContext<'a, 'b>) -> Value {
val: v8::Local<'a, v8::Value>, let scope = ctx.scope;
scope: &v8::PinnedRef<'a, v8::HandleScope>,
) -> Value {
match () { match () {
_ if val.is_big_int() => { _ if val.is_big_int() => {
let (val, lossless) = val.to_big_int(scope).unwrap().i64_value(); let (val, lossless) = val.to_big_int(scope).unwrap().i64_value();
@@ -113,14 +147,14 @@ fn to_value<'a>(
let list = (0..len) let list = (0..len)
.map(|i| { .map(|i| {
let val = val.get_index(scope, i).unwrap(); let val = val.get_index(scope, i).unwrap();
to_value(val, scope) to_value(val, ctx)
}) })
.collect(); .collect();
Value::List(List::new(list)) Value::List(List::new(list))
} }
_ if val.is_function() => Value::Func, _ if val.is_function() => Value::Func,
_ if val.is_object() => { _ if val.is_object() => {
if is_thunk(val, scope) { if is_thunk(val, ctx) {
return Value::Thunk; return Value::Thunk;
} }
@@ -134,7 +168,7 @@ fn to_value<'a>(
let key = keys.get_index(scope, i).unwrap(); let key = keys.get_index(scope, i).unwrap();
let val = val.get(scope, key).unwrap(); let val = val.get(scope, key).unwrap();
let key = key.to_rust_string_lossy(scope); let key = key.to_rust_string_lossy(scope);
(Symbol::new(key), to_value(val, scope)) (Symbol::new(key), to_value(val, ctx))
}) })
.collect(); .collect();
Value::AttrSet(AttrSet::new(attrs)) Value::AttrSet(AttrSet::new(attrs))
@@ -143,29 +177,20 @@ fn to_value<'a>(
} }
} }
fn is_thunk<'a>( fn is_thunk<'a, 'b>(val: v8::Local<'a, v8::Value>, ctx: &RuntimeContext<'a, 'b>) -> bool {
val: v8::Local<'a, v8::Value>,
scope: &v8::PinnedRef<'a, v8::HandleScope>,
) -> bool {
if !val.is_object() { if !val.is_object() {
return false; return false;
} }
let global = scope.get_current_context().global(scope); // Use cached IS_THUNK symbol from context
let nix_key = v8::String::new(scope, "Nix").unwrap(); let is_thunk_sym = match ctx.is_thunk_symbol {
let nix_obj = match global.get(scope, nix_key.into()) { Some(sym) => sym,
Some(obj) if obj.is_object() => obj.to_object(scope).unwrap(), None => return false,
_ => 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,
}; };
let scope = ctx.scope;
let obj = val.to_object(scope).unwrap(); 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] #[test]