Slide 1

Slide 1 text

SwiftϥϯλΠϜϥΠϒϥϦͱ Value Witness Table Θ͍Θ͍swiftc #6 omochimetaru 1

Slide 2

Slide 2 text

ϥϯλΠϜϥΠϒϥϦ ࣮ߦϑΝΠϧ͕ݴޠػೳΛಈ࡞ͤ͞ΔͨΊʹ࢖༻ ͢ΔϥΠϒϥϦɻ ඪ४ϥΠϒϥϦͱ͸ҟͳΓɺ ௨ৗ͸ݴޠϢʔβ͔Β͸ར༻͞Εͳ͍ɻ ίϯύΠϥͳͲͷݴޠॲཧܥ͕ఏڙ͠ɺ ίϯύΠϧ͞Εͨίʔυ͕಺෦తʹ࢖༻͢Δɻ 2

Slide 3

Slide 3 text

ϥϯλΠϜϥΠϒϥϦͷྫ Swift: libswiftCore C++: libc++abi Objective-C: libobjc Java: HotSpot JavaScript: V8 ϚωʔδυͳݴޠͰ͸ϥϯλΠϜͦͷ΋ͷɻ 3

Slide 4

Slide 4 text

libSwiftCore ඪ४ϥΠϒϥϦͱϥϯλΠϜϥΠϒϥϦΛͻͱ· ͱΊʹͨ͠ϥΠϒϥϦɻ • ඪ४ϥΠϒϥϦͷιʔε(Swift) swift/stdlib/public/core • ϥϯλΠϜϥΠϒϥϦͷιʔε(C++) swift/stdlib/public/runtime 4

Slide 5

Slide 5 text

SwiftϥϯλΠϜ $ swiftc a.swift $ otool -L a a: ... @rpath/libswiftCore.dylib ... $ otool -l a ... cmd LC_RPATH cmdsize 112 path /Applications/Xcode.app/Contents/Developer/ Toolchains/XcodeDefault.xctoolchain/usr/ lib/swift/macosx (offset 12) ... 5

Slide 6

Slide 6 text

$ which -a swift /Users/omochi/work/swift-source/build/ Xcode-DebugAssert/swift-macosx-x86_64/Debug/ bin/swift $ swiftc a.swift $ otool -L a a: ... @rpath/libswiftCore.dylib ... $ otool -l a ... cmd LC_RPATH cmdsize 112 path /Users/omochi/work/swift-source/build/ Xcode-DebugAssert/swift-macosx-x86_64/Debug/ lib/swift/macosx (offset 12) ... 6

Slide 7

Slide 7 text

ϥϯλΠϜؔ਺ͷྫ ࢀরΧ΢ϯτ(HeapObject.h) SWIFT_RUNTIME_EXPORT HeapObject *swift_retain(HeapObject *object); ࢀরܕͷϝϞϦ֬อ(HeapObject.h) SWIFT_RUNTIME_EXPORT HeapObject *swift_allocObject(HeapMetadata const *metadata, size_t requiredSize, size_t requiredAlignmentMask); 7

Slide 8

Slide 8 text

Law of Exclusivity(Exclusibity.h) SWIFT_RUNTIME_EXPORT void swift_beginAccess(void *pointer, ValueBuffer *buffer, ExclusivityFlags flags, void *pc); ྫ֎ͷσόοά(ErrorObject.h) SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API void swift_willThrow(SWIFT_CONTEXT void *unused, SWIFT_ERROR_RESULT SwiftError **object); 8

Slide 9

Slide 9 text

ϦϑϨΫγϣϯ(Reflection.h) SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT MirrorReturn swift_reflectAny(OpaqueValue *value, const Metadata *T); 9

Slide 10

Slide 10 text

ObjC࿈ܞ(SwiftObject.h) #if __has_attribute(objc_root_class) __attribute__((__objc_root_class__)) #endif SWIFT_RUNTIME_EXPORT @interface SwiftObject { @private Class isa; SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS; } - (BOOL)isEqual:(id)object; - (NSUInteger)hash; - (Class)superclass; - (Class)class; - (instancetype)self; - (struct _NSZone *)zone; - (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector withObject:(id)object; - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2; - (BOOL)isProxy; + (BOOL)isSubclassOfClass:(Class)aClass; - (BOOL)isKindOfClass:(Class)aClass; - (BOOL)isMemberOfClass:(Class)aClass; - (BOOL)conformsToProtocol:(Protocol *)aProtocol; - (BOOL)respondsToSelector:(SEL)aSelector; + (BOOL)instancesRespondToSelector:(SEL)aSelector; - (IMP)methodForSelector:(SEL)aSelector; + (IMP)instanceMethodForSelector:(SEL)aSelector; - (instancetype)retain; - (oneway void)release; - (instancetype)autorelease; - (NSUInteger)retainCount; - (NSString *)description; - (NSString *)debugDescription; @end 10

