@@ -749,6 +749,27 @@ struct IntrinsicJSFragment: Sendable {
749749
750750 private static let jsValueLowerHelperName = " __bjs_jsValueLower "
751751 private static let jsValueLiftHelperName = " __bjs_jsValueLift "
752+ private static let jsValueTakeHelperName = " __bjs_jsValueTake "
753+
754+ /// Mirrors `JavaScriptValueKind` in `_CJavaScriptKit.h`.
755+ private enum JSValueKind : Int , CaseIterable {
756+ case boolean = 0
757+ case string = 1
758+ case number = 2
759+ case object = 3
760+ case null = 4
761+ case undefined = 5
762+ case symbol = 7
763+ case bigInt = 8
764+
765+ /// Whether `payload1` is a reference in `swift.memory`.
766+ var holdsReference : Bool {
767+ switch self {
768+ case . string , . object , . symbol , . bigInt : return true
769+ case . boolean , . number , . null , . undefined : return false
770+ }
771+ }
772+ }
752773
753774 private static func registerJSValueHelpers ( scope : JSGlueVariableScope ) {
754775 scope . registerIntrinsic ( " jsValueHelpers " ) { helperPrinter in
@@ -777,6 +798,20 @@ struct IntrinsicJSFragment: Sendable {
777798 helperPrinter . write ( " return \( resultVar ) ; " )
778799 }
779800 helperPrinter . write ( " } " )
801+ helperPrinter . write ( " function \( jsValueTakeHelperName ) (kind, payload1, payload2) { " )
802+ helperPrinter . indent {
803+ helperPrinter . write ( " const value = \( jsValueLiftHelperName ) (kind, payload1, payload2); " )
804+ let holdsReference = JSValueKind . allCases . filter ( \. holdsReference )
805+ . map { " kind === \( $0 . rawValue ) " }
806+ . joined ( separator : " || " )
807+ helperPrinter . write ( " if ( \( holdsReference ) ) { " )
808+ helperPrinter . indent {
809+ helperPrinter . write ( " \( JSGlueVariableScope . reservedSwift ) .memory.release(payload1); " )
810+ }
811+ helperPrinter . write ( " } " )
812+ helperPrinter . write ( " return value; " )
813+ }
814+ helperPrinter . write ( " } " )
780815 }
781816 }
782817
@@ -792,7 +827,7 @@ struct IntrinsicJSFragment: Sendable {
792827 printer . write ( " let \( payload2Var ) ; " )
793828 printer . write ( " if ( \( value ) === null) { " )
794829 printer . indent {
795- printer . write ( " \( kindVar ) = 4 ; " )
830+ printer . write ( " \( kindVar ) = \( JSValueKind . null . rawValue ) ; " )
796831 printer . write ( " \( payload1Var ) = 0; " )
797832 printer . write ( " \( payload2Var ) = 0; " )
798833 }
@@ -802,41 +837,41 @@ struct IntrinsicJSFragment: Sendable {
802837 printer . indent {
803838 printer . write ( " case \" boolean \" : " )
804839 printer . indent {
805- printer . write ( " \( kindVar ) = 0 ; " )
840+ printer . write ( " \( kindVar ) = \( JSValueKind . boolean . rawValue ) ; " )
806841 printer . write ( " \( payload1Var ) = \( value ) ? 1 : 0; " )
807842 printer . write ( " \( payload2Var ) = 0; " )
808843 printer . write ( " break; " )
809844 }
810845 printer . write ( " case \" number \" : " )
811846 printer . indent {
812- printer . write ( " \( kindVar ) = 2 ; " )
847+ printer . write ( " \( kindVar ) = \( JSValueKind . number . rawValue ) ; " )
813848 printer . write ( " \( payload1Var ) = 0; " )
814849 printer . write ( " \( payload2Var ) = \( value ) ; " )
815850 printer . write ( " break; " )
816851 }
817- func emitRetainCase ( _ caseName : String , kind : Int ) {
852+ func emitRetainCase ( _ caseName : String , kind : JSValueKind ) {
818853 printer . write ( " case \" \( caseName ) \" : " )
819854 printer . indent {
820- printer . write ( " \( kindVar ) = \( kind ) ; " )
855+ printer . write ( " \( kindVar ) = \( kind . rawValue ) ; " )
821856 printer . write (
822857 " \( payload1Var ) = \( JSGlueVariableScope . reservedSwift ) .memory.retain( \( value ) ); "
823858 )
824859 printer . write ( " \( payload2Var ) = 0; " )
825860 printer . write ( " break; " )
826861 }
827862 }
828- emitRetainCase ( " string " , kind : 1 )
863+ emitRetainCase ( " string " , kind : . string )
829864 printer . write ( " case \" undefined \" : " )
830865 printer . indent {
831- printer . write ( " \( kindVar ) = 5 ; " )
866+ printer . write ( " \( kindVar ) = \( JSValueKind . undefined . rawValue ) ; " )
832867 printer . write ( " \( payload1Var ) = 0; " )
833868 printer . write ( " \( payload2Var ) = 0; " )
834869 printer . write ( " break; " )
835870 }
836- emitRetainCase ( " object " , kind : 3 )
837- emitRetainCase ( " function " , kind : 3 )
838- emitRetainCase ( " symbol " , kind : 7 )
839- emitRetainCase ( " bigint " , kind : 8 )
871+ emitRetainCase ( " object " , kind : . object )
872+ emitRetainCase ( " function " , kind : . object )
873+ emitRetainCase ( " symbol " , kind : . symbol )
874+ emitRetainCase ( " bigint " , kind : . bigInt )
840875 printer . write ( " default: " )
841876 printer . indent {
842877 printer . write ( " throw new TypeError( \" Unsupported JSValue type \" ); " )
@@ -874,53 +909,21 @@ struct IntrinsicJSFragment: Sendable {
874909 printer . write ( " let \( resultVar ) ; " )
875910 printer . write ( " switch ( \( kind ) ) { " )
876911 printer . indent {
877- printer . write ( " case 0: " )
878- printer . indent {
879- printer . write ( " \( resultVar ) = \( payload1 ) !== 0; " )
880- printer . write ( " break; " )
881- }
882- printer . write ( " case 1: " )
883- printer . indent {
884- printer . write (
885- " \( resultVar ) = \( JSGlueVariableScope . reservedSwift ) .memory.getObject( \( payload1 ) ); "
886- )
887- printer . write ( " break; " )
888- }
889- printer . write ( " case 2: " )
890- printer . indent {
891- printer . write ( " \( resultVar ) = \( payload2 ) ; " )
892- printer . write ( " break; " )
893- }
894- printer . write ( " case 3: " )
895- printer . indent {
896- printer . write (
897- " \( resultVar ) = \( JSGlueVariableScope . reservedSwift ) .memory.getObject( \( payload1 ) ); "
898- )
899- printer . write ( " break; " )
900- }
901- printer . write ( " case 4: " )
902- printer . indent {
903- printer . write ( " \( resultVar ) = null; " )
904- printer . write ( " break; " )
905- }
906- printer . write ( " case 5: " )
907- printer . indent {
908- printer . write ( " \( resultVar ) = undefined; " )
909- printer . write ( " break; " )
910- }
911- printer . write ( " case 7: " )
912- printer . indent {
913- printer . write (
914- " \( resultVar ) = \( JSGlueVariableScope . reservedSwift ) .memory.getObject( \( payload1 ) ); "
915- )
916- printer . write ( " break; " )
917- }
918- printer . write ( " case 8: " )
919- printer . indent {
920- printer . write (
921- " \( resultVar ) = \( JSGlueVariableScope . reservedSwift ) .memory.getObject( \( payload1 ) ); "
922- )
923- printer . write ( " break; " )
912+ for valueKind in JSValueKind . allCases {
913+ let value : String
914+ switch valueKind {
915+ case . boolean : value = " \( payload1 ) !== 0 "
916+ case . number : value = payload2
917+ case . null : value = " null "
918+ case . undefined : value = " undefined "
919+ case . string , . object , . symbol , . bigInt :
920+ value = " \( JSGlueVariableScope . reservedSwift ) .memory.getObject( \( payload1 ) ) "
921+ }
922+ printer . write ( " case \( valueKind . rawValue ) : " )
923+ printer . indent {
924+ printer . write ( " \( resultVar ) = \( value ) ; " )
925+ printer . write ( " break; " )
926+ }
924927 }
925928 printer . write ( " default: " )
926929 printer . indent {
@@ -961,11 +964,12 @@ struct IntrinsicJSFragment: Sendable {
961964 let resultVar = scope . variable ( " jsValue " )
962965 registerJSValueHelpers ( scope : scope )
963966 printer . write (
964- " const \( resultVar ) = \( jsValueLiftHelperName ) ( \( kind ) , \( payload1 ) , \( payload2 ) ); "
967+ " const \( resultVar ) = \( jsValueTakeHelperName ) ( \( kind ) , \( payload1 ) , \( payload2 ) ); "
965968 )
966969 return [ resultVar ]
967970 }
968971 )
972+ /// Swift lends the payload reference for the duration of the call, so it is not released here.
969973 static let jsValueLiftParameter = IntrinsicJSFragment (
970974 parameters : [ " kind " , " payload1 " , " payload2 " ] ,
971975 printCode : { arguments , context in
@@ -2232,7 +2236,7 @@ struct IntrinsicJSFragment: Sendable {
22322236 let resultVar = scope . variable ( " jsValue " )
22332237 registerJSValueHelpers ( scope : scope )
22342238 printer . write (
2235- " const \( resultVar ) = \( jsValueLiftHelperName ) ( \( kindVar ) , \( payload1Var ) , \( payload2Var ) ); "
2239+ " const \( resultVar ) = \( jsValueTakeHelperName ) ( \( kindVar ) , \( payload1Var ) , \( payload2Var ) ); "
22362240 )
22372241 return [ resultVar ]
22382242 }
0 commit comments