mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-27 12:11:12 +08:00
fix: shift 返回钉结果寄存器并收 length 写序偏离
This commit is contained in:
@@ -88,6 +88,20 @@ fn set_length_invalid_values_throw_range_error() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_length_entry_non_writable_skips_coercion() {
|
||||
// 入口即不可写:可写位判定先于 ArrayLength,两次强转不执行(valueOf 零调用),
|
||||
// sloppy 静默、strict 抛 TypeError 而非强转期抛出的自定义 kind。
|
||||
assert_eq!(
|
||||
eval_str("var a=[1,2,3]; Object.defineProperty(a,'length',{writable:false}); var n=0; var v={valueOf:function(){n++;throw new RangeError('x');}}; a.length=v; n+':'+a.length"),
|
||||
"0:3"
|
||||
);
|
||||
assert_eq!(
|
||||
eval_str("var a=[1,2,3]; Object.defineProperty(a,'length',{writable:false}); var n=0; var v={valueOf:function(){n++;throw new RangeError('x');}}; var r; (function(){'use strict';try{a.length=v;r='no-throw';}catch(e){r=e.name;}})(); r+':'+n+':'+a.length"),
|
||||
"TypeError:0:3"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_length_coerces_twice_before_writable_check() {
|
||||
// ToUint32 + ToNumber 各触发一次 ToPrimitive(number);第二次强转收窄可写位后
|
||||
@@ -178,6 +192,32 @@ fn push_element_write_uses_prototype_setter() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_elem_non_extensible_precedes_length_guard() {
|
||||
// 不可扩展 + length 不可写:extensible 检查先于 length 可写性判定,
|
||||
// 错误消息取 not extensible 形态(node 同序)。
|
||||
assert_eq!(
|
||||
eval_str("var a=[1]; Object.preventExtensions(a); Object.defineProperty(a,'length',{writable:false}); var m='none'; (function(){'use strict';try{a[5]=9;m='no-throw';}catch(e){m=String(e.message);}})(); /extensible/.test(m)+':'+a.length+':'+(5 in a)"),
|
||||
"true:1:false"
|
||||
);
|
||||
// 单条件各自独立生效:仅 length 不可写(可扩展)报 length 形态。
|
||||
assert_eq!(
|
||||
eval_str("var a=[1]; Object.defineProperty(a,'length',{writable:false}); var m='none'; (function(){'use strict';try{a[5]=9;m='no-throw';}catch(e){m=String(e.message);}})(); /writable/.test(m)+':'+a.length"),
|
||||
"true:1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shift_getter_temporary_survives_setter_window() {
|
||||
// 首位为 hole:Get 落原型链 getter(返回新对象),循环内用户 setter 大量
|
||||
// 分配——getter 临时对象经结果寄存器钉为 GC 根,跨重入窗口存活,返回值
|
||||
// 身份保持。
|
||||
assert_eq!(
|
||||
eval_str("var box=null; var a=[,2,3]; Object.defineProperty(Array.prototype,'0',{get:function(){box={m:1};return box;},set:function(v){Object.defineProperty(this,0,{value:v,writable:true,enumerable:true,configurable:true});var t='z';for(var i=0;i<16;i++){t=t+t;}}}); var r=a.shift(); (r===box)+':'+r.m+':'+a.length+':'+a[0]+':'+a[1]"),
|
||||
"true:1:2:2:3"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mutators_still_work_with_writable_length() {
|
||||
// 重写后正常路径回归:push/pop/shift/unshift 的元素搬移与返回值。
|
||||
|
||||
@@ -354,6 +354,27 @@ fn unreferenced_table_gens_do_not_grow_with_runs() {
|
||||
assert!(pinned > baseline, "每 run 函数对象钉住创建期代际,条目数应增长,实际 {pinned}");
|
||||
}
|
||||
|
||||
/// shift 首位 hole 落原型链 getter:getter 临时对象经结果寄存器钉为 GC 根,
|
||||
/// 跨循环内 setter 分配窗口与低阈值执行期收集存活,返回身份保持。
|
||||
#[test]
|
||||
fn shift_getter_temporary_object_survives_runtime_gc() {
|
||||
let mut vm = vm_with_threshold(512);
|
||||
let module = compile(
|
||||
"var g = {}; for (var i = 0; i < 20; i++) { g['k' + i] = 'v'.repeat(64); } \
|
||||
var box = null; var a = [, 2, 3]; \
|
||||
Object.defineProperty(Array.prototype, '0', { \
|
||||
get: function() { box = { m: 1 }; return box; }, \
|
||||
set: function(v) { \
|
||||
Object.defineProperty(this, 0, { value: v, writable: true, enumerable: true, configurable: true }); \
|
||||
var t = 'z'; for (var j = 0; j < 20; j++) { t = t + t; } } }); \
|
||||
var r = a.shift(); (r === box) + ':' + r.m + ':' + a.length + ':' + a[0] + ':' + a[1]",
|
||||
);
|
||||
let result = vm.run(&Arc::new(module)).expect("run");
|
||||
let text = vm.lookup_str(result).expect("结果应为字符串");
|
||||
assert_eq!(text, "true:1:2:2:3");
|
||||
assert!(vm.session_gc_stats().total_collections > 0, "执行期应触发收集");
|
||||
}
|
||||
|
||||
// ── 原生盒内字符串/BigInt 边存活(mark 边收集去对象预过滤) ─────────────────
|
||||
|
||||
/// 盒持唯一引用 session 串(Promise 结算值):churn 窗口内执行期收集
|
||||
|
||||
Reference in New Issue
Block a user