feat: cache IS_THUNK symbol
This commit is contained in:
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user