diff --git a/core/engine/src/builtins/eval/mod.rs b/core/engine/src/builtins/eval/mod.rs index 890d7ece3df..d76435e5a57 100644 --- a/core/engine/src/builtins/eval/mod.rs +++ b/core/engine/src/builtins/eval/mod.rs @@ -9,11 +9,13 @@ //! [spec]: https://tc39.es/ecma262/#sec-eval-x //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval +use std::rc::Rc; + use crate::{ builtins::{function::OrdinaryFunction, BuiltInObject}, bytecompiler::{eval_declaration_instantiation_context, ByteCompiler}, context::intrinsics::Intrinsics, - environments::Environment, + environments::{CompileTimeEnvironment, Environment}, error::JsNativeError, js_string, object::JsObject, @@ -229,34 +231,42 @@ impl Eval { let var_environment = context.vm.environments.outer_function_environment(); let mut var_env = var_environment.compile_env(); + let lex_env = context.vm.environments.current_compile_environment(); + let lex_env = Rc::new(CompileTimeEnvironment::new(lex_env, strict)); + + let mut annex_b_function_names = Vec::new(); + + eval_declaration_instantiation_context( + &mut annex_b_function_names, + &body, + strict, + if strict { &lex_env } else { &var_env }, + &lex_env, + context, + )?; + let mut compiler = ByteCompiler::new( js_string!("
"), body.strict(), false, var_env.clone(), - context.vm.environments.current_compile_environment(), - context, + lex_env.clone(), + context.interner_mut(), ); - let env_index = compiler.push_compile_environment(strict); + compiler.current_open_environments_count += 1; + + let env_index = compiler.constants.len() as u32; + compiler + .constants + .push(crate::vm::Constant::CompileTimeEnvironment(lex_env.clone())); + compiler.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index); - let lex_env = compiler.lexical_environment.clone(); if strict { var_env = lex_env.clone(); compiler.variable_environment = lex_env.clone(); } - let mut annex_b_function_names = Vec::new(); - - eval_declaration_instantiation_context( - &mut annex_b_function_names, - &body, - strict, - &var_env, - &lex_env, - compiler.context, - )?; - #[cfg(feature = "annex-b")] { compiler.annex_b_function_names = annex_b_function_names; diff --git a/core/engine/src/builtins/function/mod.rs b/core/engine/src/builtins/function/mod.rs index 0d1604fcba4..cdb7143c656 100644 --- a/core/engine/src/builtins/function/mod.rs +++ b/core/engine/src/builtins/function/mod.rs @@ -624,7 +624,7 @@ impl BuiltInFunctionObject { &body, context.realm().environment().compile_env(), context.realm().environment().compile_env(), - context, + context.interner_mut(), ); let environments = context.vm.environments.pop_to_global(); diff --git a/core/engine/src/builtins/json/mod.rs b/core/engine/src/builtins/json/mod.rs index 817fecf40d1..3ba82ce549c 100644 --- a/core/engine/src/builtins/json/mod.rs +++ b/core/engine/src/builtins/json/mod.rs @@ -118,7 +118,7 @@ impl Json { true, context.realm().environment().compile_env(), context.realm().environment().compile_env(), - context, + context.interner_mut(), ); compiler.compile_statement_list(script.statements(), true, false); Gc::new(compiler.finish()) diff --git a/core/engine/src/bytecompiler/class.rs b/core/engine/src/bytecompiler/class.rs index 27e134595b2..ca43318bd6f 100644 --- a/core/engine/src/bytecompiler/class.rs +++ b/core/engine/src/bytecompiler/class.rs @@ -54,7 +54,7 @@ impl ByteCompiler<'_> { self.json_parse, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); compiler.code_block_flags |= CodeBlockFlags::IS_CLASS_CONSTRUCTOR; @@ -287,7 +287,7 @@ impl ByteCompiler<'_> { self.json_parse, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); // Function environment @@ -315,7 +315,7 @@ impl ByteCompiler<'_> { self.json_parse, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); let _ = field_compiler.push_compile_environment(true); if let Some(node) = field { @@ -353,7 +353,7 @@ impl ByteCompiler<'_> { self.json_parse, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); let _ = field_compiler.push_compile_environment(true); if let Some(node) = field { @@ -387,7 +387,7 @@ impl ByteCompiler<'_> { false, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); let _ = compiler.push_compile_environment(true); diff --git a/core/engine/src/bytecompiler/declarations.rs b/core/engine/src/bytecompiler/declarations.rs index 8ecdffd05a4..95172e4e0aa 100644 --- a/core/engine/src/bytecompiler/declarations.rs +++ b/core/engine/src/bytecompiler/declarations.rs @@ -27,12 +27,36 @@ use super::{Operand, ToJsString}; /// `GlobalDeclarationInstantiation ( script, env )` /// +/// This diverges from the specification by separating the context from the compilation process. +/// Many steps are skiped that are done during bytecode compilation. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// +/// [spec]: https://tc39.es/ecma262/#sec-globaldeclarationinstantiation +#[cfg(not(feature = "annex-b"))] +#[allow(clippy::unnecessary_wraps)] +#[allow(clippy::ptr_arg)] +pub(crate) fn global_declaration_instantiation_context( + _annex_b_function_names: &mut Vec, + _script: &Script, + _env: &Rc, + _context: &mut Context, +) -> JsResult<()> { + Ok(()) +} + +/// `GlobalDeclarationInstantiation ( script, env )` +/// +/// This diverges from the specification by separating the context from the compilation process. +/// Many steps are skiped that are done during bytecode compilation. +/// /// More information: /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-globaldeclarationinstantiation #[cfg(feature = "annex-b")] -pub(crate) fn global_declaration_instantiation_annex_b( +pub(crate) fn global_declaration_instantiation_context( annex_b_function_names: &mut Vec, script: &Script, env: &Rc, @@ -171,21 +195,21 @@ pub(crate) fn global_declaration_instantiation_annex_b( /// `EvalDeclarationInstantiation ( body, varEnv, lexEnv, privateEnv, strict )` /// +/// This diverges from the specification by separating the context from the compilation process. +/// Many steps are skiped that are done during bytecode compilation. +/// /// More information: /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-evaldeclarationinstantiation pub(crate) fn eval_declaration_instantiation_context( - annex_b_function_names: &mut Vec, + #[allow(unused)] annex_b_function_names: &mut Vec, body: &Script, - strict: bool, - var_env: &Rc, - lex_env: &Rc, + #[allow(unused)] strict: bool, + #[allow(unused)] var_env: &Rc, + #[allow(unused)] lex_env: &Rc, context: &mut Context, ) -> JsResult<()> { - // 2. Let varDeclarations be the VarScopedDeclarations of body. - let var_declarations = var_scoped_declarations(body); - // SKIP: 3. If strict is false, then // 4. Let privateIdentifiers be a new empty List. @@ -213,13 +237,18 @@ pub(crate) fn eval_declaration_instantiation_context( .into()); } - // 8. Let functionsToInitialize be a new empty List. - let mut functions_to_initialize = Vec::new(); + // 2. Let varDeclarations be the VarScopedDeclarations of body. + #[cfg(feature = "annex-b")] + let var_declarations = var_scoped_declarations(body); + + // SKIP: 8. Let functionsToInitialize be a new empty List. // 9. Let declaredFunctionNames be a new empty List. + #[cfg(feature = "annex-b")] let mut declared_function_names = Vec::new(); // 10. For each element d of varDeclarations, in reverse List order, do + #[cfg(feature = "annex-b")] for declaration in var_declarations.iter().rev() { // a. If d is not either a VariableDeclaration, a ForBinding, or a BindingIdentifier, then // a.i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration. @@ -244,13 +273,10 @@ pub(crate) fn eval_declaration_instantiation_context( // 2. Append fn to declaredFunctionNames. declared_function_names.push(name); - // 3. Insert d as the first element of functionsToInitialize. - functions_to_initialize.push(declaration.clone()); + // SKIP: 3. Insert d as the first element of functionsToInitialize. } } - functions_to_initialize.reverse(); - // 11. NOTE: Annex B.3.2.3 adds additional steps at this point. // 11. If strict is false, then #[cfg(feature = "annex-b")] @@ -314,13 +340,8 @@ pub(crate) fn eval_declaration_instantiation_context( // 7. If bindingExists is false and fnDefinable is true, then if !binding_exists && fn_definable { - let mut function_names = Vec::new(); - // a. If declaredFunctionOrVarNames does not contain F, then - if !declared_function_names.contains(&f) - //&& !var_names.contains(&f) - && !function_names.contains(&f) - { + if !declared_function_names.contains(&f) { // i. If varEnv is a Global Environment Record, then if var_env.is_global() { let f = f.to_js_string(context.interner()); @@ -328,19 +349,9 @@ pub(crate) fn eval_declaration_instantiation_context( // i. Perform ? varEnv.CreateGlobalVarBinding(F, true). context.create_global_var_binding(f, true)?; } + // SKIP: ii. Else, - // else { - // let f = f.to_js_string(context.interner()); - // SKIP: i. Let bindingExists be ! varEnv.HasBinding(F). - // SKIP: ii. If bindingExists is false, then - // if !var_env.has_binding(&f) { - // SKIP: i. Perform ! varEnv.CreateMutableBinding(F, true). - // SKIP: ii. Perform ! varEnv.InitializeBinding(F, undefined). - // } - // } - - // iii. Append F to declaredFunctionOrVarNames. - function_names.push(f); + // SKIP: iii. Append F to declaredFunctionOrVarNames. } // b. When the FunctionDeclaration f is evaluated, perform the following steps @@ -358,7 +369,6 @@ pub(crate) fn eval_declaration_instantiation_context( // SKIP: 12. Let declaredVarNames be a new empty List. // SKIP: 13. For each element d of varDeclarations, do - // SKIP: 14. NOTE: No abnormal terminations occur after this algorithm step unless varEnv is a // Global Environment Record and the global object is a Proxy exotic object. // SKIP: 15. Let lexDeclarations be the LexicallyScopedDeclarations of body. @@ -502,60 +512,15 @@ impl ByteCompiler<'_> { } } - // // 11. NOTE: No abnormal terminations occur after this algorithm step if the global object is an ordinary object. - // // However, if the global object is a Proxy exotic object it may exhibit behaviours - // // that cause abnormal terminations in some of the following steps. - - // // 12. NOTE: Annex B.3.2.2 adds additional steps at this point. - // // 12. Perform the following steps: - // // a. Let strict be IsStrict of script. - // // b. If strict is false, then - // #[cfg(feature = "annex-b")] - // if !script.strict() { - // let lex_names = lexically_declared_names(script); - - // // i. Let declaredFunctionOrVarNames be the list-concatenation of declaredFunctionNames and declaredVarNames. - // // ii. For each FunctionDeclaration f that is directly contained in the StatementList of a Block, CaseClause, - // // or DefaultClause Contained within script, do - // for f in annex_b_function_declarations_names(script) { - // // 1. Let F be StringValue of the BindingIdentifier of f. - // // 2. If replacing the FunctionDeclaration f with a VariableStatement that has F as a BindingIdentifier - // // would not produce any Early Errors for script, then - // if !lex_names.contains(&f) { - // let f_string = self.resolve_identifier_expect(f); - - // // a. If env.HasLexicalDeclaration(F) is false, then - // if !env.has_lex_binding(&f_string) { - // // i. Let fnDefinable be ? env.CanDeclareGlobalVar(F). - // let fn_definable = self.context.can_declare_global_function(&f_string)?; - - // // ii. If fnDefinable is true, then - // if fn_definable { - // // i. NOTE: A var binding for F is only instantiated here if it is neither - // // a VarDeclaredName nor the name of another FunctionDeclaration. - // // ii. If declaredFunctionOrVarNames does not contain F, then - // if !declared_function_names.contains(&f) - // && !declared_var_names.contains(&f) - // { - // // i. Perform ? env.CreateGlobalVarBinding(F, false). - // self.context.create_global_var_binding(f_string, false)?; - - // // ii. Append F to declaredFunctionOrVarNames. - // declared_function_names.push(f); - // } - // // iii. When the FunctionDeclaration f is evaluated, perform the following - // // steps in place of the FunctionDeclaration Evaluation algorithm provided in 15.2.6: - // // i. Let genv be the running execution context's VariableEnvironment. - // // ii. Let benv be the running execution context's LexicalEnvironment. - // // iii. Let fobj be ! benv.GetBindingValue(F, false). - // // iv. Perform ? genv.SetMutableBinding(F, fobj, false). - // // v. Return unused. - // self.annex_b_function_names.push(f); - // } - // } - // } - // } - // } + // NOTE: These steps depend on the global object are done before bytecode compilation. + // + // SKIP: 11. NOTE: No abnormal terminations occur after this algorithm step if the global object is an ordinary object. + // However, if the global object is a Proxy exotic object it may exhibit behaviours + // that cause abnormal terminations in some of the following steps. + // SKIP: 12. NOTE: Annex B.3.2.2 adds additional steps at this point. + // SKIP: 12. Perform the following steps: + // SKIP: a. Let strict be IsStrict of script. + // SKIP: b. If strict is false, then // 13. Let lexDeclarations be the LexicallyScopedDeclarations of script. // 14. Let privateEnv be null. @@ -625,7 +590,7 @@ impl ByteCompiler<'_> { body, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); // Ensures global functions are printed when generating the global flowgraph. @@ -804,30 +769,18 @@ impl ByteCompiler<'_> { } } + // NOTE: These steps depend on the current environment state are done before bytecode compilation, + // in `eval_declaration_instantiation_context`. + // // SKIP: 4. Let privateIdentifiers be a new empty List. // SKIP: 5. Let pointer be privateEnv. // SKIP: 6. Repeat, while pointer is not null, - // a. For each Private Name binding of pointer.[[Names]], do - // i. If privateIdentifiers does not contain binding.[[Description]], - // append binding.[[Description]] to privateIdentifiers. - // b. Set pointer to pointer.[[OuterPrivateEnvironment]]. + // a. For each Private Name binding of pointer.[[Names]], do + // i. If privateIdentifiers does not contain binding.[[Description]], + // append binding.[[Description]] to privateIdentifiers. + // b. Set pointer to pointer.[[OuterPrivateEnvironment]]. // SKIP: 7. If AllPrivateIdentifiersValid of body with argument privateIdentifiers is false, throw a SyntaxError exception. - // let private_identifiers = self.context.vm.environments.private_name_descriptions(); - // let private_identifiers = private_identifiers - // .into_iter() - // .map(|ident| { - // self.interner() - // .get(ident.as_slice()) - // .expect("string should be in interner") - // }) - // .collect(); - - // if !all_private_identifiers_valid(body, private_identifiers) { - // self.emit_syntax_error("invalid private identifier"); - // return; - // } - // 8. Let functionsToInitialize be a new empty List. let mut functions_to_initialize = Vec::new(); @@ -881,123 +834,8 @@ impl ByteCompiler<'_> { // 11. If strict is false, then #[cfg(feature = "annex-b")] if !strict { - // let lexically_declared_names = lexically_declared_names(body); - - // // a. Let declaredFunctionOrVarNames be the list-concatenation of declaredFunctionNames and declaredVarNames. - // // b. For each FunctionDeclaration f that is directly contained in the StatementList - // // of a Block, CaseClause, or DefaultClause Contained within body, do - // for f in annex_b_function_declarations_names(body) { - // // i. Let F be StringValue of the BindingIdentifier of f. - // // ii. If replacing the FunctionDeclaration f with a VariableStatement that has F - // // as a BindingIdentifier would not produce any Early Errors for body, then - // if !lexically_declared_names.contains(&f) { - // // 1. Let bindingExists be false. - // let mut binding_exists = false; - - // // 2. Let thisEnv be lexEnv. - // let mut this_env = lex_env.clone(); - - // // 3. Assert: The following loop will terminate. - // // 4. Repeat, while thisEnv is not varEnv, - // while this_env.environment_index() != lex_env.environment_index() { - // let f = f.to_js_string(self.interner()); - - // // a. If thisEnv is not an Object Environment Record, then - // // i. If ! thisEnv.HasBinding(F) is true, then - // if this_env.has_binding(&f) { - // // i. Let bindingExists be true. - // binding_exists = true; - // break; - // } - - // // b. Set thisEnv to thisEnv.[[OuterEnv]]. - // if let Some(outer) = this_env.outer() { - // this_env = outer; - // } else { - // break; - // } - // } - - // // 5. If bindingExists is false and varEnv is a Global Environment Record, then - // let fn_definable = if !binding_exists && var_env.is_global() { - // let f = f.to_js_string(self.interner()); - - // // a. If varEnv.HasLexicalDeclaration(F) is false, then - // // b. Else, - // if self.variable_environment.has_lex_binding(&f) { - // // i. Let fnDefinable be false. - // false - // } else { - // // i. Let fnDefinable be ? varEnv.CanDeclareGlobalVar(F). - // self.context.can_declare_global_var(&f)? - // } - // } - // // 6. Else, - // else { - // // a. Let fnDefinable be true. - // true - // }; - - // // 7. If bindingExists is false and fnDefinable is true, then - // if !binding_exists && fn_definable { - // // let mut function_names = Vec::new(); - - // if !var_env.is_global() { - // let f = f.to_js_string(self.interner()); - // // i. Let bindingExists be ! varEnv.HasBinding(F). - // // ii. If bindingExists is false, then - // if !var_env.has_binding(&f) { - // // i. Perform ! varEnv.CreateMutableBinding(F, true). - // // ii. Perform ! varEnv.InitializeBinding(F, undefined). - // let binding = var_env.create_mutable_binding(f, true); - // let index = self.get_or_insert_binding(binding); - // self.emit_opcode(Opcode::PushUndefined); - // self.emit_with_varying_operand(Opcode::DefInitVar, index); - // } - // } - - // // // a. If declaredFunctionOrVarNames does not contain F, then - // // if !declared_function_names.contains(&f) - // // //&& !var_names.contains(&f) - // // && !function_names.contains(&f) - // // { - // // // i. If varEnv is a Global Environment Record, then - // // if var_env.is_global() { - // // let f = f.to_js_string(self.interner()); - // // // i. Perform ? varEnv.CreateGlobalVarBinding(F, true). - // // self.context.create_global_var_binding(f, true)?; - // // } - // // // ii. Else, - // // else { - // // let f = f.to_js_string(self.interner()); - // // // i. Let bindingExists be ! varEnv.HasBinding(F). - // // // ii. If bindingExists is false, then - // // if !var_env.has_binding(&f) { - // // // i. Perform ! varEnv.CreateMutableBinding(F, true). - // // // ii. Perform ! varEnv.InitializeBinding(F, undefined). - // // let binding = var_env.create_mutable_binding(f, true); - // // let index = self.get_or_insert_binding(binding); - // // self.emit_opcode(Opcode::PushUndefined); - // // self.emit_with_varying_operand(Opcode::DefInitVar, index); - // // } - // // } - - // // // iii. Append F to declaredFunctionOrVarNames. - // // function_names.push(f); - // // } - - // // b. When the FunctionDeclaration f is evaluated, perform the following steps - // // in place of the FunctionDeclaration Evaluation algorithm provided in 15.2.6: - // // i. Let genv be the running execution context's VariableEnvironment. - // // ii. Let benv be the running execution context's LexicalEnvironment. - // // iii. Let fobj be ! benv.GetBindingValue(F, false). - // // iv. Perform ? genv.SetMutableBinding(F, fobj, false). - // // v. Return unused. - // self.annex_b_function_names.push(f); - // } - // } - // } - + // NOTE: This diviates from the specification, we split the first part of defining the annex-b names + // in `eval_declaration_instantiation_context`, because it depends on the context. if !var_env.is_global() { for name in self.annex_b_function_names.clone() { let f = name.to_js_string(self.interner()); @@ -1121,7 +959,7 @@ impl ByteCompiler<'_> { body, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); // c. If varEnv is a Global Environment Record, then diff --git a/core/engine/src/bytecompiler/function.rs b/core/engine/src/bytecompiler/function.rs index 1d570836242..2a09a497b96 100644 --- a/core/engine/src/bytecompiler/function.rs +++ b/core/engine/src/bytecompiler/function.rs @@ -6,10 +6,11 @@ use crate::{ environments::CompileTimeEnvironment, js_string, vm::{CodeBlock, CodeBlockFlags, Opcode}, - Context, JsString, + JsString, }; use boa_ast::function::{FormalParameterList, FunctionBody}; use boa_gc::Gc; +use boa_interner::Interner; /// `FunctionCompiler` is used to compile AST functions to bytecode. #[derive(Debug, Clone)] @@ -91,7 +92,7 @@ impl FunctionCompiler { body: &FunctionBody, variable_environment: Rc, lexical_environment: Rc, - context: &mut Context, + interner: &mut Interner, ) -> Gc { self.strict = self.strict || body.strict(); @@ -103,7 +104,7 @@ impl FunctionCompiler { false, variable_environment, lexical_environment, - context, + interner, ); compiler.length = length; compiler diff --git a/core/engine/src/bytecompiler/mod.rs b/core/engine/src/bytecompiler/mod.rs index 813193d9a1b..4b64f6774e6 100644 --- a/core/engine/src/bytecompiler/mod.rs +++ b/core/engine/src/bytecompiler/mod.rs @@ -21,7 +21,7 @@ use crate::{ BindingOpcode, CodeBlock, CodeBlockFlags, Constant, GeneratorResumeKind, Handler, InlineCache, Opcode, VaryingOperandKind, }, - Context, JsBigInt, JsString, + JsBigInt, JsString, }; use boa_ast::{ declaration::{Binding, LexicalDeclaration, VarDeclaration}, @@ -44,7 +44,7 @@ use rustc_hash::FxHashMap; use thin_vec::ThinVec; pub(crate) use declarations::{ - eval_declaration_instantiation_context, global_declaration_instantiation_annex_b, + eval_declaration_instantiation_context, global_declaration_instantiation_context, }; pub(crate) use function::FunctionCompiler; pub(crate) use jump_control::JumpControlInfo; @@ -280,7 +280,7 @@ pub struct ByteCompiler<'ctx> { /// The current lexical environment. pub(crate) lexical_environment: Rc, - current_open_environments_count: u32, + pub(crate) current_open_environments_count: u32, current_stack_value_count: u32, pub(crate) code_block_flags: CodeBlockFlags, handlers: ThinVec, @@ -296,8 +296,7 @@ pub struct ByteCompiler<'ctx> { pub(crate) async_handler: Option, json_parse: bool, - // TODO: remove when we separate scripts from the context - pub(crate) context: &'ctx mut Context, + pub(crate) interner: &'ctx mut Interner, #[cfg(feature = "annex-b")] pub(crate) annex_b_function_names: Vec, @@ -316,8 +315,7 @@ impl<'ctx> ByteCompiler<'ctx> { json_parse: bool, variable_environment: Rc, lexical_environment: Rc, - // TODO: remove when we separate scripts from the context - context: &'ctx mut Context, + interner: &'ctx mut Interner, ) -> ByteCompiler<'ctx> { let mut code_block_flags = CodeBlockFlags::empty(); code_block_flags.set(CodeBlockFlags::STRICT, strict); @@ -346,7 +344,7 @@ impl<'ctx> ByteCompiler<'ctx> { json_parse, variable_environment, lexical_environment, - context, + interner, #[cfg(feature = "annex-b")] annex_b_function_names: Vec::new(), @@ -370,7 +368,7 @@ impl<'ctx> ByteCompiler<'ctx> { } pub(crate) fn interner(&self) -> &Interner { - self.context.interner() + self.interner } fn get_or_insert_literal(&mut self, literal: Literal) -> u32 { @@ -1320,7 +1318,7 @@ impl<'ctx> ByteCompiler<'ctx> { body, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); self.push_function_to_constants(code) @@ -1395,7 +1393,7 @@ impl<'ctx> ByteCompiler<'ctx> { body, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); let index = self.push_function_to_constants(code); @@ -1442,7 +1440,7 @@ impl<'ctx> ByteCompiler<'ctx> { body, self.variable_environment.clone(), self.lexical_environment.clone(), - self.context, + self.interner, ); let index = self.push_function_to_constants(code); diff --git a/core/engine/src/module/source.rs b/core/engine/src/module/source.rs index c36b11966a4..edc1757db87 100644 --- a/core/engine/src/module/source.rs +++ b/core/engine/src/module/source.rs @@ -1432,7 +1432,7 @@ impl SourceTextModule { false, env.clone(), env.clone(), - context, + context.interner_mut(), ); compiler.code_block_flags |= CodeBlockFlags::IS_ASYNC; diff --git a/core/engine/src/module/synthetic.rs b/core/engine/src/module/synthetic.rs index fa151d468f4..734b1e9dd9e 100644 --- a/core/engine/src/module/synthetic.rs +++ b/core/engine/src/module/synthetic.rs @@ -286,7 +286,7 @@ impl SyntheticModule { false, module_compile_env.clone(), module_compile_env.clone(), - context, + context.interner_mut(), ); // 4. For each String exportName in module.[[ExportNames]], do diff --git a/core/engine/src/script.rs b/core/engine/src/script.rs index 0f35cfc4d99..3351ae4492d 100644 --- a/core/engine/src/script.rs +++ b/core/engine/src/script.rs @@ -17,7 +17,7 @@ use boa_parser::{source::ReadChar, Parser, Source}; use boa_profiler::Profiler; use crate::{ - bytecompiler::{global_declaration_instantiation_annex_b, ByteCompiler}, + bytecompiler::{global_declaration_instantiation_context, ByteCompiler}, js_string, realm::Realm, vm::{ActiveRunnable, CallFrame, CallFrameFlags, CodeBlock}, @@ -119,11 +119,9 @@ impl Script { let _timer = Profiler::global().start_event("Script compilation", "Main"); - #[cfg(feature = "annex-b")] let mut annex_b_function_names = Vec::new(); - #[cfg(feature = "annex-b")] - global_declaration_instantiation_annex_b( + global_declaration_instantiation_context( &mut annex_b_function_names, &self.inner.source, &self.inner.realm.environment().compile_env(), @@ -136,7 +134,7 @@ impl Script { false, self.inner.realm.environment().compile_env(), self.inner.realm.environment().compile_env(), - context, + context.interner_mut(), ); #[cfg(feature = "annex-b")] diff --git a/core/engine/src/vm/code_block.rs b/core/engine/src/vm/code_block.rs index 6060cddf94e..2a486da098b 100644 --- a/core/engine/src/vm/code_block.rs +++ b/core/engine/src/vm/code_block.rs @@ -530,15 +530,15 @@ impl CodeBlock { format!("done: {done}") } Instruction::CreateGlobalFunctionBinding { - name_index, + index, configurable, } | Instruction::CreateGlobalVarBinding { - name_index, + index, configurable, } => { let name = self - .constant_string(name_index.value() as usize) + .constant_string(index.value() as usize) .to_std_string_escaped(); format!("name: {name}, configurable: {configurable}") } diff --git a/core/engine/src/vm/opcode/define/mod.rs b/core/engine/src/vm/opcode/define/mod.rs index 01d09c7d78a..5c21d2b5cee 100644 --- a/core/engine/src/vm/opcode/define/mod.rs +++ b/core/engine/src/vm/opcode/define/mod.rs @@ -137,103 +137,3 @@ impl Operation for PutLexicalValue { Self::operation(context, index as usize) } } - -/// `CreateGlobalFunctionBinding` implements the Opcode Operation for `Opcode::CreateGlobalFunctionBinding` -/// -/// Operation: -/// - Performs [`CreateGlobalFunctionBinding ( N, V, D )`][spec] -/// -/// [spec]: https://tc39.es/ecma262/#sec-createglobalfunctionbinding -#[derive(Debug, Clone, Copy)] -pub(crate) struct CreateGlobalFunctionBinding; - -impl CreateGlobalFunctionBinding { - #[allow(clippy::unnecessary_wraps)] - fn operation( - context: &mut Context, - index: usize, - configurable: bool, - ) -> JsResult { - let name = context.vm.frame().code_block().constant_string(index); - let value = context.vm.pop(); - - let function = value - .as_object() - .expect("valeu should be an function") - .clone(); - context.create_global_function_binding(name, function, configurable)?; - - Ok(CompletionType::Normal) - } -} - -impl Operation for CreateGlobalFunctionBinding { - const NAME: &'static str = "CreateGlobalFunctionBinding"; - const INSTRUCTION: &'static str = "INST - CreateGlobalFunctionBinding"; - const COST: u8 = 2; - - fn execute(context: &mut Context) -> JsResult { - let configurable = context.vm.read::() != 0; - let index = context.vm.read::() as usize; - Self::operation(context, index, configurable) - } - - fn execute_with_u16_operands(context: &mut Context) -> JsResult { - let configurable = context.vm.read::() != 0; - let index = context.vm.read::() as usize; - Self::operation(context, index, configurable) - } - - fn execute_with_u32_operands(context: &mut Context) -> JsResult { - let configurable = context.vm.read::() != 0; - let index = context.vm.read::() as usize; - Self::operation(context, index, configurable) - } -} - -/// `CreateGlobalVarBinding` implements the Opcode Operation for `Opcode::CreateGlobalVarBinding` -/// -/// Operation: -/// - Performs [`CreateGlobalVarBinding ( N, V, D )`][spec] -/// -/// [spec]: https://tc39.es/ecma262/#sec-createglobalvarbinding -#[derive(Debug, Clone, Copy)] -pub(crate) struct CreateGlobalVarBinding; - -impl CreateGlobalVarBinding { - #[allow(clippy::unnecessary_wraps)] - fn operation( - context: &mut Context, - index: usize, - configurable: bool, - ) -> JsResult { - let name = context.vm.frame().code_block().constant_string(index); - context.create_global_var_binding(name, configurable)?; - - Ok(CompletionType::Normal) - } -} - -impl Operation for CreateGlobalVarBinding { - const NAME: &'static str = "CreateGlobalVarBinding"; - const INSTRUCTION: &'static str = "INST - CreateGlobalVarBinding"; - const COST: u8 = 2; - - fn execute(context: &mut Context) -> JsResult { - let configurable = context.vm.read::() != 0; - let index = context.vm.read::() as usize; - Self::operation(context, index, configurable) - } - - fn execute_with_u16_operands(context: &mut Context) -> JsResult { - let configurable = context.vm.read::() != 0; - let index = context.vm.read::() as usize; - Self::operation(context, index, configurable) - } - - fn execute_with_u32_operands(context: &mut Context) -> JsResult { - let configurable = context.vm.read::() != 0; - let index = context.vm.read::() as usize; - Self::operation(context, index, configurable) - } -} diff --git a/core/engine/src/vm/opcode/global.rs b/core/engine/src/vm/opcode/global.rs index 6f6dda9fb13..49666dc4373 100644 --- a/core/engine/src/vm/opcode/global.rs +++ b/core/engine/src/vm/opcode/global.rs @@ -5,7 +5,9 @@ use super::Operation; /// `HasRestrictedGlobalProperty` implements the Opcode Operation for `Opcode::HasRestrictedGlobalProperty` /// /// Operation: -/// - TODO: doc +/// - Performs [`HasRestrictedGlobalProperty ( N )`][spec] +/// +/// [spec]: https://tc39.es/ecma262/#sec-hasrestrictedglobalproperty #[derive(Debug, Clone, Copy)] pub(crate) struct HasRestrictedGlobalProperty; @@ -42,7 +44,9 @@ impl Operation for HasRestrictedGlobalProperty { /// `CanDeclareGlobalFunction` implements the Opcode Operation for `Opcode::CanDeclareGlobalFunction` /// /// Operation: -/// - TODO: doc +/// - Performs [`CanDeclareGlobalFunction ( N )`][spec] +/// +/// [spec]: https://tc39.es/ecma262/#sec-candeclareglobalfunction #[derive(Debug, Clone, Copy)] pub(crate) struct CanDeclareGlobalFunction; @@ -79,7 +83,9 @@ impl Operation for CanDeclareGlobalFunction { /// `CanDeclareGlobalVar` implements the Opcode Operation for `Opcode::CanDeclareGlobalVar` /// /// Operation: -/// - TODO: doc +/// - Performs [`CanDeclareGlobalVar ( N )`][spec] +/// +/// [spec]: https://tc39.es/ecma262/#sec-candeclareglobalvar #[derive(Debug, Clone, Copy)] pub(crate) struct CanDeclareGlobalVar; @@ -112,3 +118,103 @@ impl Operation for CanDeclareGlobalVar { Self::operation(context, index) } } + +/// `CreateGlobalFunctionBinding` implements the Opcode Operation for `Opcode::CreateGlobalFunctionBinding` +/// +/// Operation: +/// - Performs [`CreateGlobalFunctionBinding ( N, V, D )`][spec] +/// +/// [spec]: https://tc39.es/ecma262/#sec-createglobalfunctionbinding +#[derive(Debug, Clone, Copy)] +pub(crate) struct CreateGlobalFunctionBinding; + +impl CreateGlobalFunctionBinding { + #[allow(clippy::unnecessary_wraps)] + fn operation( + context: &mut Context, + index: usize, + configurable: bool, + ) -> JsResult { + let name = context.vm.frame().code_block().constant_string(index); + let value = context.vm.pop(); + + let function = value + .as_object() + .expect("valeu should be an function") + .clone(); + context.create_global_function_binding(name, function, configurable)?; + + Ok(CompletionType::Normal) + } +} + +impl Operation for CreateGlobalFunctionBinding { + const NAME: &'static str = "CreateGlobalFunctionBinding"; + const INSTRUCTION: &'static str = "INST - CreateGlobalFunctionBinding"; + const COST: u8 = 2; + + fn execute(context: &mut Context) -> JsResult { + let configurable = context.vm.read::() != 0; + let index = context.vm.read::() as usize; + Self::operation(context, index, configurable) + } + + fn execute_with_u16_operands(context: &mut Context) -> JsResult { + let configurable = context.vm.read::() != 0; + let index = context.vm.read::() as usize; + Self::operation(context, index, configurable) + } + + fn execute_with_u32_operands(context: &mut Context) -> JsResult { + let configurable = context.vm.read::() != 0; + let index = context.vm.read::() as usize; + Self::operation(context, index, configurable) + } +} + +/// `CreateGlobalVarBinding` implements the Opcode Operation for `Opcode::CreateGlobalVarBinding` +/// +/// Operation: +/// - Performs [`CreateGlobalVarBinding ( N, V, D )`][spec] +/// +/// [spec]: https://tc39.es/ecma262/#sec-createglobalvarbinding +#[derive(Debug, Clone, Copy)] +pub(crate) struct CreateGlobalVarBinding; + +impl CreateGlobalVarBinding { + #[allow(clippy::unnecessary_wraps)] + fn operation( + context: &mut Context, + index: usize, + configurable: bool, + ) -> JsResult { + let name = context.vm.frame().code_block().constant_string(index); + context.create_global_var_binding(name, configurable)?; + + Ok(CompletionType::Normal) + } +} + +impl Operation for CreateGlobalVarBinding { + const NAME: &'static str = "CreateGlobalVarBinding"; + const INSTRUCTION: &'static str = "INST - CreateGlobalVarBinding"; + const COST: u8 = 2; + + fn execute(context: &mut Context) -> JsResult { + let configurable = context.vm.read::() != 0; + let index = context.vm.read::() as usize; + Self::operation(context, index, configurable) + } + + fn execute_with_u16_operands(context: &mut Context) -> JsResult { + let configurable = context.vm.read::() != 0; + let index = context.vm.read::() as usize; + Self::operation(context, index, configurable) + } + + fn execute_with_u32_operands(context: &mut Context) -> JsResult { + let configurable = context.vm.read::() != 0; + let index = context.vm.read::() as usize; + Self::operation(context, index, configurable) + } +} diff --git a/core/engine/src/vm/opcode/mod.rs b/core/engine/src/vm/opcode/mod.rs index 348d56d5400..3f54a0080f8 100644 --- a/core/engine/src/vm/opcode/mod.rs +++ b/core/engine/src/vm/opcode/mod.rs @@ -1600,27 +1600,6 @@ generate_opcodes! { /// Stack: **=>** ThrowNewSyntaxError { message: VaryingOperand }, - /// TODO: doc - /// - /// Operands: name_index: u32 - /// - /// Stack: **=>** - HasRestrictedGlobalProperty { index: VaryingOperand }, - - /// TODO: doc - /// - /// Operands: name_index: u32 - /// - /// Stack: **=>** - CanDeclareGlobalFunction { index: VaryingOperand }, - - /// TODO: doc - /// - /// Operands: name_index: u32 - /// - /// Stack: **=>** - CanDeclareGlobalVar { index: VaryingOperand }, - /// Pops value converts it to boolean and pushes it back. /// /// Operands: @@ -2101,23 +2080,50 @@ generate_opcodes! { /// Stack: **=>** `arguments` CreateUnmappedArgumentsObject, + /// Performs [`HasRestrictedGlobalProperty ( N )`][spec] + /// + /// Operands: `index`: u32 + /// + /// Stack: **=>** + /// + /// [spec]: https://tc39.es/ecma262/#sec-hasrestrictedglobalproperty + HasRestrictedGlobalProperty { index: VaryingOperand }, + + /// Performs [`CanDeclareGlobalFunction ( N )`][spec] + /// + /// Operands: `index`: u32 + /// + /// Stack: **=>** + /// + /// [spec]: https://tc39.es/ecma262/#sec-candeclareglobalfunction + CanDeclareGlobalFunction { index: VaryingOperand }, + + /// Performs [`CanDeclareGlobalVar ( N )`][spec] + /// + /// Operands: `index`: u32 + /// + /// Stack: **=>** + /// + /// [spec]: https://tc39.es/ecma262/#sec-candeclareglobalvar + CanDeclareGlobalVar { index: VaryingOperand }, + /// Performs [`CreateGlobalFunctionBinding ( N, V, D )`][spec] /// - /// Operands: configurable: `bool`, `name_index`: `VaryingOperand` + /// Operands: configurable: `bool`, `index`: `VaryingOperand` /// - /// Stack: `value` **=>** + /// Stack: `function` **=>** /// /// [spec]: https://tc39.es/ecma262/#sec-createglobalfunctionbinding - CreateGlobalFunctionBinding { configurable: bool, name_index: VaryingOperand }, + CreateGlobalFunctionBinding { configurable: bool, index: VaryingOperand }, /// Performs [`CreateGlobalVarBinding ( N, V, D )`][spec] /// - /// Operands: configurable: `bool`, `name_index`: `VaryingOperand` + /// Operands: configurable: `bool`, `index`: `VaryingOperand` /// - /// Stack: `value` **=>** + /// Stack: **=>** /// /// [spec]: https://tc39.es/ecma262/#sec-createglobalvarbinding - CreateGlobalVarBinding { configurable: bool, name_index: VaryingOperand }, + CreateGlobalVarBinding { configurable: bool, index: VaryingOperand }, /// No-operation instruction, does nothing. ///