[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:
Igor Sheludko 2017-06-26 17:28:05 +02:00 committed by Commit Bot
parent f9e0322ae8
commit e7bd43c32d
5 changed files with 155 additions and 86 deletions

View File

@ -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;
});
})

View File

@ -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);

View File

@ -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();
}

View File

@ -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());

View File

@ -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) \