diff --git a/Libraries/LibJS/Bytecode/Executable.cpp b/Libraries/LibJS/Bytecode/Executable.cpp index e012256418..826caf52a0 100644 --- a/Libraries/LibJS/Bytecode/Executable.cpp +++ b/Libraries/LibJS/Bytecode/Executable.cpp @@ -25,7 +25,7 @@ Executable::Executable( size_t number_of_property_lookup_caches, size_t number_of_global_variable_caches, size_t number_of_registers, - bool is_strict_mode) + Strict strict) : bytecode(move(bytecode)) , string_table(move(string_table)) , identifier_table(move(identifier_table)) @@ -33,7 +33,7 @@ Executable::Executable( , constants(move(constants)) , source_code(move(source_code)) , number_of_registers(number_of_registers) - , is_strict_mode(is_strict_mode) + , is_strict_mode(strict == Strict::Yes) { property_lookup_caches.resize(number_of_property_lookup_caches); global_variable_caches.resize(number_of_global_variable_caches); diff --git a/Libraries/LibJS/Bytecode/Executable.h b/Libraries/LibJS/Bytecode/Executable.h index 9b7a451971..9d4c9128cd 100644 --- a/Libraries/LibJS/Bytecode/Executable.h +++ b/Libraries/LibJS/Bytecode/Executable.h @@ -75,7 +75,7 @@ public: size_t number_of_property_lookup_caches, size_t number_of_global_variable_caches, size_t number_of_registers, - bool is_strict_mode); + Strict); virtual ~Executable() override; diff --git a/Libraries/LibJS/Bytecode/Generator.cpp b/Libraries/LibJS/Bytecode/Generator.cpp index 0cf1c835e1..2d727f397d 100644 --- a/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Libraries/LibJS/Bytecode/Generator.cpp @@ -218,6 +218,14 @@ CodeGenerationErrorOr Generator::emit_function_declaration_instantiation(E CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNode const& node, FunctionKind enclosing_function_kind, GC::Ptr function, MustPropagateCompletion must_propagate_completion, Vector local_variable_names) { Generator generator(vm, function, must_propagate_completion); + + if (is(node)) + generator.m_strict = static_cast(node).is_strict_mode() ? Strict::Yes : Strict::No; + else if (is(node)) + generator.m_strict = static_cast(node).in_strict_mode() ? Strict::Yes : Strict::No; + else if (is(node)) + generator.m_strict = static_cast(node).is_strict_mode() ? Strict::Yes : Strict::No; + generator.m_local_variables = local_variable_names; generator.switch_to_basic_block(generator.make_block()); @@ -260,14 +268,6 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNode co } } - bool is_strict_mode = false; - if (is(node)) - is_strict_mode = static_cast(node).is_strict_mode(); - else if (is(node)) - is_strict_mode = static_cast(node).in_strict_mode(); - else if (is(node)) - is_strict_mode = static_cast(node).is_strict_mode(); - size_t size_needed = 0; for (auto& block : generator.m_root_basic_blocks) { size_needed += block->size(); @@ -453,7 +453,7 @@ CodeGenerationErrorOr> Generator::compile(VM& vm, ASTNode co generator.m_next_property_lookup_cache, generator.m_next_global_variable_cache, generator.m_next_register, - is_strict_mode); + generator.m_strict); Vector linked_exception_handlers; diff --git a/Libraries/LibJS/Bytecode/Generator.h b/Libraries/LibJS/Bytecode/Generator.h index 9cc0512d4a..87c7d7b415 100644 --- a/Libraries/LibJS/Bytecode/Generator.h +++ b/Libraries/LibJS/Bytecode/Generator.h @@ -93,6 +93,7 @@ public: grow(sizeof(OpType)); void* slot = m_current_basic_block->data() + slot_offset; new (slot) OpType(forward(args)...); + static_cast(slot)->set_strict(m_strict); if constexpr (OpType::IsTerminator) m_current_basic_block->terminate({}); m_current_basic_block->add_source_map_entry(slot_offset, { m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); @@ -110,6 +111,7 @@ public: grow(size_to_allocate); void* slot = m_current_basic_block->data() + slot_offset; new (slot) OpType(forward(args)...); + static_cast(slot)->set_strict(m_strict); if constexpr (OpType::IsTerminator) m_current_basic_block->terminate({}); m_current_basic_block->add_source_map_entry(slot_offset, { m_current_ast_node->start_offset(), m_current_ast_node->end_offset() }); @@ -383,6 +385,8 @@ private: Vector language_label_set; }; + Strict m_strict { Strict::No }; + BasicBlock* m_current_basic_block { nullptr }; ASTNode const* m_current_ast_node { nullptr }; UnwindContext const* m_current_unwind_context { nullptr }; diff --git a/Libraries/LibJS/Bytecode/Instruction.h b/Libraries/LibJS/Bytecode/Instruction.h index 679540dbbb..1b768eeb0f 100644 --- a/Libraries/LibJS/Bytecode/Instruction.h +++ b/Libraries/LibJS/Bytecode/Instruction.h @@ -188,7 +188,7 @@ public: constexpr static bool IsTerminator = false; static constexpr bool IsVariableLength = false; - enum class Type { + enum class Type : u8 { #define __BYTECODE_OP(op) \ op, ENUMERATE_BYTECODE_OPS(__BYTECODE_OP) @@ -202,6 +202,9 @@ public: void visit_operands(Function visitor); static void destroy(Instruction&); + Strict strict() const { return m_strict; } + void set_strict(Strict strict) { m_strict = strict; } + protected: explicit Instruction(Type type) : m_type(type) @@ -213,6 +216,7 @@ protected: private: Type m_type {}; + Strict m_strict {}; }; class InstructionStreamIterator { diff --git a/Libraries/LibJS/Bytecode/Interpreter.cpp b/Libraries/LibJS/Bytecode/Interpreter.cpp index 6fa3ebe5cc..cf5191cc28 100644 --- a/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -1023,7 +1023,7 @@ inline ThrowCompletionOr get_by_value(VM& vm, Optionalinternal_get(property_key, base_value)); } -inline ThrowCompletionOr get_global(Interpreter& interpreter, IdentifierTableIndex identifier_index, GlobalVariableCache& cache) +inline ThrowCompletionOr get_global(Interpreter& interpreter, IdentifierTableIndex identifier_index, Strict strict, GlobalVariableCache& cache) { auto& vm = interpreter.vm(); auto& binding_object = interpreter.global_object(); @@ -1068,7 +1068,7 @@ inline ThrowCompletionOr get_global(Interpreter& interpreter, IdentifierT cache.in_module_environment = true; return TRY(module_environment.get_binding_value_direct(vm, index.value())); } - return TRY(module_environment.get_binding_value(vm, identifier, vm.in_strict_mode())); + return TRY(module_environment.get_binding_value(vm, identifier, strict == Strict::Yes)); } } @@ -1077,7 +1077,7 @@ inline ThrowCompletionOr get_global(Interpreter& interpreter, IdentifierT cache.environment_binding_index = static_cast(offset.value()); cache.has_environment_binding_index = true; cache.in_module_environment = false; - return TRY(declarative_record.get_binding_value(vm, identifier, vm.in_strict_mode())); + return TRY(declarative_record.get_binding_value(vm, identifier, strict == Strict::Yes)); } if (TRY(binding_object.has_property(identifier))) { @@ -1098,10 +1098,10 @@ inline ThrowCompletionOr get_global(Interpreter& interpreter, IdentifierT } template -ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value this_value, Value value, Optional const& base_identifier, PropertyKey name, PropertyLookupCache* caches = nullptr) +ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value this_value, Value value, Optional const& base_identifier, PropertyKey name, Strict strict, PropertyLookupCache* caches = nullptr) { // Better error message than to_object would give - if (vm.in_strict_mode() && base.is_nullish()) [[unlikely]] + if (strict == Strict::Yes && base.is_nullish()) [[unlikely]] return vm.throw_completion(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); // a. Let baseObj be ? ToObject(V.[[Base]]). @@ -1277,7 +1277,7 @@ ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value this_value } } - if (!succeeded && vm.in_strict_mode()) [[unlikely]] { + if (!succeeded && strict == Strict::Yes) [[unlikely]] { if (base.is_object()) return vm.throw_completion(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); return vm.throw_completion(ErrorType::ReferencePrimitiveSetProperty, name, base.typeof_(vm)->utf8_string(), base.to_string_without_side_effects()); @@ -1296,14 +1296,14 @@ ThrowCompletionOr put_by_property_key(VM& vm, Value base, Value this_value return {}; } -inline ThrowCompletionOr perform_call(Interpreter& interpreter, Value this_value, Op::CallType call_type, Value callee, ReadonlySpan argument_values) +inline ThrowCompletionOr perform_call(Interpreter& interpreter, Value this_value, Op::CallType call_type, Value callee, ReadonlySpan argument_values, Strict strict) { auto& vm = interpreter.vm(); auto& function = callee.as_function(); Value return_value; if (call_type == Op::CallType::DirectEval) { if (callee == interpreter.realm().intrinsics().eval_function()) - return_value = TRY(perform_eval(vm, !argument_values.is_empty() ? argument_values[0] : js_undefined(), vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct)); + return_value = TRY(perform_eval(vm, !argument_values.is_empty() ? argument_values[0] : js_undefined(), strict == Strict::Yes ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct)); else return_value = TRY(JS::call(vm, function, this_value, argument_values)); } else if (call_type == Op::CallType::Call) @@ -1389,7 +1389,7 @@ inline Value new_function(Interpreter& interpreter, FunctionNode const& function } template -inline ThrowCompletionOr put_by_value(VM& vm, Value base, Optional const& base_identifier, Value property_key_value, Value value) +inline ThrowCompletionOr put_by_value(VM& vm, Value base, Optional const& base_identifier, Value property_key_value, Value value, Strict strict) { // OPTIMIZATION: Fast path for simple Int32 indexes in array-like objects. if (kind == PutKind::Normal @@ -1501,7 +1501,7 @@ inline ThrowCompletionOr put_by_value(VM& vm, Value base, Optional(vm, base, base, value, base_identifier, property_key)); + TRY(put_by_property_key(vm, base, base, value, base_identifier, property_key, strict)); return {}; } @@ -1510,7 +1510,7 @@ struct CalleeAndThis { Value this_value; }; -inline ThrowCompletionOr get_callee_and_this_from_environment(Bytecode::Interpreter& interpreter, Utf16FlyString const& name, EnvironmentCoordinate& cache) +inline ThrowCompletionOr get_callee_and_this_from_environment(Interpreter& interpreter, Utf16FlyString const& name, Strict strict, EnvironmentCoordinate& cache) { auto& vm = interpreter.vm(); @@ -1534,7 +1534,7 @@ inline ThrowCompletionOr get_callee_and_this_from_environment(Byt cache = {}; } - auto reference = TRY(vm.resolve_binding(name)); + auto reference = TRY(vm.resolve_binding(name, strict)); if (reference.environment_coordinate().has_value()) cache = reference.environment_coordinate().value(); @@ -1694,39 +1694,6 @@ inline ThrowCompletionOr append(VM& vm, Value lhs, Value rhs, bool is_spre return {}; } -inline ThrowCompletionOr delete_by_id(Bytecode::Interpreter& interpreter, Value base, IdentifierTableIndex property) -{ - auto& vm = interpreter.vm(); - - auto const& identifier = interpreter.get_identifier(property); - bool strict = vm.in_strict_mode(); - auto reference = Reference { base, identifier, {}, strict }; - - return TRY(reference.delete_(vm)); -} - -inline ThrowCompletionOr delete_by_value(Bytecode::Interpreter& interpreter, Value base, Value property_key_value) -{ - auto& vm = interpreter.vm(); - - auto property_key = TRY(property_key_value.to_property_key(vm)); - bool strict = vm.in_strict_mode(); - auto reference = Reference { base, property_key, {}, strict }; - - return Value(TRY(reference.delete_(vm))); -} - -inline ThrowCompletionOr delete_by_value_with_this(Bytecode::Interpreter& interpreter, Value base, Value property_key_value, Value this_value) -{ - auto& vm = interpreter.vm(); - - auto property_key = TRY(property_key_value.to_property_key(vm)); - bool strict = vm.in_strict_mode(); - auto reference = Reference { base, property_key, this_value, strict }; - - return Value(TRY(reference.delete_(vm))); -} - class JS_API PropertyNameIterator final : public Object , public BuiltinIterator { @@ -2290,7 +2257,7 @@ enum class BindingIsKnownToBeInitialized { }; template -static ThrowCompletionOr get_binding(Interpreter& interpreter, Operand dst, IdentifierTableIndex identifier, EnvironmentCoordinate& cache) +static ThrowCompletionOr get_binding(Interpreter& interpreter, Operand dst, IdentifierTableIndex identifier, Strict strict, EnvironmentCoordinate& cache) { auto& vm = interpreter.vm(); @@ -2312,7 +2279,7 @@ static ThrowCompletionOr get_binding(Interpreter& interpreter, Operand dst } auto& executable = interpreter.current_executable(); - auto reference = TRY(vm.resolve_binding(executable.get_identifier(identifier))); + auto reference = TRY(vm.resolve_binding(executable.get_identifier(identifier), strict)); if (reference.environment_coordinate().has_value()) cache = reference.environment_coordinate().value(); interpreter.set(dst, TRY(reference.get_value(vm))); @@ -2321,12 +2288,12 @@ static ThrowCompletionOr get_binding(Interpreter& interpreter, Operand dst ThrowCompletionOr GetBinding::execute_impl(Bytecode::Interpreter& interpreter) const { - return get_binding(interpreter, m_dst, m_identifier, m_cache); + return get_binding(interpreter, m_dst, m_identifier, strict(), m_cache); } ThrowCompletionOr GetInitializedBinding::execute_impl(Bytecode::Interpreter& interpreter) const { - return get_binding(interpreter, m_dst, m_identifier, m_cache); + return get_binding(interpreter, m_dst, m_identifier, strict(), m_cache); } ThrowCompletionOr GetCalleeAndThisFromEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const @@ -2334,6 +2301,7 @@ ThrowCompletionOr GetCalleeAndThisFromEnvironment::execute_impl(Bytecode:: auto callee_and_this = TRY(get_callee_and_this_from_environment( interpreter, interpreter.get_identifier(m_identifier), + strict(), m_cache)); interpreter.set(m_callee, callee_and_this.callee); interpreter.set(m_this_value, callee_and_this.this_value); @@ -2342,7 +2310,7 @@ ThrowCompletionOr GetCalleeAndThisFromEnvironment::execute_impl(Bytecode:: ThrowCompletionOr GetGlobal::execute_impl(Bytecode::Interpreter& interpreter) const { - interpreter.set(dst(), TRY(get_global(interpreter, m_identifier, interpreter.current_executable().global_variable_caches[m_cache_index]))); + interpreter.set(dst(), TRY(get_global(interpreter, m_identifier, strict(), interpreter.current_executable().global_variable_caches[m_cache_index]))); return {}; } @@ -2373,9 +2341,9 @@ ThrowCompletionOr SetGlobal::execute_impl(Bytecode::Interpreter& interpret if (cache.has_environment_binding_index) { if (cache.in_module_environment) { auto module = vm.running_execution_context().script_or_module.get_pointer>(); - TRY((*module)->environment()->set_mutable_binding_direct(vm, cache.environment_binding_index, src, vm.in_strict_mode())); + TRY((*module)->environment()->set_mutable_binding_direct(vm, cache.environment_binding_index, src, strict() == Strict::Yes)); } else { - TRY(declarative_record.set_mutable_binding_direct(vm, cache.environment_binding_index, src, vm.in_strict_mode())); + TRY(declarative_record.set_mutable_binding_direct(vm, cache.environment_binding_index, src, strict() == Strict::Yes)); } return {}; } @@ -2395,9 +2363,9 @@ ThrowCompletionOr SetGlobal::execute_impl(Bytecode::Interpreter& interpret cache.environment_binding_index = static_cast(index.value()); cache.has_environment_binding_index = true; cache.in_module_environment = true; - return TRY(module_environment.set_mutable_binding_direct(vm, index.value(), src, vm.in_strict_mode())); + return TRY(module_environment.set_mutable_binding_direct(vm, index.value(), src, strict() == Strict::Yes)); } - return TRY(module_environment.set_mutable_binding(vm, identifier, src, vm.in_strict_mode())); + return TRY(module_environment.set_mutable_binding(vm, identifier, src, strict() == Strict::Yes)); } } @@ -2406,14 +2374,14 @@ ThrowCompletionOr SetGlobal::execute_impl(Bytecode::Interpreter& interpret cache.environment_binding_index = static_cast(offset.value()); cache.has_environment_binding_index = true; cache.in_module_environment = false; - TRY(declarative_record.set_mutable_binding(vm, identifier, src, vm.in_strict_mode())); + TRY(declarative_record.set_mutable_binding(vm, identifier, src, strict() == Strict::Yes)); return {}; } if (TRY(binding_object.has_property(identifier))) { CacheableSetPropertyMetadata cacheable_metadata; auto success = TRY(binding_object.internal_set(identifier, src, &binding_object, &cacheable_metadata)); - if (!success && vm.in_strict_mode()) { + if (!success && strict() == Strict::Yes) { // Note: Nothing like this in the spec, this is here to produce nicer errors instead of the generic one thrown by Object::set(). auto property_or_error = binding_object.internal_get_own_property(identifier); @@ -2436,7 +2404,7 @@ ThrowCompletionOr SetGlobal::execute_impl(Bytecode::Interpreter& interpret return {}; } - auto reference = TRY(vm.resolve_binding(identifier, &declarative_record)); + auto reference = TRY(vm.resolve_binding(identifier, strict(), &declarative_record)); TRY(reference.put_value(vm, src)); return {}; @@ -2446,7 +2414,7 @@ ThrowCompletionOr DeleteVariable::execute_impl(Bytecode::Interpreter& inte { auto& vm = interpreter.vm(); auto const& string = interpreter.get_identifier(m_identifier); - auto reference = TRY(vm.resolve_binding(string)); + auto reference = TRY(vm.resolve_binding(string, strict())); interpreter.set(dst(), Value(TRY(reference.delete_(vm)))); return {}; } @@ -2548,7 +2516,7 @@ void CreateArguments::execute_impl(Bytecode::Interpreter& interpreter) const } template -static ThrowCompletionOr initialize_or_set_binding(Interpreter& interpreter, IdentifierTableIndex identifier_index, Value value, EnvironmentCoordinate& cache) +static ThrowCompletionOr initialize_or_set_binding(Interpreter& interpreter, IdentifierTableIndex identifier_index, Strict strict, Value value, EnvironmentCoordinate& cache) { auto& vm = interpreter.vm(); @@ -2563,14 +2531,14 @@ static ThrowCompletionOr initialize_or_set_binding(Interpreter& interprete if constexpr (initialization_mode == BindingInitializationMode::Initialize) { TRY(static_cast(*environment).initialize_binding_direct(vm, cache.index, value, Environment::InitializeBindingHint::Normal)); } else { - TRY(static_cast(*environment).set_mutable_binding_direct(vm, cache.index, value, vm.in_strict_mode())); + TRY(static_cast(*environment).set_mutable_binding_direct(vm, cache.index, value, strict == Strict::Yes)); } return {}; } cache = {}; } - auto reference = TRY(vm.resolve_binding(interpreter.get_identifier(identifier_index), environment)); + auto reference = TRY(vm.resolve_binding(interpreter.get_identifier(identifier_index), strict, environment)); if (reference.environment_coordinate().has_value()) cache = reference.environment_coordinate().value(); if constexpr (initialization_mode == BindingInitializationMode::Initialize) { @@ -2583,22 +2551,22 @@ static ThrowCompletionOr initialize_or_set_binding(Interpreter& interprete ThrowCompletionOr InitializeLexicalBinding::execute_impl(Bytecode::Interpreter& interpreter) const { - return initialize_or_set_binding(interpreter, m_identifier, interpreter.get(m_src), m_cache); + return initialize_or_set_binding(interpreter, m_identifier, strict(), interpreter.get(m_src), m_cache); } ThrowCompletionOr InitializeVariableBinding::execute_impl(Bytecode::Interpreter& interpreter) const { - return initialize_or_set_binding(interpreter, m_identifier, interpreter.get(m_src), m_cache); + return initialize_or_set_binding(interpreter, m_identifier, strict(), interpreter.get(m_src), m_cache); } ThrowCompletionOr SetLexicalBinding::execute_impl(Bytecode::Interpreter& interpreter) const { - return initialize_or_set_binding(interpreter, m_identifier, interpreter.get(m_src), m_cache); + return initialize_or_set_binding(interpreter, m_identifier, strict(), interpreter.get(m_src), m_cache); } ThrowCompletionOr SetVariableBinding::execute_impl(Bytecode::Interpreter& interpreter) const { - return initialize_or_set_binding(interpreter, m_identifier, interpreter.get(m_src), m_cache); + return initialize_or_set_binding(interpreter, m_identifier, strict(), interpreter.get(m_src), m_cache); } ThrowCompletionOr GetById::execute_impl(Bytecode::Interpreter& interpreter) const @@ -2678,90 +2646,90 @@ ThrowCompletionOr PutBySpread::execute_impl(Bytecode::Interpreter& interpr return {}; } -#define DEFINE_PUT_KIND_BY_ID(kind) \ - ThrowCompletionOr Put##kind##ById::execute_impl(Bytecode::Interpreter& interpreter) const \ - { \ - auto& vm = interpreter.vm(); \ - auto value = interpreter.get(m_src); \ - auto base = interpreter.get(m_base); \ - auto base_identifier = interpreter.get_identifier(m_base_identifier); \ - PropertyKey name { interpreter.get_identifier(m_property), PropertyKey::StringMayBeNumber::No }; \ - auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index]; \ - TRY(put_by_property_key(vm, base, base, value, base_identifier, name, &cache)); \ - return {}; \ - } \ - ByteString Put##kind##ById::to_byte_string_impl(Bytecode::Executable const& executable) const \ - { \ - return ByteString::formatted("Put" #kind "ById {}, {}, {}", \ - format_operand("base"sv, m_base, executable), \ - executable.identifier_table->get(m_property), \ - format_operand("src"sv, m_src, executable)); \ +#define DEFINE_PUT_KIND_BY_ID(kind) \ + ThrowCompletionOr Put##kind##ById::execute_impl(Bytecode::Interpreter& interpreter) const \ + { \ + auto& vm = interpreter.vm(); \ + auto value = interpreter.get(m_src); \ + auto base = interpreter.get(m_base); \ + auto base_identifier = interpreter.get_identifier(m_base_identifier); \ + PropertyKey name { interpreter.get_identifier(m_property), PropertyKey::StringMayBeNumber::No }; \ + auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index]; \ + TRY(put_by_property_key(vm, base, base, value, base_identifier, name, strict(), &cache)); \ + return {}; \ + } \ + ByteString Put##kind##ById::to_byte_string_impl(Bytecode::Executable const& executable) const \ + { \ + return ByteString::formatted("Put" #kind "ById {}, {}, {}", \ + format_operand("base"sv, m_base, executable), \ + executable.identifier_table->get(m_property), \ + format_operand("src"sv, m_src, executable)); \ } JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_ID) -#define DEFINE_PUT_KIND_BY_NUMERIC_ID(kind) \ - ThrowCompletionOr Put##kind##ByNumericId::execute_impl(Bytecode::Interpreter& interpreter) const \ - { \ - auto& vm = interpreter.vm(); \ - auto value = interpreter.get(m_src); \ - auto base = interpreter.get(m_base); \ - auto base_identifier = interpreter.get_identifier(m_base_identifier); \ - PropertyKey name { m_property }; \ - auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index]; \ - TRY(put_by_property_key(vm, base, base, value, base_identifier, name, &cache)); \ - return {}; \ - } \ - ByteString Put##kind##ByNumericId::to_byte_string_impl(Bytecode::Executable const& executable) const \ - { \ - return ByteString::formatted("Put" #kind "ByNumericId {}, {}, {}", \ - format_operand("base"sv, m_base, executable), \ - m_property, \ - format_operand("src"sv, m_src, executable)); \ +#define DEFINE_PUT_KIND_BY_NUMERIC_ID(kind) \ + ThrowCompletionOr Put##kind##ByNumericId::execute_impl(Bytecode::Interpreter& interpreter) const \ + { \ + auto& vm = interpreter.vm(); \ + auto value = interpreter.get(m_src); \ + auto base = interpreter.get(m_base); \ + auto base_identifier = interpreter.get_identifier(m_base_identifier); \ + PropertyKey name { m_property }; \ + auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index]; \ + TRY(put_by_property_key(vm, base, base, value, base_identifier, name, strict(), &cache)); \ + return {}; \ + } \ + ByteString Put##kind##ByNumericId::to_byte_string_impl(Bytecode::Executable const& executable) const \ + { \ + return ByteString::formatted("Put" #kind "ByNumericId {}, {}, {}", \ + format_operand("base"sv, m_base, executable), \ + m_property, \ + format_operand("src"sv, m_src, executable)); \ } JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_NUMERIC_ID) -#define DEFINE_PUT_KIND_BY_NUMERIC_ID_WITH_THIS(kind) \ - ThrowCompletionOr Put##kind##ByNumericIdWithThis::execute_impl(Bytecode::Interpreter& interpreter) const \ - { \ - auto& vm = interpreter.vm(); \ - auto value = interpreter.get(m_src); \ - auto base = interpreter.get(m_base); \ - PropertyKey name { m_property }; \ - auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index]; \ - TRY(put_by_property_key(vm, base, interpreter.get(m_this_value), value, {}, name, &cache)); \ - return {}; \ - } \ - ByteString Put##kind##ByNumericIdWithThis::to_byte_string_impl(Bytecode::Executable const& executable) const \ - { \ - return ByteString::formatted("Put" #kind "ByNumericIdWithThis {}, {}, {}, {}", \ - format_operand("base"sv, m_base, executable), \ - m_property, \ - format_operand("src"sv, m_src, executable), \ - format_operand("this"sv, m_this_value, executable)); \ +#define DEFINE_PUT_KIND_BY_NUMERIC_ID_WITH_THIS(kind) \ + ThrowCompletionOr Put##kind##ByNumericIdWithThis::execute_impl(Bytecode::Interpreter& interpreter) const \ + { \ + auto& vm = interpreter.vm(); \ + auto value = interpreter.get(m_src); \ + auto base = interpreter.get(m_base); \ + PropertyKey name { m_property }; \ + auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index]; \ + TRY(put_by_property_key(vm, base, interpreter.get(m_this_value), value, {}, name, strict(), &cache)); \ + return {}; \ + } \ + ByteString Put##kind##ByNumericIdWithThis::to_byte_string_impl(Bytecode::Executable const& executable) const \ + { \ + return ByteString::formatted("Put" #kind "ByNumericIdWithThis {}, {}, {}, {}", \ + format_operand("base"sv, m_base, executable), \ + m_property, \ + format_operand("src"sv, m_src, executable), \ + format_operand("this"sv, m_this_value, executable)); \ } JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_NUMERIC_ID_WITH_THIS) -#define DEFINE_PUT_KIND_BY_ID_WITH_THIS(kind) \ - ThrowCompletionOr Put##kind##ByIdWithThis::execute_impl(Bytecode::Interpreter& interpreter) const \ - { \ - auto& vm = interpreter.vm(); \ - auto value = interpreter.get(m_src); \ - auto base = interpreter.get(m_base); \ - PropertyKey name { interpreter.get_identifier(m_property), PropertyKey::StringMayBeNumber::No }; \ - auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index]; \ - TRY(put_by_property_key(vm, base, interpreter.get(m_this_value), value, {}, name, &cache)); \ - return {}; \ - } \ - ByteString Put##kind##ByIdWithThis::to_byte_string_impl(Bytecode::Executable const& executable) const \ - { \ - return ByteString::formatted("Put" #kind "ByIdWithThis {}, {}, {}, {}", \ - format_operand("base"sv, m_base, executable), \ - executable.identifier_table->get(m_property), \ - format_operand("src"sv, m_src, executable), \ - format_operand("this"sv, m_this_value, executable)); \ +#define DEFINE_PUT_KIND_BY_ID_WITH_THIS(kind) \ + ThrowCompletionOr Put##kind##ByIdWithThis::execute_impl(Bytecode::Interpreter& interpreter) const \ + { \ + auto& vm = interpreter.vm(); \ + auto value = interpreter.get(m_src); \ + auto base = interpreter.get(m_base); \ + PropertyKey name { interpreter.get_identifier(m_property), PropertyKey::StringMayBeNumber::No }; \ + auto& cache = interpreter.current_executable().property_lookup_caches[m_cache_index]; \ + TRY(put_by_property_key(vm, base, interpreter.get(m_this_value), value, {}, name, strict(), &cache)); \ + return {}; \ + } \ + ByteString Put##kind##ByIdWithThis::to_byte_string_impl(Bytecode::Executable const& executable) const \ + { \ + return ByteString::formatted("Put" #kind "ByIdWithThis {}, {}, {}, {}", \ + format_operand("base"sv, m_base, executable), \ + executable.identifier_table->get(m_property), \ + format_operand("src"sv, m_src, executable), \ + format_operand("this"sv, m_this_value, executable)); \ } JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_ID_WITH_THIS) @@ -2779,8 +2747,10 @@ ThrowCompletionOr PutPrivateById::execute_impl(Bytecode::Interpreter& inte ThrowCompletionOr DeleteById::execute_impl(Bytecode::Interpreter& interpreter) const { - auto base_value = interpreter.get(m_base); - interpreter.set(dst(), TRY(Bytecode::delete_by_id(interpreter, base_value, m_property))); + auto& vm = interpreter.vm(); + auto const& identifier = interpreter.get_identifier(m_property); + auto reference = Reference { interpreter.get(m_base), identifier, {}, strict() }; + interpreter.set(dst(), Value(TRY(reference.delete_(vm)))); return {}; } @@ -2789,8 +2759,7 @@ ThrowCompletionOr DeleteByIdWithThis::execute_impl(Bytecode::Interpreter& auto& vm = interpreter.vm(); auto base_value = interpreter.get(m_base); auto const& identifier = interpreter.get_identifier(m_property); - bool strict = vm.in_strict_mode(); - auto reference = Reference { base_value, identifier, interpreter.get(m_this_value), strict }; + auto reference = Reference { base_value, identifier, interpreter.get(m_this_value), strict() }; interpreter.set(dst(), Value(TRY(reference.delete_(vm)))); return {}; } @@ -2888,7 +2857,8 @@ static ThrowCompletionOr execute_call( Value this_value, ReadonlySpan arguments, Operand dst, - Optional const& expression_string) + Optional const& expression_string, + Strict strict) { TRY(throw_if_needed_for_call(interpreter, callee, call_type, expression_string)); @@ -2912,7 +2882,7 @@ static ThrowCompletionOr execute_call( Value retval; if (call_type == CallType::DirectEval && callee == interpreter.realm().intrinsics().eval_function()) { - retval = TRY(perform_eval(interpreter.vm(), !callee_context->arguments.is_empty() ? callee_context->arguments[0] : js_undefined(), interpreter.vm().in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct)); + retval = TRY(perform_eval(interpreter.vm(), !callee_context->arguments.is_empty() ? callee_context->arguments[0] : js_undefined(), strict == Strict::Yes ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct)); } else if (call_type == CallType::Construct) { retval = TRY(function.internal_construct(*callee_context, function)); } else { @@ -2924,17 +2894,17 @@ static ThrowCompletionOr execute_call( ThrowCompletionOr Call::execute_impl(Bytecode::Interpreter& interpreter) const { - return execute_call(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string); + return execute_call(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string, strict()); } NEVER_INLINE ThrowCompletionOr CallConstruct::execute_impl(Bytecode::Interpreter& interpreter) const { - return execute_call(interpreter, interpreter.get(m_callee), js_undefined(), { m_arguments, m_argument_count }, m_dst, m_expression_string); + return execute_call(interpreter, interpreter.get(m_callee), js_undefined(), { m_arguments, m_argument_count }, m_dst, m_expression_string, strict()); } ThrowCompletionOr CallDirectEval::execute_impl(Bytecode::Interpreter& interpreter) const { - return execute_call(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string); + return execute_call(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string, strict()); } ThrowCompletionOr CallBuiltin::execute_impl(Bytecode::Interpreter& interpreter) const @@ -2946,7 +2916,7 @@ ThrowCompletionOr CallBuiltin::execute_impl(Bytecode::Interpreter& interpr return {}; } - return execute_call(interpreter, callee, interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string); + return execute_call(interpreter, callee, interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string, strict()); } template @@ -2956,7 +2926,8 @@ static ThrowCompletionOr call_with_argument_array( Value this_value, Value arguments, Operand dst, - Optional const& expression_string) + Optional const& expression_string, + Strict strict) { TRY(throw_if_needed_for_call(interpreter, callee, call_type, expression_string)); @@ -2988,7 +2959,7 @@ static ThrowCompletionOr call_with_argument_array( Value retval; if (call_type == CallType::DirectEval && callee == interpreter.realm().intrinsics().eval_function()) { auto& vm = interpreter.vm(); - retval = TRY(perform_eval(vm, !callee_context->arguments.is_empty() ? callee_context->arguments[0] : js_undefined(), vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct)); + retval = TRY(perform_eval(vm, !callee_context->arguments.is_empty() ? callee_context->arguments[0] : js_undefined(), strict == Strict::Yes ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct)); } else if (call_type == CallType::Construct) { retval = TRY(function.internal_construct(*callee_context, function)); } else { @@ -3001,17 +2972,17 @@ static ThrowCompletionOr call_with_argument_array( ThrowCompletionOr CallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const { - return call_with_argument_array(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string()); + return call_with_argument_array(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string(), strict()); } ThrowCompletionOr CallDirectEvalWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const { - return call_with_argument_array(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string()); + return call_with_argument_array(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string(), strict()); } ThrowCompletionOr CallConstructWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const { - return call_with_argument_array(interpreter, interpreter.get(callee()), js_undefined(), interpreter.get(arguments()), dst(), expression_string()); + return call_with_argument_array(interpreter, interpreter.get(callee()), js_undefined(), interpreter.get(arguments()), dst(), expression_string(), strict()); } // 13.3.7.1 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-super-keyword-runtime-semantics-evaluation @@ -3276,7 +3247,7 @@ ThrowCompletionOr GetByValueWithThis::execute_impl(Bytecode::Interpreter& auto base = interpreter.get(m_base); \ auto base_identifier = interpreter.get_identifier(m_base_identifier); \ auto property = interpreter.get(m_property); \ - TRY(put_by_value(vm, base, base_identifier, property, value)); \ + TRY(put_by_value(vm, base, base_identifier, property, value, strict())); \ return {}; \ } \ ByteString Put##kind##ByValue::to_byte_string_impl(Bytecode::Executable const& executable) const \ @@ -3297,7 +3268,7 @@ JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_VALUE) auto base = interpreter.get(m_base); \ auto this_value = interpreter.get(m_this_value); \ auto property_key = TRY(interpreter.get(m_property).to_property_key(vm)); \ - TRY(put_by_property_key(vm, base, this_value, value, {}, property_key)); \ + TRY(put_by_property_key(vm, base, this_value, value, {}, property_key, strict())); \ return {}; \ } \ ByteString Put##kind##ByValueWithThis::to_byte_string_impl(Bytecode::Executable const& executable) const \ @@ -3313,20 +3284,20 @@ JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_VALUE_WITH_THIS) ThrowCompletionOr DeleteByValue::execute_impl(Bytecode::Interpreter& interpreter) const { - auto base_value = interpreter.get(m_base); - auto property_key_value = interpreter.get(m_property); - interpreter.set(dst(), TRY(delete_by_value(interpreter, base_value, property_key_value))); - + auto& vm = interpreter.vm(); + auto property_key = TRY(interpreter.get(m_property).to_property_key(vm)); + auto reference = Reference { interpreter.get(m_base), property_key, {}, strict() }; + interpreter.set(m_dst, Value(TRY(reference.delete_(vm)))); return {}; } ThrowCompletionOr DeleteByValueWithThis::execute_impl(Bytecode::Interpreter& interpreter) const { + auto& vm = interpreter.vm(); auto property_key_value = interpreter.get(m_property); - auto base_value = interpreter.get(m_base); - auto this_value = interpreter.get(m_this_value); - interpreter.set(dst(), TRY(delete_by_value_with_this(interpreter, base_value, property_key_value, this_value))); - + auto property_key = TRY(property_key_value.to_property_key(vm)); + auto reference = Reference { interpreter.get(m_base), property_key, interpreter.get(m_this_value), strict() }; + interpreter.set(dst(), Value(TRY(reference.delete_(vm)))); return {}; } @@ -3442,7 +3413,7 @@ ThrowCompletionOr TypeofBinding::execute_impl(Bytecode::Interpreter& inter } // 1. Let val be the result of evaluating UnaryExpression. - auto reference = TRY(vm.resolve_binding(interpreter.get_identifier(m_identifier))); + auto reference = TRY(vm.resolve_binding(interpreter.get_identifier(m_identifier), strict())); // 2. If val is a Reference Record, then // a. If IsUnresolvableReference(val) is true, return "undefined". diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h index 80aa8cbe79..9828ca4b64 100644 --- a/Libraries/LibJS/Forward.h +++ b/Libraries/LibJS/Forward.h @@ -152,6 +152,11 @@ namespace JS { +enum class Strict : u8 { + No, + Yes, +}; + class ASTNode; class Accessor; class Agent; diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 2c9e780146..3b723f00d5 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -810,6 +810,8 @@ void Parser::parse_script(Program& program, bool starts_in_strict_mode) void Parser::parse_module(Program& program) { + program.set_strict_mode(); + TemporaryChange strict_mode_rollback(m_state.strict_mode, true); TemporaryChange await_expression_valid_rollback(m_state.await_expression_is_valid, true); diff --git a/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Libraries/LibJS/Runtime/AbstractOperations.cpp index 67dbd58322..f2e020cc59 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.cpp +++ b/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -238,30 +238,6 @@ ThrowCompletionOr get_function_realm(VM& vm, FunctionObject const& funct return vm.current_realm(); } -// 8.5.2.1 InitializeBoundName ( name, value, environment ), https://tc39.es/ecma262/#sec-initializeboundname -ThrowCompletionOr initialize_bound_name(VM& vm, Utf16FlyString const& name, Value value, Environment* environment) -{ - // 1. If environment is not undefined, then - if (environment) { - // FIXME: The normal is not included in the explicit resource management spec yet, so there is no spec link for it. - // a. Perform ! environment.InitializeBinding(name, value, normal). - MUST(environment->initialize_binding(vm, name, value, Environment::InitializeBindingHint::Normal)); - - // b. Return unused. - return {}; - } - // 2. Else, - else { - // a. Let lhs be ? ResolveBinding(name). - auto lhs = TRY(vm.resolve_binding(name)); - - // b. Return ? PutValue(lhs, value). - return TRY(lhs.put_value(vm, value)); - } - - VERIFY_NOT_REACHED(); -} - // 10.1.6.2 IsCompatiblePropertyDescriptor ( Extensible, Desc, Current ), https://tc39.es/ecma262/#sec-iscompatiblepropertydescriptor bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor& descriptor, Optional const& current) { diff --git a/Libraries/LibJS/Runtime/AbstractOperations.h b/Libraries/LibJS/Runtime/AbstractOperations.h index 814eaaf9d2..50981c97ea 100644 --- a/Libraries/LibJS/Runtime/AbstractOperations.h +++ b/Libraries/LibJS/Runtime/AbstractOperations.h @@ -40,7 +40,6 @@ JS_API ThrowCompletionOr length_of_array_like(VM&, Object const&); ThrowCompletionOr> create_list_from_array_like(VM&, Value, Function(Value)> = {}); ThrowCompletionOr species_constructor(VM&, Object const&, FunctionObject& default_constructor); JS_API ThrowCompletionOr get_function_realm(VM&, FunctionObject const&); -ThrowCompletionOr initialize_bound_name(VM&, Utf16FlyString const&, Value, Environment*); bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor&, Optional const& current); bool validate_and_apply_property_descriptor(Object*, PropertyKey const&, bool extensible, PropertyDescriptor&, Optional const& current); JS_API ThrowCompletionOr get_prototype_from_constructor(VM&, FunctionObject const& constructor, GC::Ref (Intrinsics::*intrinsic_default_prototype)()); diff --git a/Libraries/LibJS/Runtime/Reference.cpp b/Libraries/LibJS/Runtime/Reference.cpp index d4d500734f..c4e8b40a9f 100644 --- a/Libraries/LibJS/Runtime/Reference.cpp +++ b/Libraries/LibJS/Runtime/Reference.cpp @@ -25,7 +25,7 @@ ThrowCompletionOr Reference::put_value(VM& vm, Value value) // 4. If IsUnresolvableReference(V) is true, then if (is_unresolvable()) { // a. If V.[[Strict]] is true, throw a ReferenceError exception. - if (m_strict) + if (m_strict == Strict::Yes) return throw_reference_error(vm); // b. Let globalObj be GetGlobalObject(). @@ -53,7 +53,7 @@ ThrowCompletionOr Reference::put_value(VM& vm, Value value) auto succeeded = TRY(base_obj->internal_set(name(), value, get_this_value())); // d. If succeeded is false and V.[[Strict]] is true, throw a TypeError exception. - if (!succeeded && m_strict) + if (!succeeded && m_strict == Strict::Yes) return vm.throw_completion(ErrorType::ReferenceNullishSetProperty, name(), m_base_value.to_string_without_side_effects()); // e. Return unused. @@ -69,9 +69,9 @@ ThrowCompletionOr Reference::put_value(VM& vm, Value value) // c. Return ? base.SetMutableBinding(V.[[ReferencedName]], W, V.[[Strict]]) (see 9.1). if (m_environment_coordinate.has_value()) - return static_cast(m_base_environment)->set_mutable_binding_direct(vm, m_environment_coordinate->index, value, m_strict); + return static_cast(m_base_environment)->set_mutable_binding_direct(vm, m_environment_coordinate->index, value, m_strict == Strict::Yes); else - return m_base_environment->set_mutable_binding(vm, name().as_string(), value, m_strict); + return m_base_environment->set_mutable_binding(vm, name().as_string(), value, m_strict == Strict::Yes); } Completion Reference::throw_reference_error(VM& vm) const @@ -144,7 +144,7 @@ ThrowCompletionOr Reference::get_value(VM& vm) const // c. Return ? base.GetBindingValue(V.[[ReferencedName]], V.[[Strict]]) (see 9.1). if (m_environment_coordinate.has_value()) return static_cast(m_base_environment)->get_binding_value_direct(vm, m_environment_coordinate->index); - return m_base_environment->get_binding_value(vm, name().as_string(), m_strict); + return m_base_environment->get_binding_value(vm, name().as_string(), m_strict == Strict::Yes); } // 13.5.1.2 Runtime Semantics: Evaluation, https://tc39.es/ecma262/#sec-delete-operator-runtime-semantics-evaluation @@ -161,7 +161,7 @@ ThrowCompletionOr Reference::delete_(VM& vm) // 4. If IsUnresolvableReference(ref) is true, then if (is_unresolvable()) { // a. Assert: ref.[[Strict]] is false. - VERIFY(!m_strict); + VERIFY(m_strict == Strict::No); // b. Return true. return true; } @@ -182,7 +182,7 @@ ThrowCompletionOr Reference::delete_(VM& vm) bool delete_status = TRY(base_obj->internal_delete(name())); // e. If deleteStatus is false and ref.[[Strict]] is true, throw a TypeError exception. - if (!delete_status && m_strict) + if (!delete_status && m_strict == Strict::Yes) return vm.throw_completion(ErrorType::ReferenceNullishDeleteProperty, name(), m_base_value.to_string_without_side_effects()); // f. Return deleteStatus. diff --git a/Libraries/LibJS/Runtime/Reference.h b/Libraries/LibJS/Runtime/Reference.h index 1b20017e23..0004062a9f 100644 --- a/Libraries/LibJS/Runtime/Reference.h +++ b/Libraries/LibJS/Runtime/Reference.h @@ -24,14 +24,14 @@ public: Environment, }; - Reference(BaseType type, PropertyKey name, bool strict) + Reference(BaseType type, PropertyKey name, Strict strict) : m_base_type(type) , m_name(move(name)) , m_strict(strict) { } - Reference(Value base, PropertyKey name, Optional this_value, bool strict = false) + Reference(Value base, PropertyKey name, Optional this_value, Strict strict) : m_base_type(BaseType::Value) , m_base_value(base) , m_name(move(name)) @@ -40,7 +40,7 @@ public: { } - Reference(Environment& base, Utf16FlyString referenced_name, bool strict = false, Optional environment_coordinate = {}) + Reference(Environment& base, Utf16FlyString referenced_name, Strict strict, Optional environment_coordinate = {}) : m_base_type(BaseType::Environment) , m_base_environment(&base) , m_name(move(referenced_name)) @@ -53,7 +53,7 @@ public: : m_base_type(BaseType::Value) , m_base_value(base) , m_name(move(name)) - , m_strict(true) + , m_strict(Strict::Yes) { } @@ -71,7 +71,7 @@ public: PropertyKey const& name() const { return m_name.get(); } PrivateName const& private_name() const { return m_name.get(); } - bool is_strict() const { return m_strict; } + bool is_strict() const { return m_strict == Strict::Yes; } // 6.2.4.2 IsUnresolvableReference ( V ), https://tc39.es/ecma262/#sec-isunresolvablereference bool is_unresolvable() const { return m_base_type == BaseType::Unresolvable; } @@ -133,7 +133,7 @@ private: }; Variant m_name; Optional m_this_value; - bool m_strict { false }; + Strict m_strict { Strict::No }; Optional m_environment_coordinate; }; diff --git a/Libraries/LibJS/Runtime/VM.cpp b/Libraries/LibJS/Runtime/VM.cpp index 4cd097d073..2498f1bb37 100644 --- a/Libraries/LibJS/Runtime/VM.cpp +++ b/Libraries/LibJS/Runtime/VM.cpp @@ -287,7 +287,7 @@ void VM::gather_roots(HashMap& roots) } // 9.1.2.1 GetIdentifierReference ( env, name, strict ), https://tc39.es/ecma262/#sec-getidentifierreference -ThrowCompletionOr VM::get_identifier_reference(Environment* environment, Utf16FlyString name, bool strict, size_t hops) +ThrowCompletionOr VM::get_identifier_reference(Environment* environment, Utf16FlyString name, Strict strict, size_t hops) { // 1. If env is the value null, then if (!environment) { @@ -321,7 +321,7 @@ ThrowCompletionOr VM::get_identifier_reference(Environment* environme } // 9.4.2 ResolveBinding ( name [ , env ] ), https://tc39.es/ecma262/#sec-resolvebinding -ThrowCompletionOr VM::resolve_binding(Utf16FlyString const& name, Environment* environment) +ThrowCompletionOr VM::resolve_binding(Utf16FlyString const& name, Strict strict, Environment* environment) { // 1. If env is not present or if env is undefined, then if (!environment) { @@ -333,7 +333,7 @@ ThrowCompletionOr VM::resolve_binding(Utf16FlyString const& name, Env VERIFY(environment); // 3. If the source text matched by the syntactic production that is being evaluated is contained in strict mode code, let strict be true; else let strict be false. - bool strict = in_strict_mode(); + // NOTE: We take this as a parameter. // 4. Return ? GetIdentifierReference(env, name, strict). return get_identifier_reference(environment, name, strict); diff --git a/Libraries/LibJS/Runtime/VM.h b/Libraries/LibJS/Runtime/VM.h index 6470d01ebc..8d138b8492 100644 --- a/Libraries/LibJS/Runtime/VM.h +++ b/Libraries/LibJS/Runtime/VM.h @@ -174,11 +174,6 @@ public: FunctionObject const* active_function_object() const { return running_execution_context().function; } FunctionObject* active_function_object() { return running_execution_context().function; } - bool in_strict_mode() const - { - return running_execution_context().is_strict_mode; - } - size_t argument_count() const { return running_execution_context().arguments.size(); @@ -204,8 +199,8 @@ public: u32 execution_generation() const { return m_execution_generation; } void finish_execution_generation() { ++m_execution_generation; } - ThrowCompletionOr resolve_binding(Utf16FlyString const&, Environment* = nullptr); - ThrowCompletionOr get_identifier_reference(Environment*, Utf16FlyString, bool strict, size_t hops = 0); + ThrowCompletionOr resolve_binding(Utf16FlyString const&, Strict, Environment* = nullptr); + ThrowCompletionOr get_identifier_reference(Environment*, Utf16FlyString, Strict, size_t hops = 0); // 5.2.3.2 Throw an Exception, https://tc39.es/ecma262/#sec-throw-an-exception template diff --git a/Tests/LibJS/test-js.cpp b/Tests/LibJS/test-js.cpp index f2ccf88e93..386697f792 100644 --- a/Tests/LibJS/test-js.cpp +++ b/Tests/LibJS/test-js.cpp @@ -19,7 +19,7 @@ TESTJS_PROGRAM_FLAG(test262_parser_tests, "Run test262 parser tests", "test262-p TESTJS_GLOBAL_FUNCTION(is_strict_mode, isStrictMode, 0) { - return JS::Value(vm.in_strict_mode()); + return JS::Value(vm.running_execution_context().is_strict_mode); } TESTJS_GLOBAL_FUNCTION(can_parse_source, canParseSource) @@ -83,7 +83,7 @@ TESTJS_GLOBAL_FUNCTION(mark_as_garbage, markAsGarbage) if (!outer_environment.has_value()) return vm.throw_completion(JS::ErrorType::UnknownIdentifier, variable_name.utf8_string_view()); - auto reference = TRY(vm.resolve_binding(variable_name.utf16_string(), outer_environment.value()->lexical_environment)); + auto reference = TRY(vm.resolve_binding(variable_name.utf16_string(), JS::Strict::No, outer_environment.value()->lexical_environment)); auto value = TRY(reference.get_value(vm)); diff --git a/Utilities/js.cpp b/Utilities/js.cpp index b07d78f69b..0c5fe40f63 100644 --- a/Utilities/js.cpp +++ b/Utilities/js.cpp @@ -766,7 +766,7 @@ static ErrorOr run_repl(bool gc_on_every_allocation, bool syntax_highlight) switch (mode) { case CompleteProperty: { - auto reference_or_error = g_vm->resolve_binding(variable_name, &global_environment); + auto reference_or_error = g_vm->resolve_binding(variable_name, JS::Strict::No, &global_environment); if (reference_or_error.is_error()) return {}; auto value_or_error = reference_or_error.value().get_value(*g_vm);