Skip to content

Commit afebae5

Browse files
Moved computation of offset for pureStructKeyPaths into KeyPathPatternVisitors.
Next expected commit: Move information stored in _pureStructValueOffset to _kvcKeyPathStringPtr (or similar).
1 parent 353eb9f commit afebae5

File tree

1 file changed

+70
-75
lines changed

1 file changed

+70
-75
lines changed

stdlib/public/core/KeyPath.swift

Lines changed: 70 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
158158
let base = UnsafeMutableRawPointer(Builtin.projectTailElems(keypath,
159159
Int32.self))
160160
body(UnsafeMutableRawBufferPointer(start: base, count: bytes))
161-
keypath._computeOffsetForPureStructKeypath()
161+
keypath._pureStructValueOffset = 0
162162
return keypath
163163
}
164164
final internal func withBuffer<T>(_ f: (KeyPathBuffer) throws -> T) rethrows -> T {
@@ -173,7 +173,8 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
173173
}
174174

175175
internal func isClass(_ item: Any.Type) -> Bool {
176-
// Displays "warning: 'is' test is always true" at compile time, but that's not actually the case.
176+
// Displays "warning: 'is' test is always true" at compile time,
177+
// but that's not actually the case.
177178
return (item is AnyObject)
178179
}
179180

@@ -192,73 +193,14 @@ public class AnyKeyPath: Hashable, _AppendKeyPath {
192193
let mirror = Mirror(reflecting: unwrapType(item))
193194
let description = mirror.description
194195
let offsetOfFirstBracketForMirrorDescriptionOfTuple = 11
195-
let idx = description.index(description.startIndex, offsetBy: offsetOfFirstBracketForMirrorDescriptionOfTuple)
196+
let idx = description.index(description.startIndex,
197+
offsetBy: offsetOfFirstBracketForMirrorDescriptionOfTuple)
196198
if description[idx] == "(" {
197199
return true
198200
}
199201
return false
200202
}
201203

