mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00: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
Notes:
github-actions[bot]
2025-10-29 20:22:27 +00:00
Author: https://github.com/awesomekling
Commit: fb05063dde
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6629
16 changed files with 183 additions and 227 deletions
|
|
@ -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
|
||||
|
|
@ -2678,90 +2646,90 @@ ThrowCompletionOr<void> PutBySpread::execute_impl(Bytecode::Interpreter& interpr
|
|||
return {};
|
||||
}
|
||||
|
||||
#define DEFINE_PUT_KIND_BY_ID(kind) \
|
||||
ThrowCompletionOr<void> 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<PutKind::kind>(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<void> 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<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 \
|
||||
{ \
|
||||
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<void> 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<PutKind::kind>(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<void> 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<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 \
|
||||
{ \
|
||||
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<void> 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<PutKind::kind>(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<void> 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<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 \
|
||||
{ \
|
||||
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<void> 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<PutKind::kind>(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<void> 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<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 \
|
||||
{ \
|
||||
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<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".
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue