mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
feat: 对象方法 super 门加计算型 super 成员加 VM 步序对齐
This commit is contained in:
@@ -53,45 +53,18 @@ impl Emitter {
|
||||
(callee_reg, obj_reg)
|
||||
}
|
||||
Expression::StaticMemberExpression(member) => {
|
||||
let is_super_member = matches!(&member.object, Expression::Super(_));
|
||||
let obj_reg = if is_super_member {
|
||||
let this_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(this_reg), Operand::This, Operand::None));
|
||||
this_reg
|
||||
if matches!(&member.object, Expression::Super(_)) {
|
||||
let this_reg = self.emit_super_this(ctx)?;
|
||||
let prop_name = member.property.name.as_str();
|
||||
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
|
||||
let key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
let callee_reg = self.emit_super_get(this_reg, key_reg, ctx);
|
||||
(callee_reg, this_reg)
|
||||
} else {
|
||||
self.emit_expression(&member.object, ctx)?
|
||||
};
|
||||
let prop_name = member.property.name.as_str();
|
||||
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
|
||||
let key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
if is_super_member {
|
||||
if !ctx.in_instance_method && !ctx.in_static_method && !ctx.in_derived_constructor {
|
||||
return Err("super property only supported in class methods".into());
|
||||
}
|
||||
let op = if ctx.in_static_method {
|
||||
OpCode::SUPER_STATIC_GET_PROP
|
||||
} else {
|
||||
OpCode::SUPER_GET_PROP
|
||||
};
|
||||
ctx.inst(Inst::new(op, Operand::Reg(callee_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
|
||||
} else {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_VAR,
|
||||
Operand::Reg(callee_reg),
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::None,
|
||||
));
|
||||
ctx.inst(Inst::ic_get(Operand::Reg(callee_reg), Operand::Reg(key_reg)));
|
||||
}
|
||||
(callee_reg, obj_reg)
|
||||
}
|
||||
Expression::ComputedMemberExpression(member) => {
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
// 常量字符串键折叠为 IC 静态路径:callee 寄存器独立于对象,this 保留对象。
|
||||
if let Some(key) = crate::expr::member::computed_const_key(&member.expression) {
|
||||
let idx = ctx.add_constant(Constant::String(key));
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
let prop_name = member.property.name.as_str();
|
||||
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
|
||||
let key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
@@ -103,16 +76,41 @@ impl Emitter {
|
||||
));
|
||||
ctx.inst(Inst::ic_get(Operand::Reg(callee_reg), Operand::Reg(key_reg)));
|
||||
(callee_reg, obj_reg)
|
||||
} else {
|
||||
}
|
||||
}
|
||||
Expression::ComputedMemberExpression(member) => {
|
||||
if matches!(&member.object, Expression::Super(_)) {
|
||||
let this_reg = self.emit_super_this(ctx)?;
|
||||
let key_reg = self.emit_expression(&member.expression, ctx)?;
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::GET_PROP_DYNAMIC,
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::Reg(key_reg),
|
||||
Operand::Reg(callee_reg),
|
||||
));
|
||||
(callee_reg, obj_reg)
|
||||
let callee_reg = self.emit_super_get(this_reg, key_reg, ctx);
|
||||
(callee_reg, this_reg)
|
||||
} else {
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
// 常量字符串键折叠为 IC 静态路径:callee 寄存器独立于对象,this 保留对象。
|
||||
if let Some(key) = crate::expr::member::computed_const_key(&member.expression) {
|
||||
let idx = ctx.add_constant(Constant::String(key));
|
||||
let key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_VAR,
|
||||
Operand::Reg(callee_reg),
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::None,
|
||||
));
|
||||
ctx.inst(Inst::ic_get(Operand::Reg(callee_reg), Operand::Reg(key_reg)));
|
||||
(callee_reg, obj_reg)
|
||||
} else {
|
||||
let key_reg = self.emit_expression(&member.expression, ctx)?;
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::GET_PROP_DYNAMIC,
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::Reg(key_reg),
|
||||
Operand::Reg(callee_reg),
|
||||
));
|
||||
(callee_reg, obj_reg)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
||||
@@ -61,6 +61,11 @@ impl Emitter {
|
||||
)?
|
||||
};
|
||||
sub_module.is_arrow = true;
|
||||
// 箭头函数词法继承 super 上下文:父带任一 super 标志时,本箭头须挂
|
||||
// home object(运行期从外层函数继承,见 CREATE_CLOSURE 分发)。
|
||||
if ctx.in_instance_method || ctx.in_static_method || ctx.in_derived_constructor {
|
||||
sub_module.needs_home_object = true;
|
||||
}
|
||||
|
||||
ctx.nested.push(sub_module);
|
||||
// 子模块下标 1 起始:0 保留为无子模块哨兵
|
||||
|
||||
@@ -10,27 +10,43 @@ use oxide_ir::operand::Operand;
|
||||
use oxide_parser::Expression;
|
||||
|
||||
impl Emitter {
|
||||
/// super 属性读门判定与 this 装载(GetThisBinding):this 未初始化时
|
||||
/// 运行期抛 ReferenceError(VM 侧)。返回 this 寄存器。
|
||||
///
|
||||
/// 键装载须在本方法之后(规范序:GetThisBinding 先于键表达式求值)。
|
||||
pub(crate) fn emit_super_this(&self, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
if !ctx.in_instance_method && !ctx.in_static_method && !ctx.in_derived_constructor {
|
||||
return Err("super property only supported in class methods".into());
|
||||
}
|
||||
let this_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(this_reg), Operand::This, Operand::None));
|
||||
Ok(this_reg)
|
||||
}
|
||||
|
||||
/// super 属性读:给定 this 寄存器与键寄存器,发 `SUPER_GET_PROP` /
|
||||
/// `SUPER_STATIC_GET_PROP`(GetSuperBase + RequireObjectCoercible +
|
||||
/// ToPropertyKey + Get 在运行期完成)。返回结果寄存器。
|
||||
pub(crate) fn emit_super_get(&self, this_reg: u32, key_reg: u32, ctx: &mut CompileCtx) -> u32 {
|
||||
let result_reg = ctx.alloc_reg();
|
||||
let op = if ctx.in_static_method {
|
||||
OpCode::SUPER_STATIC_GET_PROP
|
||||
} else {
|
||||
OpCode::SUPER_GET_PROP
|
||||
};
|
||||
ctx.inst(Inst::new(op, Operand::Reg(result_reg), Operand::Reg(this_reg), Operand::Reg(key_reg)));
|
||||
result_reg
|
||||
}
|
||||
|
||||
fn emit_static_member_expression(
|
||||
&self, member: &oxide_parser::StaticMemberExpression, ctx: &mut CompileCtx,
|
||||
) -> Result<u32, String> {
|
||||
if matches!(&member.object, Expression::Super(_)) {
|
||||
if !ctx.in_instance_method && !ctx.in_static_method && !ctx.in_derived_constructor {
|
||||
return Err("super property only supported in class methods".into());
|
||||
}
|
||||
let this_reg = self.emit_super_this(ctx)?;
|
||||
let prop_name = member.property.name.as_str();
|
||||
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
|
||||
let key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
let this_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(this_reg), Operand::This, Operand::None));
|
||||
let result_reg = ctx.alloc_reg();
|
||||
let op = if ctx.in_static_method {
|
||||
OpCode::SUPER_STATIC_GET_PROP
|
||||
} else {
|
||||
OpCode::SUPER_GET_PROP
|
||||
};
|
||||
ctx.inst(Inst::new(op, Operand::Reg(result_reg), Operand::Reg(this_reg), Operand::Reg(key_reg)));
|
||||
return Ok(result_reg);
|
||||
return Ok(self.emit_super_get(this_reg, key_reg, ctx));
|
||||
}
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
let prop_name = member.property.name.as_str();
|
||||
@@ -44,6 +60,13 @@ impl Emitter {
|
||||
fn emit_computed_member_expression(
|
||||
&self, member: &oxide_parser::ComputedMemberExpression, ctx: &mut CompileCtx,
|
||||
) -> Result<u32, String> {
|
||||
// super['x']:this 先装载(GetThisBinding),键表达式后求值(规范序),
|
||||
// 后走 super 读。
|
||||
if matches!(&member.object, Expression::Super(_)) {
|
||||
let this_reg = self.emit_super_this(ctx)?;
|
||||
let key_reg = self.emit_expression(&member.expression, ctx)?;
|
||||
return Ok(self.emit_super_get(this_reg, key_reg, ctx));
|
||||
}
|
||||
// 常量字符串键折叠为 IC 静态路径:免去运行期键 interning 与慢路径 ordinary_get。
|
||||
if let Some(key) = computed_const_key(&member.expression) {
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
|
||||
@@ -8,6 +8,35 @@ use oxide_ir::operand::Operand;
|
||||
use oxide_parser::{ObjectPropertyKind, PropertyKind};
|
||||
|
||||
impl Emitter {
|
||||
/// 对象方法值发射:体编译期置 `in_instance_method`(清静态/派生构造器标志,
|
||||
/// 与类方法同形),闭包物化后给方法函数挂 home object(home = 对象字面量本身)
|
||||
/// 并置 `needs_home_object`。
|
||||
///
|
||||
/// 仅箭头/函数表达式值挂 home(类表达式排除:类表达式方法由类自身 emit 挂
|
||||
/// home object,外层对象不作 home);非函数值只作普通值发射。
|
||||
fn emit_object_method_value(
|
||||
&self, value: &oxide_parser::Expression, obj_reg: u32, ctx: &mut CompileCtx,
|
||||
) -> Result<u32, String> {
|
||||
let saved_instance = ctx.in_instance_method;
|
||||
let saved_static = ctx.in_static_method;
|
||||
let saved_derived = ctx.in_derived_constructor;
|
||||
ctx.in_instance_method = true;
|
||||
ctx.in_static_method = false;
|
||||
ctx.in_derived_constructor = false;
|
||||
let val_reg = self.emit_expression(value, ctx);
|
||||
ctx.in_instance_method = saved_instance;
|
||||
ctx.in_static_method = saved_static;
|
||||
ctx.in_derived_constructor = saved_derived;
|
||||
let val_reg = val_reg?;
|
||||
if is_object_method_fn(value) {
|
||||
if let Some(sub_mod) = ctx.nested.last_mut() {
|
||||
sub_mod.needs_home_object = true;
|
||||
}
|
||||
ctx.inst(Inst::new(OpCode::SET_HOME_OBJECT, Operand::Reg(val_reg), Operand::Reg(obj_reg), Operand::None));
|
||||
}
|
||||
Ok(val_reg)
|
||||
}
|
||||
|
||||
pub(crate) fn emit_object_expression(
|
||||
&self, obj: &oxide_parser::ObjectExpression, ctx: &mut CompileCtx,
|
||||
) -> Result<u32, String> {
|
||||
@@ -37,7 +66,7 @@ impl Emitter {
|
||||
let ObjectPropertyKind::ObjectProperty(p) = prop else {
|
||||
unreachable!("批量前缀必为 ObjectProperty");
|
||||
};
|
||||
let val_reg = self.emit_expression(&p.value, ctx)?;
|
||||
let val_reg = self.emit_object_method_value(&p.value, obj_reg, ctx)?;
|
||||
if crate::is_anonymous_function_definition(&p.value) {
|
||||
if let Some(sub_mod) = ctx.nested.last_mut() {
|
||||
sub_mod.function_name = Some(self.class_property_name(&p.key).expect("批量前缀键为静态名"));
|
||||
@@ -112,7 +141,7 @@ impl Emitter {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let accessor_reg = self.emit_expression(&p.value, ctx)?;
|
||||
let accessor_reg = self.emit_object_method_value(&p.value, obj_reg, ctx)?;
|
||||
if !computed {
|
||||
if let Some(sub_mod) = ctx.nested.last_mut() {
|
||||
// 访问器函数名带 "get "/"set " 前缀(SetFunctionName 语义)。
|
||||
@@ -162,7 +191,7 @@ impl Emitter {
|
||||
ctx.inst(Inst::load_const(Operand::Reg(reg), idx));
|
||||
reg
|
||||
};
|
||||
let val_reg = self.emit_expression(&p.value, ctx)?;
|
||||
let val_reg = self.emit_object_method_value(&p.value, obj_reg, ctx)?;
|
||||
if crate::is_anonymous_function_definition(&p.value) {
|
||||
if let Some(sub_mod) = ctx.nested.last_mut() {
|
||||
sub_mod.function_name = Some(prop_name.to_string());
|
||||
@@ -180,3 +209,13 @@ impl Emitter {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 对象方法函数值(剥括号):箭头/函数表达式。类表达式排除——其方法由类自身
|
||||
/// emit 挂 home object,外层对象不作 home。
|
||||
fn is_object_method_fn(value: &oxide_parser::Expression) -> bool {
|
||||
match value {
|
||||
oxide_parser::Expression::ArrowFunctionExpression(_) | oxide_parser::Expression::FunctionExpression(_) => true,
|
||||
oxide_parser::Expression::ParenthesizedExpression(p) => is_object_method_fn(&p.expression),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,22 +88,12 @@ impl Emitter {
|
||||
let pair = match tag {
|
||||
Expression::StaticMemberExpression(member) => {
|
||||
if matches!(&member.object, Expression::Super(_)) {
|
||||
if !ctx.in_instance_method && !ctx.in_static_method && !ctx.in_derived_constructor {
|
||||
return Err("super property only supported in class methods".into());
|
||||
}
|
||||
let this_reg = self.emit_super_this(ctx)?;
|
||||
let prop_name = member.property.name.as_str();
|
||||
let key_reg = ctx.alloc_reg();
|
||||
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
let this_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(this_reg), Operand::This, Operand::None));
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
let op = if ctx.in_static_method {
|
||||
OpCode::SUPER_STATIC_GET_PROP
|
||||
} else {
|
||||
OpCode::SUPER_GET_PROP
|
||||
};
|
||||
ctx.inst(Inst::new(op, Operand::Reg(callee_reg), Operand::Reg(this_reg), Operand::Reg(key_reg)));
|
||||
let callee_reg = self.emit_super_get(this_reg, key_reg, ctx);
|
||||
(callee_reg, this_reg)
|
||||
} else {
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
@@ -123,30 +113,37 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
Expression::ComputedMemberExpression(member) => {
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
if let Some(key) = crate::expr::member::computed_const_key(&member.expression) {
|
||||
let key_reg = ctx.alloc_reg();
|
||||
let idx = ctx.add_constant(Constant::String(key));
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_VAR,
|
||||
Operand::Reg(callee_reg),
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::None,
|
||||
));
|
||||
ctx.inst(Inst::ic_get(Operand::Reg(callee_reg), Operand::Reg(key_reg)));
|
||||
(callee_reg, obj_reg)
|
||||
} else {
|
||||
if matches!(&member.object, Expression::Super(_)) {
|
||||
let this_reg = self.emit_super_this(ctx)?;
|
||||
let key_reg = self.emit_expression(&member.expression, ctx)?;
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::GET_PROP_DYNAMIC,
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::Reg(key_reg),
|
||||
Operand::Reg(callee_reg),
|
||||
));
|
||||
(callee_reg, obj_reg)
|
||||
let callee_reg = self.emit_super_get(this_reg, key_reg, ctx);
|
||||
(callee_reg, this_reg)
|
||||
} else {
|
||||
let obj_reg = self.emit_expression(&member.object, ctx)?;
|
||||
if let Some(key) = crate::expr::member::computed_const_key(&member.expression) {
|
||||
let key_reg = ctx.alloc_reg();
|
||||
let idx = ctx.add_constant(Constant::String(key));
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_VAR,
|
||||
Operand::Reg(callee_reg),
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::None,
|
||||
));
|
||||
ctx.inst(Inst::ic_get(Operand::Reg(callee_reg), Operand::Reg(key_reg)));
|
||||
(callee_reg, obj_reg)
|
||||
} else {
|
||||
let key_reg = self.emit_expression(&member.expression, ctx)?;
|
||||
let callee_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::GET_PROP_DYNAMIC,
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::Reg(key_reg),
|
||||
Operand::Reg(callee_reg),
|
||||
));
|
||||
(callee_reg, obj_reg)
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::PrivateFieldExpression(member) => {
|
||||
|
||||
Reference in New Issue
Block a user