Browse Source

Decouple bytecompiler from CodeBlock (#2669)

Hopefully this is a PR in a series of PRs to implement a bytecode optimizer, before that can happen there needs to be a lot of refactoring in the way we store and compile it.

This also give us some memory benefits, it reduces `CodeBlock` size from `264` **=>** `208` (removes `56` bytes).

Additionally when calling `into_boxed_slice`, If the vector has excess capacity, its items will be moved into a newly-allocated buffer with exactly the right capacity removing wasted space.
pull/2678/head
Haled Odat 2 years ago
parent
commit
da866cae64
  1. 107
      boa_engine/src/bytecompiler/class.rs
  2. 33
      boa_engine/src/bytecompiler/function.rs
  3. 153
      boa_engine/src/bytecompiler/mod.rs
  4. 28
      boa_engine/src/vm/code_block.rs
  5. 2
      boa_engine/src/vm/flowgraph/mod.rs

107
boa_engine/src/bytecompiler/class.rs

@ -1,5 +1,5 @@
use super::{ByteCompiler, Literal, NodeKind}; use super::{ByteCompiler, Literal, NodeKind};
use crate::vm::{BindingOpcode, CodeBlock, Opcode}; use crate::vm::{BindingOpcode, Opcode};
use boa_ast::{ use boa_ast::{
declaration::Binding, declaration::Binding,
expression::Identifier, expression::Identifier,
@ -9,7 +9,6 @@ use boa_ast::{
}; };
use boa_gc::Gc; use boa_gc::Gc;
use boa_interner::Sym; use boa_interner::Sym;
use rustc_hash::FxHashMap;
impl ByteCompiler<'_, '_> { impl ByteCompiler<'_, '_> {
/// This function compiles a class declaration or expression. /// This function compiles a class declaration or expression.
@ -20,22 +19,11 @@ impl ByteCompiler<'_, '_> {
pub(crate) fn compile_class(&mut self, class: &Class, expression: bool) { pub(crate) fn compile_class(&mut self, class: &Class, expression: bool) {
let class_name = class.name().map_or(Sym::EMPTY_STRING, Identifier::sym); let class_name = class.name().map_or(Sym::EMPTY_STRING, Identifier::sym);
let code = CodeBlock::new(class_name, 0, true); let mut compiler = ByteCompiler::new(class_name, true, self.json_parse, self.context);
let mut compiler = ByteCompiler {
code_block: code,
literals_map: FxHashMap::default(),
names_map: FxHashMap::default(),
private_names_map: FxHashMap::default(),
bindings_map: FxHashMap::default(),
jump_info: Vec::new(),
in_async_generator: false,
json_parse: self.json_parse,
context: self.context,
};
if let Some(class_name) = class.name() { if let Some(class_name) = class.name() {
if class.has_binding_identifier() { if class.has_binding_identifier() {
compiler.code_block.has_binding_identifier = true; compiler.has_binding_identifier = true;
compiler.context.push_compile_time_environment(false); compiler.context.push_compile_time_environment(false);
compiler.context.create_immutable_binding(class_name, true); compiler.context.create_immutable_binding(class_name, true);
} }
@ -44,12 +32,12 @@ impl ByteCompiler<'_, '_> {
compiler.context.push_compile_time_environment(true); compiler.context.push_compile_time_environment(true);
if let Some(expr) = class.constructor() { if let Some(expr) = class.constructor() {
compiler.code_block.length = expr.parameters().length(); compiler.length = expr.parameters().length();
compiler.code_block.params = expr.parameters().clone(); compiler.params = expr.parameters().clone();
compiler compiler
.context .context
.create_mutable_binding(Sym::ARGUMENTS.into(), false, false); .create_mutable_binding(Sym::ARGUMENTS.into(), false, false);
compiler.code_block.arguments_binding = Some( compiler.arguments_binding = Some(
compiler compiler
.context .context
.initialize_mutable_binding(Sym::ARGUMENTS.into(), false), .initialize_mutable_binding(Sym::ARGUMENTS.into(), false),
@ -84,10 +72,9 @@ impl ByteCompiler<'_, '_> {
compiler.emit_opcode(Opcode::RestParameterPop); compiler.emit_opcode(Opcode::RestParameterPop);
} }
let env_label = if expr.parameters().has_expressions() { let env_label = if expr.parameters().has_expressions() {
compiler.code_block.num_bindings = compiler.context.get_binding_number(); compiler.num_bindings = compiler.context.get_binding_number();
compiler.context.push_compile_time_environment(true); compiler.context.push_compile_time_environment(true);
compiler.code_block.function_environment_push_location = compiler.function_environment_push_location = compiler.next_opcode_location();
compiler.next_opcode_location();
Some(compiler.emit_opcode_with_two_operands(Opcode::PushFunctionEnvironment)) Some(compiler.emit_opcode_with_two_operands(Opcode::PushFunctionEnvironment))
} else { } else {
None None
@ -107,8 +94,8 @@ impl ByteCompiler<'_, '_> {
let (num_bindings, compile_environment) = let (num_bindings, compile_environment) =
compiler.context.pop_compile_time_environment(); compiler.context.pop_compile_time_environment();
compiler.push_compile_environment(compile_environment); compiler.push_compile_environment(compile_environment);
compiler.code_block.num_bindings = num_bindings; compiler.num_bindings = num_bindings;
compiler.code_block.is_class_constructor = true; compiler.is_class_constructor = true;
} }
} else { } else {
if class.super_ref().is_some() { if class.super_ref().is_some() {
@ -117,8 +104,8 @@ impl ByteCompiler<'_, '_> {
let (num_bindings, compile_environment) = let (num_bindings, compile_environment) =
compiler.context.pop_compile_time_environment(); compiler.context.pop_compile_time_environment();
compiler.push_compile_environment(compile_environment); compiler.push_compile_environment(compile_environment);
compiler.code_block.num_bindings = num_bindings; compiler.num_bindings = num_bindings;
compiler.code_block.is_class_constructor = true; compiler.is_class_constructor = true;
} }
if class.name().is_some() && class.has_binding_identifier() { if class.name().is_some() && class.has_binding_identifier() {
@ -130,8 +117,8 @@ impl ByteCompiler<'_, '_> {
compiler.emit_opcode(Opcode::Return); compiler.emit_opcode(Opcode::Return);
let code = Gc::new(compiler.finish()); let code = Gc::new(compiler.finish());
let index = self.code_block.functions.len() as u32; let index = self.functions.len() as u32;
self.code_block.functions.push(code); self.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0); self.emit_u8(0);
@ -279,18 +266,8 @@ impl ByteCompiler<'_, '_> {
self.compile_expr(name, true); self.compile_expr(name, true);
} }
} }
let field_code = CodeBlock::new(Sym::EMPTY_STRING, 0, true); let mut field_compiler =
let mut field_compiler = ByteCompiler { ByteCompiler::new(Sym::EMPTY_STRING, true, self.json_parse, self.context);
code_block: field_code,
literals_map: FxHashMap::default(),
names_map: FxHashMap::default(),
private_names_map: FxHashMap::default(),
bindings_map: FxHashMap::default(),
jump_info: Vec::new(),
in_async_generator: false,
json_parse: self.json_parse,
context: self.context,
};
field_compiler.context.push_compile_time_environment(false); field_compiler.context.push_compile_time_environment(false);
field_compiler field_compiler
.context .context
@ -307,14 +284,14 @@ impl ByteCompiler<'_, '_> {
let (_, compile_environment) = let (_, compile_environment) =
field_compiler.context.pop_compile_time_environment(); field_compiler.context.pop_compile_time_environment();
field_compiler.push_compile_environment(compile_environment); field_compiler.push_compile_environment(compile_environment);
field_compiler.code_block.num_bindings = num_bindings; field_compiler.num_bindings = num_bindings;
field_compiler.emit_opcode(Opcode::Return); field_compiler.emit_opcode(Opcode::Return);
let mut code = field_compiler.finish(); let mut code = field_compiler.finish();
code.class_field_initializer_name = Some(Sym::EMPTY_STRING); code.class_field_initializer_name = Some(Sym::EMPTY_STRING);
let code = Gc::new(code); let code = Gc::new(code);
let index = self.code_block.functions.len() as u32; let index = self.functions.len() as u32;
self.code_block.functions.push(code); self.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0); self.emit_u8(0);
self.emit_opcode(Opcode::PushClassField); self.emit_opcode(Opcode::PushClassField);
@ -322,18 +299,8 @@ impl ByteCompiler<'_, '_> {
ClassElement::PrivateFieldDefinition(name, field) => { ClassElement::PrivateFieldDefinition(name, field) => {
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
let name_index = self.get_or_insert_private_name(*name); let name_index = self.get_or_insert_private_name(*name);
let field_code = CodeBlock::new(Sym::EMPTY_STRING, 0, true); let mut field_compiler =
let mut field_compiler = ByteCompiler { ByteCompiler::new(class_name, true, self.json_parse, self.context);
code_block: field_code,
literals_map: FxHashMap::default(),
names_map: FxHashMap::default(),
private_names_map: FxHashMap::default(),
bindings_map: FxHashMap::default(),
jump_info: Vec::new(),
in_async_generator: false,
json_parse: self.json_parse,
context: self.context,
};
field_compiler.context.push_compile_time_environment(false); field_compiler.context.push_compile_time_environment(false);
field_compiler field_compiler
.context .context
@ -350,14 +317,14 @@ impl ByteCompiler<'_, '_> {
let (_, compile_environment) = let (_, compile_environment) =
field_compiler.context.pop_compile_time_environment(); field_compiler.context.pop_compile_time_environment();
field_compiler.push_compile_environment(compile_environment); field_compiler.push_compile_environment(compile_environment);
field_compiler.code_block.num_bindings = num_bindings; field_compiler.num_bindings = num_bindings;
field_compiler.emit_opcode(Opcode::Return); field_compiler.emit_opcode(Opcode::Return);
let mut code = field_compiler.finish(); let mut code = field_compiler.finish();
code.class_field_initializer_name = Some(Sym::EMPTY_STRING); code.class_field_initializer_name = Some(Sym::EMPTY_STRING);
let code = Gc::new(code); let code = Gc::new(code);
let index = self.code_block.functions.len() as u32; let index = self.functions.len() as u32;
self.code_block.functions.push(code); self.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0); self.emit_u8(0);
self.emit(Opcode::PushClassFieldPrivate, &[name_index]); self.emit(Opcode::PushClassFieldPrivate, &[name_index]);
@ -375,18 +342,8 @@ impl ByteCompiler<'_, '_> {
None None
} }
}; };
let field_code = CodeBlock::new(Sym::EMPTY_STRING, 0, true); let mut field_compiler =
let mut field_compiler = ByteCompiler { ByteCompiler::new(class_name, true, self.json_parse, self.context);
code_block: field_code,
literals_map: FxHashMap::default(),
names_map: FxHashMap::default(),
private_names_map: FxHashMap::default(),
bindings_map: FxHashMap::default(),
jump_info: Vec::new(),
in_async_generator: false,
json_parse: self.json_parse,
context: self.context,
};
field_compiler.context.push_compile_time_environment(false); field_compiler.context.push_compile_time_environment(false);
field_compiler field_compiler
.context .context
@ -403,14 +360,14 @@ impl ByteCompiler<'_, '_> {
let (_, compile_environment) = let (_, compile_environment) =
field_compiler.context.pop_compile_time_environment(); field_compiler.context.pop_compile_time_environment();
field_compiler.push_compile_environment(compile_environment); field_compiler.push_compile_environment(compile_environment);
field_compiler.code_block.num_bindings = num_bindings; field_compiler.num_bindings = num_bindings;
field_compiler.emit_opcode(Opcode::Return); field_compiler.emit_opcode(Opcode::Return);
let mut code = field_compiler.finish(); let mut code = field_compiler.finish();
code.class_field_initializer_name = Some(Sym::EMPTY_STRING); code.class_field_initializer_name = Some(Sym::EMPTY_STRING);
let code = Gc::new(code); let code = Gc::new(code);
let index = self.code_block.functions.len() as u32; let index = self.functions.len() as u32;
self.code_block.functions.push(code); self.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0); self.emit_u8(0);
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);
@ -447,11 +404,11 @@ impl ByteCompiler<'_, '_> {
compiler.push_compile_environment(compile_environment); compiler.push_compile_environment(compile_environment);
let (_, compile_environment) = compiler.context.pop_compile_time_environment(); let (_, compile_environment) = compiler.context.pop_compile_time_environment();
compiler.push_compile_environment(compile_environment); compiler.push_compile_environment(compile_environment);
compiler.code_block.num_bindings = num_bindings; compiler.num_bindings = num_bindings;
let code = Gc::new(compiler.finish()); let code = Gc::new(compiler.finish());
let index = self.code_block.functions.len() as u32; let index = self.functions.len() as u32;
self.code_block.functions.push(code); self.functions.push(code);
self.emit(Opcode::GetFunction, &[index]); self.emit(Opcode::GetFunction, &[index]);
self.emit_u8(0); self.emit_u8(0);
self.emit_opcode(Opcode::SetHomeObject); self.emit_opcode(Opcode::SetHomeObject);

33
boa_engine/src/bytecompiler/function.rs

@ -9,7 +9,6 @@ use boa_ast::{
}; };
use boa_gc::Gc; use boa_gc::Gc;
use boa_interner::Sym; use boa_interner::Sym;
use rustc_hash::FxHashMap;
/// `FunctionCompiler` is used to compile AST functions to bytecode. /// `FunctionCompiler` is used to compile AST functions to bytecode.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -95,24 +94,15 @@ impl FunctionCompiler {
self.strict = self.strict || body.strict(); self.strict = self.strict || body.strict();
let length = parameters.length(); let length = parameters.length();
let mut code = CodeBlock::new(self.name, length, self.strict);
let mut compiler = ByteCompiler::new(self.name, self.strict, false, context);
compiler.length = length;
compiler.in_async_generator = self.generator && self.r#async;
if self.arrow { if self.arrow {
code.this_mode = ThisMode::Lexical; compiler.this_mode = ThisMode::Lexical;
} }
let mut compiler = ByteCompiler {
code_block: code,
literals_map: FxHashMap::default(),
names_map: FxHashMap::default(),
private_names_map: FxHashMap::default(),
bindings_map: FxHashMap::default(),
jump_info: Vec::new(),
in_async_generator: self.generator && self.r#async,
json_parse: false,
context,
};
if let Some(class_name) = self.class_name { if let Some(class_name) = self.class_name {
compiler.context.push_compile_time_environment(false); compiler.context.push_compile_time_environment(false);
compiler compiler
@ -121,7 +111,7 @@ impl FunctionCompiler {
} }
if let Some(binding_identifier) = self.binding_identifier { if let Some(binding_identifier) = self.binding_identifier {
compiler.code_block.has_binding_identifier = true; compiler.has_binding_identifier = true;
compiler.context.push_compile_time_environment(false); compiler.context.push_compile_time_environment(false);
compiler compiler
.context .context
@ -139,7 +129,7 @@ impl FunctionCompiler {
compiler compiler
.context .context
.create_mutable_binding(Sym::ARGUMENTS.into(), false, false); .create_mutable_binding(Sym::ARGUMENTS.into(), false, false);
compiler.code_block.arguments_binding = Some( compiler.arguments_binding = Some(
compiler compiler
.context .context
.initialize_mutable_binding(Sym::ARGUMENTS.into(), false), .initialize_mutable_binding(Sym::ARGUMENTS.into(), false),
@ -184,10 +174,9 @@ impl FunctionCompiler {
} }
let env_label = if parameters.has_expressions() { let env_label = if parameters.has_expressions() {
compiler.code_block.num_bindings = compiler.context.get_binding_number(); compiler.num_bindings = compiler.context.get_binding_number();
compiler.context.push_compile_time_environment(true); compiler.context.push_compile_time_environment(true);
compiler.code_block.function_environment_push_location = compiler.function_environment_push_location = compiler.next_opcode_location();
compiler.next_opcode_location();
Some(compiler.emit_opcode_with_two_operands(Opcode::PushFunctionEnvironment)) Some(compiler.emit_opcode_with_two_operands(Opcode::PushFunctionEnvironment))
} else { } else {
None None
@ -215,7 +204,7 @@ impl FunctionCompiler {
let (num_bindings, compile_environment) = let (num_bindings, compile_environment) =
compiler.context.pop_compile_time_environment(); compiler.context.pop_compile_time_environment();
compiler.push_compile_environment(compile_environment); compiler.push_compile_environment(compile_environment);
compiler.code_block.num_bindings = num_bindings; compiler.num_bindings = num_bindings;
} }
if self.binding_identifier.is_some() { if self.binding_identifier.is_some() {
@ -228,7 +217,7 @@ impl FunctionCompiler {
compiler.push_compile_environment(compile_environment); compiler.push_compile_environment(compile_environment);
} }
compiler.code_block.params = parameters.clone(); compiler.params = parameters.clone();
// TODO These are redundant if a function returns so may need to check if a function returns and adding these if it doesn't // TODO These are redundant if a function returns so may need to check if a function returns and adding these if it doesn't
compiler.emit(Opcode::PushUndefined, &[]); compiler.emit(Opcode::PushUndefined, &[]);

153
boa_engine/src/bytecompiler/mod.rs

@ -9,6 +9,7 @@ mod module;
mod statement; mod statement;
use crate::{ use crate::{
builtins::function::ThisMode,
environments::{BindingLocator, CompileTimeEnvironment}, environments::{BindingLocator, CompileTimeEnvironment},
vm::{BindingOpcode, CodeBlock, Opcode}, vm::{BindingOpcode, CodeBlock, Opcode},
Context, JsBigInt, JsString, JsValue, Context, JsBigInt, JsString, JsValue,
@ -210,8 +211,65 @@ impl Access<'_> {
/// The [`ByteCompiler`] is used to compile ECMAScript AST from [`boa_ast`] to bytecode. /// The [`ByteCompiler`] is used to compile ECMAScript AST from [`boa_ast`] to bytecode.
#[derive(Debug)] #[derive(Debug)]
#[allow(clippy::struct_excessive_bools)]
pub struct ByteCompiler<'b, 'host> { pub struct ByteCompiler<'b, 'host> {
code_block: CodeBlock, /// Name of this function.
pub(crate) function_name: Sym,
/// Indicates if the function is an expression and has a binding identifier.
pub(crate) has_binding_identifier: bool,
/// The number of arguments expected.
pub(crate) length: u32,
/// Is this function in strict mode.
pub(crate) strict: bool,
/// \[\[ThisMode\]\]
pub(crate) this_mode: ThisMode,
/// Parameters passed to this function.
pub(crate) params: FormalParameterList,
/// Bytecode
pub(crate) bytecode: Vec<u8>,
/// Literals
pub(crate) literals: Vec<JsValue>,
/// Property field names.
pub(crate) names: Vec<Identifier>,
/// Private names.
pub(crate) private_names: Vec<PrivateName>,
/// Locators for all bindings in the codeblock.
pub(crate) bindings: Vec<BindingLocator>,
/// Number of binding for the function environment.
pub(crate) num_bindings: usize,
/// Functions inside this function
pub(crate) functions: Vec<Gc<CodeBlock>>,
/// The `arguments` binding location of the function, if set.
pub(crate) arguments_binding: Option<BindingLocator>,
/// Compile time environments in this function.
pub(crate) compile_environments: Vec<Gc<GcRefCell<CompileTimeEnvironment>>>,
/// The `[[IsClassConstructor]]` internal slot.
pub(crate) is_class_constructor: bool,
/// The `[[ClassFieldInitializerName]]` internal slot.
pub(crate) class_field_initializer_name: Option<Sym>,
/// Marks the location in the code where the function environment in pushed.
/// This is only relevant for functions with expressions in the parameters.
/// We execute the parameter expressions in the function code and push the function environment afterward.
/// When the execution of the parameter expressions throws an error, we do not need to pop the function environment.
pub(crate) function_environment_push_location: u32,
literals_map: FxHashMap<Literal, u32>, literals_map: FxHashMap<Literal, u32>,
names_map: FxHashMap<Identifier, u32>, names_map: FxHashMap<Identifier, u32>,
private_names_map: FxHashMap<PrivateName, u32>, private_names_map: FxHashMap<PrivateName, u32>,
@ -226,7 +284,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
/// Represents a placeholder address that will be patched later. /// Represents a placeholder address that will be patched later.
const DUMMY_ADDRESS: u32 = u32::MAX; const DUMMY_ADDRESS: u32 = u32::MAX;
/// Creates a new `ByteCompiler`. /// Creates a new [`ByteCompiler`].
#[inline] #[inline]
pub fn new( pub fn new(
name: Sym, name: Sym,
@ -235,7 +293,25 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
context: &'b mut Context<'host>, context: &'b mut Context<'host>,
) -> ByteCompiler<'b, 'host> { ) -> ByteCompiler<'b, 'host> {
Self { Self {
code_block: CodeBlock::new(name, 0, strict), function_name: name,
strict,
length: 0,
bytecode: Vec::default(),
literals: Vec::default(),
names: Vec::default(),
private_names: Vec::default(),
bindings: Vec::default(),
num_bindings: 0,
functions: Vec::default(),
has_binding_identifier: false,
this_mode: ThisMode::Global,
params: FormalParameterList::default(),
arguments_binding: None,
compile_environments: Vec::default(),
is_class_constructor: false,
class_field_initializer_name: None,
function_environment_push_location: 0,
literals_map: FxHashMap::default(), literals_map: FxHashMap::default(),
names_map: FxHashMap::default(), names_map: FxHashMap::default(),
private_names_map: FxHashMap::default(), private_names_map: FxHashMap::default(),
@ -256,8 +332,8 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
&mut self, &mut self,
environment: Gc<GcRefCell<CompileTimeEnvironment>>, environment: Gc<GcRefCell<CompileTimeEnvironment>>,
) -> usize { ) -> usize {
let index = self.code_block.compile_environments.len(); let index = self.compile_environments.len();
self.code_block.compile_environments.push(environment); self.compile_environments.push(environment);
index index
} }
@ -271,8 +347,8 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
Literal::BigInt(value) => JsValue::new(value), Literal::BigInt(value) => JsValue::new(value),
}; };
let index = self.code_block.literals.len() as u32; let index = self.literals.len() as u32;
self.code_block.literals.push(value); self.literals.push(value);
self.literals_map.insert(literal, index); self.literals_map.insert(literal, index);
index index
} }
@ -282,8 +358,8 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
return *index; return *index;
} }
let index = self.code_block.names.len() as u32; let index = self.names.len() as u32;
self.code_block.names.push(name); self.names.push(name);
self.names_map.insert(name, index); self.names_map.insert(name, index);
index index
} }
@ -294,8 +370,8 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
return *index; return *index;
} }
let index = self.code_block.private_names.len() as u32; let index = self.private_names.len() as u32;
self.code_block.private_names.push(name); self.private_names.push(name);
self.private_names_map.insert(name, index); self.private_names_map.insert(name, index);
index index
} }
@ -306,8 +382,8 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
return *index; return *index;
} }
let index = self.code_block.bindings.len() as u32; let index = self.bindings.len() as u32;
self.code_block.bindings.push(binding); self.bindings.push(binding);
self.bindings_map.insert(binding, index); self.bindings_map.insert(binding, index);
index index
} }
@ -357,8 +433,8 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
} }
fn next_opcode_location(&mut self) -> u32 { fn next_opcode_location(&mut self) -> u32 {
assert!(self.code_block.bytecode.len() < u32::MAX as usize); assert!(self.bytecode.len() < u32::MAX as usize);
self.code_block.bytecode.len() as u32 self.bytecode.len() as u32
} }
fn emit(&mut self, opcode: Opcode, operands: &[u32]) { fn emit(&mut self, opcode: Opcode, operands: &[u32]) {
@ -369,15 +445,15 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
} }
fn emit_u64(&mut self, value: u64) { fn emit_u64(&mut self, value: u64) {
self.code_block.bytecode.extend(value.to_ne_bytes()); self.bytecode.extend(value.to_ne_bytes());
} }
fn emit_u32(&mut self, value: u32) { fn emit_u32(&mut self, value: u32) {
self.code_block.bytecode.extend(value.to_ne_bytes()); self.bytecode.extend(value.to_ne_bytes());
} }
fn emit_u16(&mut self, value: u16) { fn emit_u16(&mut self, value: u16) {
self.code_block.bytecode.extend(value.to_ne_bytes()); self.bytecode.extend(value.to_ne_bytes());
} }
fn emit_opcode(&mut self, opcode: Opcode) { fn emit_opcode(&mut self, opcode: Opcode) {
@ -385,7 +461,7 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
} }
fn emit_u8(&mut self, value: u8) { fn emit_u8(&mut self, value: u8) {
self.code_block.bytecode.push(value); self.bytecode.push(value);
} }
fn emit_push_integer(&mut self, value: i32) { fn emit_push_integer(&mut self, value: i32) {
@ -473,10 +549,10 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
let index = index as usize; let index = index as usize;
let bytes = target.to_ne_bytes(); let bytes = target.to_ne_bytes();
self.code_block.bytecode[index + 1] = bytes[0]; self.bytecode[index + 1] = bytes[0];
self.code_block.bytecode[index + 2] = bytes[1]; self.bytecode[index + 2] = bytes[1];
self.code_block.bytecode[index + 3] = bytes[2]; self.bytecode[index + 3] = bytes[2];
self.code_block.bytecode[index + 4] = bytes[3]; self.bytecode[index + 4] = bytes[3];
} }
fn patch_jump(&mut self, label: Label) { fn patch_jump(&mut self, label: Label) {
@ -1042,13 +1118,13 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
.name(name.map(Identifier::sym)) .name(name.map(Identifier::sym))
.generator(generator) .generator(generator)
.r#async(r#async) .r#async(r#async)
.strict(self.code_block.strict) .strict(self.strict)
.arrow(arrow) .arrow(arrow)
.binding_identifier(binding_identifier) .binding_identifier(binding_identifier)
.compile(parameters, body, self.context); .compile(parameters, body, self.context);
let index = self.code_block.functions.len() as u32; let index = self.functions.len() as u32;
self.code_block.functions.push(code); self.functions.push(code);
if r#async && generator { if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[index]); self.emit(Opcode::GetGeneratorAsync, &[index]);
@ -1121,8 +1197,8 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
.class_name(class_name) .class_name(class_name)
.compile(parameters, body, self.context); .compile(parameters, body, self.context);
let index = self.code_block.functions.len() as u32; let index = self.functions.len() as u32;
self.code_block.functions.push(code); self.functions.push(code);
if r#async && generator { if r#async && generator {
self.emit(Opcode::GetGeneratorAsync, &[index]); self.emit(Opcode::GetGeneratorAsync, &[index]);
@ -1228,7 +1304,26 @@ impl<'b, 'host> ByteCompiler<'b, 'host> {
#[must_use] #[must_use]
#[allow(clippy::missing_const_for_fn)] #[allow(clippy::missing_const_for_fn)]
pub fn finish(self) -> CodeBlock { pub fn finish(self) -> CodeBlock {
self.code_block CodeBlock {
name: self.function_name,
has_binding_identifier: self.has_binding_identifier,
length: self.length,
strict: self.strict,
this_mode: self.this_mode,
params: self.params,
bytecode: self.bytecode.into_boxed_slice(),
literals: self.literals.into_boxed_slice(),
names: self.names.into_boxed_slice(),
private_names: self.private_names.into_boxed_slice(),
bindings: self.bindings.into_boxed_slice(),
num_bindings: self.num_bindings,
functions: self.functions.into_boxed_slice(),
arguments_binding: self.arguments_binding,
compile_environments: self.compile_environments.into_boxed_slice(),
is_class_constructor: self.is_class_constructor,
class_field_initializer_name: self.class_field_initializer_name,
function_environment_push_location: self.function_environment_push_location,
}
} }
fn compile_declaration_pattern(&mut self, pattern: &Pattern, def: BindingOpcode) { fn compile_declaration_pattern(&mut self, pattern: &Pattern, def: BindingOpcode) {

28
boa_engine/src/vm/code_block.rs

@ -80,35 +80,35 @@ pub struct CodeBlock {
pub(crate) params: FormalParameterList, pub(crate) params: FormalParameterList,
/// Bytecode /// Bytecode
pub(crate) bytecode: Vec<u8>, pub(crate) bytecode: Box<[u8]>,
/// Literals /// Literals
pub(crate) literals: Vec<JsValue>, pub(crate) literals: Box<[JsValue]>,
/// Property field names. /// Property field names.
#[unsafe_ignore_trace] #[unsafe_ignore_trace]
pub(crate) names: Vec<Identifier>, pub(crate) names: Box<[Identifier]>,
/// Private names. /// Private names.
#[unsafe_ignore_trace] #[unsafe_ignore_trace]
pub(crate) private_names: Vec<PrivateName>, pub(crate) private_names: Box<[PrivateName]>,
/// Locators for all bindings in the codeblock. /// Locators for all bindings in the codeblock.
#[unsafe_ignore_trace] #[unsafe_ignore_trace]
pub(crate) bindings: Vec<BindingLocator>, pub(crate) bindings: Box<[BindingLocator]>,
/// Number of binding for the function environment. /// Number of binding for the function environment.
pub(crate) num_bindings: usize, pub(crate) num_bindings: usize,
/// Functions inside this function /// Functions inside this function
pub(crate) functions: Vec<Gc<Self>>, pub(crate) functions: Box<[Gc<Self>]>,
/// The `arguments` binding location of the function, if set. /// The `arguments` binding location of the function, if set.
#[unsafe_ignore_trace] #[unsafe_ignore_trace]
pub(crate) arguments_binding: Option<BindingLocator>, pub(crate) arguments_binding: Option<BindingLocator>,
/// Compile time environments in this function. /// Compile time environments in this function.
pub(crate) compile_environments: Vec<Gc<GcRefCell<CompileTimeEnvironment>>>, pub(crate) compile_environments: Box<[Gc<GcRefCell<CompileTimeEnvironment>>]>,
/// The `[[IsClassConstructor]]` internal slot. /// The `[[IsClassConstructor]]` internal slot.
pub(crate) is_class_constructor: bool, pub(crate) is_class_constructor: bool,
@ -129,13 +129,13 @@ impl CodeBlock {
#[must_use] #[must_use]
pub fn new(name: Sym, length: u32, strict: bool) -> Self { pub fn new(name: Sym, length: u32, strict: bool) -> Self {
Self { Self {
bytecode: Vec::new(), bytecode: Box::default(),
literals: Vec::new(), literals: Box::default(),
names: Vec::new(), names: Box::default(),
private_names: Vec::new(), private_names: Box::default(),
bindings: Vec::new(), bindings: Box::default(),
num_bindings: 0, num_bindings: 0,
functions: Vec::new(), functions: Box::default(),
name, name,
has_binding_identifier: false, has_binding_identifier: false,
length, length,
@ -143,7 +143,7 @@ impl CodeBlock {
this_mode: ThisMode::Global, this_mode: ThisMode::Global,
params: FormalParameterList::default(), params: FormalParameterList::default(),
arguments_binding: None, arguments_binding: None,
compile_environments: Vec::new(), compile_environments: Box::default(),
is_class_constructor: false, is_class_constructor: false,
class_field_initializer_name: None, class_field_initializer_name: None,
function_environment_push_location: 0, function_environment_push_location: 0,

2
boa_engine/src/vm/flowgraph/mod.rs

@ -550,7 +550,7 @@ impl CodeBlock {
graph.add_node(pc, NodeShape::Diamond, "End".into(), Color::Red); graph.add_node(pc, NodeShape::Diamond, "End".into(), Color::Red);
for function in &self.functions { for function in self.functions.as_ref() {
let subgraph = graph.subgraph(String::new()); let subgraph = graph.subgraph(String::new());
function.to_graph(interner, subgraph); function.to_graph(interner, subgraph);
} }

Loading…
Cancel
Save