mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
153 lines
4.5 KiB
Rust
153 lines
4.5 KiB
Rust
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
|
use oxide_types::object::JsObject;
|
|
use oxide_types::value::JsValue;
|
|
|
|
use crate::native::{NativeFn, NativeResult};
|
|
use crate::vm::Vm;
|
|
|
|
fn invoke_target(
|
|
vm: &mut Vm,
|
|
target_val: JsValue,
|
|
this_val: JsValue,
|
|
arg_regs: &[u8],
|
|
) -> NativeResult {
|
|
if !target_val.is_object() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let tgt_ptr = target_val.as_js_object_ptr();
|
|
if tgt_ptr.is_null() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let tgt = unsafe { &*tgt_ptr };
|
|
if !tgt.is_function() || tgt.native_fn().is_none() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let func: NativeFn = unsafe { std::mem::transmute(tgt.native_fn().unwrap()) };
|
|
|
|
let base = 230u8;
|
|
let n = arg_regs.len();
|
|
let mut args_buf = [0u8; 64];
|
|
args_buf[0] = base;
|
|
vm.set_reg(base, this_val);
|
|
for (i, ®) in arg_regs.iter().enumerate().take(n.min(63)) {
|
|
vm.set_reg(base + 1 + i as u8, vm.reg(reg));
|
|
args_buf[i + 1] = base + 1 + i as u8;
|
|
}
|
|
|
|
func(vm, &args_buf[..n + 1])
|
|
}
|
|
|
|
fn bind_dispatcher(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
|
let wrapper_val = vm.reg(254);
|
|
let wrapper = unsafe { &*wrapper_val.as_js_object_ptr() };
|
|
let bound_target = wrapper.get_prop(0);
|
|
let bound_this = wrapper.get_prop(1);
|
|
|
|
let n = args.len().saturating_sub(1);
|
|
let base = 230u8;
|
|
let mut args_buf = [0u8; 64];
|
|
args_buf[0] = base;
|
|
vm.set_reg(base, bound_this);
|
|
for (i, ®) in args.iter().skip(1).enumerate().take(n.min(63)) {
|
|
vm.set_reg(base + 1 + i as u8, vm.reg(reg));
|
|
args_buf[i + 1] = base + 1 + i as u8;
|
|
}
|
|
|
|
if !bound_target.is_object() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let tgt_ptr = bound_target.as_js_object_ptr();
|
|
if tgt_ptr.is_null() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let tgt = unsafe { &*tgt_ptr };
|
|
if !tgt.is_function() || tgt.native_fn().is_none() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let func: NativeFn = unsafe { std::mem::transmute(tgt.native_fn().unwrap()) };
|
|
func(vm, &args_buf[..n + 1])
|
|
}
|
|
|
|
pub fn function_call(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
|
if args.is_empty() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let target_val = vm.reg(args[0]);
|
|
let this_val = if args.len() > 1 {
|
|
vm.reg(args[1])
|
|
} else {
|
|
JsValue::undefined()
|
|
};
|
|
let arg_regs: Vec<u8> = args.iter().skip(2).copied().collect();
|
|
invoke_target(vm, target_val, this_val, &arg_regs)
|
|
}
|
|
|
|
pub fn function_apply(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
|
if args.is_empty() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let target_val = vm.reg(args[0]);
|
|
let this_val = if args.len() > 1 {
|
|
vm.reg(args[1])
|
|
} else {
|
|
JsValue::undefined()
|
|
};
|
|
|
|
let arg_regs: Vec<u8>;
|
|
if args.len() > 2 {
|
|
let arr_val = vm.reg(args[2]);
|
|
if arr_val.is_object() {
|
|
let arr_ptr = arr_val.as_js_object_ptr();
|
|
if !arr_ptr.is_null() {
|
|
let arr = unsafe { &*arr_ptr };
|
|
if arr.is_array() {
|
|
let n = arr.prop_count() as usize;
|
|
let base = 200u8;
|
|
arg_regs = (0..n).map(|i| base + i as u8).collect();
|
|
for i in 0..n {
|
|
vm.set_reg(base + i as u8, arr.get_prop(i as u8));
|
|
}
|
|
} else {
|
|
arg_regs = Vec::new();
|
|
}
|
|
} else {
|
|
arg_regs = Vec::new();
|
|
}
|
|
} else {
|
|
arg_regs = Vec::new();
|
|
}
|
|
} else {
|
|
arg_regs = Vec::new();
|
|
}
|
|
invoke_target(vm, target_val, this_val, &arg_regs)
|
|
}
|
|
|
|
pub fn function_bind(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
|
if args.is_empty() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let target_val = vm.reg(args[0]);
|
|
if !target_val.is_object() {
|
|
return Err(JsValue::undefined());
|
|
}
|
|
let bound_this = if args.len() > 1 {
|
|
vm.reg(args[1])
|
|
} else {
|
|
JsValue::undefined()
|
|
};
|
|
|
|
let wrapper = vm
|
|
.epoch()
|
|
.alloc(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null()));
|
|
unsafe {
|
|
(*wrapper).set_function(true);
|
|
(*wrapper).set_native_fn(Some(bind_dispatcher as *const ()));
|
|
(*wrapper).set_native_arg_count(0);
|
|
(*wrapper).set_prop_count(2);
|
|
(*wrapper).set_inline_prop(0, target_val);
|
|
(*wrapper).set_inline_prop(1, bound_this);
|
|
}
|
|
|
|
Ok(JsValue::from_js_object(wrapper))
|
|
}
|