Skip to content

Commit

Permalink
Simplify run method
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Jul 27, 2023
1 parent 50de81b commit 52cb2f6
Showing 1 changed file with 66 additions and 94 deletions.
160 changes: 66 additions & 94 deletions boa_engine/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ impl Vm {
self.frames.last_mut().expect("no frame found")
}

pub(crate) fn push_frame(&mut self, frame: CallFrame) {
pub(crate) fn push_frame(&mut self, mut frame: CallFrame) {
let current_stack_length = self.stack.len();
frame.set_frame_pointer(current_stack_length as u32);
self.frames.push(frame);
}

Expand Down Expand Up @@ -198,15 +200,18 @@ impl Context<'_> {
const NUMBER_OF_COLUMNS: usize = 4;

#[inline(never)]
fn display_trace_call_frame(&self) {
fn trace_call_frame(&self) {
let msg = if self.vm.frames.last().is_some() {
" Call Frame "
format!(
" Call Frame -- {} ",
self.vm.frame().code_block().name().to_std_string_escaped()
)
} else {
" VM Start "
" VM Start ".to_string()
};

println!(
"{}\n",
"{}",
self.vm
.frame()
.code_block
Expand All @@ -217,7 +222,7 @@ impl Context<'_> {
width = Self::COLUMN_WIDTH * Self::NUMBER_OF_COLUMNS - 10
);
println!(
"{:<TIME_COLUMN_WIDTH$} {:<OPCODE_COLUMN_WIDTH$} {:<OPERAND_COLUMN_WIDTH$} Top Of Stack\n",
"{:<TIME_COLUMN_WIDTH$} {:<OPCODE_COLUMN_WIDTH$} {:<OPERAND_COLUMN_WIDTH$} Stack\n",
"Time",
"Opcode",
"Operands",
Expand All @@ -227,6 +232,7 @@ impl Context<'_> {
);
}

#[inline(never)]
fn trace_execute_instruction(&mut self) -> JsResult<CompletionType> {
let mut pc = self.vm.frame().pc as usize;
let opcode: Opcode = self.vm.frame().code_block.read::<u8>(pc).into();
Expand All @@ -240,47 +246,38 @@ impl Context<'_> {
let result = self.execute_instruction();

let duration = instant.elapsed();

let stack = {
let mut stack = String::from("[ ");
for (i, value) in self.vm.stack.iter().rev().enumerate() {
match value {
value if value.is_callable() => stack.push_str("[function]"),
value if value.is_object() => stack.push_str("[object]"),
value => stack.push_str(&value.display().to_string()),
}

if i + 1 != self.vm.stack.len() {
stack.push(',');
}

stack.push(' ');
}

stack.push(']');
stack
};

println!(
"{:<TIME_COLUMN_WIDTH$} {:<OPCODE_COLUMN_WIDTH$} {operands:<OPERAND_COLUMN_WIDTH$} {}",
"{:<TIME_COLUMN_WIDTH$} {:<OPCODE_COLUMN_WIDTH$} {operands:<OPERAND_COLUMN_WIDTH$} {stack}",
format!("{}μs", duration.as_micros()),
opcode.as_str(),
match self.vm.stack.last() {
Some(value) if value.is_callable() => "[function]".to_string(),
Some(value) if value.is_object() => "[object]".to_string(),
Some(value) => value.display().to_string(),
None => "<empty>".to_string(),
},
TIME_COLUMN_WIDTH = Self::TIME_COLUMN_WIDTH,
OPCODE_COLUMN_WIDTH = Self::OPCODE_COLUMN_WIDTH,
OPERAND_COLUMN_WIDTH = Self::OPERAND_COLUMN_WIDTH,
);

result
}

#[inline(never)]
fn display_trace_stack(&self) {
println!("\nStack:");
if self.vm.stack.is_empty() {
println!(" <empty>");
} else {
for (i, value) in self.vm.stack.iter().enumerate() {
println!(
"{i:04}{:<width$} {}",
"",
if value.is_callable() {
"[function]".to_string()
} else if value.is_object() {
"[object]".to_string()
} else {
value.display().to_string()
},
width = Self::COLUMN_WIDTH / 2 - 4,
);
}
}
println!("\n");
}
}

impl Context<'_> {
Expand All @@ -306,44 +303,49 @@ impl Context<'_> {

#[cfg(feature = "trace")]
if self.vm.trace {
self.display_trace_call_frame();
self.trace_call_frame();
}

let current_stack_length = self.vm.stack.len();
self.vm
.frame_mut()
.set_frame_pointer(current_stack_length as u32);

let execution_completion = loop {
let mut result = Ok(CompletionType::Normal);
loop {
#[cfg(feature = "fuzz")]
{
if self.instructions_remaining == 0 {
let err = JsError::from_native(JsNativeError::no_instructions_remain());
self.vm.pending_exception = Some(err);
break CompletionType::Throw;
return CompletionRecord::Throw(err);
}
self.instructions_remaining -= 1;
}

// 1. Run the next instruction.
#[cfg(feature = "trace")]
let result = if self.vm.trace || self.vm.frame().code_block.traceable() {
self.trace_execute_instruction()
} else {
self.execute_instruction()
};

#[cfg(not(feature = "trace"))]
let result = self.execute_instruction();

// 2. Evaluate the result of executing the instruction.
match result {
Ok(CompletionType::Normal) => {}
Ok(CompletionType::Normal) => {
#[cfg(feature = "trace")]
{
result = if self.vm.trace || self.vm.frame().code_block.traceable() {
self.trace_execute_instruction()
} else {
self.execute_instruction()
};
}

#[cfg(not(feature = "trace"))]
{
result = self.execute_instruction();
}
}
Ok(CompletionType::Return) => {
break CompletionType::Return;
self.vm.stack.truncate(self.vm.frame().fp as usize);
let execution_result = self.vm.frame_mut().return_value.clone();
return CompletionRecord::Normal(execution_result);
}
Ok(CompletionType::Throw) => {
break CompletionType::Throw;
self.vm.stack.truncate(self.vm.frame().fp as usize);
return CompletionRecord::Throw(
self.vm
.pending_exception
.take()
.expect("Err must exist for a CompletionType::Throw"),
);
}
// Early return immediately.
Ok(CompletionType::Yield) => {
Expand All @@ -357,50 +359,20 @@ impl Context<'_> {
match native_error.kind {
#[cfg(feature = "fuzz")]
JsNativeErrorKind::NoInstructionsRemain => {
self.vm.pending_exception = Some(err);
break CompletionType::Throw;
return CompletionRecord::Throw(err);
}
JsNativeErrorKind::RuntimeLimit => {
self.vm.pending_exception = Some(err);
break CompletionType::Throw;
return CompletionRecord::Throw(err);
}
_ => {}
}
}

self.vm.pending_exception = Some(err);

let evaluation = Opcode::ReThrow
.execute(self)
.expect("Opcode::Throw cannot return Err");

if evaluation == CompletionType::Normal {
continue;
}

break evaluation;
result = Opcode::ReThrow.execute(self);
}
}
};

#[cfg(feature = "trace")]
if self.vm.trace {
self.display_trace_stack();
}

self.vm.stack.truncate(self.vm.frame().fp as usize);

// Any valid return statement is re-evaluated as a normal completion vs. return (yield).
if execution_completion == CompletionType::Throw {
return CompletionRecord::Throw(
self.vm
.pending_exception
.take()
.expect("Err must exist for a CompletionType::Throw"),
);
}

let execution_result = self.vm.frame_mut().return_value.clone();
CompletionRecord::Normal(execution_result)
}
}

0 comments on commit 52cb2f6

Please sign in to comment.