Skip to content

Commit

Permalink
Simplify/Refactor exception handling and last statement value
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Jun 22, 2023
1 parent 7026c71 commit fed05d7
Show file tree
Hide file tree
Showing 30 changed files with 314 additions and 633 deletions.
7 changes: 7 additions & 0 deletions boa_engine/src/bytecompiler/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ impl ByteCompiler<'_, '_> {
compiler.pop_compile_environment();
}

compiler.emit_opcode(Opcode::SetReturnValue);
compiler.emit_opcode(Opcode::Return);

let code = Gc::new(compiler.finish());
Expand Down Expand Up @@ -269,6 +270,8 @@ impl ByteCompiler<'_, '_> {
}
field_compiler.pop_compile_environment();
field_compiler.pop_compile_environment();

field_compiler.emit_opcode(Opcode::SetReturnValue);
field_compiler.emit_opcode(Opcode::Return);

field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER;
Expand Down Expand Up @@ -301,6 +304,8 @@ impl ByteCompiler<'_, '_> {
}
field_compiler.pop_compile_environment();
field_compiler.pop_compile_environment();

field_compiler.emit_opcode(Opcode::SetReturnValue);
field_compiler.emit_opcode(Opcode::Return);

field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER;
Expand Down Expand Up @@ -343,6 +348,8 @@ impl ByteCompiler<'_, '_> {
}
field_compiler.pop_compile_environment();
field_compiler.pop_compile_environment();

field_compiler.emit_opcode(Opcode::SetReturnValue);
field_compiler.emit_opcode(Opcode::Return);

