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

コンパイラから紐解くSwift method dispatch

7a4968fbcd56e81f95a4f3c186141b52?s=47 Yuta Saito
August 31, 2018

コンパイラから紐解くSwift method dispatch

7a4968fbcd56e81f95a4f3c186141b52?s=128

Yuta Saito

August 31, 2018
Tweet

Transcript

  1. ίϯύΠϥ͔Βඥղ͘ 4XJGUNFUIPEEJTQBUDI !LBUFJOPJHBLVLVO

  2. ࣗݾ঺հ w !LBUFJOPJHBLVLVO w ૣҴాେֶߴ౳ֶӃ̏೥

  3. ͍͖ͳΓͰ͕͢

  4. ΫΠζͰ͢

  5. class Cat { func bark() -> String { return "ʹΌΜ"

    } } class Dog { func bark() -> String { return "ΘΜ" } } let cat = Cat() let dog = unsafeBitCast(cat, to: Dog.self) print(dog.bark()) 2Կ͕ग़ྗ͞ΕΔͰ͠ΐ͏ʁ ʹΌΜPSΘΜ
  6. class Cat { func bark() -> String { return "ʹΌΜ"

    } } class Dog { func bark() -> String { return "ΘΜ" } } let cat = Cat() let dog = unsafeBitCast(cat, to: Dog.self) print(dog.bark()) 2Կ͕ग़ྗ͞ΕΔͰ͠ΐ͏ʁ "ΘΜ
  7. ʮΘΜʯ

  8. ࠓ೔࿩͢͜ͱ w .FUIPE%JTQBUDIͷ࢓૊Έ w ࠷దԽͷ࢓૊Έ w ύϑΥʔϚϯε

  9. 2.FUIPEEJTQBUDIͱ͸ʁ

  10. 2.FUIPEEJTQBUDIͱ͸ʁ "ϝιου͕ݺͼग़͞ΕΔ࣌ʹɺ
 ࣮ࡍʹͲͷϝιουΛ࣮ߦ͢Δ͔ΛܾΊΔػߏ

  11. None
  12. class Animal { func bark() { print("ΞχϚϧͰ͢") } } class

    Cat: Animal { override func bark() { print("ʹΌΜ") } } func callAnimalBark(_ animal: Animal) { animal.bark() }
  13. class Animal { func bark() { print("ΞχϚϧͰ͢") } } class

    Cat: Animal { override func bark() { print("ʹΌΜ") } } func callAnimalBark(_ animal: Animal) { animal.bark() // ΞχϚϧͰ͢ or ʹΌΜ }
  14. class Animal { func bark() { print("ΞχϚϧͰ͢") } } class

    Cat: Animal { override func bark() { print("ʹΌΜ") } } func callAnimalBark(_ animal: Animal) { animal.bark() // ΞχϚϧͰ͢ or ʹΌΜ } ࣮ߦ͞ΕΔϝιου͸Ͳͬͪʁʁ
  15. .FUIPE%JTQBUDIͷύλʔϯ w 4UBUJD%JTQBUDI w ݺͼग़͢ϝιουΛίϯύΠϧ࣌ʹܾΊΔ w %ZOBNJD%JTQBUDI w ݺͼग़͢ϝιουΛ࣮ߦ࣌ʹܾΊΔ

  16. 4UBUJD%JTQBUDI w ؔ਺ w ஋ܕͷϝιου w FYUFOTJPOʹॻ͍ͨϝιου w pOBMͳϝιου struct

    S { func foo() {} } let s = S() s.foo()
  17. 4UBUJD%JTQBUDI struct S { func foo() {} } let s

    = S() s.foo() ಉ͡γάωνϟͷϝιου͕ଘࡏ͠ͳ͍ w ؔ਺ w ஋ܕͷϝιου w FYUFOTJPOʹॻ͍ͨϝιου w pOBMͳϝιου
  18. %ZOBNJD%JTQBUDI w $MBTTͷϝιου w 1SPUPDPMͷϝιου protocol Animal { func foo()

    } struct Cat: Animal { func foo() {} } func callFoo<T: Animal>(_ animal: T) { animal.foo() }
  19. w $MBTTͷϝιουΦʔόʔϥΠυ w 1SPUPDPMͷϝιουෳ਺ͷܕ͕४ڌ %ZOBNJD%JTQBUDI protocol Animal { func foo()

    } struct Cat: Animal { func foo() {} } func callFoo<T: Animal>(_ animal: T) { animal.foo() } ಉ͡γάωνϟͷϝιου͕ෳ਺ଘࡏ͢Δ
  20. .FUIPE%JTQBUDIͷύλʔϯ w 4UBUJD%JTQBUDI w ݺͼग़͢ϝιουΛίϯύΠϧ࣌ʹܾΊΔ w %ZOBNJD%JTQBUDI w ݺͼग़͢ϝιουΛ࣮ߦ࣌ʹܾΊΔ

  21. .FUIPE%JTQBUDIͷύλʔϯ w 4UBUJD%JTQBUDI w ݺͼग़͢ϝιουΛίϯύΠϧ࣌ʹܾΊΔ w %ZOBNJD%JTQBUDI w ݺͼग़͢ϝιουΛ࣮ߦ࣌ʹܾΊΔ w

    75BCMF w 8JUOFTT5BCMF
  22. 75BCMF w Ծ૝ؔ਺ςʔϒϧ͔ΒϝιουΛ୳ࡧ͢Δ%JTQBUDIํࣜ w ΫϥεͷϝιουΛݺͼग़࣌͢ʹ࢖͏ w ΠϯελϯεͷϝλσʔλʹຒΊࠐ·ΕΔ

  23. func Animal.bark() *Animal.bark 75BCMFGPS"OJNBM class Animal { func bark() {}

    }
  24. func Animal.bark() *Animal.bark 75BCMFGPS$BU *Animal.bark 75BCMFGPS"OJNBM class Animal { func

    bark() {} } class Cat: Animal { }
  25. func Cat.foo() func Animal.bark() *Animal.bark *Animal.bark *Cat.foo 75BCMFGPS"OJNBM 75BCMFGPS$BU class

    Animal { func bark() {} } class Cat: Animal { func foo() {} }
  26. class Animal { func bark() {} } class Cat: Animal

    { override func bark() {} func foo() {} } 75BCMFGPS$BU func Animal.bark() 75BCMFGPS"OJNBM *Animal.bark *Animal.bark *Cat.foo func Cat.bark() func Cat.foo()
  27. 8JUOFTT5BCMF w Ծ૝ؔ਺ςʔϒϧ͔ΒϝιουΛ୳ࡧ͢Δ%JTQBUDIํࣜ w ϓϩτίϧͷϝιουΛݺͼग़࣌͢ʹ࢖͏ w ϓϩτίϧ΁ͷ४ڌ͝ͱʹఆٛ͞ΕΔ

  28. protocol Animal { func bark() }

  29. protocol Animal { func bark() } struct Dog: Animal {

    func bark() {} } 8JUOFTT5BCMFGPS"OJNBM JODPOGPSNBODF%PH *Animal.bark func Animal.bark(dog) { Dog.bark(dog) } 8JUOFTTNFUIPEGPS"OJNBM JODPOGPSNBODF%PH
  30. ʮΘΜʯ໰୊

  31. class Cat { func bark() -> String { return "ʹΌΜ"

    } } class Dog { func bark() -> String { return “ΘΜ" } } let cat = Cat() let dog = unsafeBitCast(cat, to: Dog.self) print(dog.bark()) ϝϞϦϨΠΞ΢τ͸มߋ͞Εͳ͍ ࢀর͢ΔVTable΋มΘΒͳ͍ Catͷςʔϒϧ͕ࢀর͞ΕΔ ʮʹΌΜʯ͕ग़ྗ͞ΕΔ͸ͣʂ
  32. ͔͠͠ɺ

  33. class Cat { func bark() -> String { return "ʹΌΜ"

    } } class Dog { func bark() -> String { return "ΘΜ" } } let cat = Cat() let dog = unsafeBitCast(cat, to: Dog.self) print(dog.bark()) // ΘΜ ʮΘΜʯ
  34. None
  35. ࠷దԽΛΦϑʹͯ͠ΈΔ

  36. $ swiftc -frontend -c -primary-file animal.swift $ swiftc animal.o $

    ./animal ʹΌΜ ʮʹΌΜʯ
  37. ࠷దԽͷաఔʹԿ͔͋Γͦ͏

  38. %FWJSUVBMJ[F

  39. %FWJSUVBMJ[F w 4*-0QUJNJ[FSͷ࠷దԽύε w %ZOBNJD%JTQBUDIΛ4UBUJD%JTQBUDIʹ࠷దԽ͢Δ w ίϯύΠϧ࣌ͷܕ৘ใ͔ΒϝιουΛ̍ͭʹܾΊΔ

  40. 75BCMFͷ࠷దԽ

  41. USZ%FWJSUVBMJ[F"QQMZ auto &M = FAS.getModule(); auto Instance = stripUpCasts(CMI->getOperand()); auto

    ClassType = Instance->getType(); ... if (isEffectivelyFinalMethod(FAS, ClassType, CD, CHA)) return tryDevirtualizeClassMethod(FAS, Instance, ORE, true /*isEffectivelyFinalMethod*/); if (auto Instance = getInstanceWithExactDynamicType(CMI->getOperand(), CMI->getModule(), CHA)) return tryDevirtualizeClassMethod(FAS, Instance, ORE); if (auto ExactTy = getExactDynamicType(CMI->getOperand(), CMI->getModule(), CHA)) { if (ExactTy == CMI->getOperand()->getType()) return tryDevirtualizeClassMethod(FAS, CMI->getOperand(), ORE); } MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  42. USZ%FWJSUVBMJ[F"QQMZ auto &M = FAS.getModule(); auto Instance = stripUpCasts(CMI->getOperand()); auto

    ClassType = Instance->getType(); ... if (isEffectivelyFinalMethod(FAS, ClassType, CD, CHA)) return tryDevirtualizeClassMethod(FAS, Instance, ORE, true /*isEffectivelyFinalMethod*/); if (auto Instance = getInstanceWithExactDynamicType(CMI->getOperand(), CMI->getModule(), CHA)) return tryDevirtualizeClassMethod(FAS, Instance, ORE); if (auto ExactTy = getExactDynamicType(CMI->getOperand(), CMI->getModule(), CHA)) { if (ExactTy == CMI->getOperand()->getType()) return tryDevirtualizeClassMethod(FAS, CMI->getOperand(), ORE); } Πϯελϯεͷ࣮ߦ࣌ͷܕ͕੩తʹܾఆͰ͖Δύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  43. %FWJSUVBMJ[FGPS75BCMF class Animal { func bark() {} } class Cat:

    Animal { override func bark() {} } let animal: Animal = Cat() // ΠχγϟϥΠβ͔Β࡞ͬͯΔͷͰCatܕ animal.bark() Πϯελϯεͷ࣮ߦ࣌ͷܕ͕੩తʹܾఆͰ͖Δύλʔϯ
  44. USZ%FWJSUVBMJ[F"QQMZ auto &M = FAS.getModule(); auto Instance = stripUpCasts(CMI->getOperand()); auto

    ClassType = Instance->getType(); ... if (isEffectivelyFinalMethod(FAS, ClassType, CD, CHA)) return tryDevirtualizeClassMethod(FAS, Instance, ORE, true /*isEffectivelyFinalMethod*/); if (auto Instance = getInstanceWithExactDynamicType(CMI->getOperand(), CMI->getModule(), CHA)) return tryDevirtualizeClassMethod(FAS, Instance, ORE); if (auto ExactTy = getExactDynamicType(CMI->getOperand(), CMI->getModule(), CHA)) { if (ExactTy == CMI->getOperand()->getType()) return tryDevirtualizeClassMethod(FAS, CMI->getOperand(), ORE); } ϝιου͕z࣮࣭pOBMzͳύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  45. JT&⒎FDUJWFMZ'JOBM.FUIPE static bool isEffectivelyFinalMethod(FullApplySite AI, SILType ClassType, ClassDecl *CD, ClassHierarchyAnalysis

    *CHA) { if (CD && CD->isFinal()) return true; const DeclContext *DC = AI.getModule().getAssociatedContext(); auto *CMI = cast<MethodInst>(AI.getCallee()); if (!calleesAreStaticallyKnowable(AI.getModule(), CMI->getMember())) return false; auto *Method = CMI->getMember().getAbstractFunctionDecl(); if (!Method->isOverridden()) return true; ... return true; } ϝιου͕z࣮࣭pOBMzͳύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  46. JT&⒎FDUJWFMZ'JOBM.FUIPE static bool isEffectivelyFinalMethod(FullApplySite AI, SILType ClassType, ClassDecl *CD, ClassHierarchyAnalysis

    *CHA) { if (CD && CD->isFinal()) return true; const DeclContext *DC = AI.getModule().getAssociatedContext(); auto *CMI = cast<MethodInst>(AI.getCallee()); if (!calleesAreStaticallyKnowable(AI.getModule(), CMI->getMember())) return false; auto *Method = CMI->getMember().getAbstractFunctionDecl(); if (!Method->isOverridden()) return true; ... return true; } ϝιου͕z࣮࣭pOBMzͳύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  47. JT&⒎FDUJWFMZ'JOBM.FUIPE static bool isEffectivelyFinalMethod(FullApplySite AI, SILType ClassType, ClassDecl *CD, ClassHierarchyAnalysis

    *CHA) { if (CD && CD->isFinal()) return true; const DeclContext *DC = AI.getModule().getAssociatedContext(); auto *CMI = cast<MethodInst>(AI.getCallee()); if (!calleesAreStaticallyKnowable(AI.getModule(), CMI->getMember())) return false; auto *Method = CMI->getMember().getAbstractFunctionDecl(); if (!Method->isOverridden()) return true; ... return true; } ϝιου͕z࣮࣭pOBMzͳύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  48. DBMMFFT"SF4UBUJDBMMZ,OPXBCMF bool swift::calleesAreStaticallyKnowable(SILModule &M, SILDeclRef Decl) { ... switch (AFD->getEffectiveAccess())

    { case AccessLevel::Open: return false; case AccessLevel::Public: if (isa<ConstructorDecl>(AFD)) { auto *ND = AFD->getDeclContext()->getSelfNominalTypeDecl(); if (ND->getEffectiveAccess() == AccessLevel::Open) return false; } case AccessLevel::Internal: return M.isWholeModule(); case AccessLevel::FilePrivate: case AccessLevel::Private: return true; } } ϝιουΛ੩తʹܾఆͰ͖Δύλʔϯ MJC4*-0QUJNJ[FS6UJMT-PDBMDQQ
  49. JT&⒎FDUJWFMZ'JOBM.FUIPE static bool isEffectivelyFinalMethod(FullApplySite AI, SILType ClassType, ClassDecl *CD, ClassHierarchyAnalysis

    *CHA) { if (CD && CD->isFinal()) return true; const DeclContext *DC = AI.getModule().getAssociatedContext(); auto *CMI = cast<MethodInst>(AI.getCallee()); if (!calleesAreStaticallyKnowable(AI.getModule(), CMI->getMember())) return false; auto *Method = CMI->getMember().getAbstractFunctionDecl(); if (!Method->isOverridden()) return true; ... return true; } ϝιου͕z࣮࣭pOBMzͳύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  50. JT&⒎FDUJWFMZ'JOBM.FUIPE static bool isEffectivelyFinalMethod(FullApplySite AI, SILType ClassType, ClassDecl *CD, ClassHierarchyAnalysis

    *CHA) { ... if (!Method->isOverridden()) return true; ClassHierarchyAnalysis::ClassList Subs; getAllSubclasses(CHA, CD, ClassType, AI.getModule(), Subs); auto *ImplMethod = CD->findImplementingMethod(Method); for (auto S : Subs) { auto *ImplFD = S->findImplementingMethod(Method); if (ImplFD != ImplMethod) return false; } return true; } ϝιου͕z࣮࣭pOBMzͳύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  51. JT&⒎FDUJWFMZ'JOBM.FUIPE static bool isEffectivelyFinalMethod(FullApplySite AI, SILType ClassType, ClassDecl *CD, ClassHierarchyAnalysis

    *CHA) { ... if (!Method->isOverridden()) return true; ClassHierarchyAnalysis::ClassList Subs; getAllSubclasses(CHA, CD, ClassType, AI.getModule(), Subs); auto *ImplMethod = CD->findImplementingMethod(Method); for (auto S : Subs) { auto *ImplFD = S->findImplementingMethod(Method); if (ImplFD != ImplMethod) return false; } return true; } ϝιου͕z࣮࣭pOBMzͳύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  52. JT&⒎FDUJWFMZ'JOBM.FUIPE static bool isEffectivelyFinalMethod(FullApplySite AI, SILType ClassType, ClassDecl *CD, ClassHierarchyAnalysis

    *CHA) { ... if (!Method->isOverridden()) return true; ClassHierarchyAnalysis::ClassList Subs; getAllSubclasses(CHA, CD, ClassType, AI.getModule(), Subs); auto *ImplMethod = CD->findImplementingMethod(Method); for (auto S : Subs) { auto *ImplFD = S->findImplementingMethod(Method); if (ImplFD != ImplMethod) return false; } return true; } ϝιου͕z࣮࣭pOBMzͳύλʔϯ MJC4*-0QUJNJ[FS6UJMT%FWJSUVBMJ[FDQQ
  53. 0WFSSJEF͞ΕͭͭΠϯελϯε͕ ͦͷαϒΫϥεʹͳΓಘͳ͍৔߹ class Cat<Name> { func bark() {} } enum

    Tama {} enum Kuro {} class TamaCat: Cat<Tama> { override func bark() {} } func callBark(cat: Cat<Kuro>) { cat.bark() }
  54. class Cat<Name> { func bark() {} } enum Tama {}

    enum Kuro {} // Cat<Kuro>ͷαϒλΠϓͰ͸ͳ͍ class TamaCat: Cat<Tama> { override func bark() {} } func callBark(cat: Cat<Kuro>) { cat.bark() } 0WFSSJEF͞ΕͭͭΠϯελϯε͕ ͦͷαϒΫϥεʹͳΓಘͳ͍৔߹
  55. JT&⒎FDUJWFMZ'JOBM.FUIPE ϝιου͕z࣮࣭pOBMzͳύλʔϯ

  56. ʮΘΜʯ໰୊

  57. class Cat { func bark() -> String { return “ʹΌΜ"

    } } class Dog { func bark() -> String { return "ΘΜ" } } let cat = Cat() let dog = unsafeBitCast(cat, to: Dog.self) print(dog.bark()) // ΘΜ ࠷దԽ͋Γͷ৔߹ Dog.barkϝιου͸non-final ΦʔόʔϥΠυ͞Ε͍ͯͳ͍ͷͰ”࣮࣭final” dog.bark()͕Static Dispatchʹ࠷దԽ͞ΕΔ
  58. ࠷దԽͳ͠ͷ৔߹ class Cat { func bark() -> String { return

    “ʹΌΜ" } } class Dog { func bark() -> String { return "ΘΜ" } } let cat = Cat() let dog = unsafeBitCast(cat, to: Dog.self) print(dog.bark()) // ʹΌΜ Whole Module࠷దԽ͕Φϑ Ϟδϡʔϧ಺ͰΦʔόʔϥΠυ͞ΕΔՄೳੑ͕͋Δ ΠϯελϯεͷϝλσʔλͷVTable͔Β Dynamic Dispatch͢Δ
  59. %JTQBUDI 1FSGPSNBODF

  60. LBUFJOPJHBLVLVO%JTQBUDI#FODINBSL

  61. 3VOUJNF1FSGPSNBODF /VNCFSPGEJTQBUDI $165JNF

  62. ·ͱΊ w %ZOBNJD%JTQBUDI͸΍͸Γ஗͍ w pOBM΍QSJWBUF͸ͪΌΜͱޮՌ͕͋Δ w ͕ɺίϯύΠϥ͕ݡ͍ͷͰେମ4UBUJD%JTQBUDIʹͳΔ w ίϯύΠϥΛಡΊ͹4XJGUͷڍಈ͕෼͔͓ͬͯ΋͠Ζ͍

  63. w IUUQTHJUIVCDPNBQQMFTXJGUCMPCNBTUFSEPDT4*-STU w IUUQTHJUIVCDPNBQQMFTXJGUCMPCNBTUFSEPDT 0QUJNJ[BUJPO5JQTSTUSFEVDJOHEZOBNJDEJTQBUDI w !PNPDIJNFUBSV4XJGUͷδΣωϦοΫͳϓϩτίϧͷม਺͸ͳͥ࡞Εͳ͍ͷ͔ɺ ίϯύΠϧޙͷதؒݴޠΛݟͯߟ͑ͨ  

    w IUUQTRJJUBDPNPNPDIJNFUBSVJUFNTCFFBBBFGB ࢀߟ