Skip to content

Commit

Permalink
lib: add bound apply variants of varargs primordials
Browse files Browse the repository at this point in the history
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>

PR-URL: #37005
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
  • Loading branch information
ExE-Boss authored and targos committed Feb 2, 2021
1 parent 67b58f6 commit ed58065
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 10 deletions.
64 changes: 56 additions & 8 deletions lib/internal/per_context/primordials.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,36 @@ const {
// `uncurryThis` is equivalent to `func => Function.prototype.call.bind(func)`.
// It is using `bind.bind(call)` to avoid using `Function.prototype.bind`
// and `Function.prototype.call` after it may have been mutated by users.
const { bind, call } = Function.prototype;
const { apply, bind, call } = Function.prototype;
const uncurryThis = bind.bind(call);
primordials.uncurryThis = uncurryThis;

// `applyBind` is equivalent to `func => Function.prototype.apply.bind(func)`.
// It is using `bind.bind(apply)` to avoid using `Function.prototype.bind`
// and `Function.prototype.apply` after it may have been mutated by users.
const applyBind = bind.bind(apply);
primordials.applyBind = applyBind;

// Methods that accept a variable number of arguments, and thus it's useful to
// also create `${prefix}${key}Apply`, which uses `Function.prototype.apply`,
// instead of `Function.prototype.call`, and thus doesn't require iterator
// destructuring.
const varargsMethods = [
// 'ArrayPrototypeConcat' is omitted, because it performs the spread
// on its own for arrays and array-likes with a truthy
// @@isConcatSpreadable symbol property.
'ArrayOf',
'ArrayPrototypePush',
'ArrayPrototypeUnshift',
// 'FunctionPrototypeCall' is omitted, since there's 'ReflectApply'
// and 'FunctionPrototypeApply'.
'MathHypot',
'MathMax',
'MathMin',
'StringPrototypeConcat',
'TypedArrayOf',
];

function getNewKey(key) {
return typeof key === 'symbol' ?
`Symbol${key.description[7].toUpperCase()}${key.description.slice(8)}` :
Expand All @@ -51,7 +77,13 @@ function copyPropsRenamed(src, dest, prefix) {
if ('get' in desc) {
copyAccessor(dest, prefix, newKey, desc);
} else {
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
const name = `${prefix}${newKey}`;
ReflectDefineProperty(dest, name, desc);
if (varargsMethods.includes(name)) {
ReflectDefineProperty(dest, `${name}Apply`, {
value: applyBind(desc.value, src),
});
}
}
}
}
Expand All @@ -63,10 +95,18 @@ function copyPropsRenamedBound(src, dest, prefix) {
if ('get' in desc) {
copyAccessor(dest, prefix, newKey, desc);
} else {
if (typeof desc.value === 'function') {
desc.value = desc.value.bind(src);
const { value } = desc;
if (typeof value === 'function') {
desc.value = value.bind(src);
}

const name = `${prefix}${newKey}`;
ReflectDefineProperty(dest, name, desc);
if (varargsMethods.includes(name)) {
ReflectDefineProperty(dest, `${name}Apply`, {
value: applyBind(value, src),
});
}
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
}
}
}
Expand All @@ -78,10 +118,18 @@ function copyPrototype(src, dest, prefix) {
if ('get' in desc) {
copyAccessor(dest, prefix, newKey, desc);
} else {
if (typeof desc.value === 'function') {
desc.value = uncurryThis(desc.value);
const { value } = desc;
if (typeof value === 'function') {
desc.value = uncurryThis(value);
}

const name = `${prefix}${newKey}`;
ReflectDefineProperty(dest, name, desc);
if (varargsMethods.includes(name)) {
ReflectDefineProperty(dest, `${name}Apply`, {
value: applyBind(value),
});
}
ReflectDefineProperty(dest, `${prefix}${newKey}`, desc);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const {
ArrayPrototypeFilter,
ArrayPrototypeForEach,
ArrayPrototypePush,
ArrayPrototypePushApply,
ArrayPrototypeSort,
ArrayPrototypeUnshift,
BigIntPrototypeValueOf,
Expand Down Expand Up @@ -665,7 +666,7 @@ function getKeys(value, showHidden) {
if (showHidden) {
keys = ObjectGetOwnPropertyNames(value);
if (symbols.length !== 0)
ArrayPrototypePush(keys, ...symbols);
ArrayPrototypePushApply(keys, symbols);
} else {
// This might throw if `value` is a Module Namespace Object from an
// unevaluated module, but we don't want to perform the actual type
Expand All @@ -681,7 +682,7 @@ function getKeys(value, showHidden) {
}
if (symbols.length !== 0) {
const filter = (key) => ObjectPrototypePropertyIsEnumerable(value, key);
ArrayPrototypePush(keys, ...ArrayPrototypeFilter(symbols, filter));
ArrayPrototypePushApply(keys, ArrayPrototypeFilter(symbols, filter));
}
}
return keys;
Expand Down
1 change: 1 addition & 0 deletions lib/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,7 @@ function complete(line, callback) {
if (!this.useGlobal) {
// When the context is not `global`, builtins are not own
// properties of it.
// `globalBuiltins` is a `SafeSet`, not an Array-like.
ArrayPrototypePush(contextOwnNames, ...globalBuiltins);
}
ArrayPrototypePush(completionGroups, contextOwnNames);
Expand Down

0 comments on commit ed58065

Please sign in to comment.