Browse Source

Merge `CodeBlock` constant pools (#3413)

* Merge `CodeBlock` constant pools

* Apply review
pull/3425/head
Haled Odat 1 year ago committed by GitHub
parent
commit
fee4048b4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      boa_engine/src/bytecompiler/class.rs
  2. 9
      boa_engine/src/bytecompiler/declarations.rs
  3. 5
      boa_engine/src/bytecompiler/env.rs
  4. 57
      boa_engine/src/bytecompiler/mod.rs
  5. 6
      boa_engine/src/environments/runtime/mod.rs
  6. 2
      boa_engine/src/module/source.rs
  7. 12
      boa_engine/src/object/internal_methods/function.rs
  8. 148
      boa_engine/src/vm/code_block.rs
  9. 6
      boa_engine/src/vm/flowgraph/mod.rs
  10. 2
      boa_engine/src/vm/mod.rs
  11. 2
      boa_engine/src/vm/opcode/binary_ops/mod.rs
  12. 5
      boa_engine/src/vm/opcode/control_flow/throw.rs
  13. 14
      boa_engine/src/vm/opcode/define/class/getter.rs
  14. 14
      boa_engine/src/vm/opcode/define/class/method.rs
  15. 14
      boa_engine/src/vm/opcode/define/class/setter.rs
  16. 2
      boa_engine/src/vm/opcode/define/own_property.rs
  17. 7
      boa_engine/src/vm/opcode/delete/mod.rs
  18. 8
      boa_engine/src/vm/opcode/get/function.rs
  19. 4
      boa_engine/src/vm/opcode/get/generator.rs
  20. 2
      boa_engine/src/vm/opcode/get/private.rs
  21. 7
      boa_engine/src/vm/opcode/get/property.rs
  22. 2
      boa_engine/src/vm/opcode/push/class/field.rs
  23. 6
      boa_engine/src/vm/opcode/push/class/private.rs
  24. 13
      boa_engine/src/vm/opcode/push/environment.rs
  25. 19
      boa_engine/src/vm/opcode/push/literal.rs
  26. 2
      boa_engine/src/vm/opcode/set/name.rs
  27. 10
      boa_engine/src/vm/opcode/set/private.rs
  28. 21
      boa_engine/src/vm/opcode/set/property.rs

21
boa_engine/src/bytecompiler/class.rs

@ -81,8 +81,7 @@ impl ByteCompiler<'_, '_> {
compiler.emit_opcode(Opcode::SetReturnValue); compiler.emit_opcode(Opcode::SetReturnValue);
let code = Gc::new(compiler.finish()); let code = Gc::new(compiler.finish());
let index = self.functions.len() as u32; let index = self.push_function_to_constants(code);
self.functions.push(code);
self.emit( self.emit(
Opcode::GetFunction, Opcode::GetFunction,
&[Operand::Varying(index), Operand::Bool(false)], &[Operand::Varying(index), Operand::Bool(false)],
@ -294,10 +293,8 @@ impl ByteCompiler<'_, '_> {
field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER;
let code = field_compiler.finish(); let code = Gc::new(field_compiler.finish());
let code = Gc::new(code); let index = self.push_function_to_constants(code);
let index = self.functions.len() as u32;
self.functions.push(code);
self.emit( self.emit(
Opcode::GetFunction, Opcode::GetFunction,
&[Operand::Varying(index), Operand::Bool(false)], &[Operand::Varying(index), Operand::Bool(false)],
@ -325,10 +322,8 @@ impl ByteCompiler<'_, '_> {
field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER;
let code = field_compiler.finish(); let code = Gc::new(field_compiler.finish());
let code = Gc::new(code); let index = self.push_function_to_constants(code);
let index = self.functions.len() as u32;
self.functions.push(code);
self.emit( self.emit(
Opcode::GetFunction, Opcode::GetFunction,
&[Operand::Varying(index), Operand::Bool(false)], &[Operand::Varying(index), Operand::Bool(false)],
@ -552,8 +547,7 @@ impl ByteCompiler<'_, '_> {
match element { match element {
StaticElement::StaticBlock(code) => { StaticElement::StaticBlock(code) => {
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
let index = self.functions.len() as u32; let index = self.push_function_to_constants(code);
self.functions.push(code);
self.emit( self.emit(
Opcode::GetFunction, Opcode::GetFunction,
&[Operand::Varying(index), Operand::Bool(false)], &[Operand::Varying(index), Operand::Bool(false)],
@ -565,8 +559,7 @@ impl ByteCompiler<'_, '_> {
StaticElement::StaticField((code, name_index)) => { StaticElement::StaticField((code, name_index)) => {
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup);
let index = self.functions.len() as u32; let index = self.push_function_to_constants(code);
self.functions.push(code);
self.emit( self.emit(
Opcode::GetFunction, Opcode::GetFunction,
&[Operand::Varying(index), Operand::Bool(false)], &[Operand::Varying(index), Operand::Bool(false)],

9
boa_engine/src/bytecompiler/declarations.rs

@ -282,7 +282,7 @@ impl ByteCompiler<'_, '_> {
); );
// Ensures global functions are printed when generating the global flowgraph. // 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. // b. Let fo be InstantiateFunctionObject of f with arguments env and privateEnv.
let function = if generator { let function = if generator {
@ -733,7 +733,7 @@ impl ByteCompiler<'_, '_> {
// c. If varEnv is a Global Environment Record, then // c. If varEnv is a Global Environment Record, then
if var_env.is_global() { if var_env.is_global() {
// Ensures global functions are printed when generating the global flowgraph. // 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. // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv.
let function = if generator { let function = if generator {
@ -749,8 +749,7 @@ impl ByteCompiler<'_, '_> {
// d. Else, // d. Else,
else { else {
// b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv. // b. Let fo be InstantiateFunctionObject of f with arguments lexEnv and privateEnv.
let index = self.functions.len() as u32; let index = self.push_function_to_constants(code);
self.functions.push(code);
if r#async && generator { if r#async && generator {
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
} else if generator { } else if generator {
@ -1034,7 +1033,7 @@ impl ByteCompiler<'_, '_> {
} }
if generator { 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); self.emit_opcode(Opcode::Pop);
} }

5
boa_engine/src/bytecompiler/env.rs

@ -13,8 +13,9 @@ impl ByteCompiler<'_, '_> {
function_scope, function_scope,
)); ));
let index = self.compile_environments.len() as u32; let index = self.constants.len() as u32;
self.compile_environments.push(env.clone()); self.constants
.push(crate::vm::Constant::CompileTimeEnvironment(env.clone()));
if function_scope { if function_scope {
self.variable_environment = env.clone(); self.variable_environment = env.clone();

57
boa_engine/src/bytecompiler/mod.rs

@ -18,10 +18,10 @@ use crate::{
environments::{BindingLocator, BindingLocatorError, CompileTimeEnvironment}, environments::{BindingLocator, BindingLocatorError, CompileTimeEnvironment},
js_string, js_string,
vm::{ vm::{
BindingOpcode, CodeBlock, CodeBlockFlags, GeneratorResumeKind, Handler, Opcode, BindingOpcode, CodeBlock, CodeBlockFlags, Constant, GeneratorResumeKind, Handler, Opcode,
VaryingOperandKind, VaryingOperandKind,
}, },
Context, JsBigInt, JsString, JsValue, Context, JsBigInt, JsString,
}; };
use boa_ast::{ use boa_ast::{
declaration::{Binding, LexicalDeclaration, VarDeclaration}, declaration::{Binding, LexicalDeclaration, VarDeclaration},
@ -248,21 +248,11 @@ pub struct ByteCompiler<'ctx, 'host> {
/// Bytecode /// Bytecode
pub(crate) bytecode: Vec<u8>, pub(crate) bytecode: Vec<u8>,
/// Literals pub(crate) constants: ThinVec<Constant>,
pub(crate) literals: Vec<JsValue>,
/// Property field names and private name `[[Description]]`s.
pub(crate) names: Vec<JsString>,
/// Locators for all bindings in the codeblock. /// Locators for all bindings in the codeblock.
pub(crate) bindings: Vec<BindingLocator>, pub(crate) bindings: Vec<BindingLocator>,
/// Functions inside this function
pub(crate) functions: Vec<Gc<CodeBlock>>,
/// Compile time environments in this function.
pub(crate) compile_environments: Vec<Rc<CompileTimeEnvironment>>,
/// The current variable environment. /// The current variable environment.
pub(crate) variable_environment: Rc<CompileTimeEnvironment>, pub(crate) variable_environment: Rc<CompileTimeEnvironment>,
@ -315,13 +305,10 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
function_name: name, function_name: name,
length: 0, length: 0,
bytecode: Vec::default(), bytecode: Vec::default(),
literals: Vec::default(), constants: ThinVec::default(),
names: Vec::default(),
bindings: Vec::default(), bindings: Vec::default(),
functions: Vec::default(),
this_mode: ThisMode::Global, this_mode: ThisMode::Global,
params: FormalParameterList::default(), params: FormalParameterList::default(),
compile_environments: Vec::default(),
current_open_environments_count: 0, current_open_environments_count: 0,
// This starts at two because the first value is the `this` value, then function object. // 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() { let value = match literal.clone() {
Literal::String(value) => JsValue::new(value), Literal::String(value) => Constant::String(value),
Literal::BigInt(value) => JsValue::new(value), Literal::BigInt(value) => Constant::BigInt(value),
}; };
let index = self.literals.len() as u32; let index = self.constants.len() as u32;
self.literals.push(value); self.constants.push(value);
self.literals_map.insert(literal, index); self.literals_map.insert(literal, index);
index index
} }
@ -388,8 +375,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
} }
let string = self.interner().resolve_expect(name.sym()).utf16(); let string = self.interner().resolve_expect(name.sym()).utf16();
let index = self.names.len() as u32; let index = self.constants.len() as u32;
self.names.push(js_string!(string)); self.constants.push(Constant::String(js_string!(string)));
self.names_map.insert(name, index); self.names_map.insert(name, index);
index index
} }
@ -411,6 +398,14 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
index index
} }
#[inline]
#[must_use]
pub(crate) fn push_function_to_constants(&mut self, function: Gc<CodeBlock>) -> u32 {
let index = self.constants.len() as u32;
self.constants.push(Constant::Function(function));
index
}
fn emit_binding(&mut self, opcode: BindingOpcode, name: Identifier) { fn emit_binding(&mut self, opcode: BindingOpcode, name: Identifier) {
match opcode { match opcode {
BindingOpcode::Var => { BindingOpcode::Var => {
@ -1250,10 +1245,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.context, self.context,
); );
let index = self.functions.len() as u32; self.push_function_to_constants(code)
self.functions.push(code);
index
} }
/// Compiles a function AST Node into bytecode, setting its corresponding binding or /// Compiles a function AST Node into bytecode, setting its corresponding binding or
@ -1348,8 +1340,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.context, self.context,
); );
let index = self.functions.len() as u32; let index = self.push_function_to_constants(code);
self.functions.push(code);
if r#async && generator { if r#async && generator {
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
@ -1412,8 +1403,7 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
self.context, self.context,
); );
let index = self.functions.len() as u32; let index = self.push_function_to_constants(code);
self.functions.push(code);
if r#async && generator { if r#async && generator {
self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index); self.emit_with_varying_operand(Opcode::GetGeneratorAsync, index);
@ -1535,11 +1525,8 @@ impl<'ctx, 'host> ByteCompiler<'ctx, 'host> {
this_mode: self.this_mode, this_mode: self.this_mode,
params: self.params, params: self.params,
bytecode: self.bytecode.into_boxed_slice(), bytecode: self.bytecode.into_boxed_slice(),
literals: self.literals.into_boxed_slice(), constants: self.constants,
names: self.names.into_boxed_slice(),
bindings: self.bindings.into_boxed_slice(), bindings: self.bindings.into_boxed_slice(),
functions: self.functions.into_boxed_slice(),
compile_environments: self.compile_environments.into_boxed_slice(),
handlers: self.handlers, handlers: self.handlers,
flags: Cell::new(self.code_block_flags), flags: Cell::new(self.code_block_flags),
} }

6
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 { pub(crate) fn environment_expect(&self, index: u32) -> &Environment {
self.vm self.vm
.environments .environments

2
boa_engine/src/module/source.rs

@ -1657,7 +1657,7 @@ impl SourceTextModule {
// deferred initialization of function exports // deferred initialization of function exports
for (index, locator, kind) in functions { 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() { let function = if kind.is_generator() {
create_generator_function_object(code, kind.is_async(), None, context) create_generator_function_object(code, kind.is_async(), None, context)

12
boa_engine/src/object/internal_methods/function.rs

@ -98,7 +98,7 @@ pub(crate) fn function_call(
let index = context let index = context
.vm .vm
.environments .environments
.push_lexical(code.compile_environments[last_env].clone()); .push_lexical(code.constant_compile_time_environment(last_env));
context context
.vm .vm
.environments .environments
@ -107,7 +107,7 @@ pub(crate) fn function_call(
} }
context.vm.environments.push_function( 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), FunctionSlots::new(this, function_object.clone(), None),
); );
@ -116,7 +116,7 @@ pub(crate) fn function_call(
context context
.vm .vm
.environments .environments
.push_lexical(code.compile_environments[last_env].clone()); .push_lexical(code.constant_compile_time_environment(last_env));
} }
// Taken from: `FunctionDeclarationInstantiation` abstract function. // Taken from: `FunctionDeclarationInstantiation` abstract function.
@ -226,7 +226,7 @@ fn function_construct(
let index = context let index = context
.vm .vm
.environments .environments
.push_lexical(code.compile_environments[last_env].clone()); .push_lexical(code.constant_compile_time_environment(last_env));
context context
.vm .vm
.environments .environments
@ -235,7 +235,7 @@ fn function_construct(
} }
context.vm.environments.push_function( context.vm.environments.push_function(
code.compile_environments[last_env].clone(), code.constant_compile_time_environment(last_env),
FunctionSlots::new( FunctionSlots::new(
this.clone().map_or(ThisBindingStatus::Uninitialized, |o| { this.clone().map_or(ThisBindingStatus::Uninitialized, |o| {
ThisBindingStatus::Initialized(o.into()) ThisBindingStatus::Initialized(o.into())
@ -255,7 +255,7 @@ fn function_construct(
context context
.vm .vm
.environments .environments
.push_lexical(code.compile_environments[last_env].clone()); .push_lexical(code.constant_compile_time_environment(last_env));
} }
// Taken from: `FunctionDeclarationInstantiation` abstract function. // Taken from: `FunctionDeclarationInstantiation` abstract function.

148
boa_engine/src/vm/code_block.rs

@ -8,7 +8,7 @@ use crate::{
object::{JsObject, ObjectData, PROTOTYPE}, object::{JsObject, ObjectData, PROTOTYPE},
property::PropertyDescriptor, property::PropertyDescriptor,
string::utf16, string::utf16,
Context, JsString, JsValue, Context, JsBigInt, JsString, JsValue,
}; };
use bitflags::bitflags; use bitflags::bitflags;
use boa_ast::function::FormalParameterList; 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<CodeBlock>),
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<CompileTimeEnvironment>),
}
/// The internal representation of a JavaScript function. /// The internal representation of a JavaScript function.
/// ///
/// A `CodeBlock` is generated for each function compiled by the /// A `CodeBlock` is generated for each function compiled by the
@ -135,29 +150,15 @@ pub struct CodeBlock {
/// Bytecode /// Bytecode
pub(crate) bytecode: Box<[u8]>, pub(crate) bytecode: Box<[u8]>,
/// Literals pub(crate) constants: ThinVec<Constant>,
pub(crate) literals: Box<[JsValue]>,
/// Property field names and private names `[[description]]`s.
pub(crate) names: Box<[JsString]>,
/// Locators for all bindings in the codeblock. /// Locators for all bindings in the codeblock.
#[unsafe_ignore_trace] #[unsafe_ignore_trace]
pub(crate) bindings: Box<[BindingLocator]>, pub(crate) bindings: Box<[BindingLocator]>,
/// Functions inside this function
pub(crate) functions: Box<[Gc<Self>]>,
/// Exception [`Handler`]s. /// Exception [`Handler`]s.
#[unsafe_ignore_trace] #[unsafe_ignore_trace]
pub(crate) handlers: ThinVec<Handler>, pub(crate) handlers: ThinVec<Handler>,
/// 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<CompileTimeEnvironment>]>,
} }
/// ---- `CodeBlock` public API ---- /// ---- `CodeBlock` public API ----
@ -169,17 +170,14 @@ impl CodeBlock {
flags.set(CodeBlockFlags::STRICT, strict); flags.set(CodeBlockFlags::STRICT, strict);
Self { Self {
bytecode: Box::default(), bytecode: Box::default(),
literals: Box::default(), constants: ThinVec::default(),
names: Box::default(),
bindings: Box::default(), bindings: Box::default(),
functions: Box::default(),
name, name,
flags: Cell::new(flags), flags: Cell::new(flags),
length, length,
this_mode: ThisMode::Global, this_mode: ThisMode::Global,
params: FormalParameterList::default(), params: FormalParameterList::default(),
handlers: ThinVec::default(), handlers: ThinVec::default(),
compile_environments: Box::default(),
} }
} }
@ -252,6 +250,51 @@ impl CodeBlock {
.rev() .rev()
.find(|(_, handler)| handler.contains(pc)) .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<CodeBlock>`]) 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<Self> {
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<CompileTimeEnvironment> {
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 ---- /// ---- `CodeBlock` private API ----
@ -325,11 +368,11 @@ impl CodeBlock {
pattern_index: source_index, pattern_index: source_index,
flags_index: flag_index, flags_index: flag_index,
} => { } => {
let pattern = self.names[source_index.value() as usize] let pattern = self
.clone() .constant_string(source_index.value() as usize)
.to_std_string_escaped(); .to_std_string_escaped();
let flags = self.names[flag_index.value() as usize] let flags = self
.clone() .constant_string(flag_index.value() as usize)
.to_std_string_escaped(); .to_std_string_escaped();
format!("/{pattern}/{flags}") format!("/{pattern}/{flags}")
} }
@ -383,8 +426,8 @@ impl CodeBlock {
let index = index.value() as usize; let index = index.value() as usize;
format!( format!(
"{index:04}: '{}' (length: {}), method: {method}", "{index:04}: '{}' (length: {}), method: {method}",
self.functions[index].name().to_std_string_escaped(), self.constant_function(index).name().to_std_string_escaped(),
self.functions[index].length self.constant_function(index).length
) )
} }
Instruction::GetArrowFunction { index } Instruction::GetArrowFunction { index }
@ -394,8 +437,8 @@ impl CodeBlock {
let index = index.value() as usize; let index = index.value() as usize;
format!( format!(
"{index:04}: '{}' (length: {})", "{index:04}: '{}' (length: {})",
self.functions[index].name().to_std_string_escaped(), self.constant_function(index).name().to_std_string_escaped(),
self.functions[index].length self.constant_function(index).length
) )
} }
Instruction::DefVar { index } Instruction::DefVar { index }
@ -440,7 +483,8 @@ impl CodeBlock {
format!( format!(
"{:04}: '{}'", "{:04}: '{}'",
index.value(), 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 } => { Instruction::PushPrivateEnvironment { name_indices } => {
@ -693,17 +737,34 @@ impl ToInternedString for CodeBlock {
count += 1; count += 1;
} }
f.push_str("\nLiterals:\n"); f.push_str("\nConstants:");
if self.literals.is_empty() { if self.constants.is_empty() {
f.push_str(" <empty>\n"); f.push_str(" <empty>\n");
} else { } else {
for (i, value) in self.literals.iter().enumerate() { f.push('\n');
f.push_str(&format!( for (i, value) in self.constants.iter().enumerate() {
" {i:04}: <{}> {}\n", f.push_str(&format!(" {i:04}: "));
value.type_of(), let value = match value {
value.display() 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(" <empty>\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"); f.push_str("\nHandlers:\n");
if self.handlers.is_empty() { if self.handlers.is_empty() {
f.push_str(" <empty>\n"); f.push_str(" <empty>\n");

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

@ -14,7 +14,7 @@ pub use edge::*;
pub use graph::*; pub use graph::*;
pub use node::*; pub use node::*;
use super::{Instruction, InstructionIterator}; use super::{Constant, Instruction, InstructionIterator};
impl CodeBlock { impl CodeBlock {
/// Output the [`CodeBlock`] VM instructions into a [`Graph`]. /// Output the [`CodeBlock`] VM instructions into a [`Graph`].
@ -526,9 +526,11 @@ impl CodeBlock {
} }
} }
for function in self.functions.as_ref() { for constant in &self.constants {
if let Constant::Function(function) = constant {
let subgraph = graph.subgraph(String::new()); let subgraph = graph.subgraph(String::new());
function.to_graph(interner, subgraph); function.to_graph(interner, subgraph);
} }
} }
} }
}

2
boa_engine/src/vm/mod.rs

@ -41,7 +41,7 @@ pub(crate) use {
call_frame::CallFrameFlags, call_frame::CallFrameFlags,
code_block::{ code_block::{
create_function_object, create_function_object_fast, create_generator_function_object, create_function_object, create_function_object_fast, create_generator_function_object,
CodeBlockFlags, Handler, CodeBlockFlags, Constant, Handler,
}, },
completion_record::CompletionRecord, completion_record::CompletionRecord,
opcode::BindingOpcode, opcode::BindingOpcode,

2
boa_engine/src/vm/opcode/binary_ops/mod.rs

@ -111,7 +111,7 @@ pub(crate) struct InPrivate;
impl InPrivate { impl InPrivate {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 rhs = context.vm.pop();
let Some(rhs) = rhs.as_object() else { let Some(rhs) = rhs.as_object() else {

5
boa_engine/src/vm/opcode/control_flow/throw.rs

@ -123,10 +123,7 @@ pub(crate) struct ThrowNewTypeError;
impl ThrowNewTypeError { impl ThrowNewTypeError {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let msg = context.vm.frame().code_block.literals[index] let msg = context.vm.frame().code_block().constant_string(index);
.as_string()
.expect("throw message must be a string")
.clone();
let msg = msg let msg = msg
.to_std_string() .to_std_string()
.expect("throw message must be an ASCII string"); .expect("throw message must be an ASCII string");

14
boa_engine/src/vm/opcode/define/class/getter.rs

@ -17,7 +17,12 @@ impl DefineClassStaticGetterByName {
let function = context.vm.pop(); let function = context.vm.pop();
let class = context.vm.pop(); let class = context.vm.pop();
let class = class.as_object().expect("class must be object"); 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 let function_object = function
.as_object() .as_object()
@ -81,7 +86,12 @@ impl DefineClassGetterByName {
let function = context.vm.pop(); let function = context.vm.pop();
let class_proto = context.vm.pop(); let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object"); 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 let function_object = function
.as_object() .as_object()

14
boa_engine/src/vm/opcode/define/class/method.rs

@ -17,7 +17,12 @@ impl DefineClassStaticMethodByName {
let function = context.vm.pop(); let function = context.vm.pop();
let class = context.vm.pop(); let class = context.vm.pop();
let class = class.as_object().expect("class must be object"); 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 let function_object = function
.as_object() .as_object()
@ -77,7 +82,12 @@ impl DefineClassMethodByName {
let function = context.vm.pop(); let function = context.vm.pop();
let class_proto = context.vm.pop(); let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object"); 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 let function_object = function
.as_object() .as_object()

14
boa_engine/src/vm/opcode/define/class/setter.rs

@ -17,7 +17,12 @@ impl DefineClassStaticSetterByName {
let function = context.vm.pop(); let function = context.vm.pop();
let class = context.vm.pop(); let class = context.vm.pop();
let class = class.as_object().expect("class must be object"); 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 let function_object = function
.as_object() .as_object()
@ -82,7 +87,12 @@ impl DefineClassSetterByName {
let function = context.vm.pop(); let function = context.vm.pop();
let class_proto = context.vm.pop(); let class_proto = context.vm.pop();
let class_proto = class_proto.as_object().expect("class must be object"); 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 let function_object = function
.as_object() .as_object()

2
boa_engine/src/vm/opcode/define/own_property.rs

@ -20,7 +20,7 @@ impl DefineOwnPropertyByName {
} else { } else {
object.to_object(context)? 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__( object.__define_own_property__(
&name.into(), &name.into(),
PropertyDescriptor::builder() PropertyDescriptor::builder()

7
boa_engine/src/vm/opcode/delete/mod.rs

@ -15,7 +15,12 @@ impl DeletePropertyByName {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let value = context.vm.pop(); let value = context.vm.pop();
let object = value.to_object(context)?; 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)?; let result = object.__delete__(&key, context)?;
if !result && context.vm.frame().code_block.strict() { if !result && context.vm.frame().code_block.strict() {
return Err(JsNativeError::typ() return Err(JsNativeError::typ()

8
boa_engine/src/vm/opcode/get/function.rs

@ -13,7 +13,7 @@ pub(crate) struct GetArrowFunction;
impl GetArrowFunction { impl GetArrowFunction {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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); let function = create_function_object_fast(code, false, true, false, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
@ -51,7 +51,7 @@ pub(crate) struct GetAsyncArrowFunction;
impl GetAsyncArrowFunction { impl GetAsyncArrowFunction {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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); let function = create_function_object_fast(code, true, true, false, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
@ -93,7 +93,7 @@ impl GetFunction {
index: usize, index: usize,
method: bool, method: bool,
) -> JsResult<CompletionType> { ) -> JsResult<CompletionType> {
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); let function = create_function_object_fast(code, false, false, method, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
@ -138,7 +138,7 @@ impl GetFunctionAsync {
index: usize, index: usize,
method: bool, method: bool,
) -> JsResult<CompletionType> { ) -> JsResult<CompletionType> {
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); let function = create_function_object_fast(code, true, false, method, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)

4
boa_engine/src/vm/opcode/get/generator.rs

@ -13,7 +13,7 @@ pub(crate) struct GetGenerator;
impl GetGenerator { impl GetGenerator {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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); let function = create_generator_function_object(code, false, None, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
@ -51,7 +51,7 @@ pub(crate) struct GetGeneratorAsync;
impl GetGeneratorAsync { impl GetGeneratorAsync {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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); let function = create_generator_function_object(code, true, None, context);
context.vm.push(function); context.vm.push(function);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)

2
boa_engine/src/vm/opcode/get/private.rs

@ -12,7 +12,7 @@ pub(crate) struct GetPrivateField;
impl GetPrivateField { impl GetPrivateField {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let base_obj = value.to_object(context)?; let base_obj = value.to_object(context)?;

7
boa_engine/src/vm/opcode/get/property.rs

@ -21,7 +21,12 @@ impl GetPropertyByName {
value.to_object(context)? 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)?; let result = object.__get__(&key, receiver, context)?;
context.vm.push(result); context.vm.push(result);

2
boa_engine/src/vm/opcode/push/class/field.rs

@ -55,7 +55,7 @@ pub(crate) struct PushClassFieldPrivate;
impl PushClassFieldPrivate { impl PushClassFieldPrivate {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 field_function_value = context.vm.pop();
let class_value = context.vm.pop(); let class_value = context.vm.pop();

6
boa_engine/src/vm/opcode/push/class/private.rs

@ -17,7 +17,7 @@ pub(crate) struct PushClassPrivateMethod;
impl PushClassPrivateMethod { impl PushClassPrivateMethod {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let method_object = method.as_callable().expect("method must be callable"); let method_object = method.as_callable().expect("method must be callable");
@ -79,7 +79,7 @@ pub(crate) struct PushClassPrivateGetter;
impl PushClassPrivateGetter { impl PushClassPrivateGetter {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let getter_object = getter.as_callable().expect("getter must be callable"); let getter_object = getter.as_callable().expect("getter must be callable");
let class = context.vm.pop(); let class = context.vm.pop();
@ -132,7 +132,7 @@ pub(crate) struct PushClassPrivateSetter;
impl PushClassPrivateSetter { impl PushClassPrivateSetter {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let setter_object = setter.as_callable().expect("getter must be callable"); let setter_object = setter.as_callable().expect("getter must be callable");
let class = context.vm.pop(); let class = context.vm.pop();

13
boa_engine/src/vm/opcode/push/environment.rs

@ -18,8 +18,11 @@ impl PushDeclarativeEnvironment {
context: &mut Context<'_>, context: &mut Context<'_>,
compile_environments_index: usize, compile_environments_index: usize,
) -> JsResult<CompletionType> { ) -> JsResult<CompletionType> {
let compile_environment = let compile_environment = context
context.vm.frame().code_block.compile_environments[compile_environments_index].clone(); .vm
.frame()
.code_block()
.constant_compile_time_environment(compile_environments_index);
context.vm.environments.push_lexical(compile_environment); context.vm.environments.push_lexical(compile_environment);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
} }
@ -87,7 +90,11 @@ impl Operation for PushPrivateEnvironment {
let mut names = Vec::with_capacity(count as usize); let mut names = Vec::with_capacity(count as usize);
for _ in 0..count { for _ in 0..count {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
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); names.push(name);
} }

19
boa_engine/src/vm/opcode/push/literal.rs

@ -1,7 +1,7 @@
use crate::{ use crate::{
object::JsRegExp, object::JsRegExp,
vm::{opcode::Operation, CompletionType}, vm::{opcode::Operation, CompletionType, Constant},
Context, JsResult, Context, JsResult, JsValue,
}; };
/// `PushLiteral` implements the Opcode Operation for `Opcode::PushLiteral` /// `PushLiteral` implements the Opcode Operation for `Opcode::PushLiteral`
@ -14,7 +14,12 @@ pub(crate) struct PushLiteral;
impl PushLiteral { impl PushLiteral {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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); context.vm.push(value);
Ok(CompletionType::Normal) Ok(CompletionType::Normal)
} }
@ -54,8 +59,12 @@ impl PushRegExp {
pattern_index: usize, pattern_index: usize,
flags_index: usize, flags_index: usize,
) -> JsResult<CompletionType> { ) -> JsResult<CompletionType> {
let pattern = context.vm.frame().code_block.names[pattern_index].clone(); let pattern = context
let flags = context.vm.frame().code_block.names[flags_index].clone(); .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)?; let regexp = JsRegExp::new(pattern, flags, context)?;
context.vm.push(regexp); context.vm.push(regexp);

2
boa_engine/src/vm/opcode/set/name.rs

@ -13,7 +13,7 @@ pub(crate) struct ThrowMutateImmutable;
impl ThrowMutateImmutable { impl ThrowMutateImmutable {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
let name = &context.vm.frame().code_block.names[index]; let name = context.vm.frame().code_block().constant_string(index);
Err(JsNativeError::typ() Err(JsNativeError::typ()
.with_message(format!( .with_message(format!(

10
boa_engine/src/vm/opcode/set/private.rs

@ -16,7 +16,7 @@ pub(crate) struct SetPrivateField;
impl SetPrivateField { impl SetPrivateField {
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let base_obj = object.to_object(context)?; let base_obj = object.to_object(context)?;
@ -64,7 +64,7 @@ pub(crate) struct DefinePrivateField;
impl DefinePrivateField { impl DefinePrivateField {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let object = object let object = object
@ -110,7 +110,7 @@ pub(crate) struct SetPrivateMethod;
impl SetPrivateMethod { impl SetPrivateMethod {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let value = value.as_callable().expect("method must be callable"); let value = value.as_callable().expect("method must be callable");
@ -170,7 +170,7 @@ pub(crate) struct SetPrivateSetter;
impl SetPrivateSetter { impl SetPrivateSetter {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let value = value.as_callable().expect("setter must be callable"); let value = value.as_callable().expect("setter must be callable");
let object = context.vm.pop(); let object = context.vm.pop();
@ -221,7 +221,7 @@ pub(crate) struct SetPrivateGetter;
impl SetPrivateGetter { impl SetPrivateGetter {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> { fn operation(context: &mut Context<'_>, index: usize) -> JsResult<CompletionType> {
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 = context.vm.pop();
let value = value.as_callable().expect("getter must be callable"); let value = value.as_callable().expect("getter must be callable");
let object = context.vm.pop(); let object = context.vm.pop();

21
boa_engine/src/vm/opcode/set/property.rs

@ -25,7 +25,12 @@ impl SetPropertyByName {
object.to_object(context)? 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)?; let succeeded = object.__set__(name.clone(), value.clone(), receiver, context)?;
if !succeeded && context.vm.frame().code_block.strict() { if !succeeded && context.vm.frame().code_block.strict() {
@ -176,7 +181,12 @@ impl SetPropertyGetterByName {
let value = context.vm.pop(); let value = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let object = object.to_object(context)?; 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 let set = object
.__get_own_property__(&name, context)? .__get_own_property__(&name, context)?
.as_ref() .as_ref()
@ -266,7 +276,12 @@ impl SetPropertySetterByName {
let value = context.vm.pop(); let value = context.vm.pop();
let object = context.vm.pop(); let object = context.vm.pop();
let object = object.to_object(context)?; 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 let get = object
.__get_own_property__(&name, context)? .__get_own_property__(&name, context)?
.as_ref() .as_ref()

Loading…
Cancel
Save