From 151447bdf7207b4b5cd85708f579e5c3808fe0d8 Mon Sep 17 00:00:00 2001 From: davidot Date: Mon, 9 Aug 2021 16:45:43 +0200 Subject: [PATCH] LibJS: Move Object::invoke to Value::invoke and fix it for primitives This is a tiny difference and only changes anything for primitives in strict mode. However this is tested in test262 and can be noticed by overriding toString of primitive values. This does now require one to wrap an object in a Value to call invoke but all code using invoke has been migrated. --- .../LibJS/Runtime/ArrayPrototype.cpp | 5 +--- .../Libraries/LibJS/Runtime/DatePrototype.cpp | 8 +++--- .../Libraries/LibJS/Runtime/GlobalObject.h | 12 +++++++++ Userland/Libraries/LibJS/Runtime/Object.cpp | 13 ---------- Userland/Libraries/LibJS/Runtime/Object.h | 23 ---------------- .../LibJS/Runtime/ObjectPrototype.cpp | 6 ++--- .../LibJS/Runtime/PromisePrototype.cpp | 12 ++++----- .../LibJS/Runtime/StringPrototype.cpp | 6 ++--- .../LibJS/Runtime/Temporal/Calendar.cpp | 26 +++++++++---------- .../LibJS/Runtime/TypedArrayPrototype.cpp | 5 +--- Userland/Libraries/LibJS/Runtime/Value.cpp | 16 ++++++++++++ Userland/Libraries/LibJS/Runtime/Value.h | 5 ++++ 12 files changed, 61 insertions(+), 76 deletions(-) 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 {