Slide 11

Slide 11 text

δΣωϦοΫͳϝλσʔλ(Metadata.h) SWIFT_RUNTIME_EXPORT SWIFT_CC(swift) MetadataResponse swift_getGenericMetadata(MetadataRequest request, const void * const *arguments, const TypeContextDescriptor *description); ಈతͳΫϥεॳظԽ(Metadata.h) SWIFT_RUNTIME_EXPORT void swift_initClassMetadata(ClassMetadata *self, ClassMetadata *super, ClassLayoutFlags flags, size_t numFields, const TypeLayout * const *fieldTypes, size_t *fieldOffsets); 11

Slide 12

Slide 12 text

૊ΈࠐΈܕͷValue Witness Table(Metadata.h) SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi64_); // Builtin.Int64 SWIFT_RUNTIME_EXPORT const ExtraInhabitantsValueWitnessTable VALUE_WITNESS_SYM(Bo); // Builtin.NativeObject ૊ΈࠐΈܕͷϝλσʔλ(Metadata.h) using FullOpaqueMetadata = FullMetadata; #define BUILTIN_TYPE(Symbol, Name) \ SWIFT_RUNTIME_EXPORT \ const FullOpaqueMetadata METADATA_SYM(Symbol); #include "swift/Runtime/BuiltinTypes.def" 12

Slide 13

Slide 13 text

ϥϯλΠϜؔ਺ͷݺͼग़͠ class Cat {} func main() { let a = Cat() } 13

Slide 14

Slide 14 text

// main() sil hidden @$S1a4mainyyF : $@convention(thin) () -> () { bb0: %0 = metatype $@thick Cat.Type // user: %2 // function_ref Cat.__allocating_init() %1 = function_ref @$S1a3CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %2 %2 = apply %1(%0) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %4, %3 debug_value %2 : $Cat, let, name "a" // id: %3 strong_release %2 : $Cat // id: %4 %5 = tuple () // user: %6 return %5 : $() // id: %6 } // end sil function '$S1a4mainyyF' 14

Slide 15

Slide 15 text

// main() sil hidden @$S1a4mainyyF : $@convention(thin) () -> () { bb0: %0 = metatype $@thick Cat.Type // user: %2 // function_ref Cat.__allocating_init() %1 = function_ref @$S1a3CatCACycfC : $@convention(method) (@thick Cat.Type) -> @owned Cat // user: %2 %2 = apply %1(%0) : $@convention(method) (@thick Cat.Type) -> @owned Cat // users: %4, %3 debug_value %2 : $Cat, let, name "a" // id: %3 strong_release %2 : $Cat // id: %4 %5 = tuple () // user: %6 return %5 : $() // id: %6 } // end sil function '$S1a4mainyyF' 15

Slide 16

Slide 16 text

define hidden swiftcc void @"$S1a4mainyyF"() #0 { entry: %0 = call swiftcc %swift.metadata_response @"$S1a3CatCMa"(i64 0) #5 %1 = extractvalue %swift.metadata_response %0, 0 %2 = call swiftcc %T1a3CatC* @"$S1a3CatCACycfC"(%swift.type* swiftself %1) call void asm sideeffect "", "r"(%T1a3CatC* %2) call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T1a3CatC*)*)(%T1a3CatC* %2) #3 ret void } 16

Slide 17

Slide 17 text

define hidden swiftcc void @"$S1a4mainyyF"() #0 { entry: %0 = call swiftcc %swift.metadata_response @"$S1a3CatCMa"(i64 0) #5 %1 = extractvalue %swift.metadata_response %0, 0 %2 = call swiftcc %T1a3CatC* @"$S1a3CatCACycfC"(%swift.type* swiftself %1) call void asm sideeffect "", "r"(%T1a3CatC* %2) call void bitcast (void (%swift.refcounted*)* @swift_release to void (%T1a3CatC*)*)(%T1a3CatC* %2) #3 ret void } 17

Slide 18

