Browse Source

Clarity changes for the VM (#2531)

<!---
Thank you for contributing to Boa! Please fill out the template below, and remove or add any
information as you feel necessary.
--->

Some small changes to the VM with the hopes of making it a bit more clear and concise.

It changes the following:

- Changes `code` to `code_block` and `code` to `bytecode` in `CallFrame` and `CodeBlock`, respectively.
- Adds some creation methods to `CallFrame`.
- Implements `Default` for `Vm`.
pull/2535/head
Kevin 2 years ago
parent
commit
ff06690140
  1. 2
      boa_engine/src/builtins/console/mod.rs
  2. 20
      boa_engine/src/bytecompiler/mod.rs
  3. 28
      boa_engine/src/context/mod.rs
  4. 40
      boa_engine/src/vm/call_frame.rs
  5. 134
      boa_engine/src/vm/code_block.rs
  6. 4
      boa_engine/src/vm/flowgraph/mod.rs
  7. 26
      boa_engine/src/vm/mod.rs
  8. 4
      boa_engine/src/vm/opcode/call/mod.rs
  9. 4
      boa_engine/src/vm/opcode/define/class/getter.rs
  10. 4
      boa_engine/src/vm/opcode/define/class/method.rs
  11. 4
      boa_engine/src/vm/opcode/define/class/setter.rs
  12. 8
      boa_engine/src/vm/opcode/define/mod.rs
  13. 2
      boa_engine/src/vm/opcode/define/own_property.rs
  14. 10
      boa_engine/src/vm/opcode/delete/mod.rs
  15. 8
      boa_engine/src/vm/opcode/get/function.rs
  16. 4
      boa_engine/src/vm/opcode/get/generator.rs
  17. 4
      boa_engine/src/vm/opcode/get/name.rs
  18. 2
      boa_engine/src/vm/opcode/get/private.rs
  19. 2
      boa_engine/src/vm/opcode/get/property.rs
  20. 2
      boa_engine/src/vm/opcode/push/class/field.rs
  21. 6
      boa_engine/src/vm/opcode/push/class/private.rs
  22. 4
      boa_engine/src/vm/opcode/push/environment.rs
  23. 2
      boa_engine/src/vm/opcode/push/literal.rs
  24. 6
      boa_engine/src/vm/opcode/set/name.rs
  25. 10
      boa_engine/src/vm/opcode/set/private.rs
  26. 15
      boa_engine/src/vm/opcode/set/property.rs

2
boa_engine/src/builtins/console/mod.rs

@ -319,7 +319,7 @@ impl Console {
stack_trace.push( stack_trace.push(
context context
.interner() .interner()
.resolve_expect(frame.code.name) .resolve_expect(frame.code_block.name)
.to_string(), .to_string(),
); );
} }

20
boa_engine/src/bytecompiler/mod.rs

