feat: super 属性写新建 SUPER_PUT_PROP 指令

This commit is contained in:
2026-10-10 01:37:39 +00:00
parent c38e91a65a
commit 958cc1f7a2
9 changed files with 390 additions and 21 deletions
+85 -1
View File
@@ -6,7 +6,7 @@ use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::AssignmentOperator;
use oxide_parser::{AssignmentOperator, Expression};
impl Emitter {
/// 标识符复合赋值的静态路径:upvalue / 被捕获 cell 走显式读取-运算-写回
@@ -168,10 +168,63 @@ impl Emitter {
}
}
/// 复合赋值运算符映射到二元运算指令(super 属性写与计算成员动态路径共用)。
fn super_compound_op(&self, op: AssignmentOperator) -> Result<OpCode, String> {
Ok(match op {
AssignmentOperator::Addition => OpCode::ADD,
AssignmentOperator::Subtraction => OpCode::SUB,
AssignmentOperator::Multiplication => OpCode::MUL,
AssignmentOperator::Division => OpCode::DIV,
AssignmentOperator::Remainder => OpCode::MOD,
AssignmentOperator::Exponential => OpCode::COMPOUND_EXP,
AssignmentOperator::BitwiseAnd => OpCode::BIT_AND,
AssignmentOperator::BitwiseOR => OpCode::BIT_OR,
AssignmentOperator::BitwiseXOR => OpCode::BIT_XOR,
AssignmentOperator::ShiftLeft => OpCode::SHL,
AssignmentOperator::ShiftRight => OpCode::SHR,
AssignmentOperator::ShiftRightZeroFill => OpCode::USHR,
_ => return Err(format!("compound assignment operator {:?} not supported", op)),
})
}
pub(crate) fn emit_assignment_expression(
&self, assign: &oxide_parser::AssignmentExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
if let oxide_parser::AssignmentTarget::StaticMemberExpression(member) = &assign.left {
// super 属性写:this 先装载(GetThisBinding),键常量装载,后发 SUPER_PUT_PROP
// (运行期 GetSuperBase 先于 ToPropertyKey,步序与 super 读对齐)。
if matches!(&member.object, Expression::Super(_)) {
if assign.operator.to_logical_operator().is_some() {
return Err("logical assignment to super property not supported".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));
if assign.operator != AssignmentOperator::Assign {
// 复合赋值:先读旧值(SUPER_GET_PROP),求值 RHS,运算,后写回。
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::SUPER_GET_PROP,
Operand::Reg(val_reg),
Operand::Reg(this_reg),
Operand::Reg(key_reg),
));
let rhs = self.emit_expression(&assign.right, ctx)?;
let op = self.super_compound_op(assign.operator)?;
if assign.operator == AssignmentOperator::Exponential {
ctx.inst(Inst::new(op, Operand::Reg(val_reg), Operand::Reg(rhs), Operand::None));
} else {
ctx.inst(Inst::new(op, Operand::Reg(val_reg), Operand::Reg(val_reg), Operand::Reg(rhs)));
}
self.emit_super_put(this_reg, key_reg, val_reg, ctx);
return Ok(val_reg);
}
let val_reg = self.emit_expression(&assign.right, ctx)?;
self.emit_super_put(this_reg, key_reg, val_reg, ctx);
return Ok(val_reg);
}
if let Some(logical_op) = assign.operator.to_logical_operator() {
let store_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
@@ -232,6 +285,37 @@ impl Emitter {
Ok(val_reg)
}
} else if let oxide_parser::AssignmentTarget::ComputedMemberExpression(member) = &assign.left {
// super 计算成员写:this 先装载(GetThisBinding),键表达式后求值,
// 后发 SUPER_PUT_PROP(运行期 GetSuperBase 先于 ToPropertyKey)。
if matches!(&member.object, Expression::Super(_)) {
if assign.operator.to_logical_operator().is_some() {
return Err("logical assignment to super property not supported".into());
}
let this_reg = self.emit_super_this(ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
if assign.operator != AssignmentOperator::Assign {
// 复合赋值:先读旧值(SUPER_GET_PROP),求值 RHS,运算,后写回。
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::SUPER_GET_PROP,
Operand::Reg(val_reg),
Operand::Reg(this_reg),
Operand::Reg(key_reg),
));
let rhs = self.emit_expression(&assign.right, ctx)?;
let op = self.super_compound_op(assign.operator)?;
if assign.operator == AssignmentOperator::Exponential {
ctx.inst(Inst::new(op, Operand::Reg(val_reg), Operand::Reg(rhs), Operand::None));
} else {
ctx.inst(Inst::new(op, Operand::Reg(val_reg), Operand::Reg(val_reg), Operand::Reg(rhs)));
}
self.emit_super_put(this_reg, key_reg, val_reg, ctx);
return Ok(val_reg);
}
let val_reg = self.emit_expression(&assign.right, ctx)?;
self.emit_super_put(this_reg, key_reg, val_reg, ctx);
return Ok(val_reg);
}
// 常量字符串键折叠为 IC 静态路径,与 StaticMemberExpression 分支同构。
if let Some(key) = crate::expr::member::computed_const_key(&member.expression) {
if let Some(logical_op) = assign.operator.to_logical_operator() {
+12
View File
@@ -37,6 +37,18 @@ impl Emitter {
result_reg
}
/// super 属性写:给定 this 寄存器、键寄存器与值寄存器,发 `SUPER_PUT_PROP`
/// (GetSuperBase + RequireObjectCoercible + ToPropertyKey + Set 在运行期完成,
/// 步序与 super 读对齐)。
pub(crate) fn emit_super_put(&self, this_reg: u32, key_reg: u32, val_reg: u32, ctx: &mut CompileCtx) {
ctx.inst(Inst::new(
OpCode::SUPER_PUT_PROP,
Operand::Reg(val_reg),
Operand::Reg(this_reg),
Operand::Reg(key_reg),
));
}
fn emit_static_member_expression(
&self, member: &oxide_parser::StaticMemberExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
@@ -579,6 +579,41 @@ impl Emitter {
self.emit_identifier_update_static(name, update, ctx)
}
SimpleAssignmentTarget::StaticMemberExpression(member) => {
// super 属性自增/自减:this 先装载(GetThisBinding),键常量装载,
// 读旧值(SUPER_GET_PROP),运算,写回(SUPER_PUT_PROP)。
if matches!(&member.object, Expression::Super(_)) {
let this_reg = self.emit_super_this(ctx)?;
let prop_name = member.property.name.as_str();
let key_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), key_idx));
let old_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::SUPER_GET_PROP,
Operand::Reg(old_reg),
Operand::Reg(this_reg),
Operand::Reg(key_reg),
));
let one_idx = ctx.add_constant(Constant::Int(1));
let one_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(one_reg), one_idx));
let new_reg = ctx.alloc_reg();
let op = if update.operator == UpdateOperator::Increment {
OpCode::ADD
} else {
OpCode::SUB
};
ctx.inst(Inst::new(op, Operand::Reg(new_reg), Operand::Reg(old_reg), Operand::Reg(one_reg)));
self.emit_super_put(this_reg, key_reg, new_reg, ctx);
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(if update.prefix { new_reg } else { old_reg }),
Operand::None,
));
return Ok(result_reg);
}
let obj_reg = self.emit_expression(&member.object, ctx)?;
let prop_name = member.property.name.as_str();
let key_idx = ctx.add_constant(Constant::String(prop_name.to_string()));
@@ -601,6 +636,38 @@ impl Emitter {
Ok(val_reg)
}
SimpleAssignmentTarget::ComputedMemberExpression(member) => {
// super 计算成员自增/自减:this 先装载(GetThisBinding),键表达式
// 后求值,读旧值(SUPER_GET_PROP),运算,写回(SUPER_PUT_PROP)。
if matches!(&member.object, Expression::Super(_)) {
let this_reg = self.emit_super_this(ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
let old_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::SUPER_GET_PROP,
Operand::Reg(old_reg),
Operand::Reg(this_reg),
Operand::Reg(key_reg),
));
let one_idx = ctx.add_constant(Constant::Int(1));
let one_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(one_reg), one_idx));
let new_reg = ctx.alloc_reg();
let op = if update.operator == UpdateOperator::Increment {
OpCode::ADD
} else {
OpCode::SUB
};
ctx.inst(Inst::new(op, Operand::Reg(new_reg), Operand::Reg(old_reg), Operand::Reg(one_reg)));
self.emit_super_put(this_reg, key_reg, new_reg, ctx);
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(if update.prefix { new_reg } else { old_reg }),
Operand::None,
));
return Ok(result_reg);
}
let obj_reg = self.emit_expression(&member.object, ctx)?;
// 常量字符串键折叠为 IC 静态路径:MEMBER_INC/DEC 携带 IC 扩展字。
if let Some(key) = crate::expr::member::computed_const_key(&member.expression) {