コンパイラから紐解く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. 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ΘΜ
  2. 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Կ͕ग़ྗ͞ΕΔͰ͠ΐ͏ʁ "ΘΜ
  3. 11.
  4. 12.

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

    Cat: Animal { override func bark() { print("ʹΌΜ") } } func callAnimalBark(_ animal: Animal) { animal.bark() }
  5. 13.

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

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

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

    Cat: Animal { override func bark() { print("ʹΌΜ") } } func callAnimalBark(_ animal: Animal) { animal.bark() // ΞχϚϧͰ͢ or ʹΌΜ } ࣮ߦ͞ΕΔϝιου͸Ͳͬͪʁʁ
  7. 17.

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

    = S() s.foo() ಉ͡γάωνϟͷϝιου͕ଘࡏ͠ͳ͍ w ؔ਺ w ஋ܕͷϝιου w FYUFOTJPOʹॻ͍ͨϝιου w pOBMͳϝιου
  8. 18.

    %ZOBNJD%JTQBUDI w $MBTTͷϝιου w 1SPUPDPMͷϝιου protocol Animal { func foo()

    } struct Cat: Animal { func foo() {} } func callFoo<T: Animal>(_ animal: T) { animal.foo() }
  9. 19.

    w $MBTTͷϝιουΦʔόʔϥΠυ w 1SPUPDPMͷϝιουෳ਺ͷܕ͕४ڌ %ZOBNJD%JTQBUDI protocol Animal { func foo()

    } struct Cat: Animal { func foo() {} } func callFoo<T: Animal>(_ animal: T) { animal.foo() } ಉ͡γάωνϟͷϝιου͕ෳ਺ଘࡏ͢Δ
  10. 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()
  11. 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
  12. 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ͷςʔϒϧ͕ࢀর͞ΕΔ ʮʹΌΜʯ͕ग़ྗ͞ΕΔ͸ͣʂ
  13. 32.
  14. 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()) // ΘΜ ʮΘΜʯ
  15. 34.
  16. 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
  17. 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
  18. 43.

    %FWJSUVBMJ[FGPS75BCMF class Animal { func bark() {} } class Cat:

    Animal { override func bark() {} } let animal: Animal = Cat() // ΠχγϟϥΠβ͔Β࡞ͬͯΔͷͰCatܕ animal.bark() Πϯελϯεͷ࣮ߦ࣌ͷܕ͕੩తʹܾఆͰ͖Δύλʔϯ
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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() }
  29. 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͞ΕͭͭΠϯελϯε͕ ͦͷαϒΫϥεʹͳΓಘͳ͍৔߹
  30. 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ʹ࠷దԽ͞ΕΔ
  31. 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͢Δ