Skip to content

Commit 112cc7c

Browse files
committed
lib: use safe methods from primordials
This changes the primordials to expose built-in prototypes with their methods already uncurried. The uncurryThis function is therefore moved to the primordials. All uses of uncurryThis on built-ins are changed to import the relevant prototypes from primordials. All uses of Function.call.bind are also changed to use primordials. PR-URL: #27096 Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent 969bd1e commit 112cc7c

20 files changed

+206
-189
lines changed

lib/_http_outgoing.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
'use strict';
2323

24+
const { ObjectPrototype } = primordials;
25+
2426
const assert = require('internal/assert');
2527
const Stream = require('stream');
2628
const internalUtil = require('internal/util');
@@ -53,8 +55,6 @@ const { CRLF, debug } = common;
5355

5456
const kIsCorked = Symbol('isCorked');
5557

56-
const hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);
57-
5858
const RE_CONN_CLOSE = /(?:^|\W)close(?:$|\W)/i;
5959
const RE_TE_CHUNKED = common.chunkExpression;
6060

@@ -310,7 +310,7 @@ function _storeHeader(firstLine, headers) {
310310
}
311311
} else {
312312
for (const key in headers) {
313-
if (hasOwnProperty(headers, key)) {
313+
if (ObjectPrototype.hasOwnProperty(headers, key)) {
314314
processHeader(this, state, key, headers[key], true);
315315
}
316316
}

lib/internal/async_hooks.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const { Reflect } = primordials;
3+
const { FunctionPrototype, Reflect } = primordials;
44

55
const {
66
ERR_ASYNC_TYPE,
@@ -77,8 +77,6 @@ const { kInit, kBefore, kAfter, kDestroy, kTotals, kPromiseResolve,
7777
kCheck, kExecutionAsyncId, kAsyncIdCounter, kTriggerAsyncId,
7878
kDefaultTriggerAsyncId, kStackLength } = async_wrap.constants;
7979

80-
const FunctionBind = Function.call.bind(Function.prototype.bind);
81-
8280
// Used in AsyncHook and AsyncResource.
8381
const async_id_symbol = Symbol('asyncId');
8482
const trigger_async_id_symbol = Symbol('triggerAsyncId');
@@ -181,7 +179,7 @@ function emitHook(symbol, asyncId) {
181179
}
182180

183181
function emitHookFactory(symbol, name) {
184-
const fn = FunctionBind(emitHook, undefined, symbol);
182+
const fn = FunctionPrototype.bind(emitHook, undefined, symbol);
185183

186184
// Set the name property of the function as it looks good in the stack trace.
187185
Object.defineProperty(fn, 'name', {

lib/internal/bootstrap/loaders.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ NativeModule.prototype.compileForPublicLoader = function(needToProxify) {
225225
};
226226

227227
const getOwn = (target, property, receiver) => {
228-
return Reflect.apply(ObjectPrototype.hasOwnProperty, target, [property]) ?
228+
return ObjectPrototype.hasOwnProperty(target, property) ?
229229
Reflect.get(target, property, receiver) :
230230
undefined;
231231
};
@@ -239,8 +239,7 @@ NativeModule.prototype.proxifyExports = function() {
239239

240240
const update = (property, value) => {
241241
if (this.reflect !== undefined &&
242-
Reflect.apply(ObjectPrototype.hasOwnProperty,
243-
this.reflect.exports, [property]))
242+
ObjectPrototype.hasOwnProperty(this.reflect.exports, property))
244243
this.reflect.exports[property].set(value);
245244
};
246245

@@ -254,7 +253,7 @@ NativeModule.prototype.proxifyExports = function() {
254253
!Reflect.has(handler, 'get')) {
255254
handler.get = (target, prop, receiver) => {
256255
const value = Reflect.get(target, prop, receiver);
257-
if (Reflect.apply(ObjectPrototype.hasOwnProperty, target, [prop]))
256+
if (ObjectPrototype.hasOwnProperty(target, prop))
258257
update(prop, value);
259258
return value;
260259
};

lib/internal/bootstrap/primordials.js

+32-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@
1212
// `primordials.Object` where `primordials` is a lexical variable passed
1313
// by the native module compiler.
1414

15+
const ReflectApply = Reflect.apply;
16+
17+
// This function is borrowed from the function with the same name on V8 Extras'
18+
// `utils` object. V8 implements Reflect.apply very efficiently in conjunction
19+
// with the spread syntax, such that no additional special case is needed for
20+
// function calls w/o arguments.
21+
// Refs: https://github.com/v8/v8/blob/d6ead37d265d7215cf9c5f768f279e21bd170212/src/js/prologue.js#L152-L156
22+
function uncurryThis(func) {
23+
return (thisArg, ...args) => ReflectApply(func, thisArg, args);
24+
}
25+
26+
primordials.uncurryThis = uncurryThis;
27+
1528
function copyProps(src, dest) {
1629
for (const key of Reflect.ownKeys(src)) {
1730
if (!Reflect.getOwnPropertyDescriptor(dest, key)) {
@@ -23,6 +36,18 @@ function copyProps(src, dest) {
2336
}
2437
}
2538

39+
function copyPrototype(src, dest) {
40+
for (const key of Reflect.ownKeys(src)) {
41+
if (!Reflect.getOwnPropertyDescriptor(dest, key)) {
42+
const desc = Reflect.getOwnPropertyDescriptor(src, key);
43+
if (typeof desc.value === 'function') {
44+
desc.value = uncurryThis(desc.value);
45+
}
46+
Reflect.defineProperty(dest, key, desc);
47+
}
48+
}
49+
}
50+
2651
function makeSafe(unsafe, safe) {
2752
copyProps(unsafe.prototype, safe.prototype);
2853
copyProps(unsafe, safe);
@@ -64,17 +89,23 @@ primordials.SafePromise = makeSafe(
6489
// Create copies of intrinsic objects
6590
[
6691
'Array',
92+
'BigInt',
93+
'Boolean',
6794
'Date',
95+
'Error',
6896
'Function',
97+
'Map',
98+
'Number',
6999
'Object',
70100
'RegExp',
101+
'Set',
71102
'String',
72103
'Symbol',
73104
].forEach((name) => {
74105
const target = primordials[name] = Object.create(null);
75106
copyProps(global[name], target);
76107
const proto = primordials[name + 'Prototype'] = Object.create(null);
77-
copyProps(global[name].prototype, proto);
108+
copyPrototype(global[name].prototype, proto);
78109
});
79110

80111
Object.setPrototypeOf(primordials, null);

lib/internal/cli_table.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
'use strict';
22

3-
const { Math } = primordials;
3+
const { Math, ObjectPrototype } = primordials;
44

55
const { Buffer } = require('buffer');
66
const { removeColors } = require('internal/util');
7-
const HasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);
87

98
// The use of Unicode characters below is the only non-comment use of non-ASCII
109
// Unicode characters in Node.js built-in modules. If they are ever removed or
@@ -61,7 +60,8 @@ const table = (head, columns) => {
6160
for (var j = 0; j < longestColumn; j++) {
6261
if (rows[j] === undefined)
6362
rows[j] = [];
64-
const value = rows[j][i] = HasOwnProperty(column, j) ? column[j] : '';
63+
const value = rows[j][i] =
64+
ObjectPrototype.hasOwnProperty(column, j) ? column[j] : '';
6565
const width = columnWidths[i] || 0;
6666
const counted = countSymbols(value);
6767
columnWidths[i] = Math.max(width, counted);

lib/internal/console/constructor.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// The Console constructor is not actually used to construct the global
44
// console. It's exported for backwards compatibility.
55

6-
const { Reflect } = primordials;
6+
const { ObjectPrototype, Reflect } = primordials;
77

88
const { trace } = internalBinding('trace_events');
99
const {
@@ -36,7 +36,6 @@ const {
3636
keys: ObjectKeys,
3737
values: ObjectValues,
3838
} = Object;
39-
const hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty);
4039

4140
const {
4241
isArray: ArrayIsArray,
@@ -493,7 +492,8 @@ const consoleMethods = {
493492
for (const key of keys) {
494493
if (map[key] === undefined)
495494
map[key] = [];
496-
if ((primitive && properties) || !hasOwnProperty(item, key))
495+
if ((primitive && properties) ||
496+
!ObjectPrototype.hasOwnProperty(item, key))
497497
map[key][i] = '';
498498
else
499499
map[key][i] = _inspect(item[key]);

lib/internal/error-serdes.js

+14-23
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,17 @@
22

33
const Buffer = require('buffer').Buffer;
44
const {
5-
SafeSet,
5+
ArrayPrototype,
6+
FunctionPrototype,
67
Object,
78
ObjectPrototype,
8-
FunctionPrototype,
9-
ArrayPrototype
9+
SafeSet,
1010
} = primordials;
1111

1212
const kSerializedError = 0;
1313
const kSerializedObject = 1;
1414
const kInspectedError = 2;
1515

16-
const GetPrototypeOf = Object.getPrototypeOf;
17-
const GetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
18-
const GetOwnPropertyNames = Object.getOwnPropertyNames;
19-
const DefineProperty = Object.defineProperty;
20-
const Assign = Object.assign;
21-
const ObjectPrototypeToString =
22-
FunctionPrototype.call.bind(ObjectPrototype.toString);
23-
const ForEach = FunctionPrototype.call.bind(ArrayPrototype.forEach);
24-
const Call = FunctionPrototype.call.bind(FunctionPrototype.call);
25-
2616
const errors = {
2717
Error, TypeError, RangeError, URIError, SyntaxError, ReferenceError, EvalError
2818
};
@@ -32,17 +22,18 @@ function TryGetAllProperties(object, target = object) {
3222
const all = Object.create(null);
3323
if (object === null)
3424
return all;
35-
Assign(all, TryGetAllProperties(GetPrototypeOf(object), target));
36-
const keys = GetOwnPropertyNames(object);
37-
ForEach(keys, (key) => {
25+
Object.assign(all,
26+
TryGetAllProperties(Object.getPrototypeOf(object), target));
27+
const keys = Object.getOwnPropertyNames(object);
28+
ArrayPrototype.forEach(keys, (key) => {
3829
let descriptor;
3930
try {
40-
descriptor = GetOwnPropertyDescriptor(object, key);
31+
descriptor = Object.getOwnPropertyDescriptor(object, key);
4132
} catch { return; }
4233
const getter = descriptor.get;
4334
if (getter && key !== '__proto__') {
4435
try {
45-
descriptor.value = Call(getter, target);
36+
descriptor.value = FunctionPrototype.call(getter, target);
4637
} catch {}
4738
}
4839
if ('value' in descriptor && typeof descriptor.value !== 'function') {
@@ -59,10 +50,10 @@ function GetConstructors(object) {
5950

6051
for (var current = object;
6152
current !== null;
62-
current = GetPrototypeOf(current)) {
63-
const desc = GetOwnPropertyDescriptor(current, 'constructor');
53+
current = Object.getPrototypeOf(current)) {
54+
const desc = Object.getOwnPropertyDescriptor(current, 'constructor');
6455
if (desc && desc.value) {
65-
DefineProperty(constructors, constructors.length, {
56+
Object.defineProperty(constructors, constructors.length, {
6657
value: desc.value, enumerable: true
6758
});
6859
}
@@ -72,7 +63,7 @@ function GetConstructors(object) {
7263
}
7364

7465
function GetName(object) {
75-
const desc = GetOwnPropertyDescriptor(object, 'name');
66+
const desc = Object.getOwnPropertyDescriptor(object, 'name');
7667
return desc && desc.value;
7768
}
7869

@@ -89,7 +80,7 @@ function serializeError(error) {
8980
if (!serialize) serialize = require('v8').serialize;
9081
try {
9182
if (typeof error === 'object' &&
92-
ObjectPrototypeToString(error) === '[object Error]') {
83+
ObjectPrototype.toString(error) === '[object Error]') {
9384
const constructors = GetConstructors(error);
9485
for (var i = 0; i < constructors.length; i++) {
9586
const name = GetName(constructors[i]);

lib/internal/modules/esm/create_dynamic_module.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
'use strict';
22

3+
const { ArrayPrototype } = primordials;
4+
35
const { ModuleWrap, callbackMap } = internalBinding('module_wrap');
46
const debug = require('util').debuglog('esm');
5-
const ArrayJoin = Function.call.bind(Array.prototype.join);
6-
const ArrayMap = Function.call.bind(Array.prototype.map);
77

88
const createDynamicModule = (exports, url = '', evaluate) => {
99
debug('creating ESM facade for %s with exports: %j', url, exports);
10-
const names = ArrayMap(exports, (name) => `${name}`);
10+
const names = ArrayPrototype.map(exports, (name) => `${name}`);
1111

1212
const source = `
13-
${ArrayJoin(ArrayMap(names, (name) =>
13+
${ArrayPrototype.join(ArrayPrototype.map(names, (name) =>
1414
`let $${name};
1515
export { $${name} as ${name} };
1616
import.meta.exports.${name} = {

lib/internal/modules/esm/loader.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
const { FunctionPrototype } = primordials;
4+
35
const {
46
ERR_INVALID_RETURN_PROPERTY,
57
ERR_INVALID_RETURN_PROPERTY_VALUE,
@@ -18,8 +20,6 @@ const createDynamicModule = require(
1820
const { translators } = require('internal/modules/esm/translators');
1921
const { ModuleWrap } = internalBinding('module_wrap');
2022

21-
const FunctionBind = Function.call.bind(Function.prototype.bind);
22-
2323
const debug = require('internal/util/debuglog').debuglog('esm');
2424

2525
const {
@@ -132,9 +132,11 @@ class Loader {
132132
hook({ resolve, dynamicInstantiate }) {
133133
// Use .bind() to avoid giving access to the Loader instance when called.
134134
if (resolve !== undefined)
135-
this._resolve = FunctionBind(resolve, null);
136-
if (dynamicInstantiate !== undefined)
137-
this._dynamicInstantiate = FunctionBind(dynamicInstantiate, null);
135+
this._resolve = FunctionPrototype.bind(resolve, null);
136+
if (dynamicInstantiate !== undefined) {
137+
this._dynamicInstantiate =
138+
FunctionPrototype.bind(dynamicInstantiate, null);
139+
}
138140
}
139141

140142
async getModuleJob(specifier, parentURL) {

lib/internal/modules/esm/translators.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
'use strict';
22

3+
const {
4+
SafeMap,
5+
StringPrototype,
6+
JSON
7+
} = primordials;
8+
39
const { NativeModule } = require('internal/bootstrap/loaders');
410
const { ModuleWrap, callbackMap } = internalBinding('module_wrap');
511
const {
@@ -11,10 +17,6 @@ const internalURLModule = require('internal/url');
1117
const createDynamicModule = require(
1218
'internal/modules/esm/create_dynamic_module');
1319
const fs = require('fs');
14-
const {
15-
SafeMap,
16-
JSON
17-
} = primordials;
1820
const { fileURLToPath, URL } = require('url');
1921
const { debuglog } = require('internal/util/debuglog');
2022
const { promisify } = require('internal/util');
@@ -23,7 +25,6 @@ const {
2325
ERR_UNKNOWN_BUILTIN_MODULE
2426
} = require('internal/errors').codes;
2527
const readFileAsync = promisify(fs.readFile);
26-
const StringReplace = Function.call.bind(String.prototype.replace);
2728
const JsonParse = JSON.parse;
2829

2930
const debug = debuglog('esm');
@@ -67,7 +68,8 @@ translators.set('commonjs', async function commonjsStrategy(url, isMain) {
6768
return cached;
6869
}
6970
const module = CJSModule._cache[
70-
isWindows ? StringReplace(pathname, winSepRegEx, '\\') : pathname];
71+
isWindows ? StringPrototype.replace(pathname, winSepRegEx, '\\') : pathname
72+
];
7173
if (module && module.loaded) {
7274
const exports = module.exports;
7375
return createDynamicModule(['default'], url, (reflect) => {
@@ -110,7 +112,7 @@ translators.set('json', async function jsonStrategy(url) {
110112
debug(`Loading JSONModule ${url}`);
111113
const pathname = fileURLToPath(url);
112114
const modulePath = isWindows ?
113-
StringReplace(pathname, winSepRegEx, '\\') : pathname;
115+
StringPrototype.replace(pathname, winSepRegEx, '\\') : pathname;
114116
let module = CJSModule._cache[modulePath];
115117
if (module && module.loaded) {
116118
const exports = module.exports;

0 commit comments

Comments
 (0)