Slide 18 text

call void bitcast ( void (%swift.refcounted*)* @swift_release to void (%T1a3CatC*)* ) (%T1a3CatC* %2) #3 18

Slide 19

Slide 19 text

call void bitcast ( void (%swift.refcounted*)* @swift_release to void (%T1a3CatC*)* ) (%T1a3CatC* %2) #3 19

Slide 20

Slide 20 text

LLVM declare void @swift_release(%swift.refcounted*) #3 C++ SWIFT_RUNTIME_EXPORT void swift_release(HeapObject *object); 20

Slide 21

Slide 21 text

૊ΈࠐΈܕͷϝλσʔλ func takeX(_ x: X) {} func main() { takeX(Int(3)) } 21

Slide 22

Slide 22 text

define hidden swiftcc void @"$S1b4mainyyF"() #0 { entry: %0 = alloca %TSi, align 8 %1 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.start.p0i8(i64 8, i8* %1) %._value = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0 store i64 3, i64* %._value, align 8 %2 = bitcast %TSi* %0 to %swift.opaque* call swiftcc void @"$S1b5takeXyyxlF"(%swift.opaque* noalias nocapture %2, %swift.type* @"$SSiN") %3 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.end.p0i8(i64 8, i8* %3) ret void } 22

Slide 23

Slide 23 text

define hidden swiftcc void @"$S1b4mainyyF"() #0 { entry: %0 = alloca %TSi, align 8 %1 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.start.p0i8(i64 8, i8* %1) %._value = getelementptr inbounds %TSi, %TSi* %0, i32 0, i32 0 store i64 3, i64* %._value, align 8 %2 = bitcast %TSi* %0 to %swift.opaque* call swiftcc void @"$S1b5takeXyyxlF"(%swift.opaque* noalias nocapture %2, %swift.type* @"$SSiN") %3 = bitcast %TSi* %0 to i8* call void @llvm.lifetime.end.p0i8(i64 8, i8* %3) ret void } 23

Slide 24

Slide 24 text

@"$SSiN" = external global %swift.type, align 8 $ swift demangle '$SSiN' $SSiN ---> type metadata for Swift.Int ࣮ఆٛ͸ඪ४ϥΠϒϥϦͷதʹ͋Δɻ 24

Slide 25

Slide 25 text

Swift.Int͸ඪ४ϥΠϒϥϦʹ SwiftͰॻ͔Εͨstructɻ @_fixed_layout public struct Int : FixedWidthInteger, SignedInteger, _ExpressibleByBuiltinIntegerLiteral { ... public var _value: Builtin.Int64 ... } 25

Slide 26

Slide 26 text

Intͷιʔε https://github.com/apple/swift/blob/master/ stdlib/public/core/IntegerTypes.swift.gyb gybల։݁Ռ https://github.com/omochi/SwiftStdlib/blob/ master/Sources/IntegerTypes.swift 26

Slide 27

Slide 27 text

Builtin.Int64͸૊ΈࠐΈܕɻ ίϯύΠϥ͕௚઀αϙʔτɻ 27

Slide 28

Slide 28 text

@"$SSiN" = alias %swift.type, bitcast ( i64* getelementptr inbounds ( <{ i8**, i64, <{ ... }>*, i32, [4 x i8] }>, <{ i8**, i64, <{ ... }>*, i32, [4 x i8] }>* @"$SSiMf", i32 0, i32 1) to %swift.type*) $SSiMf ---> full type metadata for Swift.Int 28

Slide 29

Slide 29 text

@"$SSiMf" = internal constant <{ i8**, i64, <{ ... }>*, i32, [4 x i8] }> <{ i8** @"$SBi64_WV", i64 512, <{ ... }>* @"$SSiMn", i32 0, [4 x i8] zeroinitializer }>, align 8 $SBi64_WV ---> value witness table for Builtin.Int64 $SSiMn ---> nominal type descriptor for Swift.Int 29

Slide 30

Slide 30 text

VWTͷγϯϘϧఆٛ Metadata.h SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi64_); // Builtin.Int64 30

Slide 31

Slide 31 text

