Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 952cf0d

Browse filesBrowse files
authored
lib: reduce overhead of validateObject
PR-URL: #49928 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 61411bb commit 952cf0d
Copy full SHA for 952cf0d

File tree

Expand file treeCollapse file tree

12 files changed

+170
-74
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

12 files changed

+170
-74
lines changed
Open diff view settings
Collapse file
+75Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
6+
const bench = common.createBenchmark(main, {
7+
n: [1e5],
8+
objectToTest: [
9+
'object',
10+
'null',
11+
'array',
12+
'function',
13+
],
14+
}, {
15+
flags: ['--expose-internals'],
16+
});
17+
18+
function getObjectToTest(objectToTest) {
19+
switch (objectToTest) {
20+
case 'object':
21+
return { foo: 'bar' };
22+
case 'null':
23+
return null;
24+
case 'array':
25+
return ['foo', 'bar'];
26+
case 'function':
27+
return () => 'foo';
28+
default:
29+
throw new Error(`Value ${objectToTest} is not a valid objectToTest.`);
30+
}
31+
}
32+
33+
function getOptions(objectToTest) {
34+
const {
35+
kValidateObjectAllowNullable,
36+
kValidateObjectAllowArray,
37+
kValidateObjectAllowFunction,
38+
} = require('internal/validators');
39+
40+
switch (objectToTest) {
41+
case 'object':
42+
return 0;
43+
case 'null':
44+
return kValidateObjectAllowNullable;
45+
case 'array':
46+
return kValidateObjectAllowArray;
47+
case 'function':
48+
return kValidateObjectAllowFunction;
49+
default:
50+
throw new Error(`Value ${objectToTest} is not a valid objectToTest.`);
51+
}
52+
}
53+
54+
let _validateResult;
55+
56+
function main({ n, objectToTest }) {
57+
const {
58+
validateObject,
59+
} = require('internal/validators');
60+
61+
const value = getObjectToTest(objectToTest);
62+
const options = getOptions(objectToTest);
63+
64+
bench.start();
65+
for (let i = 0; i < n; ++i) {
66+
try {
67+
_validateResult = validateObject(value, 'Object', options);
68+
} catch {
69+
_validateResult = undefined;
70+
}
71+
}
72+
bench.end(n);
73+
74+
assert.ok(!_validateResult);
75+
}
Collapse file

‎lib/fs.js‎

Copy file name to clipboardExpand all lines: lib/fs.js
+4-3Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ const {
140140
validateInteger,
141141
validateObject,
142142
validateString,
143+
kValidateObjectAllowNullable,
143144
} = require('internal/validators');
144145

