mirror of
https://github.com/zebrajr/ladybird.git
synced 2025-12-06 00:19:53 +01:00
LibJS: Let bytecode instructions know whether they are in strict mode
This commits puts the strict mode flag in the header of every bytecode instruction. This allows us to check for strict mode without looking at the currently running execution context.
This commit is contained in:
parent
3fb678b376
commit
fb05063dde
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -218,6 +218,14 @@ CodeGenerationErrorOr<void> Generator::emit_function_declaration_instantiation(E
|
|||
CodeGenerationErrorOr<GC::Ref<Executable>> Generator::compile(VM& vm, ASTNode const& node, FunctionKind enclosing_function_kind, GC::Ptr<ECMAScriptFunctionObject const> function, MustPropagateCompletion must_propagate_completion, Vector<LocalVariable> local_variable_names)
|
||||
{
|
||||
Generator generator(vm, function, must_propagate_completion);
|
||||
|
||||
if (is<Program>(node))
|
||||
generator.m_strict = static_cast<Program const&>(node).is_strict_mode() ? Strict::Yes : Strict::No;
|
||||
else if (is<FunctionBody>(node))
|
||||
generator.m_strict = static_cast<FunctionBody const&>(node).in_strict_mode() ? Strict::Yes : Strict::No;
|
||||
else if (is<FunctionDeclaration>(node))
|
||||
generator.m_strict = static_cast<FunctionDeclaration const&>(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<GC::Ref<Executable>> Generator::compile(VM& vm, ASTNode co
|
|||
}
|
||||
}
|
||||
|
||||
bool is_strict_mode = false;
|
||||
if (is<Program>(node))
|
||||
is_strict_mode = static_cast<Program const&>(node).is_strict_mode();
|
||||
else if (is<FunctionBody>(node))
|
||||
is_strict_mode = static_cast<FunctionBody const&>(node).in_strict_mode();
|
||||
else if (is<FunctionDeclaration>(node))
|
||||
is_strict_mode = static_cast<FunctionDeclaration const&>(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<GC::Ref<Executable>> 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<Executable::ExceptionHandlers> linked_exception_handlers;
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ public:
|
|||
grow(sizeof(OpType));
|
||||
void* slot = m_current_basic_block->data() + slot_offset;
|
||||
new (slot) OpType(forward<Args>(args)...);
|
||||
static_cast<OpType*>(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>(args)...);
|
||||
static_cast<OpType*>(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<FlyString> 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 };
|
||||
|
|
|
|||
|
|
@ -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<void(Operand&)> 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 {
|
||||
|
|
|
|||
|
|
@ -1023,7 +1023,7 @@ inline ThrowCompletionOr<Value> get_by_value(VM& vm, Optional<IdentifierTableInd
|
|||
return TRY(object->internal_get(property_key, base_value));
|
||||
}
|
||||
|
||||
inline ThrowCompletionOr<Value> get_global(Interpreter& interpreter, IdentifierTableIndex identifier_index, GlobalVariableCache& cache)
|
||||
inline ThrowCompletionOr<Value> 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<Value> 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<Value> get_global(Interpreter& interpreter, IdentifierT
|
|||
cache.environment_binding_index = static_cast<u32>(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<Value> get_global(Interpreter& interpreter, IdentifierT
|
|||
}
|
||||
|
||||
template<PutKind kind>
|
||||
ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value, Value value, Optional<Utf16FlyString const&> const& base_identifier, PropertyKey name, PropertyLookupCache* caches = nullptr)
|
||||
ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value, Value value, Optional<Utf16FlyString const&> 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<TypeError>(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects());
|
||||
|
||||
// a. Let baseObj be ? ToObject(V.[[Base]]).
|
||||
|
|
@ -1277,7 +1277,7 @@ ThrowCompletionOr<void> 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<TypeError>(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects());
|
||||
return vm.throw_completion<TypeError>(ErrorType::ReferencePrimitiveSetProperty, name, base.typeof_(vm)->utf8_string(), base.to_string_without_side_effects());
|
||||
|
|
@ -1296,14 +1296,14 @@ ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value
|
|||
return {};
|
||||
}
|
||||
|
||||
inline ThrowCompletionOr<Value> perform_call(Interpreter& interpreter, Value this_value, Op::CallType call_type, Value callee, ReadonlySpan<Value> argument_values)
|
||||
inline ThrowCompletionOr<Value> perform_call(Interpreter& interpreter, Value this_value, Op::CallType call_type, Value callee, ReadonlySpan<Value> 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<PutKind kind>
|
||||
inline ThrowCompletionOr<void> put_by_value(VM& vm, Value base, Optional<Utf16FlyString const&> const& base_identifier, Value property_key_value, Value value)
|
||||
inline ThrowCompletionOr<void> put_by_value(VM& vm, Value base, Optional<Utf16FlyString const&> 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<void> put_by_value(VM& vm, Value base, Optional<Utf16Fl
|
|||
}
|
||||
|
||||
auto property_key = TRY(property_key_value.to_property_key(vm));
|
||||
TRY(put_by_property_key<kind>(vm, base, base, value, base_identifier, property_key));
|
||||
TRY(put_by_property_key<kind>(vm, base, base, value, base_identifier, property_key, strict));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
@ -1510,7 +1510,7 @@ struct CalleeAndThis {
|
|||
Value this_value;
|
||||
};
|
||||
|
||||
inline ThrowCompletionOr<CalleeAndThis> get_callee_and_this_from_environment(Bytecode::Interpreter& interpreter, Utf16FlyString const& name, EnvironmentCoordinate& cache)
|
||||
inline ThrowCompletionOr<CalleeAndThis> 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<CalleeAndThis> 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<void> append(VM& vm, Value lhs, Value rhs, bool is_spre
|
|||
return {};
|
||||
}
|
||||
|
||||
inline ThrowCompletionOr<Value> 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<Value> 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<Value> 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<BindingIsKnownToBeInitialized binding_is_known_to_be_initialized>
|
||||
static ThrowCompletionOr<void> get_binding(Interpreter& interpreter, Operand dst, IdentifierTableIndex identifier, EnvironmentCoordinate& cache)
|
||||
static ThrowCompletionOr<void> get_binding(Interpreter& interpreter, Operand dst, IdentifierTableIndex identifier, Strict strict, EnvironmentCoordinate& cache)
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
||||
|
|
@ -2312,7 +2279,7 @@ static ThrowCompletionOr<void> 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<void> get_binding(Interpreter& interpreter, Operand dst
|
|||
|
||||
ThrowCompletionOr<void> GetBinding::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return get_binding<BindingIsKnownToBeInitialized::No>(interpreter, m_dst, m_identifier, m_cache);
|
||||
return get_binding<BindingIsKnownToBeInitialized::No>(interpreter, m_dst, m_identifier, strict(), m_cache);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> GetInitializedBinding::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return get_binding<BindingIsKnownToBeInitialized::Yes>(interpreter, m_dst, m_identifier, m_cache);
|
||||
return get_binding<BindingIsKnownToBeInitialized::Yes>(interpreter, m_dst, m_identifier, strict(), m_cache);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> GetCalleeAndThisFromEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
|
|
@ -2334,6 +2301,7 @@ ThrowCompletionOr<void> 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<void> GetCalleeAndThisFromEnvironment::execute_impl(Bytecode::
|
|||
|
||||
ThrowCompletionOr<void> 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<void> 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<GC::Ref<Module>>();
|
||||
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<void> SetGlobal::execute_impl(Bytecode::Interpreter& interpret
|
|||
cache.environment_binding_index = static_cast<u32>(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<void> SetGlobal::execute_impl(Bytecode::Interpreter& interpret
|
|||
cache.environment_binding_index = static_cast<u32>(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<void> 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<void> 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<EnvironmentMode environment_mode, BindingInitializationMode initialization_mode>
|
||||
static ThrowCompletionOr<void> initialize_or_set_binding(Interpreter& interpreter, IdentifierTableIndex identifier_index, Value value, EnvironmentCoordinate& cache)
|
||||
static ThrowCompletionOr<void> 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<void> initialize_or_set_binding(Interpreter& interprete
|
|||
if constexpr (initialization_mode == BindingInitializationMode::Initialize) {
|
||||
TRY(static_cast<DeclarativeEnvironment&>(*environment).initialize_binding_direct(vm, cache.index, value, Environment::InitializeBindingHint::Normal));
|
||||
} else {
|
||||
TRY(static_cast<DeclarativeEnvironment&>(*environment).set_mutable_binding_direct(vm, cache.index, value, vm.in_strict_mode()));
|
||||
TRY(static_cast<DeclarativeEnvironment&>(*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<void> initialize_or_set_binding(Interpreter& interprete
|
|||
|
||||
ThrowCompletionOr<void> InitializeLexicalBinding::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return initialize_or_set_binding<EnvironmentMode::Lexical, BindingInitializationMode::Initialize>(interpreter, m_identifier, interpreter.get(m_src), m_cache);
|
||||
return initialize_or_set_binding<EnvironmentMode::Lexical, BindingInitializationMode::Initialize>(interpreter, m_identifier, strict(), interpreter.get(m_src), m_cache);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> InitializeVariableBinding::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return initialize_or_set_binding<EnvironmentMode::Var, BindingInitializationMode::Initialize>(interpreter, m_identifier, interpreter.get(m_src), m_cache);
|
||||
return initialize_or_set_binding<EnvironmentMode::Var, BindingInitializationMode::Initialize>(interpreter, m_identifier, strict(), interpreter.get(m_src), m_cache);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> SetLexicalBinding::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return initialize_or_set_binding<EnvironmentMode::Lexical, BindingInitializationMode::Set>(interpreter, m_identifier, interpreter.get(m_src), m_cache);
|
||||
return initialize_or_set_binding<EnvironmentMode::Lexical, BindingInitializationMode::Set>(interpreter, m_identifier, strict(), interpreter.get(m_src), m_cache);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> SetVariableBinding::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return initialize_or_set_binding<EnvironmentMode::Var, BindingInitializationMode::Set>(interpreter, m_identifier, interpreter.get(m_src), m_cache);
|
||||
return initialize_or_set_binding<EnvironmentMode::Var, BindingInitializationMode::Set>(interpreter, m_identifier, strict(), interpreter.get(m_src), m_cache);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> GetById::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
|
|
@ -2687,7 +2655,7 @@ ThrowCompletionOr<void> PutBySpread::execute_impl(Bytecode::Interpreter& interpr
|
|||
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<PutKind::kind>(vm, base, base, value, base_identifier, name, &cache)); \
|
||||
TRY(put_by_property_key<PutKind::kind>(vm, base, base, value, base_identifier, name, strict(), &cache)); \
|
||||
return {}; \
|
||||
} \
|
||||
ByteString Put##kind##ById::to_byte_string_impl(Bytecode::Executable const& executable) const \
|
||||
|
|
@ -2709,7 +2677,7 @@ JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_ID)
|
|||
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<PutKind::kind>(vm, base, base, value, base_identifier, name, &cache)); \
|
||||
TRY(put_by_property_key<PutKind::kind>(vm, base, base, value, base_identifier, name, strict(), &cache)); \
|
||||
return {}; \
|
||||
} \
|
||||
ByteString Put##kind##ByNumericId::to_byte_string_impl(Bytecode::Executable const& executable) const \
|
||||
|
|
@ -2730,7 +2698,7 @@ JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_NUMERIC_ID)
|
|||
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<PutKind::kind>(vm, base, interpreter.get(m_this_value), value, {}, name, &cache)); \
|
||||
TRY(put_by_property_key<PutKind::kind>(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 \
|
||||
|
|
@ -2752,7 +2720,7 @@ JS_ENUMERATE_PUT_KINDS(DEFINE_PUT_KIND_BY_NUMERIC_ID_WITH_THIS)
|
|||
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<PutKind::kind>(vm, base, interpreter.get(m_this_value), value, {}, name, &cache)); \
|
||||
TRY(put_by_property_key<PutKind::kind>(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 \
|
||||
|
|
@ -2779,8 +2747,10 @@ ThrowCompletionOr<void> PutPrivateById::execute_impl(Bytecode::Interpreter& inte
|
|||
|
||||
ThrowCompletionOr<void> 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<void> 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<void> execute_call(
|
|||
Value this_value,
|
||||
ReadonlySpan<Operand> arguments,
|
||||
Operand dst,
|
||||
Optional<StringTableIndex> const& expression_string)
|
||||
Optional<StringTableIndex> const& expression_string,
|
||||
Strict strict)
|
||||
{
|
||||
TRY(throw_if_needed_for_call(interpreter, callee, call_type, expression_string));
|
||||
|
||||
|
|
@ -2912,7 +2882,7 @@ static ThrowCompletionOr<void> 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<void> execute_call(
|
|||
|
||||
ThrowCompletionOr<void> Call::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return execute_call<CallType::Call>(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||
return execute_call<CallType::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<void> CallConstruct::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return execute_call<CallType::Construct>(interpreter, interpreter.get(m_callee), js_undefined(), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||
return execute_call<CallType::Construct>(interpreter, interpreter.get(m_callee), js_undefined(), { m_arguments, m_argument_count }, m_dst, m_expression_string, strict());
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CallDirectEval::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return execute_call<CallType::DirectEval>(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||
return execute_call<CallType::DirectEval>(interpreter, interpreter.get(m_callee), interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string, strict());
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CallBuiltin::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
|
|
@ -2946,7 +2916,7 @@ ThrowCompletionOr<void> CallBuiltin::execute_impl(Bytecode::Interpreter& interpr
|
|||
return {};
|
||||
}
|
||||
|
||||
return execute_call<CallType::Call>(interpreter, callee, interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string);
|
||||
return execute_call<CallType::Call>(interpreter, callee, interpreter.get(m_this_value), { m_arguments, m_argument_count }, m_dst, m_expression_string, strict());
|
||||
}
|
||||
|
||||
template<CallType call_type>
|
||||
|
|
@ -2956,7 +2926,8 @@ static ThrowCompletionOr<void> call_with_argument_array(
|
|||
Value this_value,
|
||||
Value arguments,
|
||||
Operand dst,
|
||||
Optional<StringTableIndex> const& expression_string)
|
||||
Optional<StringTableIndex> const& expression_string,
|
||||
Strict strict)
|
||||
{
|
||||
TRY(throw_if_needed_for_call(interpreter, callee, call_type, expression_string));
|
||||
|
||||
|
|
@ -2988,7 +2959,7 @@ static ThrowCompletionOr<void> 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<void> call_with_argument_array(
|
|||
|
||||
ThrowCompletionOr<void> CallWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return call_with_argument_array<CallType::Call>(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string());
|
||||
return call_with_argument_array<CallType::Call>(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string(), strict());
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CallDirectEvalWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return call_with_argument_array<CallType::DirectEval>(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string());
|
||||
return call_with_argument_array<CallType::DirectEval>(interpreter, interpreter.get(callee()), interpreter.get(this_value()), interpreter.get(arguments()), dst(), expression_string(), strict());
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> CallConstructWithArgumentArray::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
return call_with_argument_array<CallType::Construct>(interpreter, interpreter.get(callee()), js_undefined(), interpreter.get(arguments()), dst(), expression_string());
|
||||
return call_with_argument_array<CallType::Construct>(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<void> 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<PutKind::kind>(vm, base, base_identifier, property, value)); \
|
||||
TRY(put_by_value<PutKind::kind>(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<PutKind::kind>(vm, base, this_value, value, {}, property_key)); \
|
||||
TRY(put_by_property_key<PutKind::kind>(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<void> 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<void> 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<void> 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".
|
||||
|
|
|
|||
|
|
@ -152,6 +152,11 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
enum class Strict : u8 {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
class ASTNode;
|
||||
class Accessor;
|
||||
class Agent;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -238,30 +238,6 @@ ThrowCompletionOr<Realm*> 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<void> 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<PropertyDescriptor> const& current)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ JS_API ThrowCompletionOr<size_t> length_of_array_like(VM&, Object const&);
|
|||
ThrowCompletionOr<GC::RootVector<Value>> create_list_from_array_like(VM&, Value, Function<ThrowCompletionOr<void>(Value)> = {});
|
||||
ThrowCompletionOr<FunctionObject*> species_constructor(VM&, Object const&, FunctionObject& default_constructor);
|
||||
JS_API ThrowCompletionOr<Realm*> get_function_realm(VM&, FunctionObject const&);
|
||||
ThrowCompletionOr<void> initialize_bound_name(VM&, Utf16FlyString const&, Value, Environment*);
|
||||
bool is_compatible_property_descriptor(bool extensible, PropertyDescriptor&, Optional<PropertyDescriptor> const& current);
|
||||
bool validate_and_apply_property_descriptor(Object*, PropertyKey const&, bool extensible, PropertyDescriptor&, Optional<PropertyDescriptor> const& current);
|
||||
JS_API ThrowCompletionOr<Object*> get_prototype_from_constructor(VM&, FunctionObject const& constructor, GC::Ref<Object> (Intrinsics::*intrinsic_default_prototype)());
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ ThrowCompletionOr<void> 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<void> 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<TypeError>(ErrorType::ReferenceNullishSetProperty, name(), m_base_value.to_string_without_side_effects());
|
||||
|
||||
// e. Return unused.
|
||||
|
|
@ -69,9 +69,9 @@ ThrowCompletionOr<void> 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<DeclarativeEnvironment*>(m_base_environment)->set_mutable_binding_direct(vm, m_environment_coordinate->index, value, m_strict);
|
||||
return static_cast<DeclarativeEnvironment*>(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<Value> 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<DeclarativeEnvironment*>(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<bool> 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<bool> 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<TypeError>(ErrorType::ReferenceNullishDeleteProperty, name(), m_base_value.to_string_without_side_effects());
|
||||
|
||||
// f. Return deleteStatus.
|
||||
|
|
|
|||
|
|
@ -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<Value> this_value, bool strict = false)
|
||||
Reference(Value base, PropertyKey name, Optional<Value> 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<EnvironmentCoordinate> environment_coordinate = {})
|
||||
Reference(Environment& base, Utf16FlyString referenced_name, Strict strict, Optional<EnvironmentCoordinate> 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<PropertyKey>(); }
|
||||
PrivateName const& private_name() const { return m_name.get<PrivateName>(); }
|
||||
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<PropertyKey, PrivateName> m_name;
|
||||
Optional<Value> m_this_value;
|
||||
bool m_strict { false };
|
||||
Strict m_strict { Strict::No };
|
||||
|
||||
Optional<EnvironmentCoordinate> m_environment_coordinate;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ void VM::gather_roots(HashMap<GC::Cell*, GC::HeapRoot>& roots)
|
|||
}
|
||||
|
||||
// 9.1.2.1 GetIdentifierReference ( env, name, strict ), https://tc39.es/ecma262/#sec-getidentifierreference
|
||||
ThrowCompletionOr<Reference> VM::get_identifier_reference(Environment* environment, Utf16FlyString name, bool strict, size_t hops)
|
||||
ThrowCompletionOr<Reference> 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<Reference> VM::get_identifier_reference(Environment* environme
|
|||
}
|
||||
|
||||
// 9.4.2 ResolveBinding ( name [ , env ] ), https://tc39.es/ecma262/#sec-resolvebinding
|
||||
ThrowCompletionOr<Reference> VM::resolve_binding(Utf16FlyString const& name, Environment* environment)
|
||||
ThrowCompletionOr<Reference> 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<Reference> 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);
|
||||
|
|
|
|||
|
|
@ -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<Reference> resolve_binding(Utf16FlyString const&, Environment* = nullptr);
|
||||
ThrowCompletionOr<Reference> get_identifier_reference(Environment*, Utf16FlyString, bool strict, size_t hops = 0);
|
||||
ThrowCompletionOr<Reference> resolve_binding(Utf16FlyString const&, Strict, Environment* = nullptr);
|
||||
ThrowCompletionOr<Reference> 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<typename T, typename... Args>
|
||||
|
|
|
|||
|
|
@ -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::ReferenceError>(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));
|
||||
|
||||
|
|
|
|||
|
|
@ -766,7 +766,7 @@ static ErrorOr<int> 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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user