field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER;
Expand Down
4 changes: 2 additions & 2 deletions boa_engine/src/bytecompiler/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ impl ByteCompiler<'_, '_> {
Expression::Conditional(op) => self.compile_conditional(op, use_expr),
Expression::ArrayLiteral(array) => {
self.emit_opcode(Opcode::PushNewArray);
self.emit_opcode(Opcode::PopOnReturnAdd);

for element in array.as_ref() {
if let Some(element) = element {
Expand All @@ -114,7 +113,6 @@ impl ByteCompiler<'_, '_> {
}
}

self.emit_opcode(Opcode::PopOnReturnSub);
if !use_expr {
self.emit(Opcode::Pop, &[]);
}
Expand Down Expand Up @@ -194,6 +192,8 @@ impl ByteCompiler<'_, '_> {
self.emit_opcode(Opcode::Await);
}
self.close_active_iterators();

self.emit_opcode(Opcode::SetReturnValue);
self.emit_opcode(Opcode::GeneratorResumeReturn);

self.patch_jump(throw_method_undefined);
Expand Down
1 change: 0 additions & 1 deletion boa_engine/src/bytecompiler/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ impl FunctionCompiler {
.filter(|last| **last == Opcode::Return as u8)
.is_none()
{
compiler.emit_opcode(Opcode::PushUndefined);
compiler.emit_opcode(Opcode::Return);
}

Expand Down
116 changes: 71 additions & 45 deletions boa_engine/src/bytecompiler/jump_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,15 @@ bitflags! {
const SWITCH = 0b0000_0010;
const TRY_BLOCK = 0b0000_0100;
const LABELLED = 0b0000_1000;
const IN_CATCH = 0b0001_0000;
const IN_FINALLY = 0b0010_0000;
const HAS_FINALLY = 0b0100_0000;
const ITERATOR_LOOP = 0b1000_0000;
const FOR_AWAIT_OF_LOOP = 0b1_0000_0000;
const IN_FINALLY = 0b0001_0000;
const HAS_FINALLY = 0b0010_0000;
const ITERATOR_LOOP = 0b0100_0000;
const FOR_AWAIT_OF_LOOP = 0b1000_0000;

/// Is the statement compiled with use_expr set to true.
///
/// This bitflag is inherited if the previous [`JumpControlInfo`].
const USE_EXPR = 0b0001_0000_0000;
}
}

Expand Down Expand Up @@ -134,10 +138,6 @@ impl JumpControlInfo {
self.flags.contains(JumpControlInfoFlags::LABELLED)
}

pub(crate) const fn in_catch(&self) -> bool {
self.flags.contains(JumpControlInfoFlags::IN_CATCH)
}

pub(crate) const fn in_finally(&self) -> bool {
self.flags.contains(JumpControlInfoFlags::IN_FINALLY)
}
Expand All @@ -146,6 +146,10 @@ impl JumpControlInfo {
self.flags.contains(JumpControlInfoFlags::HAS_FINALLY)
}

pub(crate) const fn use_expr(&self) -> bool {
self.flags.contains(JumpControlInfoFlags::USE_EXPR)
}

pub(crate) const fn iterator_loop(&self) -> bool {
self.flags.contains(JumpControlInfoFlags::ITERATOR_LOOP)
}
Expand All @@ -168,11 +172,6 @@ impl JumpControlInfo {
self.start_address = start_address;
}

/// Sets the `in_catch` field of `JumpControlInfo`.
pub(crate) fn set_in_catch(&mut self, value: bool) {
self.flags.set(JumpControlInfoFlags::IN_CATCH, value);
}

/// Set the `in_finally` field of `JumpControlInfo`.
pub(crate) fn set_in_finally(&mut self, value: bool) {
self.flags.set(JumpControlInfoFlags::IN_FINALLY, value);
Expand All @@ -198,9 +197,9 @@ impl ByteCompiler<'_, '_> {
/// Pushes a generic `JumpControlInfo` onto `ByteCompiler`
///
/// Default `JumpControlInfoKind` is `JumpControlInfoKind::Loop`
pub(crate) fn push_empty_loop_jump_control(&mut self) {
self.jump_info
.push(JumpControlInfo::default().with_loop_flag(true));
pub(crate) fn push_empty_loop_jump_control(&mut self, use_expr: bool) {
let new_info = JumpControlInfo::default().with_loop_flag(true);
self.push_contol_info(new_info, use_expr);
}

pub(crate) fn current_jump_control_mut(&mut self) -> Option<&mut JumpControlInfo> {
Expand All @@ -212,37 +211,43 @@ impl ByteCompiler<'_, '_> {
info.set_start_address(start_address);
}

pub(crate) fn set_jump_control_in_finally(&mut self, value: bool) {
if !self.jump_info.is_empty() {
let info = self
.jump_info
.last_mut()
.expect("must have try control label");
assert!(info.is_try_block());
info.set_in_finally(value);
pub(crate) fn push_contol_info(&mut self, mut info: JumpControlInfo, use_expr: bool) {
info.flags.set(JumpControlInfoFlags::USE_EXPR, use_expr);

if let Some(last) = self.jump_info.last() {
// Inherits the `JumpControlInfoFlags::USE_EXPR` flag.
info.flags |= last.flags & JumpControlInfoFlags::USE_EXPR;
}

self.jump_info.push(info);
}

pub(crate) fn set_jump_control_in_catch(&mut self, value: bool) {
if !self.jump_info.is_empty() {
let info = self
.jump_info
.last_mut()
.expect("must have try control label");
assert!(info.is_try_block());
info.set_in_catch(value);
/// Does the jump control info have the `use_expr` flag set to true.
///
/// See [`JumpControlInfoFlags`].
pub(crate) fn jump_control_info_has_use_expr(&self) -> bool {
if let Some(last) = self.jump_info.last() {
return last.use_expr();
}

false
}

// ---- Labelled Statement JumpControlInfo methods ---- //

/// Pushes a `LabelledStatement`'s `JumpControlInfo` onto the `jump_info` stack.
pub(crate) fn push_labelled_control_info(&mut self, label: Sym, start_address: u32) {
pub(crate) fn push_labelled_control_info(
&mut self,
label: Sym,
start_address: u32,
use_expr: bool,
) {
let new_info = JumpControlInfo::default()
.with_labelled_block_flag(true)
.with_label(Some(label))
.with_start_address(start_address);
self.jump_info.push(new_info);

self.push_contol_info(new_info, use_expr);
}

/// Pops and handles the info for a label's `JumpControlInfo`
Expand All @@ -267,40 +272,50 @@ impl ByteCompiler<'_, '_> {
// ---- `IterationStatement`'s `JumpControlInfo` methods ---- //

/// Pushes an `WhileStatement`, `ForStatement` or `DoWhileStatement`'s `JumpControlInfo` on to the `jump_info` stack.
pub(crate) fn push_loop_control_info(&mut self, label: Option<Sym>, start_address: u32) {
pub(crate) fn push_loop_control_info(
&mut self,
label: Option<Sym>,
start_address: u32,
use_expr: bool,
) {
let new_info = JumpControlInfo::default()
.with_loop_flag(true)
.with_label(label)
.with_start_address(start_address);
self.jump_info.push(new_info);

self.push_contol_info(new_info, use_expr);
}

/// Pushes a `ForInOfStatement`'s `JumpControlInfo` on to the `jump_info` stack.
pub(crate) fn push_loop_control_info_for_of_in_loop(
&mut self,
label: Option<Sym>,
start_address: u32,
use_expr: bool,
) {
let new_info = JumpControlInfo::default()
.with_loop_flag(true)
.with_label(label)
.with_start_address(start_address)
.with_iterator_loop(true);
self.jump_info.push(new_info);

self.push_contol_info(new_info, use_expr);
}

pub(crate) fn push_loop_control_info_for_await_of_loop(
&mut self,
label: Option<Sym>,
start_address: u32,
use_expr: bool,
) {
let new_info = JumpControlInfo::default()
.with_loop_flag(true)
.with_label(label)
.with_start_address(start_address)
.with_iterator_loop(true)
.with_for_await_of_loop(true);
self.jump_info.push(new_info);

self.push_contol_info(new_info, use_expr);
}

/// Pops and handles the info for a loop control block's `JumpControlInfo`
Expand All @@ -327,12 +342,18 @@ impl ByteCompiler<'_, '_> {
// ---- `SwitchStatement` `JumpControlInfo` methods ---- //

/// Pushes a `SwitchStatement`'s `JumpControlInfo` on to the `jump_info` stack.
pub(crate) fn push_switch_control_info(&mut self, label: Option<Sym>, start_address: u32) {
pub(crate) fn push_switch_control_info(
&mut self,
label: Option<Sym>,
start_address: u32,
use_expr: bool,
) {
let new_info = JumpControlInfo::default()
.with_switch_flag(true)
.with_label(label)
.with_start_address(start_address);
self.jump_info.push(new_info);

self.push_contol_info(new_info, use_expr);
}

/// Pops and handles the info for a switch block's `JumpControlInfo`
Expand All @@ -354,13 +375,18 @@ impl ByteCompiler<'_, '_> {
// ---- `TryStatement`'s `JumpControlInfo` methods ---- //

/// Pushes a `TryStatement`'s `JumpControlInfo` onto the `jump_info` stack.
pub(crate) fn push_try_control_info(&mut self, has_finally: bool, start_address: u32) {
pub(crate) fn push_try_control_info(
&mut self,
has_finally: bool,
start_address: u32,
use_expr: bool,
) {
let new_info = JumpControlInfo::default()
.with_try_block_flag(true)
.with_start_address(start_address)
.with_has_finally(has_finally);

self.jump_info.push(new_info);
self.push_contol_info(new_info, use_expr);
}

/// Pops and handles the info for a try block's `JumpControlInfo`
Expand Down Expand Up @@ -406,12 +432,12 @@ impl ByteCompiler<'_, '_> {
}

/// Pushes a `TryStatement`'s Finally block `JumpControlInfo` onto the `jump_info` stack.
pub(crate) fn push_init_finally_control_info(&mut self) {
pub(crate) fn push_init_finally_control_info(&mut self, use_expr: bool) {
let mut new_info = JumpControlInfo::default().with_try_block_flag(true);

new_info.set_in_finally(true);

self.jump_info.push(new_info);
self.push_contol_info(new_info, use_expr);
}

pub(crate) fn pop_finally_control_info(&mut self) {
Expand Down
5 changes: 3 additions & 2 deletions boa_engine/src/bytecompiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {

/// Compile a [`StatementList`].
pub fn compile_statement_list(&mut self, list: &StatementList, use_expr: bool, block: bool) {
if use_expr {
if use_expr || self.jump_control_info_has_use_expr() {
let mut has_returns_value = false;
let mut use_expr_index = 0;
let mut first_return_is_abrupt = false;
Expand All @@ -781,6 +781,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {

if first_return_is_abrupt {
self.emit_opcode(Opcode::PushUndefined);
self.emit_opcode(Opcode::SetReturnValue);
}

for (i, item) in list.statements().iter().enumerate() {
Expand Down Expand Up @@ -1055,7 +1056,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
fn compile_stmt_list_item(&mut self, item: &StatementListItem, use_expr: bool, block: bool) {
match item {
StatementListItem::Statement(stmt) => {
self.compile_stmt(stmt, use_expr);
self.compile_stmt(stmt, use_expr, false);
}
StatementListItem::Declaration(decl) => self.compile_decl(decl, block),
}
Expand Down
22 changes: 4 additions & 18 deletions boa_engine/src/bytecompiler/statement/break.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,12 @@ use boa_interner::Sym;

impl ByteCompiler<'_, '_> {
/// Compile a [`Break`] `boa_ast` node
pub(crate) fn compile_break(&mut self, node: Break) {
let opcode = if node.label().is_some() {
Opcode::BreakLabel
} else {
Opcode::Break
};

pub(crate) fn compile_break(&mut self, node: Break, _use_expr: bool) {
if let Some(info) = self.jump_info.last().filter(|info| info.is_try_block()) {
let in_finally = info.in_finally();
let in_catch_no_finally = info.in_catch() && !info.has_finally();
let has_finally_or_is_finally = info.has_finally() || info.in_finally();

if in_finally {
self.emit_opcode(Opcode::PopIfThrown);
}
if in_finally || in_catch_no_finally {
self.emit_opcode(Opcode::CatchEnd2);
}

let (break_label, target_jump_label) = self.emit_opcode_with_two_operands(opcode);
let (break_label, target_jump_label) =
self.emit_opcode_with_two_operands(Opcode::Break);

if let Some(node_label) = node.label() {
let info = self.jump_info_label(node_label);
Expand Down Expand Up @@ -54,7 +40,7 @@ impl ByteCompiler<'_, '_> {
}

// Emit the break opcode -> (Label, Label)
let (break_label, target_label) = self.emit_opcode_with_two_operands(opcode);
let (break_label, target_label) = self.emit_opcode_with_two_operands(Opcode::Break);
if let Some(label) = node.label() {
let info = self.jump_info_label(label);
info.push_break_label(break_label);
Expand Down
9 changes: 1 addition & 8 deletions boa_engine/src/bytecompiler/statement/continue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,11 @@ use boa_ast::statement::Continue;

impl ByteCompiler<'_, '_> {
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn compile_continue(&mut self, node: Continue) {
pub(crate) fn compile_continue(&mut self, node: Continue, _use_expr: bool) {
if let Some(info) = self.jump_info.last().filter(|info| info.is_try_block()) {
let in_finally = info.in_finally();
let in_finally_or_has_finally = in_finally || info.has_finally();
let in_catch_no_finally = !info.has_finally() && info.in_catch();

if in_finally {
self.emit_opcode(Opcode::PopIfThrown);
}
if in_finally || in_catch_no_finally {
self.emit_opcode(Opcode::CatchEnd2);
}
// 1. Handle if node has a label.
if let Some(node_label) = node.label() {
let items = self.jump_info.iter().rev().filter(|info| info.is_loop());
Expand Down
Loading

0 comments on commit fed05d7

Please sign in to comment.