diff --git a/core/engine/src/bytecompiler/declarations.rs b/core/engine/src/bytecompiler/declarations.rs index 8f27206ac0b..150758feed7 100644 --- a/core/engine/src/bytecompiler/declarations.rs +++ b/core/engine/src/bytecompiler/declarations.rs @@ -18,6 +18,7 @@ use boa_ast::{ visitor::NodeRef, }; use boa_interner::{JStrRef, Sym}; +use rustc_hash::FxHashSet; #[cfg(feature = "annex-b")] use boa_ast::operations::annex_b_function_declarations_names; @@ -71,7 +72,7 @@ pub(crate) fn global_declaration_instantiation_context( // SKIP: 6. Let functionsToInitialize be a new empty List. // 7. Let declaredFunctionNames be a new empty List. - let mut declared_function_names = Vec::new(); + let mut declared_function_names = FxHashSet::default(); // 8. For each element d of varDeclarations, in reverse List order, do for declaration in var_declarations.iter().rev() { @@ -88,18 +89,15 @@ pub(crate) fn global_declaration_instantiation_context( }; // a.iv. If declaredFunctionNames does not contain fn, then - if !declared_function_names.contains(&name.sym()) { - // SKIP: 1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn). - // SKIP: 2. If fnDefinable is false, throw a TypeError exception. - // 3. Append fn to declaredFunctionNames. - declared_function_names.push(name.sym()); - - // SKIP: 4. Insert d as the first element of functionsToInitialize. - } + // SKIP: 1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn). + // SKIP: 2. If fnDefinable is false, throw a TypeError exception. + // 3. Append fn to declaredFunctionNames. + // SKIP: 4. Insert d as the first element of functionsToInitialize. + declared_function_names.insert(name.sym()); } // // 9. Let declaredVarNames be a new empty List. - let mut declared_var_names = Vec::new(); + let mut declared_var_names = FxHashSet::default(); // 10. For each element d of varDeclarations, do // a. If d is either a VariableDeclaration, a ForBinding, or a BindingIdentifier, then @@ -115,10 +113,8 @@ pub(crate) fn global_declaration_instantiation_context( // SKIP: a. Let vnDefinable be ? env.CanDeclareGlobalVar(vn). // SKIP: b. If vnDefinable is false, throw a TypeError exception. // c. If declaredVarNames does not contain vn, then - if !declared_var_names.contains(&name) { - // i. Append vn to declaredVarNames. - declared_var_names.push(name); - } + // i. Append vn to declaredVarNames. + declared_var_names.insert(name); } } } @@ -160,7 +156,7 @@ pub(crate) fn global_declaration_instantiation_context( context.create_global_var_binding(f_string, false)?; // ii. Append F to declaredFunctionOrVarNames. - declared_function_names.push(f); + declared_function_names.insert(f); } // iii. When the FunctionDeclaration f is evaluated, perform the following // steps in place of the FunctionDeclaration Evaluation algorithm provided in 15.2.6: @@ -240,7 +236,7 @@ pub(crate) fn prepare_eval_declaration_instantiation( // 9. Let declaredFunctionNames be a new empty List. #[cfg(feature = "annex-b")] - let mut declared_function_names = Vec::new(); + let mut declared_function_names = FxHashSet::default(); // 10. For each element d of varDeclarations, in reverse List order, do #[cfg(feature = "annex-b")] @@ -258,21 +254,18 @@ pub(crate) fn prepare_eval_declaration_instantiation( }; // a.iv. If declaredFunctionNames does not contain fn, then - if !declared_function_names.contains(&name.sym()) { - // SKIP: 1. If varEnv is a Global Environment Record, then - - // 2. Append fn to declaredFunctionNames. - declared_function_names.push(name.sym()); - - // SKIP: 3. Insert d as the first element of functionsToInitialize. - } + // SKIP: 1. If varEnv is a Global Environment Record, then + // 2. Append fn to declaredFunctionNames. + // SKIP: 3. Insert d as the first element of functionsToInitialize. + declared_function_names.insert(name.sym()); } // 11. NOTE: Annex B.3.2.3 adds additional steps at this point. // 11. If strict is false, then #[cfg(feature = "annex-b")] if !strict { - let lexically_declared_names = lexically_declared_names(body); + let lexically_declared_names: FxHashSet = + lexically_declared_names(body).into_iter().collect(); // a. Let declaredFunctionOrVarNames be the list-concatenation of declaredFunctionNames and declaredVarNames. // b. For each FunctionDeclaration f that is directly contained in the StatementList @@ -405,7 +398,7 @@ impl ByteCompiler<'_> { let mut functions_to_initialize = Vec::new(); // 7. Let declaredFunctionNames be a new empty List. - let mut declared_function_names = Vec::new(); + let mut declared_function_names = FxHashSet::default(); // 8. For each element d of varDeclarations, in reverse List order, do for declaration in var_declarations.iter().rev() { @@ -422,7 +415,7 @@ impl ByteCompiler<'_> { }; // a.iv. If declaredFunctionNames does not contain fn, then - if !declared_function_names.contains(&name.sym()) { + if declared_function_names.insert(name.sym()) { // 1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn). // 2. If fnDefinable is false, throw a TypeError exception. // Done in `Context::global_declaration_instantiation`. @@ -430,9 +423,6 @@ impl ByteCompiler<'_> { // in `functions_to_initialize`, but in reverse order, so we can // reuse `global_fns` for this check. - // 3. Append fn to declaredFunctionNames. - declared_function_names.push(name.sym()); - // 4. Insert d as the first element of functionsToInitialize. functions_to_initialize.push(declaration.clone()); } @@ -441,7 +431,7 @@ impl ByteCompiler<'_> { functions_to_initialize.reverse(); // 9. Let declaredVarNames be a new empty List. - let mut declared_var_names = Vec::new(); + let mut declared_var_names = FxHashSet::default(); // 10. For each element d of varDeclarations, do // a. If d is either a VariableDeclaration, a ForBinding, or a BindingIdentifier, then @@ -462,10 +452,8 @@ impl ByteCompiler<'_> { // for this check. // c. If declaredVarNames does not contain vn, then - if !declared_var_names.contains(&name) { - // i. Append vn to declaredVarNames. - declared_var_names.push(name); - } + // i. Append vn to declaredVarNames. + declared_var_names.insert(name); } } } @@ -657,7 +645,7 @@ impl ByteCompiler<'_> { let mut functions_to_initialize = Vec::new(); // 9. Let declaredFunctionNames be a new empty List. - let mut declared_function_names = Vec::new(); + let mut declared_function_names = FxHashSet::default(); // 10. For each element d of varDeclarations, in reverse List order, do for declaration in var_declarations.iter().rev() { @@ -673,7 +661,7 @@ impl ByteCompiler<'_> { VarScopedDeclaration::VariableDeclaration(_) => continue, }; // a.iv. If declaredFunctionNames does not contain fn, then - if !declared_function_names.contains(&name.sym()) { + if declared_function_names.insert(name.sym()) { // 1. If varEnv is a Global Environment Record, then // a. Let fnDefinable be ? varEnv.CanDeclareGlobalFunction(fn). // b. If fnDefinable is false, throw a TypeError exception. @@ -682,9 +670,6 @@ impl ByteCompiler<'_> { // in `functions_to_initialize`, but in reverse order, so we can // reuse `global_fns` for this check. - // 2. Append fn to declaredFunctionNames. - declared_function_names.push(name.sym()); - // 3. Insert d as the first element of functionsToInitialize. functions_to_initialize.push(declaration.clone()); } @@ -717,7 +702,7 @@ impl ByteCompiler<'_> { } // 12. Let declaredVarNames be a new empty List. - let mut declared_var_names = Vec::new(); + let mut declared_var_names = FxHashSet::default(); // 13. For each element d of varDeclarations, do for declaration in var_declarations { @@ -739,10 +724,8 @@ impl ByteCompiler<'_> { // for this check. // b. If declaredVarNames does not contain vn, then - if !declared_var_names.contains(&name) { - // i. Append vn to declaredVarNames. - declared_var_names.push(name); - } + // i. Append vn to declaredVarNames. + declared_var_names.insert(name); } } } @@ -931,7 +914,7 @@ impl ByteCompiler<'_> { let lexical_names = lexically_declared_names(body); // 12. Let functionNames be a new empty List. - let mut function_names = Vec::new(); + let mut function_names = FxHashSet::default(); // 13. Let functionsToInitialize be a new empty List. let mut functions_to_initialize = Vec::new(); @@ -954,9 +937,8 @@ impl ByteCompiler<'_> { }; // a.iii. If functionNames does not contain fn, then - if !function_names.contains(&name.sym()) { + if function_names.insert(name.sym()) { // 1. Insert fn as the first element of functionNames. - function_names.push(name.sym()); // 2. NOTE: If there are multiple function declarations for the same name, the last declaration is used. // 3. Insert d as the first element of functionsToInitialize. @@ -964,7 +946,6 @@ impl ByteCompiler<'_> { } } - function_names.reverse(); functions_to_initialize.reverse(); // 15. Let argumentsObjectNeeded be true. @@ -1040,7 +1021,7 @@ impl ByteCompiler<'_> { // 23. Else, // a. Let parameterBindings be parameterNames. - let parameter_bindings = parameter_names.clone(); + let parameter_bindings: FxHashSet = parameter_names.iter().copied().collect(); // 24. Let iteratorRecord be CreateListIteratorRecord(argumentsList). // 25. If hasDuplicates is true, then @@ -1102,15 +1083,12 @@ impl ByteCompiler<'_> { let mut variable_scope = self.lexical_scope.clone(); // d. Let instantiatedVarNames be a new empty List. - let mut instantiated_var_names = Vec::new(); + let mut instantiated_var_names = FxHashSet::default(); // e. For each element n of varNames, do for n in var_names { // i. If instantiatedVarNames does not contain n, then - if !instantiated_var_names.contains(&n) { - // 1. Append n to instantiatedVarNames. - instantiated_var_names.push(n); - + if instantiated_var_names.insert(n) { let n_string = n.to_js_string(self.interner()); // 2. Perform ! varEnv.CreateMutableBinding(n, false). @@ -1151,15 +1129,12 @@ impl ByteCompiler<'_> { } else { // a. NOTE: Only a single Environment Record is needed for the parameters and top-level vars. // b. Let instantiatedVarNames be a copy of the List parameterBindings. - let mut instantiated_var_names = parameter_bindings; + let mut instantiated_var_names = parameter_bindings.clone(); // c. For each element n of varNames, do for n in var_names { // i. If instantiatedVarNames does not contain n, then - if !instantiated_var_names.contains(&n) { - // 1. Append n to instantiatedVarNames. - instantiated_var_names.push(n); - + if instantiated_var_names.insert(n) { let n = n.to_js_string(self.interner()); // 2. Perform ! env.CreateMutableBinding(n, false). @@ -1210,7 +1185,7 @@ impl ByteCompiler<'_> { ); // c. Append F to instantiatedVarNames. - instantiated_var_names.push(f); + instantiated_var_names.insert(f); } // 3. When the FunctionDeclaration f is evaluated, perform the following steps