Browse Source

Cached `this` value (#3771)

pull/3348/merge
Haled Odat 1 month ago committed by GitHub
parent
commit
fb8e16b2d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      core/engine/src/builtins/function/mod.rs
  2. 9
      core/engine/src/vm/call_frame/mod.rs
  3. 21
      core/engine/src/vm/opcode/control_flow/return.rs
  4. 12
      core/engine/src/vm/opcode/environment/mod.rs

8
core/engine/src/builtins/function/mod.rs

@ -1054,11 +1054,17 @@ fn function_construct(
Some(this)
};
let frame = CallFrame::new(code.clone(), script_or_module, environments, realm)
let mut frame = CallFrame::new(code.clone(), script_or_module, environments, realm)
.with_argument_count(argument_count as u32)
.with_env_fp(env_fp)
.with_flags(CallFrameFlags::CONSTRUCT);
// We push the `this` below so we can mark this function as having the this value
// cached if it's initialized.
frame
.flags
.set(CallFrameFlags::THIS_VALUE_CACHED, this.is_some());
let len = context.vm.stack.len();
context.vm.push_frame(frame);

9
core/engine/src/vm/call_frame/mod.rs

@ -31,6 +31,9 @@ bitflags::bitflags! {
/// Does this [`CallFrame`] need to push registers on [`Vm::push_frame()`].
const REGISTERS_ALREADY_PUSHED = 0b0000_0100;
/// If the `this` value has been cached.
const THIS_VALUE_CACHED = 0b0000_1000;
}
}
@ -323,6 +326,12 @@ impl CallFrame {
self.flags
.contains(CallFrameFlags::REGISTERS_ALREADY_PUSHED)
}
/// Does this [`CallFrame`] have a cached `this` value.
///
/// The cached value is placed in the [`CallFrame::THIS_POSITION`] position.
pub(crate) fn has_this_value_cached(&self) -> bool {
self.flags.contains(CallFrameFlags::THIS_VALUE_CACHED)
}
}
/// ---- `CallFrame` stack methods ----

21
core/engine/src/vm/opcode/control_flow/return.rs

@ -54,16 +54,21 @@ impl Operation for CheckReturn {
);
return Ok(CompletionType::Throw);
} else {
let realm = context.vm.frame().realm.clone();
let this = context.vm.environments.get_this_binding();
let frame = context.vm.frame();
if frame.has_this_value_cached() {
this
} else {
let realm = frame.realm.clone();
let this = context.vm.environments.get_this_binding();
match this {
Err(err) => {
let err = err.inject_realm(realm);
context.vm.pending_exception = Some(err);
return Ok(CompletionType::Throw);
match this {
Err(err) => {
let err = err.inject_realm(realm);
context.vm.pending_exception = Some(err);
return Ok(CompletionType::Throw);
}
Ok(this) => this,
}
Ok(this) => this,
}
};

12
core/engine/src/vm/opcode/environment/mod.rs

@ -2,7 +2,7 @@ use crate::{
builtins::function::OrdinaryFunction,
error::JsNativeError,
object::internal_methods::InternalMethodContext,
vm::{opcode::Operation, CompletionType},
vm::{opcode::Operation, CallFrameFlags, CompletionType},
Context, JsResult, JsValue,
};
@ -19,7 +19,17 @@ impl Operation for This {
const COST: u8 = 1;
fn execute(context: &mut Context) -> JsResult<CompletionType> {
let frame = context.vm.frame_mut();
let this_index = frame.fp();
if frame.has_this_value_cached() {
let this = context.vm.stack[this_index as usize].clone();
context.vm.push(this);
return Ok(CompletionType::Normal);
}
let this = context.vm.environments.get_this_binding()?;
context.vm.frame_mut().flags |= CallFrameFlags::THIS_VALUE_CACHED;
context.vm.stack[this_index as usize] = this.clone();
context.vm.push(this);
Ok(CompletionType::Normal)
}

Loading…
Cancel
Save