GeezerVison is showing github.com — perf_hooks: convert maxSize to IDL value in setResourceTimingBufferSize · nodejs/node@7cdf745
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/perf/performance.js +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -44,6 +44,7 @@ const timerify = require('internal/perf/timerify'); | 44 | 44 | const { customInspectSymbol: kInspect, kEnumerableProperty, kEmptyObject } = require('internal/util'); | 45 | 45 | const { inspect } = require('util'); | 46 | 46 | const { validateInternalField } = require('internal/validators'); | | 47 | +const { convertToInt } = require('internal/webidl'); | 47 | 48 |
| 48 | 49 | const { | 49 | 50 | getTimeOriginTimestamp | @@ -144,6 +145,8 @@ class Performance extends EventTarget { | 144 | 145 | if (arguments.length === 0) { | 145 | 146 | throw new ERR_MISSING_ARGS('maxSize'); | 146 | 147 | } | | 148 | + // unsigned long | | 149 | + maxSize = convertToInt('maxSize', maxSize, 32); | 147 | 150 | return setResourceTimingBufferSize(maxSize); | 148 | 151 | } | 149 | 152 |
| |
Collapse file Copy file name to clipboard +163Lines changed: 163 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +'use strict'; | | 2 | + | | 3 | +const { | | 4 | + MathAbs, | | 5 | + MathMax, | | 6 | + MathMin, | | 7 | + MathPow, | | 8 | + MathSign, | | 9 | + MathTrunc, | | 10 | + NumberIsNaN, | | 11 | + NumberMAX_SAFE_INTEGER, | | 12 | + NumberMIN_SAFE_INTEGER, | | 13 | +} = primordials; | | 14 | + | | 15 | +const { | | 16 | + codes: { | | 17 | + ERR_INVALID_ARG_VALUE, | | 18 | + }, | | 19 | +} = require('internal/errors'); | | 20 | +const { kEmptyObject } = require('internal/util'); | | 21 | + | | 22 | +// https://webidl.spec.whatwg.org/#abstract-opdef-integerpart | | 23 | +const integerPart = MathTrunc; | | 24 | + | | 25 | +/* eslint-disable node-core/non-ascii-character */ | | 26 | +// Round x to the nearest integer, choosing the even integer if it lies halfway | | 27 | +// between two, and choosing +0 rather than -0. | | 28 | +// This is different from Math.round, which rounds to the next integer in the | | 29 | +// direction of +∞ when the fraction portion is exactly 0.5. | | 30 | +/* eslint-enable node-core/non-ascii-character */ | | 31 | +function evenRound(x) { | | 32 | + // Convert -0 to +0. | | 33 | + const i = integerPart(x) + 0; | | 34 | + const reminder = MathAbs(x % 1); | | 35 | + const sign = MathSign(i); | | 36 | + if (reminder === 0.5) { | | 37 | + return i % 2 === 0 ? i : i + sign; | | 38 | + } | | 39 | + const r = reminder < 0.5 ? i : i + sign; | | 40 | + // Convert -0 to +0. | | 41 | + if (r === 0) { | | 42 | + return 0; | | 43 | + } | | 44 | + return r; | | 45 | +} | | 46 | + | | 47 | +function pow2(exponent) { | | 48 | + // << operates on 32 bit signed integers. | | 49 | + if (exponent < 31) { | | 50 | + return 1 << exponent; | | 51 | + } | | 52 | + if (exponent === 31) { | | 53 | + return 0x8000_0000; | | 54 | + } | | 55 | + if (exponent === 32) { | | 56 | + return 0x1_0000_0000; | | 57 | + } | | 58 | + return MathPow(2, exponent); | | 59 | +} | | 60 | + | | 61 | +// https://tc39.es/ecma262/#eqn-modulo | | 62 | +// The notation “x modulo y” computes a value k of the same sign as y. | | 63 | +function modulo(x, y) { | | 64 | + const r = x % y; | | 65 | + // Convert -0 to +0. | | 66 | + if (r === 0) { | | 67 | + return 0; | | 68 | + } | | 69 | + return r; | | 70 | +} | | 71 | + | | 72 | +// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint | | 73 | +function convertToInt(name, value, bitLength, options = kEmptyObject) { | | 74 | + const { signed = false, enforceRange = false, clamp = false } = options; | | 75 | + | | 76 | + let upperBound; | | 77 | + let lowerBound; | | 78 | + // 1. If bitLength is 64, then: | | 79 | + if (bitLength === 64) { | | 80 | + // 1.1. Let upperBound be 2^53 − 1. | | 81 | + upperBound = NumberMAX_SAFE_INTEGER; | | 82 | + // 1.2. If signedness is "unsigned", then let lowerBound be 0. | | 83 | + // 1.3. Otherwise let lowerBound be −2^53 + 1. | | 84 | + lowerBound = !signed ? 0 : NumberMIN_SAFE_INTEGER; | | 85 | + } else if (!signed) { | | 86 | + // 2. Otherwise, if signedness is "unsigned", then: | | 87 | + // 2.1. Let lowerBound be 0. | | 88 | + // 2.2. Let upperBound be 2^bitLength − 1. | | 89 | + lowerBound = 0; | | 90 | + upperBound = pow2(bitLength) - 1; | | 91 | + } else { | | 92 | + // 3. Otherwise: | | 93 | + // 3.1. Let lowerBound be -2^(bitLength − 1). | | 94 | + // 3.2. Let upperBound be 2^(bitLength − 1) − 1. | | 95 | + lowerBound = -pow2(bitLength - 1); | | 96 | + upperBound = pow2(bitLength - 1) - 1; | | 97 | + } | | 98 | + | | 99 | + // 4. Let x be ? ToNumber(V). | | 100 | + let x = +value; | | 101 | + // 5. If x is −0, then set x to +0. | | 102 | + if (x === 0) { | | 103 | + x = 0; | | 104 | + } | | 105 | + | | 106 | + // 6. If the conversion is to an IDL type associated with the [EnforceRange] | | 107 | + // extended attribute, then: | | 108 | + if (enforceRange) { | | 109 | + // 6.1. If x is NaN, +∞, or −∞, then throw a TypeError. | | 110 | + if (NumberIsNaN(x) || x === Infinity || x === -Infinity) { | | 111 | + throw new ERR_INVALID_ARG_VALUE(name, x); | | 112 | + } | | 113 | + // 6.2. Set x to IntegerPart(x). | | 114 | + x = integerPart(x); | | 115 | + | | 116 | + // 6.3. If x < lowerBound or x > upperBound, then throw a TypeError. | | 117 | + if (x < lowerBound || x > upperBound) { | | 118 | + throw new ERR_INVALID_ARG_VALUE(name, x); | | 119 | + } | | 120 | + | | 121 | + // 6.4. Return x. | | 122 | + return x; | | 123 | + } | | 124 | + | | 125 | + // 7. If x is not NaN and the conversion is to an IDL type associated with | | 126 | + // the [Clamp] extended attribute, then: | | 127 | + if (clamp && !NumberIsNaN(x)) { | | 128 | + // 7.1. Set x to min(max(x, lowerBound), upperBound). | | 129 | + x = MathMin(MathMax(x, lowerBound), upperBound); | | 130 | + | | 131 | + // 7.2. Round x to the nearest integer, choosing the even integer if it | | 132 | + // lies halfway between two, and choosing +0 rather than −0. | | 133 | + x = evenRound(x); | | 134 | + | | 135 | + // 7.3. Return x. | | 136 | + return x; | | 137 | + } | | 138 | + | | 139 | + // 8. If x is NaN, +0, +∞, or −∞, then return +0. | | 140 | + if (NumberIsNaN(x) || x === 0 || x === Infinity || x === -Infinity) { | | 141 | + return 0; | | 142 | + } | | 143 | + | | 144 | + // 9. Set x to IntegerPart(x). | | 145 | + x = integerPart(x); | | 146 | + | | 147 | + // 10. Set x to x modulo 2^bitLength. | | 148 | + x = modulo(x, pow2(bitLength)); | | 149 | + | | 150 | + // 11. If signedness is "signed" and x ≥ 2^(bitLength − 1), then return x − | | 151 | + // 2^bitLength. | | 152 | + if (signed && x >= pow2(bitLength - 1)) { | | 153 | + return x - pow2(bitLength); | | 154 | + } | | 155 | + | | 156 | + // 12. Otherwise, return x. | | 157 | + return x; | | 158 | +} | | 159 | + | | 160 | +module.exports = { | | 161 | + convertToInt, | | 162 | + evenRound, | | 163 | +}; |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-bootstrap-modules.js +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -149,6 +149,7 @@ const expectedModules = new Set([ | 149 | 149 | 'NativeModule internal/validators', | 150 | 150 | 'NativeModule internal/vm/module', | 151 | 151 | 'NativeModule internal/wasm_web_api', | | 152 | + 'NativeModule internal/webidl', | 152 | 153 | 'NativeModule internal/webstreams/adapters', | 153 | 154 | 'NativeModule internal/webstreams/compression', | 154 | 155 | 'NativeModule internal/webstreams/encoding', | |
Collapse file Copy file name to clipboard +58Lines changed: 58 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +// Flags: --expose-internals | | 2 | +'use strict'; | | 3 | + | | 4 | +require('../common'); | | 5 | +const assert = require('assert'); | | 6 | +const { convertToInt, evenRound } = require('internal/webidl'); | | 7 | + | | 8 | +assert.strictEqual(evenRound(-0.5), 0); | | 9 | +assert.strictEqual(evenRound(0.5), 0); | | 10 | +assert.strictEqual(evenRound(-1.5), -2); | | 11 | +assert.strictEqual(evenRound(1.5), 2); | | 12 | +assert.strictEqual(evenRound(3.4), 3); | | 13 | +assert.strictEqual(evenRound(4.6), 5); | | 14 | +assert.strictEqual(evenRound(5), 5); | | 15 | +assert.strictEqual(evenRound(6), 6); | | 16 | + | | 17 | +// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint | | 18 | +assert.strictEqual(convertToInt('x', 0, 64), 0); | | 19 | +assert.strictEqual(convertToInt('x', 1, 64), 1); | | 20 | +assert.strictEqual(convertToInt('x', -0.5, 64), 0); | | 21 | +assert.strictEqual(convertToInt('x', -0.5, 64, { signed: true }), 0); | | 22 | +assert.strictEqual(convertToInt('x', -1.5, 64, { signed: true }), -1); | | 23 | + | | 24 | +// EnforceRange | | 25 | +const OutOfRangeValues = [ NaN, Infinity, -Infinity, 2 ** 53, -(2 ** 53) ]; | | 26 | +for (const value of OutOfRangeValues) { | | 27 | + assert.throws(() => convertToInt('x', value, 64, { enforceRange: true }), { | | 28 | + name: 'TypeError', | | 29 | + code: 'ERR_INVALID_ARG_VALUE', | | 30 | + }); | | 31 | +} | | 32 | + | | 33 | +// Out of range: clamp | | 34 | +assert.strictEqual(convertToInt('x', NaN, 64, { clamp: true }), 0); | | 35 | +assert.strictEqual(convertToInt('x', Infinity, 64, { clamp: true }), Number.MAX_SAFE_INTEGER); | | 36 | +assert.strictEqual(convertToInt('x', -Infinity, 64, { clamp: true }), 0); | | 37 | +assert.strictEqual(convertToInt('x', -Infinity, 64, { signed: true, clamp: true }), Number.MIN_SAFE_INTEGER); | | 38 | +assert.strictEqual(convertToInt('x', 0x1_0000_0000, 32, { clamp: true }), 0xFFFF_FFFF); | | 39 | +assert.strictEqual(convertToInt('x', 0xFFFF_FFFF, 32, { clamp: true }), 0xFFFF_FFFF); | | 40 | +assert.strictEqual(convertToInt('x', 0x8000_0000, 32, { clamp: true, signed: true }), 0x7FFF_FFFF); | | 41 | +assert.strictEqual(convertToInt('x', 0xFFFF_FFFF, 32, { clamp: true, signed: true }), 0x7FFF_FFFF); | | 42 | +assert.strictEqual(convertToInt('x', 0.5, 64, { clamp: true }), 0); | | 43 | +assert.strictEqual(convertToInt('x', 1.5, 64, { clamp: true }), 2); | | 44 | +assert.strictEqual(convertToInt('x', -0.5, 64, { clamp: true }), 0); | | 45 | +assert.strictEqual(convertToInt('x', -0.5, 64, { signed: true, clamp: true }), 0); | | 46 | +assert.strictEqual(convertToInt('x', -1.5, 64, { signed: true, clamp: true }), -2); | | 47 | + | | 48 | +// Out of range, step 8. | | 49 | +assert.strictEqual(convertToInt('x', NaN, 64), 0); | | 50 | +assert.strictEqual(convertToInt('x', Infinity, 64), 0); | | 51 | +assert.strictEqual(convertToInt('x', -Infinity, 64), 0); | | 52 | +assert.strictEqual(convertToInt('x', 0x1_0000_0000, 32), 0); | | 53 | +assert.strictEqual(convertToInt('x', 0x1_0000_0001, 32), 1); | | 54 | +assert.strictEqual(convertToInt('x', 0xFFFF_FFFF, 32), 0xFFFF_FFFF); | | 55 | + | | 56 | +// Out of range, step 11. | | 57 | +assert.strictEqual(convertToInt('x', 0x8000_0000, 32, { signed: true }), -0x8000_0000); | | 58 | +assert.strictEqual(convertToInt('x', 0xFFF_FFFF, 32, { signed: true }), 0xFFF_FFFF); |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-performance-resourcetimingbuffersize.js +11Lines changed: 11 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -30,6 +30,17 @@ const initiatorType = ''; | 30 | 30 | const cacheMode = ''; | 31 | 31 |
| 32 | 32 | async function main() { | | 33 | + // Invalid buffer size values are converted to 0. | | 34 | + const invalidValues = [ null, undefined, true, false, -1, 0.5, Infinity, NaN, '', 'foo', {}, [], () => {} ]; | | 35 | + for (const value of invalidValues) { | | 36 | + performance.setResourceTimingBufferSize(value); | | 37 | + performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, globalThis, cacheMode); | | 38 | + assert.strictEqual(performance.getEntriesByType('resource').length, 0); | | 39 | + performance.clearResourceTimings(); | | 40 | + } | | 41 | + // Wait for the buffer full event to be cleared. | | 42 | + await waitBufferFullEvent(); | | 43 | + | 33 | 44 | performance.setResourceTimingBufferSize(1); | 34 | 45 | performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, globalThis, cacheMode); | 35 | 46 | // Trigger a resourcetimingbufferfull event. | |
|