fix: 不可写全局内置(undefined/NaN/Infinity)寄存器镜像写编译期拦截——sloppy 静默 no-op、strict 抛 TypeError

This commit is contained in:
2026-09-09 23:17:01 +08:00
parent 2457f283fe
commit b77a9322e5
9 changed files with 394 additions and 33 deletions
+19
View File
@@ -134,6 +134,11 @@ const BUILTIN_GLOBALS: &[&str] = &[
"$262",
];
/// 不可写全局内置名:全局对象上的数据属性为 {writable:false, configurable:false},
/// 对它们的 put 永不成功。写路径命中这些名字的全局绑定(非局部遮蔽)时编译期
/// 拦截:sloppy 静默丢弃、strict 抛 TypeError;其余内置名属性可写,写路径放行。
const NON_WRITABLE_GLOBAL_BUILTINS: &[&str] = &["undefined", "NaN", "Infinity"];
pub(crate) struct FieldBuffer {
pub(crate) insts: Vec<Inst>,
pub(crate) labels: Vec<(LabelId, usize)>,
@@ -657,6 +662,20 @@ impl CompileCtx {
false
}
/// 写目标是否为不可写全局内置(undefined/NaN/Infinity 的全局绑定)。
/// 名字在名单内且解析寄存器是全局内置槽(builtin_reg_map 登记),或名字落到
/// 全局作用域绑定(顶层 var 预声明/隐式全局,含继承的全局槽)——局部
/// var/let/参数遮蔽同名时解析到局部寄存器/局部作用域,两条件均不命中。
pub(crate) fn targets_readonly_builtin(&self, name: &str, reg: u32) -> bool {
if !NON_WRITABLE_GLOBAL_BUILTINS.contains(&name) {
return false;
}
if self.scopes.builtin_reg_map.iter().any(|(n, r)| n == name && *r == reg) {
return true;
}
matches!(self.scopes.symbols.lookup_any_binding(name), Some((_, 0)))
}
pub(crate) fn is_known_builtin(name: &str) -> bool {
BUILTIN_GLOBALS.contains(&name)
}