refactor: 退役 new_array 死参数与三十四处调用点

This commit is contained in:
2026-10-03 04:32:20 +00:00
parent a4d70a8bfe
commit 214494d3d5
18 changed files with 38 additions and 111 deletions
@@ -267,7 +267,6 @@ pub(crate) fn create_new_array<H: VmHost>(vm: &mut H, n: usize) -> *mut JsObject
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
JsValue::from_js_object(proto), JsValue::from_js_object(proto),
n.min(MAX_DENSE_PROPS), n.min(MAX_DENSE_PROPS),
vm.epoch().bump(),
)) ))
} }
+3 -3
View File
@@ -25,7 +25,7 @@ pub fn array_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
Ok(n) => n, Ok(n) => n,
Err(err) => return NativeResult::Err(err), Err(err) => return NativeResult::Err(err),
}; };
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n, vm.epoch().bump())); let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n));
// 数值长度分支建 n 个空洞而非 present-undefined:`in`、for-in、 // 数值长度分支建 n 个空洞而非 present-undefined:`in`、for-in、
// Object.keys 按缺失处理,元素 Get 落原型链。物理区以稠密上限 // Object.keys 按缺失处理,元素 Get 落原型链。物理区以稠密上限
// 钳位(越界索引无物理槽,逻辑长度已覆盖)。 // 钳位(越界索引无物理槽,逻辑长度已覆盖)。
@@ -39,7 +39,7 @@ pub fn array_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
} }
let n_elems = if args.len() > 1 { args.len() - 1 } else { 0 }; let n_elems = if args.len() > 1 { args.len() - 1 } else { 0 };
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n_elems, vm.epoch().bump())); let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, n_elems));
for i in 0..n_elems { for i in 0..n_elems {
unsafe { unsafe {
(*arr).set_prop_at(i, vm.reg(args[1 + i])); (*arr).set_prop_at(i, vm.reg(args[1 + i]));
@@ -292,7 +292,7 @@ fn construct_array_from_result<H: VmHost>(
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let proto_val = JsValue::from_js_object(proto); let proto_val = JsValue::from_js_object(proto);
let mut fallback_array = || { let mut fallback_array = || {
let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, 0, vm.epoch().bump())); let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, proto_val, 0));
(arr, true) (arr, true)
}; };
// 不可构造(箭头函数 / 非构造器标记的 native 方法 / 普通值)回退普通数组。 // 不可构造(箭头函数 / 非构造器标记的 native 方法 / 普通值)回退普通数组。
+1 -1
View File
@@ -748,7 +748,7 @@ pub fn detach_array_buffer_native<H: VmHost>(vm: &mut H, this_val: JsValue) -> N
/// 读取之前:强转副作用不先于 immutable 观测)。 /// 读取之前:强转副作用不先于 immutable 观测)。
/// 3. newByteLength = ToIntegerOrInfinity(newLength) 传播式(NaN → 0, /// 3. newByteLength = ToIntegerOrInfinity(newLength) 传播式(NaN → 0,
/// ±Infinity 保留)。 /// ±Infinity 保留)。
/// 4. 重取载荷指针(强转调用可触发 epoch 晋升,旧指针悬垂);detached /// 4. 重取载荷指针(强转调用可触发收集,旧指针悬垂);detached
/// 守卫在求值之后:强转内 detach 与本步前已 detach 同形 TypeError。 /// 守卫在求值之后:强转内 detach 与本步前已 detach 同形 TypeError。
/// 5. 定长(重读存储态上限 = 0)→ TypeError,先于界判。 /// 5. 定长(重读存储态上限 = 0)→ TypeError,先于界判。
/// 6. newByteLength < 0 或 > 真实上限(重读存储态 − 1)→ RangeError。 /// 6. newByteLength < 0 或 > 真实上限(重读存储态 − 1)→ RangeError。
+3 -9
View File
@@ -710,11 +710,10 @@ fn make_array_from_list<H: VmHost>(vm: &mut H, items: &[JsValue]) -> JsValue {
EMPTY_SHAPE_ID, EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto), JsValue::from_js_object(array_proto),
items.len().min(oxide_types::object::MAX_DENSE_PROPS), items.len().min(oxide_types::object::MAX_DENSE_PROPS),
vm.epoch().bump(),
)); ));
// 逐元素写入数组元素区,最后统一 set_prop_count(new_array 预分配不足时自动扩容)。 // 逐元素写入数组元素区,最后统一 set_prop_count(new_array 预分配不足时自动扩容)。
for (i, item) in items.iter().enumerate() { for (i, item) in items.iter().enumerate() {
// SAFETY: arr 是当前 epoch 新分配数组对象,元素区已就绪。 // SAFETY: arr 是刚经统一入口分配的数组对象,元素区已就绪。
unsafe { unsafe {
(*arr).set_prop_at(i, *item); (*arr).set_prop_at(i, *item);
} }
@@ -2051,13 +2050,8 @@ fn is_set_value(value: JsValue) -> bool {
fn make_map_set_pair<H: VmHost>(vm: &mut H, a: JsValue, b: JsValue) -> JsValue { fn make_map_set_pair<H: VmHost>(vm: &mut H, a: JsValue, b: JsValue) -> JsValue {
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let pair = vm.alloc_object(JsObject::new_array( let pair = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), 2));
EMPTY_SHAPE_ID, // SAFETY: pair 是刚经统一入口分配的数组 JsObject。
JsValue::from_js_object(array_proto),
2,
vm.epoch().bump(),
));
// SAFETY: pair 是当前 epoch 内新分配的数组 JsObject。
unsafe { unsafe {
(*pair).set_prop_at(0, a); (*pair).set_prop_at(0, a);
(*pair).set_prop_at(1, b); (*pair).set_prop_at(1, b);
+3 -7
View File
@@ -76,7 +76,7 @@ const RAW_JSON_FORBIDDEN_EDGE_UNITS: [u16; 4] = [0x09, 0x0A, 0x0D, 0x20];
/// (writable:false、enumerable:true、configurable:false)。 /// (writable:false、enumerable:true、configurable:false)。
/// ///
/// # 副作用 /// # 副作用
/// - 分配一个 session/epoch 对象与其字符串属性值。 /// - 经统一入口分配一个 session 对象与其字符串属性值。
pub fn json_raw_json<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn json_raw_json<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let text_val = match oxide_runtime_api::to_string_value_full( let text_val = match oxide_runtime_api::to_string_value_full(
if args.len() >= 2 { vm.reg(args[1]) } else { JsValue::undefined() }, if args.len() >= 2 { vm.reg(args[1]) } else { JsValue::undefined() },
@@ -649,12 +649,8 @@ fn build_js_value<H: VmHost>(vm: &mut H, node: &JsonNode) -> JsValue {
JsonKind::Array(items) => { JsonKind::Array(items) => {
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let n = items.len(); let n = items.len();
let array_obj = vm.alloc_object(JsObject::new_array( let array_obj =
EMPTY_SHAPE_ID, vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
for (i, item) in items.iter().enumerate() { for (i, item) in items.iter().enumerate() {
let jsv = build_js_value(vm, item); let jsv = build_js_value(vm, item);
unsafe { unsafe {
+1 -6
View File
@@ -612,12 +612,7 @@ pub fn map_group_by<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
existing existing
} else { } else {
let arr_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let arr_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(arr_proto), 0));
EMPTY_SHAPE_ID,
JsValue::from_js_object(arr_proto),
0,
vm.epoch().bump(),
));
let new_arr_val = JsValue::from_js_object(arr); let new_arr_val = JsValue::from_js_object(arr);
if let Err(e) = vm.call_function_sync(adder, map_val, &[group_key, new_arr_val]) { if let Err(e) = vm.call_function_sync(adder, map_val, &[group_key, new_arr_val]) {
let exc = vm let exc = vm
+7 -42
View File
@@ -275,12 +275,7 @@ pub fn object_get_own_property_symbols<H: VmHost>(vm: &mut H, args: &[u8]) -> Na
let n = symbols.len(); let n = symbols.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
for (i, v) in symbols.iter().enumerate() { for (i, v) in symbols.iter().enumerate() {
unsafe { unsafe {
(*arr).set_prop_at(i, *v); (*arr).set_prop_at(i, *v);
@@ -610,12 +605,7 @@ pub fn object_keys<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
} }
let n = owned_keys.len(); let n = owned_keys.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
for (i, (si, _offset)) in owned_keys.iter().enumerate() { for (i, (si, _offset)) in owned_keys.iter().enumerate() {
let key_val = key_si_to_js_value(vm, *si); let key_val = key_si_to_js_value(vm, *si);
unsafe { unsafe {
@@ -1522,12 +1512,7 @@ pub fn object_get_own_property_names<H: VmHost>(vm: &mut H, args: &[u8]) -> Nati
let keys = walk_own_keys(vm, obj); let keys = walk_own_keys(vm, obj);
let n = keys.len(); let n = keys.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
for (i, (si, _)) in keys.iter().enumerate() { for (i, (si, _)) in keys.iter().enumerate() {
let key_val = key_si_to_js_value(vm, *si); let key_val = key_si_to_js_value(vm, *si);
unsafe { unsafe {
@@ -2158,12 +2143,7 @@ pub fn object_entries<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
.collect(); .collect();
let n = owned_keys.len(); let n = owned_keys.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
let obj_val = JsValue::from_js_object(obj_ptr); let obj_val = JsValue::from_js_object(obj_ptr);
for (i, (si, offset)) in owned_keys.iter().enumerate() { for (i, (si, offset)) in owned_keys.iter().enumerate() {
let key_val = key_si_to_js_value(vm, *si); let key_val = key_si_to_js_value(vm, *si);
@@ -2172,12 +2152,7 @@ pub fn object_entries<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
Ok(value) => value, Ok(value) => value,
Err(exc) => return NativeResult::Err(exc), Err(exc) => return NativeResult::Err(exc),
}; };
let pair = vm.alloc_object(JsObject::new_array( let pair = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), 2));
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
2,
vm.epoch().bump(),
));
unsafe { unsafe {
(*pair).set_prop_at(0, key_val); (*pair).set_prop_at(0, key_val);
(*pair).set_prop_at(1, val); (*pair).set_prop_at(1, val);
@@ -2310,12 +2285,7 @@ pub fn object_group_by<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
existing existing
} else { } else {
let arr_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let arr_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(arr_proto), 0));
EMPTY_SHAPE_ID,
JsValue::from_js_object(arr_proto),
0,
vm.epoch().bump(),
));
let new_arr_val = JsValue::from_js_object(arr); let new_arr_val = JsValue::from_js_object(arr);
let result_ref_mut = unsafe { &mut *result }; let result_ref_mut = unsafe { &mut *result };
// 写入失败按 builtin 边界传播(result 为 fresh 对象实际不可达,不得静默吞)。 // 写入失败按 builtin 边界传播(result 为 fresh 对象实际不可达,不得静默吞)。
@@ -2348,12 +2318,7 @@ pub fn object_values<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
.collect(); .collect();
let n = owned_keys.len(); let n = owned_keys.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
let obj_val = JsValue::from_js_object(obj_ptr); let obj_val = JsValue::from_js_object(obj_ptr);
for (i, (si, offset)) in owned_keys.iter().enumerate() { for (i, (si, offset)) in owned_keys.iter().enumerate() {
// EnumerableOwnProperties 的 "value":accessor 触发 getter,异常传播原值。 // EnumerableOwnProperties 的 "value":accessor 触发 getter,异常传播原值。
+2 -7
View File
@@ -233,7 +233,7 @@ pub fn reflect_is_extensible<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
/// 2. 追加自身 Symbol 键(保持插入序),符合 OrdinaryOwnPropertyKeys 的排序。 /// 2. 追加自身 Symbol 键(保持插入序),符合 OrdinaryOwnPropertyKeys 的排序。
/// ///
/// # 副作用 /// # 副作用
/// - 结果数组分配在当前 epoch。 /// - 结果数组经统一入口分配为 session 对象。
pub fn reflect_own_keys<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn reflect_own_keys<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let target_val = arg(vm, args, 1); let target_val = arg(vm, args, 1);
let Some(target_ptr) = object_ptr(target_val) else { let Some(target_ptr) = object_ptr(target_val) else {
@@ -256,12 +256,7 @@ pub fn reflect_own_keys<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let n = keys.len() + symbols.len(); let n = keys.len() + symbols.len();
let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let array_proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = vm.alloc_object(JsObject::new_array( let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(array_proto), n));
EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto),
n,
vm.epoch().bump(),
));
for (i, (si, _)) in keys.iter().enumerate() { for (i, (si, _)) in keys.iter().enumerate() {
let key_val = key_si_to_js_value(vm, *si); let key_val = key_si_to_js_value(vm, *si);
unsafe { unsafe {
+3 -6
View File
@@ -38,8 +38,7 @@ pub(crate) fn build_indices_array<H: VmHost>(vm: &mut H, m: &regress::Match, tex
let group_count = m.captures.len(); let group_count = m.captures.len();
let n = 1 + group_count; let n = 1 + group_count;
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n));
vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n, vm.epoch().bump()));
unsafe { unsafe {
let range = m.range(); let range = m.range();
(*arr).set_prop_at(0, index_pair(vm, text.unit_pos(range.start), text.unit_pos(range.end))); (*arr).set_prop_at(0, index_pair(vm, text.unit_pos(range.start), text.unit_pos(range.end)));
@@ -61,8 +60,7 @@ pub(crate) fn build_indices_array<H: VmHost>(vm: &mut H, m: &regress::Match, tex
/// 单个 [start, end] 码元对数组(数组原型,两个自身元素)。 /// 单个 [start, end] 码元对数组(数组原型,两个自身元素)。
fn index_pair<H: VmHost>(vm: &mut H, start: usize, end: usize) -> JsValue { fn index_pair<H: VmHost>(vm: &mut H, start: usize, end: usize) -> JsValue {
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), 2));
vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), 2, vm.epoch().bump()));
unsafe { unsafe {
(*arr).set_prop_at(0, JsValue::int(start as i32)); (*arr).set_prop_at(0, JsValue::int(start as i32));
(*arr).set_prop_at(1, JsValue::int(end as i32)); (*arr).set_prop_at(1, JsValue::int(end as i32));
@@ -749,8 +747,7 @@ pub fn regexp_exec<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let group_count = m.captures.len(); let group_count = m.captures.len();
let n = 1 + group_count; let n = 1 + group_count;
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n));
vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n, vm.epoch().bump()));
unsafe { unsafe {
(*arr).set_prop_at(0, vm.new_string_units_owned(text.slice(range.start, range.end).into_owned())); (*arr).set_prop_at(0, vm.new_string_units_owned(text.slice(range.start, range.end).into_owned()));
// 捕获组:未参与匹配的组为 undefined。 // 捕获组:未参与匹配的组为 undefined。
+1 -2
View File
@@ -400,8 +400,7 @@ pub(crate) fn split_limit_to_uint32<H: VmHost>(vm: &mut H, limit_val: JsValue) -
pub(crate) fn make_string_array_values<H: VmHost>(vm: &mut H, parts: Vec<JsValue>) -> JsValue { pub(crate) fn make_string_array_values<H: VmHost>(vm: &mut H, parts: Vec<JsValue>) -> JsValue {
let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject; let proto = vm.session().builtin_world().array_proto.as_ptr() as *mut JsObject;
let n = parts.len(); let n = parts.len();
let arr = let arr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n));
vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n, vm.epoch().bump()));
unsafe { unsafe {
for (i, sv) in parts.into_iter().enumerate() { for (i, sv) in parts.into_iter().enumerate() {
(*arr).set_prop_at(i, sv); (*arr).set_prop_at(i, sv);
+1 -1
View File
@@ -422,7 +422,7 @@ impl JsObject {
} }
/// 构造数组对象:预分配 `n_elements` 个 `undefined` 的独立元素区并置 array 标志。 /// 构造数组对象:预分配 `n_elements` 个 `undefined` 的独立元素区并置 array 标志。
pub fn new_array(shape_id: ShapeId, proto: JsValue, n_elements: usize, _bump: &bumpalo::Bump) -> Self { pub fn new_array(shape_id: ShapeId, proto: JsValue, n_elements: usize) -> Self {
let mut obj = Self { let mut obj = Self {
header: (shape_id & 0x00FF_FFFF) | (1 << 30) | (1 << 29), header: (shape_id & 0x00FF_FFFF) | (1 << 30) | (1 << 29),
native_arg_count: 0, native_arg_count: 0,
+4 -8
View File
@@ -93,8 +93,7 @@ fn hash_prop_read_write() {
#[test] #[test]
fn new_array_flags() { fn new_array_flags() {
let bump = bumpalo::Bump::new(); let obj = JsObject::new_array(5, JsValue::null(), 3);
let obj = JsObject::new_array(5, JsValue::null(), 3, &bump);
assert!(obj.is_array()); assert!(obj.is_array());
assert_eq!(obj.shape_id(), 5); assert_eq!(obj.shape_id(), 5);
assert_eq!(obj.prop_count(), 3); assert_eq!(obj.prop_count(), 3);
@@ -164,8 +163,7 @@ fn accessor_meta_roundtrip_and_alignment() {
#[test] #[test]
fn array_element_write_preserves_props_after_element_growth() { fn array_element_write_preserves_props_after_element_growth() {
// 先写属性再 push 元素:元素区增长必须整体搬移属性区,不覆盖属性。 // 先写属性再 push 元素:元素区增长必须整体搬移属性区,不覆盖属性。
let bump = bumpalo::Bump::new(); let mut obj = JsObject::new_array(EMPTY_SHAPE_ID, JsValue::null(), 3);
let mut obj = JsObject::new_array(EMPTY_SHAPE_ID, JsValue::null(), 3, &bump);
obj.set_prop_shape(0, JsValue::int(99)); obj.set_prop_shape(0, JsValue::int(99));
obj.set_prop_at(3, JsValue::int(4)); obj.set_prop_at(3, JsValue::int(4));
assert_eq!(obj.prop_count(), 4); assert_eq!(obj.prop_count(), 4);
@@ -176,8 +174,7 @@ fn array_element_write_preserves_props_after_element_growth() {
#[test] #[test]
fn array_element_write_beyond_count_relocates_prop_zone() { fn array_element_write_beyond_count_relocates_prop_zone() {
// 稀疏写入(越界索引)把属性区推到新元素之后,属性读取仍命中。 // 稀疏写入(越界索引)把属性区推到新元素之后,属性读取仍命中。
let bump = bumpalo::Bump::new(); let mut obj = JsObject::new_array(EMPTY_SHAPE_ID, JsValue::null(), 2);
let mut obj = JsObject::new_array(EMPTY_SHAPE_ID, JsValue::null(), 2, &bump);
obj.set_prop_shape(0, JsValue::int(7)); obj.set_prop_shape(0, JsValue::int(7));
obj.set_prop_at(5, JsValue::int(50)); obj.set_prop_at(5, JsValue::int(50));
assert_eq!(obj.prop_count(), 6); assert_eq!(obj.prop_count(), 6);
@@ -188,8 +185,7 @@ fn array_element_write_beyond_count_relocates_prop_zone() {
#[test] #[test]
fn array_prop_count_truncate_keeps_prop_zone() { fn array_prop_count_truncate_keeps_prop_zone() {
// pop 截断元素区时属性区不得被删(meta 同步 insert/drain 对齐)。 // pop 截断元素区时属性区不得被删(meta 同步 insert/drain 对齐)。
let bump = bumpalo::Bump::new(); let mut obj = JsObject::new_array(EMPTY_SHAPE_ID, JsValue::null(), 3);
let mut obj = JsObject::new_array(EMPTY_SHAPE_ID, JsValue::null(), 3, &bump);
obj.set_prop_shape(0, JsValue::int(5)); obj.set_prop_shape(0, JsValue::int(5));
obj.set_data_meta(3, PropAttributes::new(true, false, true)); obj.set_data_meta(3, PropAttributes::new(true, false, true));
obj.set_prop_count_fast(2); obj.set_prop_count_fast(2);
+2 -4
View File
@@ -392,9 +392,8 @@ impl Vm {
let n = count as usize; let n = count as usize;
let rest_len = n.saturating_sub(fixed_count); let rest_len = n.saturating_sub(fixed_count);
let proto_ptr = self.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let proto_ptr = self.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let bump = self.epoch.bump();
let obj_ptr = let obj_ptr =
self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), rest_len, bump)); self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), rest_len));
let obj = unsafe { &mut *obj_ptr }; let obj = unsafe { &mut *obj_ptr };
for i in 0..rest_len { for i in 0..rest_len {
let val = self let val = self
@@ -413,8 +412,7 @@ impl Vm {
let n = opcode::imm16(instr) as usize; let n = opcode::imm16(instr) as usize;
vm_trace!("NEW_ARRAY rd={} n={}", rd, n); vm_trace!("NEW_ARRAY rd={} n={}", rd, n);
let proto_ptr = self.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let proto_ptr = self.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let bump = self.epoch.bump(); let obj = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), n));
let obj = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, JsValue::from_js_object(proto_ptr), n, bump));
self.regs[rd] = JsValue::object(obj as *mut u8); self.regs[rd] = JsValue::object(obj as *mut u8);
} }
+1 -2
View File
@@ -387,8 +387,7 @@ mod tests {
#[test] #[test]
fn ic_get_hit_virtual_length_marker_hits_array() { fn ic_get_hit_virtual_length_marker_hits_array() {
// shape 1(空形状)数组经虚拟长度标记命中:返回逻辑长度。 // shape 1(空形状)数组经虚拟长度标记命中:返回逻辑长度。
let bump = bumpalo::Bump::new(); let arr = JsObject::new_array(EMPTY_SHAPE_ID, JsValue::null(), 3);
let arr = JsObject::new_array(EMPTY_SHAPE_ID, JsValue::null(), 3, &bump);
assert_eq!(ic_get_hit(&arr, EMPTY_SHAPE_ID, VIRTUAL_LENGTH_SLOT, 0), Some(JsValue::int(3))); assert_eq!(ic_get_hit(&arr, EMPTY_SHAPE_ID, VIRTUAL_LENGTH_SLOT, 0), Some(JsValue::int(3)));
} }
+3 -3
View File
@@ -136,7 +136,7 @@ impl Vm {
/// 把 errors 可迭代值收集为新数组(IterableToList)。不可迭代抛 TypeError。 /// 把 errors 可迭代值收集为新数组(IterableToList)。不可迭代抛 TypeError。
fn aggregate_errors_to_list(&mut self, errors: JsValue) -> Result<JsValue, JsValue> { fn aggregate_errors_to_list(&mut self, errors: JsValue) -> Result<JsValue, JsValue> {
let array_proto = JsValue::from_js_object(self.session.builtin_world().array_proto.as_ptr() as *mut JsObject); let array_proto = JsValue::from_js_object(self.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0, self.epoch.bump())); let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0));
let list = JsValue::from_js_object(ptr); let list = JsValue::from_js_object(ptr);
let mut index = 0usize; let mut index = 0usize;
oxide_builtins::iterator::iterate_elements(self, errors, |_vm, elem| { oxide_builtins::iterator::iterate_elements(self, errors, |_vm, elem| {
@@ -152,7 +152,7 @@ impl Vm {
/// 建普通数组对象并依次写入元素(Promise.try 转发实参的承载)。 /// 建普通数组对象并依次写入元素(Promise.try 转发实参的承载)。
fn make_plain_array(&mut self, elements: Vec<JsValue>) -> JsValue { fn make_plain_array(&mut self, elements: Vec<JsValue>) -> JsValue {
let array_proto = JsValue::from_js_object(self.session.builtin_world().array_proto.as_ptr() as *mut JsObject); let array_proto = JsValue::from_js_object(self.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0, self.epoch.bump())); let ptr = self.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0));
// SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;元素写入不搬移对象。 // SAFETY: ptr 由 alloc_object 新建,返回非空 arena 指针;元素写入不搬移对象。
let obj = unsafe { &mut *ptr }; let obj = unsafe { &mut *ptr };
for (i, elem) in elements.into_iter().enumerate() { for (i, elem) in elements.into_iter().enumerate() {
@@ -482,7 +482,7 @@ fn perform_promise_combine(
JsValue::undefined() JsValue::undefined()
} else { } else {
let array_proto = JsValue::from_js_object(vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject); let array_proto = JsValue::from_js_object(vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject);
let ptr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0, vm.epoch.bump())); let ptr = vm.alloc_object(JsObject::new_array(EMPTY_SHAPE_ID, array_proto, 0));
JsValue::from_js_object(ptr) JsValue::from_js_object(ptr)
}; };
let record = vm.make_agg_record(values, resolve, reject); let record = vm.make_agg_record(values, resolve, reject);
-2
View File
@@ -195,7 +195,6 @@ fn sweep_preserves_array_elements_and_collects_dead_element_object() {
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(array_proto), JsValue::from_js_object(array_proto),
2, 2,
vm.epoch.bump(),
)); ));
let live_elem = plain_object(&mut vm); let live_elem = plain_object(&mut vm);
let dead_elem = plain_object(&mut vm); let dead_elem = plain_object(&mut vm);
@@ -1501,7 +1500,6 @@ fn run_alloc_formula_lists_bigint_and_cell_via_tables() {
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, oxide_kernel::shape_forge::EMPTY_SHAPE_ID,
JsValue::from_js_object(vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject), JsValue::from_js_object(vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject),
2, 2,
vm.epoch.bump(),
)); ));
vm.regs[3] = JsValue::from_js_object(arr); vm.regs[3] = JsValue::from_js_object(arr);
let s = vm.new_string_owned("formula".repeat(4)); let s = vm.new_string_owned("formula".repeat(4));
+1 -1
View File
@@ -1201,7 +1201,7 @@ impl Vm {
// 时对象地址稳定,缓存指针不失效——分配档不同则首次写入触发搬移, // 时对象地址稳定,缓存指针不失效——分配档不同则首次写入触发搬移,
// 缓存旧指针与新实例分叉,同一 site 两次取值将返回不同对象。 // 缓存旧指针与新实例分叉,同一 site 两次取值将返回不同对象。
let mut alloc_session_array = |n: usize| { let mut alloc_session_array = |n: usize| {
let clone = JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, proto_val, n, self.epoch.bump()); let clone = JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, proto_val, n);
self.alloc_session_object(clone) self.alloc_session_object(clone)
}; };
let cooked = alloc_session_array(n); let cooked = alloc_session_array(n);
+2 -6
View File
@@ -1682,12 +1682,8 @@ mod tests {
fn new_array_val(vm: &mut Vm, n: u32) -> JsValue { fn new_array_val(vm: &mut Vm, n: u32) -> JsValue {
let proto = vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject; let proto = vm.session.builtin_world().array_proto.as_ptr() as *mut JsObject;
let arr = JsObject::new_array( let arr =
oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsObject::new_array(oxide_kernel::shape_forge::EMPTY_SHAPE_ID, JsValue::from_js_object(proto), n as usize);
JsValue::from_js_object(proto),
n as usize,
vm.epoch.bump(),
);
JsValue::object(vm.alloc_object(arr) as *mut u8) JsValue::object(vm.alloc_object(arr) as *mut u8)
} }