mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
docs: 补齐数组与对象工具族注释并清除乱码
This commit is contained in:
@@ -72,8 +72,13 @@ pub(crate) fn get_this_array_ref<H: VmHost>(vm: &mut H, val: JsValue) -> Result<
|
||||
Ok(ptr)
|
||||
}
|
||||
|
||||
/// 接受 array 或 ArrayLike (object with length property) — for read-only methods.
|
||||
/// 返回 (object_ptr, length, is_real_array)
|
||||
/// 取 this 为真数组或类数组对象(带 length 属性的普通对象),按规范读取长度,
|
||||
/// 返回 (对象指针, 长度, 是否为真数组),供只读方法族(values/entries/keys/iterator 等)共用。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. this 非对象(null/undefined/原始值)→ TypeError。
|
||||
/// 2. 按规范 Get 语义读 length(getter 抛错向上传播,不走 prop_count 直读)。
|
||||
/// 3. ToLength:ToIntegerOrInfinity 后负数与 NaN 归 0,上限 2^53-1。
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_this_arraylike<H: VmHost>(vm: &mut H, val: JsValue) -> Result<(*mut JsObject, usize, bool), JsValue> {
|
||||
if !val.is_object() {
|
||||
@@ -101,7 +106,7 @@ pub(crate) fn get_this_arraylike<H: VmHost>(vm: &mut H, val: JsValue) -> Result<
|
||||
Ok(v) => v,
|
||||
Err(msg) => return Err(from_engine_error(vm, &msg)),
|
||||
};
|
||||
// ToLength:min(max(0, ToIntegerOrInfinity(len)), 2**53-1)
|
||||
// ToLength:len 先按 ToIntegerOrInfinity 取整,负数与 NaN 归 0,上限 2^53-1。
|
||||
let len = if len_num.is_nan() || len_num <= 0.0 {
|
||||
0
|
||||
} else {
|
||||
@@ -113,10 +118,10 @@ pub(crate) fn get_this_arraylike<H: VmHost>(vm: &mut H, val: JsValue) -> Result<
|
||||
/// 从 arraylike 读取 index 位置元素(按规范 Get:访问器/原型链/异常完整传播)。
|
||||
#[inline(always)]
|
||||
pub(crate) fn arraylike_get<H: VmHost>(vm: &mut H, ptr: *mut JsObject, i: usize) -> Result<JsValue, JsValue> {
|
||||
// 真数组密集直读快路径:无元素 meta(无 hole / accessor,O(1) 空指针判定)且
|
||||
// 索引在元素区内时,直接读数据槽,免每元素构造数字串 + 属性键转换。
|
||||
// 语义与 ordinary_get 一致:`array_elements_meta_vec().is_none()` 保证该索引
|
||||
// 恒为数据属性(见 vm_props.rs ordinary_get_inner 数组分支)。
|
||||
// 真数组密集直读快路径:无元素元信息表(记录 hole/accessor 的可选侧表,
|
||||
// 空指针判定为 O(1))且索引在元素区内时,直接读数据槽,免每元素构造数字串
|
||||
// + 属性键转换。语义与 ordinary_get 的数组分支一致:无元素元信息表保证该
|
||||
// 索引恒为数据属性,直读数据槽与规范 Get 结果相同。
|
||||
let obj = unsafe { &*ptr };
|
||||
if obj.is_array() && obj.array_elements_meta_vec().is_none() && i < obj.array_prop_count as usize {
|
||||
return Ok(obj.get_prop_at(i));
|
||||
@@ -188,6 +193,7 @@ pub(crate) fn is_constructor_value(c: JsValue) -> bool {
|
||||
&& !c_obj.is_arrow()
|
||||
&& !(c_obj.native_fn().is_some() && c_obj.type_tag != JsObject::OBJ_TYPE_CONSTRUCTOR)
|
||||
}
|
||||
/// 校验回调参数为可调用函数对象(判空与 is_function 均须通过),不是则抛 TypeError。
|
||||
pub(crate) fn require_callback<H: VmHost>(vm: &mut H, callback_val: JsValue) -> Result<JsValue, JsValue> {
|
||||
if !callback_val.is_object() {
|
||||
return Err(array_type_error(vm, "callback is not a function"));
|
||||
@@ -209,7 +215,8 @@ pub(crate) fn create_new_array<H: VmHost>(vm: &mut H, n: usize) -> *mut JsObject
|
||||
))
|
||||
}
|
||||
|
||||
/// ArrayCreate ?????length > 2**32 - 1 ? RangeError??????/???????
|
||||
/// ArrayCreate 前置检查:创建长度超过 2^32-1 时抛 RangeError
|
||||
/// (密集数组长度按 u32 存储,超之不可容纳)。
|
||||
pub(crate) fn check_array_create_len<H: VmHost>(vm: &mut H, n: usize) -> Result<(), JsValue> {
|
||||
if n > u32::MAX as usize {
|
||||
return Err(crate::error::create_range_error(vm, "Invalid array length"));
|
||||
@@ -225,6 +232,9 @@ pub(crate) fn array_length_arg<H: VmHost>(vm: &mut H, value: JsValue) -> Result<
|
||||
Ok(n as usize)
|
||||
}
|
||||
|
||||
/// native 回调通用调用入口:先校验回调可调用(非对象、空指针、非函数均转
|
||||
/// TypeError),再以 this_val 为接收者、cb_args 为实参同步调用用户回调;调用
|
||||
/// 失败时优先取回未捕获的原始异常值,无原始值时按错误文本重建异常。
|
||||
pub(crate) fn invoke_native_callback<H: VmHost>(
|
||||
vm: &mut H, callback_val: JsValue, this_val: JsValue, cb_args: &[JsValue],
|
||||
) -> NativeResult {
|
||||
|
||||
@@ -24,7 +24,8 @@ pub fn array_to_reversed<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if let Err(err) = check_array_create_len(vm, n) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
// ????????????????getter ???????????
|
||||
// 按倒序逐个读取原数组元素(规范 Get,访问器 getter 触发),写入新数组对应槽位:
|
||||
// 新数组即原数组元素的逆序。
|
||||
for i in (0..n).rev() {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
unsafe {
|
||||
@@ -68,9 +69,15 @@ pub fn array_with<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
/// 返回按比较语义排序的新数组,原数组不变(`Array.prototype.toSorted`)。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 先校验 compareFn 可调用(非 undefined 且不可调用则抛 TypeError),再读取
|
||||
/// this/length;
|
||||
/// - 未提供比较回调时按 ToString 结果的字符串字典序排序;底层 `sort_by` 为稳定
|
||||
/// 排序,比较结果相等的元素保持原有相对次序。
|
||||
pub fn array_to_sorted<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.toSorted called with {} args", args.len());
|
||||
// 规范先校验 compareFn 可调用,再读取 this/length。
|
||||
let comparator = if args.len() > 1 {
|
||||
match parse_sort_comparator(vm, vm.reg(args[1])) {
|
||||
Ok(c) => c,
|
||||
@@ -105,6 +112,14 @@ pub fn array_to_sorted<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
/// 按 start/deleteCount/插入值三元 splice 语义返回新数组,原数组不变
|
||||
///(`Array.prototype.toSpliced`)。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 全缺省(无 start 与 deleteCount)按拷贝处理;仅缺 deleteCount 时从 start
|
||||
/// 删到末尾;
|
||||
/// - start 为负时按 len + start 折算并夹到 `[0, len]`;deleteCount 为负或 NaN
|
||||
/// 视为 0,上限为 len - start。
|
||||
pub fn array_to_spliced<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.toSpliced called with {} args", args.len());
|
||||
let this_val = vm.reg(args[0]);
|
||||
@@ -140,8 +155,8 @@ pub fn array_to_spliced<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
dc.min(n - actual_start)
|
||||
};
|
||||
let insert_count = if args.len() > 3 { args.len() - 3 } else { 0 };
|
||||
// ???newLen = len + insertCount - actualDeleteCount?> 2**53-1 ? TypeError?
|
||||
// ArrayCreate(newLen) ? 2**32-1 ? RangeError??????/???????
|
||||
// 新长度 newLen = len + insertCount - actualDeleteCount 超过 2^53-1 抛 TypeError;
|
||||
// 再经 check_array_create_len 检查,超过 2^32-1 抛 RangeError。
|
||||
let new_len = n.saturating_add(insert_count).saturating_sub(delete_count);
|
||||
if new_len > 9_007_199_254_740_991 {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Invalid array length"));
|
||||
|
||||
@@ -14,10 +14,10 @@ use super::common::{
|
||||
invoke_native_callback, require_callback,
|
||||
};
|
||||
|
||||
/// `Array.prototype.sort(compareFn)`:原地排序。默认按字符串字典序;
|
||||
/// 提供比较函数时按其返回值(<0/=0/>0)排序,回调抛错则中止。
|
||||
/// 对元素向量执行 Array.prototype.sort 的比较语义(原地)。
|
||||
/// 比较回调抛错时中止并把异常返回;默认按字符串字典序。
|
||||
/// 对元素向量执行 `Array.prototype.sort` 的比较语义(原地排序)。
|
||||
///
|
||||
/// 默认按 ToString 结果的字符串字典序比较;提供比较回调时按其返回值
|
||||
///(<0/=0/>0)决定次序,回调抛错则中止并把异常原样返回。
|
||||
pub(crate) fn sort_values_inner<H: VmHost>(
|
||||
vm: &mut H, vals: &mut [JsValue], comparator: Option<JsValue>,
|
||||
) -> Result<(), JsValue> {
|
||||
@@ -70,6 +70,14 @@ pub(crate) fn parse_sort_comparator<H: VmHost>(vm: &mut H, candidate: JsValue) -
|
||||
}
|
||||
}
|
||||
|
||||
/// 原地排序数组元素并返回原数组(`Array.prototype.sort`)。
|
||||
///
|
||||
/// 未提供比较回调时按 ToString 结果的字符串字典序排序;底层 `sort_by` 为稳定
|
||||
/// 排序,比较结果相等(含 NaN)的元素保持原有相对次序。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 接收者不是数组时抛 TypeError;
|
||||
/// - 比较回调抛错时中止排序并把异常原样返回。
|
||||
pub fn array_sort<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.sort called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
//! 记录栈状态,`entries` 按入栈序存待释放资源。同步栈 dispose 只用
|
||||
//! Pending/Disposed 两态;Disposing 为异步资源栈 disposeAsync 执行期标记
|
||||
//! (当前状态机只置 Disposed,变体语义预留)。两栈共用本模块:方法按
|
||||
//! `type_tag`(24 同步 / 25 异步)区分接收者,`hint` 记录条目释放语义
|
||||
//! (0=sync-dispose,1=async-dispose),`wrap_sync` 标记 async 栈 use 落回
|
||||
//! `type_tag` 为 `JsObject::OBJ_TYPE_DISPOSABLE_STACK`(同步)或
|
||||
//! `OBJ_TYPE_ASYNC_DISPOSABLE_STACK`(异步)时区分接收者,`hint` 以 0/1 两值区分
|
||||
//! 条目释放语义(定义见 `DisposeEntry.hint`),`wrap_sync` 标记 async 栈 use 落回
|
||||
//! `@@dispose` 的条目(返回值丢弃、异常异步化)。GC 四函数
|
||||
//! (edges/rewrite/clone/drop)供 session 层跨 epoch 追踪,签名与 Map/Promise
|
||||
//! 状态盒同构。
|
||||
@@ -529,6 +530,11 @@ pub struct DisposeCapability {
|
||||
pub entries: Vec<DisposeEntry>,
|
||||
}
|
||||
|
||||
/// 取对象 `native_data` 中存放的状态盒指针。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// - 仅在对象存活期内调用(GC 边收集与绑定层);指针由分配入口
|
||||
/// `alloc_disposable_stack` 保证有效。
|
||||
pub fn get_capability_ptr(obj: &JsObject) -> *mut DisposeCapability {
|
||||
obj.native_data() as *mut DisposeCapability
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
use crate::builtins_debug;
|
||||
|
||||
/// 判断字符串是否为规范整数索引:非空、无前导零、全数字且值 < 2^32-1。
|
||||
fn is_integer_index(key: &str) -> bool {
|
||||
if key.is_empty() || key.len() > 1 && key.as_bytes()[0] == b'0' {
|
||||
return false;
|
||||
@@ -19,8 +20,9 @@ fn is_integer_index(key: &str) -> bool {
|
||||
}
|
||||
|
||||
/// 收集对象全部自身属性(数组元素区 + shape 链),按规范顺序排列:整数索引在前
|
||||
/// 升序,其余保持插入序。返回 `(属性键 si, 绝对存储索引)`:数组对象元素区索引即
|
||||
/// 绝对下标,命名属性 = `array_prop_count + shape 槽位`;普通对象即 shape 槽位。
|
||||
/// 升序,其余保持插入序。si 指 interned 字符串键编号(PermInterner 分配的 u32 id)。
|
||||
/// 返回 `(属性键 si, 绝对存储索引)`:数组对象元素区索引即绝对下标,命名属性 =
|
||||
/// `array_prop_count + shape 槽位`;普通对象即 shape 槽位。
|
||||
pub fn walk_own_keys<H: VmHost>(vm: &H, obj: &JsObject) -> Vec<(u32, u32)> {
|
||||
let mut keys: Vec<(u32, u32)> = Vec::new();
|
||||
// 数组元素区:整数下标是可枚举自身属性(hole 视为不存在),排在命名属性之前。
|
||||
@@ -78,7 +80,8 @@ pub fn walk_own_keys<H: VmHost>(vm: &H, obj: &JsObject) -> Vec<(u32, u32)> {
|
||||
keys
|
||||
}
|
||||
|
||||
/// 键 si 的数组下标值:整数键直接反解,字符串键查 interner 后判是否规范数字串。
|
||||
/// 取键 si(interned 字符串键编号)对应的数组下标值:整数键直接反解,字符串键查
|
||||
/// interner 后判是否规范数字串。
|
||||
fn int_or_string_index<H: VmHost>(vm: &H, si: u32) -> Option<u32> {
|
||||
if is_int_key(si) {
|
||||
return Some(int_key_value(si));
|
||||
@@ -87,9 +90,9 @@ fn int_or_string_index<H: VmHost>(vm: &H, si: u32) -> Option<u32> {
|
||||
is_integer_index(key).then(|| key.parse::<u32>().unwrap())
|
||||
}
|
||||
|
||||
/// 键 si 物化为 JS 可见字符串值(Object.keys / ownKeys / entries 族):
|
||||
/// 键 si 构造为 JS 可见字符串值(Object.keys / ownKeys / entries 族):
|
||||
/// 整数键反解数字串,字符串键经 `decode_key` 还原单元序列(孤立 surrogate
|
||||
/// 物化为 FlatU16,良形键与旧行为逐位一致)。
|
||||
/// 构造为 FlatU16;良形键的输出为良形 UTF-8 字符串,与直接 `to_string` 结果一致)。
|
||||
pub fn key_si_to_js_value<H: VmHost>(vm: &mut H, si: u32) -> JsValue {
|
||||
if is_int_key(si) {
|
||||
return vm.new_string(&int_key_value(si).to_string());
|
||||
@@ -792,6 +795,8 @@ fn push_desc_prop(obj: &mut JsObject, shape_forge: &ShapeForge, prop_si: u32, va
|
||||
obj.push_prop(val);
|
||||
}
|
||||
|
||||
/// 校验并取出 Object 类方法的目标对象:`args[0]` 为接收者,`args[1]` 为待转换值,
|
||||
/// 缺参或值经 ToObject 失败(null/undefined)时抛 TypeError。
|
||||
fn require_obj_arg<H: VmHost>(vm: &mut H, args: &[u8], fn_name: &str) -> Result<*mut JsObject, JsValue> {
|
||||
if args.len() < 2 {
|
||||
return Err(crate::error::create_type_error(vm, &format!("Object.{fn_name} called on non-object")));
|
||||
|
||||
@@ -183,6 +183,15 @@ pub fn drop_typed_array_native(obj: &mut JsObject) -> u64 {
|
||||
bytes
|
||||
}
|
||||
|
||||
/// 取接收者的 TypedArrayData 视图(按值返回,非借出)。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 接收者非对象、对象指针为空或不是 TypedArray 对象时抛 TypeError(接收者不兼容);
|
||||
/// - `native_fn` 槽为空值或存空指针时抛 TypeError(内部状态无效)。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// - 返回的是解引用后的拷贝(`Ok(*data_ptr)`),底层 buffer 仍由对象持有,
|
||||
/// 调用方不得据此延长其生命周期。
|
||||
pub(crate) fn get_typed_array_data<H: VmHost>(vm: &mut H, this_val: JsValue) -> Result<TypedArrayData, JsValue> {
|
||||
if !this_val.is_object() {
|
||||
return Err(type_error(vm, "TypedArray method called on incompatible receiver"));
|
||||
|
||||
Reference in New Issue
Block a user