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 ef08c50

Browse filesBrowse files
panvaaduh95
authored andcommitted
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: #62979 Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 6386914 commit ef08c50
Copy full SHA for ef08c50

18 files changed

+2,813-1,063Lines changed: 2813 additions & 1063 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎benchmark/misc/webcrypto-webidl.js‎

Copy file name to clipboard
+109Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
5+
const bench = common.createBenchmark(main, {
6+
op: [
7+
'normalizeAlgorithm-string',
8+
'normalizeAlgorithm-dict',
9+
'webidl-dict',
10+
'webidl-algorithm-identifier-string',
11+
'webidl-algorithm-identifier-object',
12+
'webidl-dict-enforce-range',
13+
'webidl-dict-ensure-sha',
14+
'webidl-dict-null',
15+
],
16+
n: [1e6],
17+
}, { flags: ['--expose-internals'] });
18+
19+
function main({ n, op }) {
20+
const { normalizeAlgorithm } = require('internal/crypto/util');
21+
22+
switch (op) {
23+
case 'normalizeAlgorithm-string': {
24+
// String shortcut + null dictionary (cheapest path).
25+
bench.start();
26+
for (let i = 0; i < n; i++)
27+
normalizeAlgorithm('SHA-256', 'digest');
28+
bench.end(n);
29+
break;
30+
}
31+
case 'normalizeAlgorithm-dict': {
32+
// Object input with a dictionary type and no BufferSource members.
33+
const alg = { name: 'ECDSA', hash: 'SHA-256' };
34+
bench.start();
35+
for (let i = 0; i < n; i++)
36+
normalizeAlgorithm(alg, 'sign');
37+
bench.end(n);
38+
break;
39+
}
40+
case 'webidl-dict': {
41+
// WebIDL dictionary converter in isolation.
42+
const webidl = require('internal/crypto/webidl');
43+
const input = { name: 'AES-GCM', iv: new Uint8Array(12) };
44+
const opts = { prefix: 'test', context: 'test' };
45+
bench.start();
46+
for (let i = 0; i < n; i++)
47+
webidl.converters.AeadParams(input, opts);
48+
bench.end(n);
49+
break;
50+
}
51+
case 'webidl-algorithm-identifier-string': {
52+
// Exercises converters.AlgorithmIdentifier string path.
53+
const webidl = require('internal/crypto/webidl');
54+
const opts = { prefix: 'test', context: 'test' };
55+
bench.start();
56+
for (let i = 0; i < n; i++)
57+
webidl.converters.AlgorithmIdentifier('SHA-256', opts);
58+
bench.end(n);
59+
break;
60+
}
61+
case 'webidl-algorithm-identifier-object': {
62+
// Exercises converters.AlgorithmIdentifier object path.
63+
const webidl = require('internal/crypto/webidl');
64+
const input = { name: 'SHA-256' };
65+
const opts = { prefix: 'test', context: 'test' };
66+
bench.start();
67+
for (let i = 0; i < n; i++)
68+
webidl.converters.AlgorithmIdentifier(input, opts);
69+
bench.end(n);
70+
break;
71+
}
72+
case 'webidl-dict-enforce-range': {
73+
// Exercises [EnforceRange] integer dictionary members.
74+
const webidl = require('internal/crypto/webidl');
75+
const input = {
76+
name: 'RSASSA-PKCS1-v1_5',
77+
modulusLength: 2048,
78+
publicExponent: new Uint8Array([1, 0, 1]),
79+
};
80+
const opts = { prefix: 'test', context: 'test' };
81+
bench.start();
82+
for (let i = 0; i < n; i++)
83+
webidl.converters.RsaKeyGenParams(input, opts);
84+
bench.end(n);
85+
break;
86+
}
87+
case 'webidl-dict-ensure-sha': {
88+
// Exercises ensureSHA on a hash member.
89+
const webidl = require('internal/crypto/webidl');
90+
const input = { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };
91+
const opts = { prefix: 'test', context: 'test' };
92+
bench.start();
93+
for (let i = 0; i < n; i++)
94+
webidl.converters.RsaHashedImportParams(input, opts);
95+
bench.end(n);
96+
break;
97+
}
98+
case 'webidl-dict-null': {
99+
// Exercises the null/undefined path in createDictionaryConverter().
100+
const webidl = require('internal/crypto/webidl');
101+
const opts = { prefix: 'test', context: 'test' };
102+
bench.start();
103+
for (let i = 0; i < n; i++)
104+
webidl.converters.JsonWebKey(undefined, opts);
105+
bench.end(n);
106+
break;
107+
}
108+
}
109+
}
Collapse file
+82Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const common = require('../common.js');
5+
6+
const bench = common.createBenchmark(main, {
7+
converter: [
8+
'byte',
9+
'octet',
10+
'unsigned short',
11+
'unsigned long',
12+
'long long',
13+
],
14+
input: [
15+
'integer',
16+
'fractional',
17+
'wrap',
18+
'clamp',
19+
'enforce-range',
20+
'object',
21+
],
22+
n: [1e6],
23+
}, { flags: ['--expose-internals'] });
24+
25+
function getConverter(converter) {
26+
switch (converter) {
27+
case 'byte':
28+
return { bitLength: 8, signedness: 'signed' };
29+
case 'octet':
30+
return { bitLength: 8 };
31+
case 'unsigned short':
32+
return { bitLength: 16 };
33+
case 'unsigned long':
34+
return { bitLength: 32 };
35+
case 'long long':
36+
return { bitLength: 64, signedness: 'signed' };
37+
default:
38+
throw new Error(`Unsupported converter: ${converter}`);
39+
}
40+
}
41+
42+
function getInput(input) {
43+
switch (input) {
44+
case 'integer':
45+
return { value: 7 };
46+
case 'fractional':
47+
return { value: 7.9 };
48+
case 'wrap':
49+
return { value: 2 ** 63 + 2 ** 11 };
50+
case 'clamp':
51+
return { value: 300.8, options: { clamp: true } };
52+
case 'enforce-range':
53+
return { value: 7.9, options: { enforceRange: true } };
54+
case 'object':
55+
return {
56+
value: {
57+
valueOf() { return 7; },
58+
},
59+
};
60+
default:
61+
throw new Error(`Unsupported input: ${input}`);
62+
}
63+
}
64+
65+
function main({ n, converter, input }) {
66+
const { convertToInt } = require('internal/webidl');
67+
const { bitLength, signedness } = getConverter(converter);
68+
const { value, options } = getInput(input);
69+
70+
let noDead;
71+
bench.start();
72+
if (options === undefined) {
73+
for (let i = 0; i < n; i++)
74+
noDead = convertToInt(value, bitLength, signedness);
75+
} else {
76+
for (let i = 0; i < n; i++)
77+
noDead = convertToInt(value, bitLength, signedness, options);
78+
}
79+
bench.end(n);
80+
81+
assert.strictEqual(typeof noDead, 'number');
82+
}
Collapse file

‎lib/internal/blob.js‎

Copy file name to clipboardExpand all lines: lib/internal/blob.js
+8-5Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ const {
5454
const { inspect } = require('internal/util/inspect');
5555
const {
5656
converters,
57-
convertToInt,
5857
createSequenceConverter,
5958
} = require('internal/webidl');
6059

@@ -245,10 +244,14 @@ class Blob {
245244
if (!isBlob(this))
246245
throw new ERR_INVALID_THIS('Blob');
247246

248-
// Coerce values to int
249-
const opts = { __proto__: null, signed: true };
250-
start = convertToInt('start', start, 64, opts);
251-
end = convertToInt('end', end, 64, opts);
247+
start = converters['long long'](
248+
start,
249+
{ __proto__: null, context: 'start' },
250+
);
251+
end = converters['long long'](
252+
end,
253+
{ __proto__: null, context: 'end' },
254+
);
252255

253256
if (start < 0) {
254257
start = MathMax(this[kLength] + start, 0);

0 commit comments

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