掀起 SWIFT 的⾯面紗
下班⾃我進修裝屌指南
Pofat @ iPlayground
我是 Pofat
Clone 過 Android Source
Code 嗎
讀過 Android Source
Code 嗎?
對 Android Source Code
有什什麼感想?
起源
Swift Source Code 對⼯工作的幫助
0%
如何開始
# Install cmake and ninja
brew install cmake ninja
mkdir swift-source
cd swift-source
# Clone Swift project to local
git clone https://github.com/apple/swift.git
${ROOT} : swift-source here
如何開始 - utils
# use update-checkout update all required
repos
./swift/utils/update-checkout —clone
Compile 前準備
Compile!
# Partially debug message
./swift/utils/build-script --release-debuginfo
# Partially debug message
./swift/utils/build-script --debug
# Partially debug message
./swift/utils/build-script --release
檔案架構
檔案架構
# build path (bin, gyb result, tests…)
${ROOT}/build/Ninja-RelWithDebInfoAssert/
swift-macosx-x86_64
# executables
${ROOT}/build/Ninja-RelWithDebInfoAssert/
swift-macosx-x86_64/bin
${BUILD_ROOT} : ${ROOT}/build/Ninja-RelWithDebInfoAssert/
swift-macosx-x86_64/
檔案架構
# Original source file
${ROOT}/swift/stdlib/public/core
# Converted swift files from gyb
${ROOT}/build/Ninja-RelWithDebInfoAssert/
swift-macosx-x86_64/stdlib/public/core/8
GYB?
gyb --line-directive '' -o 

/path/to/Some.swift Some.swift.gyb
@_fixed_layout
public struct UInt8
: FixedWidthInteger, UnsignedInteger,
_ExpressibleByBuiltinIntegerLiteral {
/// A type that represents an integer literal.
public typealias IntegerLiteralType = UInt8
@_transparent
public init(_builtinIntegerLiteral x:
_MaxBuiltinIntegerType) {
_value = Builtin.s_to_u_checked_trunc_Int2048_Int8(x).0
}
@_transparent
public init(bitPattern x: Int8) {
_value = x._value
}
Tuple
let a = (1, 2, 3, 4, 5, 6)
let b = (1, 2, 3, 4, 5, 6)
print("a == b ? (a == b)")
a == b ? true
Tuple
let c = (1, 2, 3, 4, 5, 6, 7)
let d = (1, 2, 3, 4, 5, 6, 7)
print("c == d ? (c == d)")
error: binary operator '==' cannot be applied
to two '(Int, Int, Int, Int, Int, Int, Int)' operands
Tuple’s GYB
% for arity in range(2,7):

% typeParams = [chr(ord("A") + i) for i in range(arity)]

% tupleT = "({})".format(",".join(typeParams))

% equatableTypeParams = ", ".join(["{} : Equatable".format(c) for c in typeParams])

% originalTuple = "("a", {})".format(", ".join(map(str, range(1, arity))))

% greaterTuple = "("a", {})".format(", ".join(map(str, range(1, arity - 1) + [arity])))
// Tuple.swift.gyb
public func == <A : Comparable, B : Comparable, C :
Comparable, D : Comparable, E : Comparable, F :
Comparable>(lhs: (A,B,C,D,E,F), rhs: (A,B,C,D,E,F)) ->
Bool {

guard lhs.0 == rhs.0 { return false }
return (
lhs.1, lhs.2, lhs.3, lhs.4, lhs.5
) == (
rhs.1, rhs.2, rhs.3, rhs.4, rhs.5
)



}
// Tuple.swift
Optional
@_frozen
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
@_transparent
public init(_ some: Wrapped) { self = .some(some) }
@_transparent
public init(nilLiteral: ()) {
self = .none
}
}
Optional - Map
public func map<U>(
_ transform: (Wrapped) throws -> U
) rethrows -> U? {

switch self {
case .some(let y):
return .some(try transform(y))
case .none:
return .none
}
}
Optional - flatMap
public func flatMap<U>(
_ transform: (Wrapped) throws -> U
) rethrows -> U? {

switch self {
case .some(let y):
return try transform(y)
case .none:
return .none
}
}
Optional - Unwrap
@_transparent
public func ?? <T>(optional: T?,
defaultValue: @autoclosure () throws ->
T?)
rethrows -> T? {
switch optional {
case .some(let value):
return value
case .none:
return try defaultValue()
}
}
Bool
@_fixed_layout
public struct Bool {
@usableFromInline
internal var _value: Builtin.Int1
public init() {
let zero: Int8 = 0
self._value =
Builtin.trunc_Int8_Int1(zero._value)
}
}
ExpressibleByBooleanLiteral
extension Bool: ExpressibleByBooleanLiteral
{
@_transparent
public init(booleanLiteral value: Bool) {
self = value
}
}
How to @autoclosure
if measurement.count > 0 && sum / Double(measurement.count) < 5 {
// do somehting..
}
measurement.count might be ZERO!!
How to @autoclosure
@_transparent
@inline(__always)
public static func && (
lhs: Bool, rhs: @autoclosure () throws -> Bool)
rethrows -> Bool {
return lhs ? try rhs() : false
}
Attributes
• @inlinable :expose not interface but source code, work
when -O

• @_transparent: must do inline even when -Onone

• @_fixed_layout: Processed at SIL stage. It tells compiler
that access properties by offset is possible without
looking up metadata.



Attributes
• @usableFromInline : Temporarily change scope only
during inline stage. Include @inlinable















