node/benchmark/misc/webidl-convert-to-int.js
Filip Skokan ef08c5016a
lib: refactor internal webidl converters
Rework lib/internal/webidl.js into a documented shared converter module
that follows the Web IDL conversion algorithms more closely.

Improvements:
- Add documented converters and helper factories for primitive values,
  dictionaries, enums, sequences, interfaces, required arguments,
  integers, `Uint8Array`, and `BufferSource`.
- Move WebCrypto onto the shared converters, while keeping compatibility
  wrappers for its existing `BufferSource` and `BigInteger` behavior.
- Use shared converters from Blob, Performance, Web Locks, and
  structured clone option handling.
- Add benchmarks for `ConvertToInt` and WebCrypto Web IDL converter hot
  paths.
- Add focused tests for core converters, WebCrypto converters, integer
  conversion, and buffer source behavior.

Fixes:
- Make the shared `BufferSource` and `Uint8Array` converters reject
  resizable `ArrayBuffer` and growable `SharedArrayBuffer` backing
  stores unless explicitly allowed. WebCrypto preserves its legacy
  resizable backing-store behavior through compatibility wrappers until
  a semver-major follow-up can opt in to the stricter behavior.
- Use Web IDL `ToNumber` and `ToString` behavior for BigInt, Symbol, and
  object primitive conversion.
- Use exact BigInt modulo for 64-bit `ConvertToInt` wrapping and
  document the final Number approximation behavior.
- Normalize mathematical modulo results to `+0` where Web IDL requires
  it.
- Process inherited dictionaries in least-derived to most-derived order,
  sorting members only within each dictionary level.
- Use `IteratorComplete` truthiness for sequence conversion.
- Cover detached buffers, resizable-backed views, growable-backed views,
  cross-realm buffer sources, mutation-after-call behavior, inherited
  dictionary member order, and sequence iterator completion behavior.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62979
Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-05-05 16:21:27 +02:00

82 lines
1.9 KiB
JavaScript

'use strict';
const assert = require('assert');
const common = require('../common.js');
const bench = common.createBenchmark(main, {
converter: [
'byte',
'octet',
'unsigned short',
'unsigned long',
'long long',
],
input: [
'integer',
'fractional',
'wrap',
'clamp',
'enforce-range',
'object',
],
n: [1e6],
}, { flags: ['--expose-internals'] });
function getConverter(converter) {
switch (converter) {
case 'byte':
return { bitLength: 8, signedness: 'signed' };
case 'octet':
return { bitLength: 8 };
case 'unsigned short':
return { bitLength: 16 };
case 'unsigned long':
return { bitLength: 32 };
case 'long long':
return { bitLength: 64, signedness: 'signed' };
default:
throw new Error(`Unsupported converter: ${converter}`);
}
}
function getInput(input) {
switch (input) {
case 'integer':
return { value: 7 };
case 'fractional':
return { value: 7.9 };
case 'wrap':
return { value: 2 ** 63 + 2 ** 11 };
case 'clamp':
return { value: 300.8, options: { clamp: true } };
case 'enforce-range':
return { value: 7.9, options: { enforceRange: true } };
case 'object':
return {
value: {
valueOf() { return 7; },
},
};
default:
throw new Error(`Unsupported input: ${input}`);
}
}
function main({ n, converter, input }) {
const { convertToInt } = require('internal/webidl');
const { bitLength, signedness } = getConverter(converter);
const { value, options } = getInput(input);
let noDead;
bench.start();
if (options === undefined) {
for (let i = 0; i < n; i++)
noDead = convertToInt(value, bitLength, signedness);
} else {
for (let i = 0; i < n; i++)
noDead = convertToInt(value, bitLength, signedness, options);
}
bench.end(n);
assert.strictEqual(typeof noDead, 'number');
}