| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 296f907 commit 288065c
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,6 +16,7 @@ const { | |||
| 16 | 16 | ObjectKeys, | |
| 17 | 17 | ObjectPrototypeHasOwnProperty, | |
| 18 | 18 | PromiseWithResolvers, | |
| 19 | + SafeMap, | ||
| 19 | 20 | SafeSet, | |
| 20 | 21 | StringPrototypeToUpperCase, | |
| 21 | 22 | Symbol, | |
@@ -453,8 +454,11 @@ const experimentalAlgorithms = [ | |||
| 453 | 454 | ]; | |
| 454 | 455 | ||
| 455 | 456 | // Transform the algorithm definitions into the operation-keyed structure | |
| 457 | + // Also builds a parallel Map<UPPERCASED_NAME, canonicalName> per operation | ||
| 458 | + // for O(1) case-insensitive algorithm name lookup in normalizeAlgorithm. | ||
| 456 | 459 | function createSupportedAlgorithms(algorithmDefs) { | |
| 457 | 460 | const result = {}; | |
| 461 | + const nameMap = {}; | ||
| 458 | 462 | ||
| 459 | 463 | for (const { 0: algorithmName, 1: operations } of ObjectEntries(algorithmDefs)) { | |
| 460 | 464 | // Skip algorithms that are conditionally not supported | |
@@ -465,6 +469,8 @@ function createSupportedAlgorithms(algorithmDefs) { | |||
| 465 | 469 | ||
| 466 | 470 | for (const { 0: operation, 1: dict } of ObjectEntries(operations)) { | |
| 467 | 471 | result[operation] ||= {}; | |
| 472 | + nameMap[operation] ||= new SafeMap(); | ||
| 473 | + nameMap[operation].set(StringPrototypeToUpperCase(algorithmName), algorithmName); | ||
| 468 | 474 | ||
| 469 | 475 | // Add experimental warnings for experimental algorithms | |
| 470 | 476 | if (ArrayPrototypeIncludes(experimentalAlgorithms, algorithmName)) { | |
@@ -482,10 +488,11 @@ function createSupportedAlgorithms(algorithmDefs) { | |||
| 482 | 488 | } | |
| 483 | 489 | } | |
| 484 | 490 | ||
| 485 | - return result; | ||
| 491 | + return { algorithms: result, nameMap }; | ||
| 486 | 492 | } | |
| 487 | 493 | ||
| 488 | - const kSupportedAlgorithms = createSupportedAlgorithms(kAlgorithmDefinitions); | ||
| 494 | + const { algorithms: kSupportedAlgorithms, nameMap: kAlgorithmNameMap } = | ||
| 495 | + createSupportedAlgorithms(kAlgorithmDefinitions); | ||
| 489 | 496 | ||
| 490 | 497 | const simpleAlgorithmDictionaries = { | |
| 491 | 498 | AesCbcParams: { iv: 'BufferSource' }, | |
@@ -527,6 +534,12 @@ const simpleAlgorithmDictionaries = { | |||
| 527 | 534 | TurboShakeParams: {}, | |
| 528 | 535 | }; | |
| 529 | 536 | ||
| 537 | + // Pre-compute ObjectKeys() for each dictionary entry at module init | ||
| 538 | + // to avoid allocating a new keys array on every normalizeAlgorithm call. | ||
| 539 | + for (const { 0: name, 1: types } of ObjectEntries(simpleAlgorithmDictionaries)) { | ||
| 540 | + simpleAlgorithmDictionaries[name] = { keys: ObjectKeys(types), types }; | ||
| 541 | + } | ||
| 542 | + | ||
| 530 | 543 | function validateMaxBufferLength(data, name, max = kMaxBufferLength) { | |
| 531 | 544 | if (data.byteLength > max) { | |
| 532 | 545 | throw lazyDOMException( | |
@@ -537,6 +550,14 @@ function validateMaxBufferLength(data, name, max = kMaxBufferLength) { | |||
| 537 | 550 | ||
| 538 | 551 | let webidl; | |
| 539 | 552 | ||
| 553 | + // Keep this as a regular object. The WebIDL converters read and spread these | ||
| 554 | + // options on the normalizeAlgorithm hot path, and a null-prototype object | ||
| 555 | + // measurably regresses benchmark/misc/webcrypto-webidl normalizeAlgorithm-*. | ||
| 556 | + const kNormalizeAlgorithmOpts = { | ||
| 557 | + prefix: 'Failed to normalize algorithm', | ||
| 558 | + context: 'passed algorithm', | ||
| 559 | + }; | ||
| 560 | + | ||
| 540 | 561 | // https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm | |
| 541 | 562 | // adapted for Node.js from Deno's implementation | |
| 542 | 563 | // https://github.com/denoland/deno/blob/v1.29.1/ext/crypto/00_crypto.js#L195 | |
@@ -549,69 +570,56 @@ function normalizeAlgorithm(algorithm, op) { | |||
| 549 | 570 | // 1. | |
| 550 | 571 | const registeredAlgorithms = kSupportedAlgorithms[op]; | |
| 551 | 572 | // 2. 3. | |
| 552 | - const initialAlg = webidl.converters.Algorithm(algorithm, { | ||
| 553 | - prefix: 'Failed to normalize algorithm', | ||
| 554 | - context: 'passed algorithm', | ||
| 555 | - }); | ||
| 573 | + const initialAlg = webidl.converters.Algorithm(algorithm, | ||
| 574 | + kNormalizeAlgorithmOpts); | ||
| 556 | 575 | // 4. | |
| 557 | 576 | let algName = initialAlg.name; | |
| 558 | 577 | ||
| 559 | - // 5. | ||
| 560 | - let desiredType; | ||
| 561 | - for (const key in registeredAlgorithms) { | ||
| 562 | - if (!ObjectPrototypeHasOwnProperty(registeredAlgorithms, key)) { | ||
| 563 | - continue; | ||
| 564 | - } | ||
| 565 | - if ( | ||
| 566 | - StringPrototypeToUpperCase(key) === StringPrototypeToUpperCase(algName) | ||
| 567 | - ) { | ||
| 568 | - algName = key; | ||
| 569 | - desiredType = registeredAlgorithms[key]; | ||
| 570 | - } | ||
| 571 | - } | ||
| 572 | - if (desiredType === undefined) | ||
| 578 | + // 5. Case-insensitive lookup via pre-built Map (O(1) instead of O(n)). | ||
| 579 | + const canonicalName = kAlgorithmNameMap[op]?.get( | ||
| 580 | + StringPrototypeToUpperCase(algName)); | ||
| 581 | + if (canonicalName === undefined) | ||
| 573 | 582 | throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError'); | |
| 574 | 583 | ||
| 584 | + algName = canonicalName; | ||
| 585 | + const desiredType = registeredAlgorithms[algName]; | ||
| 586 | + | ||
| 575 | 587 | // Fast path everything below if the registered dictionary is null | |
| 576 | 588 | if (desiredType === null) | |
| 577 | 589 | return { name: algName }; | |
| 578 | 590 | ||
| 579 | 591 | // 6. | |
| 580 | 592 | const normalizedAlgorithm = webidl.converters[desiredType]( | |
| 581 | 593 | { __proto__: algorithm, name: algName }, | |
| 582 | - { | ||
| 583 | - prefix: 'Failed to normalize algorithm', | ||
| 584 | - context: 'passed algorithm', | ||
| 585 | - }, | ||
| 594 | + kNormalizeAlgorithmOpts, | ||
| 586 | 595 | ); | |
| 587 | 596 | // 7. | |
| 588 | 597 | normalizedAlgorithm.name = algName; | |
| 589 | 598 | ||
| 590 | - // 9. | ||
| 591 | - const dict = simpleAlgorithmDictionaries[desiredType]; | ||
| 592 | - // 10. | ||
| 593 | - const dictKeys = dict ? ObjectKeys(dict) : []; | ||
| 594 | - for (let i = 0; i < dictKeys.length; i++) { | ||
| 595 | - const member = dictKeys[i]; | ||
| 596 | - if (!ObjectPrototypeHasOwnProperty(dict, member)) | ||
| 597 | - continue; | ||
| 598 | - const idlType = dict[member]; | ||
| 599 | - const idlValue = normalizedAlgorithm[member]; | ||
| 600 | - // 3. | ||
| 601 | - if (idlType === 'BufferSource' && idlValue) { | ||
| 602 | - const isView = ArrayBufferIsView(idlValue); | ||
| 603 | - normalizedAlgorithm[member] = TypedArrayPrototypeSlice( | ||
| 604 | - new Uint8Array( | ||
| 605 | - isView ? getDataViewOrTypedArrayBuffer(idlValue) : idlValue, | ||
| 606 | - isView ? getDataViewOrTypedArrayByteOffset(idlValue) : 0, | ||
| 607 | - isView ? getDataViewOrTypedArrayByteLength(idlValue) : ArrayBufferPrototypeGetByteLength(idlValue), | ||
| 608 | - ), | ||
| 609 | - ); | ||
| 610 | - } else if (idlType === 'HashAlgorithmIdentifier') { | ||
| 611 | - normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, 'digest'); | ||
| 612 | - } else if (idlType === 'AlgorithmIdentifier') { | ||
| 613 | - // This extension point is not used by any supported algorithm (yet?) | ||
| 614 | - throw lazyDOMException('Not implemented.', 'NotSupportedError'); | ||
| 599 | + // 9. 10. Pre-computed keys and types from simpleAlgorithmDictionaries. | ||
| 600 | + const dictMeta = simpleAlgorithmDictionaries[desiredType]; | ||
| 601 | + if (dictMeta) { | ||
| 602 | + const { keys: dictKeys, types: dictTypes } = dictMeta; | ||
| 603 | + for (let i = 0; i < dictKeys.length; i++) { | ||
| 604 | + const member = dictKeys[i]; | ||
| 605 | + const idlType = dictTypes[member]; | ||
| 606 | + const idlValue = normalizedAlgorithm[member]; | ||
| 607 | + // 3. | ||
| 608 | + if (idlType === 'BufferSource' && idlValue) { | ||
| 609 | + const isView = ArrayBufferIsView(idlValue); | ||
| 610 | + normalizedAlgorithm[member] = TypedArrayPrototypeSlice( | ||
| 611 | + new Uint8Array( | ||
| 612 | + isView ? getDataViewOrTypedArrayBuffer(idlValue) : idlValue, | ||
| 613 | + isView ? getDataViewOrTypedArrayByteOffset(idlValue) : 0, | ||
| 614 | + isView ? getDataViewOrTypedArrayByteLength(idlValue) : ArrayBufferPrototypeGetByteLength(idlValue), | ||
| 615 | + ), | ||
| 616 | + ); | ||
| 617 | + } else if (idlType === 'HashAlgorithmIdentifier') { | ||
| 618 | + normalizedAlgorithm[member] = normalizeAlgorithm(idlValue, 'digest'); | ||
| 619 | + } else if (idlType === 'AlgorithmIdentifier') { | ||
| 620 | + // This extension point is not used by any supported algorithm (yet?) | ||
| 621 | + throw lazyDOMException('Not implemented.', 'NotSupportedError'); | ||
| 622 | + } | ||
| 615 | 623 | } | |
| 616 | 624 | } | |
| 617 | 625 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments