Merge V8 5.2.361.47 DO NOT MERGE
https://chromium.googlesource.com/v8/v8/+/5.2.361.47
FPIIM-449
Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/src/js/i18n.js b/src/js/i18n.js
index 845289a..7c9535b 100644
--- a/src/js/i18n.js
+++ b/src/js/i18n.js
@@ -20,6 +20,7 @@
var ArrayIndexOf;
var ArrayJoin;
var ArrayPush;
+var FLAG_intl_extra;
var GlobalBoolean = global.Boolean;
var GlobalDate = global.Date;
var GlobalNumber = global.Number;
@@ -27,7 +28,7 @@
var GlobalString = global.String;
var InstallFunctions = utils.InstallFunctions;
var InstallGetter = utils.InstallGetter;
-var InternalPackedArray = utils.InternalPackedArray;
+var InternalArray = utils.InternalArray;
var InternalRegExpMatch;
var InternalRegExpReplace
var IsFinite;
@@ -35,8 +36,6 @@
var MakeError;
var MakeRangeError;
var MakeTypeError;
-var ObjectDefineProperties = utils.ImportNow("ObjectDefineProperties");
-var ObjectDefineProperty = utils.ImportNow("ObjectDefineProperty");
var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty");
var OverrideFunction = utils.OverrideFunction;
var patternSymbol = utils.ImportNow("intl_pattern_symbol");
@@ -66,6 +65,10 @@
StringSubstring = from.StringSubstring;
});
+utils.ImportFromExperimental(function(from) {
+ FLAG_intl_extra = from.FLAG_intl_extra;
+});
+
// Utilities for definitions
function InstallFunction(object, name, func) {
@@ -84,11 +87,11 @@
/**
* Adds bound method to the prototype of the given object.
*/
-function AddBoundMethod(obj, methodName, implementation, length) {
+function AddBoundMethod(obj, methodName, implementation, length, type) {
%CheckIsBootstrapping();
var internalName = %CreatePrivateSymbol(methodName);
var getter = function() {
- if (!%IsInitializedIntlObject(this)) {
+ if (!%IsInitializedIntlObjectOfType(this, type)) {
throw MakeTypeError(kMethodCalledOnWrongObject, methodName);
}
if (IS_UNDEFINED(this[internalName])) {
@@ -144,6 +147,13 @@
*/
var DEFAULT_ICU_LOCALE = UNDEFINED;
+function GetDefaultICULocaleJS() {
+ if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) {
+ DEFAULT_ICU_LOCALE = %GetDefaultICULocale();
+ }
+ return DEFAULT_ICU_LOCALE;
+}
+
/**
* Unicode extension regular expression.
*/
@@ -307,7 +317,7 @@
* Locales appear in the same order in the returned list as in the input list.
*/
function lookupSupportedLocalesOf(requestedLocales, availableLocales) {
- var matchedLocales = [];
+ var matchedLocales = new InternalArray();
for (var i = 0; i < requestedLocales.length; ++i) {
// Remove -u- extension.
var locale = InternalRegExpReplace(
@@ -448,11 +458,7 @@
}
// Didn't find a match, return default.
- if (IS_UNDEFINED(DEFAULT_ICU_LOCALE)) {
- DEFAULT_ICU_LOCALE = %GetDefaultICULocale();
- }
-
- return {'locale': DEFAULT_ICU_LOCALE, 'extension': '', 'position': -1};
+ return {'locale': GetDefaultICULocaleJS(), 'extension': '', 'position': -1};
}
@@ -567,21 +573,23 @@
/**
- * Converts all OwnProperties into
+ * Given an array-like, outputs an Array with the numbered
+ * properties copied over and defined
* configurable: false, writable: false, enumerable: true.
*/
-function freezeArray(array) {
- var l = array.length;
+function freezeArray(input) {
+ var array = [];
+ var l = input.length;
for (var i = 0; i < l; i++) {
- if (i in array) {
- ObjectDefineProperty(array, i, {value: array[i],
- configurable: false,
- writable: false,
- enumerable: true});
+ if (i in input) {
+ %object_define_property(array, i, {value: input[i],
+ configurable: false,
+ writable: false,
+ enumerable: true});
}
}
- ObjectDefineProperty(array, 'length', {value: l, writable: false});
+ %object_define_property(array, 'length', {value: l, writable: false});
return array;
}
@@ -643,8 +651,8 @@
* Configurable is false by default.
*/
function defineWEProperty(object, property, value) {
- ObjectDefineProperty(object, property,
- {value: value, writable: true, enumerable: true});
+ %object_define_property(object, property,
+ {value: value, writable: true, enumerable: true});
}
@@ -663,10 +671,10 @@
* Defines a property and sets writable, enumerable and configurable to true.
*/
function defineWECProperty(object, property, value) {
- ObjectDefineProperty(object, property, {value: value,
- writable: true,
- enumerable: true,
- configurable: true});
+ %object_define_property(object, property, {value: value,
+ writable: true,
+ enumerable: true,
+ configurable: true});
}
@@ -722,21 +730,24 @@
*/
function canonicalizeLanguageTag(localeID) {
// null is typeof 'object' so we have to do extra check.
- if (typeof localeID !== 'string' && typeof localeID !== 'object' ||
+ if ((!IS_STRING(localeID) && !IS_RECEIVER(localeID)) ||
IS_NULL(localeID)) {
throw MakeTypeError(kLanguageID);
}
+ // Optimize for the most common case; a language code alone in
+ // the canonical form/lowercase (e.g. "en", "fil").
+ if (IS_STRING(localeID) &&
+ !IS_NULL(InternalRegExpMatch(/^[a-z]{2,3}$/, localeID))) {
+ return localeID;
+ }
+
var localeString = GlobalString(localeID);
if (isValidLanguageTag(localeString) === false) {
throw MakeRangeError(kInvalidLanguageTag, localeString);
}
- // This call will strip -kn but not -kn-true extensions.
- // ICU bug filled - http://bugs.icu-project.org/trac/ticket/9265.
- // TODO(cira): check if -u-kn-true-kc-true-kh-true still throws after
- // upgrade to ICU 4.9.
var tag = %CanonicalizeLanguageTag(localeString);
if (tag === 'invalid-tag') {
throw MakeRangeError(kInvalidLanguageTag, localeString);
@@ -751,11 +762,8 @@
* Throws on locales that are not well formed BCP47 tags.
*/
function initializeLocaleList(locales) {
- var seen = [];
- if (IS_UNDEFINED(locales)) {
- // Constructor is called without arguments.
- seen = [];
- } else {
+ var seen = new InternalArray();
+ if (!IS_UNDEFINED(locales)) {
// We allow single string localeID.
if (typeof locales === 'string') {
%_Call(ArrayPush, seen, canonicalizeLanguageTag(locales));
@@ -810,8 +818,8 @@
// Skip language since it can match variant regex, so we start from 1.
// We are matching i-klingon here, but that's ok, since i-klingon-klingon
// is not valid and would fail LANGUAGE_TAG_RE test.
- var variants = [];
- var extensions = [];
+ var variants = new InternalArray();
+ var extensions = new InternalArray();
var parts = %_Call(StringSplit, locale, '-');
for (var i = 1; i < parts.length; i++) {
var value = parts[i];
@@ -965,8 +973,8 @@
// We define all properties C++ code may produce, to prevent security
// problems. If malicious user decides to redefine Object.prototype.locale
// we can't just use plain x.locale = 'us' or in C++ Set("locale", "us").
- // ObjectDefineProperties will either succeed defining or throw an error.
- var resolved = ObjectDefineProperties({}, {
+ // %object_define_properties will either succeed defining or throw an error.
+ var resolved = %object_define_properties({}, {
caseFirst: {writable: true},
collation: {value: internalOptions.collation, writable: true},
ignorePunctuation: {writable: true},
@@ -985,7 +993,9 @@
// Writable, configurable and enumerable are set to false by default.
%MarkAsInitializedIntlObjectOfType(collator, 'collator', internalCollator);
collator[resolvedSymbol] = resolved;
- ObjectDefineProperty(collator, 'resolved', resolvedAccessor);
+ if (FLAG_intl_extra) {
+ %object_define_property(collator, 'resolved', resolvedAccessor);
+ }
return collator;
}
@@ -1072,7 +1082,7 @@
};
-AddBoundMethod(Intl.Collator, 'compare', compare, 2);
+AddBoundMethod(Intl.Collator, 'compare', compare, 2, 'collator');
/**
* Verifies that the input is a well-formed ISO 4217 currency code.
@@ -1198,7 +1208,7 @@
getOption, internalOptions);
var requestedLocale = locale.locale + extension;
- var resolved = ObjectDefineProperties({}, {
+ var resolved = %object_define_properties({}, {
currency: {writable: true},
currencyDisplay: {writable: true},
locale: {writable: true},
@@ -1206,7 +1216,6 @@
minimumFractionDigits: {writable: true},
minimumIntegerDigits: {writable: true},
numberingSystem: {writable: true},
- pattern: patternAccessor,
requestedLocale: {value: requestedLocale, writable: true},
style: {value: internalOptions.style, writable: true},
useGrouping: {writable: true}
@@ -1222,13 +1231,16 @@
resolved);
if (internalOptions.style === 'currency') {
- ObjectDefineProperty(resolved, 'currencyDisplay', {value: currencyDisplay,
- writable: true});
+ %object_define_property(resolved, 'currencyDisplay',
+ {value: currencyDisplay, writable: true});
}
%MarkAsInitializedIntlObjectOfType(numberFormat, 'numberformat', formatter);
numberFormat[resolvedSymbol] = resolved;
- ObjectDefineProperty(numberFormat, 'resolved', resolvedAccessor);
+ if (FLAG_intl_extra) {
+ %object_define_property(resolved, 'pattern', patternAccessor);
+ %object_define_property(numberFormat, 'resolved', resolvedAccessor);
+ }
return numberFormat;
}
@@ -1334,14 +1346,12 @@
/**
* Returns a Number that represents string value that was passed in.
*/
-function parseNumber(formatter, value) {
+function IntlParseNumber(formatter, value) {
return %InternalNumberParse(%GetImplFromInitializedIntlObject(formatter),
GlobalString(value));
}
-
-AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1);
-AddBoundMethod(Intl.NumberFormat, 'v8Parse', parseNumber, 1);
+AddBoundMethod(Intl.NumberFormat, 'format', formatNumber, 1, 'numberformat');
/**
* Returns a string that matches LDML representation of the options object.
@@ -1508,33 +1518,33 @@
}
if (needsDefault && (defaults === 'date' || defaults === 'all')) {
- ObjectDefineProperty(options, 'year', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- ObjectDefineProperty(options, 'month', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- ObjectDefineProperty(options, 'day', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
+ %object_define_property(options, 'year', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ %object_define_property(options, 'month', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ %object_define_property(options, 'day', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
}
if (needsDefault && (defaults === 'time' || defaults === 'all')) {
- ObjectDefineProperty(options, 'hour', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- ObjectDefineProperty(options, 'minute', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
- ObjectDefineProperty(options, 'second', {value: 'numeric',
- writable: true,
- enumerable: true,
- configurable: true});
+ %object_define_property(options, 'hour', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ %object_define_property(options, 'minute', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
+ %object_define_property(options, 'second', {value: 'numeric',
+ writable: true,
+ enumerable: true,
+ configurable: true});
}
return options;
@@ -1592,7 +1602,7 @@
getOption, internalOptions);
var requestedLocale = locale.locale + extension;
- var resolved = ObjectDefineProperties({}, {
+ var resolved = %object_define_properties({}, {
calendar: {writable: true},
day: {writable: true},
era: {writable: true},
@@ -1603,7 +1613,6 @@
month: {writable: true},
numberingSystem: {writable: true},
[patternSymbol]: {writable: true},
- pattern: patternAccessor,
requestedLocale: {value: requestedLocale, writable: true},
second: {writable: true},
timeZone: {writable: true},
@@ -1622,7 +1631,10 @@
%MarkAsInitializedIntlObjectOfType(dateFormat, 'dateformat', formatter);
dateFormat[resolvedSymbol] = resolved;
- ObjectDefineProperty(dateFormat, 'resolved', resolvedAccessor);
+ if (FLAG_intl_extra) {
+ %object_define_property(resolved, 'pattern', patternAccessor);
+ %object_define_property(dateFormat, 'resolved', resolvedAccessor);
+ }
return dateFormat;
}
@@ -1756,15 +1768,14 @@
* DateTimeFormat.
* Returns undefined if date string cannot be parsed.
*/
-function parseDate(formatter, value) {
+function IntlParseDate(formatter, value) {
return %InternalDateParse(%GetImplFromInitializedIntlObject(formatter),
GlobalString(value));
}
// 0 because date is optional argument.
-AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0);
-AddBoundMethod(Intl.DateTimeFormat, 'v8Parse', parseDate, 1);
+AddBoundMethod(Intl.DateTimeFormat, 'format', formatDate, 0, 'dateformat');
/**
@@ -1826,7 +1837,7 @@
'type', 'string', ['character', 'word', 'sentence', 'line'], 'word'));
var locale = resolveLocale('breakiterator', locales, options);
- var resolved = ObjectDefineProperties({}, {
+ var resolved = %object_define_properties({}, {
requestedLocale: {value: locale.locale, writable: true},
type: {value: internalOptions.type, writable: true},
locale: {writable: true}
@@ -1839,7 +1850,9 @@
%MarkAsInitializedIntlObjectOfType(iterator, 'breakiterator',
internalIterator);
iterator[resolvedSymbol] = resolved;
- ObjectDefineProperty(iterator, 'resolved', resolvedAccessor);
+ if (FLAG_intl_extra) {
+ %object_define_property(iterator, 'resolved', resolvedAccessor);
+ }
return iterator;
}
@@ -1950,11 +1963,13 @@
}
-AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1);
-AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0);
-AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0);
-AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0);
-AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0);
+AddBoundMethod(Intl.v8BreakIterator, 'adoptText', adoptText, 1,
+ 'breakiterator');
+AddBoundMethod(Intl.v8BreakIterator, 'first', first, 0, 'breakiterator');
+AddBoundMethod(Intl.v8BreakIterator, 'next', next, 0, 'breakiterator');
+AddBoundMethod(Intl.v8BreakIterator, 'current', current, 0, 'breakiterator');
+AddBoundMethod(Intl.v8BreakIterator, 'breakType', breakType, 0,
+ 'breakiterator');
// Save references to Intl objects and methods we use, for added security.
var savedObjects = {
@@ -1992,6 +2007,37 @@
return new savedObjects[service](locales, useOptions);
}
+function LocaleConvertCase(s, locales, isToUpper) {
+ // ECMA 402 section 13.1.2 steps 1 through 12.
+ var language;
+ // Optimize for the most common two cases. initializeLocaleList() can handle
+ // them as well, but it's rather slow accounting for over 60% of
+ // toLocale{U,L}Case() and about 40% of toLocale{U,L}Case("<locale>").
+ if (IS_UNDEFINED(locales)) {
+ language = GetDefaultICULocaleJS();
+ } else if (IS_STRING(locales)) {
+ language = canonicalizeLanguageTag(locales);
+ } else {
+ var locales = initializeLocaleList(locales);
+ language = locales.length > 0 ? locales[0] : GetDefaultICULocaleJS();
+ }
+
+ // StringSplit is slower than this.
+ var pos = %_Call(StringIndexOf, language, '-');
+ if (pos != -1) {
+ language = %_Call(StringSubstring, language, 0, pos);
+ }
+
+ var CUSTOM_CASE_LANGUAGES = ['az', 'el', 'lt', 'tr'];
+ var langIndex = %_Call(ArrayIndexOf, CUSTOM_CASE_LANGUAGES, language);
+ if (langIndex == -1) {
+ // language-independent case conversion.
+ return isToUpper ? %StringToUpperCaseI18N(s) : %StringToLowerCaseI18N(s);
+ }
+ return %StringLocaleConvertCase(s, isToUpper,
+ CUSTOM_CASE_LANGUAGES[langIndex]);
+}
+
/**
* Compares this and that, and returns less than 0, 0 or greater than 0 value.
* Overrides the built-in method.
@@ -2044,6 +2090,56 @@
}
);
+function ToLowerCaseI18N() {
+ if (!IS_UNDEFINED(new.target)) {
+ throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
+ }
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLowerCase");
+ var s = TO_STRING(this);
+ return %StringToLowerCaseI18N(s);
+}
+
+function ToUpperCaseI18N() {
+ if (!IS_UNDEFINED(new.target)) {
+ throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
+ }
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.toUpperCase");
+ var s = TO_STRING(this);
+ return %StringToUpperCaseI18N(s);
+}
+
+function ToLocaleLowerCaseI18N(locales) {
+ if (!IS_UNDEFINED(new.target)) {
+ throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
+ }
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase");
+ return LocaleConvertCase(TO_STRING(this), locales, false);
+}
+
+%FunctionSetLength(ToLocaleLowerCaseI18N, 0);
+
+function ToLocaleUpperCaseI18N(locales) {
+ if (!IS_UNDEFINED(new.target)) {
+ throw MakeTypeError(kOrdinaryFunctionCalledAsConstructor);
+ }
+ CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase");
+ return LocaleConvertCase(TO_STRING(this), locales, true);
+}
+
+%FunctionSetLength(ToLocaleUpperCaseI18N, 0);
+
+%FunctionRemovePrototype(ToLowerCaseI18N);
+%FunctionRemovePrototype(ToUpperCaseI18N);
+%FunctionRemovePrototype(ToLocaleLowerCaseI18N);
+%FunctionRemovePrototype(ToLocaleUpperCaseI18N);
+
+utils.Export(function(to) {
+ to.ToLowerCaseI18N = ToLowerCaseI18N;
+ to.ToUpperCaseI18N = ToUpperCaseI18N;
+ to.ToLocaleLowerCaseI18N = ToLocaleLowerCaseI18N;
+ to.ToLocaleUpperCaseI18N = ToLocaleUpperCaseI18N;
+});
+
/**
* Formats a Number object (this) using locale and options values.
@@ -2138,4 +2234,10 @@
}
);
+utils.Export(function(to) {
+ to.AddBoundMethod = AddBoundMethod;
+ to.IntlParseDate = IntlParseDate;
+ to.IntlParseNumber = IntlParseNumber;
+});
+
})