145146
let truncateWarn = true;
@@ -624,7 +625,7 @@ function read(fd, buffer, offsetOrOptions, length, position, callback) {
624625
if (arguments.length <= 4) {
625626
if (arguments.length === 4) {
626627
// This is fs.read(fd, buffer, options, callback)
627-
validateObject(offsetOrOptions, 'options', { nullable: true });
628+
validateObject(offsetOrOptions, 'options', kValidateObjectAllowNullable);
628629
callback = length;
629630
params = offsetOrOptions;
630631
} else if (arguments.length === 3) {
@@ -642,7 +643,7 @@ function read(fd, buffer, offsetOrOptions, length, position, callback) {
642643
}
643644

644645
if (params !== undefined) {
645-
validateObject(params, 'options', { nullable: true });
646+
validateObject(params, 'options', kValidateObjectAllowNullable);
646647
}
647648
({
648649
offset = 0,
@@ -715,7 +716,7 @@ function readSync(fd, buffer, offsetOrOptions, length, position) {
715716
let offset = offsetOrOptions;
716717
if (arguments.length <= 3 || typeof offsetOrOptions === 'object') {
717718
if (offsetOrOptions !== undefined) {
718-
validateObject(offsetOrOptions, 'options', { nullable: true });
719+
validateObject(offsetOrOptions, 'options', kValidateObjectAllowNullable);
719720
}
720721

721722
({
Collapse file

‎lib/internal/abort_controller.js‎

Copy file name to clipboardExpand all lines: lib/internal/abort_controller.js
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ const {
4646
validateAbortSignalArray,
4747
validateObject,
4848
validateUint32,
49+
kValidateObjectAllowArray,
50+
kValidateObjectAllowFunction,
4951
} = require('internal/validators');
5052

5153
const {
@@ -436,7 +438,7 @@ async function aborted(signal, resource) {
436438
throw new ERR_INVALID_ARG_TYPE('signal', 'AbortSignal', signal);
437439
}
438440
validateAbortSignal(signal, 'signal');
439-
validateObject(resource, 'resource', { nullable: false, allowFunction: true, allowArray: true });
441+
validateObject(resource, 'resource', kValidateObjectAllowArray | kValidateObjectAllowFunction);
440442
if (signal.aborted)
441443
return PromiseResolve();
442444
const abortPromise = createDeferredPromise();
Collapse file

‎lib/internal/encoding.js‎

Copy file name to clipboardExpand all lines: lib/internal/encoding.js
+11-20Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ const {
4747
const {
4848
validateString,
4949
validateObject,
50+
kValidateObjectAllowNullable,
51+
kValidateObjectAllowArray,
52+
kValidateObjectAllowFunction,
5053
} = require('internal/validators');
5154
const binding = internalBinding('encoding_binding');
5255
const {
@@ -390,6 +393,10 @@ const TextDecoder =
390393
makeTextDecoderICU() :
391394
makeTextDecoderJS();
392395

396+
const kValidateObjectAllowObjectsAndNull = kValidateObjectAllowNullable |
397+
kValidateObjectAllowArray |
398+
kValidateObjectAllowFunction;
399+
393400
function makeTextDecoderICU() {
394401
const {
395402
decode: _decode,
@@ -399,11 +406,7 @@ function makeTextDecoderICU() {
399406
class TextDecoder {
400407
constructor(encoding = 'utf-8', options = kEmptyObject) {
401408
encoding = `${encoding}`;
402-
validateObject(options, 'options', {
403-
nullable: true,
404-
allowArray: true,
405-
allowFunction: true,
406-
});
409+
validateObject(options, 'options', kValidateObjectAllowObjectsAndNull);
407410

408411
const enc = getEncodingFromLabel(encoding);
409412
if (enc === undefined)
@@ -448,11 +451,7 @@ function makeTextDecoderICU() {
448451

449452
this.#prepareConverter();
450453

451-
validateObject(options, 'options', {
452-
nullable: true,
453-
allowArray: true,
454-
allowFunction: true,
455-
});
454+
validateObject(options, 'options', kValidateObjectAllowObjectsAndNull);
456455

457456
let flags = 0;
458457
if (options !== null)
@@ -482,11 +481,7 @@ function makeTextDecoderJS() {
482481
class TextDecoder {
483482
constructor(encoding = 'utf-8', options = kEmptyObject) {
484483
encoding = `${encoding}`;
485-
validateObject(options, 'options', {
486-
nullable: true,
487-
allowArray: true,
488-
allowFunction: true,
489-
});
484+
validateObject(options, 'options', kValidateObjectAllowObjectsAndNull);
490485

491486
const enc = getEncodingFromLabel(encoding);
492487
if (enc === undefined || !hasConverter(enc))
@@ -528,11 +523,7 @@ function makeTextDecoderJS() {
528523
['ArrayBuffer', 'ArrayBufferView'],
529524
input);
530525
}
531-
validateObject(options, 'options', {
532-
nullable: true,
533-
allowArray: true,
534-
allowFunction: true,
535-
});
526+
validateObject(options, 'options', kValidateObjectAllowObjectsAndNull);
536527

537528
if (this[kFlags] & CONVERTER_FLAGS_FLUSH) {
538529
this[kBOMSeen] = false;
Collapse file

‎lib/internal/event_target.js‎

Copy file name to clipboardExpand all lines: lib/internal/event_target.js
+9-4Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ const {
3030
ERR_INVALID_THIS,
3131
},
3232
} = require('internal/errors');
33-
const { validateAbortSignal, validateObject, validateString, validateInternalField } = require('internal/validators');
33+
const {
34+
validateAbortSignal,
35+
validateObject,
36+
validateString,
37+
validateInternalField,
38+
kValidateObjectAllowArray,
39+
kValidateObjectAllowFunction,
40+
} = require('internal/validators');
3441

3542
const {
3643
customInspectSymbol,
@@ -1037,9 +1044,7 @@ function validateEventListenerOptions(options) {
10371044

10381045
if (options === null)
10391046
return kEmptyObject;
1040-
validateObject(options, 'options', {
1041-
allowArray: true, allowFunction: true,
1042-
});
1047+
validateObject(options, 'options', kValidateObjectAllowArray | kValidateObjectAllowFunction);
10431048
return {
10441049
once: Boolean(options.once),
10451050
capture: Boolean(options.capture),
Collapse file

‎lib/internal/fs/promises.js‎

Copy file name to clipboardExpand all lines: lib/internal/fs/promises.js
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ const {
8282
validateInteger,
8383
validateObject,
8484
validateString,
85+
kValidateObjectAllowNullable,
8586
} = require('internal/validators');
8687
const pathModule = require('path');
8788
const {
@@ -597,7 +598,7 @@ async function read(handle, bufferOrParams, offset, length, position) {
597598
if (!isArrayBufferView(buffer)) {
598599
// This is fh.read(params)
599600
if (bufferOrParams !== undefined) {
600-
validateObject(bufferOrParams, 'options', { nullable: true });
601+
validateObject(bufferOrParams, 'options', kValidateObjectAllowNullable);
601602
}
602603
({
603604
buffer = Buffer.alloc(16384),
Collapse file

‎lib/internal/util/inspect.js‎

Copy file name to clipboardExpand all lines: lib/internal/util/inspect.js
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ const { BuiltinModule } = require('internal/bootstrap/realm');
154154
const {
155155
validateObject,
156156
validateString,
157+
kValidateObjectAllowArray,
157158
} = require('internal/validators');
158159

159160
let hexSlice;
@@ -2155,7 +2156,7 @@ function format(...args) {
21552156
}
21562157

21572158
function formatWithOptions(inspectOptions, ...args) {
2158-
validateObject(inspectOptions, 'inspectOptions', { allowArray: true });
2159+
validateObject(inspectOptions, 'inspectOptions', kValidateObjectAllowArray);
21592160
return formatWithOptionsInternal(inspectOptions, args);
21602161
}
21612162

Collapse file

‎lib/internal/validators.js‎

Copy file name to clipboardExpand all lines: lib/internal/validators.js
+38-27Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ function validateNumber(value, name, min = undefined, max) {
177177
throw new ERR_INVALID_ARG_TYPE(name, 'number', value);
178178

179179
if ((min != null && value < min) || (max != null && value > max) ||
180-
((min != null || max != null) && NumberIsNaN(value))) {
180+
((min != null || max != null) && NumberIsNaN(value))) {
181181
throw new ERR_OUT_OF_RANGE(
182182
name,
183183
`${min != null ? `>= ${min}` : ''}${min != null && max != null ? ' && ' : ''}${max != null ? `<= ${max}` : ''}`,
@@ -218,41 +218,48 @@ function validateBoolean(value, name) {
218218
throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value);
219219
}
220220

221-
/**
222-
* @param {any} options
223-
* @param {string} key
224-
* @param {boolean} defaultValue
225-
* @returns {boolean}
226-
*/
227-
function getOwnPropertyValueOrDefault(options, key, defaultValue) {
228-
return options == null || !ObjectPrototypeHasOwnProperty(options, key) ?
229-
defaultValue :
230-
options[key];
231-
}
221+
const kValidateObjectNone = 0;
222+
const kValidateObjectAllowNullable = 1 << 0;
223+
const kValidateObjectAllowArray = 1 << 1;
224+
const kValidateObjectAllowFunction = 1 << 2;
232225

233226
/**
234227
* @callback validateObject
235228
* @param {*} value
236229
* @param {string} name
237-
* @param {{
238-
* allowArray?: boolean,
239-
* allowFunction?: boolean,
240-
* nullable?: boolean
241-
* }} [options]
230+
* @param {number} [options]
242231
*/
243232

244233
/** @type {validateObject} */
245234
const validateObject = hideStackFrames(
246-
(value, name, options = null) => {
247-
const allowArray = getOwnPropertyValueOrDefault(options, 'allowArray', false);
248-
const allowFunction = getOwnPropertyValueOrDefault(options, 'allowFunction', false);
249-
const nullable = getOwnPropertyValueOrDefault(options, 'nullable', false);
250-
if ((!nullable && value === null) ||
251-
(!allowArray && ArrayIsArray(value)) ||
252-
(typeof value !== 'object' && (
253-
!allowFunction || typeof value !== 'function'
254-
))) {
255-
throw new ERR_INVALID_ARG_TYPE(name, 'Object', value);
235+
(value, name, options = kValidateObjectNone) => {
236+
if (options === kValidateObjectNone) {
237+
if (value === null || ArrayIsArray(value)) {
238+
throw new ERR_INVALID_ARG_TYPE(name, 'Object', value);
239+
}
240+
241+
if (typeof value !== 'object') {
242+
throw new ERR_INVALID_ARG_TYPE(name, 'Object', value);
243+
}
244+
} else {
245+
const throwOnNullable = (kValidateObjectAllowNullable & options) === 0;
246+
247+
if (throwOnNullable && value === null) {
248+
throw new ERR_INVALID_ARG_TYPE(name, 'Object', value);
249+
}
250+
251+
const throwOnArray = (kValidateObjectAllowArray & options) === 0;
252+
253+
if (throwOnArray && ArrayIsArray(value)) {
254+
throw new ERR_INVALID_ARG_TYPE(name, 'Object', value);
255+
}
256+
257+
const throwOnFunction = (kValidateObjectAllowFunction & options) === 0;
258+
const typeofValue = typeof value;
259+
260+
if (typeofValue !== 'object' && (throwOnFunction || typeofValue !== 'function')) {
261+
throw new ERR_INVALID_ARG_TYPE(name, 'Object', value);
262+
}
256263
}
257264
});
258265

@@ -564,6 +571,10 @@ module.exports = {
564571
validateInteger,
565572
validateNumber,
566573
validateObject,
574+
kValidateObjectNone,
575+
kValidateObjectAllowNullable,
576+
kValidateObjectAllowArray,
577+
kValidateObjectAllowFunction,
567578
validateOneOf,
568579
validatePlainFunction,
569580
validatePort,
Collapse file

‎lib/internal/vm.js‎

Copy file name to clipboardExpand all lines: lib/internal/vm.js
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ const {
1717
validateString,
1818
validateStringArray,
1919
validateUint32,
20+
kValidateObjectAllowArray,
21+
kValidateObjectAllowNullable,
2022
} = require('internal/validators');
2123
const {
2224
ERR_INVALID_ARG_TYPE,
2325
} = require('internal/errors').codes;
2426

2527
function isContext(object) {
26-
validateObject(object, 'object', { __proto__: null, allowArray: true });
28+
validateObject(object, 'object', kValidateObjectAllowArray);
2729

2830
return _isContext(object);
2931
}
@@ -67,7 +69,7 @@ function internalCompileFunction(code, params, options) {
6769
validateArray(contextExtensions, 'options.contextExtensions');
6870
ArrayPrototypeForEach(contextExtensions, (extension, i) => {
6971
const name = `options.contextExtensions[${i}]`;
70-
validateObject(extension, name, { __proto__: null, nullable: true });
72+
validateObject(extension, name, kValidateObjectAllowNullable);
7173
});
7274

7375
const result = compileFunction(

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.