Browse Source

Store active runnable and active function in `CallFrame` (#3197)

* Move acrive runnable to CallFrame

* Move active function to CallFrame

* Add some code doc

* Fix doc link

* Apply review
pull/3284/head
Haled Odat 1 year ago committed by GitHub
parent
commit
6a91a85e0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      boa_engine/src/builtins/array/mod.rs
  2. 2
      boa_engine/src/builtins/async_function/mod.rs
  3. 2
      boa_engine/src/builtins/async_generator_function/mod.rs
  4. 4
      boa_engine/src/builtins/error/aggregate.rs
  5. 4
      boa_engine/src/builtins/error/eval.rs
  6. 4
      boa_engine/src/builtins/error/mod.rs
  7. 4
      boa_engine/src/builtins/error/range.rs
  8. 4
      boa_engine/src/builtins/error/reference.rs
  9. 4
      boa_engine/src/builtins/error/syntax.rs
  10. 4
      boa_engine/src/builtins/error/type.rs
  11. 4
      boa_engine/src/builtins/error/uri.rs
  12. 2
      boa_engine/src/builtins/eval/mod.rs
  13. 4
      boa_engine/src/builtins/function/mod.rs
  14. 6
      boa_engine/src/builtins/generator/mod.rs
  15. 2
      boa_engine/src/builtins/generator_function/mod.rs
  16. 4
      boa_engine/src/builtins/intl/collator/mod.rs
  17. 4
      boa_engine/src/builtins/intl/date_time_format.rs
  18. 2
      boa_engine/src/builtins/json/mod.rs
  19. 4
      boa_engine/src/builtins/object/mod.rs
  20. 4
      boa_engine/src/builtins/regexp/mod.rs
  21. 37
      boa_engine/src/context/mod.rs
  22. 11
      boa_engine/src/job.rs
  23. 38
      boa_engine/src/module/source.rs
  24. 14
      boa_engine/src/script.rs
  25. 15
      boa_engine/src/vm/call_frame/mod.rs
  26. 162
      boa_engine/src/vm/code_block.rs
  27. 9
      boa_engine/src/vm/mod.rs
  28. 4
      boa_engine/src/vm/opcode/call/mod.rs
  29. 14
      boa_engine/src/vm/opcode/generator/mod.rs
  30. 2
      boa_engine/src/vm/opcode/meta/mod.rs

4
boa_engine/src/builtins/array/mod.rs

@ -174,9 +174,7 @@ impl BuiltInConstructor for Array {
// If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| context.intrinsics().constructors().array().constructor())
.into()
} else {

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

@ -66,7 +66,7 @@ impl BuiltInConstructor for AsyncFunction {
args: &[JsValue],
context: &mut Context<'_>,
) -> JsResult<JsValue> {
let active_function = context.vm.active_function.clone().unwrap_or_else(|| {
let active_function = context.active_function_object().unwrap_or_else(|| {
context
.intrinsics()
.constructors()

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

@ -71,7 +71,7 @@ impl BuiltInConstructor for AsyncGeneratorFunction {
args: &[JsValue],
context: &mut Context<'_>,
) -> JsResult<JsValue> {
let active_function = context.vm.active_function.clone().unwrap_or_else(|| {
let active_function = context.active_function_object().unwrap_or_else(|| {
context
.intrinsics()
.constructors()

4
boa_engine/src/builtins/error/aggregate.rs

@ -63,9 +63,7 @@ impl BuiltInConstructor for AggregateError {
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| {
context
.intrinsics()

4
boa_engine/src/builtins/error/eval.rs

@ -65,9 +65,7 @@ impl BuiltInConstructor for EvalError {
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| {
context
.intrinsics()

4
boa_engine/src/builtins/error/mod.rs

@ -165,9 +165,7 @@ impl BuiltInConstructor for Error {
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| context.intrinsics().constructors().error().constructor())
.into()
} else {

4
boa_engine/src/builtins/error/range.rs

@ -63,9 +63,7 @@ impl BuiltInConstructor for RangeError {
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| {
context
.intrinsics()

4
boa_engine/src/builtins/error/reference.rs

@ -62,9 +62,7 @@ impl BuiltInConstructor for ReferenceError {
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| {
context
.intrinsics()

4
boa_engine/src/builtins/error/syntax.rs

@ -65,9 +65,7 @@ impl BuiltInConstructor for SyntaxError {
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| {
context
.intrinsics()

4
boa_engine/src/builtins/error/type.rs

@ -73,9 +73,7 @@ impl BuiltInConstructor for TypeError {
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| {
context
.intrinsics()

4
boa_engine/src/builtins/error/uri.rs

@ -64,9 +64,7 @@ impl BuiltInConstructor for UriError {
// 1. If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| {
context
.intrinsics()

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

@ -256,7 +256,7 @@ impl Eval {
let env_fp = context.vm.environments.len() as u32;
context
.vm
.push_frame(CallFrame::new(code_block).with_env_fp(env_fp));
.push_frame(CallFrame::new(code_block, None, None).with_env_fp(env_fp));
context.realm().resize_global_env();
let record = context.run();

4
boa_engine/src/builtins/function/mod.rs

@ -532,9 +532,7 @@ impl BuiltInConstructor for BuiltInFunctionObject {
context: &mut Context<'_>,
) -> JsResult<JsValue> {
let active_function = context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| context.intrinsics().constructors().function().constructor());
Self::create_dynamic_function(active_function, new_target, args, false, false, context)
.map(Into::into)

6
boa_engine/src/builtins/generator/mod.rs

@ -60,7 +60,6 @@ unsafe impl Trace for GeneratorState {
pub(crate) struct GeneratorContext {
pub(crate) environments: EnvironmentStack,
pub(crate) stack: Vec<JsValue>,
pub(crate) active_function: Option<JsObject>,
pub(crate) call_frame: Option<CallFrame>,
pub(crate) realm: Realm,
}
@ -70,14 +69,12 @@ impl GeneratorContext {
pub(crate) fn new(
environments: EnvironmentStack,
stack: Vec<JsValue>,
active_function: Option<JsObject>,
call_frame: CallFrame,
realm: Realm,
) -> Self {
Self {
environments,
stack,
active_function,
call_frame: Some(call_frame),
realm,
}
@ -90,7 +87,6 @@ impl GeneratorContext {
environments: context.vm.environments.clone(),
call_frame: Some(context.vm.frame().clone()),
stack: context.vm.stack[fp..].to_vec(),
active_function: context.vm.active_function.clone(),
realm: context.realm().clone(),
};
@ -108,7 +104,6 @@ impl GeneratorContext {
) -> CompletionRecord {
std::mem::swap(&mut context.vm.environments, &mut self.environments);
std::mem::swap(&mut context.vm.stack, &mut self.stack);
std::mem::swap(&mut context.vm.active_function, &mut self.active_function);
context.swap_realm(&mut self.realm);
context
.vm
@ -125,7 +120,6 @@ impl GeneratorContext {
std::mem::swap(&mut context.vm.environments, &mut self.environments);
std::mem::swap(&mut context.vm.stack, &mut self.stack);
std::mem::swap(&mut context.vm.active_function, &mut self.active_function);
context.swap_realm(&mut self.realm);
self.call_frame = context.vm.pop_frame();
assert!(self.call_frame.is_some());

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

@ -76,7 +76,7 @@ impl BuiltInConstructor for GeneratorFunction {
args: &[JsValue],
context: &mut Context<'_>,
) -> JsResult<JsValue> {
let active_function = context.vm.active_function.clone().unwrap_or_else(|| {
let active_function = context.active_function_object().unwrap_or_else(|| {
context
.intrinsics()
.constructors()

4
boa_engine/src/builtins/intl/collator/mod.rs

@ -216,9 +216,7 @@ impl BuiltInConstructor for Collator {
// 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| context.intrinsics().constructors().collator().constructor())
.into()
} else {

4
boa_engine/src/builtins/intl/date_time_format.rs

@ -99,9 +99,7 @@ impl BuiltInConstructor for DateTimeFormat {
// 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() {
context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| {
context
.intrinsics()

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

@ -131,7 +131,7 @@ impl Json {
let env_fp = context.vm.environments.len() as u32;
context
.vm
.push_frame(CallFrame::new(code_block).with_env_fp(env_fp));
.push_frame(CallFrame::new(code_block, None, None).with_env_fp(env_fp));
context.realm().resize_global_env();
let record = context.run();
context.vm.pop_frame();

4
boa_engine/src/builtins/object/mod.rs

@ -131,9 +131,7 @@ impl BuiltInConstructor for Object {
if !new_target.is_undefined()
&& new_target
!= &context
.vm
.active_function
.clone()
.active_function_object()
.unwrap_or_else(|| context.intrinsics().constructors().object().constructor())
.into()
{

4
boa_engine/src/builtins/regexp/mod.rs

@ -172,9 +172,7 @@ impl BuiltInConstructor for RegExp {
if new_target.is_undefined() {
// a. Let newTarget be the active function object.
let new_target = context
.vm
.active_function
.clone()
.active_function_object()
.map_or(JsValue::undefined(), JsValue::new);
// b. If patternIsRegExp is true and flags is undefined, then

37
boa_engine/src/context/mod.rs

@ -27,7 +27,7 @@ use crate::{
property::{Attribute, PropertyDescriptor, PropertyKey},
realm::Realm,
script::Script,
vm::{CallFrame, Vm},
vm::{ActiveRunnable, CallFrame, Vm},
JsResult, JsValue, Source,
};
use boa_ast::{expression::Identifier, StatementList};
@ -706,6 +706,41 @@ impl Context<'_> {
pub(crate) const fn is_strict(&self) -> bool {
self.strict
}
/// `9.4.1 GetActiveScriptOrModule ( )`
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-getactivescriptormodule
pub(crate) fn get_active_script_or_module(&self) -> Option<ActiveRunnable> {
// 1. If the execution context stack is empty, return null.
// 2. Let ec be the topmost execution context on the execution context stack whose ScriptOrModule component is not null.
// 3. If no such execution context exists, return null. Otherwise, return ec's ScriptOrModule.
self.vm
.frames
.iter()
.rev()
.find_map(|frame| frame.active_runnable.clone())
}
/// Get `active function object`
///
/// More information:
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#active-function-object
pub(crate) fn active_function_object(&self) -> Option<JsObject> {
if self.vm.native_active_function.is_some() {
return self.vm.native_active_function.clone();
}
if let Some(frame) = self.vm.frames.last() {
return frame.active_function.clone();
}
None
}
}
impl<'host> Context<'host> {

11
boa_engine/src/job.rs

@ -22,7 +22,6 @@ use std::{any::Any, cell::RefCell, collections::VecDeque, fmt::Debug, future::Fu
use crate::{
object::{JsFunction, NativeObject},
realm::Realm,
vm::ActiveRunnable,
Context, JsResult, JsValue,
};
use boa_gc::{Finalize, Trace};
@ -69,7 +68,6 @@ pub struct NativeJob {
#[allow(clippy::type_complexity)]
f: Box<dyn FnOnce(&mut Context<'_>) -> JsResult<JsValue>>,
realm: Option<Realm>,
active_runnable: Option<ActiveRunnable>,
}
impl Debug for NativeJob {
@ -87,19 +85,17 @@ impl NativeJob {
Self {
f: Box::new(f),
realm: None,
active_runnable: None,
}
}
/// Creates a new `NativeJob` from a closure and an execution realm.
pub fn with_realm<F>(f: F, realm: Realm, context: &mut Context<'_>) -> Self
pub fn with_realm<F>(f: F, realm: Realm, _context: &mut Context<'_>) -> Self
where
F: FnOnce(&mut Context<'_>) -> JsResult<JsValue> + 'static,
{
Self {
f: Box::new(f),
realm: Some(realm),
active_runnable: context.vm.active_runnable.clone(),
}
}
@ -115,7 +111,7 @@ impl NativeJob {
///
/// If the native job has an execution realm defined, this sets the running execution
/// context to the realm's before calling the inner closure, and resets it after execution.
pub fn call(mut self, context: &mut Context<'_>) -> JsResult<JsValue> {
pub fn call(self, context: &mut Context<'_>) -> JsResult<JsValue> {
// If realm is not null, each time job is invoked the implementation must perform
// implementation-defined steps such that execution is prepared to evaluate ECMAScript
// code at the time of job's invocation.
@ -126,12 +122,9 @@ impl NativeJob {
// invoked. If realm is not null, each time job is invoked the implementation must
// perform implementation-defined steps such that scriptOrModule is the active script or
// module at the time of job's invocation.
std::mem::swap(&mut context.vm.active_runnable, &mut self.active_runnable);
let result = (self.f)(context);
context.enter_realm(old_realm);
std::mem::swap(&mut context.vm.active_runnable, &mut self.active_runnable);
result
} else {

38
boa_engine/src/module/source.rs

@ -1607,20 +1607,19 @@ impl SourceTextModule {
let mut envs = EnvironmentStack::new(global_env);
envs.push_module(module_compile_env);
// 9. Set the Function of moduleContext to null.
// 12. Set the ScriptOrModule of moduleContext to module.
let active_runnable = context
.vm
.active_runnable
.replace(ActiveRunnable::Module(parent.clone()));
let call_frame = CallFrame::new(
codeblock.clone(),
Some(ActiveRunnable::Module(parent.clone())),
None,
);
context.vm.push_frame(call_frame);
// 13. Set the VariableEnvironment of moduleContext to module.[[Environment]].
// 14. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
// 15. Set the PrivateEnvironment of moduleContext to null.
std::mem::swap(&mut context.vm.environments, &mut envs);
let stack = std::mem::take(&mut context.vm.stack);
// 9. Set the Function of moduleContext to null.
let active_function = context.vm.active_function.take();
// 10. Assert: module.[[Realm]] is not undefined.
// 11. Set the Realm of moduleContext to module.[[Realm]].
@ -1682,10 +1681,11 @@ impl SourceTextModule {
}
// 25. Remove moduleContext from the execution context stack.
context
.vm
.pop_frame()
.expect("There should be a call frame");
std::mem::swap(&mut context.vm.environments, &mut envs);
context.vm.stack = stack;
context.vm.active_function = active_function;
context.vm.active_runnable = active_runnable;
context.swap_realm(&mut realm);
debug_assert!(envs.current().as_declarative().is_some());
@ -1733,22 +1733,18 @@ impl SourceTextModule {
_ => unreachable!("`execute` should only be called for evaluating modules."),
};
// 2. Set the Function of moduleContext to null.
// 4. Set the ScriptOrModule of moduleContext to module.
let env_fp = environments.len() as u32;
let mut callframe = CallFrame::new(codeblock).with_env_fp(env_fp);
let mut callframe =
CallFrame::new(codeblock, Some(ActiveRunnable::Module(self.parent())), None)
.with_env_fp(env_fp);
callframe.promise_capability = capability;
// 4. Set the ScriptOrModule of moduleContext to module.
let active_runnable = context
.vm
.active_runnable
.replace(ActiveRunnable::Module(self.parent()));
// 5. Assert: module has been linked and declarations in its module environment have been instantiated.
// 6. Set the VariableEnvironment of moduleContext to module.[[Environment]].
// 7. Set the LexicalEnvironment of moduleContext to module.[[Environment]].
std::mem::swap(&mut context.vm.environments, &mut environments);
// 2. Set the Function of moduleContext to null.
let function = context.vm.active_function.take();
// 3. Set the Realm of moduleContext to module.[[Realm]].
context.swap_realm(&mut realm);
// 8. Suspend the running execution context.
@ -1766,8 +1762,6 @@ impl SourceTextModule {
let result = context.run();
std::mem::swap(&mut context.vm.environments, &mut environments);
context.vm.active_function = function;
context.vm.active_runnable = active_runnable;
context.swap_realm(&mut realm);
context.vm.pop_frame();

14
boa_engine/src/script.rs

@ -138,15 +138,11 @@ impl Script {
let codeblock = self.codeblock(context)?;
let old_realm = context.enter_realm(self.inner.realm.clone());
let active_function = context.vm.active_function.take();
let old_active = context
.vm
.active_runnable
.replace(ActiveRunnable::Script(self.clone()));
let env_fp = context.vm.environments.len() as u32;
context
.vm
.push_frame(CallFrame::new(codeblock).with_env_fp(env_fp));
context.vm.push_frame(
CallFrame::new(codeblock, Some(ActiveRunnable::Script(self.clone())), None)
.with_env_fp(env_fp),
);
// TODO: Here should be https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
@ -154,8 +150,6 @@ impl Script {
let record = context.run();
context.vm.pop_frame();
context.vm.active_function = active_function;
context.vm.active_runnable = old_active;
context.enter_realm(old_realm);
context.clear_kept_objects();

15
boa_engine/src/vm/call_frame/mod.rs

@ -12,6 +12,8 @@ use crate::{
use boa_gc::{Finalize, Gc, Trace};
use thin_vec::ThinVec;
use super::ActiveRunnable;
/// A `CallFrame` holds the state of a function call.
#[derive(Clone, Debug, Finalize, Trace)]
pub struct CallFrame {
@ -36,6 +38,11 @@ pub struct CallFrame {
/// How many iterations a loop has done.
pub(crate) loop_iteration_count: u64,
/// \[\[ScriptOrModule\]\]
pub(crate) active_runnable: Option<ActiveRunnable>,
pub(crate) active_function: Option<JsObject>,
}
/// ---- `CallFrame` public API ----
@ -51,7 +58,11 @@ impl CallFrame {
/// ---- `CallFrame` creation methods ----
impl CallFrame {
/// Creates a new `CallFrame` with the provided `CodeBlock`.
pub(crate) fn new(code_block: Gc<CodeBlock>) -> Self {
pub(crate) fn new(
code_block: Gc<CodeBlock>,
active_runnable: Option<ActiveRunnable>,
active_function: Option<JsObject>,
) -> Self {
Self {
code_block,
pc: 0,
@ -63,6 +74,8 @@ impl CallFrame {
iterators: ThinVec::new(),
binding_stack: Vec::new(),
loop_iteration_count: 0,
active_runnable,
active_function,
}
}

162
boa_engine/src/vm/code_block.rs

@ -758,7 +758,7 @@ pub(crate) fn create_function_object(
let name: JsValue = code.name().clone().into();
let length: JsValue = code.length.into();
let script_or_module = context.vm.active_runnable.clone();
let script_or_module = context.get_active_script_or_module();
let function = if r#async {
Function::new(
@ -838,7 +838,7 @@ pub(crate) fn create_function_object_fast(
let name: JsValue = code.name().clone().into();
let length: JsValue = code.length.into();
let script_or_module = context.vm.active_runnable.clone();
let script_or_module = context.get_active_script_or_module();
let function = if r#async {
FunctionKind::Async {
@ -943,7 +943,7 @@ pub(crate) fn create_generator_function_object(
ObjectData::ordinary(),
);
let script_or_module = context.vm.active_runnable.clone();
let script_or_module = context.get_active_script_or_module();
let constructor = if r#async {
let function = Function::new(
@ -1007,87 +1007,89 @@ impl JsObject {
context: &mut Context<'_>,
) -> JsResult<JsValue> {
let old_realm = context.realm().clone();
let old_active_fn = context.vm.active_function.clone();
let context = &mut context.guard(move |ctx| {
ctx.enter_realm(old_realm);
ctx.vm.active_function = old_active_fn;
});
let this_function_object = self.clone();
let active_function = self.clone();
let object = self.borrow();
let function_object = object.as_function().expect("not a function");
let realm = function_object.realm().clone();
context.enter_realm(realm);
context.vm.active_function = Some(active_function);
let (code, mut environments, class_object, mut script_or_module) =
match function_object.kind() {
FunctionKind::Native {
function,
constructor,
} => {
let function = function.clone();
let constructor = *constructor;
drop(object);
return if constructor.is_some() {
function.call(&JsValue::undefined(), args, context)
} else {
function.call(this, args, context)
}
.map_err(|err| err.inject_realm(context.realm().clone()));
}
FunctionKind::Ordinary {
code,
environments,
class_object,
script_or_module,
..
} => {
let code = code.clone();
if code.is_class_constructor() {
return Err(JsNativeError::typ()
.with_message("class constructor cannot be invoked without 'new'")
.with_realm(context.realm().clone())
.into());
}
(
code,
environments.clone(),
class_object.clone(),
script_or_module.clone(),
)
}
FunctionKind::Async {
code,
environments,
class_object,
script_or_module,
..
let (code, mut environments, class_object, script_or_module) = match function_object.kind()
{
FunctionKind::Native {
function,
constructor,
} => {
let function = function.clone();
let constructor = *constructor;
drop(object);
context.vm.native_active_function = Some(this_function_object);
let result = if constructor.is_some() {
function.call(&JsValue::undefined(), args, context)
} else {
function.call(this, args, context)
}
| FunctionKind::Generator {
code,
environments,
class_object,
script_or_module,
..
.map_err(|err| err.inject_realm(context.realm().clone()));
context.vm.native_active_function = None;
return result;
}
FunctionKind::Ordinary {
code,
environments,
class_object,
script_or_module,
..
} => {
let code = code.clone();
if code.is_class_constructor() {
return Err(JsNativeError::typ()
.with_message("class constructor cannot be invoked without 'new'")
.with_realm(context.realm().clone())
.into());
}
| FunctionKind::AsyncGenerator {
(
code,
environments,
class_object,
script_or_module,
..
} => (
code.clone(),
environments.clone(),
class_object.clone(),
script_or_module.clone(),
),
};
)
}
FunctionKind::Async {
code,
environments,
class_object,
script_or_module,
..
}
| FunctionKind::Generator {
code,
environments,
class_object,
script_or_module,
..
}
| FunctionKind::AsyncGenerator {
code,
environments,
class_object,
script_or_module,
..
} => (
code.clone(),
environments.clone(),
class_object.clone(),
script_or_module.clone(),
),
};
drop(object);
@ -1185,12 +1187,10 @@ impl JsObject {
let argument_count = args.len();
let parameters_count = code.params.as_ref().len();
let frame = CallFrame::new(code)
let frame = CallFrame::new(code, script_or_module, Some(self.clone()))
.with_argument_count(argument_count as u32)
.with_env_fp(env_fp);
std::mem::swap(&mut context.vm.active_runnable, &mut script_or_module);
context.vm.push_frame(frame);
// Push function arguments to the stack.
@ -1206,7 +1206,6 @@ impl JsObject {
context.vm.pop_frame().expect("frame must exist");
std::mem::swap(&mut environments, &mut context.vm.environments);
std::mem::swap(&mut context.vm.active_runnable, &mut script_or_module);
result
}
@ -1218,20 +1217,16 @@ impl JsObject {
context: &mut Context<'_>,
) -> JsResult<Self> {
let old_realm = context.realm().clone();
let old_active_fn = context.vm.active_function.clone();
let context = &mut context.guard(move |ctx| {
ctx.enter_realm(old_realm);
ctx.vm.active_function = old_active_fn;
});
let this_function_object = self.clone();
let active_function = self.clone();
let object = self.borrow();
let function_object = object.as_function().expect("not a function");
let realm = function_object.realm().clone();
context.enter_realm(realm);
context.vm.active_function = Some(active_function);
match function_object.kind() {
FunctionKind::Native {
@ -1243,7 +1238,9 @@ impl JsObject {
let constructor = *constructor;
drop(object);
function
context.vm.native_active_function = Some(this_function_object);
let result = function
.call(this_target, args, context)
.map_err(|err| err.inject_realm(context.realm().clone()))
.and_then(|v| match v {
@ -1270,7 +1267,11 @@ impl JsObject {
.into())
}
}
})
});
context.vm.native_active_function = None;
result
}
FunctionKind::Ordinary {
code,
@ -1281,7 +1282,7 @@ impl JsObject {
} => {
let code = code.clone();
let mut environments = environments.clone();
let mut script_or_module = script_or_module.clone();
let script_or_module = script_or_module.clone();
let constructor_kind = *constructor_kind;
drop(object);
@ -1384,10 +1385,8 @@ impl JsObject {
let has_binding_identifier = code.has_binding_identifier();
std::mem::swap(&mut context.vm.active_runnable, &mut script_or_module);
context.vm.push_frame(
CallFrame::new(code)
CallFrame::new(code, script_or_module, Some(self.clone()))
.with_argument_count(argument_count as u32)
.with_env_fp(environments_len as u32),
);
@ -1403,7 +1402,6 @@ impl JsObject {
context.vm.pop_frame();
std::mem::swap(&mut environments, &mut context.vm.environments);
std::mem::swap(&mut context.vm.active_runnable, &mut script_or_module);
let environment = if has_binding_identifier {
environments.truncate(environments_len + 2);

9
boa_engine/src/vm/mod.rs

@ -69,8 +69,10 @@ pub struct Vm {
pub(crate) pending_exception: Option<JsError>,
pub(crate) environments: EnvironmentStack,
pub(crate) runtime_limits: RuntimeLimits,
pub(crate) active_function: Option<JsObject>,
pub(crate) active_runnable: Option<ActiveRunnable>,
/// This is used to assign a native (rust) function as the active function,
/// because we don't push a frame for them.
pub(crate) native_active_function: Option<JsObject>,
#[cfg(feature = "trace")]
pub(crate) trace: bool,
@ -102,8 +104,7 @@ impl Vm {
environments: EnvironmentStack::new(global),
pending_exception: None,
runtime_limits: RuntimeLimits::default(),
active_function: None,
active_runnable: None,
native_active_function: None,
#[cfg(feature = "trace")]
trace: false,
}

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

@ -272,9 +272,7 @@ impl Operation for ImportCall {
// 1. Let referrer be GetActiveScriptOrModule().
// 2. If referrer is null, set referrer to the current Realm Record.
let referrer = context
.vm
.active_runnable
.clone()
.get_active_script_or_module()
.map_or_else(|| Referrer::Realm(context.realm().clone()), Into::into);
// 3. Let argRef be ? Evaluation of AssignmentExpression.

14
boa_engine/src/vm/opcode/generator/mod.rs

@ -38,8 +38,11 @@ impl Operation for Generator {
let r#async = context.vm.read::<u8>() != 0;
let code_block = context.vm.frame().code_block().clone();
let active_runnable = context.vm.frame().active_runnable.clone();
let active_function = context.vm.frame().active_function.clone();
let pc = context.vm.frame().pc;
let mut dummy_call_frame = CallFrame::new(code_block);
let mut dummy_call_frame =
CallFrame::new(code_block, active_runnable, active_function.clone());
dummy_call_frame.pc = pc;
let mut call_frame = std::mem::replace(context.vm.frame_mut(), dummy_call_frame);
@ -50,11 +53,8 @@ impl Operation for Generator {
call_frame.fp = 0;
let this_function_object = context
.vm
.active_function
.clone()
.expect("active function should be set to the generator");
let this_function_object =
active_function.expect("active function should be set to the generator");
let proto = this_function_object
.get(PROTOTYPE, context)
@ -83,7 +83,6 @@ impl Operation for Generator {
context: Some(GeneratorContext::new(
environments,
stack,
context.vm.active_function.clone(),
call_frame,
context.realm().clone(),
)),
@ -95,7 +94,6 @@ impl Operation for Generator {
context: GeneratorContext::new(
environments,
stack,
context.vm.active_function.clone(),
call_frame,
context.realm().clone(),
),

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

@ -54,7 +54,7 @@ impl Operation for ImportMeta {
// 1. Let module be GetActiveScriptOrModule().
let Some(ActiveRunnable::Module(module)) = context.vm.active_runnable.clone() else {
let Some(ActiveRunnable::Module(module)) = context.get_active_script_or_module() else {
unreachable!("2. Assert: module is a Source Text Module Record.");
};

Loading…
Cancel
Save