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

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

Yuta Saito
August 31, 2018

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

Yuta Saito

August 31, 2018
Tweet

More Decks by Yuta Saito

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

  3. ͍͖ͳΓͰ͕͢

    View Slide

  4. ΫΠζͰ͢

    View Slide

  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ΘΜ

    View Slide

  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Կ͕ग़ྗ͞ΕΔͰ͠ΐ͏ʁ
    "ΘΜ

    View Slide

  7. ʮΘΜʯ

    View Slide

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

    View Slide

  9. 2.FUIPEEJTQBUDIͱ͸ʁ

    View Slide

  10. 2.FUIPEEJTQBUDIͱ͸ʁ
    "ϝιου͕ݺͼग़͞ΕΔ࣌ʹɺ

    ࣮ࡍʹͲͷϝιουΛ࣮ߦ͢Δ͔ΛܾΊΔػߏ

    View Slide

  11. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  16. 4UBUJD%JTQBUDI
    w ؔ਺
    w ஋ܕͷϝιου
    w FYUFOTJPOʹॻ͍ͨϝιου
    w pOBMͳϝιου
    struct S {
    func foo() {}
    }
    let s = S()
    s.foo()

    View Slide

  17. 4UBUJD%JTQBUDI
    struct S {
    func foo() {}
    }
    let s = S()
    s.foo()
    ಉ͡γάωνϟͷϝιου͕ଘࡏ͠ͳ͍
    w ؔ਺
    w ஋ܕͷϝιου
    w FYUFOTJPOʹॻ͍ͨϝιου
    w pOBMͳϝιου

    View Slide

  18. %ZOBNJD%JTQBUDI
    w $MBTTͷϝιου
    w 1SPUPDPMͷϝιου
    protocol Animal {
    func foo()
    }
    struct Cat: Animal {
    func foo() {}
    }
    func callFoo(_ animal: T) {
    animal.foo()
    }

    View Slide

  19. w $MBTTͷϝιουΦʔόʔϥΠυ
    w 1SPUPDPMͷϝιουෳ਺ͷܕ͕४ڌ
    %ZOBNJD%JTQBUDI
    protocol Animal {
    func foo()
    }
    struct Cat: Animal {
    func foo() {}
    }
    func callFoo(_ animal: T) {
    animal.foo()
    }
    ಉ͡γάωνϟͷϝιου͕ෳ਺ଘࡏ͢Δ

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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() {}
    }

    View Slide

  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()

    View Slide

  27. 8JUOFTT5BCMF
    w Ծ૝ؔ਺ςʔϒϧ͔ΒϝιουΛ୳ࡧ͢Δ%JTQBUDIํࣜ
    w ϓϩτίϧͷϝιουΛݺͼग़࣌͢ʹ࢖͏
    w ϓϩτίϧ΁ͷ४ڌ͝ͱʹఆٛ͞ΕΔ

    View Slide

  28. protocol Animal {
    func bark()
    }

    View Slide

  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

    View Slide

  30. ʮΘΜʯ໰୊

    View Slide

  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ͷςʔϒϧ͕ࢀর͞ΕΔ
    ʮʹΌΜʯ͕ग़ྗ͞ΕΔ͸ͣʂ

    View Slide

  32. ͔͠͠ɺ

    View Slide

  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()) // ΘΜ
    ʮΘΜʯ

    View Slide

  34. View Slide

  35. ࠷దԽΛΦϑʹͯ͠ΈΔ

    View Slide

  36. $ swiftc -frontend -c -primary-file animal.swift
    $ swiftc animal.o
    $ ./animal
    ʹΌΜ
    ʮʹΌΜʯ

    View Slide

  37. ࠷దԽͷաఔʹԿ͔͋Γͦ͏

    View Slide

  38. %FWJSUVBMJ[F

    View Slide

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

    View Slide

  40. 75BCMFͷ࠷దԽ

    View Slide

  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

    View Slide

  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

    View Slide

  43. %FWJSUVBMJ[FGPS75BCMF
    class Animal {
    func bark() {}
    }
    class Cat: Animal {
    override func bark() {}
    }
    let animal: Animal = Cat() // ΠχγϟϥΠβ͔Β࡞ͬͯΔͷͰCatܕ
    animal.bark()
    Πϯελϯεͷ࣮ߦ࣌ͷܕ͕੩తʹܾఆͰ͖Δύλʔϯ

    View Slide

  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

    View Slide

  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(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

    View Slide

  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(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

    View Slide

  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(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

    View Slide

  48. DBMMFFT"SF4UBUJDBMMZ,OPXBCMF
    bool swift::calleesAreStaticallyKnowable(SILModule &M, SILDeclRef Decl) {
    ...
    switch (AFD->getEffectiveAccess()) {
    case AccessLevel::Open:
    return false;
    case AccessLevel::Public:
    if (isa(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

    View Slide

  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(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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  53. 0WFSSJEF͞ΕͭͭΠϯελϯε͕
    ͦͷαϒΫϥεʹͳΓಘͳ͍৔߹
    class Cat {
    func bark() {}
    }
    enum Tama {}
    enum Kuro {}
    class TamaCat: Cat {
    override func bark() {}
    }
    func callBark(cat: Cat) {
    cat.bark()
    }

    View Slide

  54. class Cat {
    func bark() {}
    }
    enum Tama {}
    enum Kuro {}
    // CatͷαϒλΠϓͰ͸ͳ͍
    class TamaCat: Cat {
    override func bark() {}
    }
    func callBark(cat: Cat) {
    cat.bark()
    }
    0WFSSJEF͞ΕͭͭΠϯελϯε͕
    ͦͷαϒΫϥεʹͳΓಘͳ͍৔߹

    View Slide

  55. JT&⒎FDUJWFMZ'JOBM.FUIPE
    ϝιου͕z࣮࣭pOBMzͳύλʔϯ

    View Slide

  56. ʮΘΜʯ໰୊

    View Slide

  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ʹ࠷దԽ͞ΕΔ

    View Slide

  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͢Δ

    View Slide

  59. %JTQBUDI
    1FSGPSNBODF

    View Slide

  60. LBUFJOPJHBLVLVO%JTQBUDI#FODINBSL

    View Slide

  61. 3VOUJNF1FSGPSNBODF
    /VNCFSPGEJTQBUDI
    $165JNF

    View Slide

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

    View Slide

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

    w IUUQTRJJUBDPNPNPDIJNFUBSVJUFNTCFFBBBFGB
    ࢀߟ

    View Slide