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 1cc09366315..9e80b65e099 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 43852dd4845..3c3e85eb3ee 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 869e93c7b5a..4660e28c4b2 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 ea4df7667ee..be6dca8ec81 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 7721c616632..0a4cb7c34fd 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 10a70ca7001..ee54bd17227 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 4d1d825c8d2..86d77af681c 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 4fcdd8bf70b..7ac6f43b778 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 0d6292829f0..8666846e8c8 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 6f0ff37cfa9..5efb49a60f9 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 81cb54cf4c3..13d3b4b3fc6 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 ee3a6fd74d0..187848ee3ad 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 {