Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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