Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Store call frames in Vec instead of singly-linked list (boa-dev#2164)
Browse files Browse the repository at this point in the history
This storage method should be more cache friendly since we store in contiguous memory, besides that it should make boa-dev#2157 a bit easier. Will work on that next after this gets merged :)

It changes the following:
- Remove the unneeded `prev` field in `CallFrame`
- Preallocate some space for future calls (16 slots)
HalidOdat authored and lameferret committed Jul 6, 2022
1 parent 360fe19 commit f6f3e14
Showing 7 changed files with 16 additions and 28 deletions.
4 changes: 1 addition & 3 deletions boa_engine/src/builtins/console/mod.rs
Original file line number Diff line number Diff line change
@@ -294,16 +294,14 @@ impl Console {

fn get_stack_trace(context: &mut Context) -> Vec<String> {
let mut stack_trace: Vec<String> = vec![];
let mut prev_frame = context.vm.frame.as_ref();

while let Some(frame) = prev_frame {
for frame in context.vm.frames.iter().rev() {
stack_trace.push(
context
.interner()
.resolve_expect(frame.code.name)
.to_owned(),
);
prev_frame = frame.prev.as_ref();
}

stack_trace
4 changes: 2 additions & 2 deletions boa_engine/src/builtins/generator/mod.rs
Original file line number Diff line number Diff line change
@@ -263,7 +263,7 @@ impl Generator {

let result = context.run();

generator_context.call_frame = *context
generator_context.call_frame = context
.vm
.pop_frame()
.expect("generator call frame must exist");
@@ -384,7 +384,7 @@ impl Generator {
context.run()
}
};
generator_context.call_frame = *context
generator_context.call_frame = context
.vm
.pop_frame()
.expect("generator call frame must exist");
3 changes: 1 addition & 2 deletions boa_engine/src/context/mod.rs
Original file line number Diff line number Diff line change
@@ -714,7 +714,6 @@ impl Context {
let _timer = Profiler::global().start_event("Execution", "Main");

self.vm.push_frame(CallFrame {
prev: None,
code: code_block,
pc: 0,
catch: Vec::new(),
@@ -833,7 +832,7 @@ impl ContextBuilder {
console: Console::default(),
intrinsics: Intrinsics::default(),
vm: Vm {
frame: None,
frames: Vec::with_capacity(16),
stack: Vec::with_capacity(1024),
trace: false,
stack_size_limit: 1024,
1 change: 0 additions & 1 deletion boa_engine/src/vm/call_frame.rs
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@ use boa_gc::{Finalize, Gc, Trace};

#[derive(Clone, Debug, Finalize, Trace)]
pub struct CallFrame {
pub(crate) prev: Option<Box<Self>>,
pub(crate) code: Gc<CodeBlock>,
pub(crate) pc: usize,
#[unsafe_ignore_trace]
6 changes: 1 addition & 5 deletions boa_engine/src/vm/code_block.rs
Original file line number Diff line number Diff line change
@@ -723,7 +723,6 @@ impl JsObject {
let has_expressions = code.params.has_expressions();

context.vm.push_frame(CallFrame {
prev: None,
code,
pc: 0,
catch: Vec::new(),
@@ -844,7 +843,6 @@ impl JsObject {
let has_expressions = code.params.has_expressions();

context.vm.push_frame(CallFrame {
prev: None,
code,
pc: 0,
catch: Vec::new(),
@@ -955,7 +953,6 @@ impl JsObject {
let param_count = code.params.parameters.len();

let call_frame = CallFrame {
prev: None,
code,
pc: 0,
catch: Vec::new(),
@@ -999,7 +996,7 @@ impl JsObject {
state: GeneratorState::SuspendedStart,
context: Some(Gc::new(Cell::new(GeneratorContext {
environments,
call_frame: *call_frame,
call_frame,
stack,
}))),
}),
@@ -1189,7 +1186,6 @@ impl JsObject {
let param_count = code.params.parameters.len();

context.vm.push_frame(CallFrame {
prev: None,
code,
pc: 0,
catch: Vec::new(),
24 changes: 10 additions & 14 deletions boa_engine/src/vm/mod.rs
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ mod tests;
/// Virtual Machine.
#[derive(Debug)]
pub struct Vm {
pub(crate) frame: Option<Box<CallFrame>>,
pub(crate) frames: Vec<CallFrame>,
pub(crate) stack: Vec<JsValue>,
pub(crate) trace: bool,
pub(crate) stack_size_limit: usize,
@@ -81,7 +81,7 @@ impl Vm {
/// If there is no frame, then this will panic.
#[inline]
pub(crate) fn frame(&self) -> &CallFrame {
self.frame.as_ref().expect("no frame found")
self.frames.last().expect("no frame found")
}

/// Retrieves the VM frame mutably
@@ -91,21 +91,17 @@ impl Vm {
/// If there is no frame, then this will panic.
#[inline]
pub(crate) fn frame_mut(&mut self) -> &mut CallFrame {
self.frame.as_mut().expect("no frame found")
self.frames.last_mut().expect("no frame found")
}

#[inline]
pub(crate) fn push_frame(&mut self, mut frame: CallFrame) {
let prev = self.frame.take();
frame.prev = prev;
self.frame = Some(Box::new(frame));
pub(crate) fn push_frame(&mut self, frame: CallFrame) {
self.frames.push(frame);
}

#[inline]
pub(crate) fn pop_frame(&mut self) -> Option<Box<CallFrame>> {
let mut current = self.frame.take()?;
self.frame = current.prev.take();
Some(current)
pub(crate) fn pop_frame(&mut self) -> Option<CallFrame> {
self.frames.pop()
}
}

@@ -2307,7 +2303,7 @@ impl Context {
context.vm.push(args.get_or_undefined(0));
context.run()?;

*frame = *context
*frame = context
.vm
.pop_frame()
.expect("generator call frame must exist");
@@ -2346,7 +2342,7 @@ impl Context {
context.vm.push(args.get_or_undefined(0));
context.run()?;

*frame = *context
*frame = context
.vm
.pop_frame()
.expect("generator call frame must exist");
@@ -2392,7 +2388,7 @@ impl Context {
let _timer = Profiler::global().start_event("run", "vm");

if self.vm.trace {
let msg = if self.vm.frame().prev.is_some() {
let msg = if self.vm.frames.get(self.vm.frames.len() - 2).is_some() {
" Call Frame "
} else {
" VM Start "
2 changes: 1 addition & 1 deletion test262
Submodule test262 updated 1331 files

0 comments on commit f6f3e14

Please sign in to comment.