mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
fix: 读路径按规范跳洞对齐并补 HasProperty 存在判定
This commit is contained in:
@@ -177,6 +177,14 @@ pub(crate) fn unit_string_value<H: VmHost>(vm: &mut H, unit: u16) -> JsValue {
|
||||
}
|
||||
}
|
||||
|
||||
/// 索引位置存在性判定(规范 HasProperty:自身与原型链任一层命中即存在,
|
||||
/// 数组元素区 hole 视同缺失,TypedArray 整数索引按视图长度判在界)。
|
||||
pub(crate) fn arraylike_index_present<H: VmHost>(vm: &mut H, ptr: *mut JsObject, i: usize) -> bool {
|
||||
// SAFETY: ptr 来自 this/参数对象,指向存活对象。
|
||||
let key_si = vm.string_key_si(&i.to_string());
|
||||
vm.has_property(unsafe { &*ptr }, key_si)
|
||||
}
|
||||
|
||||
/// 元素读取失败时直接把异常作为 NativeResult::Err 返回。
|
||||
macro_rules! arraylike_get_or_err {
|
||||
($vm:expr, $ptr:expr, $i:expr) => {
|
||||
|
||||
@@ -9,8 +9,9 @@ use crate::builtins_debug;
|
||||
use crate::builtins_error;
|
||||
|
||||
use super::common::{
|
||||
array_ptr, array_type_error, arraylike_get, arraylike_get_or_err, check_array_create_len, clamp_relative,
|
||||
create_new_array, get_this_array_ref, get_this_arraylike, js_array_index, to_integer_or_infinity_bounded,
|
||||
array_ptr, array_type_error, arraylike_get, arraylike_get_or_err, arraylike_index_present, check_array_create_len,
|
||||
clamp_relative, create_new_array, get_this_array_ref, get_this_arraylike, js_array_index,
|
||||
to_integer_or_infinity_bounded,
|
||||
};
|
||||
use super::from::{array_species_create, create_data_property_or_throw, from_engine_error};
|
||||
|
||||
@@ -125,28 +126,38 @@ pub fn array_slice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
Ok(p) => p,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
// HasProperty + Get + CreateDataPropertyOrThrow 逐元素拷贝。
|
||||
// HasProperty + Get + CreateDataPropertyOrThrow 逐元素拷贝;洞位只在真数组
|
||||
// 目标上留洞(目标预填 present-undefined,须显式置洞)。
|
||||
let mut k = start;
|
||||
let mut out_idx = 0usize;
|
||||
let mut holes: Vec<usize> = Vec::new();
|
||||
while k < end {
|
||||
let key_str = vm.new_string(&k.to_string());
|
||||
let key_si = vm.property_key_si(key_str);
|
||||
if vm.resolve_property(unsafe { &*arr_ptr }, key_si).is_some() {
|
||||
if arraylike_index_present(vm, arr_ptr, k) {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, k);
|
||||
let out_key = vm.new_string(&out_idx.to_string());
|
||||
let out_key_si = vm.property_key_si(out_key);
|
||||
if let Err(err) = create_data_property_or_throw(vm, unsafe { &mut *a_ptr }, out_key_si, elem) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
out_idx += 1;
|
||||
} else {
|
||||
holes.push(out_idx);
|
||||
}
|
||||
out_idx += 1;
|
||||
k += 1;
|
||||
}
|
||||
// 收尾 Set(A, "length", final):普通 Set 语义(可触发继承 setter/异常)。
|
||||
// 收尾 Set(A, "length", final):终长 = 区间长度(end - start),洞位计入;
|
||||
// 普通 Set 语义(可触发继承 setter/异常)。
|
||||
let a_val = JsValue::from_js_object(a_ptr);
|
||||
if unsafe { &*a_ptr }.is_array() {
|
||||
for p in holes {
|
||||
unsafe {
|
||||
(*a_ptr).mark_hole_at(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
let length_key = vm.new_string("length");
|
||||
let length_si = vm.property_key_si(length_key);
|
||||
if let Err(err) = vm.ordinary_set(unsafe { &mut *a_ptr }, length_si, js_array_index(out_idx), a_val, true) {
|
||||
if let Err(err) = vm.ordinary_set(unsafe { &mut *a_ptr }, length_si, js_array_index(count), a_val, true) {
|
||||
return NativeResult::Err(from_engine_error(vm, &err));
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(a_ptr))
|
||||
@@ -225,12 +236,19 @@ pub fn array_concat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
Ok(v) => v,
|
||||
Err(e) => return NativeResult::Err(e),
|
||||
};
|
||||
// this 与数组实参的洞位按缺失复制:结果对应位留洞(记录洞下标,收尾置洞)。
|
||||
let mut all: Vec<JsValue> = Vec::new();
|
||||
let mut holes: Vec<usize> = Vec::new();
|
||||
if let Err(err) = check_array_create_len(vm, n) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
all.push(arraylike_get_or_err!(vm, arr_ptr, i));
|
||||
if arraylike_index_present(vm, arr_ptr, i) {
|
||||
all.push(arraylike_get_or_err!(vm, arr_ptr, i));
|
||||
} else {
|
||||
holes.push(all.len());
|
||||
all.push(JsValue::undefined());
|
||||
}
|
||||
}
|
||||
for &arg_reg in args.iter().skip(1) {
|
||||
let val = vm.reg(arg_reg);
|
||||
@@ -239,10 +257,16 @@ pub fn array_concat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if !o_ptr.is_null() {
|
||||
let o = unsafe { &*o_ptr };
|
||||
let on = o.prop_count() as usize;
|
||||
// 真数组时展开元素。
|
||||
// 真数组时展开元素(洞位同样留洞)。
|
||||
if o.is_array() && on > 0 {
|
||||
let dense = o.array_elements_meta_vec().is_none();
|
||||
for i in 0..on {
|
||||
all.push(o.get_prop_at(i));
|
||||
if dense || !o.prop_meta_at(i).is_some_and(|m| m.is_hole()) {
|
||||
all.push(o.get_prop_at(i));
|
||||
} else {
|
||||
holes.push(all.len());
|
||||
all.push(JsValue::undefined());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -255,6 +279,9 @@ pub fn array_concat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
for (i, val) in all.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
for h in holes {
|
||||
(*new_arr).mark_hole_at(h);
|
||||
}
|
||||
(*new_arr).set_prop_count(all.len());
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
@@ -329,6 +356,10 @@ pub fn array_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
0
|
||||
};
|
||||
for i in from_index..n {
|
||||
// 洞位不参与比较:HasProperty 缺失即跳过(洞不是 undefined 元素)。
|
||||
if !arraylike_index_present(vm, ptr, i) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, ptr, i);
|
||||
if oxide_runtime_api::strict_equality(elem, target) {
|
||||
return NativeResult::Ok(js_array_index(i));
|
||||
@@ -426,8 +457,15 @@ pub fn array_flat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let o = unsafe { &*ptr };
|
||||
if o.is_array() {
|
||||
seen.push(ptr);
|
||||
// 嵌套展开丢弃洞位:flat 结果恒为紧凑数组。
|
||||
let on = o.prop_count() as usize;
|
||||
let sub: Vec<JsValue> = (0..on).map(|i| o.get_prop_at(i)).collect();
|
||||
let dense = o.array_elements_meta_vec().is_none();
|
||||
let mut sub: Vec<JsValue> = Vec::with_capacity(on);
|
||||
for i in 0..on {
|
||||
if dense || !o.prop_meta_at(i).is_some_and(|m| m.is_hole()) {
|
||||
sub.push(o.get_prop_at(i));
|
||||
}
|
||||
}
|
||||
let flat = flatten(&sub, remaining_depth - 1, seen);
|
||||
seen.pop();
|
||||
out.extend(flat);
|
||||
@@ -440,7 +478,14 @@ pub fn array_flat<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
out
|
||||
}
|
||||
|
||||
let all: Vec<JsValue> = (0..n).map(|i| arr.get_prop_at(i)).collect();
|
||||
// 顶层同样丢弃洞位(接收者恒为真数组,元数据表判洞免字符串键)。
|
||||
let dense = arr.array_elements_meta_vec().is_none();
|
||||
let mut all: Vec<JsValue> = Vec::with_capacity(n);
|
||||
for i in 0..n {
|
||||
if dense || !arr.prop_meta_at(i).is_some_and(|m| m.is_hole()) {
|
||||
all.push(arr.get_prop_at(i));
|
||||
}
|
||||
}
|
||||
let mut seen = vec![arr_ptr];
|
||||
let flat = flatten(&all, depth, &mut seen);
|
||||
let new_arr = create_new_array(vm, flat.len());
|
||||
@@ -689,6 +734,10 @@ pub fn array_last_index_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Ok(JsValue::int(-1));
|
||||
}
|
||||
for i in (0..=from_index_isize as usize).rev() {
|
||||
// 洞位不参与比较:HasProperty 缺失即跳过(洞不是 undefined 元素)。
|
||||
if !arraylike_index_present(vm, ptr, i) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, ptr, i);
|
||||
if oxide_runtime_api::strict_equality(elem, search) {
|
||||
return NativeResult::Ok(js_array_index(i));
|
||||
|
||||
@@ -8,8 +8,9 @@ use crate::builtins_debug;
|
||||
use crate::builtins_error;
|
||||
|
||||
use super::common::{
|
||||
array_ptr_len3, array_type_error, arraylike_get, arraylike_get_or_err, check_array_create_len, create_new_array,
|
||||
get_this_arraylike, invoke_native_callback, js_array_index, require_callback, unexpected_tail_call_error,
|
||||
array_ptr_len3, array_type_error, arraylike_get, arraylike_get_or_err, arraylike_index_present,
|
||||
check_array_create_len, create_new_array, get_this_arraylike, invoke_native_callback, js_array_index,
|
||||
require_callback, unexpected_tail_call_error,
|
||||
};
|
||||
|
||||
/// `Array.prototype.forEach(callback, thisArg)`:对每个元素调用 callback,返回 undefined。
|
||||
@@ -26,6 +27,10 @@ pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
// 洞位跳过:回调不得在缺失索引上触发。
|
||||
if !arraylike_index_present(vm, arr_ptr, i) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(_) => {}
|
||||
@@ -54,6 +59,13 @@ pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
// 洞位跳过回调,并在结果对应位留洞(结果数组预填 present-undefined,须显式置洞)。
|
||||
if !arraylike_index_present(vm, arr_ptr, i) {
|
||||
unsafe {
|
||||
(*new_arr).mark_hole_at(i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(mapped) => unsafe {
|
||||
@@ -91,6 +103,10 @@ pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
// 洞位跳过:结果保持紧凑,不复制缺失索引。
|
||||
if !arraylike_index_present(vm, arr_ptr, i) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
@@ -118,10 +134,6 @@ pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.reduce called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if n == 0 && args.len() < 3 {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
@@ -140,11 +152,30 @@ pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
accumulator = vm.reg(args[2]);
|
||||
start_idx = 0;
|
||||
} else {
|
||||
accumulator = arraylike_get_or_err!(vm, arr_ptr, 0);
|
||||
start_idx = 1;
|
||||
// FindFirstKey:无初值时取首个存在索引作累加器;全洞(含空数组)抛 TypeError。
|
||||
let mut found = None;
|
||||
for i in 0..n {
|
||||
if arraylike_index_present(vm, arr_ptr, i) {
|
||||
found = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let idx = match found {
|
||||
Some(idx) => idx,
|
||||
None => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
};
|
||||
accumulator = arraylike_get_or_err!(vm, arr_ptr, idx);
|
||||
start_idx = idx + 1;
|
||||
}
|
||||
let this_val = JsValue::undefined();
|
||||
for i in start_idx..n {
|
||||
// 洞位跳过:累加器保持上一 present 元素的结果。
|
||||
if !arraylike_index_present(vm, arr_ptr, i) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[accumulator, elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result) => accumulator = result,
|
||||
@@ -217,6 +248,10 @@ pub fn array_some<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
// 洞位跳过:回调不得在缺失索引上触发。
|
||||
if !arraylike_index_present(vm, arr_ptr, i) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
@@ -255,6 +290,10 @@ pub fn array_every<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
// 洞位跳过:回调不得在缺失索引上触发。
|
||||
if !arraylike_index_present(vm, arr_ptr, i) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
@@ -297,6 +336,10 @@ pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
// 洞位跳过:回调不得在缺失索引上触发。
|
||||
if !arraylike_index_present(vm, arr_ptr, i) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result) => {
|
||||
@@ -305,9 +348,13 @@ pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if !r_ptr.is_null() {
|
||||
let r = unsafe { &*r_ptr };
|
||||
if r.is_array() {
|
||||
// 嵌套数组展开丢弃洞位:结果为紧凑数组。
|
||||
let rn = r.prop_count() as usize;
|
||||
let dense = r.array_elements_meta_vec().is_none();
|
||||
for j in 0..rn {
|
||||
flat.push(r.get_prop_at(j));
|
||||
if dense || !r.prop_meta_at(j).is_some_and(|m| m.is_hole()) {
|
||||
flat.push(r.get_prop_at(j));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -394,8 +441,8 @@ pub fn array_find_last<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in (0..n).rev() {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i) };
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i), o_val]) {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i as usize);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i as usize), o_val]) {
|
||||
NativeResult::Ok(r) => {
|
||||
if oxide_runtime_api::to_boolean(r) {
|
||||
return NativeResult::Ok(elem);
|
||||
@@ -433,15 +480,35 @@ pub fn array_reduce_right<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let (mut acc, start_idx): (JsValue, i32) = if args.len() > 2 {
|
||||
(vm.reg(args[2]), n as i32 - 1)
|
||||
} else {
|
||||
if n == 0 {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
// FindFirstKey 自尾:无初值时取末尾首个存在索引作累加器;全洞抛 TypeError。
|
||||
let mut found = None;
|
||||
for i in (0..n).rev() {
|
||||
if arraylike_index_present(vm, arr_ptr, i) {
|
||||
found = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
(unsafe { (*arr_ptr).get_prop_at(n - 1) }, n as i32 - 2)
|
||||
let idx = match found {
|
||||
Some(idx) => idx,
|
||||
None => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
};
|
||||
(arraylike_get_or_err!(vm, arr_ptr, idx), idx as i32 - 1)
|
||||
};
|
||||
for i in (0..=start_idx).rev() {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as usize) };
|
||||
match invoke_native_callback(vm, callback_val, JsValue::undefined(), &[acc, elem, JsValue::int(i), o_val]) {
|
||||
// 洞位跳过:累加器保持上一 present 元素的结果。
|
||||
if !arraylike_index_present(vm, arr_ptr, i as usize) {
|
||||
continue;
|
||||
}
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i as usize);
|
||||
match invoke_native_callback(
|
||||
vm,
|
||||
callback_val,
|
||||
JsValue::undefined(),
|
||||
&[acc, elem, js_array_index(i as usize), o_val],
|
||||
) {
|
||||
NativeResult::Ok(r) => acc = r,
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
|
||||
@@ -73,7 +73,8 @@ pub(crate) fn parse_sort_comparator<H: VmHost>(vm: &mut H, candidate: JsValue) -
|
||||
/// 原地排序数组元素并返回原数组(`Array.prototype.sort`)。
|
||||
///
|
||||
/// 未提供比较回调时按 ToString 结果的字符串字典序排序;底层 `sort_by` 为稳定
|
||||
/// 排序,比较结果相等(含 NaN)的元素保持原有相对次序。
|
||||
/// 排序,比较结果相等(含 NaN)的元素保持原有相对次序。洞位不参与比较:
|
||||
/// present 值稳定排序后自索引 0 紧凑写回,尾部空位转为洞。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 接收者不是数组时抛 TypeError;
|
||||
@@ -82,7 +83,13 @@ 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);
|
||||
let len = unsafe { (*arr_ptr).prop_count() as usize };
|
||||
let mut vals: Vec<JsValue> = (0..len).map(|i| unsafe { (*arr_ptr).get_prop_at(i) }).collect();
|
||||
// 洞位不参与比较:只收集 present 元素(接收者恒为真数组,元数据表判洞免字符串键)。
|
||||
let arr_ref = unsafe { &*arr_ptr };
|
||||
let dense = arr_ref.array_elements_meta_vec().is_none();
|
||||
let mut vals: Vec<JsValue> = (0..len)
|
||||
.filter(|&i| dense || !arr_ref.prop_meta_at(i).is_some_and(|m| m.is_hole()))
|
||||
.map(|i| arr_ref.get_prop_at(i))
|
||||
.collect();
|
||||
let comparator = if args.len() > 1 {
|
||||
match parse_sort_comparator(vm, vm.reg(args[1])) {
|
||||
Ok(c) => c,
|
||||
@@ -98,10 +105,14 @@ pub fn array_sort<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_error!("Array.prototype.sort: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
// present 值稳定排序后从索引 0 紧凑写回,尾部空位转为洞。
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
for (i, &v) in vals.iter().enumerate() {
|
||||
arr.set_prop_at(i, v);
|
||||
}
|
||||
for i in vals.len()..len {
|
||||
arr.mark_hole_at(i);
|
||||
}
|
||||
NativeResult::Ok(vm.reg(args[0]))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user