Commit cdb4d913 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[Intl] Optimize Intl.PluralRules

Previously, Intl.PluralRules was mostly implemented in JavaScript. This
patch moves most of the constructor and parts of other methods to C++.

The size of the Intl.PluralRules object is reduced by not storing
MinimumIntegerDigits, MinimumFractionDigits, MaximumFractionDigits,
MinimumSignificantDigits, MaximumSignificantDigits. Instead these are
looked up from icu::DecimalFormat as required.

Another optimziation is that we don't create the result of
resolvedOptions when the Intl.PluralRules object is constructed, but
instead defer until this method is called. In the future, we may want
to cache the result.

This patch also cleans up several error handling paths that shouldn't
happen with ICU and instead just crashes should it ever happen.

Bug: v8:5751
Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng
Change-Id: I84c5aa6c25c35fe2d336693dee1b36bf3dcd4a79
Reviewed-on: https://chromium-review.googlesource.com/1158701
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarJungshik Shin <jshin@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54917}
parent 13ed3e38
......@@ -2168,6 +2168,9 @@ v8_source_set("v8_base") {
"src/objects/js-locale-inl.h",
"src/objects/js-locale.cc",
"src/objects/js-locale.h",
"src/objects/js-plural-rules-inl.h",
"src/objects/js-plural-rules.cc",
"src/objects/js-plural-rules.h",
"src/objects/js-promise-inl.h",
"src/objects/js-promise.h",
"src/objects/js-proxy-inl.h",
......@@ -2865,6 +2868,9 @@ v8_source_set("v8_base") {
"src/objects/js-locale-inl.h",
"src/objects/js-locale.cc",
"src/objects/js-locale.h",
"src/objects/js-plural-rules-inl.h",
"src/objects/js-plural-rules.cc",
"src/objects/js-plural-rules.h",
"src/objects/js-relative-time-format-inl.h",
"src/objects/js-relative-time-format.cc",
"src/objects/js-relative-time-format.h",
......
......@@ -31,6 +31,7 @@
#include "src/objects/js-regexp-string-iterator.h"
#include "src/objects/js-regexp.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-plural-rules.h"
#include "src/objects/js-relative-time-format.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/templates.h"
......@@ -2968,10 +2969,13 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
{
Handle<JSFunction> plural_rules_constructor = InstallFunction(
isolate_, intl, "PluralRules", JS_OBJECT_TYPE, PluralRules::kSize, 0,
factory->the_hole_value(), Builtins::kIllegal);
native_context()->set_intl_plural_rules_function(
*plural_rules_constructor);
isolate_, intl, "PluralRules", JS_INTL_PLURAL_RULES_TYPE,
JSPluralRules::kSize, 0, factory->the_hole_value(),
Builtins::kPluralRulesConstructor);
plural_rules_constructor->shared()->DontAdaptArguments();
InstallWithIntrinsicDefaultProto(
isolate_, plural_rules_constructor,
Context::INTL_PLURAL_RULES_FUNCTION_INDEX);
Handle<JSObject> prototype(
JSObject::cast(plural_rules_constructor->prototype()), isolate_);
......
......@@ -1360,6 +1360,8 @@ namespace internal {
CPP(NumberFormatInternalFormatNumber) \
/* ecma402 #sec-intl.numberformat.prototype.format */ \
CPP(NumberFormatPrototypeFormatNumber) \
/* ecma402 #sec-intl.pluralrules */ \
CPP(PluralRulesConstructor) \
/* ecma402 #sec-intl.RelativeTimeFormat.constructor */ \
CPP(RelativeTimeFormatConstructor) \
/* ecma402 #sec-intl.RelativeTimeFormat.prototype.resolvedOptions */ \
......
......@@ -17,6 +17,7 @@
#include "src/objects/intl-objects.h"
#include "src/objects/js-list-format-inl.h"
#include "src/objects/js-locale-inl.h"
#include "src/objects/js-plural-rules-inl.h"
#include "src/objects/js-relative-time-format-inl.h"
#include "unicode/datefmt.h"
......@@ -1095,5 +1096,40 @@ BUILTIN(StringPrototypeToLocaleUpperCase) {
args.atOrUndefined(isolate, 1)));
}
BUILTIN(PluralRulesConstructor) {
HandleScope scope(isolate);
// 1. If NewTarget is undefined, throw a TypeError exception.
if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
isolate->factory()->NewStringFromStaticChars(
"Intl.PluralRules")));
}
// [[Construct]]
Handle<JSFunction> target = args.target();
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
Handle<Object> locales = args.atOrUndefined(isolate, 1);
Handle<Object> options = args.atOrUndefined(isolate, 2);
// 2. Let pluralRules be ? OrdinaryCreateFromConstructor(newTarget,
// "%PluralRulesPrototype%", « [[InitializedPluralRules]],
// [[Locale]], [[Type]], [[MinimumIntegerDigits]],
// [[MinimumFractionDigits]], [[MaximumFractionDigits]],
// [[MinimumSignificantDigits]], [[MaximumSignificantDigits]] »).
Handle<JSObject> plural_rules_obj;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, plural_rules_obj,
JSObject::New(target, new_target));
Handle<JSPluralRules> plural_rules =
Handle<JSPluralRules>::cast(plural_rules_obj);
// 3. Return ? InitializePluralRules(pluralRules, locales, options).
RETURN_RESULT_OR_FAILURE(
isolate, JSPluralRules::InitializePluralRules(isolate, plural_rules,
locales, options));
}
} // namespace internal
} // namespace v8
......@@ -209,6 +209,7 @@ Type::bitset BitsetType::Lub(HeapObjectType const& type) {
#ifdef V8_INTL_SUPPORT
case JS_INTL_LIST_FORMAT_TYPE:
case JS_INTL_LOCALE_TYPE:
case JS_INTL_PLURAL_RULES_TYPE:
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
#endif // V8_INTL_SUPPORT
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
......
......@@ -78,6 +78,8 @@ enum ContextLookupFlags {
V(ARRAY_FOR_EACH_ITERATOR_INDEX, JSFunction, array_for_each_iterator) \
V(ARRAY_KEYS_ITERATOR_INDEX, JSFunction, array_keys_iterator) \
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
V(CANONICALIZE_LOCALE_LIST_FUNCTION_INDEX, JSFunction, \
canonicalize_locale_list) \
V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
V(ERROR_TO_STRING, JSFunction, error_to_string) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
......
......@@ -760,6 +760,14 @@ function canonicalizeLocaleList(locales) {
return seen;
}
// TODO(ftang): remove the %InstallToContext once
// initializeLocaleList is available in C++
// https://bugs.chromium.org/p/v8/issues/detail?id=7987
%InstallToContext([
"canonicalize_locale_list", canonicalizeLocaleList
]);
function initializeLocaleList(locales) {
return freezeArray(canonicalizeLocaleList(locales));
}
......@@ -949,84 +957,10 @@ function compare(collator, x, y) {
AddBoundMethod(GlobalIntlCollator, 'compare', compare, 2, COLLATOR_TYPE, false);
function PluralRulesConstructor() {
if (IS_UNDEFINED(new.target)) {
throw %make_type_error(kConstructorNotFunction, "PluralRules");
}
var locales = arguments[0];
var options = arguments[1];
if (IS_UNDEFINED(options)) {
options = {__proto__: null};
}
var getOption = getGetOption(options, 'pluralrules');
var locale = resolveLocale('pluralrules', locales, options);
var internalOptions = {__proto__: null};
%DefineWEProperty(internalOptions, 'type', getOption(
'type', 'string', ['cardinal', 'ordinal'], 'cardinal'));
SetNumberFormatDigitOptions(internalOptions, options, 0, 3);
var requestedLocale = locale.locale;
var resolved = %object_define_properties({__proto__: null}, {
type: {value: internalOptions.type, writable: true},
locale: {writable: true},
maximumFractionDigits: {writable: true},
minimumFractionDigits: {writable: true},
minimumIntegerDigits: {writable: true},
requestedLocale: {value: requestedLocale, writable: true},
});
if (HAS_OWN_PROPERTY(internalOptions, 'minimumSignificantDigits')) {
%DefineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED);
}
if (HAS_OWN_PROPERTY(internalOptions, 'maximumSignificantDigits')) {
%DefineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED);
}
%DefineWEProperty(resolved, 'pluralCategories', []);
var pluralRules = %CreatePluralRules(requestedLocale, internalOptions,
resolved);
%MarkAsInitializedIntlObjectOfType(pluralRules, PLURAL_RULES_TYPE);
pluralRules[resolvedSymbol] = resolved;
return pluralRules;
}
%SetCode(GlobalIntlPluralRules, PluralRulesConstructor);
DEFINE_METHOD(
GlobalIntlPluralRules.prototype,
resolvedOptions() {
if (!%IsInitializedIntlObjectOfType(this, PLURAL_RULES_TYPE)) {
throw %make_type_error(kIncompatibleMethodReceiver,
'Intl.PluralRules.prototype.resolvedOptions',
this);
}
var result = {
locale: this[resolvedSymbol].locale,
type: this[resolvedSymbol].type,
minimumIntegerDigits: this[resolvedSymbol].minimumIntegerDigits,
minimumFractionDigits: this[resolvedSymbol].minimumFractionDigits,
maximumFractionDigits: this[resolvedSymbol].maximumFractionDigits,
};
if (HAS_OWN_PROPERTY(this[resolvedSymbol], 'minimumSignificantDigits')) {
defineWECProperty(result, 'minimumSignificantDigits',
this[resolvedSymbol].minimumSignificantDigits);
}
if (HAS_OWN_PROPERTY(this[resolvedSymbol], 'maximumSignificantDigits')) {
defineWECProperty(result, 'maximumSignificantDigits',
this[resolvedSymbol].maximumSignificantDigits);
}
defineWECProperty(result, 'pluralCategories',
%_Call(ArraySlice, this[resolvedSymbol].pluralCategories));
return result;
return %PluralRulesResolvedOptions(this);
}
);
......@@ -1040,12 +974,6 @@ DEFINE_METHOD(
DEFINE_METHOD(
GlobalIntlPluralRules.prototype,
select(value) {
if (!%IsInitializedIntlObjectOfType(this, PLURAL_RULES_TYPE)) {
throw %make_type_error(kIncompatibleMethodReceiver,
'Intl.PluralRules.prototype.select',
this);
}
return %PluralRulesSelect(this, TO_NUMBER(value) + 0);
}
);
......
......@@ -728,6 +728,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
#ifdef V8_INTL_SUPPORT
case JS_INTL_LIST_FORMAT_TYPE:
case JS_INTL_LOCALE_TYPE:
case JS_INTL_PLURAL_RULES_TYPE:
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
#endif // V8_INTL_SUPPORT
case WASM_GLOBAL_TYPE:
......
......@@ -28,6 +28,7 @@
#include "src/objects/js-regexp-inl.h"
#include "src/objects/js-regexp-string-iterator-inl.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-plural-rules-inl.h"
#include "src/objects/js-relative-time-format-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/maybe-object.h"
......@@ -358,6 +359,9 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
case JS_INTL_LOCALE_TYPE:
JSLocale::cast(this)->JSLocaleVerify(isolate);
break;
case JS_INTL_PLURAL_RULES_TYPE:
JSPluralRules::cast(this)->JSPluralRulesVerify(isolate);
break;
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
JSRelativeTimeFormat::cast(this)->JSRelativeTimeFormatVerify(isolate);
break;
......@@ -1865,12 +1869,14 @@ void InterpreterData::InterpreterDataVerify(Isolate* isolate) {
#ifdef V8_INTL_SUPPORT
void JSListFormat::JSListFormatVerify(Isolate* isolate) {
JSObjectVerify(isolate);
VerifyObjectField(isolate, kLocaleOffset);
VerifyObjectField(isolate, kFormatterOffset);
VerifyObjectField(isolate, kFlagsOffset);
}
void JSLocale::JSLocaleVerify(Isolate* isolate) {
JSObjectVerify(isolate);
VerifyObjectField(isolate, kLanguageOffset);
VerifyObjectField(isolate, kScriptOffset);
VerifyObjectField(isolate, kRegionOffset);
......@@ -1885,7 +1891,17 @@ void JSLocale::JSLocaleVerify(Isolate* isolate) {
VerifyObjectField(isolate, kNumberingSystemOffset);
}
void JSPluralRules::JSPluralRulesVerify(Isolate* isolate) {
CHECK(IsJSPluralRules());
JSObjectVerify(isolate);
VerifyObjectField(isolate, kLocaleOffset);
VerifyObjectField(isolate, kTypeOffset);
VerifyObjectField(isolate, kICUPluralRulesOffset);
VerifyObjectField(isolate, kICUDecimalFormatOffset);
}
void JSRelativeTimeFormat::JSRelativeTimeFormatVerify(Isolate* isolate) {
JSObjectVerify(isolate);
VerifyObjectField(isolate, kLocaleOffset);
VerifyObjectField(isolate, kFormatterOffset);
VerifyObjectField(isolate, kFlagsOffset);
......
......@@ -219,6 +219,7 @@ namespace internal {
INSTANCE_TYPE_LIST_BEFORE_INTL(V) \
V(JS_INTL_LIST_FORMAT_TYPE) \
V(JS_INTL_LOCALE_TYPE) \
V(JS_INTL_PLURAL_RULES_TYPE) \
V(JS_INTL_RELATIVE_TIME_FORMAT_TYPE) \
INSTANCE_TYPE_LIST_AFTER_INTL(V)
#else
......
......@@ -26,6 +26,7 @@
#include "src/objects/js-regexp-inl.h"
#include "src/objects/js-regexp-string-iterator-inl.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-plural-rules-inl.h"
#include "src/objects/js-relative-time-format-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/literal-objects-inl.h"
......@@ -310,6 +311,9 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case JS_INTL_LOCALE_TYPE:
JSLocale::cast(this)->JSLocalePrint(os);
break;
case JS_INTL_PLURAL_RULES_TYPE:
JSPluralRules::cast(this)->JSPluralRulesPrint(os);
break;
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
JSRelativeTimeFormat::cast(this)->JSRelativeTimeFormatPrint(os);
break;
......@@ -1976,6 +1980,16 @@ void JSLocale::JSLocalePrint(std::ostream& os) { // NOLINT
os << "\n";
}
void JSPluralRules::JSPluralRulesPrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "JSPluralRules");
JSObjectPrint(os);
os << "\n - locale: " << Brief(locale());
os << "\n - type: " << Brief(type());
os << "\n - icu plural rules: " << Brief(icu_plural_rules());
os << "\n - icu decimal format: " << Brief(icu_decimal_format());
os << "\n";
}
void JSRelativeTimeFormat::JSRelativeTimeFormatPrint(
std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "JSRelativeTimeFormat");
......
......@@ -68,6 +68,7 @@
#include "src/objects/js-regexp-inl.h"
#include "src/objects/js-regexp-string-iterator.h"
#ifdef V8_INTL_SUPPORT
#include "src/objects/js-plural-rules.h"
#include "src/objects/js-relative-time-format.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/literal-objects-inl.h"
......@@ -1422,6 +1423,8 @@ int JSObject::GetHeaderSize(InstanceType type,
return JSListFormat::kSize;
case JS_INTL_LOCALE_TYPE:
return JSLocale::kSize;
case JS_INTL_PLURAL_RULES_TYPE:
return JSPluralRules::kSize;
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
return JSRelativeTimeFormat::kSize;
#endif // V8_INTL_SUPPORT
......@@ -3170,6 +3173,7 @@ VisitorId Map::GetVisitorId(Map* map) {
#ifdef V8_INTL_SUPPORT
case JS_INTL_LIST_FORMAT_TYPE:
case JS_INTL_LOCALE_TYPE:
case JS_INTL_PLURAL_RULES_TYPE:
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
#endif // V8_INTL_SUPPORT
case WASM_GLOBAL_TYPE:
......@@ -13211,6 +13215,9 @@ bool CanSubclassHaveInobjectProperties(InstanceType instance_type) {
case JS_DATE_TYPE:
case JS_FUNCTION_TYPE:
case JS_GENERATOR_OBJECT_TYPE:
#ifdef V8_INTL_SUPPORT
case JS_INTL_PLURAL_RULES_TYPE:
#endif
case JS_ASYNC_GENERATOR_OBJECT_TYPE:
case JS_MAP_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
......
......@@ -77,6 +77,7 @@
// - JSModuleNamespace
// - JSListFormat // If V8_INTL_SUPPORT enabled.
// - JSLocale // If V8_INTL_SUPPORT enabled.
// - JSPluralRules // If V8_INTL_SUPPORT enabled.
// - JSRelativeTimeFormat // If V8_INTL_SUPPORT enabled.
// - WasmGlobalObject
// - WasmInstanceObject
......@@ -585,6 +586,7 @@ enum InstanceType : uint16_t {
#ifdef V8_INTL_SUPPORT
JS_INTL_LIST_FORMAT_TYPE,
JS_INTL_LOCALE_TYPE,
JS_INTL_PLURAL_RULES_TYPE,
JS_INTL_RELATIVE_TIME_FORMAT_TYPE,
#endif // V8_INTL_SUPPORT
......@@ -701,6 +703,7 @@ class JSGlobalProxy;
#ifdef V8_INTL_SUPPORT
class JSListFormat;
class JSLocale;
class JSPluralRules;
class JSRelativeTimeFormat;
#endif // V8_INTL_SUPPORT
class JSPromise;
......@@ -912,6 +915,7 @@ class ZoneForwardList;
HEAP_OBJECT_ORDINARY_TYPE_LIST_BASE(V) \
V(JSListFormat) \
V(JSLocale) \
V(JSPluralRules) \
V(JSRelativeTimeFormat)
#else
#define HEAP_OBJECT_ORDINARY_TYPE_LIST(V) HEAP_OBJECT_ORDINARY_TYPE_LIST_BASE(V)
......@@ -1028,10 +1032,11 @@ class ZoneForwardList;
#ifdef V8_INTL_SUPPORT
#define INSTANCE_TYPE_CHECKERS_SINGLE(V) \
INSTANCE_TYPE_CHECKERS_SINGLE_BASE(V) \
V(JSListFormat, JS_INTL_LIST_FORMAT_TYPE) \
V(JSLocale, JS_INTL_LOCALE_TYPE) \
#define INSTANCE_TYPE_CHECKERS_SINGLE(V) \
INSTANCE_TYPE_CHECKERS_SINGLE_BASE(V) \
V(JSListFormat, JS_INTL_LIST_FORMAT_TYPE) \
V(JSLocale, JS_INTL_LOCALE_TYPE) \
V(JSPluralRules, JS_INTL_PLURAL_RULES_TYPE) \
V(JSRelativeTimeFormat, JS_INTL_RELATIVE_TIME_FORMAT_TYPE)
#else
......
This diff is collapsed.
......@@ -15,6 +15,7 @@
#include "src/contexts.h"
#include "src/intl.h"
#include "src/objects.h"
#include "unicode/locid.h"
#include "unicode/uversion.h"
namespace U_ICU_NAMESPACE {
......@@ -136,41 +137,6 @@ class Collator {
Collator();
};
class PluralRules {
public:
// Create a PluralRules and DecimalFormat for the specificied locale and
// options. Returns false on an ICU failure.
static void InitializePluralRules(Isolate* isolate, Handle<String> locale,
Handle<JSObject> options,
Handle<JSObject> resolved,
icu::PluralRules** plural_rules,
icu::DecimalFormat** decimal_format);
// Unpacks PluralRules object from corresponding JavaScript object.
static icu::PluralRules* UnpackPluralRules(Handle<JSObject> obj);
// Unpacks NumberFormat object from corresponding JavaScript PluralRUles
// object.
static icu::DecimalFormat* UnpackNumberFormat(Handle<JSObject> obj);
// Release memory we allocated for the Collator once the JS object that holds
// the pointer gets garbage collected.
static void DeletePluralRules(const v8::WeakCallbackInfo<void>& data);
// Layout description.
static const int kPluralRules = JSObject::kHeaderSize;
// Values are formatted with this NumberFormat and then parsed as a Number
// to round them based on the options passed into the PluralRules objct.
// TODO(littledan): If a future version of ICU supports the rounding
// built-in to PluralRules, switch to that, see this bug:
// http://bugs.icu-project.org/trac/ticket/12763
static const int kNumberFormat = kPluralRules + kPointerSize;
static const int kSize = kNumberFormat + kPointerSize;
private:
PluralRules();
};
class V8BreakIterator {
public:
// Create a BreakIterator for the specificied locale and options. Returns the
......@@ -266,6 +232,13 @@ class Intl {
Isolate* isolate, const char* service, Handle<Object> requestedLocales,
Handle<Object> options);
// This currently calls out to the JavaScript implementation of
// CanonicalizeLocaleList.
//
// ecma402/#sec-canonicalizelocalelist
V8_WARN_UNUSED_RESULT static MaybeHandle<JSObject> CanonicalizeLocaleList(
Isolate* isolate, Handle<Object> locales);
// ECMA402 9.2.10. GetOption( options, property, type, values, fallback)
// ecma402/#sec-getoption
//
......@@ -337,14 +310,25 @@ class Intl {
Handle<Object> options);
// ecma402/#sec-defaultnumberoption
V8_WARN_UNUSED_RESULT static MaybeHandle<Smi> DefaultNumberOption(
V8_WARN_UNUSED_RESULT static Maybe<int> DefaultNumberOption(
Isolate* isolate, Handle<Object> value, int min, int max, int fallback,
Handle<String> property);
// ecma402/#sec-getnumberoption
V8_WARN_UNUSED_RESULT static MaybeHandle<Smi> GetNumberOption(
V8_WARN_UNUSED_RESULT static Maybe<int> GetNumberOption(
Isolate* isolate, Handle<JSReceiver> options, Handle<String> property,
int min, int max, int fallback);
V8_WARN_UNUSED_RESULT static Maybe<int> GetNumberOption(
Isolate* isolate, Handle<JSReceiver> options, const char* property,
int min, int max, int fallback);
// ecma402/#sec-setnfdigitoptions
V8_WARN_UNUSED_RESULT static Maybe<bool> SetNumberFormatDigitOptions(
Isolate* isolate, icu::DecimalFormat* number_format,
Handle<JSReceiver> options, int mnfd_default, int mxfd_default);
icu::Locale static CreateICULocale(Isolate* isolate,
Handle<String> bcp47_locale_str);
};
} // namespace internal
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif // V8_INTL_SUPPORT
#ifndef V8_OBJECTS_JS_PLURAL_RULES_INL_H_
#define V8_OBJECTS_JS_PLURAL_RULES_INL_H_
#include "src/api-inl.h"
#include "src/objects-inl.h"
#include "src/objects/js-plural-rules.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
ACCESSORS(JSPluralRules, locale, String, kLocaleOffset)
ACCESSORS(JSPluralRules, type, String, kTypeOffset)
ACCESSORS(JSPluralRules, icu_plural_rules, Managed<icu::PluralRules>,
kICUPluralRulesOffset)
ACCESSORS(JSPluralRules, icu_decimal_format, Managed<icu::DecimalFormat>,
kICUDecimalFormatOffset)
CAST_ACCESSOR(JSPluralRules);
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_PLURAL_RULES_INL_H_
This diff is collapsed.
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTL_SUPPORT
#error Internationalization is expected to be enabled.
#endif // V8_INTL_SUPPORT
#ifndef V8_OBJECTS_JS_PLURAL_RULES_H_
#define V8_OBJECTS_JS_PLURAL_RULES_H_
#include "src/heap/factory.h"
#include "src/isolate.h"
#include "src/objects.h"
#include "src/objects/intl-objects.h"
#include "src/objects/managed.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class JSPluralRules : public JSObject {
public:
V8_WARN_UNUSED_RESULT static MaybeHandle<JSPluralRules> InitializePluralRules(
Isolate* isolate, Handle<JSPluralRules> plural_rules,
Handle<Object> locales, Handle<Object> options);
static Handle<JSObject> ResolvedOptions(Isolate* isolate,
Handle<JSPluralRules> plural_rules);
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ResolvePlural(
Isolate* isolate, Handle<JSPluralRules> plural_rules,
Handle<Object> number);
DECL_CAST(JSPluralRules)
DECL_PRINTER(JSPluralRules)
DECL_VERIFIER(JSPluralRules)
// Layout description.
#define JS_PLURAL_RULES_FIELDS(V) \
V(kLocaleOffset, kPointerSize) \
/* In the future, this can be an enum, \
and not a string. */ \
V(kTypeOffset, kPointerSize) \
V(kICUPluralRulesOffset, kPointerSize) \
V(kICUDecimalFormatOffset, kPointerSize) \
/* Total size. */ \
V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize, JS_PLURAL_RULES_FIELDS)
#undef JS_PLURAL_RULES_FIELDS
DECL_ACCESSORS(locale, String)
DECL_ACCESSORS(type, String)
DECL_ACCESSORS(icu_plural_rules, Managed<icu::PluralRules>)
DECL_ACCESSORS(icu_decimal_format, Managed<icu::DecimalFormat>)
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSPluralRules);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_PLURAL_RULES_H_
......@@ -20,6 +20,7 @@
#include "src/messages.h"
#include "src/objects/intl-objects-inl.h"
#include "src/objects/intl-objects.h"
#include "src/objects/js-plural-rules-inl.h"
#include "src/objects/managed.h"
#include "src/runtime/runtime-utils.h"
#include "src/utils.h"
......@@ -60,9 +61,13 @@ RUNTIME_FUNCTION(Runtime_GetNumberOption) {
CONVERT_SMI_ARG_CHECKED(min, 2);
CONVERT_SMI_ARG_CHECKED(max, 3);
CONVERT_SMI_ARG_CHECKED(fallback, 4);
RETURN_RESULT_OR_FAILURE(
isolate,
Intl::GetNumberOption(isolate, options, property, min, max, fallback));
Maybe<int> num =
Intl::GetNumberOption(isolate, options, property, min, max, fallback);
if (num.IsNothing()) {
return ReadOnlyRoots(isolate).exception();
}
return Smi::FromInt(num.FromJust());
}
RUNTIME_FUNCTION(Runtime_DefaultNumberOption) {
......@@ -73,9 +78,13 @@ RUNTIME_FUNCTION(Runtime_DefaultNumberOption) {
CONVERT_SMI_ARG_CHECKED(max, 2);
CONVERT_SMI_ARG_CHECKED(fallback, 3);
CONVERT_ARG_HANDLE_CHECKED(String, property, 4);
RETURN_RESULT_OR_FAILURE(
isolate,
Intl::DefaultNumberOption(isolate, value, min, max, fallback, property));
Maybe<int> num =
Intl::DefaultNumberOption(isolate, value, min, max, fallback, property);
if (num.IsNothing()) {
return ReadOnlyRoots(isolate).exception();
}
return Smi::FromInt(num.FromJust());
}
// ECMA 402 6.2.3
......@@ -275,80 +284,52 @@ RUNTIME_FUNCTION(Runtime_InternalCompare) {
return *Intl::InternalCompare(isolate, collator_holder, string1, string2);
}
RUNTIME_FUNCTION(Runtime_CreatePluralRules) {
RUNTIME_FUNCTION(Runtime_PluralRulesResolvedOptions) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, locale, 0);
CONVERT_ARG_HANDLE_CHECKED(JSObject, options, 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, resolved, 2);
Handle<JSFunction> constructor(
isolate->native_context()->intl_plural_rules_function(), isolate);
Handle<JSObject> local_object;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, local_object,
JSObject::New(constructor, constructor));
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, plural_rules_obj, 0);
// Set pluralRules as internal field of the resulting JS object.
icu::PluralRules* plural_rules;
icu::DecimalFormat* decimal_format;
PluralRules::InitializePluralRules(isolate, locale, options, resolved,
&plural_rules, &decimal_format);
CHECK_NOT_NULL(plural_rules);
CHECK_NOT_NULL(decimal_format);
// 3. If pr does not have an [[InitializedPluralRules]] internal
// slot, throw a TypeError exception.
if (!plural_rules_obj->IsJSPluralRules()) {
Handle<String> method_str = isolate->factory()->NewStringFromStaticChars(
"Intl.PluralRules.prototype.resolvedOptions");
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
method_str, plural_rules_obj));
}
local_object->SetEmbedderField(0, reinterpret_cast<Smi*>(plural_rules));
local_object->SetEmbedderField(1, reinterpret_cast<Smi*>(decimal_format));
Handle<JSPluralRules> plural_rules =
Handle<JSPluralRules>::cast(plural_rules_obj);
Handle<Object> wrapper = isolate->global_handles()->Create(*local_object);
GlobalHandles::MakeWeak(wrapper.location(), wrapper.location(),
PluralRules::DeletePluralRules,
WeakCallbackType::kInternalFields);
return *local_object;
return *JSPluralRules::ResolvedOptions(isolate, plural_rules);
}
RUNTIME_FUNCTION(Runtime_PluralRulesSelect) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, plural_rules_holder, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, plural_rules_obj, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, number, 1);
icu::PluralRules* plural_rules =
PluralRules::UnpackPluralRules(plural_rules_holder);
CHECK_NOT_NULL(plural_rules);
icu::DecimalFormat* number_format =
PluralRules::UnpackNumberFormat(plural_rules_holder);
CHECK_NOT_NULL(number_format);
// Currently, PluralRules doesn't implement all the options for rounding that
// the Intl spec provides; format and parse the number to round to the
// appropriate amount, then apply PluralRules.
//
// TODO(littledan): If a future ICU version supports an extended API to avoid
// this step, then switch to that API. Bug thread:
// http://bugs.icu-project.org/trac/ticket/12763
icu::UnicodeString rounded_string;
number_format->format(number->Number(), rounded_string);
icu::Formattable formattable;
UErrorCode status = U_ZERO_ERROR;
number_format->parse(rounded_string, formattable, status);
if (!U_SUCCESS(status)) return isolate->ThrowIllegalOperation();
double rounded = formattable.getDouble(status);
if (!U_SUCCESS(status)) return isolate->ThrowIllegalOperation();
icu::UnicodeString result = plural_rules->select(rounded);
return *isolate->factory()
->NewStringFromTwoByte(Vector<const uint16_t>(
reinterpret_cast<const uint16_t*>(result.getBuffer()),
result.length()))
.ToHandleChecked();
// 3. If pr does not have an [[InitializedPluralRules]] internal
// slot, throw a TypeError exception.
if (!plural_rules_obj->IsJSPluralRules()) {
Handle<String> method_str = isolate->factory()->NewStringFromStaticChars(
"Intl.PluralRules.prototype.select");
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
method_str, plural_rules_obj));
}
Handle<JSPluralRules> plural_rules =
Handle<JSPluralRules>::cast(plural_rules_obj);
// 4. Return ? ResolvePlural(pr, n).
RETURN_RESULT_OR_FAILURE(
isolate, JSPluralRules::ResolvePlural(isolate, plural_rules, number));
}
RUNTIME_FUNCTION(Runtime_CreateBreakIterator) {
......
......@@ -214,7 +214,6 @@ namespace internal {
F(CreateDateTimeFormat, 3, 1) \
F(CreateNumberFormat, 3, 1) \
F(DefineWEProperty, 3, 1) \
F(CreatePluralRules, 3, 1) \
F(CurrencyDigits, 1, 1) \
F(DateCacheVersion, 0, 1) \
F(DefaultNumberOption, 5, 1) \
......@@ -226,6 +225,7 @@ namespace internal {
F(IsInitializedIntlObjectOfType, 2, 1) \
F(IsWellFormedCurrencyCode, 1, 1) \
F(MarkAsInitializedIntlObjectOfType, 2, 1) \
F(PluralRulesResolvedOptions, 1, 1) \
F(PluralRulesSelect, 2, 1) \
F(StringToLowerCaseIntl, 1, 1) \
F(StringToUpperCaseIntl, 1, 1)
......
......@@ -161,14 +161,15 @@ INSTANCE_TYPES = {
1083: "JS_DATA_VIEW_TYPE",
1084: "JS_INTL_LIST_FORMAT_TYPE",
1085: "JS_INTL_LOCALE_TYPE",
1086: "JS_INTL_RELATIVE_TIME_FORMAT_TYPE",
1087: "WASM_GLOBAL_TYPE",
1088: "WASM_INSTANCE_TYPE",
1089: "WASM_MEMORY_TYPE",
1090: "WASM_MODULE_TYPE",
1091: "WASM_TABLE_TYPE",
1092: "JS_BOUND_FUNCTION_TYPE",
1093: "JS_FUNCTION_TYPE",
1086: "JS_INTL_PLURAL_RULES_TYPE",
1087: "JS_INTL_RELATIVE_TIME_FORMAT_TYPE",
1088: "WASM_GLOBAL_TYPE",
1089: "WASM_INSTANCE_TYPE",
1090: "WASM_MEMORY_TYPE",
1091: "WASM_MODULE_TYPE",
1092: "WASM_TABLE_TYPE",
1093: "JS_BOUND_FUNCTION_TYPE",
1094: "JS_FUNCTION_TYPE",
}
# List of known V8 maps.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment