diff --git a/boa_engine/src/bytecompiler/class.rs b/boa_engine/src/bytecompiler/class.rs index 331bf0f33e2..bae59003bbf 100644 --- a/boa_engine/src/bytecompiler/class.rs +++ b/boa_engine/src/bytecompiler/class.rs @@ -81,8 +81,7 @@ impl ByteCompiler<'_, '_> { compiler.emit_opcode(Opcode::SetReturnValue); let code = Gc::new(compiler.finish()); - let index = self.functions.len() as u32; - self.functions.push(code); + let index = self.push_function_to_constants(code); self.emit( Opcode::GetFunction, &[Operand::Varying(index), Operand::Bool(false)], @@ -294,10 +293,8 @@ impl ByteCompiler<'_, '_> { field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; - let code = field_compiler.finish(); - let code = Gc::new(code); - let index = self.functions.len() as u32; - self.functions.push(code); + let code = Gc::new(field_compiler.finish()); + let index = self.push_function_to_constants(code); self.emit( Opcode::GetFunction, &[Operand::Varying(index), Operand::Bool(false)], @@ -325,10 +322,8 @@ impl ByteCompiler<'_, '_> { field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; - let code = field_compiler.finish(); - let code = Gc::new(code); - let index = self.functions.len() as u32; - self.functions.push(code); + let code = Gc::new(field_compiler.finish()); + let index = self.push_function_to_constants(code); self.emit( Opcode::GetFunction, &[Operand::Varying(index), Operand::Bool(false)], @@ -552,8 +547,7 @@ impl ByteCompiler<'_, '_> { match element { StaticElement::StaticBlock(code) => { self.emit_opcode(Opcode::Dup); - let index = self.functions.len() as u32; - self.functions.push(code); + let index = self.push_function_to_constants(code); self.emit( Opcode::GetFunction, &[Operand::Varying(index), Operand::Bool(false)], @@ -565,8 +559,7 @@ impl ByteCompiler<'_, '_> { StaticElement::StaticField((code, name_index)) => { self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup); - let index = self.functions.len() as u32; - self.functions.push(code); + let index = self.push_function_to_constants(code); self.emit( Opcode::GetFunction, &[Operand::Varying(index), Operand::Bool(false)], diff --git a/boa_engine/src/bytecompiler/declarations.rs b/boa_engine/src/bytecompiler/declarations.rs index 158a6bb4c0e..332d7e313ef 100644 --- a/boa_engine/src/bytecompiler/declarations.rs +++ b/boa_engine/src/bytecompiler/declarations.rs @@ -282,7 +282,7 @@ impl ByteCompiler<'_, '_> { ); // Ensures global functions are printed when generating the global flowgraph. - self.functions.push(code.clone()); + let _ = self.push_function_to_constants(code.clone()); // b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv. let function = if generator { @@ -733,7 +733,7 @@ impl ByteCompiler<'_, '_> { // c. If varEnv is a Global Environment Record, then if var_env.is_global() { // Ensures global functions are printed when generating the global flowgraph. - self.functions.push(code.clone()); + let _ = self.push_function_to_constants(code.clone()); // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv. let function = if generator { @@ -749,8 +749,7 @@ impl ByteCompiler<'_, '_> { // d. Else, else { // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv. - let index = self.functions.len() as u32; - self.functions.push(code); + let index = self.push_function_to_constants(code); if r#async && generator { self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); } else if generator { @@ -1034,7 +1033,7 @@ impl ByteCompiler<'_, '_> { } if generator { - self.emit(Opcode::Generator, &[Operand::U8(self.in_async().into())]); + self.emit(Opcode::Generator, &[Operand::Bool(self.in_async())]); self.emit_opcode(Opcode::Pop); } diff --git a/boa_engine/src/bytecompiler/env.rs b/boa_engine/src/bytecompiler/env.rs index ae2137c54f0..a31be573be2 100644 --- a/boa_engine/src/bytecompiler/env.rs +++ b/boa_engine/src/bytecompiler/env.rs @@ -13,8 +13,9 @@ impl ByteCompiler<'_, '_> { function_scope, )); - let index = self.compile_environments.len() as u32; - self.compile_environments.push(env.clone()); + let index = self.constants.len() as u32; + self.constants + .push(crate::vm::Constant::CompileTimeEnvironment(env.clone())); if function_scope { self.variable_environment = env.clone(); diff --git a/boa_engine/src/bytecompiler/mod.rs b/boa_engine/src/bytecompiler/mod.rs index 58cbba90dcc..71a63509f8b 100644 --- a/boa_engine/src/bytecompiler/mod.rs +++ b/boa_engine/src/bytecompiler/mod.rs @@ -18,10 +18,10 @@ use crate::{ environments::{BindingLocator, BindingLocatorError, CompileTimeEnvironment}, js_string, vm::{ - BindingOpcode, CodeBlock, CodeBlockFlags, GeneratorResumeKind, Handler, Opcode, + BindingOpcode, CodeBlock, CodeBlockFlags, Constant, GeneratorResumeKind, Handler, Opcode, VaryingOperandKind, }, - Context, JsBigInt, JsString, JsValue, + Context, JsBigInt, JsString, }; use boa_ast::{ declaration::{Binding, LexicalDeclaration, VarDeclaration}, @@ -248,21 +248,11 @@ pub struct ByteCompiler<'ctx, 'host> { /// Bytecode pub(crate) bytecode: Vec, - /// Literals - pub(crate) literals: Vec, - - /// Property field names and private name `[[Description]]`s. - pub(crate) names: Vec, + pub(crate) constants: ThinVec, /// Locators for all bindings in the codeblock. pub(crate) bindings: Vec, - /// Functions inside this function - pub(crate) functions: Vec>, - - /// Compile time environments in this function. - pub(crate) compile_environments: Vec>, - /// The current variable environment. pub(crate) variable_environment: Rc, @@ -315,13 +305,10 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { function_name: name, length: 0, bytecode: Vec::default(), - literals: Vec::default(), - names: Vec::default(), + constants: ThinVec::default(), bindings: Vec::default(), - functions: Vec::default(), this_mode: ThisMode::Global, params: FormalParameterList::default(), - compile_environments: Vec::default(), current_open_environments_count: 0, // This starts at two because the first value is the `this` value, then function object. @@ -372,12 +359,12 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { } let value = match literal.clone() { - Literal::String(value) => JsValue::new(value), - Literal::BigInt(value) => JsValue::new(value), + Literal::String(value) => Constant::String(value), + Literal::BigInt(value) => Constant::BigInt(value), }; - let index = self.literals.len() as u32; - self.literals.push(value); + let index = self.constants.len() as u32; + self.constants.push(value); self.literals_map.insert(literal, index); index } @@ -388,8 +375,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { } let string = self.interner().resolve_expect(name.sym()).utf16(); - let index = self.names.len() as u32; - self.names.push(js_string!(string)); + let index = self.constants.len() as u32; + self.constants.push(Constant::String(js_string!(string))); self.names_map.insert(name, index); index } @@ -411,6 +398,14 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { index } + #[inline] + #[must_use] + pub(crate) fn push_function_to_constants(&mut self, function: Gc) -> u32 { + let index = self.constants.len() as u32; + self.constants.push(Constant::Function(function)); + index + } + fn emit_binding(&mut self, opcode: BindingOpcode, name: Identifier) { match opcode { BindingOpcode::Var => { @@ -1250,10 +1245,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { self.context, ); - let index = self.functions.len() as u32; - self.functions.push(code); - - index + self.push_function_to_constants(code) } /// Compiles a function AST Node into bytecode, setting its corresponding binding or @@ -1348,8 +1340,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { self.context, ); - let index = self.functions.len() as u32; - self.functions.push(code); + let index = self.push_function_to_constants(code); if r#async && generator { self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); @@ -1412,8 +1403,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { self.context, ); - let index = self.functions.len() as u32; - self.functions.push(code); + let index = self.push_function_to_constants(code); if r#async && generator { self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); @@ -1535,11 +1525,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> { 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(), + constants: self.constants, bindings: self.bindings.into_boxed_slice(), - functions: self.functions.into_boxed_slice(), - compile_environments: self.compile_environments.into_boxed_slice(), handlers: self.handlers, flags: Cell::new(self.code_block_flags), } diff --git a/boa_engine/src/environments/runtime/mod.rs b/boa_engine/src/environments/runtime/mod.rs index 1c2b284b87f..f873dfd95f0 100644 --- a/boa_engine/src/environments/runtime/mod.rs +++ b/boa_engine/src/environments/runtime/mod.rs @@ -672,7 +672,11 @@ impl Context<'_> { } } - /// Return the environment at the given index. Panics if the index is out of range. + /// Return the environment at the given index. + /// + /// # Panics + /// + /// Panics if the `index` is out of range. pub(crate) fn environment_expect(&self, index: u32) -> &Environment { self.vm .environments diff --git a/boa_engine/src/module/source.rs b/boa_engine/src/module/source.rs index f3e50c4c51f..4365f63aeb2 100644 --- a/boa_engine/src/module/source.rs +++ b/boa_engine/src/module/source.rs @@ -1657,7 +1657,7 @@ impl SourceTextModule { // deferred initialization of function exports for (index, locator, kind) in functions { - let code = codeblock.functions[index as usize].clone(); + let code = codeblock.constant_function(index as usize); let function = if kind.is_generator() { create_generator_function_object(code, kind.is_async(), None, context) diff --git a/boa_engine/src/object/internal_methods/function.rs b/boa_engine/src/object/internal_methods/function.rs index 2d65f009d31..fcc21fcb85f 100644 --- a/boa_engine/src/object/internal_methods/function.rs +++ b/boa_engine/src/object/internal_methods/function.rs @@ -98,7 +98,7 @@ pub(crate) fn function_call( let index = context .vm .environments - .push_lexical(code.compile_environments[last_env].clone()); + .push_lexical(code.constant_compile_time_environment(last_env)); context .vm .environments @@ -107,7 +107,7 @@ pub(crate) fn function_call( } context.vm.environments.push_function( - code.compile_environments[last_env].clone(), + code.constant_compile_time_environment(last_env), FunctionSlots::new(this, function_object.clone(), None), ); @@ -116,7 +116,7 @@ pub(crate) fn function_call( context .vm .environments - .push_lexical(code.compile_environments[last_env].clone()); + .push_lexical(code.constant_compile_time_environment(last_env)); } // Taken from: `FunctionDeclarationInstantiation` abstract function. @@ -226,7 +226,7 @@ fn function_construct( let index = context .vm .environments - .push_lexical(code.compile_environments[last_env].clone()); + .push_lexical(code.constant_compile_time_environment(last_env)); context .vm .environments @@ -235,7 +235,7 @@ fn function_construct( } context.vm.environments.push_function( - code.compile_environments[last_env].clone(), + code.constant_compile_time_environment(last_env), FunctionSlots::new( this.clone().map_or(ThisBindingStatus::Uninitialized, |o| { ThisBindingStatus::Initialized(o.into()) @@ -255,7 +255,7 @@ fn function_construct( context .vm .environments - .push_lexical(code.compile_environments[last_env].clone()); + .push_lexical(code.constant_compile_time_environment(last_env)); } // Taken from: `FunctionDeclarationInstantiation` abstract function. diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index 0cef1c11c52..3ea3cbc0979 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -8,7 +8,7 @@ use crate::{ object::{JsObject, ObjectData, PROTOTYPE}, property::PropertyDescriptor, string::utf16, - Context, JsString, JsValue, + Context, JsBigInt, JsString, JsValue, }; use bitflags::bitflags; use boa_ast::function::FormalParameterList; @@ -108,6 +108,21 @@ impl Handler { } } +#[derive(Clone, Debug, Trace, Finalize)] +pub(crate) enum Constant { + /// Property field names and private names `[[description]]`s. + String(JsString), + Function(Gc), + BigInt(#[unsafe_ignore_trace] JsBigInt), + + /// Compile time environments in this function. + /// + // Safety: Nothing in CompileTimeEnvironment needs tracing, so this is safe. + // + // TODO(#3034): Maybe changing this to Gc after garbage collection would be better than Rc. + CompileTimeEnvironment(#[unsafe_ignore_trace] Rc), +} + /// The internal representation of a JavaScript function. /// /// A `CodeBlock` is generated for each function compiled by the @@ -135,29 +150,15 @@ pub struct CodeBlock { /// Bytecode pub(crate) bytecode: Box<[u8]>, - /// Literals - pub(crate) literals: Box<[JsValue]>, - - /// Property field names and private names `[[description]]`s. - pub(crate) names: Box<[JsString]>, + pub(crate) constants: ThinVec, /// Locators for all bindings in the codeblock. #[unsafe_ignore_trace] pub(crate) bindings: Box<[BindingLocator]>, - /// Functions inside this function - pub(crate) functions: Box<[Gc]>, - /// Exception [`Handler`]s. #[unsafe_ignore_trace] pub(crate) handlers: ThinVec, - - /// Compile time environments in this function. - // Safety: Nothing in CompileTimeEnvironment needs tracing, so this is safe. - // - // TODO(#3034): Maybe changing this to Gc after garbage collection would be better than Rc. - #[unsafe_ignore_trace] - pub(crate) compile_environments: Box<[Rc]>, } /// ---- `CodeBlock` public API ---- @@ -169,17 +170,14 @@ impl CodeBlock { flags.set(CodeBlockFlags::STRICT, strict); Self { bytecode: Box::default(), - literals: Box::default(), - names: Box::default(), + constants: ThinVec::default(), bindings: Box::default(), - functions: Box::default(), name, flags: Cell::new(flags), length, this_mode: ThisMode::Global, params: FormalParameterList::default(), handlers: ThinVec::default(), - compile_environments: Box::default(), } } @@ -252,6 +250,51 @@ impl CodeBlock { .rev() .find(|(_, handler)| handler.contains(pc)) } + + /// Get the [`JsString`] constant from the [`CodeBlock`]. + /// + /// # Panics + /// + /// If the type of the [`Constant`] is not [`Constant::String`]. + /// Or `index` is greater or equal to length of `constants`. + pub(crate) fn constant_string(&self, index: usize) -> JsString { + if let Some(Constant::String(value)) = self.constants.get(index) { + return value.clone(); + } + + panic!("expected string constant at index {index}") + } + + /// Get the function ([`Gc`]) constant from the [`CodeBlock`]. + /// + /// # Panics + /// + /// If the type of the [`Constant`] is not [`Constant::Function`]. + /// Or `index` is greater or equal to length of `constants`. + pub(crate) fn constant_function(&self, index: usize) -> Gc { + if let Some(Constant::Function(value)) = self.constants.get(index) { + return value.clone(); + } + + panic!("expected function constant at index {index}") + } + + /// Get the [`CompileTimeEnvironment`] constant from the [`CodeBlock`]. + /// + /// # Panics + /// + /// If the type of the [`Constant`] is not [`Constant::CompileTimeEnvironment`]. + /// Or `index` is greater or equal to length of `constants`. + pub(crate) fn constant_compile_time_environment( + &self, + index: usize, + ) -> Rc { + if let Some(Constant::CompileTimeEnvironment(value)) = self.constants.get(index) { + return value.clone(); + } + + panic!("expected compile time environment constant at index {index}") + } } /// ---- `CodeBlock` private API ---- @@ -325,11 +368,11 @@ impl CodeBlock { pattern_index: source_index, flags_index: flag_index, } => { - let pattern = self.names[source_index.value() as usize] - .clone() + let pattern = self + .constant_string(source_index.value() as usize) .to_std_string_escaped(); - let flags = self.names[flag_index.value() as usize] - .clone() + let flags = self + .constant_string(flag_index.value() as usize) .to_std_string_escaped(); format!("/{pattern}/{flags}") } @@ -383,8 +426,8 @@ impl CodeBlock { let index = index.value() as usize; format!( "{index:04}: '{}' (length: {}), method: {method}", - self.functions[index].name().to_std_string_escaped(), - self.functions[index].length + self.constant_function(index).name().to_std_string_escaped(), + self.constant_function(index).length ) } Instruction::GetArrowFunction { index } @@ -394,8 +437,8 @@ impl CodeBlock { let index = index.value() as usize; format!( "{index:04}: '{}' (length: {})", - self.functions[index].name().to_std_string_escaped(), - self.functions[index].length + self.constant_function(index).name().to_std_string_escaped(), + self.constant_function(index).length ) } Instruction::DefVar { index } @@ -440,7 +483,8 @@ impl CodeBlock { format!( "{:04}: '{}'", index.value(), - self.names[index.value() as usize].to_std_string_escaped(), + self.constant_string(index.value() as usize) + .to_std_string_escaped(), ) } Instruction::PushPrivateEnvironment { name_indices } => { @@ -693,17 +737,34 @@ impl ToInternedString for CodeBlock { count += 1; } - f.push_str("\nLiterals:\n"); + f.push_str("\nConstants:"); - if self.literals.is_empty() { - f.push_str(" \n"); + if self.constants.is_empty() { + f.push_str(" \n"); } else { - for (i, value) in self.literals.iter().enumerate() { - f.push_str(&format!( - " {i:04}: <{}> {}\n", - value.type_of(), - value.display() - )); + f.push('\n'); + for (i, value) in self.constants.iter().enumerate() { + f.push_str(&format!(" {i:04}: ")); + let value = match value { + Constant::String(v) => { + format!("[STRING] \"{}\"", v.to_std_string_escaped().escape_debug()) + } + Constant::BigInt(v) => format!("[BIGINT] {v}n"), + Constant::Function(code) => format!( + "[FUNCTION] name: '{}' (length: {})\n", + code.name().to_std_string_escaped(), + code.length + ), + Constant::CompileTimeEnvironment(v) => { + format!( + "[ENVIRONMENT] index: {}, bindings: {}", + v.environment_index(), + v.num_bindings() + ) + } + }; + f.push_str(&value); + f.push('\n'); } } @@ -719,19 +780,6 @@ impl ToInternedString for CodeBlock { } } - f.push_str("\nFunctions:\n"); - if self.functions.is_empty() { - f.push_str(" \n"); - } else { - for (i, code) in self.functions.iter().enumerate() { - f.push_str(&format!( - " {i:04}: name: '{}' (length: {})\n", - code.name().to_std_string_escaped(), - code.length - )); - } - } - f.push_str("\nHandlers:\n"); if self.handlers.is_empty() { f.push_str(" \n"); diff --git a/boa_engine/src/vm/flowgraph/mod.rs b/boa_engine/src/vm/flowgraph/mod.rs index e5495cafed0..f81ca59353b 100644 --- a/boa_engine/src/vm/flowgraph/mod.rs +++ b/boa_engine/src/vm/flowgraph/mod.rs @@ -14,7 +14,7 @@ pub use edge::*; pub use graph::*; pub use node::*; -use super::{Instruction, InstructionIterator}; +use super::{Constant, Instruction, InstructionIterator}; impl CodeBlock { /// Output the [`CodeBlock`] VM instructions into a [`Graph`]. @@ -526,9 +526,11 @@ impl CodeBlock { } } - for function in self.functions.as_ref() { - let subgraph = graph.subgraph(String::new()); - function.to_graph(interner, subgraph); + for constant in &self.constants { + if let Constant::Function(function) = constant { + let subgraph = graph.subgraph(String::new()); + function.to_graph(interner, subgraph); + } } } } diff --git a/boa_engine/src/vm/mod.rs b/boa_engine/src/vm/mod.rs index 369cda869d7..883f6eae0e6 100644 --- a/boa_engine/src/vm/mod.rs +++ b/boa_engine/src/vm/mod.rs @@ -41,7 +41,7 @@ pub(crate) use { call_frame::CallFrameFlags, code_block::{ create_function_object, create_function_object_fast, create_generator_function_object, - CodeBlockFlags, Handler, + CodeBlockFlags, Constant, Handler, }, completion_record::CompletionRecord, opcode::BindingOpcode, diff --git a/boa_engine/src/vm/opcode/binary_ops/mod.rs b/boa_engine/src/vm/opcode/binary_ops/mod.rs index a50f200698e..2c801064217 100644 --- a/boa_engine/src/vm/opcode/binary_ops/mod.rs +++ b/boa_engine/src/vm/opcode/binary_ops/mod.rs @@ -111,7 +111,7 @@ pub(crate) struct InPrivate; impl InPrivate { fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let rhs = context.vm.pop(); let Some(rhs) = rhs.as_object() else { diff --git a/boa_engine/src/vm/opcode/control_flow/throw.rs b/boa_engine/src/vm/opcode/control_flow/throw.rs index c85c6e4ae68..5ea28b84249 100644 --- a/boa_engine/src/vm/opcode/control_flow/throw.rs +++ b/boa_engine/src/vm/opcode/control_flow/throw.rs @@ -123,10 +123,7 @@ pub(crate) struct ThrowNewTypeError; impl ThrowNewTypeError { fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let msg = context.vm.frame().code_block.literals[index] - .as_string() - .expect("throw message must be a string") - .clone(); + let msg = context.vm.frame().code_block().constant_string(index); let msg = msg .to_std_string() .expect("throw message must be an ASCII string"); diff --git a/boa_engine/src/vm/opcode/define/class/getter.rs b/boa_engine/src/vm/opcode/define/class/getter.rs index 6ebe6f83f5b..5b9d6ca4706 100644 --- a/boa_engine/src/vm/opcode/define/class/getter.rs +++ b/boa_engine/src/vm/opcode/define/class/getter.rs @@ -17,7 +17,12 @@ impl DefineClassStaticGetterByName { let function = context.vm.pop(); let class = context.vm.pop(); let class = class.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index].clone().into(); + let key = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); { let function_object = function .as_object() @@ -81,7 +86,12 @@ impl DefineClassGetterByName { let function = context.vm.pop(); let class_proto = context.vm.pop(); let class_proto = class_proto.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index].clone().into(); + let key = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); { let function_object = function .as_object() diff --git a/boa_engine/src/vm/opcode/define/class/method.rs b/boa_engine/src/vm/opcode/define/class/method.rs index a0539617106..bc6e8b53e41 100644 --- a/boa_engine/src/vm/opcode/define/class/method.rs +++ b/boa_engine/src/vm/opcode/define/class/method.rs @@ -17,7 +17,12 @@ impl DefineClassStaticMethodByName { let function = context.vm.pop(); let class = context.vm.pop(); let class = class.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index].clone().into(); + let key = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); { let function_object = function .as_object() @@ -77,7 +82,12 @@ impl DefineClassMethodByName { let function = context.vm.pop(); let class_proto = context.vm.pop(); let class_proto = class_proto.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index].clone().into(); + let key = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); { let function_object = function .as_object() diff --git a/boa_engine/src/vm/opcode/define/class/setter.rs b/boa_engine/src/vm/opcode/define/class/setter.rs index 165c85d80c8..73cfa2740ea 100644 --- a/boa_engine/src/vm/opcode/define/class/setter.rs +++ b/boa_engine/src/vm/opcode/define/class/setter.rs @@ -17,7 +17,12 @@ impl DefineClassStaticSetterByName { let function = context.vm.pop(); let class = context.vm.pop(); let class = class.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index].clone().into(); + let key = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); { let function_object = function .as_object() @@ -82,7 +87,12 @@ impl DefineClassSetterByName { let function = context.vm.pop(); let class_proto = context.vm.pop(); let class_proto = class_proto.as_object().expect("class must be object"); - let key = context.vm.frame().code_block.names[index].clone().into(); + let key = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); { let function_object = function .as_object() diff --git a/boa_engine/src/vm/opcode/define/own_property.rs b/boa_engine/src/vm/opcode/define/own_property.rs index 0ecbe226da1..82dde0f9961 100644 --- a/boa_engine/src/vm/opcode/define/own_property.rs +++ b/boa_engine/src/vm/opcode/define/own_property.rs @@ -20,7 +20,7 @@ impl DefineOwnPropertyByName { } else { object.to_object(context)? }; - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); object.__define_own_property__( &name.into(), PropertyDescriptor::builder() diff --git a/boa_engine/src/vm/opcode/delete/mod.rs b/boa_engine/src/vm/opcode/delete/mod.rs index 0f50cf50206..2068ea8798d 100644 --- a/boa_engine/src/vm/opcode/delete/mod.rs +++ b/boa_engine/src/vm/opcode/delete/mod.rs @@ -15,7 +15,12 @@ impl DeletePropertyByName { fn operation(context: &mut Context<'_>, index: usize) -> JsResult { let value = context.vm.pop(); let object = value.to_object(context)?; - let key = context.vm.frame().code_block.names[index].clone().into(); + let key = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); let result = object.__delete__(&key, context)?; if !result && context.vm.frame().code_block.strict() { return Err(JsNativeError::typ() diff --git a/boa_engine/src/vm/opcode/get/function.rs b/boa_engine/src/vm/opcode/get/function.rs index 2f96412d52b..2c4b5208dda 100644 --- a/boa_engine/src/vm/opcode/get/function.rs +++ b/boa_engine/src/vm/opcode/get/function.rs @@ -13,7 +13,7 @@ pub(crate) struct GetArrowFunction; impl GetArrowFunction { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let code = context.vm.frame().code_block.functions[index].clone(); + let code = context.vm.frame().code_block().constant_function(index); let function = create_function_object_fast(code, false, true, false, context); context.vm.push(function); Ok(CompletionType::Normal) @@ -51,7 +51,7 @@ pub(crate) struct GetAsyncArrowFunction; impl GetAsyncArrowFunction { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let code = context.vm.frame().code_block.functions[index].clone(); + let code = context.vm.frame().code_block().constant_function(index); let function = create_function_object_fast(code, true, true, false, context); context.vm.push(function); Ok(CompletionType::Normal) @@ -93,7 +93,7 @@ impl GetFunction { index: usize, method: bool, ) -> JsResult { - let code = context.vm.frame().code_block.functions[index].clone(); + let code = context.vm.frame().code_block().constant_function(index); let function = create_function_object_fast(code, false, false, method, context); context.vm.push(function); Ok(CompletionType::Normal) @@ -138,7 +138,7 @@ impl GetFunctionAsync { index: usize, method: bool, ) -> JsResult { - let code = context.vm.frame().code_block.functions[index].clone(); + let code = context.vm.frame().code_block().constant_function(index); let function = create_function_object_fast(code, true, false, method, context); context.vm.push(function); Ok(CompletionType::Normal) diff --git a/boa_engine/src/vm/opcode/get/generator.rs b/boa_engine/src/vm/opcode/get/generator.rs index ab7689ff6b9..1ecc72d3f7b 100644 --- a/boa_engine/src/vm/opcode/get/generator.rs +++ b/boa_engine/src/vm/opcode/get/generator.rs @@ -13,7 +13,7 @@ pub(crate) struct GetGenerator; impl GetGenerator { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let code = context.vm.frame().code_block.functions[index].clone(); + let code = context.vm.frame().code_block().constant_function(index); let function = create_generator_function_object(code, false, None, context); context.vm.push(function); Ok(CompletionType::Normal) @@ -51,7 +51,7 @@ pub(crate) struct GetGeneratorAsync; impl GetGeneratorAsync { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let code = context.vm.frame().code_block.functions[index].clone(); + let code = context.vm.frame().code_block().constant_function(index); let function = create_generator_function_object(code, true, None, context); context.vm.push(function); Ok(CompletionType::Normal) diff --git a/boa_engine/src/vm/opcode/get/private.rs b/boa_engine/src/vm/opcode/get/private.rs index eb260f33b5d..269eee1d21d 100644 --- a/boa_engine/src/vm/opcode/get/private.rs +++ b/boa_engine/src/vm/opcode/get/private.rs @@ -12,7 +12,7 @@ pub(crate) struct GetPrivateField; impl GetPrivateField { fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let value = context.vm.pop(); let base_obj = value.to_object(context)?; diff --git a/boa_engine/src/vm/opcode/get/property.rs b/boa_engine/src/vm/opcode/get/property.rs index bf425b29673..fe077618ec6 100644 --- a/boa_engine/src/vm/opcode/get/property.rs +++ b/boa_engine/src/vm/opcode/get/property.rs @@ -21,7 +21,12 @@ impl GetPropertyByName { value.to_object(context)? }; - let key = context.vm.frame().code_block.names[index].clone().into(); + let key = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); let result = object.__get__(&key, receiver, context)?; context.vm.push(result); diff --git a/boa_engine/src/vm/opcode/push/class/field.rs b/boa_engine/src/vm/opcode/push/class/field.rs index 3db65fd9b85..3e6ce9f8295 100644 --- a/boa_engine/src/vm/opcode/push/class/field.rs +++ b/boa_engine/src/vm/opcode/push/class/field.rs @@ -55,7 +55,7 @@ pub(crate) struct PushClassFieldPrivate; impl PushClassFieldPrivate { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let field_function_value = context.vm.pop(); let class_value = context.vm.pop(); diff --git a/boa_engine/src/vm/opcode/push/class/private.rs b/boa_engine/src/vm/opcode/push/class/private.rs index cb41a2c1096..727e8118886 100644 --- a/boa_engine/src/vm/opcode/push/class/private.rs +++ b/boa_engine/src/vm/opcode/push/class/private.rs @@ -17,7 +17,7 @@ pub(crate) struct PushClassPrivateMethod; impl PushClassPrivateMethod { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let method = context.vm.pop(); let method_object = method.as_callable().expect("method must be callable"); @@ -79,7 +79,7 @@ pub(crate) struct PushClassPrivateGetter; impl PushClassPrivateGetter { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let getter = context.vm.pop(); let getter_object = getter.as_callable().expect("getter must be callable"); let class = context.vm.pop(); @@ -132,7 +132,7 @@ pub(crate) struct PushClassPrivateSetter; impl PushClassPrivateSetter { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let setter = context.vm.pop(); let setter_object = setter.as_callable().expect("getter must be callable"); let class = context.vm.pop(); diff --git a/boa_engine/src/vm/opcode/push/environment.rs b/boa_engine/src/vm/opcode/push/environment.rs index e903372400c..6ddef4dc56e 100644 --- a/boa_engine/src/vm/opcode/push/environment.rs +++ b/boa_engine/src/vm/opcode/push/environment.rs @@ -18,8 +18,11 @@ impl PushDeclarativeEnvironment { context: &mut Context<'_>, compile_environments_index: usize, ) -> JsResult { - let compile_environment = - context.vm.frame().code_block.compile_environments[compile_environments_index].clone(); + let compile_environment = context + .vm + .frame() + .code_block() + .constant_compile_time_environment(compile_environments_index); context.vm.environments.push_lexical(compile_environment); Ok(CompletionType::Normal) } @@ -87,7 +90,11 @@ impl Operation for PushPrivateEnvironment { let mut names = Vec::with_capacity(count as usize); for _ in 0..count { let index = context.vm.read::(); - let name = context.vm.frame().code_block.names[index as usize].clone(); + let name = context + .vm + .frame() + .code_block() + .constant_string(index as usize); names.push(name); } diff --git a/boa_engine/src/vm/opcode/push/literal.rs b/boa_engine/src/vm/opcode/push/literal.rs index f684c7223d6..db192274247 100644 --- a/boa_engine/src/vm/opcode/push/literal.rs +++ b/boa_engine/src/vm/opcode/push/literal.rs @@ -1,7 +1,7 @@ use crate::{ object::JsRegExp, - vm::{opcode::Operation, CompletionType}, - Context, JsResult, + vm::{opcode::Operation, CompletionType, Constant}, + Context, JsResult, JsValue, }; /// `PushLiteral` implements the Opcode Operation for `Opcode::PushLiteral` @@ -14,7 +14,12 @@ pub(crate) struct PushLiteral; impl PushLiteral { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let value = context.vm.frame().code_block.literals[index].clone(); + let constant = &context.vm.frame().code_block().constants[index]; + let value: JsValue = match constant { + Constant::BigInt(v) => v.clone().into(), + Constant::String(v) => v.clone().into(), + _ => unreachable!("constant should be a string or bigint"), + }; context.vm.push(value); Ok(CompletionType::Normal) } @@ -54,8 +59,12 @@ impl PushRegExp { pattern_index: usize, flags_index: usize, ) -> JsResult { - let pattern = context.vm.frame().code_block.names[pattern_index].clone(); - let flags = context.vm.frame().code_block.names[flags_index].clone(); + let pattern = context + .vm + .frame() + .code_block() + .constant_string(pattern_index); + let flags = context.vm.frame().code_block().constant_string(flags_index); let regexp = JsRegExp::new(pattern, flags, context)?; context.vm.push(regexp); diff --git a/boa_engine/src/vm/opcode/set/name.rs b/boa_engine/src/vm/opcode/set/name.rs index fe027bc997c..dd26674e59c 100644 --- a/boa_engine/src/vm/opcode/set/name.rs +++ b/boa_engine/src/vm/opcode/set/name.rs @@ -13,7 +13,7 @@ pub(crate) struct ThrowMutateImmutable; impl ThrowMutateImmutable { fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = &context.vm.frame().code_block.names[index]; + let name = context.vm.frame().code_block().constant_string(index); Err(JsNativeError::typ() .with_message(format!( diff --git a/boa_engine/src/vm/opcode/set/private.rs b/boa_engine/src/vm/opcode/set/private.rs index 3916bc67f36..287ad0d2750 100644 --- a/boa_engine/src/vm/opcode/set/private.rs +++ b/boa_engine/src/vm/opcode/set/private.rs @@ -16,7 +16,7 @@ pub(crate) struct SetPrivateField; impl SetPrivateField { fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let value = context.vm.pop(); let object = context.vm.pop(); let base_obj = object.to_object(context)?; @@ -64,7 +64,7 @@ pub(crate) struct DefinePrivateField; impl DefinePrivateField { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let value = context.vm.pop(); let object = context.vm.pop(); let object = object @@ -110,7 +110,7 @@ pub(crate) struct SetPrivateMethod; impl SetPrivateMethod { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let value = context.vm.pop(); let value = value.as_callable().expect("method must be callable"); @@ -170,7 +170,7 @@ pub(crate) struct SetPrivateSetter; impl SetPrivateSetter { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let value = context.vm.pop(); let value = value.as_callable().expect("setter must be callable"); let object = context.vm.pop(); @@ -221,7 +221,7 @@ pub(crate) struct SetPrivateGetter; impl SetPrivateGetter { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context<'_>, index: usize) -> JsResult { - let name = context.vm.frame().code_block.names[index].clone(); + let name = context.vm.frame().code_block().constant_string(index); let value = context.vm.pop(); let value = value.as_callable().expect("getter must be callable"); let object = context.vm.pop(); diff --git a/boa_engine/src/vm/opcode/set/property.rs b/boa_engine/src/vm/opcode/set/property.rs index 93b8a8c6d40..a07fb841da3 100644 --- a/boa_engine/src/vm/opcode/set/property.rs +++ b/boa_engine/src/vm/opcode/set/property.rs @@ -25,7 +25,12 @@ impl SetPropertyByName { object.to_object(context)? }; - let name: PropertyKey = context.vm.frame().code_block.names[index].clone().into(); + let name: PropertyKey = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); let succeeded = object.__set__(name.clone(), value.clone(), receiver, context)?; if !succeeded && context.vm.frame().code_block.strict() { @@ -176,7 +181,12 @@ impl SetPropertyGetterByName { let value = context.vm.pop(); let object = context.vm.pop(); let object = object.to_object(context)?; - let name = context.vm.frame().code_block.names[index].clone().into(); + let name = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); let set = object .__get_own_property__(&name, context)? .as_ref() @@ -266,7 +276,12 @@ impl SetPropertySetterByName { let value = context.vm.pop(); let object = context.vm.pop(); let object = object.to_object(context)?; - let name = context.vm.frame().code_block.names[index].clone().into(); + let name = context + .vm + .frame() + .code_block() + .constant_string(index) + .into(); let get = object .__get_own_property__(&name, context)? .as_ref()