@_fixed_layout
public struct Bool {
@usableFromInline
internal var _value: Builtin.Int1
// …
What is Builtin ?
Builtin.Int1

Builtin.trunc_Int8_Int1(zero._value) 



Builtin.s_to_u_checked_trunc_Int2048_Int8(x)
Integer Again
public struct Int
: FixedWidthInteger, SignedInteger,
_ExpressibleByBuiltinIntegerLiteral {


public init(_builtinIntegerLiteral x:
_MaxBuiltinIntegerType) {
_value =
Builtin.s_to_s_checked_trunc_Int2048_Int64(x).0
}
+
public static func +(lhs: Int, rhs: Int) -> Int {
var lhs = lhs
lhs += rhs
return lhs
}
+=
public static func +=(lhs: inout Int, rhs: Int) {
let (result, overflow) =
Builtin.sadd_with_overflow_Int64(
lhs._value, rhs._value, true._value)
Builtin.condfail(overflow)
lhs = Int(result)
}
You may surprise…
• Int is a struct in standard library

• + is a global function declared in standard library

• What an inefficient way !! Do we really implement basic
arithmetic operations by cross-module function calls?



ObjC & Swift Compilation
Clang
Frontend
ObjC
LLVM
LLVM IR Machine Code
Swift
Frontend
Swift
IRGen
SIL Machine Code
LLVM
LLVM IR
Example
// sum.swift
let a = 1
let b = 2
let c = a + b
$swiftc -emit-ir sum.swift
LLVM IR
define i32 @main(i32, i8**) #0 {
entry:
%2 = bitcast i8** %1 to i8*
store i64 1, i64* getelementptr inbounds (%TSi, %TSi*
@"$S4test1aSivp", i32 0, i32 0), align 8
store i64 2, i64* getelementptr inbounds (%TSi, %TSi*
@"$S4test1bSivp", i32 0, i32 0), align 8
%3 = load i64, i64* getelementptr inbounds (%TSi, %TSi*
@"$S4test1aSivp", i32 0, i32 0), align 8
%4 = load i64, i64* getelementptr inbounds (%TSi, %TSi*
@"$S4test1bSivp", i32 0, i32 0), align 8
%5 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %3,
i64 %4)
%6 = extractvalue { i64, i1 } %5, 0
%7 = extractvalue { i64, i1 } %5, 1
br i1 %7, label %9, label %8
llvm::Intrinsic::ID
swift::getLLVMIntrinsicIDForBuiltinWithOverflow(BuiltinValue
Kind ID) {
switch (ID) {
default: break;
case BuiltinValueKind::SAddOver:
return llvm::Intrinsic::sadd_with_overflow;
case BuiltinValueKind::UAddOver:
return llvm::Intrinsic::uadd_with_overflow;
case BuiltinValueKind::SSubOver:
return llvm::Intrinsic::ssub_with_overflow;
case BuiltinValueKind::USubOver:
return llvm::Intrinsic::usub_with_overflow;
case BuiltinValueKind::SMulOver:
return llvm::Intrinsic::smul_with_overflow;
case BuiltinValueKind::UMulOver:
return llvm::Intrinsic::umul_with_overflow;
}
llvm_unreachable("Cannot convert the overflow builtin to
llvm intrinsic.");
}
${ROOT}/swift/lib/AST/Builtin.cpp
Builtin is a portal
LLVM IR Builtin
Builtin.type
Builtin.method
Standard
Library
TYPE
METHOD
SIL stage
How To Use Builtin.
// builtin_add.swift
import Swift
let (result, overflow) =
Builtin.sadd_with_overflow_Int64(1._value, 2._value,
true._getBuiltinLogicValue())
print(Int(result))
$swiftc -parse-stdlib builtin_add.swift && ./builtin_add
@usableFromInline
// builtin_add.swift
import Swift
let (result, overflow) =
Builtin.sadd_with_overflow_Int64(1._value, 2._value,
true._value)
print(Int(result))
error: '_value' is inaccessible due to 'internal' protection level
Sequence
https://swiftdoc.org/v4.2/protocol/sequence/hierarchy/
Sequence
public protocol Sequence {
associatedtype Element
associatedtype Iterator : IteratorProtocol where
Iterator.Element == Element
func makeIterator() -> Iterator
}

public protocol IteratorProtocol {
mutating func next() -> Element?
}
Sequence
public protocol Sequence {
associatedtype Element
associatedtype Iterator : IteratorProtocol where
Iterator.Element == Element
func makeIterator() -> Iterator
}

public protocol IteratorProtocol {
mutating func next() -> Element?
}
for (index, value) in mySeq.enumerated() {
// do seomthing ...
}
O(1)
Enumerated
/// - Complexity: O(1)
@inlinabl
public func enumerated() -> EnumeratedSequence<Self> {
return EnumeratedSequence(_base: self)
}
Enumerated
public struct EnumeratedSequence<Base: Sequence> {
internal var _base: Base
internal init(_base: Base) {
self._base = _base
}
}
for-in EnumeratedSequence
extension EnumeratedSequence {
public struct Iterator {
internal var _base: Base.Iterator
internal var _count: Int
internal init(_base: Base.Iterator) {
self._base = _base
self._count = 0
}
}
}
for-in EnumeratedSequence
extension EnumeratedSequence.Iterator: IteratorProtocol, Sequence
{
public typealias Element = (offset: Int, element: Base.Element)
public mutating func next() -> Element? {
guard let b = _base.next() else { return nil }
let result = (offset: _count, element: b)
_count += 1
return result
}
}
Map
public func map<T>(
_ transform: (Element) throws -> T
) rethrows -> [T] {

let initialCapacity = underestimatedCount
var result = ContiguousArray<T>()
result.reserveCapacity(initialCapacity)
var iterator = self.makeIterator()
// lower half of map func
Map
// upper half of map func
for _ in 0..<initialCapacity {
result.append(try transform(iterator.next()!))
}
while let element = iterator.next() {
result.append(try transform(element))
}
return Array(result)
}
Reduce
public func reduce<Result>(
_ initialResult: Result,
_ nextPartialResult:
(_ partialResult: Result, Element) throws -> Result
) rethrows -> Result {

var accumulator = initialResult
for element in self {
accumulator = try nextPartialResult(accumulator,
element)
}

return accumulator
}
Reduce Into
public func reduce<Result>(
into initialResult: Result,
_ updateAccumulatingResult:
(_ partialResult: inout Result, Element) throws ->
()
) rethrows -> Result {
var accumulator = initialResult
for element in self {
try updateAccumulatingResult(&accumulator, element)
}
return accumulator
}
}
flatMap
public func flatMap<SegmentOfResult : Sequence>(
_ transform: (Element) throws -> SegmentOfResult
) rethrows -> [SegmentOfResult.Element] {

var result: [SegmentOfResult.Element] = []
for element in self {
result.append(contentsOf: try
transform(element))
}

return result
}
compactMap
public func compactMap<ElementOfResult>(
_ transform: (Element) throws ->
ElementOfResult?
) rethrows -> [ElementOfResult] {

return try _compactMap(transform)

}
public func _compactMap<ElementOfResult>(
_ transform: (Element) throws ->
ElementOfResult?
) rethrows -> [ElementOfResult] {

var result: [ElementOfResult] = []

for element in self {
if let newElement = try transform(element) {
result.append(newElement)
}
}

return result
}
They are EAGER
class FileReadIterator: IteratorProtocol {


private let handler =
FileHandle(forReadingAtPath: "/path/to/large_file")!
func next() -> UInt8? {
let data = handler.readData(ofLength: 1)
return data[0]
}


deinit {
handler.closeFile()
}
}
let fileSequence = AnySequence { FileReadIterator() }

let batchOperation = fileSequence.map{ print($0) }
Make It LAZY
Lazy Sequence
extension Sequence {

public var lazy: LazySequence<Self> {
return LazySequence(_base: self)
}

}
LazySequence
public struct LazySequence<Base : Sequence>:
_SequenceWrapper {

public var _base: Base
internal init(_base: Base) {
self._base = _base
}
}
LazySequenceProtocol
extension LazySequenceProtocol {
public func map<U>(
_ transform: @escaping (Elements.Element) -> U
) -> LazyMapSequence<Self.Elements, U> {
return LazyMapSequence(_base: self.elements,
transform: transform)
}
}
public struct LazyMapSequence<Base : Sequence,
Element> {
internal var _base: Base
internal let _transform: (Base.Element) -> Element
internal init(_base: Base, transform: @escaping
(Base.Element) -> Element) {

self._base = _base
self._transform = transform

}
}
extension LazyMapSequence.Iterator:
IteratorProtocol, Sequence {
public mutating func next() -> Element? {

return _base.next().map(_transform)

}
}
File Reader Revised
let fileSequence = AnySequence { FileReadIterator() }

let lazyBatch = fileSequence.lazy.map{ print($0)}
var batchIterator = lazyBatch.makeIterator()
for _ in 1 ... 10 {
batchIterator.next()
}
File Reader Revised
let fileSequence = AnySequence { FileReadIterator() }

let lazyBatch = fileSequence.lazy.map{ print($0)}
var batchIterator = lazyBatch.makeIterator()
for _ in 1 ... 1024 {
batchIterator.next()
}
Collection
https://swiftdoc.org/v4.2/protocol/collection/hierarchy/
Collection remove(at:)
problem
for obj in objsToDelete {
myCollection.remove(at: myCollection.index(of: obj)!)
}
O(N)
Collection
removeAll(where:)
extension RangeReplaceableCollection {

public mutating func removeAll(
where shouldBeRemoved: (Element) throws -> Bool
) rethrows {

let suffixStart = try _halfStablePartition(isSuffixElement:
shouldBeRemoved)

removeSubrange(suffixStart…)
}
}
mutating func _halfStablePartition(
isSuffixElement: (Element) throws -> Bool
) rethrows -> Index {

guard var i = try firstIndex(where: isSuffixElement)
else { return endIndex }
var j = index(after: i)
while j != endIndex {
if try !isSuffixElement(self[j]) { swapAt(i, j);
formIndex(after: &i) }
formIndex(after: &j)
}

return i
}
mutating func _halfStablePartition(
isSuffixElement: (Element) throws -> Bool
) rethrows -> Index {

guard var i = try firstIndex(where: isSuffixElement)
else { return endIndex }
var j = index(after: i)

while j != endIndex {
if try !isSuffixElement(self[j]) {
swapAt(i, j)
formIndex(after: &i)
}
formIndex(after: &j)
}

return i
}
OH! It’s moving zeros!
Array
Inside Array
public struct Array<Element>: _DestructorSafeContainer {
#if _runtime(_ObjC)
internal typealias _Buffer = _ArrayBuffer<Element>
#endif
internal var _buffer: _Buffer
internal init(_buffer: _Buffer) {
self._buffer = _buffer
}
}
struct Array
_buffer
struct _ArrayBuffer
_storage
struct _BridgStorage
_rawValue
Contiguous Array

or
NSArray
Builtin.BridgeObject
Copy On Write
mutating func append(_ newElement: __owned Element)
{
_makeUniqueAndReserveCapacityIfNotUnique()

let oldCount = _getCount()
_reserveCapacityAssumingUniqueBuffer(oldCount:
oldCount)

_appendElementAssumeUniqueAndCapacity(oldCount,
newElement: newElement)
}
Copy If Not Unique
mutating func _makeUniqueAndReserveCapacityIfNotUnique() {
if _slowPath(!
_buffer.isMutableAndUniquelyReferenced()) {
_copyToNewBuffer(oldCount: _buffer.count)
}
}
isUnique
mutating func isMutableAndUniquelyReferenced() ->
Bool {
return isUniquelyReferenced()
}

isUnique
mutating func isUniquelyReferenced() -> Bool {

if !_isClassOrObjCExistential(Element.self) {
return
_storage.isUniquelyReferenced_native_noSpareBits()
}
if !_storage.isUniquelyReferencedNative() {
return false
}

return _isNative
}

Copy To New Buffer
mutating func _copyToNewBuffer(oldCount: Int) {
let newCount = oldCount + 1
var newBuffer =
_buffer._forceCreateUniqueMutableBuffer(
countForNewBuffer: oldCount, minNewCapacity:
newCount)
_buffer._arrayOutOfPlaceUpdate(&newBuffer,
oldCount, 0)
}
What If Reach Full Capacity
func _forceCreateUniqueMutableBufferImpl(
countForBuffer: Int, minNewCapacity: Int,
requiredCapacity: Int
) -> _ContiguousArrayBuffer<Element> {
let minimumCapacity = Swift.max(requiredCapacity,
minNewCapacity > capacity
? _growArrayCapacity(capacity) : capacity)
return _ContiguousArrayBuffer(
_uninitializedCount: countForBuffer, minimumCapacity:
minimumCapacity)
}
Array Grow
func _growArrayCapacity(_ capacity: Int) -> Int {
return capacity * 2
}
Array Is Not Thread Safe
import Dispatch
var array = [Int]()
DispatchQueue.concurrentPerform(iterations: 50)
{ index in
let last = array.last ?? 0
array.append(last + 1)
}
print("array count: (array.count)")
var array = [1, 2, 3, 4, 5]
let arrayAccessQueue = DispatchQueue(label: "array",
qos: .utility, attributes: .concurrent)
// read
var readValue: Int = 0
arrayAccessQueue.sync {
readValue = array[0]
}
// write
arrayAccessQueue.async(flags: .barrier) {
array.append(6)
}
// thread_safe_access_array.swift
Sorting Array
mutating func sort(
by areInIncreasingOrder: (Element, Element) throws ->
Bool
) rethrows {
let didSortUnsafeBuffer = try
_withUnsafeMutableBufferPointerIfSupported {
buffer -> Void? in
try buffer.sort(by: areInIncreasingOrder)
}
if didSortUnsafeBuffer == nil {
try _introSort(within: startIndex..<endIndex, by:
areInIncreasingOrder)
}
}
Insertion / Intro / Heap
mutating func _introSortImpl(
within range: Range<Index>,
by areInIncreasingOrder: (Element, Element) throws -> Bool,
depthLimit: Int
) rethrows {
if distance(from: range.lowerBound, to: range.upperBound) < 20 {
try _insertionSort(within: range, by: areInIncreasingOrder)
} else if depthLimit == 0 {
try _heapSort(within: range, by: areInIncreasingOrder)
} else {
let partIdx = try _partition(within: range, by: areInIncreasingOrder)
try _introSortImpl(
within: range.lowerBound..<partIdx,
by: areInIncreasingOrder,
depthLimit: depthLimit &- 1)
try _introSortImpl(
within: partIdx..<range.upperBound,
by: areInIncreasingOrder,
depthLimit: depthLimit &- 1)
}
}
Sorting Strategy
mutating func _introSortImpl(
within range: Range<Index>,
by areInIncreasingOrder: (Element, Element) throws -> Bool,
depthLimit: Int
) rethrows {
if distance(from: range.lowerBound, to: range.upperBound) < 20 {
try _insertionSort(within: range, by: areInIncreasingOrder)
} else if depthLimit == 0 {
try _heapSort(within: range, by: areInIncreasingOrder)
} else {
let partIdx = try _partition(within: range, by: areInIncreasingOrder)
try _introSortImpl(
within: range.lowerBound..<partIdx,
by: areInIncreasingOrder,
depthLimit: depthLimit &- 1)
try _introSortImpl(
within: partIdx..<range.upperBound,
by: areInIncreasingOrder,
depthLimit: depthLimit &- 1)
}
}
Sorting Strategy
mutating func _introSortImpl(
within range: Range<Index>,
by areInIncreasingOrder: (Element, Element) throws -> Bool,
depthLimit: Int
) rethrows {
if distance(from: range.lowerBound, to: range.upperBound) < 20 {
try _insertionSort(within: range, by: areInIncreasingOrder)
} else if depthLimit == 0 {
try _heapSort(within: range, by: areInIncreasingOrder)
} else {
let partIdx = try _partition(within: range, by: areInIncreasingOrder)
try _introSortImpl(
within: range.lowerBound..<partIdx,
by: areInIncreasingOrder,
depthLimit: depthLimit &- 1)
try _introSortImpl(
within: partIdx..<range.upperBound,
by: areInIncreasingOrder,
depthLimit: depthLimit &- 1)
}
}
Develop Swift !!
Better Reduce:
User first element in sequence as initial value
Test FIRST!
SequenceTypeTests.test("betterReduce") {
let animals = ["Antelope", "Butterfly", "Camel",
“Dolphin"]
var timesClosureWasCalled = 0
let longestAnimal = animals.betterReduce
{ current, animal in
timesClousreWasCalled += 1
if current.count > animal.count {
return current
} else {
return animal
}
} ?? “"
// expects …
}
// ${ROOT}/swift/validation-test/stdlib/SequenceType.swift.gyb
SequenceTypeTests.test("betterReduce") {
// Codes …
expectEqual(longestAnimal, “Butterfly")
expectEqual(
animals.count, timesClosureWasCalled,
"betterReduce() should be eager”)
}
// ${ROOT}/swift/validation-test/stdlib/SequenceType.swift.gyb
Now CODE!!
// SequenceAlgorithm.swift — extension Sequence
@inlinable
public func betterReduce(
_ nextPartialResult:
(_ partialResult: Element, Element) throws -> Element
) rethrows -> Element? {

var i = makeIterator()
guard var accumulated = i.next() else {
return nil
}
while let element = i.next() {
accumulated = try nextPartialResult(accumulated,
element)
}
return accumulated
}
Test Swift!!
./swift/utils/build-script -r -tCompile and test
./swift/utils/build-script -r -T
Compile and
validation test
4XXX tests!!
10000+ tests!!
Test Standard Library Only
./llvm/utils/lit/lit.py -sv ${BUILD_ROOT}/swift-
macosx-x86_64/test-macosx-x86_64/stdlib
A full-test run is suggested in the first place
./llvm/utils/lit/lit.py -sv ${BUILD_ROOT}/
swift-macosx-x86_64/validation-test-macosx-
x86_64/stdlib
sh ${BUILD_ROOT}/validation-test-macosx-x86_64/stdlib/Output/
Bool.swift.script
Now you can do single test with
Wait!
Not compiled yet…
${BUILD_ROOT} ninja swift-stdlib
Thanks to ninja, lets build standard library only
sh ${BUILD_RTTO}/validation-test-macosx-x86_64/

stdlib/Output/SequenceType.swift.gyb.script
And do test!!
😎
所以,看 Source
Code到底有何幫助??
參參考來來源
• https://github.com/apple/swift

• 喵神 Swift 标准库源码导读 
我的裝屌指南系列列
• EP I: GitHub 裝屌指南

• EP II: Vim 裝屌指南

• EP III: Debug 裝屌指南
講完惹
關愛 Swift 發展者或想討論 ,歡迎和我聯聯繫 tjazzterATgmailDOTcom

掀起 Swift 的面紗

  • 1.
  • 2.
  • 3.
    Clone 過 AndroidSource Code 嗎 讀過 Android Source Code 嗎? 對 Android Source Code 有什什麼感想? 起源
  • 4.
    Swift Source Code對⼯工作的幫助 0%
  • 5.
    如何開始 # Install cmakeand ninja brew install cmake ninja mkdir swift-source cd swift-source # Clone Swift project to local git clone https://github.com/apple/swift.git ${ROOT} : swift-source here
  • 6.
  • 7.
    # use update-checkoutupdate all required repos ./swift/utils/update-checkout —clone
  • 8.
  • 9.
    Compile! # Partially debugmessage ./swift/utils/build-script --release-debuginfo # Partially debug message ./swift/utils/build-script --debug # Partially debug message ./swift/utils/build-script --release
  • 10.
  • 11.
    檔案架構 # build path(bin, gyb result, tests…) ${ROOT}/build/Ninja-RelWithDebInfoAssert/ swift-macosx-x86_64 # executables ${ROOT}/build/Ninja-RelWithDebInfoAssert/ swift-macosx-x86_64/bin ${BUILD_ROOT} : ${ROOT}/build/Ninja-RelWithDebInfoAssert/ swift-macosx-x86_64/
  • 12.
    檔案架構 # Original sourcefile ${ROOT}/swift/stdlib/public/core # Converted swift files from gyb ${ROOT}/build/Ninja-RelWithDebInfoAssert/ swift-macosx-x86_64/stdlib/public/core/8
  • 13.
    GYB? gyb --line-directive ''-o 
 /path/to/Some.swift Some.swift.gyb
  • 14.
    @_fixed_layout public struct UInt8 :FixedWidthInteger, UnsignedInteger, _ExpressibleByBuiltinIntegerLiteral { /// A type that represents an integer literal. public typealias IntegerLiteralType = UInt8 @_transparent public init(_builtinIntegerLiteral x: _MaxBuiltinIntegerType) { _value = Builtin.s_to_u_checked_trunc_Int2048_Int8(x).0 } @_transparent public init(bitPattern x: Int8) { _value = x._value }
  • 15.
    Tuple let a =(1, 2, 3, 4, 5, 6) let b = (1, 2, 3, 4, 5, 6) print("a == b ? (a == b)") a == b ? true
  • 16.
    Tuple let c =(1, 2, 3, 4, 5, 6, 7) let d = (1, 2, 3, 4, 5, 6, 7) print("c == d ? (c == d)") error: binary operator '==' cannot be applied to two '(Int, Int, Int, Int, Int, Int, Int)' operands
  • 17.
    Tuple’s GYB % forarity in range(2,7): % typeParams = [chr(ord("A") + i) for i in range(arity)] % tupleT = "({})".format(",".join(typeParams)) % equatableTypeParams = ", ".join(["{} : Equatable".format(c) for c in typeParams]) % originalTuple = "("a", {})".format(", ".join(map(str, range(1, arity)))) % greaterTuple = "("a", {})".format(", ".join(map(str, range(1, arity - 1) + [arity]))) // Tuple.swift.gyb
  • 18.
    public func ==<A : Comparable, B : Comparable, C : Comparable, D : Comparable, E : Comparable, F : Comparable>(lhs: (A,B,C,D,E,F), rhs: (A,B,C,D,E,F)) -> Bool {
 guard lhs.0 == rhs.0 { return false } return ( lhs.1, lhs.2, lhs.3, lhs.4, lhs.5 ) == ( rhs.1, rhs.2, rhs.3, rhs.4, rhs.5 )
 
 } // Tuple.swift
  • 19.
    Optional @_frozen public enum Optional<Wrapped>: ExpressibleByNilLiteral { case none case some(Wrapped) @_transparent public init(_ some: Wrapped) { self = .some(some) } @_transparent public init(nilLiteral: ()) { self = .none } }
  • 20.
    Optional - Map publicfunc map<U>( _ transform: (Wrapped) throws -> U ) rethrows -> U? {
 switch self { case .some(let y): return .some(try transform(y)) case .none: return .none } }
  • 21.
    Optional - flatMap publicfunc flatMap<U>( _ transform: (Wrapped) throws -> U ) rethrows -> U? {
 switch self { case .some(let y): return try transform(y) case .none: return .none } }
  • 22.
    Optional - Unwrap @_transparent publicfunc ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T? { switch optional { case .some(let value): return value case .none: return try defaultValue() } }
  • 23.
    Bool @_fixed_layout public struct Bool{ @usableFromInline internal var _value: Builtin.Int1 public init() { let zero: Int8 = 0 self._value = Builtin.trunc_Int8_Int1(zero._value) } }
  • 24.
  • 25.
    How to @autoclosure ifmeasurement.count > 0 && sum / Double(measurement.count) < 5 { // do somehting.. } measurement.count might be ZERO!!
  • 26.
    How to @autoclosure @_transparent @inline(__always) publicstatic func && ( lhs: Bool, rhs: @autoclosure () throws -> Bool) rethrows -> Bool { return lhs ? try rhs() : false }
  • 27.
    Attributes • @inlinable :exposenot interface but source code, work when -O • @_transparent: must do inline even when -Onone • @_fixed_layout: Processed at SIL stage. It tells compiler that access properties by offset is possible without looking up metadata.
 

  • 28.
    Attributes • @usableFromInline :Temporarily change scope only during inline stage. Include @inlinable
 
 
 
 
 
 
 
 @_fixed_layout public struct Bool { @usableFromInline internal var _value: Builtin.Int1 // …
  • 29.
    What is Builtin? Builtin.Int1
 Builtin.trunc_Int8_Int1(zero._value) 
 
 Builtin.s_to_u_checked_trunc_Int2048_Int8(x)
  • 30.
    Integer Again public structInt : FixedWidthInteger, SignedInteger, _ExpressibleByBuiltinIntegerLiteral { 
 public init(_builtinIntegerLiteral x: _MaxBuiltinIntegerType) { _value = Builtin.s_to_s_checked_trunc_Int2048_Int64(x).0 }
  • 31.
    + public static func+(lhs: Int, rhs: Int) -> Int { var lhs = lhs lhs += rhs return lhs }
  • 32.
    += public static func+=(lhs: inout Int, rhs: Int) { let (result, overflow) = Builtin.sadd_with_overflow_Int64( lhs._value, rhs._value, true._value) Builtin.condfail(overflow) lhs = Int(result) }
  • 33.
    You may surprise… •Int is a struct in standard library • + is a global function declared in standard library • What an inefficient way !! Do we really implement basic arithmetic operations by cross-module function calls?
 

  • 35.
    ObjC & SwiftCompilation Clang Frontend ObjC LLVM LLVM IR Machine Code Swift Frontend Swift IRGen SIL Machine Code LLVM LLVM IR
  • 36.
    Example // sum.swift let a= 1 let b = 2 let c = a + b $swiftc -emit-ir sum.swift
  • 37.
    LLVM IR define i32@main(i32, i8**) #0 { entry: %2 = bitcast i8** %1 to i8* store i64 1, i64* getelementptr inbounds (%TSi, %TSi* @"$S4test1aSivp", i32 0, i32 0), align 8 store i64 2, i64* getelementptr inbounds (%TSi, %TSi* @"$S4test1bSivp", i32 0, i32 0), align 8 %3 = load i64, i64* getelementptr inbounds (%TSi, %TSi* @"$S4test1aSivp", i32 0, i32 0), align 8 %4 = load i64, i64* getelementptr inbounds (%TSi, %TSi* @"$S4test1bSivp", i32 0, i32 0), align 8 %5 = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %3, i64 %4) %6 = extractvalue { i64, i1 } %5, 0 %7 = extractvalue { i64, i1 } %5, 1 br i1 %7, label %9, label %8
  • 38.
    llvm::Intrinsic::ID swift::getLLVMIntrinsicIDForBuiltinWithOverflow(BuiltinValue Kind ID) { switch(ID) { default: break; case BuiltinValueKind::SAddOver: return llvm::Intrinsic::sadd_with_overflow; case BuiltinValueKind::UAddOver: return llvm::Intrinsic::uadd_with_overflow; case BuiltinValueKind::SSubOver: return llvm::Intrinsic::ssub_with_overflow; case BuiltinValueKind::USubOver: return llvm::Intrinsic::usub_with_overflow; case BuiltinValueKind::SMulOver: return llvm::Intrinsic::smul_with_overflow; case BuiltinValueKind::UMulOver: return llvm::Intrinsic::umul_with_overflow; } llvm_unreachable("Cannot convert the overflow builtin to llvm intrinsic."); } ${ROOT}/swift/lib/AST/Builtin.cpp
  • 39.
    Builtin is aportal LLVM IR Builtin Builtin.type Builtin.method Standard Library TYPE METHOD SIL stage
  • 40.
    How To UseBuiltin. // builtin_add.swift import Swift let (result, overflow) = Builtin.sadd_with_overflow_Int64(1._value, 2._value, true._getBuiltinLogicValue()) print(Int(result)) $swiftc -parse-stdlib builtin_add.swift && ./builtin_add
  • 41.
    @usableFromInline // builtin_add.swift import Swift let(result, overflow) = Builtin.sadd_with_overflow_Int64(1._value, 2._value, true._value) print(Int(result)) error: '_value' is inaccessible due to 'internal' protection level
  • 42.
  • 43.
    Sequence public protocol Sequence{ associatedtype Element associatedtype Iterator : IteratorProtocol where Iterator.Element == Element func makeIterator() -> Iterator }
 public protocol IteratorProtocol { mutating func next() -> Element? }
  • 44.
    Sequence public protocol Sequence{ associatedtype Element associatedtype Iterator : IteratorProtocol where Iterator.Element == Element func makeIterator() -> Iterator }
 public protocol IteratorProtocol { mutating func next() -> Element? }
  • 45.
    for (index, value)in mySeq.enumerated() { // do seomthing ... } O(1)
  • 46.
    Enumerated /// - Complexity:O(1) @inlinabl public func enumerated() -> EnumeratedSequence<Self> { return EnumeratedSequence(_base: self) }
  • 47.
    Enumerated public struct EnumeratedSequence<Base:Sequence> { internal var _base: Base internal init(_base: Base) { self._base = _base } }
  • 48.
    for-in EnumeratedSequence extension EnumeratedSequence{ public struct Iterator { internal var _base: Base.Iterator internal var _count: Int internal init(_base: Base.Iterator) { self._base = _base self._count = 0 } } }
  • 49.
    for-in EnumeratedSequence extension EnumeratedSequence.Iterator:IteratorProtocol, Sequence { public typealias Element = (offset: Int, element: Base.Element) public mutating func next() -> Element? { guard let b = _base.next() else { return nil } let result = (offset: _count, element: b) _count += 1 return result } }
  • 50.
    Map public func map<T>( _transform: (Element) throws -> T ) rethrows -> [T] {
 let initialCapacity = underestimatedCount var result = ContiguousArray<T>() result.reserveCapacity(initialCapacity) var iterator = self.makeIterator() // lower half of map func
  • 51.
    Map // upper halfof map func for _ in 0..<initialCapacity { result.append(try transform(iterator.next()!)) } while let element = iterator.next() { result.append(try transform(element)) } return Array(result) }
  • 52.
    Reduce public func reduce<Result>( _initialResult: Result, _ nextPartialResult: (_ partialResult: Result, Element) throws -> Result ) rethrows -> Result {
 var accumulator = initialResult for element in self { accumulator = try nextPartialResult(accumulator, element) }
 return accumulator }
  • 53.
    Reduce Into public funcreduce<Result>( into initialResult: Result, _ updateAccumulatingResult: (_ partialResult: inout Result, Element) throws -> () ) rethrows -> Result { var accumulator = initialResult for element in self { try updateAccumulatingResult(&accumulator, element) } return accumulator } }
  • 54.
    flatMap public func flatMap<SegmentOfResult: Sequence>( _ transform: (Element) throws -> SegmentOfResult ) rethrows -> [SegmentOfResult.Element] {
 var result: [SegmentOfResult.Element] = [] for element in self { result.append(contentsOf: try transform(element)) }
 return result }
  • 55.
    compactMap public func compactMap<ElementOfResult>( _transform: (Element) throws -> ElementOfResult? ) rethrows -> [ElementOfResult] {
 return try _compactMap(transform)
 }
  • 56.
    public func _compactMap<ElementOfResult>( _transform: (Element) throws -> ElementOfResult? ) rethrows -> [ElementOfResult] {
 var result: [ElementOfResult] = []
 for element in self { if let newElement = try transform(element) { result.append(newElement) } }
 return result }
  • 57.
  • 58.
    class FileReadIterator: IteratorProtocol{ 
 private let handler = FileHandle(forReadingAtPath: "/path/to/large_file")! func next() -> UInt8? { let data = handler.readData(ofLength: 1) return data[0] } 
 deinit { handler.closeFile() } }
  • 59.
    let fileSequence =AnySequence { FileReadIterator() }
 let batchOperation = fileSequence.map{ print($0) }
  • 60.
  • 61.
    Lazy Sequence extension Sequence{
 public var lazy: LazySequence<Self> { return LazySequence(_base: self) }
 }
  • 62.
    LazySequence public struct LazySequence<Base: Sequence>: _SequenceWrapper {
 public var _base: Base internal init(_base: Base) { self._base = _base } }
  • 63.
    LazySequenceProtocol extension LazySequenceProtocol { publicfunc map<U>( _ transform: @escaping (Elements.Element) -> U ) -> LazyMapSequence<Self.Elements, U> { return LazyMapSequence(_base: self.elements, transform: transform) } }
  • 64.
    public struct LazyMapSequence<Base: Sequence, Element> { internal var _base: Base internal let _transform: (Base.Element) -> Element internal init(_base: Base, transform: @escaping (Base.Element) -> Element) {
 self._base = _base self._transform = transform
 } }
  • 65.
    extension LazyMapSequence.Iterator: IteratorProtocol, Sequence{ public mutating func next() -> Element? {
 return _base.next().map(_transform)
 } }
  • 66.
    File Reader Revised letfileSequence = AnySequence { FileReadIterator() }
 let lazyBatch = fileSequence.lazy.map{ print($0)} var batchIterator = lazyBatch.makeIterator() for _ in 1 ... 10 { batchIterator.next() }
  • 67.
    File Reader Revised letfileSequence = AnySequence { FileReadIterator() }
 let lazyBatch = fileSequence.lazy.map{ print($0)} var batchIterator = lazyBatch.makeIterator() for _ in 1 ... 1024 { batchIterator.next() }
  • 68.
  • 69.
    Collection remove(at:) problem for objin objsToDelete { myCollection.remove(at: myCollection.index(of: obj)!) } O(N)
  • 70.
    Collection removeAll(where:) extension RangeReplaceableCollection {
 publicmutating func removeAll( where shouldBeRemoved: (Element) throws -> Bool ) rethrows {
 let suffixStart = try _halfStablePartition(isSuffixElement: shouldBeRemoved)
 removeSubrange(suffixStart…) } }
  • 71.
    mutating func _halfStablePartition( isSuffixElement:(Element) throws -> Bool ) rethrows -> Index {
 guard var i = try firstIndex(where: isSuffixElement) else { return endIndex } var j = index(after: i) while j != endIndex { if try !isSuffixElement(self[j]) { swapAt(i, j); formIndex(after: &i) } formIndex(after: &j) }
 return i }
  • 72.
    mutating func _halfStablePartition( isSuffixElement:(Element) throws -> Bool ) rethrows -> Index {
 guard var i = try firstIndex(where: isSuffixElement) else { return endIndex } var j = index(after: i)
 while j != endIndex { if try !isSuffixElement(self[j]) { swapAt(i, j) formIndex(after: &i) } formIndex(after: &j) }
 return i } OH! It’s moving zeros!
  • 73.
  • 74.
    Inside Array public structArray<Element>: _DestructorSafeContainer { #if _runtime(_ObjC) internal typealias _Buffer = _ArrayBuffer<Element> #endif internal var _buffer: _Buffer internal init(_buffer: _Buffer) { self._buffer = _buffer } }
  • 75.
    struct Array _buffer struct _ArrayBuffer _storage struct_BridgStorage _rawValue Contiguous Array
 or NSArray Builtin.BridgeObject
  • 77.
    Copy On Write mutatingfunc append(_ newElement: __owned Element) { _makeUniqueAndReserveCapacityIfNotUnique()
 let oldCount = _getCount() _reserveCapacityAssumingUniqueBuffer(oldCount: oldCount)
 _appendElementAssumeUniqueAndCapacity(oldCount, newElement: newElement) }
  • 78.
    Copy If NotUnique mutating func _makeUniqueAndReserveCapacityIfNotUnique() { if _slowPath(! _buffer.isMutableAndUniquelyReferenced()) { _copyToNewBuffer(oldCount: _buffer.count) } }
  • 79.
    isUnique mutating func isMutableAndUniquelyReferenced()-> Bool { return isUniquelyReferenced() }

  • 80.
    isUnique mutating func isUniquelyReferenced()-> Bool {
 if !_isClassOrObjCExistential(Element.self) { return _storage.isUniquelyReferenced_native_noSpareBits() } if !_storage.isUniquelyReferencedNative() { return false }
 return _isNative }

  • 81.
    Copy To NewBuffer mutating func _copyToNewBuffer(oldCount: Int) { let newCount = oldCount + 1 var newBuffer = _buffer._forceCreateUniqueMutableBuffer( countForNewBuffer: oldCount, minNewCapacity: newCount) _buffer._arrayOutOfPlaceUpdate(&newBuffer, oldCount, 0) }
  • 82.
    What If ReachFull Capacity func _forceCreateUniqueMutableBufferImpl( countForBuffer: Int, minNewCapacity: Int, requiredCapacity: Int ) -> _ContiguousArrayBuffer<Element> { let minimumCapacity = Swift.max(requiredCapacity, minNewCapacity > capacity ? _growArrayCapacity(capacity) : capacity) return _ContiguousArrayBuffer( _uninitializedCount: countForBuffer, minimumCapacity: minimumCapacity) }
  • 83.
    Array Grow func _growArrayCapacity(_capacity: Int) -> Int { return capacity * 2 }
  • 84.
    Array Is NotThread Safe import Dispatch var array = [Int]() DispatchQueue.concurrentPerform(iterations: 50) { index in let last = array.last ?? 0 array.append(last + 1) } print("array count: (array.count)")
  • 85.
    var array =[1, 2, 3, 4, 5] let arrayAccessQueue = DispatchQueue(label: "array", qos: .utility, attributes: .concurrent) // read var readValue: Int = 0 arrayAccessQueue.sync { readValue = array[0] } // write arrayAccessQueue.async(flags: .barrier) { array.append(6) } // thread_safe_access_array.swift
  • 86.
    Sorting Array mutating funcsort( by areInIncreasingOrder: (Element, Element) throws -> Bool ) rethrows { let didSortUnsafeBuffer = try _withUnsafeMutableBufferPointerIfSupported { buffer -> Void? in try buffer.sort(by: areInIncreasingOrder) } if didSortUnsafeBuffer == nil { try _introSort(within: startIndex..<endIndex, by: areInIncreasingOrder) } }
  • 87.
    Insertion / Intro/ Heap mutating func _introSortImpl( within range: Range<Index>, by areInIncreasingOrder: (Element, Element) throws -> Bool, depthLimit: Int ) rethrows { if distance(from: range.lowerBound, to: range.upperBound) < 20 { try _insertionSort(within: range, by: areInIncreasingOrder) } else if depthLimit == 0 { try _heapSort(within: range, by: areInIncreasingOrder) } else { let partIdx = try _partition(within: range, by: areInIncreasingOrder) try _introSortImpl( within: range.lowerBound..<partIdx, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) try _introSortImpl( within: partIdx..<range.upperBound, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) } }
  • 88.
    Sorting Strategy mutating func_introSortImpl( within range: Range<Index>, by areInIncreasingOrder: (Element, Element) throws -> Bool, depthLimit: Int ) rethrows { if distance(from: range.lowerBound, to: range.upperBound) < 20 { try _insertionSort(within: range, by: areInIncreasingOrder) } else if depthLimit == 0 { try _heapSort(within: range, by: areInIncreasingOrder) } else { let partIdx = try _partition(within: range, by: areInIncreasingOrder) try _introSortImpl( within: range.lowerBound..<partIdx, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) try _introSortImpl( within: partIdx..<range.upperBound, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) } }
  • 89.
    Sorting Strategy mutating func_introSortImpl( within range: Range<Index>, by areInIncreasingOrder: (Element, Element) throws -> Bool, depthLimit: Int ) rethrows { if distance(from: range.lowerBound, to: range.upperBound) < 20 { try _insertionSort(within: range, by: areInIncreasingOrder) } else if depthLimit == 0 { try _heapSort(within: range, by: areInIncreasingOrder) } else { let partIdx = try _partition(within: range, by: areInIncreasingOrder) try _introSortImpl( within: range.lowerBound..<partIdx, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) try _introSortImpl( within: partIdx..<range.upperBound, by: areInIncreasingOrder, depthLimit: depthLimit &- 1) } }
  • 90.
    Develop Swift !! BetterReduce: User first element in sequence as initial value
  • 91.
  • 92.
    SequenceTypeTests.test("betterReduce") { let animals= ["Antelope", "Butterfly", "Camel", “Dolphin"] var timesClosureWasCalled = 0 let longestAnimal = animals.betterReduce { current, animal in timesClousreWasCalled += 1 if current.count > animal.count { return current } else { return animal } } ?? “" // expects … } // ${ROOT}/swift/validation-test/stdlib/SequenceType.swift.gyb
  • 93.
    SequenceTypeTests.test("betterReduce") { // Codes… expectEqual(longestAnimal, “Butterfly") expectEqual( animals.count, timesClosureWasCalled, "betterReduce() should be eager”) } // ${ROOT}/swift/validation-test/stdlib/SequenceType.swift.gyb
  • 94.
  • 95.
    // SequenceAlgorithm.swift —extension Sequence @inlinable public func betterReduce( _ nextPartialResult: (_ partialResult: Element, Element) throws -> Element ) rethrows -> Element? {
 var i = makeIterator() guard var accumulated = i.next() else { return nil } while let element = i.next() { accumulated = try nextPartialResult(accumulated, element) } return accumulated }
  • 96.
    Test Swift!! ./swift/utils/build-script -r-tCompile and test ./swift/utils/build-script -r -T Compile and validation test 4XXX tests!! 10000+ tests!!
  • 97.
    Test Standard LibraryOnly ./llvm/utils/lit/lit.py -sv ${BUILD_ROOT}/swift- macosx-x86_64/test-macosx-x86_64/stdlib A full-test run is suggested in the first place ./llvm/utils/lit/lit.py -sv ${BUILD_ROOT}/ swift-macosx-x86_64/validation-test-macosx- x86_64/stdlib
  • 99.
  • 100.
  • 101.
    ${BUILD_ROOT} ninja swift-stdlib Thanksto ninja, lets build standard library only sh ${BUILD_RTTO}/validation-test-macosx-x86_64/
 stdlib/Output/SequenceType.swift.gyb.script And do test!!
  • 102.
  • 104.
  • 106.
  • 107.
    我的裝屌指南系列列 • EP I:GitHub 裝屌指南 • EP II: Vim 裝屌指南 • EP III: Debug 裝屌指南
  • 108.
    講完惹 關愛 Swift 發展者或想討論,歡迎和我聯聯繫 tjazzterATgmailDOTcom