mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 顶层 var 撞既有属性写面对齐 node 锚定
This commit is contained in:
Generated
+18
-18
@@ -1095,7 +1095,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1120,7 +1120,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1128,7 +1128,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1139,7 +1139,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1159,7 +1159,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1168,7 +1168,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1187,7 +1187,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1201,7 +1201,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1216,7 +1216,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1225,7 +1225,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1240,7 +1240,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1252,7 +1252,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1261,7 +1261,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1276,7 +1276,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1292,7 +1292,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1304,7 +1304,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"hashbrown 0.14.5",
|
||||
@@ -1333,7 +1333,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.21"
|
||||
version = "0.8.22"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -303,13 +303,14 @@ impl Vm {
|
||||
|
||||
/// 定义全局 var 绑定数据属性:rd=全局对象,a=值,b=键。
|
||||
///
|
||||
/// 描述符语义(CreateGlobalVarBinding):
|
||||
/// - 已有可配置数据属性且不可写:no-op 返回——规范不更新既有数据描述符
|
||||
/// (writable/enumerable/configurable 与值均保持原样)。
|
||||
/// - 已有可配置属性且可写(数据或 accessor):保 enumerable/configurable、
|
||||
/// 更新值;accessor 形重定义为数据属性(既有行为,不扩面)。
|
||||
/// - 已有不可配置属性:走定义不变量检查(末尾统一路径)——描述符冲突或
|
||||
/// 不可写属性值变更时静默 no-op,否则仅更新值、描述符不变。
|
||||
/// 描述符语义(CreateGlobalVarBinding 写点,对照 node 锚定):
|
||||
/// - 已有 accessor 属性(可配置或不可配置):零修改返回——var 声明写点
|
||||
/// 不覆写访问器(两模式均不抛,值与描述符保持原样)。
|
||||
/// - 已有数据属性且不可写(可配置或不可配置):strict 抛 TypeError、
|
||||
/// sloppy 静默 no-op(规范不更新既有数据描述符,writable/enumerable/
|
||||
/// configurable 与值均保持原样)。
|
||||
/// - 已有数据属性且可写(可配置或不可配置):保 enumerable/configurable、
|
||||
/// 仅更新值。
|
||||
/// - 属性缺失:新建可写/可枚举/不可配置数据属性。
|
||||
///
|
||||
/// # 边界与前提
|
||||
@@ -323,24 +324,32 @@ impl Vm {
|
||||
let prop_name_si = self.property_key_si(self.regs[b])?;
|
||||
let value = self.regs[a];
|
||||
let obj = unsafe { &mut *obj_val.as_js_object_ptr() };
|
||||
// 已有可配置属性:CreateGlobalVarBinding 不改既有数据描述符;可写数据
|
||||
// 属性仅更新值(保 e/c),accessor 形重定义为数据属性。
|
||||
// 已有属性:CreateGlobalVarBinding 不改既有描述符——accessor 形零修改
|
||||
// (不覆写、不抛);数据属性不可写时 strict 抛 TypeError、sloppy 静默
|
||||
// no-op;可写数据属性保 enumerable/configurable 仅更新值。
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
||||
if let Some(current) = obj.prop_meta_at(pos) {
|
||||
if current.attributes.configurable() {
|
||||
// 既有数据属性不可写:不更新描述符也不更新值(规范零修改)。
|
||||
if !current.is_accessor && !current.attributes.writable() {
|
||||
// accessor 形:var 声明写点不覆写访问器,两模式均零修改。
|
||||
if current.is_accessor {
|
||||
return Ok(());
|
||||
}
|
||||
// 既有数据属性不可写(可配置与不可配置同口径):strict 抛
|
||||
// TypeError、sloppy 静默 no-op。
|
||||
if !current.attributes.writable() {
|
||||
return if self.current_strict() {
|
||||
self.raise_error_kind("TypeError", "cannot assign to read-only property")
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
// 可写数据属性:保 enumerable/configurable、仅更新值。
|
||||
let attrs =
|
||||
PropAttributes::new(true, current.attributes.enumerable(), current.attributes.configurable());
|
||||
let _ = self.define_data_property(obj, prop_name_si, value, attrs);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 属性缺失或不可配置既有属性:统一走定义,不可配置时由定义侧不变量
|
||||
// 检查决定更新值或静默 no-op。
|
||||
// 属性缺失:新建可写/可枚举/不可配置数据属性。
|
||||
let _ = self.define_data_property(obj, prop_name_si, value, PropAttributes::new(true, true, false));
|
||||
Ok(())
|
||||
}
|
||||
@@ -351,8 +360,9 @@ impl Vm {
|
||||
/// eval 脚本 var/函数声明的属性描述符)。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 属性已存在:CreateGlobalVarBinding 不改既有描述符——保持原属性只更新
|
||||
/// 值(不可写数据/访问器:strict 抛 TypeError、sloppy 静默 no-op)。
|
||||
/// 1. 属性已存在:CreateGlobalVarBinding 不改既有描述符——accessor 形零修改
|
||||
/// (不覆写、不抛);数据属性不可写时 strict 抛 TypeError、sloppy 静默
|
||||
/// no-op;可写数据属性保原描述符仅更新值。
|
||||
/// 2. 属性缺失:新建可写/可枚举/可配置属性;全局对象不可扩展 → TypeError
|
||||
/// (两模式均抛,CreateGlobalVarBinding 语义)。
|
||||
///
|
||||
@@ -370,18 +380,24 @@ impl Vm {
|
||||
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject;
|
||||
// SAFETY: 全局对象钉在 session 永久区,指针在 VM 生命周期内有效。
|
||||
let obj = unsafe { &mut *global_ptr };
|
||||
// 属性已存在:保持原描述符只更新值,不升级 configurable(规范:
|
||||
// CreateGlobalVarBinding 对既有属性不改描述符)。
|
||||
// 属性已存在:CreateGlobalVarBinding 不改既有描述符——accessor 形零修改
|
||||
// (不覆写、不抛);数据属性不可写时 strict 抛 TypeError、sloppy 静默
|
||||
// no-op;可写数据属性保原描述符仅更新值。
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), si) {
|
||||
if let Some(current) = obj.prop_meta_at(pos) {
|
||||
let writable = !current.is_accessor && current.attributes.writable();
|
||||
if !writable {
|
||||
// accessor 形:var 声明写点不覆写访问器,两模式均零修改。
|
||||
if current.is_accessor {
|
||||
return Ok(());
|
||||
}
|
||||
// 既有数据属性不可写:strict 抛 TypeError、sloppy 静默 no-op。
|
||||
if !current.attributes.writable() {
|
||||
return if self.current_strict() {
|
||||
self.raise_error_kind("TypeError", "cannot assign to read-only property")
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
// 可写数据属性:保原描述符仅更新值。
|
||||
return self.define_data_property(obj, si, value, current.attributes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,3 +616,43 @@ fn nonextensible_global_var_existing_property_no_throw() {
|
||||
"var ex; ex === 1 && globalThis.ex === 1",
|
||||
);
|
||||
}
|
||||
|
||||
// ── 顶层 var 撞 builtin 名与 accessor 形:写面对照 node 锚定(零覆写 / 可写仅更值)──
|
||||
|
||||
#[test]
|
||||
fn var_init_on_builtin_math_updates_value() {
|
||||
// var Math = 1:Math 是既有可写数据属性(c:true、e:false),PutValue 更新
|
||||
// 值、保 enumerable;裸读与反射见同一新值。
|
||||
eval_truthy("var Math = 1; Math === 1 && globalThis.Math === 1 && typeof Math === 'number'");
|
||||
eval_truthy(
|
||||
"var Math = 1; var d = Object.getOwnPropertyDescriptor(globalThis, 'Math'); \
|
||||
d.value === 1 && d.writable === true && d.enumerable === false && d.configurable === true",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strict_var_init_on_builtin_math_updates_value() {
|
||||
// strict 同形:可写 builtin 名更新值不抛。
|
||||
eval_truthy("'use strict'; var Math = 1; Math === 1 && globalThis.Math === 1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_init_on_accessor_property_does_not_overwrite() {
|
||||
// accessor 形:var 声明写点不覆写访问器,两模式均零修改(描述符保持原样)。
|
||||
// 既有 accessor 须先于 GDI 存在,分两阶段。写面锚定:globalThis 反射见
|
||||
// 访问器原值(getter 返回 1),描述符保持 accessor 形(get 在、无 value 面)。
|
||||
assert_two_phases_truthy(
|
||||
"Object.defineProperty(globalThis, 'acc', {get() { return 1; }, configurable: true})",
|
||||
"var acc = 2; globalThis.acc === 1",
|
||||
);
|
||||
assert_two_phases_truthy(
|
||||
"Object.defineProperty(globalThis, 'acc2', {get() { return 1; }, configurable: true})",
|
||||
"var acc2 = 2; var d = Object.getOwnPropertyDescriptor(globalThis, 'acc2'); \
|
||||
typeof d.get === 'function' && d.value === undefined",
|
||||
);
|
||||
// strict 同形:accessor 零修改不抛。
|
||||
assert_two_phases_truthy(
|
||||
"Object.defineProperty(globalThis, 'acc3', {get() { return 1; }, configurable: true})",
|
||||
"'use strict'; var acc3 = 2; globalThis.acc3 === 1",
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user