Skip to content

Commit

Permalink
Fix update expressions getting values multiple times
Browse files Browse the repository at this point in the history
  • Loading branch information
raskad committed Mar 24, 2023
1 parent e465743 commit f9e0ab1
Showing 1 changed file with 126 additions and 31 deletions.
157 changes: 126 additions & 31 deletions boa_engine/src/bytecompiler/expression/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,136 @@ use crate::{
bytecompiler::{Access, ByteCompiler},
vm::Opcode,
};
use boa_ast::expression::operator::{update::UpdateOp, Update};
use boa_ast::expression::{
access::{PropertyAccess, PropertyAccessField},
operator::{update::UpdateOp, Update},
};

impl ByteCompiler<'_, '_> {
pub(crate) fn compile_update(&mut self, update: &Update, use_expr: bool) {
let access = Access::from_update_target(update.target());

match update.op() {
UpdateOp::IncrementPre => {
self.access_set(access, true, |compiler, _| {
compiler.access_get(access, true);
compiler.emit_opcode(Opcode::Inc);
});
}
UpdateOp::DecrementPre => {
self.access_set(access, true, |compiler, _| {
compiler.access_get(access, true);
compiler.emit_opcode(Opcode::Dec);
});
}
UpdateOp::IncrementPost => {
self.access_set(access, false, |compiler, level| {
compiler.access_get(access, true);
compiler.emit_opcode(Opcode::IncPost);
compiler.emit_opcode(Opcode::RotateRight);
compiler.emit_u8(level + 2);
});
}
UpdateOp::DecrementPost => {
self.access_set(access, false, |compiler, level| {
compiler.access_get(access, true);
compiler.emit_opcode(Opcode::DecPost);
compiler.emit_opcode(Opcode::RotateRight);
compiler.emit_u8(level + 2);
});
let opcode = match update.op() {
UpdateOp::IncrementPre => Opcode::Inc,
UpdateOp::DecrementPre => Opcode::Dec,
UpdateOp::IncrementPost => Opcode::IncPost,
UpdateOp::DecrementPost => Opcode::DecPost,
};
let post = matches!(
update.op(),
UpdateOp::IncrementPost | UpdateOp::DecrementPost
);

match Access::from_update_target(update.target()) {
Access::Variable { name } => {
let binding = self.context.get_binding_value(name);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::GetName, &[index]);

self.emit_opcode(opcode);
if post {
self.emit_opcode(Opcode::Swap);
} else {
self.emit_opcode(Opcode::Dup);
}

let binding = self.context.set_mutable_binding(name);
let index = self.get_or_insert_binding(binding);
self.emit(Opcode::SetName, &[index]);
}
Access::Property { access } => match access {
PropertyAccess::Simple(access) => match access.field() {
PropertyAccessField::Const(name) => {
let index = self.get_or_insert_name((*name).into());
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup);

self.emit(Opcode::GetPropertyByName, &[index]);
self.emit_opcode(opcode);
if post {
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(4);
}

self.emit(Opcode::SetPropertyByName, &[index]);
if post {
self.emit_opcode(Opcode::Pop);
}
}
PropertyAccessField::Expr(expr) => {
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true);

self.emit_opcode(Opcode::GetPropertyByValuePush);
self.emit_opcode(opcode);
if post {
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(4);
}

self.emit_opcode(Opcode::SetPropertyByValue);
if post {
self.emit_opcode(Opcode::Pop);
}
}
},
PropertyAccess::Private(access) => {
let index = self.get_or_insert_private_name(access.field());
self.compile_expr(access.target(), true);
self.emit_opcode(Opcode::Dup);

self.emit(Opcode::GetPrivateField, &[index]);
self.emit_opcode(opcode);
if post {
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(3);
}

self.emit(Opcode::SetPrivateField, &[index]);
if post {
self.emit_opcode(Opcode::Pop);
}
}
PropertyAccess::Super(access) => match access.field() {
PropertyAccessField::Const(name) => {
let index = self.get_or_insert_name((*name).into());
self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::This);
self.emit_opcode(Opcode::Swap);

self.emit(Opcode::GetPropertyByName, &[index]);
self.emit_opcode(opcode);
if post {
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(3);
}

self.emit(Opcode::SetPropertyByName, &[index]);
if post {
self.emit_opcode(Opcode::Pop);
}
}
PropertyAccessField::Expr(expr) => {
self.emit_opcode(Opcode::Super);
self.emit_opcode(Opcode::Dup);
self.compile_expr(expr, true);

self.emit_opcode(Opcode::GetPropertyByValuePush);
self.emit_opcode(opcode);
if post {
self.emit_opcode(Opcode::RotateRight);
self.emit_u8(2);
}

self.emit_opcode(Opcode::SetPropertyByValue);
if post {
self.emit_opcode(Opcode::Pop);
}
}
},
},
Access::This => unreachable!(),
}

if !use_expr {
Expand Down

0 comments on commit f9e0ab1

Please sign in to comment.