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))
|
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]
|
||||||
|
|||||||
Reference in New Issue
Block a user