@@ -348,6 +348,11 @@ public struct BridgeJSLink {
348348 declarations. append ( " return; " )
349349 declarations. append ( " } " )
350350 declarations. append ( " __bjs_typeHandlesRegistered = true; " )
351+ // The core (primitive) handles live in the JavaScriptKit library, so
352+ // they are registered once here rather than by every module.
353+ declarations. append (
354+ " \( JSGlueVariableScope . reservedInstance) .exports[ \" \( ABINameGenerator . coreTypeRegistrationFunctionName) \" ](); "
355+ )
351356 for skeleton in skeletons {
352357 guard skeleton. typeRegistrationEntries != nil else { continue }
353358 let name = ABINameGenerator . typeRegistrationFunctionName ( moduleName: skeleton. moduleName)
@@ -426,46 +431,70 @@ public struct BridgeJSLink {
426431 )
427432 }
428433
434+ /// Pairs the type IDs Swift pushed with codecs in the matching skeleton order.
435+ private func writeTypeHandleRegistrationBody( into printer: CodeFragmentPrinter ) {
436+ printer. write (
437+ " const typeIds = new Int32Array( \( JSGlueVariableScope . reservedMemory) .buffer, base >>> 0, count >>> 0); "
438+ )
439+ printer. write ( " for (let i = 0; i < count; i++) { " )
440+ printer. indent {
441+ printer. write ( " \( JSGlueVariableScope . reservedCodecByTypeId) .set(typeIds[i], codecs[i]); " )
442+ }
443+ printer. write ( " } " )
444+ }
445+
446+ /// Installs the `bjs_core_register_type_handles` hook. The core handles are
447+ /// owned by the JavaScriptKit library rather than by generated code, so the
448+ /// wasm import exists in every binary that links JavaScriptKit and the hook
449+ /// is always installed; without generics anywhere in the build it is a no-op
450+ /// and the registration export is never called.
451+ private func generateCoreTypeRegistrationHook( into printer: CodeFragmentPrinter ) throws {
452+ let hookName = ABINameGenerator . coreTypeRegistrationFunctionName
453+ guard hasGenerics else {
454+ printer. write ( " bjs[ \" \( hookName) \" ] = function() {}; " )
455+ return
456+ }
457+ try ContainerCodecJS . registerPrimitiveCodecs ( context: makeCodecPrintContext ( printer: printer) )
458+ printer. write ( " bjs[ \" \( hookName) \" ] = function(base, count) { " )
459+ printer. indent {
460+ // Same canonical order as `_bjs_core_register_type_handles` in the
461+ // JavaScriptKit library.
462+ printer. write ( " const codecs = [ " )
463+ printer. indent {
464+ for primitive in BridgeType . genericBridgeablePrimitives {
465+ printer. write ( " \( JSGlueVariableScope . reservedPrimitiveCodecs) . \( primitive. token) , " )
466+ }
467+ }
468+ printer. write ( " ]; " )
469+ writeTypeHandleRegistrationBody ( into: printer)
470+ }
471+ printer. write ( " } " )
472+ }
473+
429474 /// Installs the per-module `bjs_<Module>_register_type_handles` import
430475 /// hooks. A module with a registration function always carries the wasm
431476 /// import, so a hook is always installed; without generics anywhere in the
432477 /// build it is a no-op and the registration export is never called.
433478 private func generateTypeRegistrationHooks( into printer: CodeFragmentPrinter ) throws {
479+ try generateCoreTypeRegistrationHook ( into: printer)
434480 for skeleton in skeletons {
435- guard skeleton . typeRegistrationEntries != nil else { continue }
481+ guard let moduleEntries = skeleton . typeRegistrationEntries else { continue }
436482 let hookName = ABINameGenerator . typeRegistrationFunctionName ( moduleName: skeleton. moduleName)
437483 guard hasGenerics else {
438484 printer. write ( " bjs[ \" \( hookName) \" ] = function() {}; " )
439485 continue
440486 }
441- // The hooks resolve type IDs against the shared primitive codec table.
442- try ContainerCodecJS . registerPrimitiveCodecs ( context: makeCodecPrintContext ( printer: printer) )
443- let moduleEntries = skeleton. exported? . genericBridgeableTypeEntries ?? [ ]
444487 printer. write ( " bjs[ \" \( hookName) \" ] = function(base, count) { " )
445488 try printer. indent {
446- // Same canonical order as the Swift registration function:
447- // primitives first, then the module's own types.
489+ // Same order as the module's Swift registration function.
448490 printer. write ( " const codecs = [ " )
449- printer. indent {
450- for primitive in BridgeType . genericBridgeablePrimitives {
451- printer. write ( " \( JSGlueVariableScope . reservedPrimitiveCodecs) . \( primitive. token) , " )
452- }
453- }
454- printer. write ( " ].concat([ " )
455491 try printer. indent {
456492 for entry in moduleEntries {
457493 try appendGenericCodecLiteral ( type: entry. bridgeType, into: printer)
458494 }
459495 }
460- printer. write ( " ]); " )
461- printer. write (
462- " const typeIds = new Int32Array( \( JSGlueVariableScope . reservedMemory) .buffer, base >>> 0, count >>> 0); "
463- )
464- printer. write ( " for (let i = 0; i < count; i++) { " )
465- printer. indent {
466- printer. write ( " \( JSGlueVariableScope . reservedCodecByTypeId) .set(typeIds[i], codecs[i]); " )
467- }
468- printer. write ( " } " )
496+ printer. write ( " ]; " )
497+ writeTypeHandleRegistrationBody ( into: printer)
469498 }
470499 printer. write ( " } " )
471500 }
0 commit comments