@ -349,8 +349,8 @@ impl<'b, 'icu> ByteCompiler<'b, 'icu> {
} }
fn next_opcode_location(&mut self) -> u32 { fn next_opcode_location(&mut self) -> u32 {
assert!(self.code_block.code.len() < u32::MAX as usize); assert!(self.code_block.bytecode.len() < u32::MAX as usize);
self.code_block.code.len() as u32 self.code_block.bytecode.len() as u32
} }
fn emit(&mut self, opcode: Opcode, operands: &[u32]) { fn emit(&mut self, opcode: Opcode, operands: &[u32]) {
@ -361,15 +361,15 @@ impl<'b, 'icu> ByteCompiler<'b, 'icu> {
} }
fn emit_u64(&mut self, value: u64) { fn emit_u64(&mut self, value: u64) {
self.code_block.code.extend(value.to_ne_bytes()); self.code_block.bytecode.extend(value.to_ne_bytes());
} }
fn emit_u32(&mut self, value: u32) { fn emit_u32(&mut self, value: u32) {
self.code_block.code.extend(value.to_ne_bytes()); self.code_block.bytecode.extend(value.to_ne_bytes());
} }
fn emit_u16(&mut self, value: u16) { fn emit_u16(&mut self, value: u16) {
self.code_block.code.extend(value.to_ne_bytes()); self.code_block.bytecode.extend(value.to_ne_bytes());
} }
fn emit_opcode(&mut self, opcode: Opcode) { fn emit_opcode(&mut self, opcode: Opcode) {
@ -377,7 +377,7 @@ impl<'b, 'icu> ByteCompiler<'b, 'icu> {
} }
fn emit_u8(&mut self, value: u8) { fn emit_u8(&mut self, value: u8) {
self.code_block.code.push(value); self.code_block.bytecode.push(value);
} }
fn emit_push_integer(&mut self, value: i32) { fn emit_push_integer(&mut self, value: i32) {
@ -465,10 +465,10 @@ impl<'b, 'icu> ByteCompiler<'b, 'icu> {
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.code[index + 1] = bytes[0]; self.code_block.bytecode[index + 1] = bytes[0];
self.code_block.code[index + 2] = bytes[1]; self.code_block.bytecode[index + 2] = bytes[1];
self.code_block.code[index + 3] = bytes[2]; self.code_block.bytecode[index + 3] = bytes[2];
self.code_block.code[index + 4] = bytes[3]; self.code_block.bytecode[index + 4] = bytes[3];
} }
fn patch_jump(&mut self, label: Label) { fn patch_jump(&mut self, label: Label) {

28
boa_engine/src/context/mod.rs

@ -25,7 +25,7 @@ use crate::{
object::{FunctionObjectBuilder, GlobalPropertyMap, JsObject}, object::{FunctionObjectBuilder, GlobalPropertyMap, JsObject},
property::{Attribute, PropertyDescriptor, PropertyKey}, property::{Attribute, PropertyDescriptor, PropertyKey},
realm::Realm, realm::Realm,
vm::{CallFrame, CodeBlock, FinallyReturn, GeneratorResumeKind, Vm}, vm::{CallFrame, CodeBlock, Vm},
JsResult, JsValue, JsResult, JsValue,
}; };
@ -205,24 +205,7 @@ impl Context<'_> {
pub fn execute(&mut self, code_block: Gc<CodeBlock>) -> JsResult<JsValue> { pub fn execute(&mut self, code_block: Gc<CodeBlock>) -> JsResult<JsValue> {
let _timer = Profiler::global().start_event("Execution", "Main"); let _timer = Profiler::global().start_event("Execution", "Main");
self.vm.push_frame(CallFrame { self.vm.push_frame(CallFrame::new(code_block));
code: code_block,
pc: 0,
catch: Vec::new(),
finally_return: FinallyReturn::None,
finally_jump: Vec::new(),
pop_on_return: 0,
loop_env_stack: Vec::from([0]),
try_env_stack: Vec::from([crate::vm::TryStackEntry {
num_env: 0,
num_loop_stack_entries: 0,
}]),
param_count: 0,
arg_count: 0,
generator_resume_kind: GeneratorResumeKind::Normal,
thrown: false,
async_generator: None,
});
self.realm.set_global_binding_number(); self.realm.set_global_binding_number();
let result = self.run(); let result = self.run();
@ -572,12 +555,7 @@ impl<'a> ContextBuilder<'a> {
#[cfg(feature = "console")] #[cfg(feature = "console")]
console: Console::default(), console: Console::default(),
intrinsics, intrinsics,
vm: Vm { vm: Vm::default(),
frames: Vec::with_capacity(16),
stack: Vec::with_capacity(1024),
trace: false,
stack_size_limit: 1024,
},
#[cfg(feature = "intl")] #[cfg(feature = "intl")]
icu: self.icu.unwrap_or_else(|| { icu: self.icu.unwrap_or_else(|| {
let provider = BoaProvider::Buffer(boa_icu_provider::buffer()); let provider = BoaProvider::Buffer(boa_icu_provider::buffer());

40
boa_engine/src/vm/call_frame.rs

@ -8,7 +8,7 @@ use boa_gc::{Finalize, Gc, Trace};
/// A `CallFrame` holds the state of a function call. /// A `CallFrame` holds the state of a function call.
#[derive(Clone, Debug, Finalize, Trace)] #[derive(Clone, Debug, Finalize, Trace)]
pub struct CallFrame { pub struct CallFrame {
pub(crate) code: Gc<CodeBlock>, pub(crate) code_block: Gc<CodeBlock>,
pub(crate) pc: usize, pub(crate) pc: usize,
#[unsafe_ignore_trace] #[unsafe_ignore_trace]
pub(crate) catch: Vec<CatchAddresses>, pub(crate) catch: Vec<CatchAddresses>,
@ -39,6 +39,44 @@ pub struct CallFrame {
pub(crate) async_generator: Option<JsObject>, pub(crate) async_generator: Option<JsObject>,
} }
/// ---- `CallFrame` creation methods ----
impl CallFrame {
/// Creates a new `CallFrame` with the provided `CodeBlock`.
pub(crate) fn new(code_block: Gc<CodeBlock>) -> Self {
Self {
code_block,
pc: 0,
catch: Vec::new(),
finally_return: FinallyReturn::None,
finally_jump: Vec::new(),
pop_on_return: 0,
loop_env_stack: Vec::from([0]),
try_env_stack: Vec::from([TryStackEntry {
num_env: 0,
num_loop_stack_entries: 0,
}]),
param_count: 0,
arg_count: 0,
generator_resume_kind: GeneratorResumeKind::Normal,
thrown: false,
async_generator: None,
}
}
/// Updates a `CallFrame`'s `param_count` field with the value provided.
pub(crate) fn with_param_count(mut self, count: usize) -> Self {
self.param_count = count;
self
}
/// Updates a `CallFrame`'s `arg_count` field with the value provided.
pub(crate) fn with_arg_count(mut self, count: usize) -> Self {
self.arg_count = count;
self
}
}
/// ---- `CallFrame` stack methods ----
impl CallFrame { impl CallFrame {
/// Tracks that one environment has been pushed in the current loop block. /// Tracks that one environment has been pushed in the current loop block.
pub(crate) fn loop_env_stack_inc(&mut self) { pub(crate) fn loop_env_stack_inc(&mut self) {

134
boa_engine/src/vm/code_block.rs

@ -15,8 +15,7 @@ use crate::{
js_string, js_string,
object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData}, object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectData},
property::PropertyDescriptor, property::PropertyDescriptor,
vm::call_frame::GeneratorResumeKind, vm::{CallFrame, Opcode},
vm::{call_frame::FinallyReturn, CallFrame, Opcode},
Context, JsResult, JsString, JsValue, Context, JsResult, JsString, JsValue,
}; };
use boa_ast::{ use boa_ast::{
@ -78,7 +77,7 @@ pub struct CodeBlock {
pub(crate) params: FormalParameterList, pub(crate) params: FormalParameterList,
/// Bytecode /// Bytecode
pub(crate) code: Vec<u8>, pub(crate) bytecode: Vec<u8>,
/// Literals /// Literals
pub(crate) literals: Vec<JsValue>, pub(crate) literals: Vec<JsValue>,
@ -127,7 +126,7 @@ 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 {
code: Vec::new(), bytecode: Vec::new(),
literals: Vec::new(), literals: Vec::new(),
names: Vec::new(), names: Vec::new(),
private_names: Vec::new(), private_names: Vec::new(),
@ -162,7 +161,13 @@ impl CodeBlock {
// //
// This has to be an unaligned read because we can't guarantee that // This has to be an unaligned read because we can't guarantee that
// the types are aligned. // the types are aligned.
unsafe { self.code.as_ptr().add(offset).cast::<T>().read_unaligned() } unsafe {
self.bytecode
.as_ptr()
.add(offset)
.cast::<T>()
.read_unaligned()
}
} }
/// Read type T from code. /// Read type T from code.
@ -171,7 +176,7 @@ impl CodeBlock {
where where
T: Readable, T: Readable,
{ {
assert!(offset + size_of::<T>() - 1 < self.code.len()); assert!(offset + size_of::<T>() - 1 < self.bytecode.len());
// Safety: We checked that it is not an out-of-bounds read, // Safety: We checked that it is not an out-of-bounds read,
// so this is safe. // so this is safe.
@ -183,7 +188,7 @@ impl CodeBlock {
/// ///
/// Returns an empty `String` if no operands are present. /// Returns an empty `String` if no operands are present.
pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String { pub(crate) fn instruction_operands(&self, pc: &mut usize, interner: &Interner) -> String {
let opcode: Opcode = self.code[*pc].try_into().expect("invalid opcode"); let opcode: Opcode = self.bytecode[*pc].try_into().expect("invalid opcode");
*pc += size_of::<Opcode>(); *pc += size_of::<Opcode>();
match opcode { match opcode {
Opcode::SetFunctionName => { Opcode::SetFunctionName => {
@ -453,8 +458,8 @@ impl ToInternedString for CodeBlock {
let mut pc = 0; let mut pc = 0;
let mut count = 0; let mut count = 0;
while pc < self.code.len() { while pc < self.bytecode.len() {
let opcode: Opcode = self.code[pc].try_into().expect("invalid opcode"); let opcode: Opcode = self.bytecode[pc].try_into().expect("invalid opcode");
let opcode = opcode.as_str(); let opcode = opcode.as_str();
let previous_pc = pc; let previous_pc = pc;
let operands = self.instruction_operands(&mut pc, interner); let operands = self.instruction_operands(&mut pc, interner);
@ -854,24 +859,11 @@ impl JsObject {
let param_count = code.params.as_ref().len(); let param_count = code.params.as_ref().len();
context.vm.push_frame(CallFrame { context.vm.push_frame(
code, CallFrame::new(code)
pc: 0, .with_param_count(param_count)
catch: Vec::new(), .with_arg_count(arg_count),
finally_return: FinallyReturn::None, );
finally_jump: Vec::new(),
pop_on_return: 0,
loop_env_stack: Vec::from([0]),
try_env_stack: Vec::from([crate::vm::TryStackEntry {
num_env: 0,
num_loop_stack_entries: 0,
}]),
param_count,
arg_count,
generator_resume_kind: GeneratorResumeKind::Normal,
thrown: false,
async_generator: None,
});
let result = context.run(); let result = context.run();
context.vm.pop_frame().expect("must have frame"); context.vm.pop_frame().expect("must have frame");
@ -990,24 +982,11 @@ impl JsObject {
let param_count = code.params.as_ref().len(); let param_count = code.params.as_ref().len();
context.vm.push_frame(CallFrame { context.vm.push_frame(
code, CallFrame::new(code)
pc: 0, .with_param_count(param_count)
catch: Vec::new(), .with_arg_count(arg_count),
finally_return: FinallyReturn::None, );
finally_jump: Vec::new(),
pop_on_return: 0,
loop_env_stack: Vec::from([0]),
try_env_stack: Vec::from([crate::vm::TryStackEntry {
num_env: 0,
num_loop_stack_entries: 0,
}]),
param_count,
arg_count,
generator_resume_kind: GeneratorResumeKind::Normal,
thrown: false,
async_generator: None,
});
let _result = context.run(); let _result = context.run();
context.vm.pop_frame().expect("must have frame"); context.vm.pop_frame().expect("must have frame");
@ -1119,24 +1098,9 @@ impl JsObject {
let param_count = code.params.as_ref().len(); let param_count = code.params.as_ref().len();
let call_frame = CallFrame { let call_frame = CallFrame::new(code)
code, .with_param_count(param_count)
pc: 0, .with_arg_count(arg_count);
catch: Vec::new(),
finally_return: FinallyReturn::None,
finally_jump: Vec::new(),
pop_on_return: 0,
loop_env_stack: Vec::from([0]),
try_env_stack: Vec::from([crate::vm::TryStackEntry {
num_env: 0,
num_loop_stack_entries: 0,
}]),
param_count,
arg_count,
generator_resume_kind: GeneratorResumeKind::Normal,
thrown: false,
async_generator: None,
};
let mut stack = args; let mut stack = args;
std::mem::swap(&mut context.vm.stack, &mut stack); std::mem::swap(&mut context.vm.stack, &mut stack);
@ -1275,24 +1239,9 @@ impl JsObject {
let param_count = code.params.as_ref().len(); let param_count = code.params.as_ref().len();
let call_frame = CallFrame { let call_frame = CallFrame::new(code)
code, .with_param_count(param_count)
pc: 0, .with_arg_count(arg_count);
catch: Vec::new(),
finally_return: FinallyReturn::None,
finally_jump: Vec::new(),
pop_on_return: 0,
loop_env_stack: Vec::from([0]),
try_env_stack: Vec::from([crate::vm::TryStackEntry {
num_env: 0,
num_loop_stack_entries: 0,
}]),
param_count,
arg_count,
generator_resume_kind: GeneratorResumeKind::Normal,
thrown: false,
async_generator: None,
};
let mut stack = args; let mut stack = args;
std::mem::swap(&mut context.vm.stack, &mut stack); std::mem::swap(&mut context.vm.stack, &mut stack);
@ -1494,24 +1443,11 @@ impl JsObject {
let param_count = code.params.as_ref().len(); let param_count = code.params.as_ref().len();
let has_binding_identifier = code.has_binding_identifier; let has_binding_identifier = code.has_binding_identifier;
context.vm.push_frame(CallFrame { context.vm.push_frame(
code, CallFrame::new(code)
pc: 0, .with_param_count(param_count)
catch: Vec::new(), .with_arg_count(arg_count),
finally_return: FinallyReturn::None, );
finally_jump: Vec::new(),
pop_on_return: 0,
loop_env_stack: Vec::from([0]),
try_env_stack: Vec::from([crate::vm::TryStackEntry {
num_env: 0,
num_loop_stack_entries: 0,
}]),
param_count,
arg_count,
generator_resume_kind: GeneratorResumeKind::Normal,
thrown: false,
async_generator: None,
});
let result = context.run(); let result = context.run();

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

@ -31,8 +31,8 @@ impl CodeBlock {
let mut returns = Vec::new(); let mut returns = Vec::new();
let mut pc = 0; let mut pc = 0;
while pc < self.code.len() { while pc < self.bytecode.len() {
let opcode: Opcode = self.code[pc].try_into().expect("invalid opcode"); let opcode: Opcode = self.bytecode[pc].try_into().expect("invalid opcode");
let opcode_str = opcode.as_str(); let opcode_str = opcode.as_str();
let previous_pc = pc; let previous_pc = pc;

26
boa_engine/src/vm/mod.rs

@ -41,6 +41,17 @@ pub struct Vm {
pub(crate) stack_size_limit: usize, pub(crate) stack_size_limit: usize,
} }
impl Default for Vm {
fn default() -> Self {
Self {
frames: Vec::with_capacity(16),
stack: Vec::with_capacity(1024),
trace: false,
stack_size_limit: 1024,
}
}
}
impl Vm { impl Vm {
/// Push a value on the stack. /// Push a value on the stack.
pub(crate) fn push<T>(&mut self, value: T) pub(crate) fn push<T>(&mut self, value: T)
@ -62,7 +73,7 @@ impl Vm {
#[track_caller] #[track_caller]
pub(crate) fn read<T: Readable>(&mut self) -> T { pub(crate) fn read<T: Readable>(&mut self) -> T {
let value = self.frame().code.read::<T>(self.frame().pc); let value = self.frame().code_block.read::<T>(self.frame().pc);
self.frame_mut().pc += size_of::<T>(); self.frame_mut().pc += size_of::<T>();
value value
} }
@ -114,7 +125,7 @@ impl Context<'_> {
fn execute_instruction(&mut self) -> JsResult<ShouldExit> { fn execute_instruction(&mut self) -> JsResult<ShouldExit> {
let opcode: Opcode = { let opcode: Opcode = {
let _timer = Profiler::global().start_event("Opcode retrieval", "vm"); let _timer = Profiler::global().start_event("Opcode retrieval", "vm");
let opcode = self.vm.frame().code.code[self.vm.frame().pc] let opcode = self.vm.frame().code_block.bytecode[self.vm.frame().pc]
.try_into() .try_into()
.expect("could not convert code at PC to opcode"); .expect("could not convert code at PC to opcode");
self.vm.frame_mut().pc += 1; self.vm.frame_mut().pc += 1;
@ -146,7 +157,10 @@ impl Context<'_> {
println!( println!(
"{}\n", "{}\n",
self.vm.frame().code.to_interned_string(self.interner()) self.vm
.frame()
.code_block
.to_interned_string(self.interner())
); );
println!( println!(
"{msg:-^width$}", "{msg:-^width$}",
@ -178,7 +192,7 @@ impl Context<'_> {
.and_then(|f| f.get_promise_capability().cloned()) .and_then(|f| f.get_promise_capability().cloned())
}); });
while self.vm.frame().pc < self.vm.frame().code.code.len() { while self.vm.frame().pc < self.vm.frame().code_block.bytecode.len() {
#[cfg(feature = "fuzz")] #[cfg(feature = "fuzz")]
{ {
if self.instructions_remaining == 0 { if self.instructions_remaining == 0 {
@ -192,14 +206,14 @@ impl Context<'_> {
let opcode: Opcode = self let opcode: Opcode = self
.vm .vm
.frame() .frame()
.code .code_block
.read::<u8>(pc) .read::<u8>(pc)
.try_into() .try_into()
.expect("invalid opcode"); .expect("invalid opcode");
let operands = self let operands = self
.vm .vm
.frame() .frame()
.code .code_block
.instruction_operands(&mut pc, self.interner()); .instruction_operands(&mut pc, self.interner());
let instant = Instant::now(); let instant = Instant::now();

4
boa_engine/src/vm/opcode/call/mod.rs

@ -44,7 +44,7 @@ impl Operation for CallEval {
// A native function with the name "eval" implies, that is this the built-in eval function. // A native function with the name "eval" implies, that is this the built-in eval function.
let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. })); let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. }));
let strict = context.vm.frame().code.strict; let strict = context.vm.frame().code_block.strict;
if eval { if eval {
if let Some(x) = arguments.get(0) { if let Some(x) = arguments.get(0) {
@ -106,7 +106,7 @@ impl Operation for CallEvalSpread {
// A native function with the name "eval" implies, that is this the built-in eval function. // A native function with the name "eval" implies, that is this the built-in eval function.
let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. })); let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. }));
let strict = context.vm.frame().code.strict; let strict = context.vm.frame().code_block.strict;
if eval { if eval {
if let Some(x) = arguments.get(0) { if let Some(x) = arguments.get(0) {

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

@ -23,7 +23,7 @@ impl Operation for DefineClassStaticGetterByName {
let class = class.as_object().expect("class must be object"); let class = class.as_object().expect("class must be object");
let key = context let key = context
.interner() .interner()
.resolve_expect(context.vm.frame().code.names[index as usize].sym()) .resolve_expect(context.vm.frame().code_block.names[index as usize].sym())
.into_common::<JsString>(false) .into_common::<JsString>(false)
.into(); .into();
{ {
@ -75,7 +75,7 @@ impl Operation for DefineClassGetterByName {
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 let key = context
.interner() .interner()
.resolve_expect(context.vm.frame().code.names[index as usize].sym()) .resolve_expect(context.vm.frame().code_block.names[index as usize].sym())
.into_common::<JsString>(false) .into_common::<JsString>(false)
.into(); .into();
{ {

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

@ -23,7 +23,7 @@ impl Operation for DefineClassStaticMethodByName {
let class = class.as_object().expect("class must be object"); let class = class.as_object().expect("class must be object");
let key = context let key = context
.interner() .interner()
.resolve_expect(context.vm.frame().code.names[index as usize].sym()) .resolve_expect(context.vm.frame().code_block.names[index as usize].sym())
.into_common::<JsString>(false) .into_common::<JsString>(false)
.into(); .into();
{ {
@ -70,7 +70,7 @@ impl Operation for DefineClassMethodByName {
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 let key = context
.interner() .interner()
.resolve_expect(context.vm.frame().code.names[index as usize].sym()) .resolve_expect(context.vm.frame().code_block.names[index as usize].sym())
.into_common::<JsString>(false) .into_common::<JsString>(false)
.into(); .into();
{ {

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

@ -23,7 +23,7 @@ impl Operation for DefineClassStaticSetterByName {
let class = class.as_object().expect("class must be object"); let class = class.as_object().expect("class must be object");
let key = context let key = context
.interner() .interner()
.resolve_expect(context.vm.frame().code.names[index as usize].sym()) .resolve_expect(context.vm.frame().code_block.names[index as usize].sym())
.into_common::<JsString>(false) .into_common::<JsString>(false)
.into(); .into();
{ {
@ -75,7 +75,7 @@ impl Operation for DefineClassSetterByName {
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 let key = context
.interner() .interner()
.resolve_expect(context.vm.frame().code.names[index as usize].sym()) .resolve_expect(context.vm.frame().code_block.names[index as usize].sym())
.into_common::<JsString>(false) .into_common::<JsString>(false)
.into(); .into();
{ {

8
boa_engine/src/vm/opcode/define/mod.rs

@ -23,7 +23,7 @@ impl Operation for DefVar {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code.bindings[index as usize]; let binding_locator = context.vm.frame().code_block.bindings[index as usize];
if binding_locator.is_global() { if binding_locator.is_global() {
let key = context let key = context
@ -63,7 +63,7 @@ impl Operation for DefInitVar {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let value = context.vm.pop(); let value = context.vm.pop();
let binding_locator = context.vm.frame().code.bindings[index as usize]; let binding_locator = context.vm.frame().code_block.bindings[index as usize];
if binding_locator.is_silent() { if binding_locator.is_silent() {
return Ok(ShouldExit::False); return Ok(ShouldExit::False);
} }
@ -100,7 +100,7 @@ impl Operation for DefLet {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code.bindings[index as usize]; let binding_locator = context.vm.frame().code_block.bindings[index as usize];
context.realm.environments.put_value( context.realm.environments.put_value(
binding_locator.environment_index(), binding_locator.environment_index(),
binding_locator.binding_index(), binding_locator.binding_index(),
@ -126,7 +126,7 @@ macro_rules! implement_declaritives {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let value = context.vm.pop(); let value = context.vm.pop();
let binding_locator = context.vm.frame().code.bindings[index as usize]; let binding_locator = context.vm.frame().code_block.bindings[index as usize];
context.realm.environments.put_value( context.realm.environments.put_value(
binding_locator.environment_index(), binding_locator.environment_index(),
binding_locator.binding_index(), binding_locator.binding_index(),

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

@ -24,7 +24,7 @@ impl Operation for DefineOwnPropertyByName {
} else { } else {
object.to_object(context)? object.to_object(context)?
}; };
let name = context.vm.frame().code.names[index as usize]; let name = context.vm.frame().code_block.names[index as usize];
let name = context let name = context
.interner() .interner()
.resolve_expect(name.sym()) .resolve_expect(name.sym())

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

@ -17,7 +17,7 @@ impl Operation for DeletePropertyByName {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let key = context.vm.frame().code.names[index as usize]; let key = context.vm.frame().code_block.names[index as usize];
let key = context let key = context
.interner() .interner()
.resolve_expect(key.sym()) .resolve_expect(key.sym())
@ -25,7 +25,7 @@ impl Operation for DeletePropertyByName {
.into(); .into();
let object = context.vm.pop(); let object = context.vm.pop();
let result = object.to_object(context)?.__delete__(&key, context)?; let result = object.to_object(context)?.__delete__(&key, context)?;
if !result && context.vm.frame().code.strict { if !result && context.vm.frame().code_block.strict {
return Err(JsNativeError::typ() return Err(JsNativeError::typ()
.with_message("Cannot delete property") .with_message("Cannot delete property")
.into()); .into());
@ -52,7 +52,7 @@ impl Operation for DeletePropertyByValue {
let result = object let result = object
.to_object(context)? .to_object(context)?
.__delete__(&key.to_property_key(context)?, context)?; .__delete__(&key.to_property_key(context)?, context)?;
if !result && context.vm.frame().code.strict { if !result && context.vm.frame().code_block.strict {
return Err(JsNativeError::typ() return Err(JsNativeError::typ()
.with_message("Cannot delete property") .with_message("Cannot delete property")
.into()); .into());
@ -75,7 +75,7 @@ impl Operation for DeleteName {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code.bindings[index as usize]; let binding_locator = context.vm.frame().code_block.bindings[index as usize];
binding_locator.throw_mutate_immutable(context)?; binding_locator.throw_mutate_immutable(context)?;
let deleted = if binding_locator.is_global() let deleted = if binding_locator.is_global()
@ -93,7 +93,7 @@ impl Operation for DeleteName {
context, context,
)?; )?;
if !deleted && context.vm.frame().code.strict { if !deleted && context.vm.frame().code_block.strict {
return Err(JsNativeError::typ() return Err(JsNativeError::typ()
.with_message(format!( .with_message(format!(
"property `{}` is non-configurable and cannot be deleted", "property `{}` is non-configurable and cannot be deleted",

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

@ -16,7 +16,7 @@ impl Operation for GetArrowFunction {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let code = context.vm.frame().code.functions[index as usize].clone(); let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_function_object(code, false, true, None, context); let function = create_function_object(code, false, true, None, context);
context.vm.push(function); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
@ -36,7 +36,7 @@ impl Operation for GetAsyncArrowFunction {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let code = context.vm.frame().code.functions[index as usize].clone(); let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_function_object(code, true, true, None, context); let function = create_function_object(code, true, true, None, context);
context.vm.push(function); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
@ -56,7 +56,7 @@ impl Operation for GetFunction {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let code = context.vm.frame().code.functions[index as usize].clone(); let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_function_object(code, false, false, None, context); let function = create_function_object(code, false, false, None, context);
context.vm.push(function); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
@ -76,7 +76,7 @@ impl Operation for GetFunctionAsync {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let code = context.vm.frame().code.functions[index as usize].clone(); let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_function_object(code, true, false, None, context); let function = create_function_object(code, true, false, None, context);
context.vm.push(function); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)

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

@ -16,7 +16,7 @@ impl Operation for GetGenerator {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let code = context.vm.frame().code.functions[index as usize].clone(); let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_generator_function_object(code, false, context); let function = create_generator_function_object(code, false, context);
context.vm.push(function); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)
@ -36,7 +36,7 @@ impl Operation for GetGeneratorAsync {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let code = context.vm.frame().code.functions[index as usize].clone(); let code = context.vm.frame().code_block.functions[index as usize].clone();
let function = create_generator_function_object(code, true, context); let function = create_generator_function_object(code, true, context);
context.vm.push(function); context.vm.push(function);
Ok(ShouldExit::False) Ok(ShouldExit::False)

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

@ -18,7 +18,7 @@ impl Operation for GetName {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code.bindings[index as usize]; let binding_locator = context.vm.frame().code_block.bindings[index as usize];
binding_locator.throw_mutate_immutable(context)?; binding_locator.throw_mutate_immutable(context)?;
let value = if binding_locator.is_global() { let value = if binding_locator.is_global() {
@ -92,7 +92,7 @@ impl Operation for GetNameOrUndefined {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code.bindings[index as usize]; let binding_locator = context.vm.frame().code_block.bindings[index as usize];
binding_locator.throw_mutate_immutable(context)?; binding_locator.throw_mutate_immutable(context)?;
let value = if binding_locator.is_global() { let value = if binding_locator.is_global() {
if let Some(value) = context if let Some(value) = context

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

@ -16,7 +16,7 @@ impl Operation for GetPrivateField {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
let value = context.vm.pop(); let value = context.vm.pop();
let base_obj = value.to_object(context)?; let base_obj = value.to_object(context)?;
let result = base_obj.private_get(&name, context)?; let result = base_obj.private_get(&name, context)?;

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

@ -27,7 +27,7 @@ impl Operation for GetPropertyByName {
let key: PropertyKey = context let key: PropertyKey = context
.interner() .interner()
.resolve_expect(context.vm.frame().code.names[index as usize].sym()) .resolve_expect(context.vm.frame().code_block.names[index as usize].sym())
.into_common::<JsString>(false) .into_common::<JsString>(false)
.into(); .into();
let result = object.__get__(&key, value, context)?; let result = object.__get__(&key, value, context)?;

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

@ -58,7 +58,7 @@ impl Operation for PushClassFieldPrivate {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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

@ -18,7 +18,7 @@ impl Operation for PushClassPrivateMethod {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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");
@ -63,7 +63,7 @@ impl Operation for PushClassPrivateGetter {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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();
@ -101,7 +101,7 @@ impl Operation for PushClassPrivateSetter {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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();

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

@ -17,7 +17,7 @@ impl Operation for PushDeclarativeEnvironment {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let num_bindings = context.vm.read::<u32>(); let num_bindings = context.vm.read::<u32>();
let compile_environments_index = context.vm.read::<u32>(); let compile_environments_index = context.vm.read::<u32>();
let compile_environment = context.vm.frame().code.compile_environments let compile_environment = context.vm.frame().code_block.compile_environments
[compile_environments_index as usize] [compile_environments_index as usize]
.clone(); .clone();
context context
@ -44,7 +44,7 @@ impl Operation for PushFunctionEnvironment {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let num_bindings = context.vm.read::<u32>(); let num_bindings = context.vm.read::<u32>();
let compile_environments_index = context.vm.read::<u32>(); let compile_environments_index = context.vm.read::<u32>();
let compile_environment = context.vm.frame().code.compile_environments let compile_environment = context.vm.frame().code_block.compile_environments
[compile_environments_index as usize] [compile_environments_index as usize]
.clone(); .clone();
context context

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

@ -16,7 +16,7 @@ impl Operation for PushLiteral {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>() as usize; let index = context.vm.read::<u32>() as usize;
let value = context.vm.frame().code.literals[index].clone(); let value = context.vm.frame().code_block.literals[index].clone();
context.vm.push(value); context.vm.push(value);
Ok(ShouldExit::False) Ok(ShouldExit::False)
} }

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

@ -17,7 +17,7 @@ impl Operation for SetName {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let binding_locator = context.vm.frame().code.bindings[index as usize]; let binding_locator = context.vm.frame().code_block.bindings[index as usize];
let value = context.vm.pop(); let value = context.vm.pop();
if binding_locator.is_silent() { if binding_locator.is_silent() {
return Ok(ShouldExit::False); return Ok(ShouldExit::False);
@ -36,7 +36,7 @@ impl Operation for SetName {
.into_common(false); .into_common(false);
let exists = context.global_bindings_mut().contains_key(&key); let exists = context.global_bindings_mut().contains_key(&key);
if !exists && context.vm.frame().code.strict { if !exists && context.vm.frame().code_block.strict {
return Err(JsNativeError::reference() return Err(JsNativeError::reference()
.with_message(format!( .with_message(format!(
"assignment to undeclared variable {}", "assignment to undeclared variable {}",
@ -51,7 +51,7 @@ impl Operation for SetName {
context, context,
)?; )?;
if !success && context.vm.frame().code.strict { if !success && context.vm.frame().code_block.strict {
return Err(JsNativeError::typ() return Err(JsNativeError::typ()
.with_message(format!( .with_message(format!(
"cannot set non-writable property: {}", "cannot set non-writable property: {}",

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

@ -18,7 +18,7 @@ impl Operation for SetPrivateField {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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)?;
@ -41,7 +41,7 @@ impl Operation for DefinePrivateField {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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
@ -68,7 +68,7 @@ impl Operation for SetPrivateMethod {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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");
@ -113,7 +113,7 @@ impl Operation for SetPrivateSetter {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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();
@ -151,7 +151,7 @@ impl Operation for SetPrivateGetter {
fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> { fn execute(context: &mut Context<'_>) -> JsResult<ShouldExit> {
let index = context.vm.read::<u32>(); let index = context.vm.read::<u32>();
let name = context.vm.frame().code.private_names[index as usize]; let name = context.vm.frame().code_block.private_names[index as usize];
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();

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

@ -28,7 +28,7 @@ impl Operation for SetPropertyByName {
object.to_object(context)? object.to_object(context)?
}; };
let name = context.vm.frame().code.names[index as usize]; let name = context.vm.frame().code_block.names[index as usize];
let name: PropertyKey = context let name: PropertyKey = context
.interner() .interner()
.resolve_expect(name.sym()) .resolve_expect(name.sym())
@ -37,7 +37,7 @@ impl Operation for SetPropertyByName {
//object.set(name, value.clone(), context.vm.frame().code.strict, context)?; //object.set(name, value.clone(), context.vm.frame().code.strict, context)?;
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.strict { if !succeeded && context.vm.frame().code_block.strict {
return Err(JsNativeError::typ() return Err(JsNativeError::typ()
.with_message(format!("cannot set non-writable property: {name}")) .with_message(format!("cannot set non-writable property: {name}"))
.into()); .into());
@ -69,7 +69,12 @@ impl Operation for SetPropertyByValue {
}; };
let key = key.to_property_key(context)?; let key = key.to_property_key(context)?;
object.set(key, value.clone(), context.vm.frame().code.strict, context)?; object.set(
key,
value.clone(),
context.vm.frame().code_block.strict,
context,
)?;
context.vm.stack.push(value); context.vm.stack.push(value);
Ok(ShouldExit::False) Ok(ShouldExit::False)
} }
@ -91,7 +96,7 @@ impl Operation for 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.names[index as usize]; let name = context.vm.frame().code_block.names[index as usize];
let name = context let name = context
.interner() .interner()
.resolve_expect(name.sym()) .resolve_expect(name.sym())
@ -168,7 +173,7 @@ impl Operation for 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.names[index as usize]; let name = context.vm.frame().code_block.names[index as usize];
let name = context let name = context
.interner() .interner()
.resolve_expect(name.sym()) .resolve_expect(name.sym())

Loading…
Cancel
Save