diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp index f67ce9ea2a..f0e24c6376 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.cpp @@ -423,4 +423,30 @@ MarkedVector argument_list_evaluation(Bytecode::Interpreter& interpreter) return argument_values; } +ThrowCompletionOr create_variable(VM& vm, DeprecatedFlyString const& name, Op::EnvironmentMode mode, bool is_global, bool is_immutable, bool is_strict) +{ + if (mode == Op::EnvironmentMode::Lexical) { + VERIFY(!is_global); + + // Note: This is papering over an issue where "FunctionDeclarationInstantiation" creates these bindings for us. + // Instead of crashing in there, we'll just raise an exception here. + if (TRY(vm.lexical_environment()->has_binding(name))) + return vm.throw_completion(TRY_OR_THROW_OOM(vm, String::formatted("Lexical environment already has binding '{}'", name))); + + if (is_immutable) + return vm.lexical_environment()->create_immutable_binding(vm, name, is_strict); + return vm.lexical_environment()->create_mutable_binding(vm, name, is_strict); + } + + if (!is_global) { + if (is_immutable) + return vm.variable_environment()->create_immutable_binding(vm, name, is_strict); + return vm.variable_environment()->create_mutable_binding(vm, name, is_strict); + } + + // NOTE: CreateVariable with m_is_global set to true is expected to only be used in GlobalDeclarationInstantiation currently, which only uses "false" for "can_be_deleted". + // The only area that sets "can_be_deleted" to true is EvalDeclarationInstantiation, which is currently fully implemented in C++ and not in Bytecode. + return verify_cast(vm.variable_environment())->create_global_var_binding(name, false); +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h index 372ab7c1e9..478a863a17 100644 --- a/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h +++ b/Userland/Libraries/LibJS/Bytecode/CommonImplementations.h @@ -32,5 +32,6 @@ struct CalleeAndThis { ThrowCompletionOr get_callee_and_this_from_environment(Bytecode::Interpreter&, DeprecatedFlyString const& name, u32 cache_index); Value new_regexp(VM&, ParsedRegex const&, DeprecatedString const& pattern, DeprecatedString const& flags); MarkedVector argument_list_evaluation(Bytecode::Interpreter&); +ThrowCompletionOr create_variable(VM&, DeprecatedFlyString const& name, Op::EnvironmentMode, bool is_global, bool is_immutable, bool is_strict); } diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index fa8e461dab..d8b523089a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -819,34 +819,8 @@ ThrowCompletionOr EnterObjectEnvironment::execute_impl(Bytecode::Interpret ThrowCompletionOr CreateVariable::execute_impl(Bytecode::Interpreter& interpreter) const { - auto& vm = interpreter.vm(); auto const& name = interpreter.current_executable().get_identifier(m_identifier); - - if (m_mode == EnvironmentMode::Lexical) { - VERIFY(!m_is_global); - - // Note: This is papering over an issue where "FunctionDeclarationInstantiation" creates these bindings for us. - // Instead of crashing in there, we'll just raise an exception here. - if (TRY(vm.lexical_environment()->has_binding(name))) - return vm.throw_completion(TRY_OR_THROW_OOM(vm, String::formatted("Lexical environment already has binding '{}'", name))); - - if (m_is_immutable) - return vm.lexical_environment()->create_immutable_binding(vm, name, m_is_strict); - else - return vm.lexical_environment()->create_mutable_binding(vm, name, m_is_strict); - } else { - if (!m_is_global) { - if (m_is_immutable) - return vm.variable_environment()->create_immutable_binding(vm, name, m_is_strict); - else - return vm.variable_environment()->create_mutable_binding(vm, name, m_is_strict); - } else { - // NOTE: CreateVariable with m_is_global set to true is expected to only be used in GlobalDeclarationInstantiation currently, which only uses "false" for "can_be_deleted". - // The only area that sets "can_be_deleted" to true is EvalDeclarationInstantiation, which is currently fully implemented in C++ and not in Bytecode. - return verify_cast(vm.variable_environment())->create_global_var_binding(name, false); - } - } - return {}; + return create_variable(interpreter.vm(), name, m_mode, m_is_global, m_is_immutable, m_is_strict); } ThrowCompletionOr SetVariable::execute_impl(Bytecode::Interpreter& interpreter) const