Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SwiftランタイムライブラリとValue Witness Table

SwiftランタイムライブラリとValue Witness Table

表題の通り

3781f49ea2c76d6ecf0c6cda46096d49?s=128

omochimetaru

October 29, 2018
Tweet

Transcript

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

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

  3. ϥϯλΠϜϥΠϒϥϦͷྫ Swift: libswiftCore C++: libc++abi Objective-C: libobjc Java: HotSpot JavaScript:

    V8 ϚωʔδυͳݴޠͰ͸ϥϯλΠϜͦͷ΋ͷɻ 3
  4. libSwiftCore ඪ४ϥΠϒϥϦͱϥϯλΠϜϥΠϒϥϦΛͻͱ· ͱΊʹͨ͠ϥΠϒϥϦɻ • ඪ४ϥΠϒϥϦͷιʔε(Swift) swift/stdlib/public/core • ϥϯλΠϜϥΠϒϥϦͷιʔε(C++) swift/stdlib/public/runtime 4

  5. 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
  6. $ 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
  7. ϥϯλΠϜؔ਺ͷྫ ࢀরΧ΢ϯτ(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
  8. 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
  9. ϦϑϨΫγϣϯ(Reflection.h) SWIFT_CC(swift) SWIFT_RUNTIME_EXPORT MirrorReturn swift_reflectAny(OpaqueValue *value, const Metadata *T); 9

  10. ObjC࿈ܞ(SwiftObject.h) #if __has_attribute(objc_root_class) __attribute__((__objc_root_class__)) #endif SWIFT_RUNTIME_EXPORT @interface SwiftObject<NSObject> { @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
  11. δΣωϦοΫͳϝλσʔλ(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
  12. ૊ΈࠐΈܕͷ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<OpaqueMetadata>; #define BUILTIN_TYPE(Symbol, Name) \ SWIFT_RUNTIME_EXPORT \ const FullOpaqueMetadata METADATA_SYM(Symbol); #include "swift/Runtime/BuiltinTypes.def" 12
  13. ϥϯλΠϜؔ਺ͷݺͼग़͠ class Cat {} func main() { let a =

    Cat() } 13
  14. // 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
  15. // 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
  16. 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
  17. 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
  18. call void bitcast ( void (%swift.refcounted*)* @swift_release to void (%T1a3CatC*)*

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

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

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

    } 21
  22. 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
  23. 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
  24. @"$SSiN" = external global %swift.type, align 8 $ swift demangle

    '$SSiN' $SSiN ---> type metadata for Swift.Int ࣮ఆٛ͸ඪ४ϥΠϒϥϦͷதʹ͋Δɻ 24
  25. Swift.Int͸ඪ४ϥΠϒϥϦʹ SwiftͰॻ͔Εͨstructɻ @_fixed_layout public struct Int : FixedWidthInteger, SignedInteger, _ExpressibleByBuiltinIntegerLiteral

    { ... public var _value: Builtin.Int64 ... } 25
  26. 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

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

  28. @"$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
  29. @"$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
  30. VWTͷγϯϘϧఆٛ Metadata.h SWIFT_RUNTIME_EXPORT const ValueWitnessTable VALUE_WITNESS_SYM(Bi64_); // Builtin.Int64 30

  31. #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
  32. VWTͷܕఆٛ using ValueWitnessTable = TargetValueWitnessTable<InProcess>; 32

  33. template <typename Runtime> struct TargetValueWitnessTable { ... #define WANT_ONLY_REQUIRED_VALUE_WITNESSES #define

    VALUE_WITNESS(LOWER_ID, UPPER_ID) \ typename TargetValueWitnessTypes<Runtime>::LOWER_ID LOWER_ID; #include "swift/ABI/ValueWitness.def" ... }; 33
  34. template <typename Runtime> struct TargetValueWitnessTable { typename TargetValueWitnessTypes<Runtime>::initializeBufferWithCopyOfBuffer initializeBufferWithCopyOfBuffer; typename

    TargetValueWitnessTypes<Runtime>::destroy destroy; typename TargetValueWitnessTypes<Runtime>::initializeWithCopy initializeWithCopy; typename TargetValueWitnessTypes<Runtime>::assignWithCopy assignWithCopy; typename TargetValueWitnessTypes<Runtime>::initializeWithTake initializeWithTake; typename TargetValueWitnessTypes<Runtime>::assignWithTake assignWithTake; typename TargetValueWitnessTypes<Runtime>::getEnumTagSinglePayload getEnumTagSinglePayload; typename TargetValueWitnessTypes<Runtime>::storeEnumTagSinglePayload storeEnumTagSinglePayload; typename TargetValueWitnessTypes<Runtime>::size size; typename TargetValueWitnessTypes<Runtime>::flags flags; typename TargetValueWitnessTypes<Runtime>::stride stride; ... } 34
  35. template <typename Runtime> 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<Runtime, returnType paramTypes> lowerId; #define MUTABLE_VALUE_TYPE TargetPointer<Runtime, OpaqueValue> #define IMMUTABLE_VALUE_TYPE ConstTargetPointer<Runtime, OpaqueValue> #define MUTABLE_BUFFER_TYPE TargetPointer<Runtime, ValueBuffer> #define IMMUTABLE_BUFFER_TYPE ConstTargetPointer<Runtime, ValueBuffer> #define TYPE_TYPE ConstTargetPointer<Runtime, Metadata> #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
  36. template <typename Runtime> class TargetValueWitnessTypes { public: using StoredPointer =

    typename Runtime::StoredPointer; typedef TargetPointer<Runtime, TargetPointer<Runtime, OpaqueValue> (TargetPointer<Runtime, ValueBuffer>, TargetPointer<Runtime, ValueBuffer>, ConstTargetPointer<Runtime, Metadata>)> initializeBufferWithCopyOfBuffer; typedef TargetPointer<Runtime, void (TargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata>)> destroy; typedef TargetPointer<Runtime, TargetPointer<Runtime, OpaqueValue> (TargetPointer<Runtime, OpaqueValue>, TargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata>)> initializeWithCopy; typedef TargetPointer<Runtime, TargetPointer<Runtime, OpaqueValue> (TargetPointer<Runtime, OpaqueValue>, TargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata>)> assignWithCopy; typedef TargetPointer<Runtime, TargetPointer<Runtime, OpaqueValue> (TargetPointer<Runtime, OpaqueValue>, TargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata>)> initializeWithTake; typedef TargetPointer<Runtime, TargetPointer<Runtime, OpaqueValue> (TargetPointer<Runtime, OpaqueValue>, TargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata>)> assignWithTake; typedef TargetPointer<Runtime, unsigned (ConstTargetPointer<Runtime, OpaqueValue>, unsigned, ConstTargetPointer<Runtime, Metadata>)> getEnumTagSinglePayload; typedef TargetPointer<Runtime, void (TargetPointer<Runtime, OpaqueValue>, unsigned, unsigned, ConstTargetPointer<Runtime, Metadata>)> storeEnumTagSinglePayload; typedef TargetPointer<Runtime, void (TargetPointer<Runtime, OpaqueValue>, int, ConstTargetPointer<Runtime, Metadata>)> storeExtraInhabitant; typedef TargetPointer<Runtime, int (ConstTargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata>)> getExtraInhabitantIndex; typedef TargetPointer<Runtime, int (ConstTargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata>)> getEnumTag; typedef TargetPointer<Runtime, void (TargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata>)> destructiveProjectEnumData; typedef TargetPointer<Runtime, void (TargetPointer<Runtime, OpaqueValue>, unsigned, ConstTargetPointer<Runtime, Metadata>)> destructiveInjectEnumTag; typedef size_t size; typedef ValueWitnessFlags flags; typedef size_t stride; typedef ExtraInhabitantFlags extraInhabitantFlags; }; 36
  37. typedef TargetPointer<Runtime, void ( TargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata> ) >

    destroy; typedef TargetPointer<Runtime, TargetPointer<Runtime, OpaqueValue> ( TargetPointer<Runtime, OpaqueValue>, TargetPointer<Runtime, OpaqueValue>, ConstTargetPointer<Runtime, Metadata> ) > initializeWithCopy; 37
  38. template <typename Runtime, typename T> using TargetPointer = typename Runtime::template

    Pointer<T>; Runtime == InProcess 38
  39. 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 <typename T> using Pointer = T*; template <typename T, bool Nullable = false> using FarRelativeDirectPointer = FarRelativeDirectPointer<T, Nullable>; template <typename T, bool Nullable = false> using RelativeIndirectablePointer = RelativeIndirectablePointer<T, Nullable>; template <typename T, bool Nullable = true> using RelativeDirectPointer = RelativeDirectPointer<T, Nullable>; }; 39
  40. VWTͷ࣮૷ KnownMetadata.cpp const ValueWitnessTable swift::VALUE_WITNESS_SYM(Bi64_) = ValueWitnessTableForBox<NativeBox<uint64_t, 8>>::table; 40

  41. template <class Box> using ValueWitnessTableForBox = ValueWitnessTableGenerator<ValueWitnesses<Box>>; template <class Witnesses,

    bool HasExtraInhabitants = Witnesses::hasExtraInhabitants> struct ValueWitnessTableGenerator; template <class Witnesses> struct ValueWitnessTableGenerator<Witnesses, false> { 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
  42. template <class Witnesses> struct ValueWitnessTableGenerator<Witnesses, false> { 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<NativeBox<uint64_t, 8>> 42
  43. template <class Box> struct ValueWitnesses : FixedSizeBufferValueWitnesses< ValueWitnesses<Box>, 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
  44. template <class T, size_t Alignment = alignof(T), size_t Size =

    sizeof(T), size_t Stride = sizeof(T)> struct NativeBox { using type = T; static constexpr size_t size = Size; static constexpr size_t alignment = Alignment; static constexpr size_t stride = Stride; ... }; 44
  45. ·ͱΊ • ίϯύΠϧ͞ΕͨSwiftίʔυ͸ɺ ඪ४ϥΠϒϥϦͱϥϯλΠϜϥΠϒϥϦΛར༻ ͢Δɻ • ඪ४ϥΠϒϥϦͱϥϯλΠϜϥΠϒϥϦ͸ɺ libswiftCore.dylibͱͯ͠ఏڙ͞ΕΔɻ • BuiltinܕͷVWT͸ɺC++ͷίϯύΠϧ࣌ఆ਺ͱ

    ࣮ͯ͠૷͞Ε͍ͯΔɻ 45