Browse Source

Remove `Context` from `ByteCompiler`

pull/3829/head
Haled Odat 4 weeks ago
parent
commit
4b1fc4b812
  1. 42
      core/engine/src/builtins/eval/mod.rs
  2. 2
      core/engine/src/builtins/function/mod.rs
  3. 2
      core/engine/src/builtins/json/mod.rs
  4. 10
      core/engine/src/bytecompiler/class.rs
  5. 288
      core/engine/src/bytecompiler/declarations.rs
  6. 7
      core/engine/src/bytecompiler/function.rs
  7. 22
      core/engine/src/bytecompiler/mod.rs
  8. 2
      core/engine/src/module/source.rs
  9. 2
      core/engine/src/module/synthetic.rs
  10. 8
      core/engine/src/script.rs
  11. 6
      core/engine/src/vm/code_block.rs
  12. 100
      core/engine/src/vm/opcode/define/mod.rs
  13. 112
      core/engine/src/vm/opcode/global.rs
  14. 60
      core/engine/src/vm/opcode/mod.rs

42
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!("<main>"),
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;

2
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();

2
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())

10
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);

288
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<Identifier>,
_script: &Script,
_env: &Rc<CompileTimeEnvironment>,
_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<Identifier>,
script: &Script,
env: &Rc<CompileTimeEnvironment>,
@ -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<Identifier>,
#[allow(unused, clippy::ptr_arg)] annex_b_function_names: &mut Vec<Identifier>,
body: &Script,
strict: bool,
var_env: &Rc<CompileTimeEnvironment>,
lex_env: &Rc<CompileTimeEnvironment>,
#[allow(unused)] strict: bool,
#[allow(unused)] var_env: &Rc<CompileTimeEnvironment>,
#[allow(unused)] lex_env: &Rc<CompileTimeEnvironment>,
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

7
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<CompileTimeEnvironment>,
lexical_environment: Rc<CompileTimeEnvironment>,
context: &mut Context,
interner: &mut Interner,
) -> Gc<CodeBlock> {
self.strict = self.strict || body.strict();
@ -103,7 +104,7 @@ impl FunctionCompiler {
false,
variable_environment,
lexical_environment,
context,
interner,
);
compiler.length = length;
compiler

22
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<CompileTimeEnvironment>,
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<Handler>,
@ -296,8 +296,7 @@ pub struct ByteCompiler<'ctx> {
pub(crate) async_handler: Option<u32>,
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<Identifier>,
@ -316,8 +315,7 @@ impl<'ctx> ByteCompiler<'ctx> {
json_parse: bool,
variable_environment: Rc<CompileTimeEnvironment>,
lexical_environment: Rc<CompileTimeEnvironment>,
// 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);

2
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;

2
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

8
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")]

6
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}")
}

100
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<CompletionType> {
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<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index, configurable)
}
fn execute_with_u16_operands(context: &mut Context) -> JsResult<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index, configurable)
}
fn execute_with_u32_operands(context: &mut Context) -> JsResult<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u32>() 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<CompletionType> {
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<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index, configurable)
}
fn execute_with_u16_operands(context: &mut Context) -> JsResult<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index, configurable)
}
fn execute_with_u32_operands(context: &mut Context) -> JsResult<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index, configurable)
}
}

112
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<CompletionType> {
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<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index, configurable)
}
fn execute_with_u16_operands(context: &mut Context) -> JsResult<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index, configurable)
}
fn execute_with_u32_operands(context: &mut Context) -> JsResult<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u32>() 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<CompletionType> {
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<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u8>() as usize;
Self::operation(context, index, configurable)
}
fn execute_with_u16_operands(context: &mut Context) -> JsResult<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u16>() as usize;
Self::operation(context, index, configurable)
}
fn execute_with_u32_operands(context: &mut Context) -> JsResult<CompletionType> {
let configurable = context.vm.read::<u8>() != 0;
let index = context.vm.read::<u32>() as usize;
Self::operation(context, index, configurable)
}
}

60
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.
///

Loading…
Cancel
Save