#define MANGLING_PREFIX $S #define MANGLING_CONCAT2_IMPL(a, b) a##b #define MANGLING_CONCAT2(a, b) MANGLING_CONCAT2_IMPL(a, b) #define MANGLE_SYM(Ops) MANGLING_CONCAT2(MANGLING_PREFIX, Ops) #define VALUE_WITNESS_SYM(Ty) \ MANGLE_SYM(MANGLING_CONCAT2(Ty, WV)) VALUE_WITNESS_SYM(Bi64_) => MANGLE_SYM(MANGLING_CONCAT2(Bi64_, WV)) => MANGLE_SYM(Bi64_WV) => MANGLING_CONCAT2(MANGLING_PREFIX, Bi64_WV) => MANGLING_CONCAT2($S, Bi64_WV) => $SBi64_WV SWIFT_RUNTIME_EXPORT const ValueWitnessTable $SBi64_WV; 31

Slide 32

Slide 32 text

VWTͷܕఆٛ using ValueWitnessTable = TargetValueWitnessTable; 32

Slide 33

Slide 33 text

template struct TargetValueWitnessTable { ... #define WANT_ONLY_REQUIRED_VALUE_WITNESSES #define VALUE_WITNESS(LOWER_ID, UPPER_ID) \ typename TargetValueWitnessTypes::LOWER_ID LOWER_ID; #include "swift/ABI/ValueWitness.def" ... }; 33

Slide 34

Slide 34 text

template struct TargetValueWitnessTable { typename TargetValueWitnessTypes::initializeBufferWithCopyOfBuffer initializeBufferWithCopyOfBuffer; typename TargetValueWitnessTypes::destroy destroy; typename TargetValueWitnessTypes::initializeWithCopy initializeWithCopy; typename TargetValueWitnessTypes::assignWithCopy assignWithCopy; typename TargetValueWitnessTypes::initializeWithTake initializeWithTake; typename TargetValueWitnessTypes::assignWithTake assignWithTake; typename TargetValueWitnessTypes::getEnumTagSinglePayload getEnumTagSinglePayload; typename TargetValueWitnessTypes::storeEnumTagSinglePayload storeEnumTagSinglePayload; typename TargetValueWitnessTypes::size size; typename TargetValueWitnessTypes::flags flags; typename TargetValueWitnessTypes::stride stride; ... } 34

Slide 35

Slide 35 text

template class TargetValueWitnessTypes { public: using StoredPointer = typename Runtime::StoredPointer; #define WANT_ALL_VALUE_WITNESSES #define DATA_VALUE_WITNESS(lowerId, upperId, type) #define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \ typedef TargetPointer lowerId; #define MUTABLE_VALUE_TYPE TargetPointer #define IMMUTABLE_VALUE_TYPE ConstTargetPointer #define MUTABLE_BUFFER_TYPE TargetPointer #define IMMUTABLE_BUFFER_TYPE ConstTargetPointer #define TYPE_TYPE ConstTargetPointer #define SIZE_TYPE StoredSize #define INT_TYPE int #define UINT_TYPE unsigned #define VOID_TYPE void #include "swift/ABI/ValueWitness.def" typedef size_t size; typedef ValueWitnessFlags flags; typedef size_t stride; typedef ExtraInhabitantFlags extraInhabitantFlags; }; 35

Slide 36

Slide 36 text

template class TargetValueWitnessTypes { public: using StoredPointer = typename Runtime::StoredPointer; typedef TargetPointer (TargetPointer, TargetPointer, ConstTargetPointer)> initializeBufferWithCopyOfBuffer; typedef TargetPointer, ConstTargetPointer)> destroy; typedef TargetPointer (TargetPointer, TargetPointer, ConstTargetPointer)> initializeWithCopy; typedef TargetPointer (TargetPointer, TargetPointer, ConstTargetPointer)> assignWithCopy; typedef TargetPointer (TargetPointer, TargetPointer, ConstTargetPointer)> initializeWithTake; typedef TargetPointer (TargetPointer, TargetPointer, ConstTargetPointer)> assignWithTake; typedef TargetPointer, unsigned, ConstTargetPointer)> getEnumTagSinglePayload; typedef TargetPointer, unsigned, unsigned, ConstTargetPointer)> storeEnumTagSinglePayload; typedef TargetPointer, int, ConstTargetPointer)> storeExtraInhabitant; typedef TargetPointer, ConstTargetPointer)> getExtraInhabitantIndex; typedef TargetPointer, ConstTargetPointer)> getEnumTag; typedef TargetPointer, ConstTargetPointer)> destructiveProjectEnumData; typedef TargetPointer, unsigned, ConstTargetPointer)> destructiveInjectEnumTag; typedef size_t size; typedef ValueWitnessFlags flags; typedef size_t stride; typedef ExtraInhabitantFlags extraInhabitantFlags; }; 36

