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))
}
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> {
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<Value> {
};
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<Value> {
}
}
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]