
This patch adds two macros to declare per-type allocators: - JS_DECLARE_ALLOCATOR(TypeName) - JS_DEFINE_ALLOCATOR(TypeName) When used, they add a type-specific CellAllocator that the Heap will delegate allocation requests to. The result of this is that GC objects of the same type always end up within the same HeapBlock, drastically reducing the ability to perform type confusion attacks. It also improves HeapBlock utilization, since each block now has cells sized exactly to the type used within that block. (Previously we only had a handful of block sizes available, and most GC allocations ended up with a large amount of slack in their tails.) There is a small performance hit from this, but I'm sure we can make up for it elsewhere. Note that the old size-based allocators still exist, and we fall back to them for any type that doesn't have its own CellAllocator.
118 lines
5.3 KiB
C++
118 lines
5.3 KiB
C++
/*
|
||
* Copyright (c) 2022-2023, Tim Flynn <trflynn89@serenityos.org>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#include <AK/Array.h>
|
||
#include <LibJS/Runtime/AbstractOperations.h>
|
||
#include <LibJS/Runtime/Array.h>
|
||
#include <LibJS/Runtime/GlobalObject.h>
|
||
#include <LibJS/Runtime/Intl/AbstractOperations.h>
|
||
#include <LibJS/Runtime/Intl/NumberFormatConstructor.h>
|
||
#include <LibJS/Runtime/Intl/PluralRules.h>
|
||
#include <LibJS/Runtime/Intl/PluralRulesConstructor.h>
|
||
|
||
namespace JS::Intl {
|
||
|
||
JS_DEFINE_ALLOCATOR(PluralRulesConstructor);
|
||
|
||
// 16.1 The Intl.PluralRules Constructor, https://tc39.es/ecma402/#sec-intl-pluralrules-constructor
|
||
PluralRulesConstructor::PluralRulesConstructor(Realm& realm)
|
||
: NativeFunction(realm.vm().names.PluralRules.as_string(), realm.intrinsics().function_prototype())
|
||
{
|
||
}
|
||
|
||
void PluralRulesConstructor::initialize(Realm& realm)
|
||
{
|
||
Base::initialize(realm);
|
||
|
||
auto& vm = this->vm();
|
||
|
||
// 16.2.1 Intl.PluralRules.prototype, https://tc39.es/ecma402/#sec-intl.pluralrules.prototype
|
||
define_direct_property(vm.names.prototype, realm.intrinsics().intl_plural_rules_prototype(), 0);
|
||
define_direct_property(vm.names.length, Value(0), Attribute::Configurable);
|
||
|
||
u8 attr = Attribute::Writable | Attribute::Configurable;
|
||
define_native_function(realm, vm.names.supportedLocalesOf, supported_locales_of, 1, attr);
|
||
}
|
||
|
||
// 16.1.1 Intl.PluralRules ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-intl.pluralrules
|
||
ThrowCompletionOr<Value> PluralRulesConstructor::call()
|
||
{
|
||
// 1. If NewTarget is undefined, throw a TypeError exception.
|
||
return vm().throw_completion<TypeError>(ErrorType::ConstructorWithoutNew, "Intl.PluralRules");
|
||
}
|
||
|
||
// 16.1.1 Intl.PluralRules ( [ locales [ , options ] ] ), https://tc39.es/ecma402/#sec-intl.pluralrules
|
||
ThrowCompletionOr<NonnullGCPtr<Object>> PluralRulesConstructor::construct(FunctionObject& new_target)
|
||
{
|
||
auto& vm = this->vm();
|
||
|
||
auto locales = vm.argument(0);
|
||
auto options = vm.argument(1);
|
||
|
||
// 2. Let pluralRules be ? OrdinaryCreateFromConstructor(NewTarget, "%PluralRules.prototype%", « [[InitializedPluralRules]], [[Locale]], [[Type]], [[MinimumIntegerDigits]], [[MinimumFractionDigits]], [[MaximumFractionDigits]], [[MinimumSignificantDigits]], [[MaximumSignificantDigits]], [[RoundingType]], [[RoundingMode]], [[RoundingIncrement]], [[TrailingZeroDisplay]] »).
|
||
auto plural_rules = TRY(ordinary_create_from_constructor<PluralRules>(vm, new_target, &Intrinsics::intl_plural_rules_prototype));
|
||
|
||
// 3. Return ? InitializePluralRules(pluralRules, locales, options).
|
||
return TRY(initialize_plural_rules(vm, plural_rules, locales, options));
|
||
}
|
||
|
||
// 16.2.2 Intl.PluralRules.supportedLocalesOf ( locales [ , options ] ), https://tc39.es/ecma402/#sec-intl.pluralrules.supportedlocalesof
|
||
JS_DEFINE_NATIVE_FUNCTION(PluralRulesConstructor::supported_locales_of)
|
||
{
|
||
auto locales = vm.argument(0);
|
||
auto options = vm.argument(1);
|
||
|
||
// 1. Let availableLocales be %PluralRules%.[[AvailableLocales]].
|
||
|
||
// 2. Let requestedLocales be ? CanonicalizeLocaleList(locales).
|
||
auto requested_locales = TRY(canonicalize_locale_list(vm, locales));
|
||
|
||
// 3. Return ? SupportedLocales(availableLocales, requestedLocales, options).
|
||
return TRY(supported_locales(vm, requested_locales, options));
|
||
}
|
||
|
||
// 16.1.2 InitializePluralRules ( pluralRules, locales, options ), https://tc39.es/ecma402/#sec-initializepluralrules
|
||
ThrowCompletionOr<NonnullGCPtr<PluralRules>> initialize_plural_rules(VM& vm, PluralRules& plural_rules, Value locales_value, Value options_value)
|
||
{
|
||
// 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
|
||
auto requested_locales = TRY(canonicalize_locale_list(vm, locales_value));
|
||
|
||
// 2. Set options to ? CoerceOptionsToObject(options).
|
||
auto* options = TRY(coerce_options_to_object(vm, options_value));
|
||
|
||
// 3. Let opt be a new Record.
|
||
LocaleOptions opt {};
|
||
|
||
// 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit").
|
||
auto matcher = TRY(get_option(vm, *options, vm.names.localeMatcher, OptionType::String, AK::Array { "lookup"sv, "best fit"sv }, "best fit"sv));
|
||
|
||
// 5. Set opt.[[localeMatcher]] to matcher.
|
||
opt.locale_matcher = matcher;
|
||
|
||
// 6. Let t be ? GetOption(options, "type", string, « "cardinal", "ordinal" », "cardinal").
|
||
auto type = TRY(get_option(vm, *options, vm.names.type, OptionType::String, AK::Array { "cardinal"sv, "ordinal"sv }, "cardinal"sv));
|
||
|
||
// 7. Set pluralRules.[[Type]] to t.
|
||
plural_rules.set_type(type.as_string().utf8_string_view());
|
||
|
||
// 8. Perform ? SetNumberFormatDigitOptions(pluralRules, options, +0𝔽, 3𝔽, "standard").
|
||
TRY(set_number_format_digit_options(vm, plural_rules, *options, 0, 3, NumberFormat::Notation::Standard));
|
||
|
||
// 9. Let localeData be %PluralRules%.[[LocaleData]].
|
||
// 10. Let r be ResolveLocale(%PluralRules%.[[AvailableLocales]], requestedLocales, opt, %PluralRules%.[[RelevantExtensionKeys]], localeData).
|
||
auto result = resolve_locale(requested_locales, opt, {});
|
||
|
||
// 11. Set pluralRules.[[Locale]] to r.[[locale]].
|
||
plural_rules.set_locale(move(result.locale));
|
||
|
||
// Non-standard, the data locale is used by our NumberFormat implementation.
|
||
plural_rules.set_data_locale(move(result.data_locale));
|
||
|
||
// 12. Return pluralRules.
|
||
return plural_rules;
|
||
}
|
||
|
||
}
|