From 36eeea1c7277a0c07a53678d197400ef6373b0e6 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:51:35 +0100 Subject: [PATCH] Fix evaluation order in destructive property assignments (#3895) --- .../declaration/declaration_pattern.rs | 66 +++++++++++++------ 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/core/engine/src/bytecompiler/declaration/declaration_pattern.rs b/core/engine/src/bytecompiler/declaration/declaration_pattern.rs index e7b7928f59..efde60a13d 100644 --- a/core/engine/src/bytecompiler/declaration/declaration_pattern.rs +++ b/core/engine/src/bytecompiler/declaration/declaration_pattern.rs @@ -117,31 +117,57 @@ impl ByteCompiler<'_> { } => { self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup); - match name { - PropertyName::Literal(name) => { - self.emit_get_property_by_name(*name); - } - PropertyName::Computed(node) => { - self.compile_expr(node, true); - if rest_exits { - self.emit_opcode(Opcode::GetPropertyByValuePush); - } else { - self.emit_opcode(Opcode::GetPropertyByValue); - } - } - } - - if let Some(init) = default_init { - let skip = - self.emit_opcode_with_operand(Opcode::JumpIfNotUndefined); - self.compile_expr(init, true); - self.patch_jump(skip); + if let PropertyName::Computed(node) = &name { + self.compile_expr(node, true); + self.emit_opcode(Opcode::Swap); } self.access_set( Access::Property { access }, false, - ByteCompiler::access_set_top_of_stack_expr_fn, + |compiler: &mut ByteCompiler<'_>, level: u8| { + match level { + 0 => {} + 1 => compiler.emit_opcode(Opcode::Swap), + _ => { + compiler.emit( + Opcode::RotateLeft, + &[Operand::U8(level + 1)], + ); + } + } + compiler.emit_opcode(Opcode::Dup); + + match name { + PropertyName::Literal(name) => { + compiler.emit_get_property_by_name(*name); + } + PropertyName::Computed(_) => { + compiler.emit( + Opcode::RotateLeft, + &[Operand::U8(level + 3)], + ); + if rest_exits { + compiler + .emit_opcode(Opcode::GetPropertyByValuePush); + compiler.emit_opcode(Opcode::Swap); + compiler.emit( + Opcode::RotateRight, + &[Operand::U8(level + 2)], + ); + } else { + compiler.emit_opcode(Opcode::GetPropertyByValue); + } + } + } + + if let Some(init) = default_init { + let skip = compiler + .emit_opcode_with_operand(Opcode::JumpIfNotUndefined); + compiler.compile_expr(init, true); + compiler.patch_jump(skip); + } + }, ); if rest_exits && name.computed().is_some() {