mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 函数名登记为作用域内不可写绑定并按帧槽写入函数对象
This commit is contained in:
Generated
+19
-19
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1226,7 +1226,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1235,7 +1235,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1255,7 +1255,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1269,7 +1269,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1284,7 +1284,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1296,7 +1296,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1305,7 +1305,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1319,7 +1319,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1331,7 +1331,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1340,7 +1340,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1355,7 +1355,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1371,7 +1371,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1384,7 +1384,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1402,7 +1402,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1415,7 +1415,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.13.19"
|
||||
version = "0.13.20"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -66,6 +66,9 @@ pub struct CompiledModule {
|
||||
pub captured_this_const_idx: u16,
|
||||
/// 由赋值上下文推断的函数名,在变量声明 / 对象属性赋值点设置。
|
||||
pub function_name: Option<String>,
|
||||
/// 函数名不可写绑定的寄存器(帧槽写入目标):压帧时把 callee 函数对象写入该槽。
|
||||
/// `None` 表示无名绑定(匿名函数 / 形参或 var 同名抑制 / arguments 特例)。
|
||||
pub function_name_reg: Option<u32>,
|
||||
/// 函数 `length` 属性值:第一个带默认值/解构默认的形参之前的形参数(rest 不计)。
|
||||
pub function_length: u32,
|
||||
/// 形参列表是否 simple(全部无初始值标识符且无 rest):arguments 对象
|
||||
@@ -110,6 +113,7 @@ impl CompiledModule {
|
||||
is_strict: false,
|
||||
captured_this_const_idx: 0,
|
||||
function_name: None,
|
||||
function_name_reg: None,
|
||||
function_length: 0,
|
||||
has_simple_params: false,
|
||||
is_class_constructor: false,
|
||||
@@ -146,6 +150,7 @@ impl Clone for CompiledModule {
|
||||
is_strict: self.is_strict,
|
||||
captured_this_const_idx: self.captured_this_const_idx,
|
||||
function_name: self.function_name.clone(),
|
||||
function_name_reg: self.function_name_reg,
|
||||
function_length: self.function_length,
|
||||
has_simple_params: self.has_simple_params,
|
||||
is_class_constructor: self.is_class_constructor,
|
||||
|
||||
@@ -271,6 +271,7 @@ impl Emitter {
|
||||
&field_value_exprs,
|
||||
&extra_upvalue_names,
|
||||
true,
|
||||
None,
|
||||
)?
|
||||
} else {
|
||||
let mut module = self.compile_function_body_with_field_hooks(
|
||||
@@ -285,6 +286,7 @@ impl Emitter {
|
||||
&field_value_exprs,
|
||||
&extra_upvalue_names,
|
||||
true,
|
||||
None,
|
||||
)?;
|
||||
if is_derived {
|
||||
module.insts.clear();
|
||||
|
||||
@@ -138,6 +138,7 @@ impl Emitter {
|
||||
method_value.generator,
|
||||
method_value.r#async,
|
||||
true,
|
||||
None,
|
||||
)?;
|
||||
ctx.in_instance_method = saved_instance;
|
||||
ctx.in_static_method = saved_static;
|
||||
|
||||
@@ -208,6 +208,14 @@ pub struct CompileCtx {
|
||||
/// 运行时与模块 flat_id 组成模板对象缓存键,保证同一编译树同 site 恒返回
|
||||
/// 同一对象、不同编译树(eval 每次编译)互不共享。
|
||||
pub(crate) next_template_site: u32,
|
||||
/// 本函数登记的函数名(非抑制面):`assemble_ir` 回写到 IR 供调试与
|
||||
/// 帧槽写入判定。抑制面(形参/var 同名)不登记名绑定,此字段仍记名
|
||||
/// 供 `instantiate_var_bindings` 排除入口 undefined 写。
|
||||
pub(crate) function_name: Option<String>,
|
||||
/// 函数名不可写绑定的寄存器(帧槽写入目标):压帧时把 callee 函数对象
|
||||
/// 写入该槽。非抑制面在名登记时分配;抑制面(var 同名)在
|
||||
/// `instantiate_var_bindings` 回填为 var 槽寄存器。
|
||||
pub(crate) function_name_reg: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
@@ -304,6 +312,8 @@ impl CompileCtx {
|
||||
module_self_aliases: HashMap::new(),
|
||||
module_alias_pairs: Vec::new(),
|
||||
next_template_site: 0,
|
||||
function_name: None,
|
||||
function_name_reg: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,6 +1014,7 @@ impl CompileCtx {
|
||||
is_strict: self.is_strict,
|
||||
captured_this_const_idx: 0,
|
||||
function_name: None,
|
||||
function_name_reg: self.function_name_reg,
|
||||
function_length: self.function_length,
|
||||
has_simple_params: self.has_simple_params,
|
||||
is_top_level: parent_ctx.is_none(),
|
||||
|
||||
@@ -47,6 +47,7 @@ impl Emitter {
|
||||
is_expr_body,
|
||||
true,
|
||||
arrow.has_use_strict_directive(),
|
||||
None,
|
||||
)?
|
||||
} else {
|
||||
self.compile_function_body(
|
||||
@@ -56,6 +57,7 @@ impl Emitter {
|
||||
is_expr_body,
|
||||
true,
|
||||
arrow.has_use_strict_directive(),
|
||||
None,
|
||||
)?
|
||||
};
|
||||
sub_module.is_arrow = true;
|
||||
@@ -98,14 +100,15 @@ impl Emitter {
|
||||
let body_stmts: &[Statement] = if let Some(body) = &fe.body { &body.statements } else { &[] };
|
||||
|
||||
let own_strict = fe.has_use_strict_directive();
|
||||
let fn_name = fe.id.as_ref().map(|id| id.name.as_str());
|
||||
let mut sub_module = if fe.generator && fe.r#async {
|
||||
self.compile_async_generator_body(¶m_names, body_stmts, ctx, own_strict)?
|
||||
self.compile_async_generator_body(¶m_names, body_stmts, ctx, own_strict, fn_name)?
|
||||
} else if fe.generator {
|
||||
self.compile_generator_body(¶m_names, body_stmts, ctx, own_strict)?
|
||||
self.compile_generator_body(¶m_names, body_stmts, ctx, own_strict, fn_name)?
|
||||
} else if fe.r#async {
|
||||
self.compile_async_body(¶m_names, body_stmts, ctx, false, false, own_strict)?
|
||||
self.compile_async_body(¶m_names, body_stmts, ctx, false, false, own_strict, fn_name)?
|
||||
} else {
|
||||
self.compile_function_body(¶m_names, body_stmts, ctx, false, false, own_strict)?
|
||||
self.compile_function_body(¶m_names, body_stmts, ctx, false, false, own_strict, fn_name)?
|
||||
};
|
||||
if let Some(id) = &fe.id {
|
||||
sub_module.function_name = Some(id.name.to_string());
|
||||
|
||||
@@ -141,10 +141,12 @@ impl Emitter {
|
||||
///
|
||||
/// `is_expression_body` 为 true(箭头表达式体)时返回最后一个表达式的值,
|
||||
/// 否则返回 undefined。`is_arrow` 控制 super 相关标志的继承:箭头函数词法
|
||||
/// 继承外层 super,普通函数重置 super 作用域。
|
||||
/// 继承外层 super,普通函数重置 super 作用域。`name` 为函数名(具名函数
|
||||
/// 声明/表达式传名,箭头与匿名传 `None`),用于函数名不可写绑定登记。
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn compile_function_body<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, is_arrow: bool, own_strict: bool,
|
||||
is_expression_body: bool, is_arrow: bool, own_strict: bool, name: Option<&str>,
|
||||
) -> Result<IRFunction, String> {
|
||||
self.compile_function_body_with_flags(
|
||||
param_specs,
|
||||
@@ -155,12 +157,14 @@ impl Emitter {
|
||||
false,
|
||||
false,
|
||||
own_strict,
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
/// 编译函数体并显式指定生成器标志(`function*` 走此入口)。
|
||||
pub(crate) fn compile_generator_body<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, own_strict: bool,
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
own_strict: bool, name: Option<&str>,
|
||||
) -> Result<IRFunction, String> {
|
||||
self.compile_function_body_with_flags(
|
||||
param_specs,
|
||||
@@ -171,6 +175,7 @@ impl Emitter {
|
||||
true,
|
||||
false,
|
||||
own_strict,
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -178,16 +183,20 @@ impl Emitter {
|
||||
/// 同时标记 `is_generator` 与 `is_async`,VM 调用时按异步生成器协议执行
|
||||
/// (next 返回 Promise,yield 挂起与 await 挂起共存)。
|
||||
pub(crate) fn compile_async_generator_body<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, own_strict: bool,
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
own_strict: bool, name: Option<&str>,
|
||||
) -> Result<IRFunction, String> {
|
||||
self.compile_function_body_with_flags(param_specs, body_stmts, parent_ctx, false, false, true, true, own_strict)
|
||||
self.compile_function_body_with_flags(
|
||||
param_specs, body_stmts, parent_ctx, false, false, true, true, own_strict, name,
|
||||
)
|
||||
}
|
||||
|
||||
/// 编译异步函数体(`async function` / async 箭头走此入口):`is_async` 使
|
||||
/// `assemble_ir` 标记模块,VM 调用时按异步函数协议执行。
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn compile_async_body<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, is_arrow: bool, own_strict: bool,
|
||||
is_expression_body: bool, is_arrow: bool, own_strict: bool, name: Option<&str>,
|
||||
) -> Result<IRFunction, String> {
|
||||
self.compile_function_body_with_flags(
|
||||
param_specs,
|
||||
@@ -198,6 +207,7 @@ impl Emitter {
|
||||
false,
|
||||
true,
|
||||
own_strict,
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -205,6 +215,7 @@ impl Emitter {
|
||||
fn compile_function_body_with_flags<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, is_arrow: bool, is_generator: bool, is_async: bool, own_strict: bool,
|
||||
name: Option<&str>,
|
||||
) -> Result<IRFunction, String> {
|
||||
let body_context = if is_arrow {
|
||||
FunctionBodyContext::Arrow
|
||||
@@ -221,6 +232,7 @@ impl Emitter {
|
||||
is_generator,
|
||||
is_async,
|
||||
own_strict,
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -228,7 +240,7 @@ impl Emitter {
|
||||
pub(crate) fn compile_function_body_with_bindings_gen<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
|
||||
is_generator: bool, is_async: bool, own_strict: bool,
|
||||
is_generator: bool, is_async: bool, own_strict: bool, name: Option<&str>,
|
||||
) -> Result<IRFunction, String> {
|
||||
self.compile_function_body_with_field_hooks_gen(
|
||||
param_specs,
|
||||
@@ -244,6 +256,7 @@ impl Emitter {
|
||||
is_generator,
|
||||
is_async,
|
||||
own_strict,
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -259,7 +272,7 @@ impl Emitter {
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
|
||||
emit_fields: Option<E>, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>],
|
||||
extra_upvalue_names: &[(&str, u8)], own_strict: bool,
|
||||
extra_upvalue_names: &[(&str, u8)], own_strict: bool, name: Option<&str>,
|
||||
) -> Result<IRFunction, String>
|
||||
where
|
||||
E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>,
|
||||
@@ -278,6 +291,7 @@ impl Emitter {
|
||||
false,
|
||||
false,
|
||||
own_strict,
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -287,6 +301,7 @@ impl Emitter {
|
||||
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
|
||||
mut emit_fields: Option<E>, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>],
|
||||
extra_upvalue_names: &[(&str, u8)], is_generator: bool, is_async: bool, own_strict: bool,
|
||||
name: Option<&str>,
|
||||
) -> Result<IRFunction, String>
|
||||
where
|
||||
E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>,
|
||||
@@ -368,6 +383,7 @@ impl Emitter {
|
||||
// 父层 cell 索引在子帧无效:子帧经 upvalue 路径访问父捕获
|
||||
// 绑定,不复制索引(复制会让解析点误发子帧 cell 表读)。
|
||||
cell_idx: None,
|
||||
non_writable: binding.non_writable,
|
||||
},
|
||||
);
|
||||
inherited_reg_start = inherited_reg_start.max(binding.reg.saturating_add(1));
|
||||
@@ -394,6 +410,7 @@ impl Emitter {
|
||||
lexical: false,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
non_writable: false,
|
||||
},
|
||||
);
|
||||
inherited_reg_start = inherited_reg_start.max(reg.saturating_add(1));
|
||||
@@ -411,6 +428,7 @@ impl Emitter {
|
||||
body_context,
|
||||
extra_capture_exprs,
|
||||
extra_upvalue_names,
|
||||
name,
|
||||
)?;
|
||||
// 实例字段 computed key 数组所在 upvalue 下标,供字段初始化 emit 定位。
|
||||
ctx.field_keys_uv = ctx
|
||||
@@ -458,6 +476,22 @@ impl Emitter {
|
||||
// MAKE_CELL(undefined) 实例化,此处只补未捕获名。
|
||||
self.instantiate_var_bindings(body_stmts, &mut ctx);
|
||||
|
||||
// 被捕获的函数名绑定同样建 cell(MAKE_CELL):值源是帧槽写入已置位的
|
||||
// 名槽寄存器(函数对象),非 undefined。名槽寄存器此时已知(非抑制面
|
||||
// 在名登记时分配、抑制面在 instantiate_var_bindings 回填)。
|
||||
if let Some(fn_name) = ctx.function_name.as_deref() {
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(fn_name) {
|
||||
if let Some(name_reg) = ctx.function_name_reg {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::MAKE_CELL,
|
||||
Operand::Reg(name_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
Operand::None,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 函数体是释放作用域:仅当体含 using 声明时发 mark/pop(无 using 的体
|
||||
// 不发,防早退 return 跳过 POP 留未配对水位错乱外层对齐)。
|
||||
let has_using = Self::scope_contains_using(body_stmts);
|
||||
@@ -596,12 +630,18 @@ impl Emitter {
|
||||
true
|
||||
}
|
||||
|
||||
/// 参数 prologue:函数作用域 + 参数声明/解构 + 闭包捕获与 upvalue 分析。返回 param_base。
|
||||
/// 参数 prologue:函数作用域 + 参数声明/解构 + 函数名不可写绑定登记 +
|
||||
/// 闭包捕获与 upvalue 分析。返回 param_base。
|
||||
///
|
||||
/// `name` 为函数名(具名函数声明/表达式传名,箭头与匿名传 `None`):
|
||||
/// 非抑制面在函数作用域登记不可写绑定并分配名槽寄存器(帧槽写入目标);
|
||||
/// 抑制面(形参/var 同名、arguments 特例)不建名绑定,var 同名时名槽
|
||||
/// 回填到 var 槽寄存器(`instantiate_var_bindings` 处)。
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn emit_params_prologue<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
ctx: &mut CompileCtx, body_context: FunctionBodyContext, extra_capture_exprs: &[&'a Expression<'a>],
|
||||
extra_upvalue_names: &[(&str, u8)],
|
||||
extra_upvalue_names: &[(&str, u8)], name: Option<&str>,
|
||||
) -> Result<u32, String> {
|
||||
ctx.push_scope_with_kind(ScopeKind::FunctionScope);
|
||||
let param_base = ctx.next_reg;
|
||||
@@ -655,6 +695,48 @@ impl Emitter {
|
||||
arguments_reg = Some(reg);
|
||||
}
|
||||
|
||||
// 函数名不可写绑定(15.2.10.1 步 m):函数名在函数作用域登记为不可写
|
||||
// 绑定,帧槽写入把它初始化为函数对象。抑制面(形参同名 / 体内容器 var
|
||||
// 同名 / arguments 对象占位)不建名绑定:前两者名解析到参数/var 绑定,
|
||||
// 后者 arguments 绑定占位(var 同名时由帧槽写入初始化为函数对象)。
|
||||
// 名登记须先于 set_captured_bindings:嵌套函数捕获名分析依赖 own_bindings
|
||||
// 完整(名被捕获时须识别为本函数绑定并建 cell)。
|
||||
if let Some(fn_name) = name {
|
||||
let var_names = collect_var_binding_names(body_stmts);
|
||||
let suppressed = ctx.param_names.contains(fn_name)
|
||||
|| var_names.contains(fn_name)
|
||||
|| (fn_name == "arguments" && arguments_reg.is_some());
|
||||
if !suppressed {
|
||||
let reg = ctx.alloc_reg();
|
||||
ctx.scopes
|
||||
.symbols
|
||||
.scopes
|
||||
.last_mut()
|
||||
.expect("函数作用域已压入")
|
||||
.bindings
|
||||
.insert(
|
||||
fn_name.to_string(),
|
||||
Binding {
|
||||
reg,
|
||||
initialized: true,
|
||||
is_const: false,
|
||||
lexical: false,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
non_writable: true,
|
||||
},
|
||||
);
|
||||
ctx.own_bindings.insert(fn_name.to_string());
|
||||
ctx.function_name = Some(fn_name.to_string());
|
||||
ctx.function_name_reg = Some(reg);
|
||||
} else if var_names.contains(fn_name) {
|
||||
// 抑制面:var 绑定持名槽,帧槽写入把函数对象写入该 var 槽。
|
||||
// var 绑定此时未声明(predeclare_var_declarations 在后),名槽
|
||||
// 寄存器在 instantiate_var_bindings 回填。
|
||||
ctx.function_name = Some(fn_name.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// 字段初始化表达式(值表达式)与参数默认值一并纳入捕获分析。
|
||||
let mut capture_exprs: Vec<&oxide_parser::Expression> = param_defaults.clone();
|
||||
capture_exprs.extend_from_slice(extra_capture_exprs);
|
||||
@@ -844,6 +926,9 @@ impl Emitter {
|
||||
.into_iter()
|
||||
.filter(|n| !param_names.contains(&n.as_str()) && n != "arguments")
|
||||
.filter(|n| ctx.captured_bindings.contains_key(n))
|
||||
// 函数名(抑制面 var 同名)由专属 MAKE_CELL 处理(值源是帧槽写入的
|
||||
// 名槽寄存器,非 undefined),此处排除以免误发 undefined 源。
|
||||
.filter(|n| Some(n.as_str()) != ctx.function_name.as_deref())
|
||||
.collect();
|
||||
// HashSet 迭代序带随机种子,排序后入口 MAKE_CELL 发射序跨进程稳定。
|
||||
var_names.sort();
|
||||
@@ -926,6 +1011,17 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
// 抑制面:函数名是 var 绑定,帧槽写入把它初始化为函数对象,入口 undefined
|
||||
// 写须排除该名(否则覆盖帧槽写入的函数对象),并回填名槽寄存器供帧槽写入。
|
||||
// 非抑制面名绑定不是 var(不在 name_set 内),remove 返回 false 不回填。
|
||||
if let Some(fn_name) = ctx.function_name.as_deref() {
|
||||
if name_set.remove(fn_name) {
|
||||
if let Some(reg) = ctx.scopes.symbols.lookup_any(fn_name) {
|
||||
ctx.function_name_reg = Some(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut names: Vec<String> = name_set
|
||||
.into_iter()
|
||||
.filter(|n| !ctx.param_names.contains(n) && n != "arguments")
|
||||
|
||||
@@ -152,13 +152,13 @@ impl Emitter {
|
||||
let body_stmts: &[Statement] = if let Some(body) = &fd.body { &body.statements } else { &[] };
|
||||
let own_strict = fd.has_use_strict_directive();
|
||||
let mut sub_module = if fd.generator && fd.r#async {
|
||||
self.compile_async_generator_body(¶m_names, body_stmts, ctx, own_strict)?
|
||||
self.compile_async_generator_body(¶m_names, body_stmts, ctx, own_strict, Some(name))?
|
||||
} else if fd.generator {
|
||||
self.compile_generator_body(¶m_names, body_stmts, ctx, own_strict)?
|
||||
self.compile_generator_body(¶m_names, body_stmts, ctx, own_strict, Some(name))?
|
||||
} else if fd.r#async {
|
||||
self.compile_async_body(¶m_names, body_stmts, ctx, false, false, own_strict)?
|
||||
self.compile_async_body(¶m_names, body_stmts, ctx, false, false, own_strict, Some(name))?
|
||||
} else {
|
||||
self.compile_function_body(¶m_names, body_stmts, ctx, false, false, own_strict)?
|
||||
self.compile_function_body(¶m_names, body_stmts, ctx, false, false, own_strict, Some(name))?
|
||||
};
|
||||
sub_module.function_name = Some(name.to_string());
|
||||
ctx.nested.push(sub_module);
|
||||
|
||||
@@ -34,6 +34,9 @@ pub(crate) struct Binding {
|
||||
/// 函数级绑定由捕获分析的名字排序分配回填;块级遮蔽绑定在预声明点
|
||||
/// 追加新索引。解析点按绑定实例取索引,同名多绑定各持各的 cell。
|
||||
pub(crate) cell_idx: Option<u8>,
|
||||
/// 函数名不可写绑定标志(与 `is_const` 正交):函数名绑定在 sloppy 模式
|
||||
/// 写静默失败、strict 抛 TypeError,模式相关故独立于 const 的无条件抛错。
|
||||
pub(crate) non_writable: bool,
|
||||
}
|
||||
|
||||
/// 作用域符号表:名字 → 寄存器号/初始化状态/const 标志。
|
||||
@@ -120,6 +123,7 @@ impl SymbolTable {
|
||||
lexical: !matches!(kind, VariableDeclarationKind::Var),
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
non_writable: false,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
@@ -196,6 +200,7 @@ impl SymbolTable {
|
||||
lexical: false,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
non_writable: false,
|
||||
},
|
||||
);
|
||||
reg_for_new
|
||||
@@ -214,6 +219,19 @@ impl SymbolTable {
|
||||
false
|
||||
}
|
||||
|
||||
/// 返回已初始化绑定是否为函数名不可写绑定(用于写路径守卫);未初始化/未找到返回 false。
|
||||
pub fn lookup_non_writable(&self, name: &str) -> bool {
|
||||
for scope in self.scopes.iter().rev() {
|
||||
if let Some(b) = scope.bindings.get(name) {
|
||||
if b.initialized {
|
||||
return b.non_writable;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// 声明并直接标记为已初始化;绑定已存在时仅补初始化标志(供预声明路径)。
|
||||
pub fn declare_initialized(
|
||||
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind, is_const: bool,
|
||||
@@ -238,6 +256,7 @@ impl SymbolTable {
|
||||
lexical: !matches!(kind, VariableDeclarationKind::Var),
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
non_writable: false,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
@@ -252,6 +271,7 @@ impl SymbolTable {
|
||||
lexical: false,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
non_writable: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -278,6 +298,7 @@ impl SymbolTable {
|
||||
lexical: !matches!(kind, VariableDeclarationKind::Var),
|
||||
predeclared: true,
|
||||
cell_idx: None,
|
||||
non_writable: false,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
@@ -339,6 +360,7 @@ impl SymbolTable {
|
||||
lexical: true,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
non_writable: false,
|
||||
},
|
||||
);
|
||||
self.aliases.insert(local.to_string(), base);
|
||||
|
||||
@@ -62,6 +62,9 @@ pub struct IRFunction {
|
||||
pub is_strict: bool,
|
||||
pub captured_this_const_idx: u16,
|
||||
pub function_name: Option<String>,
|
||||
/// 函数名不可写绑定的寄存器(帧槽写入目标):压帧时把 callee 函数对象写入该槽。
|
||||
/// `None` 表示无名绑定(匿名函数 / 形参或 var 同名抑制 / arguments 特例)。
|
||||
pub function_name_reg: Option<u32>,
|
||||
/// 函数 `length` 属性值:第一个带默认值/解构默认的形参之前的形参数(rest 不计)。
|
||||
pub function_length: u32,
|
||||
/// 形参列表是否 simple(全部无初始值标识符且无 rest):arguments 对象
|
||||
@@ -99,6 +102,7 @@ impl IRFunction {
|
||||
is_strict: false,
|
||||
captured_this_const_idx: 0,
|
||||
function_name: None,
|
||||
function_name_reg: None,
|
||||
function_length: 0,
|
||||
has_simple_params: false,
|
||||
is_top_level: false,
|
||||
|
||||
@@ -89,6 +89,7 @@ pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
|
||||
is_strict: f.is_strict,
|
||||
captured_this_const_idx: f.captured_this_const_idx,
|
||||
function_name: f.function_name.clone(),
|
||||
function_name_reg: f.function_name_reg,
|
||||
function_length: f.function_length,
|
||||
has_simple_params: f.has_simple_params,
|
||||
is_class_constructor: f.is_class_constructor,
|
||||
|
||||
@@ -58,6 +58,15 @@ pub(super) fn run(f: &mut IRFunction, map: &AllocMap) {
|
||||
// 直接槽引用(class field 计算键等)的 escaped vreg 已由预着色恒等保留。
|
||||
// 注:cell 捕获变量的父 vreg 可被 RegAlloc 移动(MAKE_CELL 后值入 cell,与寄存器无关),
|
||||
// 此处不做恒等断言。
|
||||
|
||||
// 函数名不可写绑定寄存器回写:vreg → 物理槽(与 builtin_reg_map 同口径)。
|
||||
// 映射缺失(名槽无字节码引用,帧槽写入为死写)时置 None,VM 侧跳过写入。
|
||||
if let Some(vreg) = f.function_name_reg {
|
||||
f.function_name_reg = match map.map.get(&vreg) {
|
||||
Some(Alloc::Phys(p)) => Some(*p),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -293,6 +293,13 @@ impl Vm {
|
||||
};
|
||||
self.regs[sub_param_base + i] = v;
|
||||
}
|
||||
// 函数名不可写绑定帧槽写入:把 callee 函数对象写入名槽寄存器(压帧时置位,
|
||||
// 函数体入口的 MAKE_CELL / 读取据此取函数对象)。无名绑定(None)不写。
|
||||
// 须在 this 绑定之前:名槽寄存器与 this 槽(254)互不重叠,但集中在此
|
||||
// 保持帧初始化顺序清晰。
|
||||
if let Some(name_reg) = sub.function_name_reg {
|
||||
self.regs[name_reg as usize] = callee;
|
||||
}
|
||||
// this 绑定:箭头函数恒用词法捕获;sloppy 普通函数 this 为 null/undefined 时
|
||||
// 替换为全局对象,其余原始值经 ToObject 盒装(ECMA-262 10.4.3);严格模式
|
||||
// this 原样保留。
|
||||
|
||||
@@ -17,6 +17,15 @@ fn assert_num(result: JsValue, expected: f64) {
|
||||
assert!((actual - expected).abs() < 0.0001, "expected {expected}, got {actual}");
|
||||
}
|
||||
|
||||
/// 判断值是否为函数对象:经对象指针解出 header 函数标志,非对象返回假。
|
||||
fn is_function_value(v: JsValue) -> bool {
|
||||
let ptr = v.as_js_object_ptr();
|
||||
if ptr.is_null() {
|
||||
return false;
|
||||
}
|
||||
unsafe { (*ptr).is_function() }
|
||||
}
|
||||
|
||||
// --- Function Declaration Basics ---
|
||||
|
||||
#[test]
|
||||
@@ -218,3 +227,61 @@ fn function_default_prototype_accepts_member_assignment() {
|
||||
let rendered = vm.lookup_str(result).unwrap_or_default();
|
||||
assert_eq!(rendered, "ok");
|
||||
}
|
||||
|
||||
// ── 函数名不可写局部绑定(函数作用域内读回函数对象)──
|
||||
|
||||
#[test]
|
||||
fn fn_name_binding_readable() {
|
||||
let mut vm = Vm::new();
|
||||
// 函数名登记进函数作用域,体内裸读 f 解析到名绑定,读回函数对象本身。
|
||||
let result = eval(&mut vm, "function f() { return f; } f()").unwrap();
|
||||
assert!(is_function_value(result), "expected the function itself, got: {:?}", result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_name_binding_shadows_outer_var() {
|
||||
let mut vm = Vm::new();
|
||||
// 外层 var f 持 'x';函数表达式名绑定 f 在函数作用域内优先,体内读回函数对象而非 'x'。
|
||||
let result = eval(&mut vm, "var f = 'x'; var g = function f() { return typeof f; }; g()").unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "function");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_name_var_suppression() {
|
||||
let mut vm = Vm::new();
|
||||
// 体内容器 var f 同名:不建不可写绑定,var 绑定由帧槽写入初始化为函数对象。
|
||||
let result = eval(&mut vm, "function f() { var f; return f; } f()").unwrap();
|
||||
assert!(is_function_value(result), "expected the function, got: {:?}", result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_name_param_priority() {
|
||||
let mut vm = Vm::new();
|
||||
// 形参同名:形参绑定持有实参,名绑定被抑制,读回实参值。
|
||||
let result = eval(&mut vm, "function f(f) { return f; } f(1)").unwrap();
|
||||
assert_eq!(result.as_int(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_name_capture_side() {
|
||||
let mut vm = Vm::new();
|
||||
// 嵌套函数捕获外层名绑定(upvalue),内层读回外层函数对象。
|
||||
let result = eval(&mut vm, "function f() { return function() { return f; }; } f()()").unwrap();
|
||||
assert!(is_function_value(result), "expected the outer function, got: {:?}", result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_name_arguments_special_case() {
|
||||
let mut vm = Vm::new();
|
||||
// 名等于 arguments 且 arguments 对象已建:抑制名绑定,arguments 解析到 arguments 对象。
|
||||
let result = eval(&mut vm, "function arguments() { return arguments; } arguments()").unwrap();
|
||||
assert!(result.is_object(), "expected the arguments object, got: {:?}", result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_name_recursive_call() {
|
||||
let mut vm = Vm::new();
|
||||
// 递归调用依赖名绑定读回函数对象再调用,覆盖寄存器写回回归面。
|
||||
let result = eval(&mut vm, "function fact(n) { return n <= 1 ? 1 : n * fact(n - 1); } fact(5)").unwrap();
|
||||
assert_num(result, 120.0);
|
||||
}
|
||||
|
||||
@@ -390,8 +390,9 @@ fn cross_module_aliased_imports_read_live_value() {
|
||||
assert_eq!(result, "1|1|2|2", "一源两别名未同步读到重赋后的活值");
|
||||
}
|
||||
|
||||
/// 默认导出具名函数体的自引用重赋:函数体内 `fn = 2` 写模块级绑定,
|
||||
/// 导入方再次读 default 得新值(含捕获分析下探 export 声明与共享 cell)。
|
||||
/// 默认导出具名函数体的自引用重赋:函数名 `fn` 在函数作用域登记为不可写
|
||||
/// 绑定(15.2.10.1 步 m),遮蔽模块级同名绑定;体内容器 `fn = 2` 落在函数
|
||||
/// 作用域名绑定,模块级绑定不被改写,导入方读 default 仍得函数。
|
||||
#[test]
|
||||
fn cross_module_default_export_reads_live_value() {
|
||||
let cwd = std::env::current_dir().expect("cwd");
|
||||
@@ -402,11 +403,11 @@ fn cross_module_default_export_reads_live_value() {
|
||||
dir.join("main.mjs"),
|
||||
"import val from './dep.mjs';\n \
|
||||
const ret = val();\n \
|
||||
globalThis.__ns = [ret, val].join('|');",
|
||||
globalThis.__ns = [ret, typeof val].join('|');",
|
||||
)
|
||||
.expect("write main");
|
||||
let _cleanup = Cleanup(dir.clone());
|
||||
|
||||
let result = run_namespace_module(&dir);
|
||||
assert_eq!(result, "1|2", "default 导出的具名函数自引用重赋未活读");
|
||||
assert_eq!(result, "1|function", "函数名不可写绑定遮蔽模块级绑定,自引用重赋静默失败");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user