202-
// TODO: Merge the functionality of _computeOffsetForPureStructKeypath,
203-
// _recalculateOffsetForPureStructKeyPath() and _storedInlineOffset.
204-
205-
// If this keypath traverses structs only, it'll have a predictable memory layout.
206-
// We can then jump to the value directly in _projectReadOnly().
207-
internal func _computeOffsetForPureStructKeypath() {
208-
_pureStructValueOffset = 0
209-
var isPureStruct = true
210-
var exitEarly = false
211-
defer {
212-
_isPureStructKeyPath = isPureStruct
213-
}
214-
withBuffer {
215-
var buffer = $0
216-
if buffer.data.isEmpty {
217-
if isClass(Self._rootAndValueType.root) {
218-
isPureStruct = false
219-
}
220-
} else {
221-
while !exitEarly {
222-
let (rawComponent, optNextType) = buffer.next()
223-
if isTuple(optNextType as Any) {
224-
isPureStruct = false
225-
break
226-
}
227-
switch rawComponent.header.kind {
228-
case .struct:
229-
_pureStructValueOffset += rawComponent._structOrClassOffset
230-
case .class, .computed, .optionalChain, .optionalForce, .optionalWrap, .external:
231-
isPureStruct = false
232-
exitEarly = true
233-
}
234-
if optNextType == nil {
235-
break
236-
}
237-
}
238-
}
239-
}
240-
}
241-
242-
// Recalculates the offset in the case where one pure struct keypath is appended to another.
243-
internal func _recalculateOffsetForPureStructKeyPath() {
244-
_pureStructValueOffset = 0
245-
withBuffer {
246-
var buffer = $0
247-
while true {
248-
let (rawComponent, optNextType) = buffer.next()
249-
switch rawComponent.header.kind {
250-
case .struct:
251-
_pureStructValueOffset += rawComponent._structOrClassOffset
252-
case .class, .computed, .optionalChain, .optionalForce, .optionalWrap, .external:
253-
return
254-
}
255-
if optNextType == nil {
256-
break
257-
}
258-
}
259-
}
260-
}
261-
262204
@usableFromInline // Exposed as public API by MemoryLayout<Root>.offset(of:)
263205
internal var _storedInlineOffset: Int? {
264206
return withBuffer {
@@ -2370,10 +2312,15 @@ extension _AppendKeyPath /* where Self == ReferenceWritableKeyPath<T,U> */ {
23702312
/// Note: Currently we only distinguish between keypaths that traverse only structs to get to the final value,
23712313
/// and all other types. This is done for performance reasons.
23722314
/// Other type information may be handled in the future to improve performance.
2373-
internal func _processAppendingKeyPathType(root: inout AnyKeyPath, leaf: AnyKeyPath) {
2374-
root._isPureStructKeyPath = root.isPureStructKeyPath && leaf.isPureStructKeyPath
2375-
if let isPureStruct = root._isPureStructKeyPath, isPureStruct {
2376-
root._computeOffsetForPureStructKeypath()
2315+
internal func _processOffsetForAppendedKeyPath(
2316+
appendedKeyPath: inout AnyKeyPath,
2317+
root: AnyKeyPath,
2318+
leaf: AnyKeyPath
2319+
) {
2320+
appendedKeyPath._isPureStructKeyPath = root.isPureStructKeyPath && leaf.isPureStructKeyPath
2321+
if let isPureStruct = appendedKeyPath._isPureStructKeyPath, isPureStruct {
2322+
appendedKeyPath._pureStructValueOffset = root._pureStructValueOffset + leaf
2323+
._pureStructValueOffset
23772324
}
23782325
}
23792326

@@ -2403,11 +2350,10 @@ internal func _tryToAppendKeyPaths<Result: AnyKeyPath>(
24032350
}
24042351
return _openExistential(rootValue, do: open2)
24052352
}
2406-
var returnValue:AnyKeyPath = _openExistential(rootRoot, do: open)
2407-
_processAppendingKeyPathType(root: &returnValue, leaf: leaf)
2408-
if let returnValue = returnValue as? Result
2409-
{
2410-
return returnValue
2353+
var returnValue: AnyKeyPath = _openExistential(rootRoot, do: open)
2354+
_processOffsetForAppendedKeyPath(appendedKeyPath: &returnValue, root: root, leaf: leaf)
2355+
if let returnValue = returnValue as? Result {
2356+
return returnValue
24112357
}
24122358
return nil
24132359
}
@@ -2555,7 +2501,7 @@ internal func _appendingKeyPaths<
25552501
return unsafeDowncast(result, to: Result.self)
25562502
}
25572503
}
2558-
_processAppendingKeyPathType(root: &returnValue, leaf: leaf)
2504+
_processOffsetForAppendedKeyPath(appendedKeyPath: &returnValue, root: root, leaf: leaf)
25592505
return returnValue as! Result
25602506
}
25612507

@@ -2639,12 +2585,33 @@ public func _swift_getKeyPath(pattern: UnsafeMutableRawPointer,
26392585
let (keyPathClass, rootType, size, _)
26402586
= _getKeyPathClassAndInstanceSizeFromPattern(patternPtr, arguments)
26412587

2588+
var offset = UInt32(0)
2589+
var isPureStruct = true
2590+
var keyPathBase: Any.Type?
26422591
// Allocate the instance.
26432592
let instance = keyPathClass._create(capacityInBytes: size) { instanceData in
26442593
// Instantiate the pattern into the instance.
2645-
_instantiateKeyPathBuffer(patternPtr, instanceData, rootType, arguments)
2594+
let returnValue = _instantiateKeyPathBuffer(patternPtr, instanceData, rootType, arguments)
2595+
offset += returnValue.structOffset
2596+
2597+
let booleans = returnValue.componentStructList
2598+
if(booleans.count == 0) {
2599+
isPureStruct = false
2600+
}
2601+
for value in booleans {
2602+
isPureStruct = isPureStruct && value
2603+
}
2604+
keyPathBase = rootType
26462605
}
26472606

2607+
// TODO: See if there's a better way to eliminate
2608+
// tuples from the current `isPureStruct` optimization.
2609+
if let keyPathBase = keyPathBase, instance.isTuple(keyPathBase) {
2610+
isPureStruct = false
2611+
}
2612+
instance._pureStructValueOffset = Int(offset)
2613+
instance._isPureStructKeyPath = isPureStruct
2614+
26482615
// Adopt the KVC string from the pattern.
26492616
let kvcStringBase = patternPtr.advanced(by: 12)
26502617
let kvcStringOffset = kvcStringBase.load(as: Int32.self)
@@ -2848,6 +2815,10 @@ internal protocol KeyPathPatternVisitor {
28482815
mutating func visitIntermediateComponentType(metadataRef: MetadataReference)
28492816

28502817
mutating func finish()
2818+
2819+
// Offset for pure-struct keypaths.
2820+
var structOffset: UInt32 { get set }
2821+
var isPureStruct: [Bool] { get set }
28512822
}
28522823

28532824
internal func _resolveRelativeAddress(_ base: UnsafeRawPointer,
@@ -3175,6 +3146,8 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
31753146
var leaf: Any.Type!
31763147
var genericEnvironment: UnsafeRawPointer?
31773148
let patternArgs: UnsafeRawPointer?
3149+
var structOffset: UInt32 = 0
3150+
var isPureStruct: [Bool] = []
31783151

31793152
init(patternArgs: UnsafeRawPointer?) {
31803153
self.patternArgs = patternArgs
@@ -3382,6 +3355,8 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
33823355
var genericEnvironment: UnsafeRawPointer?
33833356
let patternArgs: UnsafeRawPointer?
33843357
var base: Any.Type
3358+
var structOffset: UInt32 = 0
3359+
var isPureStruct: [Bool] = []
33853360

33863361
init(destData: UnsafeMutableRawBufferPointer,
33873362
patternArgs: UnsafeRawPointer?,
@@ -3454,6 +3429,12 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
34543429
mutable: Bool,
34553430
offset: KeyPathPatternStoredOffset) {
34563431
let previous = updatePreviousComponentAddr()
3432+
switch kind {
3433+
case .struct:
3434+
isPureStruct.append(true)
3435+
default:
3436+
isPureStruct.append(false)
3437+
}
34573438
switch kind {
34583439
case .class:
34593440
// A mutable class property can end the reference prefix.
@@ -3470,6 +3451,12 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
34703451
mutable: mutable,
34713452
inlineOffset: value)
34723453
pushDest(header)
3454+
switch kind {
3455+
case .struct:
3456+
structOffset += value
3457+
default:
3458+
break
3459+
}
34733460
case .outOfLine(let offset):
34743461
let header = RawKeyPathComponent.Header(storedWithOutOfLineOffset: kind,
34753462
mutable: mutable)
@@ -3515,6 +3502,7 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
35153502
setter: UnsafeRawPointer?,
35163503
arguments: KeyPathPatternComputedArguments?,
35173504
externalArgs: UnsafeBufferPointer<Int32>?) {
3505+
isPureStruct.append(false)
35183506
let previous = updatePreviousComponentAddr()
35193507
let settable = setter != nil
35203508
// A nonmutating settable property can end the reference prefix.
@@ -3654,22 +3642,26 @@ internal struct InstantiateKeyPathBuffer: KeyPathPatternVisitor {
36543642
}
36553643

36563644
mutating func visitOptionalChainComponent() {
3645+
isPureStruct.append(false)
36573646
let _ = updatePreviousComponentAddr()
36583647
let header = RawKeyPathComponent.Header(optionalChain: ())
36593648
pushDest(header)
36603649
}
36613650
mutating func visitOptionalWrapComponent() {
3651+
isPureStruct.append(false)
36623652
let _ = updatePreviousComponentAddr()
36633653
let header = RawKeyPathComponent.Header(optionalWrap: ())
36643654
pushDest(header)
36653655
}
36663656
mutating func visitOptionalForceComponent() {
3657+
isPureStruct.append(false)
36673658
let _ = updatePreviousComponentAddr()
36683659
let header = RawKeyPathComponent.Header(optionalForce: ())
36693660
pushDest(header)
36703661
}
36713662

36723663
mutating func visitIntermediateComponentType(metadataRef: MetadataReference) {
3664+
isPureStruct.append(false)
36733665
// Get the metadata for the intermediate type.
36743666
let metadata = _resolveKeyPathMetadataReference(
36753667
metadataRef,
@@ -3694,6 +3686,8 @@ internal struct ValidatingInstantiateKeyPathBuffer: KeyPathPatternVisitor {
36943686
var sizeVisitor: GetKeyPathClassAndInstanceSizeFromPattern
36953687
var instantiateVisitor: InstantiateKeyPathBuffer
36963688
let origDest: UnsafeMutableRawPointer
3689+
var structOffset: UInt32 = 0
3690+
var isPureStruct: [Bool] = []
36973691

36983692
init(sizeVisitor: GetKeyPathClassAndInstanceSizeFromPattern,
36993693
instantiateVisitor: InstantiateKeyPathBuffer) {
@@ -3795,7 +3789,7 @@ internal func _instantiateKeyPathBuffer(
37953789
_ origDestData: UnsafeMutableRawBufferPointer,
37963790
_ rootType: Any.Type,
37973791
_ arguments: UnsafeRawPointer
3798-
) {
3792+
) -> (structOffset: UInt32, componentStructList: [Bool]) {
37993793
let destHeaderPtr = origDestData.baseAddress.unsafelyUnwrapped
38003794
var destData = UnsafeMutableRawBufferPointer(
38013795
start: destHeaderPtr.advanced(by: MemoryLayout<Int>.size),
@@ -3847,6 +3841,7 @@ internal func _instantiateKeyPathBuffer(
38473841
endOfReferencePrefixComponent.storeBytes(of: componentHeader,
38483842
as: RawKeyPathComponent.Header.self)
38493843
}
3844+
return (walker.structOffset, walker.isPureStruct)
38503845
}
38513846

38523847
#if SWIFT_ENABLE_REFLECTION

0 commit comments

Comments
 (0)