@@ -355,6 +355,11 @@ public struct BridgeJSLink {
355355 declarations. append ( " return; " )
356356 declarations. append ( " } " )
357357 declarations. append ( " __bjs_typeHandlesRegistered = true; " )
358+ // The core (primitive) handles live in the JavaScriptKit library, so
359+ // they are registered once here rather than by every module.
360+ declarations. append (
361+ " \( JSGlueVariableScope . reservedInstance) .exports[ \" \( ABINameGenerator . coreTypeRegistrationFunctionName) \" ](); "
362+ )
358363 for skeleton in skeletons {
359364 guard skeleton. typeRegistrationEntries != nil else { continue }
360365 let name = ABINameGenerator . typeRegistrationFunctionName ( moduleName: skeleton. moduleName)
@@ -433,53 +438,88 @@ public struct BridgeJSLink {
433438 )
434439 }
435440
441+ /// Writes the body shared by every registration hook: verify the codec array
442+ /// lines up with the buffer Swift pushed, then pair IDs with codecs by index.
443+ ///
444+ /// The count check is the enforcement point of the ordering contract: the
445+ /// Swift side and the JS side derive their lists from the same declaration
446+ /// order, so a divergence shows up here instead of as a silent mismatch.
447+ private func writeTypeHandleRegistrationBody(
448+ into printer: CodeFragmentPrinter ,
449+ mismatchDescription: String
450+ ) {
451+ printer. write ( " if (count !== codecs.length) { " )
452+ printer. indent {
453+ printer. write (
454+ " throw new Error( \" BridgeJS: type handle registration mismatch for \( mismatchDescription) \" ); "
455+ )
456+ }
457+ printer. write ( " } " )
458+ printer. write (
459+ " const typeIds = new Int32Array( \( JSGlueVariableScope . reservedMemory) .buffer, base >>> 0, count >>> 0); "
460+ )
461+ printer. write ( " for (let i = 0; i < count; i++) { " )
462+ printer. indent {
463+ printer. write ( " \( JSGlueVariableScope . reservedCodecByTypeId) .set(typeIds[i], codecs[i]); " )
464+ }
465+ printer. write ( " } " )
466+ }
467+
468+ /// Installs the `bjs_core_register_type_handles` hook. The core handles are
469+ /// owned by the JavaScriptKit library rather than by generated code, so the
470+ /// wasm import exists in every binary that links JavaScriptKit and the hook
471+ /// is always installed; without generics anywhere in the build it is a no-op
472+ /// and the registration export is never called.
473+ private func generateCoreTypeRegistrationHook( into printer: CodeFragmentPrinter ) throws {
474+ let hookName = ABINameGenerator . coreTypeRegistrationFunctionName
475+ guard hasGenerics else {
476+ printer. write ( " bjs[ \" \( hookName) \" ] = function() {}; " )
477+ return
478+ }
479+ try ContainerCodecJS . registerPrimitiveCodecs ( context: makeCodecPrintContext ( printer: printer) )
480+ printer. write ( " bjs[ \" \( hookName) \" ] = function(base, count) { " )
481+ printer. indent {
482+ // Same canonical order as `_bjs_core_register_type_handles` in the
483+ // JavaScriptKit library.
484+ printer. write ( " const codecs = [ " )
485+ printer. indent {
486+ for primitive in BridgeType . genericBridgeablePrimitives {
487+ printer. write ( " \( JSGlueVariableScope . reservedPrimitiveCodecs) . \( primitive. token) , " )
488+ }
489+ }
490+ printer. write ( " ]; " )
491+ writeTypeHandleRegistrationBody ( into: printer, mismatchDescription: " core types " )
492+ }
493+ printer. write ( " } " )
494+ }
495+
436496 /// Installs the per-module `bjs_<Module>_register_type_handles` import
437497 /// hooks. A module with a registration function always carries the wasm
438498 /// import, so a hook is always installed; without generics anywhere in the
439499 /// build it is a no-op and the registration export is never called.
440500 private func generateTypeRegistrationHooks( into printer: CodeFragmentPrinter ) throws {
501+ try generateCoreTypeRegistrationHook ( into: printer)
441502 for skeleton in skeletons {
442- guard skeleton . typeRegistrationEntries != nil else { continue }
503+ guard let moduleEntries = skeleton . typeRegistrationEntries else { continue }
443504 let hookName = ABINameGenerator . typeRegistrationFunctionName ( moduleName: skeleton. moduleName)
444505 guard hasGenerics else {
445506 printer. write ( " bjs[ \" \( hookName) \" ] = function() {}; " )
446507 continue
447508 }
448- // The hooks resolve type IDs against the shared primitive codec table.
449- try ContainerCodecJS . registerPrimitiveCodecs ( context: makeCodecPrintContext ( printer: printer) )
450- let moduleEntries = skeleton. exported? . genericBridgeableTypeEntries ?? [ ]
451509 printer. write ( " bjs[ \" \( hookName) \" ] = function(base, count) { " )
452510 try printer. indent {
453- // Same canonical order as the Swift registration function:
454- // primitives first, then the module's own types.
511+ // Same order as the module's Swift registration function.
455512 printer. write ( " const codecs = [ " )
456- printer. indent {
457- for primitive in BridgeType . genericBridgeablePrimitives {
458- printer. write ( " \( JSGlueVariableScope . reservedPrimitiveCodecs) . \( primitive. token) , " )
459- }
460- }
461- printer. write ( " ].concat([ " )
462513 try printer. indent {
463514 for entry in moduleEntries {
464515 try appendGenericCodecLiteral ( type: entry. bridgeType, into: printer)
465516 }
466517 }
467- printer. write ( " ]); " )
468- printer. write ( " if (count !== codecs.length) { " )
469- printer. indent {
470- printer. write (
471- " throw new Error( \" BridgeJS: type handle registration mismatch for module ' \( skeleton. moduleName) ' \" ); "
472- )
473- }
474- printer. write ( " } " )
475- printer. write (
476- " const typeIds = new Int32Array( \( JSGlueVariableScope . reservedMemory) .buffer, base >>> 0, count >>> 0); "
518+ printer. write ( " ]; " )
519+ writeTypeHandleRegistrationBody (
520+ into: printer,
521+ mismatchDescription: " module ' \( skeleton. moduleName) ' "
477522 )
478- printer. write ( " for (let i = 0; i < count; i++) { " )
479- printer. indent {
480- printer. write ( " \( JSGlueVariableScope . reservedCodecByTypeId) .set(typeIds[i], codecs[i]); " )
481- }
482- printer. write ( " } " )
483523 }
484524 printer. write ( " } " )
485525 }
0 commit comments