docs: 统一循环与声明写点的注释措辞

This commit is contained in:
2026-09-17 15:37:12 +00:00
parent a656c42f77
commit 24cc61d51e
4 changed files with 45 additions and 35 deletions
+8 -5
View File
@@ -109,10 +109,13 @@ impl Emitter {
// 脚本顶层 var:同步写全局对象,使 globalThis.x 反射声明值。
if ctx.is_global_scope && matches!(kind, VariableDeclarationKind::Var) {
if CompileCtx::is_known_builtin(name) {
// builtin 名保持 GDI 零动作写点(序言镜像值语义),不扩 strict 面。
// 内置名保持 GlobalDeclarationInstantiation(脚本顶层声明实例化)
// 序言的零动作写点——属性已存在时不改动值、仅缺失时新建;槽内保留
// 求值开始前预载的全局属性值(镜像值),本路径不扩大 strict 抛错面。
self.emit_global_prop_write(name, src_reg, ctx);
} else {
// 用户名既有属性面:声明带初始化是 PutValue,0x98 带 strict 分派。
// 用户名的既有属性面:声明带初始化是 PutValue 语义,经
// `DEFINE_GLOBAL_PROP_C`(`0x98`)并带 strict 分派。
self.emit_global_put_write(name, src_reg, ctx);
}
}
@@ -149,7 +152,7 @@ impl Emitter {
return Ok(());
}
if is_tier {
// 顶层已声明 var 解构赋值目标:值落全局对象属性(A 侧单一真值)。
// 顶层已声明 var 解构赋值目标:值写入全局对象属性——顶层 var 值的唯一存储是全局对象属性,引擎侧不另存副本。
self.emit_tier_global_write(name, src_reg, ctx);
return Ok(());
}
@@ -360,7 +363,7 @@ impl Emitter {
return Ok(());
}
if is_tier {
// 顶层已声明 var 解构赋值目标:值落全局对象属性(A 侧单一真值)。
// 顶层已声明 var 解构赋值目标:值写入全局对象属性——顶层 var 值的唯一存储是全局对象属性,引擎侧不另存副本。
self.emit_tier_global_write(name, src_reg, ctx);
return Ok(());
}
@@ -453,7 +456,7 @@ impl Emitter {
return Ok(());
}
if is_tier {
// 顶层已声明 var 对象解构赋值:值落全局对象属性(A 侧单一真值)。
// 顶层已声明 var 解构赋值目标:值写入全局对象属性——顶层 var 值的唯一存储是全局对象属性,引擎侧不另存副本。
self.emit_tier_global_write(name, prop_reg, ctx);
continue;
}
@@ -49,12 +49,16 @@ impl Emitter {
} else {
self.materialize_function_declaration(fd, &name, ctx)?
};
// 块内函数声明求值写回外层 var 绑定(sloppy web-compat):预声明期为该
// 名实例化的外层 var 绑定(函数作用域)在此写入块槽位里的函数对象,
// 求值一次写回一次(循环体内每迭代覆写头绑定)。形参/词法声明同名
// (抑制集)与顶层只读三常量名不写回(对不可写属性 put 在 sloppy 下
// 永不成功,跳过与执行等价);顶层 A 侧补全局对象属性写(与 for 头写
// 同形)。
// 块内函数声明求值后按三种情形处理:
//
// sloppy 模式下按浏览器/web 实现惯例为块级函数声明建外层 var 绑定并写回:
// 预声明期为该名实例化的函数作用域 var 绑定在此写入块槽位里的函数对象,
// 求值一次写回一次(循环体内每迭代覆写头绑定)。
//
// 形参或函数作用域树内同名词法声明(抑制集)不写回:该名被同名声明遮蔽。
//
// 顶层不可写内置名不写回:sloppy 下对其赋值(put)永不成功,跳过与执行等价;
// 顶层情形另补全局对象属性写(与 for-in 循环头的顶层写同形)。
if !ctx.is_strict
&& ctx.scopes.symbols.scopes.len() > 1
&& !ctx.block_fn_suppressed.contains(&name)
@@ -68,10 +72,10 @@ impl Emitter {
Operand::Reg(var_reg),
Operand::None,
));
// 顶层 A 侧同步写以外层绑定是否落全局作用域为准:此处块内
// Let 绑定已占内层作用域,按名解析(is_global_tier_name)会
// 命中块绑定误判为非顶层;嵌套函数作用域同名局部 var 不在
// 全局 ctx 上,经 is_global_scope 门禁不走全局对象写。
// 全局对象属性写以「外层绑定的作用域层级是否为 0(全局作用域)」判定,
// 不按名字解析:此处块内 Let 绑定已占内层作用域,按名解析
// (`is_global_tier_name`)会命中块绑定误判为非顶层;嵌套函数作用域
// 的同名局部 var 不在全局 ctx 上,经 `is_global_scope` 门禁不走全局对象写。
if ctx.is_global_scope && var_target == 0 && ctx.global_tier_names.contains(&name) {
self.emit_tier_global_write(&name, var_reg, ctx);
}
@@ -79,8 +83,9 @@ impl Emitter {
}
// 脚本顶层(非块内)函数声明:同步写全局对象,使 globalThis 可反射函数名。
// 块内声明不走本臂(其全局可见性只经上方外层 var 写回面建立)。
// 严格 eval 代码函数声明绑定 eval 自身 lexical 环境、不落全局对象:抑制 A
// 侧写(局部绑定读面未暴露),同时避免不可写全局内置在 0x98 上误抛 strict。
// 严格 eval 代码的函数声明绑定 eval 自身词法环境、不落全局对象:抑制全局对象属性写
// (局部绑定读面未暴露),同时避免不可写全局内置名在 `DEFINE_GLOBAL_PROP_C`(`0x98`,
// 严格 eval 路径经此指令)上误抛 strict `TypeError`。
if ctx.is_global_scope && ctx.scopes.symbols.scopes.len() == 1 && !(ctx.is_eval_script && ctx.is_strict) {
self.emit_global_func_bind_write(&name, var_reg, ctx);
}
+7 -5
View File
@@ -44,8 +44,9 @@ impl Emitter {
let n_labeled = ctx.take_pending_loop_labels(end_label, update_label);
// 循环头声明中被嵌套函数捕获的 let/const 绑定:每迭代 fresh cell。
let mut fresh_bindings: Vec<(String, u8)> = Vec::new();
// 循环头 let/const 声明名:update 段是 per-iteration 可变绑定
// (规范 §14.7.4.4 CreatePerIterationEnvironment 用 CreateMutableBinding),
// 循环头 let/const 声明名:update 段是 per-iteration 可变绑定(规范
// §14.7.4.4 CreatePerIterationEnvironment 用 CreateMutableBinding)——
// 规范允许 update 段写 let/const 循环变量,每迭代新建一个可变绑定;
// 编译期 const 写检查对 update 段豁免,故记录全部声明名(含未被捕获者)。
let mut update_names: Vec<String> = Vec::new();
if let Some(init) = &fr.init {
@@ -137,9 +138,10 @@ impl Emitter {
let body_result = self.emit_statement(&fr.body, ctx)?;
ctx.labels.set_label_pos(update_label, ctx.insts.len());
if let Some(update) = &fr.update {
// update 段写寄存器(而非 cell):被捕获的 let/const 循环变量每迭代 fresh,
// update 写寄存器供下一迭代 fresh 拷贝——否则 CELL_SET 会污染本迭代闭包
// 捕获的 cell。未捕获者本就走寄存器,一并登记以豁免 update 段的 const 检查。
// update 段写循环变量寄存器、不写 cell:被捕获的 let/const 循环变量每迭代
// 新分配 cell,寄存器值供其拷入(否则 CELL_SET 会污染本迭代闭包捕获的
// cell);未捕获者本就走寄存器,一并登记以豁免 update 段的 const 检查。
// 机制见 `compile_ctx.rs` 的 `register_update_names` 字段文档。
let prev = std::mem::take(&mut ctx.register_update_names);
ctx.register_update_names = update_names;
self.emit_expression(update, ctx)?;
+13 -13
View File
@@ -58,8 +58,9 @@ impl Emitter {
let tdz_idx = next;
next = next.saturating_add(1);
ctx.captured_bindings.insert(name.clone(), tdz_idx);
// 未初始化标志走 b 槽:a 槽 Imm 的高字节会覆写 b 槽,故标志并入
// 立即数高字节,dispatch 侧按 a/b 分槽取回。
// MAKE_CELL 的 16 位立即数:低字节是 cell 索引,高字节 bit 0 是
// 未初始化标记。标志折入立即数高字节(0x0100),dispatch 侧按字节
// 拆回两字段。
let undef_reg = self.emit_undefined(ctx);
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
@@ -73,8 +74,8 @@ impl Emitter {
}
/// 右值区求值完毕后把覆盖从 TDZ cell 切到体区 fresh cell:每头名分配新
/// cell 并改写映射,头发射捕获臂与体区读/捕获自然命中(每迭代
/// MAKE_CELL_FRESH 建新 cell,本迭代闭包捕获新 cell)。
/// cell 并改写映射,头发射捕获臂与体区读/捕获自然命中。每迭代新分配一个
/// cell;机制见 `compile_ctx.rs` 的 `register_update_names` 字段文档。
pub(crate) fn switch_for_head_env_to_body(&self, env: &mut ForHeadEnv, ctx: &mut CompileCtx) {
let mut next = ctx.captured_bindings.values().copied().max().map_or(0, |m| m.saturating_add(1));
for (name, _, _, body_idx) in &mut env.entries {
@@ -140,9 +141,9 @@ impl Emitter {
let is_const = matches!(decl.kind, VariableDeclarationKind::Const);
let name = bi.name.as_str();
let var_reg = ctx.alloc_reg();
// var 声明:绑定已存在(顶层 var 预声明、GDI 序言预登记
// builtin 名、同 scope 先前声明)时复用既有槽位,不重复
// 声明;let/const 同 scope 重复声明仍报错。
// var 声明:绑定已存在(顶层 var 预声明、
// GlobalDeclarationInstantiation(脚本顶层声明实例化)序言预登记的内置名、
// 同 scope 先前声明)时复用既有槽位,不重复声明;let/const 同 scope 重复声明仍报错。
let target_reg = if matches!(decl.kind, VariableDeclarationKind::Var) {
match ctx.declare(name, var_reg, decl.kind, is_const) {
Ok(()) => var_reg,
@@ -173,9 +174,9 @@ impl Emitter {
Operand::Reg(key_reg),
Operand::None,
));
// 顶层 for-in var 头:迭代值落全局对象属性(A 侧单一真值)。
// 只读三常量已在上方拦截臂跳过;其余 builtin 名属性可写,
// 迭代键照规范覆写既有全局属性。
// 顶层 for-in var 头:迭代值写入全局对象属性——顶层 var 值的唯一存储是全局对象属性,引擎侧不另存副本。
// 只读三常量(不可写全局内置)已在上方拦截臂跳过;其余内置名属性
// 可写,迭代键照规范覆写既有全局属性。
if self.is_global_tier_name(ctx, name) {
self.emit_tier_global_write(name, key_reg, ctx);
}
@@ -203,9 +204,8 @@ impl Emitter {
// 严格模式未声明写:抛 ReferenceError,跳过寄存器写(值无关)。
self.emit_strict_undeclared_write(name, ctx)?;
} else if is_tier {
// 顶层 for-in 赋值头:迭代值落全局对象属性(A 侧单一真值)。
// 只读三常量已在上方拦截臂跳过;其余 builtin 名属性可写,
// 迭代键照规范覆写既有全局属性。
// 顶层 for-in 赋值头:迭代值写入全局对象属性——顶层 var 值的唯一存储是全局对象属性,引擎侧不另存副本。
// 同上:只读三常量已在拦截臂跳过,其余内置名属性可写。
self.emit_tier_global_write(name, key_reg, ctx);
} else {
ctx.inst(Inst::new(