@@ -1119,6 +1119,44 @@ internal enum KeyPathComputedIDResolution {
11191119 case functionCall
11201120}
11211121
1122+ internal struct ComputedArgumentSize {
1123+ let value : UInt
1124+
1125+ static var sizeMask : UInt {
1126+ #if _pointerBitWidth(_64)
1127+ 0x7FFF_FFFF_FFFF_FFFF
1128+ #elseif _pointerBitWidth(_32)
1129+ 0x3FFF_FFFF
1130+ #else
1131+ #error("Unsupported platform")
1132+ #endif
1133+ }
1134+
1135+ static var paddingShift : UInt {
1136+ #if _pointerBitWidth(_64)
1137+ 63
1138+ #elseif _pointerBitWidth(_32)
1139+ 30
1140+ #else
1141+ #error("Unsupported platform")
1142+ #endif
1143+ }
1144+
1145+ // The total size of the argument buffer is in the bottom 30/63 bits.
1146+ var size : Int {
1147+ Int ( truncatingIfNeeded: value & Self . sizeMask)
1148+ }
1149+
1150+ // The number of padding bytes required so that the argument is properly
1151+ // aligned in the keypath buffer. This is in the top 2 bits for 32 bit
1152+ // platforms (because they need to represent 8 and 16 overaligned types) and
1153+ // top 1 bit for 64 bit platforms (because they only need to represent 16
1154+ // alignment).
1155+ var padding : Int {
1156+ Int ( truncatingIfNeeded: value &>> Self . paddingShift) &* MemoryLayout< Int> . size
1157+ }
1158+ }
1159+
11221160@_unavailableInEmbedded
11231161@safe
11241162internal struct RawKeyPathComponent {
@@ -1534,7 +1572,7 @@ internal struct RawKeyPathComponent {
15341572 // two words for argument header: size, witnesses
15351573 total &+= ptrSize &* 2
15361574 // size of argument area
1537- total &+= _computedArgumentSize
1575+ total &+= _computedArgumentSize. size
15381576 if header. isComputedInstantiatedFromExternalWithArguments {
15391577 total &+= Header . externalWithArgumentsExtraSize
15401578 }
@@ -1592,8 +1630,8 @@ internal struct RawKeyPathComponent {
15921630 ( header. isComputedSettable ? 3 : 2 )
15931631 }
15941632
1595- internal var _computedArgumentSize : Int {
1596- return unsafe _computedArgumentHeaderPointer. load ( as: Int . self)
1633+ internal var _computedArgumentSize : ComputedArgumentSize {
1634+ return unsafe _computedArgumentHeaderPointer. load ( as: ComputedArgumentSize . self)
15971635 }
15981636 internal
15991637 var _computedArgumentWitnesses : ComputedArgumentWitnessesPtr {
@@ -1611,6 +1649,10 @@ internal struct RawKeyPathComponent {
16111649 if header . isComputedInstantiatedFromExternalWithArguments {
16121650 unsafe base += Header . externalWithArgumentsExtraSize
16131651 }
1652+
1653+ // If the argument needed padding to be properly aligned, skip that.
1654+ unsafe base += _computedArgumentSize. padding
1655+
16141656 return unsafe base
16151657 }
16161658 internal var _computedMutableArguments : UnsafeMutableRawPointer {
@@ -1648,7 +1690,7 @@ internal struct RawKeyPathComponent {
16481690 if header . hasComputedArguments {
16491691 unsafe argument = unsafe KeyPathComponent. ArgumentRef (
16501692 data: UnsafeRawBufferPointer ( start: _computedArguments,
1651- count: _computedArgumentSize) ,
1693+ count: _computedArgumentSize. size &- _computedArgumentSize . padding ) ,
16521694 witnesses: _computedArgumentWitnesses,
16531695 witnessSizeAdjustment: _computedArgumentWitnessSizeAdjustment)
16541696 } else {
@@ -1688,7 +1730,7 @@ internal struct RawKeyPathComponent {
16881730 if header. hasComputedArguments,
16891731 let destructor = unsafe _computedArgumentWitnesses. destroy {
16901732 unsafe destructor( _computedMutableArguments,
1691- _computedArgumentSize &- _computedArgumentWitnessSizeAdjustment)
1733+ _computedArgumentSize. size &- _computedArgumentWitnessSizeAdjustment)
16921734 }
16931735 case . external :
16941736 _internalInvar iantFailure( " should have been instantiated away " )
@@ -1741,12 +1783,14 @@ internal struct RawKeyPathComponent {
17411783 componentSize += MemoryLayout< Int> . size
17421784 }
17431785
1786+ // FIXME: Need to handle if buffer is already aligned when copying
1787+ // arguments which would impact the argument size word.
17441788 if header . hasComputedArguments {
17451789 let arguments = unsafe _computedArguments
17461790 let argumentSize = _computedArgumentSize
17471791 unsafe buffer. storeBytes ( of: argumentSize,
17481792 toByteOffset: componentSize,
1749- as: Int . self)
1793+ as: ComputedArgumentSize . self)
17501794 componentSize += MemoryLayout< Int> . size
17511795 unsafe buffer. storeBytes ( of: _computedArgumentWitnesses,
17521796 toByteOffset: componentSize,
@@ -1761,7 +1805,7 @@ internal struct RawKeyPathComponent {
17611805 as: Int . self)
17621806 componentSize += MemoryLayout< Int> . size
17631807 }
1764- let adjustedSize = argumentSize - _computedArgumentWitnessSizeAdjustment
1808+ let adjustedSize = argumentSize. size - _computedArgumentWitnessSizeAdjustment
17651809 let argumentDest =
17661810 unsafe buffer. baseAddress . unsafelyUnwrapped + componentSize
17671811 unsafe _computedArgumentWitnesses. copy(
@@ -1776,7 +1820,7 @@ internal struct RawKeyPathComponent {
17761820 size: UInt ( _computedArgumentWitnessSizeAdjustment) )
17771821 }
17781822
1779- componentSize += argumentSize
1823+ componentSize += argumentSize. size
17801824 }
17811825
17821826 case . external:
@@ -3527,46 +3571,44 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
35273571 if settable {
35283572 unsafe size += MemoryLayout< Int> . size
35293573 }
3530-
3531- // ...and the arguments, if any.
3532- let argumentHeaderSize = MemoryLayout< Int> . size * 2
3533- switch unsafe ( arguments, externalArgs) {
3534- case ( nil , nil ) :
3535- break
3536- case ( let arguments? , nil ) :
3537- unsafe size += argumentHeaderSize
3538- // If we have arguments, calculate how much space they need by invoking
3539- // the layout function.
3540- let ( addedSize, addedAlignmentMask) = unsafe arguments. getLayout ( patternArgs)
3541- // TODO: Handle over-aligned values
3542- _internalInvariant ( addedAlignmentMask < MemoryLayout< Int> . alignment,
3543- " overaligned computed property element not supported " )
3544- unsafe size += addedSize
3545-
3546- case ( let arguments? , let externalArgs? ) :
3547- // If we're referencing an external declaration, and it takes captured
3548- // arguments, then we have to build a bit of a chimera. The canonical
3549- // identity and accessors come from the descriptor, but the argument
3550- // handling is still as described in the local candidate.
3551- unsafe size += argumentHeaderSize
3552- let ( addedSize, addedAlignmentMask) = unsafe arguments. getLayout ( patternArgs)
3553- // TODO: Handle over-aligned values
3554- _internalInvariant ( addedAlignmentMask < MemoryLayout< Int> . alignment,
3555- " overaligned computed property element not supported " )
3556- unsafe size += addedSize
3574+
3575+ // Handle local arguments.
3576+ if let arguments = arguments {
3577+ // Argument size and witnesses ptr.
3578+ unsafe size &+= MemoryLayout < Int > . size &* 2
3579+
3580+ let ( typeSize, typeAlignMask) = unsafe arguments. getLayout ( patternArgs)
3581+
3582+ // We are known to be pointer aligned at this point in the KeyPath buffer.
3583+ // However, for types who have an alignment large than pointers, we need
3584+ // to determine if the current position is suitable for the argument, or
3585+ // if we need to add padding bytes to align ourselves.
3586+ let misalign = unsafe size & typeAlignMask
3587+
3588+ if misalign != 0 {
3589+ let typeAlignment = typeAlignMask &+ 1
3590+ let padding = Swift . max ( 0 , typeAlignment &- MemoryLayout< Int> . alignment)
3591+ unsafe size &+= padding
3592+ }
3593+
3594+ unsafe size &+= typeSize
3595+ unsafe roundUpToPointerAlignment( )
3596+ }
3597+
3598+ // Handle external arguments.
3599+ if let externalArgs = externalArgs {
3600+ // Argument size and witnesses ptr if we didn't have local arguments.
3601+ if arguments == nil {
3602+ unsafe size &+= MemoryLayout < Int > . size &* 2
3603+ }
3604+
35573605 // We also need to store the size of the local arguments so we can
35583606 // find the external component arguments.
3559- unsafe roundUpToPointerAlignment ( )
3560- unsafe size += RawKeyPathComponent . Header. externalWithArgumentsExtraSize
3561- unsafe size += MemoryLayout < Int > . size * externalArgs . count
3607+ if arguments != nil {
3608+ unsafe size & += RawKeyPathComponent . Header. externalWithArgumentsExtraSize
3609+ }
35623610
3563- case ( nil , let externalArgs? ) :
3564- // If we're instantiating an external property with a local
3565- // candidate that has no arguments, then things are a little
3566- // easier. We only need to instantiate the generic
3567- // arguments for the external component's accessors.
3568- unsafe size += argumentHeaderSize
3569- unsafe size += MemoryLayout< Int> . size * externalArgs. count
3611+ unsafe size &+= MemoryLayout < Int > . size &* externalArgs. count
35703612 }
35713613 }
35723614
@@ -3599,8 +3641,7 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
35993641 }
36003642
36013643 mutating func finish( ) {
3602- unsafe sizeWithMaxSize = unsafe size
3603- unsafe sizeWithMaxSize = unsafe MemoryLayout< Int> . _roundingUpToAlignment( sizeWithMaxSize)
3644+ unsafe sizeWithMaxSize = unsafe MemoryLayout< Int> . _roundingUpToAlignment( size)
36043645 unsafe sizeWithMaxSize &+= MemoryLayout< Int> . size
36053646 }
36063647}
@@ -3891,22 +3932,13 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
38913932 }
38923933
38933934 if let arguments = unsafe arguments {
3894- // Instantiate the arguments.
3895- let ( baseSize, alignmentMask) = unsafe arguments. getLayout ( patternArgs)
3896- _internalInvariant ( alignmentMask < MemoryLayout< Int> . alignment,
3897- " overaligned computed arguments not implemented yet " )
3898-
3899- // The real buffer stride will be rounded up to alignment.
3900- var totalSize = ( baseSize + alignmentMask) & ~ alignmentMask
3901-
3902- // If an external property descriptor also has arguments, they'll be
3903- // added to the end with pointer alignment.
3904- if let externalArgs = unsafe externalArgs {
3905- totalSize = MemoryLayout< Int> . _roundingUpToAlignment( totalSize)
3906- totalSize += MemoryLayout < Int > . size * externalArgs. count
3907- }
3908-
3935+ // Record a placeholder for the total size of the arguments. We need to
3936+ // check after pushing preliminary data if the resulting argument will
3937+ // require padding bytes to be properly aligned.
3938+ let totalSizeAddress = unsafe destData. baseAddress . _unsafelyUnwrappedUnchecked
3939+ var totalSize : UInt = 0
39093940 unsafe pushDest( totalSize)
3941+
39103942 unsafe pushDest( arguments. witnesses)
39113943
39123944 // A nonnull destructor in the witnesses file indicates the instantiated
@@ -3922,15 +3954,58 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
39223954 unsafe pushDest( externalArgs. count * MemoryLayout< Int> . size)
39233955 }
39243956
3957+ let ( typeSize, typeAlignMask) = unsafe arguments. getLayout ( patternArgs)
3958+ let typeAlignment = typeAlignMask &+ 1
3959+ let padding = Swift . max ( 0 , typeAlignment &- MemoryLayout< Int> . alignment)
3960+
3961+ totalSize = UInt ( truncatingIfNeeded: typeSize)
3962+
3963+ // We are known to be pointer aligned at this point in the KeyPath buffer.
3964+ // However, for types who have an alignment large than pointers, we need
3965+ // to determine if the current position is suitable for the argument, or
3966+ // if we need to add padding bytes to align ourselves.
3967+ let argumentAddress = unsafe destData. baseAddress . _unsafelyUnwrappedUnchecked
3968+ let misalign = Int ( bitPattern: argumentAddress) & typeAlignMask
3969+
3970+ if misalign != 0 {
3971+ totalSize &+= UInt ( truncatingIfNeeded: padding)
3972+
3973+ // Go ahead and append the padding.
3974+ for _ in 0 ..< padding {
3975+ unsafe pushDest( UInt8 ( 0 ) )
3976+ }
3977+ }
3978+
3979+ // If an external property descriptor also has arguments, they'll be
3980+ // added to the end with pointer alignment.
3981+ if let externalArgs = unsafe externalArgs {
3982+ totalSize = MemoryLayout< Int> . _roundingUpToAlignment( totalSize)
3983+ totalSize += UInt ( truncatingIfNeeded: MemoryLayout < Int > . size * externalArgs. count)
3984+ }
3985+
3986+ // The argument total size contains the padding bytes required for the
3987+ // argument in the top 4 bits, so ensure the size of the argument buffer
3988+ // is small enough to account for that.
3989+ _precondition (
3990+ totalSize <= ComputedArgumentSize . sizeMask,
3991+ " keypath arguments are too large "
3992+ )
3993+
3994+ totalSize |= UInt ( truncatingIfNeeded: padding / MemoryLayout< Int> . size) &<< ComputedArgumentSize . paddingShift
3995+
3996+ // Ok, we've fully calculated totalSize, go ahead and update the
3997+ // placeholder.
3998+ unsafe totalSizeAddress. storeBytes ( of: totalSize, as: UInt . self)
3999+
39254000 // Initialize the local candidate arguments here.
3926- unsafe _internalInvariant( Int ( bitPattern: destData. baseAddress) & alignmentMask == 0 ,
4001+ unsafe _internalInvariant ( Int ( bitPattern: destData. baseAddress) & typeAlignMask == 0 ,
39274002 " argument destination not aligned " )
39284003 unsafe arguments. initializer ( patternArgs,
39294004 destData. baseAddress. _unsafelyUnwrappedUnchecked)
39304005
39314006 unsafe destData = unsafe UnsafeMutableRawBufferPointer(
3932- start: destData. baseAddress. _unsafelyUnwrappedUnchecked + baseSize ,
3933- count: destData. count - baseSize )
4007+ start: destData. baseAddress. _unsafelyUnwrappedUnchecked + typeSize ,
4008+ count: destData. count - typeSize )
39344009 }
39354010
39364011 if let externalArgs = unsafe externalArgs {
0 commit comments