diff --git a/crates/oxide_builtins/src/object.rs b/crates/oxide_builtins/src/object.rs index c9d2176..522d6fc 100644 --- a/crates/oxide_builtins/src/object.rs +++ b/crates/oxide_builtins/src/object.rs @@ -55,8 +55,42 @@ pub(crate) fn walk_own_keys(vm: &H, obj: &JsObject) -> Vec<(u32, u32) } /// JS `Object()` 构造逻辑:创建空对象(prototype 为 null,由 VM 补装内置原型)。 -pub fn object_constructor(vm: &mut H, _args: &[u8]) -> NativeResult { - let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::null())); +pub fn object_constructor(vm: &mut H, args: &[u8]) -> NativeResult { + let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let object_proto = vm.session().builtin_world().object_proto.as_ptr() as *mut JsObject; + // 对象参数原样返回;原始值参数创建对应 boxed 对象(规范 ToObject)。 + if val.is_object() { + return NativeResult::Ok(val); + } + if val.is_null() || val.is_undefined() { + let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto))); + return NativeResult::Ok(JsValue::from_js_object(obj)); + } + if val.is_int() || val.is_double() { + let proto = vm.session().builtin_world().number_proto.as_ptr() as *mut JsObject; + let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto))); + let obj_ref = unsafe { &mut *obj }; + obj_ref.type_tag = JsObject::OBJ_TYPE_NUMBER_OBJ; + obj_ref.set_prop_at(0, val); + return NativeResult::Ok(JsValue::from_js_object(obj)); + } + if val.is_string() { + let proto = vm.session().builtin_world().string_proto.as_ptr() as *mut JsObject; + let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto))); + let obj_ref = unsafe { &mut *obj }; + obj_ref.type_tag = JsObject::OBJ_TYPE_STRING_OBJ; + obj_ref.set_prop_at(0, val); + return NativeResult::Ok(JsValue::from_js_object(obj)); + } + if val.is_bool() { + let proto = vm.session().builtin_world().boolean_proto.as_ptr() as *mut JsObject; + let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto))); + let obj_ref = unsafe { &mut *obj }; + obj_ref.type_tag = JsObject::OBJ_TYPE_BOOLEAN_OBJ; + obj_ref.set_prop_at(0, val); + return NativeResult::Ok(JsValue::from_js_object(obj)); + } + let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto))); NativeResult::Ok(JsValue::from_js_object(obj)) } @@ -849,3 +883,4 @@ pub fn object_values(vm: &mut H, args: &[u8]) -> NativeResult { } NativeResult::Ok(JsValue::from_js_object(arr)) } + diff --git a/crates/oxide_builtins/src/string.rs b/crates/oxide_builtins/src/string.rs index b3f6c41..33f226e 100644 --- a/crates/oxide_builtins/src/string.rs +++ b/crates/oxide_builtins/src/string.rs @@ -8,12 +8,13 @@ use oxide_runtime_api::{NativeResult, VmHost}; use crate::builtins_debug; use crate::builtins_error; -fn this_string(vm: &H, args: &[u8]) -> String { +fn this_string(vm: &mut H, args: &[u8]) -> String { let this_val = vm.reg(args[0]); if this_val.is_null() || this_val.is_undefined() { String::new() // caller should check and throw TypeError } else { - oxide_runtime_api::to_string(this_val) + // 对象 this 须经 ToString 完整转换(boxed Number/String 等取内部原始值)。 + oxide_runtime_api::to_string_full(this_val, vm).unwrap_or_else(|_| String::new()) } }