LibJS: Inline fast case for Value::to_{boolean,number,numeric,primitive}

These functions all have a very common case that can be dealt with a
very simple inline check, often avoiding the need to call an out-of-line
function. This patch moves the common case to inline functions in a new
ValueInlines.h header (necessary due to header dependency issues..)

8% speed-up on the entire Kraken benchmark :^)
This commit is contained in:
Andreas Kling 2023-10-06 17:54:21 +02:00
parent 42d80aab06
commit 65717e3b75
53 changed files with 111 additions and 8 deletions

View file

@ -3252,6 +3252,7 @@ void generate_namespace_implementation(IDL::Interface const& interface, StringBu
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/@namespace_class@.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
@ -3415,6 +3416,7 @@ void generate_constructor_implementation(IDL::Interface const& interface, String
#include <LibJS/Runtime/DataView.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibWeb/Bindings/@constructor_class@.h>
#include <LibWeb/Bindings/@prototype_class@.h>
@ -3807,6 +3809,7 @@ void generate_prototype_implementation(IDL::Interface const& interface, StringBu
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/@prototype_class@.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
@ -4121,6 +4124,7 @@ void generate_global_mixin_implementation(IDL::Interface const& interface, Strin
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/@class_name@.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>

View file

@ -5,6 +5,7 @@
*/
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibTest/TestCase.h>
using namespace JS;

View file

@ -19,6 +19,7 @@
#include <LibJS/Contrib/Test262/GlobalObject.h>
#include <LibJS/Parser.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/Script.h>
#include <LibJS/SourceTextModule.h>
#include <fcntl.h>

View file

@ -18,6 +18,7 @@
#include <LibGUI/FileIconProvider.h>
#include <LibJS/Bytecode/Interpreter.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/Script.h>
#include <errno.h>
#include <fcntl.h>

View file

@ -8,6 +8,7 @@
#include "Spreadsheet.h"
#include <AK/StringBuilder.h>
#include <AK/TemporaryChange.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace Spreadsheet {

View file

@ -9,6 +9,7 @@
#include "../Spreadsheet.h"
#include "Format.h"
#include <AK/ScopeGuard.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace Spreadsheet {

View file

@ -12,6 +12,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace Spreadsheet {

View file

@ -34,6 +34,7 @@
#include <LibJS/Runtime/Reference.h>
#include <LibJS/Runtime/RegExpObject.h>
#include <LibJS/Runtime/Shape.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <typeinfo>
namespace JS {

View file

@ -29,6 +29,7 @@
#include <LibJS/Runtime/Reference.h>
#include <LibJS/Runtime/RegExpObject.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/SourceTextModule.h>
namespace JS::Bytecode {

View file

@ -14,6 +14,7 @@
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/StringConstructor.h>
#include <LibJS/Runtime/Temporal/Duration.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -34,6 +34,7 @@
#include <LibJS/Runtime/ProxyObject.h>
#include <LibJS/Runtime/Reference.h>
#include <LibJS/Runtime/SuppressedError.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -13,6 +13,7 @@
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -23,6 +23,7 @@
#include <LibJS/Runtime/ObjectPrototype.h>
#include <LibJS/Runtime/Realm.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -11,6 +11,7 @@
#include <LibJS/Runtime/PromiseCapability.h>
#include <LibJS/Runtime/PromiseConstructor.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -11,6 +11,7 @@
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -9,6 +9,7 @@
#include <LibJS/Runtime/BooleanConstructor.h>
#include <LibJS/Runtime/BooleanObject.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -7,6 +7,7 @@
#include <AK/Checked.h>
#include <AK/TypeCasts.h>
#include <LibJS/Runtime/DataViewPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -17,6 +17,7 @@
#include <LibJS/Runtime/DatePrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <sys/time.h>
#include <time.h>

View file

@ -23,6 +23,7 @@
#include <LibJS/Runtime/Intl/DateTimeFormatConstructor.h>
#include <LibJS/Runtime/Temporal/Instant.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibLocale/DateTimeFormat.h>
#include <LibLocale/Locale.h>
#include <LibTimeZone/TimeZone.h>

View file

@ -80,6 +80,7 @@
#include <LibJS/Runtime/Temporal/ZonedDateTimeConstructor.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/Runtime/WeakMapConstructor.h>
#include <LibJS/Runtime/WeakRefConstructor.h>
#include <LibJS/Runtime/WeakSetConstructor.h>

View file

@ -15,6 +15,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Intl/AbstractOperations.h>
#include <LibJS/Runtime/Intl/Locale.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibLocale/Locale.h>
namespace JS::Intl {

View file

@ -10,6 +10,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Intl/DateTimeFormat.h>
#include <LibJS/Runtime/Intl/DateTimeFormatFunction.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Intl {

View file

@ -9,6 +9,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Intl/DateTimeFormatFunction.h>
#include <LibJS/Runtime/Intl/DateTimeFormatPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibLocale/DateTimeFormat.h>
namespace JS::Intl {

View file

@ -16,6 +16,7 @@
#include <LibJS/Runtime/Intl/PluralRulesConstructor.h>
#include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Intl {

View file

@ -15,6 +15,7 @@
#include <LibJS/Runtime/Intl/NumberFormat.h>
#include <LibJS/Runtime/Intl/NumberFormatFunction.h>
#include <LibJS/Runtime/Intl/PluralRules.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibUnicode/CurrencyCode.h>
#include <math.h>
#include <stdlib.h>

View file

@ -8,6 +8,7 @@
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Intl/PluralRulesPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibLocale/PluralRules.h>
namespace JS::Intl {

View file

@ -7,6 +7,7 @@
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Intl/RelativeTimeFormatPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Intl {

View file

@ -12,6 +12,7 @@
#include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -12,6 +12,7 @@
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/IteratorHelper.h>
#include <LibJS/Runtime/IteratorPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -23,6 +23,7 @@
#include <LibJS/Runtime/NumberObject.h>
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/StringObject.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -12,6 +12,7 @@
#include <AK/Random.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/MathObject.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <math.h>
namespace JS {

View file

@ -7,6 +7,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ObjectEnvironment.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -10,6 +10,7 @@
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/PropertyDescriptor.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -12,6 +12,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/PropertyDescriptor.h>
#include <LibJS/Runtime/ProxyObject.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -19,6 +19,7 @@
#include <LibJS/Runtime/RegExpPrototype.h>
#include <LibJS/Runtime/RegExpStringIterator.h>
#include <LibJS/Runtime/StringPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -11,6 +11,7 @@
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/SetIterator.h>
#include <LibJS/Runtime/SetPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -14,6 +14,7 @@
#include <LibJS/Runtime/StringConstructor.h>
#include <LibJS/Runtime/StringObject.h>
#include <LibJS/Runtime/Utf16String.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -26,6 +26,7 @@
#include <LibJS/Runtime/StringPrototype.h>
#include <LibJS/Runtime/Utf16String.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibLocale/Locale.h>
#include <LibUnicode/CharacterTypes.h>
#include <LibUnicode/Normalize.h>

View file

@ -24,6 +24,7 @@
#include <LibJS/Runtime/Temporal/PlainTime.h>
#include <LibJS/Runtime/Temporal/TimeZone.h>
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Temporal {

View file

@ -14,6 +14,7 @@
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Temporal/ISO8601.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Temporal {

View file

@ -23,6 +23,7 @@
#include <LibJS/Runtime/Temporal/TimeZone.h>
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Temporal {

View file

@ -19,6 +19,7 @@
#include <LibJS/Runtime/Temporal/PlainDate.h>
#include <LibJS/Runtime/Temporal/TimeZone.h>
#include <LibJS/Runtime/Temporal/ZonedDateTime.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Temporal {

View file

@ -10,6 +10,7 @@
#include <LibJS/Runtime/Temporal/AbstractOperations.h>
#include <LibJS/Runtime/Temporal/Duration.h>
#include <LibJS/Runtime/Temporal/DurationConstructor.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Temporal {

View file

@ -9,6 +9,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/Temporal/Instant.h>
#include <LibJS/Runtime/Temporal/InstantConstructor.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS::Temporal {

View file

@ -15,6 +15,7 @@
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/TypedArrayConstructor.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -13,6 +13,7 @@
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/TypedArray.h>
#include <LibJS/Runtime/TypedArrayPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
namespace JS {

View file

@ -39,6 +39,7 @@
#include <LibJS/Runtime/Utf16String.h>
#include <LibJS/Runtime/VM.h>
#include <LibJS/Runtime/Value.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <math.h>
namespace JS {
@ -453,7 +454,7 @@ ThrowCompletionOr<Utf16String> Value::to_utf16_string(VM& vm) const
}
// 7.1.2 ToBoolean ( argument ), https://tc39.es/ecma262/#sec-toboolean
bool Value::to_boolean() const
bool Value::to_boolean_slow_case() const
{
if (is_double()) {
if (is_nan())
@ -490,7 +491,7 @@ bool Value::to_boolean() const
}
// 7.1.1 ToPrimitive ( input [ , preferredType ] ), https://tc39.es/ecma262/#sec-toprimitive
ThrowCompletionOr<Value> Value::to_primitive(VM& vm, PreferredType preferred_type) const
ThrowCompletionOr<Value> Value::to_primitive_slow_case(VM& vm, PreferredType preferred_type) const
{
// 1. If input is an Object, then
if (is_object()) {
@ -585,12 +586,8 @@ ThrowCompletionOr<NonnullGCPtr<Object>> Value::to_object(VM& vm) const
}
// 7.1.3 ToNumeric ( value ), https://tc39.es/ecma262/#sec-tonumeric
FLATTEN ThrowCompletionOr<Value> Value::to_numeric(VM& vm) const
FLATTEN ThrowCompletionOr<Value> Value::to_numeric_slow_case(VM& vm) const
{
// OPTIMIZATION: Fast path for when this value is already a number.
if (is_number())
return *this;
// 1. Let primValue be ? ToPrimitive(value, number).
auto primitive_value = TRY(to_primitive(vm, Value::PreferredType::Number));
@ -688,7 +685,7 @@ double string_to_number(StringView string)
}
// 7.1.4 ToNumber ( argument ), https://tc39.es/ecma262/#sec-tonumber
ThrowCompletionOr<Value> Value::to_number(VM& vm) const
ThrowCompletionOr<Value> Value::to_number_slow_case(VM& vm) const
{
VERIFY(!is_empty());

View file

@ -440,6 +440,11 @@ public:
}
private:
bool to_boolean_slow_case() const;
ThrowCompletionOr<Value> to_number_slow_case(VM&) const;
ThrowCompletionOr<Value> to_numeric_slow_case(VM&) const;
ThrowCompletionOr<Value> to_primitive_slow_case(VM&, PreferredType) const;
Value(u64 tag, u64 val)
{
VERIFY(!(tag & val));

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
inline bool Value::to_boolean() const
{
// OPTIMIZATION: Fast path for when this value is already a boolean.
if (is_boolean())
return as_bool();
return to_boolean_slow_case();
}
inline ThrowCompletionOr<Value> Value::to_number(VM& vm) const
{
// OPTIMIZATION: Fast path for when this value is already a number.
if (is_number())
return *this;
return to_number_slow_case(vm);
}
inline ThrowCompletionOr<Value> Value::to_numeric(VM& vm) const
{
// OPTIMIZATION: Fast path for when this value is already a number.
if (is_number())
return *this;
return to_numeric_slow_case(vm);
}
inline ThrowCompletionOr<Value> Value::to_primitive(VM& vm, PreferredType preferred_type) const
{
if (!is_object())
return *this;
return to_primitive_slow_case(vm, preferred_type);
}
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/HTMLOptionElementPrototype.h>
#include <LibWeb/Bindings/OptionConstructor.h>

View file

@ -6,6 +6,7 @@
#include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/Iterator.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/Bindings/CustomElementRegistryPrototype.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/ElementFactory.h>

View file

@ -6,6 +6,7 @@
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibWeb/WebGL/WebGLContextAttributes.h>
namespace Web::WebGL {

View file

@ -24,6 +24,7 @@
#include <LibJS/Runtime/GlobalEnvironment.h>
#include <LibJS/Runtime/JSONObject.h>
#include <LibJS/Runtime/StringPrototype.h>
#include <LibJS/Runtime/ValueInlines.h>
#include <LibJS/SourceTextModule.h>
#include <LibLine/Editor.h>
#include <LibMain/Main.h>