Slide 37

Slide 37 text

typedef TargetPointer, ConstTargetPointer ) > destroy; typedef TargetPointer ( TargetPointer, TargetPointer, ConstTargetPointer ) > initializeWithCopy; 37

Slide 38

Slide 38 text

template using TargetPointer = typename Runtime::template Pointer; Runtime == InProcess 38

Slide 39

Slide 39 text

struct InProcess { static constexpr size_t PointerSize = sizeof(uintptr_t); using StoredPointer = uintptr_t; using StoredSize = size_t; using StoredPointerDifference = ptrdiff_t; static_assert(sizeof(StoredSize) == sizeof(StoredPointerDifference), "target uses differently-sized size_t and ptrdiff_t"); template using Pointer = T*; template using FarRelativeDirectPointer = FarRelativeDirectPointer; template using RelativeIndirectablePointer = RelativeIndirectablePointer; template using RelativeDirectPointer = RelativeDirectPointer; }; 39

Slide 40

Slide 40 text

VWTͷ࣮૷ KnownMetadata.cpp const ValueWitnessTable swift::VALUE_WITNESS_SYM(Bi64_) = ValueWitnessTableForBox>::table; 40

Slide 41

Slide 41 text

template using ValueWitnessTableForBox = ValueWitnessTableGenerator>; template struct ValueWitnessTableGenerator; template struct ValueWitnessTableGenerator { static constexpr const ValueWitnessTable table = { #define WANT_ONLY_REQUIRED_VALUE_WITNESSES #define VALUE_WITNESS(LOWER_ID, UPPER_ID) Witnesses::LOWER_ID, #include "swift/ABI/ValueWitness.def" }; }; 41

Slide 42

Slide 42 text

template struct ValueWitnessTableGenerator { static constexpr const ValueWitnessTable table = { Witnesses::initializeBufferWithCopyOfBuffer, Witnesses::destroy, Witnesses::initializeWithCopy, Witnesses::assignWithCopy, Witnesses::initializeWithTake, Witnesses::assignWithTake, Witnesses::getEnumTagSinglePayload, Witnesses::storeEnumTagSinglePayload, Witnesses::size, Witnesses::flags, Witnesses::stride, }; }; Witnesses == ValueWitnesses> 42

Slide 43

Slide 43 text

template struct ValueWitnesses : FixedSizeBufferValueWitnesses< ValueWitnesses, Box::isBitwiseTakable, Box::size, Box::alignment, hasExtraInhabitants(Box::numExtraInhabitants)> { ... static constexpr size_t size = Box::size; static constexpr size_t stride = Box::stride; static constexpr size_t alignment = Box::alignment; static constexpr ValueWitnessFlags flags = ...; static void destroy(OpaqueValue *value, const Metadata *self) { ... } static OpaqueValue *initializeWithCopy(OpaqueValue *dest, OpaqueValue *src, const Metadata *self) { ... } static OpaqueValue *initializeWithTake(OpaqueValue *dest, OpaqueValue *src, const Metadata *self) { ... } static OpaqueValue *assignWithCopy(OpaqueValue *dest, OpaqueValue *src, const Metadata *self) { ... } static OpaqueValue *assignWithTake(OpaqueValue *dest, OpaqueValue *src, const Metadata *self) { ... } static void storeExtraInhabitant(OpaqueValue *dest, int index, const Metadata *self) { ... } static int getExtraInhabitantIndex(const OpaqueValue *src, const Metadata *self) { ... } ... }; 43

Slide 44

Slide 44 text

template struct NativeBox { using type = T; static constexpr size_t size = Size; static constexpr size_t alignment = Alignment; static constexpr size_t stride = Stride; ... }; 44

Slide 45

Slide 45 text

·ͱΊ • ίϯύΠϧ͞ΕͨSwiftίʔυ͸ɺ ඪ४ϥΠϒϥϦͱϥϯλΠϜϥΠϒϥϦΛར༻ ͢Δɻ • ඪ४ϥΠϒϥϦͱϥϯλΠϜϥΠϒϥϦ͸ɺ libswiftCore.dylibͱͯ͠ఏڙ͞ΕΔɻ • BuiltinܕͷVWT͸ɺC++ͷίϯύΠϧ࣌ఆ਺ͱ ࣮ͯ͠૷͞Ε͍ͯΔɻ 45