$30 off During Our Annual Pro Sale. View Details »

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

コンパイラから紐解く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