diff --git a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp index 1cc0936631..9e80b65e09 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -542,10 +542,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_locale_string) return {}; if (value.is_nullish()) continue; - auto* value_object = value.to_object(global_object); - if (!value_object) - return {}; - auto locale_string_result = value_object->invoke(vm.names.toLocaleString); + auto locale_string_result = value.invoke(global_object, vm.names.toLocaleString); if (vm.exception()) return {}; auto string = locale_string_result.to_string(global_object); diff --git a/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp b/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp index 43852dd484..3c3e85eb3e 100644 --- a/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/DatePrototype.cpp @@ -846,18 +846,16 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_string) // 21.4.4.37 Date.prototype.toJSON ( key ), https://tc39.es/ecma262/#sec-date.prototype.tojson JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_json) { - auto* this_object = vm.this_value(global_object).to_object(global_object); - if (!this_object) - return {}; + auto this_value = vm.this_value(global_object); - auto time_value = Value(this_object).to_primitive(global_object, Value::PreferredType::Number); + auto time_value = this_value.to_primitive(global_object, Value::PreferredType::Number); if (vm.exception()) return {}; if (time_value.is_number() && !time_value.is_finite_number()) return js_null(); - return this_object->invoke(vm.names.toISOString); + return this_value.invoke(global_object, vm.names.toISOString); } // 14.1.1 Date.prototype.toTemporalInstant ( ), https://tc39.es/proposal-temporal/#sec-date.prototype.totemporalinstant diff --git a/Userland/Libraries/LibJS/Runtime/GlobalObject.h b/Userland/Libraries/LibJS/Runtime/GlobalObject.h index 869e93c7b5..4660e28c4b 100644 --- a/Userland/Libraries/LibJS/Runtime/GlobalObject.h +++ b/Userland/Libraries/LibJS/Runtime/GlobalObject.h @@ -163,4 +163,16 @@ inline GlobalObject* Shape::global_object() const template<> inline bool Object::fast_is() const { return is_global_object(); } +template +[[nodiscard]] ALWAYS_INLINE Value Value::invoke(GlobalObject& global_object, PropertyName const& property_name, Args... args) +{ + if constexpr (sizeof...(Args) > 0) { + MarkedValueList arglist { global_object.vm().heap() }; + (..., arglist.append(move(args))); + return invoke_internal(global_object, property_name, move(arglist)); + } + + return invoke_internal(global_object, property_name, Optional {}); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index ea4df7667e..be6dca8ec8 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -1199,17 +1199,4 @@ Value Object::ordinary_to_primitive(Value::PreferredType preferred_type) const return {}; } -Value Object::invoke_internal(PropertyName const& property_name, Optional arguments) -{ - auto& vm = this->vm(); - auto property = get(property_name); - if (vm.exception()) - return {}; - if (!property.is_function()) { - vm.throw_exception(global_object(), ErrorType::NotAFunction, property.to_string_without_side_effects()); - return {}; - } - return vm.call(property.as_function(), this, move(arguments)); -} - } diff --git a/Userland/Libraries/LibJS/Runtime/Object.h b/Userland/Libraries/LibJS/Runtime/Object.h index 7721c61663..0a4cb7c34f 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.h +++ b/Userland/Libraries/LibJS/Runtime/Object.h @@ -150,20 +150,6 @@ public: IndexedProperties& indexed_properties() { return m_indexed_properties; } void set_indexed_property_elements(Vector&& values) { m_indexed_properties = IndexedProperties(move(values)); } - [[nodiscard]] Value invoke_internal(PropertyName const&, Optional arguments); - - template - [[nodiscard]] ALWAYS_INLINE Value invoke(PropertyName const& property_name, Args... args) - { - if constexpr (sizeof...(Args) > 0) { - MarkedValueList arglist { heap() }; - (..., arglist.append(move(args))); - return invoke(property_name, move(arglist)); - } - - return invoke(property_name); - } - Shape& shape() { return *m_shape; } Shape const& shape() const { return *m_shape; } @@ -201,13 +187,4 @@ private: IndexedProperties m_indexed_properties; }; -template<> -[[nodiscard]] ALWAYS_INLINE Value Object::invoke(PropertyName const& property_name, MarkedValueList arguments) { return invoke_internal(property_name, move(arguments)); } - -template<> -[[nodiscard]] ALWAYS_INLINE Value Object::invoke(PropertyName const& property_name, Optional arguments) { return invoke_internal(property_name, move(arguments)); } - -template<> -[[nodiscard]] ALWAYS_INLINE Value Object::invoke(PropertyName const& property_name) { return invoke(property_name, Optional {}); } - } diff --git a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp index 10a70ca700..ee54bd1722 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp @@ -145,10 +145,8 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string) // 20.1.3.5 Object.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-object.prototype.tolocalestring JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_locale_string) { - auto* this_object = vm.this_value(global_object).to_object(global_object); - if (!this_object) - return {}; - return this_object->invoke(vm.names.toString); + auto this_value = vm.this_value(global_object); + return this_value.invoke(global_object, vm.names.toString); } // 20.1.3.7 Object.prototype.valueOf ( ), https://tc39.es/ecma262/#sec-object.prototype.valueof diff --git a/Userland/Libraries/LibJS/Runtime/PromisePrototype.cpp b/Userland/Libraries/LibJS/Runtime/PromisePrototype.cpp index 4d1d825c8d..86d77af681 100644 --- a/Userland/Libraries/LibJS/Runtime/PromisePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/PromisePrototype.cpp @@ -67,11 +67,9 @@ JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::then) // 27.2.5.1 Promise.prototype.catch ( onRejected ), https://tc39.es/ecma262/#sec-promise.prototype.catch JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::catch_) { - auto* this_object = vm.this_value(global_object).to_object(global_object); - if (!this_object) - return {}; + auto this_value = vm.this_value(global_object); auto on_rejected = vm.argument(0); - return this_object->invoke(vm.names.then, js_undefined(), on_rejected); + return this_value.invoke(global_object, vm.names.then, js_undefined(), on_rejected); } // 27.2.5.3 Promise.prototype.finally ( onFinally ), https://tc39.es/ecma262/#sec-promise.prototype.finally @@ -104,7 +102,7 @@ JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::finally) auto* value_thunk = NativeFunction::create(global_object, "", [value](auto&, auto&) -> Value { return value; }); - return promise->invoke(vm.names.then, value_thunk); + return Value(promise).invoke(global_object, vm.names.then, value_thunk); }); then_finally_function->define_direct_property(vm.names.length, Value(1), Attribute::Configurable); @@ -123,14 +121,14 @@ JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::finally) vm.throw_exception(global_object, reason); return {}; }); - return promise->invoke(vm.names.then, thrower); + return Value(promise).invoke(global_object, vm.names.then, thrower); }); catch_finally_function->define_direct_property(vm.names.length, Value(1), Attribute::Configurable); then_finally = Value(then_finally_function); catch_finally = Value(catch_finally_function); } - return promise->invoke(vm.names.then, then_finally, catch_finally); + return Value(promise).invoke(global_object, vm.names.then, then_finally, catch_finally); } } diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp index 4fcdd8bf70..7ac6f43b77 100644 --- a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -878,7 +878,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match) auto rx = regexp_create(global_object, regexp, js_undefined()); if (!rx) return {}; - return rx->invoke(*vm.well_known_symbol_match(), js_string(vm, utf16_string_view)); + return Value(rx).invoke(global_object, *vm.well_known_symbol_match(), js_string(vm, utf16_string_view)); } // 22.1.3.12 String.prototype.matchAll ( regexp ), https://tc39.es/ecma262/#sec-string.prototype.matchall @@ -921,7 +921,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match_all) auto rx = regexp_create(global_object, regexp, js_string(vm, "g")); if (!rx) return {}; - return rx->invoke(*vm.well_known_symbol_match_all(), js_string(vm, utf16_string_view)); + return Value(rx).invoke(global_object, *vm.well_known_symbol_match_all(), js_string(vm, utf16_string_view)); } // 22.1.3.17 String.prototype.replace ( searchValue, replaceValue ), https://tc39.es/ecma262/#sec-string.prototype.replace @@ -1119,7 +1119,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::search) auto rx = regexp_create(global_object, regexp, js_undefined()); if (!rx) return {}; - return rx->invoke(*vm.well_known_symbol_search(), js_string(vm, utf16_string_view)); + return Value(rx).invoke(global_object, *vm.well_known_symbol_search(), js_string(vm, utf16_string_view)); } // B.2.3.2.1 CreateHTML ( string, tag, attribute, value ), https://tc39.es/ecma262/#sec-createhtml diff --git a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp index 0d6292829f..8666846e8c 100644 --- a/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp +++ b/Userland/Libraries/LibJS/Runtime/Temporal/Calendar.cpp @@ -129,7 +129,7 @@ double calendar_year(GlobalObject& global_object, Object& calendar, Object& date // 1. Assert: Type(calendar) is Object. // 2. Let result be ? Invoke(calendar, "year", « dateLike »). - auto result = calendar.invoke(vm.names.year, &date_like); + auto result = Value(&calendar).invoke(global_object, vm.names.year, &date_like); if (vm.exception()) return {}; @@ -150,7 +150,7 @@ double calendar_month(GlobalObject& global_object, Object& calendar, Object& dat // 1. Assert: Type(calendar) is Object. // 2. Let result be ? Invoke(calendar, "month", « dateLike »). - auto result = calendar.invoke(vm.names.month, &date_like); + auto result = Value(&calendar).invoke(global_object, vm.names.month, &date_like); if (vm.exception()) return {}; @@ -171,7 +171,7 @@ String calendar_month_code(GlobalObject& global_object, Object& calendar, Object // 1. Assert: Type(calendar) is Object. // 2. Let result be ? Invoke(calendar, "monthCode", « dateLike »). - auto result = calendar.invoke(vm.names.monthCode, &date_like); + auto result = Value(&calendar).invoke(global_object, vm.names.monthCode, &date_like); if (vm.exception()) return {}; @@ -192,7 +192,7 @@ double calendar_day(GlobalObject& global_object, Object& calendar, Object& date_ // 1. Assert: Type(calendar) is Object. // 2. Let result be ? Invoke(calendar, "day", « dateLike »). - auto result = calendar.invoke(vm.names.day, &date_like); + auto result = Value(&calendar).invoke(global_object, vm.names.day, &date_like); if (vm.exception()) return {}; @@ -213,7 +213,7 @@ Value calendar_day_of_week(GlobalObject& global_object, Object& calendar, Object // 1. Assert: Type(calendar) is Object. // 2. Return ? Invoke(calendar, "dayOfWeek", « dateLike »). - return calendar.invoke(vm.names.dayOfWeek, &date_like); + return Value(&calendar).invoke(global_object, vm.names.dayOfWeek, &date_like); } // 12.1.14 CalendarDayOfYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardayofyear @@ -223,7 +223,7 @@ Value calendar_day_of_year(GlobalObject& global_object, Object& calendar, Object // 1. Assert: Type(calendar) is Object. // 2. Return ? Invoke(calendar, "dayOfYear", « dateLike »). - return calendar.invoke(vm.names.dayOfYear, &date_like); + return Value(&calendar).invoke(global_object, vm.names.dayOfYear, &date_like); } // 12.1.15 CalendarWeekOfYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarweekofyear @@ -233,7 +233,7 @@ Value calendar_week_of_year(GlobalObject& global_object, Object& calendar, Objec // 1. Assert: Type(calendar) is Object. // 2. Return ? Invoke(calendar, "weekOfYear", « dateLike »). - return calendar.invoke(vm.names.weekOfYear, &date_like); + return Value(&calendar).invoke(global_object, vm.names.weekOfYear, &date_like); } // 12.1.16 CalendarDaysInWeek ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardaysinweek @@ -243,7 +243,7 @@ Value calendar_days_in_week(GlobalObject& global_object, Object& calendar, Objec // 1. Assert: Type(calendar) is Object. // 2. Return ? Invoke(calendar, "daysInWeek", « dateLike »). - return calendar.invoke(vm.names.daysInWeek, &date_like); + return Value(&calendar).invoke(global_object, vm.names.daysInWeek, &date_like); } // 12.1.17 CalendarDaysInMonth ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardaysinmonth @@ -253,7 +253,7 @@ Value calendar_days_in_month(GlobalObject& global_object, Object& calendar, Obje // 1. Assert: Type(calendar) is Object. // 2. Return ? Invoke(calendar, "daysInMonth", « dateLike »). - return calendar.invoke(vm.names.daysInMonth, &date_like); + return Value(&calendar).invoke(global_object, vm.names.daysInMonth, &date_like); } // 12.1.18 CalendarDaysInYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendardaysinyear @@ -263,7 +263,7 @@ Value calendar_days_in_year(GlobalObject& global_object, Object& calendar, Objec // 1. Assert: Type(calendar) is Object. // 2. Return ? Invoke(calendar, "daysInYear", « dateLike »). - return calendar.invoke(vm.names.daysInYear, &date_like); + return Value(&calendar).invoke(global_object, vm.names.daysInYear, &date_like); } // 12.1.19 CalendarMonthsInYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarmonthsinyear @@ -273,7 +273,7 @@ Value calendar_months_in_year(GlobalObject& global_object, Object& calendar, Obj // 1. Assert: Type(calendar) is Object. // 2. Return ? Invoke(calendar, "monthsInYear", « dateLike »). - return calendar.invoke(vm.names.monthsInYear, &date_like); + return Value(&calendar).invoke(global_object, vm.names.monthsInYear, &date_like); } // 12.1.20 CalendarInLeapYear ( calendar, dateLike ), https://tc39.es/proposal-temporal/#sec-temporal-calendarinleapyear @@ -283,7 +283,7 @@ Value calendar_in_leap_year(GlobalObject& global_object, Object& calendar, Objec // 1. Assert: Type(calendar) is Object. // 2. Return ? Invoke(calendar, "inLeapYear", « dateLike »). - return calendar.invoke(vm.names.inLeapYear, &date_like); + return Value(&calendar).invoke(global_object, vm.names.inLeapYear, &date_like); } // 12.1.21 ToTemporalCalendar ( temporalCalendarLike ), https://tc39.es/proposal-temporal/#sec-temporal-totemporalcalendar @@ -396,7 +396,7 @@ PlainDate* date_from_fields(GlobalObject& global_object, Object& calendar, Objec // 2. Assert: Type(fields) is Object. // 3. Let date be ? Invoke(calendar, "dateFromFields", « fields, options »). - auto date = calendar.invoke(vm.names.dateFromFields, &fields, &options); + auto date = Value(&calendar).invoke(global_object, vm.names.dateFromFields, &fields, &options); if (vm.exception()) return {}; diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp index 6f0ff37cfa..5efb49a60f 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp @@ -1521,10 +1521,7 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::to_locale_string) return {}; if (value.is_nullish()) continue; - auto* value_object = value.to_object(global_object); - if (!value_object) - return {}; - auto locale_string_result = value_object->invoke(vm.names.toLocaleString); + auto locale_string_result = value.invoke(global_object, vm.names.toLocaleString); if (vm.exception()) return {}; auto string = locale_string_result.to_string(global_object); diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index 81cb54cf4c..13d3b4b3fc 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -1581,4 +1582,19 @@ TriState abstract_relation(GlobalObject& global_object, bool left_first, Value l return TriState::False; } +// 7.3.20 Invoke ( V, P [ , argumentsList ] ), https://tc39.es/ecma262/#sec-invoke +Value Value::invoke_internal(GlobalObject& global_object, JS::PropertyName const& property_name, Optional arguments) +{ + auto& vm = global_object.vm(); + auto property = get(global_object, property_name); + if (vm.exception()) + return {}; + if (!property.is_function()) { + vm.throw_exception(global_object, ErrorType::NotAFunction, property.to_string_without_side_effects()); + return {}; + } + + return vm.call(property.as_function(), *this, move(arguments)); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Value.h b/Userland/Libraries/LibJS/Runtime/Value.h index ee3a6fd74d..187848ee3a 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.h +++ b/Userland/Libraries/LibJS/Runtime/Value.h @@ -290,9 +290,14 @@ public: bool operator==(Value const&) const; + template + [[nodiscard]] ALWAYS_INLINE Value invoke(GlobalObject& global_object, PropertyName const& property_name, Args... args); + private: Type m_type { Type::Empty }; + [[nodiscard]] Value invoke_internal(GlobalObject& global_object, PropertyName const&, Optional arguments); + i32 to_i32_slow_case(GlobalObject&) const; union {