use oxide_kernel::shape_forge::EMPTY_SHAPE_ID; use oxide_types::object::{JsObject, NativeFnPtr, PropAttributes}; use oxide_types::value::JsValue; use oxide_runtime_api::{to_integer_or_infinity, to_string_full, NativeResult, VmHost}; fn invoke_target(vm: &mut H, target_val: JsValue, this_val: JsValue, arg_regs: &[u8]) -> NativeResult { let args: Vec = arg_regs.iter().map(|&r| vm.reg(r)).collect(); NativeResult::TailCall { callee: target_val, this: this_val, args, } } /// `Function(...)` / `new Function(...)` 构造器:动态编译一个匿名函数。 /// /// 除最后一个实参为函数体外,其余实参为形参名;无实参时函数体为空串。 /// 编译成功返回函数对象,语法错误抛 SyntaxError,实参 ToString 失败抛 TypeError。 pub fn function_constructor(vm: &mut H, args: &[u8]) -> NativeResult { let arg_regs = &args[1..]; let (param_regs, body_reg) = if arg_regs.is_empty() { (vec![], None) } else { let (head, tail) = arg_regs.split_at(arg_regs.len() - 1); (head.to_vec(), Some(tail[0])) }; let mut params = Vec::with_capacity(param_regs.len()); for &r in ¶m_regs { match to_string_full(vm.reg(r), vm) { Ok(s) => params.push(s), Err(e) => return NativeResult::Err(to_string_error_value(vm, &e)), } } let body = match body_reg { Some(r) => match to_string_full(vm.reg(r), vm) { Ok(s) => s, Err(e) => return NativeResult::Err(to_string_error_value(vm, &e)), }, None => String::new(), }; match vm.create_dynamic_function(¶ms, &body) { Ok(func) => NativeResult::Ok(func), Err(msg) => NativeResult::Err(crate::error::create_syntax_error(vm, &msg)), } } /// 把 ToString 强制转换错误转成可抛异常值:用户回调抛出的原始值优先原样传播 /// (经 `last_uncaught_value` 侧通道),否则按普通 TypeError 处理。 fn to_string_error_value(vm: &mut H, msg: &str) -> JsValue { vm.take_uncaught_value() .unwrap_or_else(|| crate::error::create_type_error(vm, msg)) } fn bind_dispatcher(vm: &mut H, args: &[u8]) -> NativeResult { let wrapper_val = vm.reg(254); let wrapper = unsafe { &*wrapper_val.as_js_object_ptr() }; // dense 布局:[length, name, caller, arguments, target, thisArg, ...boundArgs]—— // 前 4 槽是 shape 属性(length/name 数据 + caller/arguments 访问器占位), // 绑定状态从槽位 4 起(shape 槽位与 dense 下标对齐)。 let props = wrapper.hash_props_vec().cloned().unwrap_or_default(); let bound_target = props.get(4).copied().unwrap_or(JsValue::undefined()); let bound_this = props.get(5).copied().unwrap_or(JsValue::undefined()); // 拼接调用实参:绑定实参(props[6..])在前,本次调用实参(跳过 args[0] // 即绑定包装器的 receiver)在后,与规范的"绑定实参先于调用实参"一致。 let mut call_args: Vec = props.iter().skip(6).copied().collect(); for &r in args.iter().skip(1) { call_args.push(vm.reg(r)); } NativeResult::TailCall { callee: bound_target, this: bound_this, args: call_args, } } /// `Function.prototype.call(thisArg, ...args)`:以指定 this 调用目标函数。 /// 返回 TailCall 让 VM 继续执行目标函数体。 pub fn function_call(vm: &mut H, args: &[u8]) -> NativeResult { if args.is_empty() { return NativeResult::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 = args.iter().skip(2).copied().collect(); invoke_target(vm, target_val, this_val, &arg_regs) } /// `Function.prototype.apply(thisArg, argsArray)`:以指定 this 和参数数组调用目标函数。 /// 数组元素拷入寄存器(上限受寄存器空间限制,最多 55 个参数)。 pub fn function_apply(vm: &mut H, args: &[u8]) -> NativeResult { if args.is_empty() { return NativeResult::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; 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 max_args = 55usize; // base=200,255 号寄存器之前的安全上限。 let n = arr.prop_count() as usize; let n = n.min(max_args); 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_at(i)); } } 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) } /// `Function.prototype.bind(thisArg, ...args)`:返回绑定 this 与前置实参的新包装函数, /// 调用时通过 `bind_dispatcher` 把绑定实参拼到调用实参前转发到原目标。非函数目标抛 TypeError。 pub fn function_bind(vm: &mut H, args: &[u8]) -> NativeResult { if args.is_empty() { return NativeResult::Err(crate::error::create_type_error( vm, "Function.prototype.bind called on null or undefined", )); } let target_val = vm.reg(args[0]); if !target_val.is_object() || target_val.as_js_object_ptr().is_null() || !unsafe { &*target_val.as_js_object_ptr() }.is_function() { return NativeResult::Err(crate::error::create_type_error( vm, "Function.prototype.bind called on non-function", )); } let bound_this = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; let bound_arg_count = args.len().saturating_sub(2); // bound 函数 [[Prototype]] 为 Function.prototype(BoundFunctionCreate 语义)。 let fn_proto_val = JsValue::from_js_object(vm.session().builtin_world().function_proto.as_ptr() as *mut JsObject); let wrapper = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); unsafe { (*wrapper).set_function(true); (*wrapper).set_native_fn(Some(NativeFnPtr::from_raw(bind_dispatcher:: as *const ()))); // 绑定实参个数记入 native_arg_count,与 Function.length 语义一致。 (*wrapper).set_native_arg_count(bound_arg_count as u8); } // length/name 先定义占 dense 槽位 0/1(shape 属性),绑定状态 [target, thisArg, // ...boundArgs] 随后从槽位 2 起存放,保证 shape 槽位与 dense 下标对齐。 let length_si = vm.kernel_core().perm_interner().intern("length").0; let name_si = vm.kernel_core().perm_interner().intern("name").0; let caller_si = vm.kernel_core().perm_interner().intern("caller").0; let arguments_si = vm.kernel_core().perm_interner().intern("arguments").0; let attrs = PropAttributes::new(false, false, true); // bound 函数的 caller/arguments 是受限访问器:读写一律抛 TypeError(poisoned)。 let thrower = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto_val)); unsafe { (*thrower).set_function(true); (*thrower).set_native_fn(Some(NativeFnPtr::from_raw(bound_restricted_thrower:: as *const ()))); } let thrower_val = JsValue::from_js_object(thrower); // 全部 shape 属性(length/name/caller/arguments)须先于状态数据定义完成, // 保证 shape 槽位与 dense 下标对齐,再 push [target, thisArg, ...boundArgs]。 unsafe { let wrapper_ref = &mut *wrapper; let target_obj = &*target_val.as_js_object_ptr(); let target_length = vm .resolve_property(target_obj, length_si) .map(to_integer_or_infinity) .unwrap_or(0.0); // length = max(0, target.length - boundArgs);target.length 为 +∞ 时保持 +∞。 let length = if target_length == f64::INFINITY { f64::INFINITY } else { (target_length - bound_arg_count as f64).max(0.0) }; // 规范 length 无上界:i32 装得下用 int,否则(如 2^31、MAX_SAFE_INTEGER)用 float。 let length_val = if length <= i32::MAX as f64 { JsValue::int(length as i32) } else { JsValue::float(length) }; if let Err(e) = vm.define_data_property(wrapper_ref, length_si, length_val, attrs) { return NativeResult::Err(crate::error::create_type_error(vm, &e)); } let target_name = vm .resolve_property(target_obj, name_si) .and_then(|v| vm.lookup_str(v)) .unwrap_or_default(); let name_val = vm.new_string(&format!("bound {target_name}")); if let Err(e) = vm.define_data_property(wrapper_ref, name_si, name_val, attrs) { return NativeResult::Err(crate::error::create_type_error(vm, &e)); } if let Err(e) = vm.define_accessor_property(wrapper_ref, caller_si, thrower_val, thrower_val, attrs) { return NativeResult::Err(crate::error::create_type_error(vm, &e)); } if let Err(e) = vm.define_accessor_property(wrapper_ref, arguments_si, thrower_val, thrower_val, attrs) { return NativeResult::Err(crate::error::create_type_error(vm, &e)); } } unsafe { let props = (*wrapper).ensure_hash_props(); props.push(target_val); props.push(bound_this); for &r in args.iter().skip(2) { props.push(vm.reg(r)); } } NativeResult::Ok(JsValue::from_js_object(wrapper)) } /// bound 函数 caller/arguments 的受限访问器:任何访问(get/set)都抛 TypeError。 fn bound_restricted_thrower(vm: &mut H, _args: &[u8]) -> NativeResult { NativeResult::Err(crate::error::create_type_error( vm, "'caller' and 'arguments' are restricted on bound functions", )) } /// `Function.prototype.toString`:返回 `function name() { [native code] }` /// 或 `[bytecode]` 形式;函数名取自 `name` 属性或字节码子模块名。 pub fn function_to_string(vm: &mut H, args: &[u8]) -> NativeResult { let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); if !this_val.is_object() { return NativeResult::Err(crate::error::create_type_error( vm, "Function.prototype.toString called on non-function", )); } let func = unsafe { &*this_val.as_js_object_ptr() }; if !func.is_function() { return NativeResult::Err(crate::error::create_type_error( vm, "Function.prototype.toString called on non-function", )); } let name_si = vm.kernel_core().perm_interner().intern("name").0; let name = vm .resolve_property(func, name_si) .and_then(|v| vm.lookup_str(v)) .unwrap_or_else(|| { let sub_idx = func.sub_module_index(); if sub_idx > 0 { vm.sub_module_function_name((sub_idx - 1) as u16) } else { String::new() } }); let body = if func.native_fn().is_some() { "[native code]" } else { "[bytecode]" }; let result = if name.is_empty() { format!("function () {{ {body} }}") } else { format!("function {name}() {{ {body} }}") }; NativeResult::Ok(vm.new_string(&result)) }