@@ -154,8 +154,37 @@ public class AnyKeyPath: _AppendKeyPath {
154154 ) -> Self {
155155 _internalInvariant ( bytes > 0 && bytes % 4 == 0 ,
156156 " capacity must be multiple of 4 bytes " )
157- let result = Builtin . allocWithTailElems_1 ( self , ( bytes/ 4 ) . _builtinWordValue,
158- Int32 . self)
157+
158+ // Subtract the buffer header and any padding it may have from the number of
159+ // bytes we need to allocate. The alloc below has a 0 sized 16 byte aligned
160+ // tail element that will force the compiler to insert buffer header + any
161+ // padding necessary to accomodate.
162+ let bytesWithoutHeader = bytes &- MemoryLayout< Int> . size
163+
164+ let result = Builtin . allocWithTailElems_2 (
165+ self ,
166+
167+ // This tail element accomplishes two things:
168+ // 1. Guarantees a 16 byte alignment for the allocated object pointer.
169+ // 2. Forces the compiler to add padding after the kvc string to support
170+ // this 16 byte aligned tail element.
171+ //
172+ // The size of keypath objects before any tail elements is 24 bytes large
173+ // on 64 bit platforms and 12 bytes large on 32 bit platforms.
174+ // (Isa, RC, and KVC). The amount of padding bytes needed after the kvc
175+ // string pointer to support a 16 byte aligned tail element is the exact
176+ // same amount of bytes that the keypath buffer header occupies on both
177+ // 64 & 32 bit platforms (because we always start component headers on
178+ // pointer aligned addresses). That is the purpose for the subtraction
179+ // above. The result of this tail element should just be the 16 byte
180+ // pointer aligned requirement and no extra bytes allocated.
181+ 0 . _builtinWordValue,
182+ SIMD16< Int8> . self ,
183+
184+ ( bytesWithoutHeader/ 4 ) . _builtinWordValue,
185+ Int32 . self
186+ )
187+
159188 unsafe result. _kvcKeyPathStringPtr = nil
160189 let base = UnsafeMutableRawPointer ( Builtin . projectTailElems ( result,
161190 Int32 . self) )
@@ -3071,7 +3100,7 @@ public func _swift_getKeyPath(pattern: UnsafeMutableRawPointer,
30713100 // Instantiate a new key path object modeled on the pattern.
30723101 // Do a pass to determine the class of the key path we'll be instantiating
30733102 // and how much space we'll need for it.
3074- let ( keyPathClass, rootType, size, sizeWithMaxSize, _ )
3103+ let ( keyPathClass, rootType, size, sizeWithMaxSize)
30753104 = unsafe _getKeyPathClassAndInstanceSizeFromPattern( patternPtr, arguments)
30763105
30773106 var pureStructOffset : UInt32 ? = nil
@@ -3633,6 +3662,9 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
36333662 // start with one word for the header
36343663 var size : Int = MemoryLayout< Int> . size
36353664 var sizeWithMaxSize : Int = 0
3665+ var sizeWithObjectHeaderAndKvc : Int {
3666+ size &+ MemoryLayout < Int > . size * 3
3667+ }
36363668
36373669 var capability : KeyPathKind = . value
36383670 var didChain : Bool = false
@@ -3735,13 +3767,24 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
37353767 // Argument size and witnesses ptr.
37363768 unsafe size &+= MemoryLayout < Int > . size &* 2
37373769
3770+ // If we also have external arguments, we need to store the size of the
3771+ // local arguments so we can find the external component arguments.
3772+ if unsafe externalArgs != nil {
3773+ unsafe size &+= RawKeyPathComponent . Header. externalWithArgumentsExtraSize
3774+ }
3775+
37383776 let ( typeSize, typeAlignMask) = unsafe arguments. getLayout ( patternArgs)
37393777
37403778 // We are known to be pointer aligned at this point in the KeyPath buffer.
37413779 // However, for types who have an alignment large than pointers, we need
37423780 // to determine if the current position is suitable for the argument, or
37433781 // if we need to add padding bytes to align ourselves.
3744- let misaligned = unsafe size & typeAlignMask
3782+ //
3783+ // Note: We need to account for the object header and kvc pointer because
3784+ // it's an odd number of words which will affect whether the size visitor
3785+ // determines if we need padding. It would cause out of sync answers when
3786+ // going to actually instantiate the buffer.
3787+ let misaligned = unsafe sizeWithObjectHeaderAndKvc & typeAlignMask
37453788
37463789 if misaligned != 0 {
37473790 // We were misaligned, add the padding to the total size of the keypath
@@ -3761,12 +3804,6 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
37613804 unsafe size &+= MemoryLayout < Int > . size &* 2
37623805 }
37633806
3764- // We also need to store the size of the local arguments so we can
3765- // find the external component arguments.
3766- if unsafe arguments != nil {
3767- unsafe size &+= RawKeyPathComponent . Header. externalWithArgumentsExtraSize
3768- }
3769-
37703807 unsafe size &+= MemoryLayout < Int > . size &* externalArgs. count
37713808 }
37723809 }
@@ -3813,8 +3850,7 @@ internal func _getKeyPathClassAndInstanceSizeFromPattern(
38133850 keyPathClass: AnyKeyPath . Type,
38143851 rootType: Any . Type,
38153852 size: Int,
3816- sizeWithMaxSize: Int,
3817- alignmentMask: Int
3853+ sizeWithMaxSize: Int
38183854) {
38193855 var walker = unsafe GetKeyPathClassAndInstanceSizeFromPattern( patternArgs: arguments)
38203856 unsafe _walkKeyPathPattern( pattern, walker: & walker)
@@ -3840,12 +3876,12 @@ internal func _getKeyPathClassAndInstanceSizeFromPattern(
38403876 }
38413877 let classTy = unsafe _openExistential ( walker. root!, do: openRoot)
38423878
3843- return unsafe ( keyPathClass : classTy ,
3844- rootType : walker . root! ,
3845- size : walker. size ,
3846- sizeWithMaxSize : walker. sizeWithMaxSize ,
3847- // FIXME: Handle overalignment
3848- alignmentMask : MemoryLayout < Int > . _alignmentMask )
3879+ return unsafe (
3880+ keyPathClass : classTy ,
3881+ rootType : walker. root! ,
3882+ size : walker. size ,
3883+ sizeWithMaxSize : walker . sizeWithMaxSize
3884+ )
38493885}
38503886
38513887internal func _getTypeSize< Type> ( _: Type . Type) - > Int {
@@ -4279,7 +4315,6 @@ internal struct ValidatingInstantiateKeyPathBuffer: KeyPathPatternVisitor {
42794315 offset: offset)
42804316 unsafe checkSizeConsistency ( )
42814317 unsafe structOffset = unsafe instantiateVisitor . structOffset
4282- unsafe isPureStruct . append ( contentsOf: instantiateVisitor. isPureStruct)
42834318 }
42844319 mutating func visitComputedComponent( mutating: Bool ,
42854320 idKind: KeyPathComputedIDKind ,
@@ -4311,31 +4346,26 @@ internal struct ValidatingInstantiateKeyPathBuffer: KeyPathPatternVisitor {
43114346 // Note: For this function and the ones below, modification of structOffset
43124347 // is omitted since these types of KeyPaths won't have a pureStruct
43134348 // offset anyway.
4314- unsafe isPureStruct . append ( contentsOf: instantiateVisitor. isPureStruct)
43154349 unsafe checkSizeConsistency ( )
43164350 }
43174351 mutating func visitOptionalChainComponent( ) {
43184352 unsafe sizeVisitor . visitOptionalChainComponent ( )
43194353 unsafe instantiateVisitor . visitOptionalChainComponent ( )
4320- unsafe isPureStruct . append ( contentsOf: instantiateVisitor. isPureStruct)
43214354 unsafe checkSizeConsistency ( )
43224355 }
43234356 mutating func visitOptionalWrapComponent( ) {
43244357 unsafe sizeVisitor . visitOptionalWrapComponent ( )
43254358 unsafe instantiateVisitor . visitOptionalWrapComponent ( )
4326- unsafe isPureStruct . append ( contentsOf: instantiateVisitor. isPureStruct)
43274359 unsafe checkSizeConsistency ( )
43284360 }
43294361 mutating func visitOptionalForceComponent( ) {
43304362 unsafe sizeVisitor . visitOptionalForceComponent ( )
43314363 unsafe instantiateVisitor . visitOptionalForceComponent ( )
4332- unsafe isPureStruct . append ( contentsOf: instantiateVisitor. isPureStruct)
43334364 unsafe checkSizeConsistency ( )
43344365 }
43354366 mutating func visitIntermediateComponentType( metadataRef: MetadataReference ) {
43364367 unsafe sizeVisitor . visitIntermediateComponentType ( metadataRef: metadataRef)
43374368 unsafe instantiateVisitor . visitIntermediateComponentType ( metadataRef: metadataRef)
4338- unsafe isPureStruct . append ( contentsOf: instantiateVisitor. isPureStruct)
43394369 unsafe checkSizeConsistency ( )
43404370 }
43414371
0 commit comments