[runtime] Cleanup native methods creation in js/intl.js.
This CL replaces usages of utils.InstallFunctions and utils.InstallGetter() with the DEFINE_METHOD* macros that ensure that the native function is created in proper form from the beginning. Thus the function will not require further reconfiguring like adding a computed name or removing of 'prototype' property. This CL is one of a series of cleanup CL which are the preliminary steps for improving function closures creation. Bug: v8:6459 Cq-Include-Trybots: master.tryserver.v8:v8_linux_noi18n_rel_ng Change-Id: I667d70fae12a2f50d0fe18d958b6520110b4b573 Reviewed-on: https://chromium-review.googlesource.com/548075 Commit-Queue: Igor Sheludko <ishell@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Cr-Commit-Position: refs/heads/master@{#46278}
This commit is contained in:
parent
f9e0322ae8
commit
e7bd43c32d
176
src/js/intl.js
176
src/js/intl.js
@ -29,15 +29,11 @@ var GlobalNumber = global.Number;
|
||||
var GlobalRegExp = global.RegExp;
|
||||
var GlobalString = global.String;
|
||||
var IntlFallbackSymbol = utils.ImportNow("intl_fallback_symbol");
|
||||
var InstallFunctions = utils.InstallFunctions;
|
||||
var InstallGetter = utils.InstallGetter;
|
||||
var InternalArray = utils.InternalArray;
|
||||
var MaxSimple;
|
||||
var ObjectHasOwnProperty = global.Object.prototype.hasOwnProperty;
|
||||
var OverrideFunction = utils.OverrideFunction;
|
||||
var patternSymbol = utils.ImportNow("intl_pattern_symbol");
|
||||
var resolvedSymbol = utils.ImportNow("intl_resolved_symbol");
|
||||
var SetFunctionName = utils.SetFunctionName;
|
||||
var StringSubstr = GlobalString.prototype.substr;
|
||||
var StringSubstring = GlobalString.prototype.substring;
|
||||
|
||||
@ -49,11 +45,6 @@ utils.Import(function(from) {
|
||||
|
||||
// Utilities for definitions
|
||||
|
||||
function InstallFunction(object, name, func) {
|
||||
InstallFunctions(object, DONT_ENUM, [name, func]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds bound method to the prototype of the given object.
|
||||
*/
|
||||
@ -61,41 +52,36 @@ function AddBoundMethod(obj, methodName, implementation, length, typename,
|
||||
compat) {
|
||||
%CheckIsBootstrapping();
|
||||
var internalName = %CreatePrivateSymbol(methodName);
|
||||
// Making getter an anonymous function will cause
|
||||
// %DefineGetterPropertyUnchecked to properly set the "name"
|
||||
// property on each JSFunction instance created here, rather
|
||||
// than (as utils.InstallGetter would) on the SharedFunctionInfo
|
||||
// associated with all functions returned from AddBoundMethod.
|
||||
var getter = ANONYMOUS_FUNCTION(function() {
|
||||
var receiver = Unwrap(this, typename, obj, methodName, compat);
|
||||
if (IS_UNDEFINED(receiver[internalName])) {
|
||||
var boundMethod;
|
||||
if (IS_UNDEFINED(length) || length === 2) {
|
||||
boundMethod =
|
||||
ANONYMOUS_FUNCTION((fst, snd) => implementation(receiver, fst, snd));
|
||||
} else if (length === 1) {
|
||||
boundMethod = ANONYMOUS_FUNCTION(fst => implementation(receiver, fst));
|
||||
} else {
|
||||
boundMethod = ANONYMOUS_FUNCTION((...args) => {
|
||||
// DateTimeFormat.format needs to be 0 arg method, but can still
|
||||
// receive an optional dateValue param. If one was provided, pass it
|
||||
// along.
|
||||
if (args.length > 0) {
|
||||
return implementation(receiver, args[0]);
|
||||
} else {
|
||||
return implementation(receiver);
|
||||
}
|
||||
});
|
||||
}
|
||||
%SetNativeFlag(boundMethod);
|
||||
receiver[internalName] = boundMethod;
|
||||
}
|
||||
return receiver[internalName];
|
||||
});
|
||||
|
||||
%FunctionRemovePrototype(getter);
|
||||
%DefineGetterPropertyUnchecked(obj.prototype, methodName, getter, DONT_ENUM);
|
||||
%SetNativeFlag(getter);
|
||||
DEFINE_METHOD(
|
||||
obj.prototype,
|
||||
get [methodName]() {
|
||||
var receiver = Unwrap(this, typename, obj, methodName, compat);
|
||||
if (IS_UNDEFINED(receiver[internalName])) {
|
||||
var boundMethod;
|
||||
if (IS_UNDEFINED(length) || length === 2) {
|
||||
boundMethod =
|
||||
ANONYMOUS_FUNCTION((fst, snd) => implementation(receiver, fst, snd));
|
||||
} else if (length === 1) {
|
||||
boundMethod = ANONYMOUS_FUNCTION(fst => implementation(receiver, fst));
|
||||
} else {
|
||||
boundMethod = ANONYMOUS_FUNCTION((...args) => {
|
||||
// DateTimeFormat.format needs to be 0 arg method, but can still
|
||||
// receive an optional dateValue param. If one was provided, pass it
|
||||
// along.
|
||||
if (args.length > 0) {
|
||||
return implementation(receiver, args[0]);
|
||||
} else {
|
||||
return implementation(receiver);
|
||||
}
|
||||
});
|
||||
}
|
||||
%SetNativeFlag(boundMethod);
|
||||
receiver[internalName] = boundMethod;
|
||||
}
|
||||
return receiver[internalName];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function IntlConstruct(receiver, constructor, create, newTarget, args,
|
||||
@ -914,7 +900,9 @@ function BuildLanguageTagREs() {
|
||||
}
|
||||
|
||||
// ECMA 402 section 8.2.1
|
||||
InstallFunction(GlobalIntl, 'getCanonicalLocales', function(locales) {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntl,
|
||||
getCanonicalLocales(locales) {
|
||||
return makeArray(canonicalizeLocaleList(locales));
|
||||
}
|
||||
);
|
||||
@ -1035,7 +1023,9 @@ function CollatorConstructor() {
|
||||
/**
|
||||
* Collator resolvedOptions method.
|
||||
*/
|
||||
InstallFunction(GlobalIntlCollator.prototype, 'resolvedOptions', function() {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlCollator.prototype,
|
||||
resolvedOptions() {
|
||||
var coll = Unwrap(this, 'collator', GlobalIntlCollator, 'resolvedOptions',
|
||||
false);
|
||||
return {
|
||||
@ -1057,7 +1047,9 @@ InstallFunction(GlobalIntlCollator.prototype, 'resolvedOptions', function() {
|
||||
* order in the returned list as in the input list.
|
||||
* Options are optional parameter.
|
||||
*/
|
||||
InstallFunction(GlobalIntlCollator, 'supportedLocalesOf', function(locales) {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlCollator,
|
||||
supportedLocalesOf(locales) {
|
||||
return supportedLocalesOf('collator', locales, arguments[1]);
|
||||
}
|
||||
);
|
||||
@ -1254,8 +1246,9 @@ function NumberFormatConstructor() {
|
||||
/**
|
||||
* NumberFormat resolvedOptions method.
|
||||
*/
|
||||
InstallFunction(GlobalIntlNumberFormat.prototype, 'resolvedOptions',
|
||||
function() {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlNumberFormat.prototype,
|
||||
resolvedOptions() {
|
||||
var format = Unwrap(this, 'numberformat', GlobalIntlNumberFormat,
|
||||
'resolvedOptions', true);
|
||||
var result = {
|
||||
@ -1295,8 +1288,9 @@ InstallFunction(GlobalIntlNumberFormat.prototype, 'resolvedOptions',
|
||||
* order in the returned list as in the input list.
|
||||
* Options are optional parameter.
|
||||
*/
|
||||
InstallFunction(GlobalIntlNumberFormat, 'supportedLocalesOf',
|
||||
function(locales) {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlNumberFormat,
|
||||
supportedLocalesOf(locales) {
|
||||
return supportedLocalesOf('numberformat', locales, arguments[1]);
|
||||
}
|
||||
);
|
||||
@ -1614,8 +1608,9 @@ function DateTimeFormatConstructor() {
|
||||
/**
|
||||
* DateTimeFormat resolvedOptions method.
|
||||
*/
|
||||
InstallFunction(GlobalIntlDateTimeFormat.prototype, 'resolvedOptions',
|
||||
function() {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlDateTimeFormat.prototype,
|
||||
resolvedOptions() {
|
||||
var format = Unwrap(this, 'dateformat', GlobalIntlDateTimeFormat,
|
||||
'resolvedOptions', true);
|
||||
|
||||
@ -1666,8 +1661,9 @@ InstallFunction(GlobalIntlDateTimeFormat.prototype, 'resolvedOptions',
|
||||
* order in the returned list as in the input list.
|
||||
* Options are optional parameter.
|
||||
*/
|
||||
InstallFunction(GlobalIntlDateTimeFormat, 'supportedLocalesOf',
|
||||
function(locales) {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlDateTimeFormat,
|
||||
supportedLocalesOf(locales) {
|
||||
return supportedLocalesOf('dateformat', locales, arguments[1]);
|
||||
}
|
||||
);
|
||||
@ -1691,8 +1687,9 @@ function formatDate(formatter, dateValue) {
|
||||
return %InternalDateFormat(formatter, new GlobalDate(dateMs));
|
||||
}
|
||||
|
||||
InstallFunction(GlobalIntlDateTimeFormat.prototype, 'formatToParts',
|
||||
function(dateValue) {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlDateTimeFormat.prototype,
|
||||
formatToParts(dateValue) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "Intl.DateTimeFormat.prototype.formatToParts");
|
||||
if (!IS_OBJECT(this)) {
|
||||
throw %make_type_error(kCalledOnNonObject, this);
|
||||
@ -1810,8 +1807,9 @@ function v8BreakIteratorConstructor() {
|
||||
/**
|
||||
* BreakIterator resolvedOptions method.
|
||||
*/
|
||||
InstallFunction(GlobalIntlv8BreakIterator.prototype, 'resolvedOptions',
|
||||
function() {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlv8BreakIterator.prototype,
|
||||
resolvedOptions() {
|
||||
if (!IS_UNDEFINED(new.target)) {
|
||||
throw %make_type_error(kOrdinaryFunctionCalledAsConstructor);
|
||||
}
|
||||
@ -1833,8 +1831,9 @@ InstallFunction(GlobalIntlv8BreakIterator.prototype, 'resolvedOptions',
|
||||
* order in the returned list as in the input list.
|
||||
* Options are optional parameter.
|
||||
*/
|
||||
InstallFunction(GlobalIntlv8BreakIterator, 'supportedLocalesOf',
|
||||
function(locales) {
|
||||
DEFINE_METHOD(
|
||||
GlobalIntlv8BreakIterator,
|
||||
supportedLocalesOf(locales) {
|
||||
if (!IS_UNDEFINED(new.target)) {
|
||||
throw %make_type_error(kOrdinaryFunctionCalledAsConstructor);
|
||||
}
|
||||
@ -1976,7 +1975,9 @@ function LocaleConvertCase(s, locales, isToUpper) {
|
||||
* Compares this and that, and returns less than 0, 0 or greater than 0 value.
|
||||
* Overrides the built-in method.
|
||||
*/
|
||||
OverrideFunction(GlobalString.prototype, 'localeCompare', function(that) {
|
||||
DEFINE_METHOD(
|
||||
GlobalString.prototype,
|
||||
localeCompare(that) {
|
||||
if (IS_NULL_OR_UNDEFINED(this)) {
|
||||
throw %make_type_error(kMethodInvokedOnNullOrUndefined);
|
||||
}
|
||||
@ -1988,26 +1989,31 @@ OverrideFunction(GlobalString.prototype, 'localeCompare', function(that) {
|
||||
}
|
||||
);
|
||||
|
||||
function ToLocaleLowerCaseIntl(locales) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase");
|
||||
return LocaleConvertCase(TO_STRING(this), locales, false);
|
||||
}
|
||||
var StringPrototypeMethods = {};
|
||||
DEFINE_METHODS_LEN(
|
||||
StringPrototypeMethods,
|
||||
{
|
||||
toLocaleLowerCase(locales) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase");
|
||||
return LocaleConvertCase(TO_STRING(this), locales, false);
|
||||
}
|
||||
|
||||
%FunctionSetLength(ToLocaleLowerCaseIntl, 0);
|
||||
|
||||
function ToLocaleUpperCaseIntl(locales) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase");
|
||||
return LocaleConvertCase(TO_STRING(this), locales, true);
|
||||
}
|
||||
|
||||
%FunctionSetLength(ToLocaleUpperCaseIntl, 0);
|
||||
toLocaleUpperCase(locales) {
|
||||
CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase");
|
||||
return LocaleConvertCase(TO_STRING(this), locales, true);
|
||||
}
|
||||
},
|
||||
0 /* Set function length of both methods. */
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Formats a Number object (this) using locale and options values.
|
||||
* If locale or options are omitted, defaults are used.
|
||||
*/
|
||||
OverrideFunction(GlobalNumber.prototype, 'toLocaleString', function() {
|
||||
DEFINE_METHOD(
|
||||
GlobalNumber.prototype,
|
||||
toLocaleString() {
|
||||
if (!(this instanceof GlobalNumber) && typeof(this) !== 'number') {
|
||||
throw %make_type_error(kMethodInvokedOnWrongType, "Number");
|
||||
}
|
||||
@ -2045,7 +2051,9 @@ function toLocaleDateTime(date, locales, options, required, defaults, service) {
|
||||
* If locale or options are omitted, defaults are used - both date and time are
|
||||
* present in the output.
|
||||
*/
|
||||
OverrideFunction(GlobalDate.prototype, 'toLocaleString', function() {
|
||||
DEFINE_METHOD(
|
||||
GlobalDate.prototype,
|
||||
toLocaleString() {
|
||||
var locales = arguments[0];
|
||||
var options = arguments[1];
|
||||
return toLocaleDateTime(
|
||||
@ -2059,7 +2067,9 @@ OverrideFunction(GlobalDate.prototype, 'toLocaleString', function() {
|
||||
* If locale or options are omitted, defaults are used - only date is present
|
||||
* in the output.
|
||||
*/
|
||||
OverrideFunction(GlobalDate.prototype, 'toLocaleDateString', function() {
|
||||
DEFINE_METHOD(
|
||||
GlobalDate.prototype,
|
||||
toLocaleDateString() {
|
||||
var locales = arguments[0];
|
||||
var options = arguments[1];
|
||||
return toLocaleDateTime(
|
||||
@ -2073,7 +2083,9 @@ OverrideFunction(GlobalDate.prototype, 'toLocaleDateString', function() {
|
||||
* If locale or options are omitted, defaults are used - only time is present
|
||||
* in the output.
|
||||
*/
|
||||
OverrideFunction(GlobalDate.prototype, 'toLocaleTimeString', function() {
|
||||
DEFINE_METHOD(
|
||||
GlobalDate.prototype,
|
||||
toLocaleTimeString() {
|
||||
var locales = arguments[0];
|
||||
var options = arguments[1];
|
||||
return toLocaleDateTime(
|
||||
@ -2081,15 +2093,9 @@ OverrideFunction(GlobalDate.prototype, 'toLocaleTimeString', function() {
|
||||
}
|
||||
);
|
||||
|
||||
%FunctionRemovePrototype(ToLocaleLowerCaseIntl);
|
||||
%FunctionRemovePrototype(ToLocaleUpperCaseIntl);
|
||||
|
||||
utils.SetFunctionName(ToLocaleLowerCaseIntl, "toLocaleLowerCase");
|
||||
utils.SetFunctionName(ToLocaleUpperCaseIntl, "toLocaleUpperCase");
|
||||
|
||||
utils.Export(function(to) {
|
||||
to.ToLocaleLowerCaseIntl = ToLocaleLowerCaseIntl;
|
||||
to.ToLocaleUpperCaseIntl = ToLocaleUpperCaseIntl;
|
||||
to.ToLocaleLowerCaseIntl = StringPrototypeMethods.toLocaleLowerCase;
|
||||
to.ToLocaleUpperCaseIntl = StringPrototypeMethods.toLocaleUpperCase;
|
||||
});
|
||||
|
||||
})
|
||||
|
@ -99,6 +99,11 @@ macro SET_PRIVATE(obj, sym, val) = (obj[sym] = val);
|
||||
# To avoid ES2015 Function name inference.
|
||||
macro ANONYMOUS_FUNCTION(fn) = (0, (fn));
|
||||
|
||||
macro DEFINE_METHODS_LEN(obj, class_def, len) = %DefineMethodsInternal(obj, class class_def, len);
|
||||
macro DEFINE_METHOD_LEN(obj, method_def, len) = %DefineMethodsInternal(obj, class { method_def }, len);
|
||||
macro DEFINE_METHODS(obj, class_def) = DEFINE_METHODS_LEN(obj, class_def, -1);
|
||||
macro DEFINE_METHOD(obj, method_def) = DEFINE_METHOD_LEN(obj, method_def, -1);
|
||||
|
||||
# Constants. The compiler constant folds them.
|
||||
define INFINITY = (1/0);
|
||||
define UNDEFINED = (void 0);
|
||||
|
@ -130,7 +130,6 @@ RUNTIME_FUNCTION(Runtime_FunctionSetLength) {
|
||||
|
||||
CONVERT_ARG_CHECKED(JSFunction, fun, 0);
|
||||
CONVERT_SMI_ARG_CHECKED(length, 1);
|
||||
CHECK((length & 0xC0000000) == 0xC0000000 || (length & 0xC0000000) == 0x0);
|
||||
fun->shared()->set_length(length);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
@ -917,6 +917,64 @@ RUNTIME_FUNCTION(Runtime_CopyDataPropertiesWithExcludedProperties) {
|
||||
return *target;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline void TrySetNative(Handle<Object> maybe_func) {
|
||||
if (!maybe_func->IsJSFunction()) return;
|
||||
JSFunction::cast(*maybe_func)->shared()->set_native(true);
|
||||
}
|
||||
|
||||
inline void TrySetNativeAndLength(Handle<Object> maybe_func, int length) {
|
||||
if (!maybe_func->IsJSFunction()) return;
|
||||
SharedFunctionInfo* shared = JSFunction::cast(*maybe_func)->shared();
|
||||
shared->set_native(true);
|
||||
if (length >= 0) {
|
||||
shared->set_length(length);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DefineMethodsInternal) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
CHECK(isolate->bootstrapper()->IsActive());
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, source_class, 1);
|
||||
CONVERT_SMI_ARG_CHECKED(length, 2);
|
||||
|
||||
DCHECK(source_class->prototype()->IsJSObject());
|
||||
Handle<JSObject> source(JSObject::cast(source_class->prototype()), isolate);
|
||||
|
||||
Handle<FixedArray> keys;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, keys,
|
||||
KeyAccumulator::GetKeys(source, KeyCollectionMode::kOwnOnly,
|
||||
ALL_PROPERTIES,
|
||||
GetKeysConversion::kConvertToString));
|
||||
|
||||
for (int i = 0; i < keys->length(); ++i) {
|
||||
Handle<Name> key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate));
|
||||
if (*key == isolate->heap()->constructor_string()) continue;
|
||||
|
||||
PropertyDescriptor descriptor;
|
||||
Maybe<bool> did_get_descriptor =
|
||||
JSReceiver::GetOwnPropertyDescriptor(isolate, source, key, &descriptor);
|
||||
CHECK(did_get_descriptor.FromJust());
|
||||
if (descriptor.has_value()) {
|
||||
TrySetNativeAndLength(descriptor.value(), length);
|
||||
} else {
|
||||
if (descriptor.has_get()) TrySetNative(descriptor.get());
|
||||
if (descriptor.has_set()) TrySetNative(descriptor.set());
|
||||
}
|
||||
|
||||
Maybe<bool> success = JSReceiver::DefineOwnProperty(
|
||||
isolate, target, key, &descriptor, Object::DONT_THROW);
|
||||
CHECK(success.FromJust());
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(4, args.length());
|
||||
|
@ -428,6 +428,7 @@ namespace internal {
|
||||
F(CopyDataPropertiesWithExcludedProperties, -1 /* >= 1 */, 1) \
|
||||
F(DefineGetterPropertyUnchecked, 4, 1) \
|
||||
F(DefineSetterPropertyUnchecked, 4, 1) \
|
||||
F(DefineMethodsInternal, 3, 1) \
|
||||
F(ToObject, 1, 1) \
|
||||
F(ToPrimitive, 1, 1) \
|
||||
F(ToPrimitive_Number, 1, 1) \
|
||||
|
Loading…
Reference in New Issue
Block a user