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. 48
      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. // If NewTarget is undefined, let newTarget be the active function object; else let newTarget be NewTarget.
let new_target = &if new_target.is_undefined() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| context.intrinsics().constructors().array().constructor()) .unwrap_or_else(|| context.intrinsics().constructors().array().constructor())
.into() .into()
} else { } else {

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

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

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

@ -71,7 +71,7 @@ impl BuiltInConstructor for AsyncGeneratorFunction {
args: &[JsValue], args: &[JsValue],
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsResult<JsValue> { ) -> JsResult<JsValue> {
let active_function = context.vm.active_function.clone().unwrap_or_else(|| { let active_function = context.active_function_object().unwrap_or_else(|| {
context context
.intrinsics() .intrinsics()
.constructors() .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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| { .unwrap_or_else(|| {
context context
.intrinsics() .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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| { .unwrap_or_else(|| {
context context
.intrinsics() .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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| context.intrinsics().constructors().error().constructor()) .unwrap_or_else(|| context.intrinsics().constructors().error().constructor())
.into() .into()
} else { } 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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| { .unwrap_or_else(|| {
context context
.intrinsics() .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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| { .unwrap_or_else(|| {
context context
.intrinsics() .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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| { .unwrap_or_else(|| {
context context
.intrinsics() .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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| { .unwrap_or_else(|| {
context context
.intrinsics() .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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| { .unwrap_or_else(|| {
context context
.intrinsics() .intrinsics()

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

@ -256,7 +256,7 @@ impl Eval {
let env_fp = context.vm.environments.len() as u32; let env_fp = context.vm.environments.len() as u32;
context context
.vm .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(); context.realm().resize_global_env();
let record = context.run(); let record = context.run();

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

@ -532,9 +532,7 @@ impl BuiltInConstructor for BuiltInFunctionObject {
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsResult<JsValue> { ) -> JsResult<JsValue> {
let active_function = context let active_function = context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| context.intrinsics().constructors().function().constructor()); .unwrap_or_else(|| context.intrinsics().constructors().function().constructor());
Self::create_dynamic_function(active_function, new_target, args, false, false, context) Self::create_dynamic_function(active_function, new_target, args, false, false, context)
.map(Into::into) .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) struct GeneratorContext {
pub(crate) environments: EnvironmentStack, pub(crate) environments: EnvironmentStack,
pub(crate) stack: Vec<JsValue>, pub(crate) stack: Vec<JsValue>,
pub(crate) active_function: Option<JsObject>,
pub(crate) call_frame: Option<CallFrame>, pub(crate) call_frame: Option<CallFrame>,
pub(crate) realm: Realm, pub(crate) realm: Realm,
} }
@ -70,14 +69,12 @@ impl GeneratorContext {
pub(crate) fn new( pub(crate) fn new(
environments: EnvironmentStack, environments: EnvironmentStack,
stack: Vec<JsValue>, stack: Vec<JsValue>,
active_function: Option<JsObject>,
call_frame: CallFrame, call_frame: CallFrame,
realm: Realm, realm: Realm,
) -> Self { ) -> Self {
Self { Self {
environments, environments,
stack, stack,
active_function,
call_frame: Some(call_frame), call_frame: Some(call_frame),
realm, realm,
} }
@ -90,7 +87,6 @@ impl GeneratorContext {
environments: context.vm.environments.clone(), environments: context.vm.environments.clone(),
call_frame: Some(context.vm.frame().clone()), call_frame: Some(context.vm.frame().clone()),
stack: context.vm.stack[fp..].to_vec(), stack: context.vm.stack[fp..].to_vec(),
active_function: context.vm.active_function.clone(),
realm: context.realm().clone(), realm: context.realm().clone(),
}; };
@ -108,7 +104,6 @@ impl GeneratorContext {
) -> CompletionRecord { ) -> CompletionRecord {
std::mem::swap(&mut context.vm.environments, &mut self.environments); 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.stack, &mut self.stack);
std::mem::swap(&mut context.vm.active_function, &mut self.active_function);
context.swap_realm(&mut self.realm); context.swap_realm(&mut self.realm);
context context
.vm .vm
@ -125,7 +120,6 @@ impl GeneratorContext {
std::mem::swap(&mut context.vm.environments, &mut self.environments); 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.stack, &mut self.stack);
std::mem::swap(&mut context.vm.active_function, &mut self.active_function);
context.swap_realm(&mut self.realm); context.swap_realm(&mut self.realm);
self.call_frame = context.vm.pop_frame(); self.call_frame = context.vm.pop_frame();
assert!(self.call_frame.is_some()); 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], args: &[JsValue],
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsResult<JsValue> { ) -> JsResult<JsValue> {
let active_function = context.vm.active_function.clone().unwrap_or_else(|| { let active_function = context.active_function_object().unwrap_or_else(|| {
context context
.intrinsics() .intrinsics()
.constructors() .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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| context.intrinsics().constructors().collator().constructor()) .unwrap_or_else(|| context.intrinsics().constructors().collator().constructor())
.into() .into()
} else { } 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. // 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() { let new_target = &if new_target.is_undefined() {
context context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| { .unwrap_or_else(|| {
context context
.intrinsics() .intrinsics()

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

@ -131,7 +131,7 @@ impl Json {
let env_fp = context.vm.environments.len() as u32; let env_fp = context.vm.environments.len() as u32;
context context
.vm .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(); context.realm().resize_global_env();
let record = context.run(); let record = context.run();
context.vm.pop_frame(); 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() if !new_target.is_undefined()
&& new_target && new_target
!= &context != &context
.vm .active_function_object()
.active_function
.clone()
.unwrap_or_else(|| context.intrinsics().constructors().object().constructor()) .unwrap_or_else(|| context.intrinsics().constructors().object().constructor())
.into() .into()
{ {

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

@ -172,9 +172,7 @@ impl BuiltInConstructor for RegExp {
if new_target.is_undefined() { if new_target.is_undefined() {
// a. Let newTarget be the active function object. // a. Let newTarget be the active function object.
let new_target = context let new_target = context
.vm .active_function_object()
.active_function
.clone()
.map_or(JsValue::undefined(), JsValue::new); .map_or(JsValue::undefined(), JsValue::new);
// b. If patternIsRegExp is true and flags is undefined, then // 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}, property::{Attribute, PropertyDescriptor, PropertyKey},
realm::Realm, realm::Realm,
script::Script, script::Script,
vm::{CallFrame, Vm}, vm::{ActiveRunnable, CallFrame, Vm},
JsResult, JsValue, Source, JsResult, JsValue, Source,
}; };
use boa_ast::{expression::Identifier, StatementList}; use boa_ast::{expression::Identifier, StatementList};
@ -706,6 +706,41 @@ impl Context<'_> {
pub(crate) const fn is_strict(&self) -> bool { pub(crate) const fn is_strict(&self) -> bool {
self.strict 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> { 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::{ use crate::{
object::{JsFunction, NativeObject}, object::{JsFunction, NativeObject},
realm::Realm, realm::Realm,
vm::ActiveRunnable,
Context, JsResult, JsValue, Context, JsResult, JsValue,
}; };
use boa_gc::{Finalize, Trace}; use boa_gc::{Finalize, Trace};
@ -69,7 +68,6 @@ pub struct NativeJob {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
f: Box<dyn FnOnce(&mut Context<'_>) -> JsResult<JsValue>>, f: Box<dyn FnOnce(&mut Context<'_>) -> JsResult<JsValue>>,
realm: Option<Realm>, realm: Option<Realm>,
active_runnable: Option<ActiveRunnable>,
} }
impl Debug for NativeJob { impl Debug for NativeJob {
@ -87,19 +85,17 @@ impl NativeJob {
Self { Self {
f: Box::new(f), f: Box::new(f),
realm: None, realm: None,
active_runnable: None,
} }
} }
/// Creates a new `NativeJob` from a closure and an execution realm. /// 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 where
F: FnOnce(&mut Context<'_>) -> JsResult<JsValue> + 'static, F: FnOnce(&mut Context<'_>) -> JsResult<JsValue> + 'static,
{ {
Self { Self {
f: Box::new(f), f: Box::new(f),
realm: Some(realm), 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 /// 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. /// 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 // 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 // implementation-defined steps such that execution is prepared to evaluate ECMAScript
// code at the time of job's invocation. // 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 // 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 // perform implementation-defined steps such that scriptOrModule is the active script or
// module at the time of job's invocation. // 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); let result = (self.f)(context);
context.enter_realm(old_realm); context.enter_realm(old_realm);
std::mem::swap(&mut context.vm.active_runnable, &mut self.active_runnable);
result result
} else { } else {

38
boa_engine/src/module/source.rs

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

14
boa_engine/src/script.rs

@ -138,15 +138,11 @@ impl Script {
let codeblock = self.codeblock(context)?; let codeblock = self.codeblock(context)?;
let old_realm = context.enter_realm(self.inner.realm.clone()); 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; let env_fp = context.vm.environments.len() as u32;
context context.vm.push_frame(
.vm CallFrame::new(codeblock, Some(ActiveRunnable::Script(self.clone())), None)
.push_frame(CallFrame::new(codeblock).with_env_fp(env_fp)); .with_env_fp(env_fp),
);
// TODO: Here should be https://tc39.es/ecma262/#sec-globaldeclarationinstantiation // TODO: Here should be https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
@ -154,8 +150,6 @@ impl Script {
let record = context.run(); let record = context.run();
context.vm.pop_frame(); context.vm.pop_frame();
context.vm.active_function = active_function;
context.vm.active_runnable = old_active;
context.enter_realm(old_realm); context.enter_realm(old_realm);
context.clear_kept_objects(); 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 boa_gc::{Finalize, Gc, Trace};
use thin_vec::ThinVec; use thin_vec::ThinVec;
use super::ActiveRunnable;
/// 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 {
@ -36,6 +38,11 @@ pub struct CallFrame {
/// How many iterations a loop has done. /// How many iterations a loop has done.
pub(crate) loop_iteration_count: u64, pub(crate) loop_iteration_count: u64,
/// \[\[ScriptOrModule\]\]
pub(crate) active_runnable: Option<ActiveRunnable>,
pub(crate) active_function: Option<JsObject>,
} }
/// ---- `CallFrame` public API ---- /// ---- `CallFrame` public API ----
@ -51,7 +58,11 @@ impl CallFrame {
/// ---- `CallFrame` creation methods ---- /// ---- `CallFrame` creation methods ----
impl CallFrame { impl CallFrame {
/// Creates a new `CallFrame` with the provided `CodeBlock`. /// 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 { Self {
code_block, code_block,
pc: 0, pc: 0,
@ -63,6 +74,8 @@ impl CallFrame {
iterators: ThinVec::new(), iterators: ThinVec::new(),
binding_stack: Vec::new(), binding_stack: Vec::new(),
loop_iteration_count: 0, loop_iteration_count: 0,
active_runnable,
active_function,
} }
} }

48
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 name: JsValue = code.name().clone().into();
let length: JsValue = code.length.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 { let function = if r#async {
Function::new( Function::new(
@ -838,7 +838,7 @@ pub(crate) fn create_function_object_fast(
let name: JsValue = code.name().clone().into(); let name: JsValue = code.name().clone().into();
let length: JsValue = code.length.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 { let function = if r#async {
FunctionKind::Async { FunctionKind::Async {
@ -943,7 +943,7 @@ pub(crate) fn create_generator_function_object(
ObjectData::ordinary(), 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 constructor = if r#async {
let function = Function::new( let function = Function::new(
@ -1007,24 +1007,20 @@ impl JsObject {
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsResult<JsValue> { ) -> JsResult<JsValue> {
let old_realm = context.realm().clone(); let old_realm = context.realm().clone();
let old_active_fn = context.vm.active_function.clone();
let context = &mut context.guard(move |ctx| { let context = &mut context.guard(move |ctx| {
ctx.enter_realm(old_realm); ctx.enter_realm(old_realm);
ctx.vm.active_function = old_active_fn;
}); });
let this_function_object = self.clone(); let this_function_object = self.clone();
let active_function = self.clone();
let object = self.borrow(); let object = self.borrow();
let function_object = object.as_function().expect("not a function"); let function_object = object.as_function().expect("not a function");
let realm = function_object.realm().clone(); let realm = function_object.realm().clone();
context.enter_realm(realm); context.enter_realm(realm);
context.vm.active_function = Some(active_function);
let (code, mut environments, class_object, mut script_or_module) = let (code, mut environments, class_object, script_or_module) = match function_object.kind()
match function_object.kind() { {
FunctionKind::Native { FunctionKind::Native {
function, function,
constructor, constructor,
@ -1033,12 +1029,18 @@ impl JsObject {
let constructor = *constructor; let constructor = *constructor;
drop(object); drop(object);
return if constructor.is_some() { context.vm.native_active_function = Some(this_function_object);
let result = if constructor.is_some() {
function.call(&JsValue::undefined(), args, context) function.call(&JsValue::undefined(), args, context)
} else { } else {
function.call(this, args, context) function.call(this, args, context)
} }
.map_err(|err| err.inject_realm(context.realm().clone())); .map_err(|err| err.inject_realm(context.realm().clone()));
context.vm.native_active_function = None;
return result;
} }
FunctionKind::Ordinary { FunctionKind::Ordinary {
code, code,
@ -1185,12 +1187,10 @@ impl JsObject {
let argument_count = args.len(); let argument_count = args.len();
let parameters_count = code.params.as_ref().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_argument_count(argument_count as u32)
.with_env_fp(env_fp); .with_env_fp(env_fp);
std::mem::swap(&mut context.vm.active_runnable, &mut script_or_module);
context.vm.push_frame(frame); context.vm.push_frame(frame);
// Push function arguments to the stack. // Push function arguments to the stack.
@ -1206,7 +1206,6 @@ impl JsObject {
context.vm.pop_frame().expect("frame must exist"); context.vm.pop_frame().expect("frame must exist");
std::mem::swap(&mut environments, &mut context.vm.environments); std::mem::swap(&mut environments, &mut context.vm.environments);
std::mem::swap(&mut context.vm.active_runnable, &mut script_or_module);
result result
} }
@ -1218,20 +1217,16 @@ impl JsObject {
context: &mut Context<'_>, context: &mut Context<'_>,
) -> JsResult<Self> { ) -> JsResult<Self> {
let old_realm = context.realm().clone(); let old_realm = context.realm().clone();
let old_active_fn = context.vm.active_function.clone();
let context = &mut context.guard(move |ctx| { let context = &mut context.guard(move |ctx| {
ctx.enter_realm(old_realm); ctx.enter_realm(old_realm);
ctx.vm.active_function = old_active_fn;
}); });
let this_function_object = self.clone(); let this_function_object = self.clone();
let active_function = self.clone();
let object = self.borrow(); let object = self.borrow();
let function_object = object.as_function().expect("not a function"); let function_object = object.as_function().expect("not a function");
let realm = function_object.realm().clone(); let realm = function_object.realm().clone();
context.enter_realm(realm); context.enter_realm(realm);
context.vm.active_function = Some(active_function);
match function_object.kind() { match function_object.kind() {
FunctionKind::Native { FunctionKind::Native {
@ -1243,7 +1238,9 @@ impl JsObject {
let constructor = *constructor; let constructor = *constructor;
drop(object); drop(object);
function context.vm.native_active_function = Some(this_function_object);
let result = function
.call(this_target, args, context) .call(this_target, args, context)
.map_err(|err| err.inject_realm(context.realm().clone())) .map_err(|err| err.inject_realm(context.realm().clone()))
.and_then(|v| match v { .and_then(|v| match v {
@ -1270,7 +1267,11 @@ impl JsObject {
.into()) .into())
} }
} }
}) });
context.vm.native_active_function = None;
result
} }
FunctionKind::Ordinary { FunctionKind::Ordinary {
code, code,
@ -1281,7 +1282,7 @@ impl JsObject {
} => { } => {
let code = code.clone(); let code = code.clone();
let mut environments = environments.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; let constructor_kind = *constructor_kind;
drop(object); drop(object);
@ -1384,10 +1385,8 @@ impl JsObject {
let has_binding_identifier = code.has_binding_identifier(); let has_binding_identifier = code.has_binding_identifier();
std::mem::swap(&mut context.vm.active_runnable, &mut script_or_module);
context.vm.push_frame( context.vm.push_frame(
CallFrame::new(code) CallFrame::new(code, script_or_module, Some(self.clone()))
.with_argument_count(argument_count as u32) .with_argument_count(argument_count as u32)
.with_env_fp(environments_len as u32), .with_env_fp(environments_len as u32),
); );
@ -1403,7 +1402,6 @@ impl JsObject {
context.vm.pop_frame(); context.vm.pop_frame();
std::mem::swap(&mut environments, &mut context.vm.environments); 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 { let environment = if has_binding_identifier {
environments.truncate(environments_len + 2); 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) pending_exception: Option<JsError>,
pub(crate) environments: EnvironmentStack, pub(crate) environments: EnvironmentStack,
pub(crate) runtime_limits: RuntimeLimits, 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")] #[cfg(feature = "trace")]
pub(crate) trace: bool, pub(crate) trace: bool,
@ -102,8 +104,7 @@ impl Vm {
environments: EnvironmentStack::new(global), environments: EnvironmentStack::new(global),
pending_exception: None, pending_exception: None,
runtime_limits: RuntimeLimits::default(), runtime_limits: RuntimeLimits::default(),
active_function: None, native_active_function: None,
active_runnable: None,
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
trace: false, trace: false,
} }

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

@ -272,9 +272,7 @@ impl Operation for ImportCall {
// 1. Let referrer be GetActiveScriptOrModule(). // 1. Let referrer be GetActiveScriptOrModule().
// 2. If referrer is null, set referrer to the current Realm Record. // 2. If referrer is null, set referrer to the current Realm Record.
let referrer = context let referrer = context
.vm .get_active_script_or_module()
.active_runnable
.clone()
.map_or_else(|| Referrer::Realm(context.realm().clone()), Into::into); .map_or_else(|| Referrer::Realm(context.realm().clone()), Into::into);
// 3. Let argRef be ? Evaluation of AssignmentExpression. // 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 r#async = context.vm.read::<u8>() != 0;
let code_block = context.vm.frame().code_block().clone(); 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 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; dummy_call_frame.pc = pc;
let mut call_frame = std::mem::replace(context.vm.frame_mut(), dummy_call_frame); 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; call_frame.fp = 0;
let this_function_object = context let this_function_object =
.vm active_function.expect("active function should be set to the generator");
.active_function
.clone()
.expect("active function should be set to the generator");
let proto = this_function_object let proto = this_function_object
.get(PROTOTYPE, context) .get(PROTOTYPE, context)
@ -83,7 +83,6 @@ impl Operation for Generator {
context: Some(GeneratorContext::new( context: Some(GeneratorContext::new(
environments, environments,
stack, stack,
context.vm.active_function.clone(),
call_frame, call_frame,
context.realm().clone(), context.realm().clone(),
)), )),
@ -95,7 +94,6 @@ impl Operation for Generator {
context: GeneratorContext::new( context: GeneratorContext::new(
environments, environments,
stack, stack,
context.vm.active_function.clone(),
call_frame, call_frame,
context.realm().clone(), 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(). // 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."); unreachable!("2. Assert: module is a Source Text Module Record.");
}; };

Loading…
Cancel
Save