Skip to content

Commit 1071451

Browse files
committed
Force keypath objects to be 16 byte aligned
1 parent 9933d3c commit 1071451

File tree

1 file changed

+54
-24
lines changed

1 file changed

+54
-24
lines changed

stdlib/public/core/KeyPath.swift

Lines changed: 54 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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

38513887
internal 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

Comments
 (0)