原文:Static Dispatch Over Dynamic Dispatch

Author: Shubham Bakshi

[a] dispatch [b] dispatch [C] dispatch [D] dispatch Message-dispatch system (message-dispatch system

Like the comment and hope it gets better and better with your help

Author: @ios growth refers to north, this article was first published in the public number iOS growth refers to north, welcome to the correction

Please contact me if there is a need to reprint, remember to contact oh!!

This is the first day of my participation in Gwen Challenge

Method dispatch is a term that refers to the mechanism by which a program determines which operation (by operation, in this case, a set of instructions) should be performed. Sometimes we just want to determine the specific method behavior at run time. This mechanism leads to different method distribution mechanisms, each with its own advantages and disadvantages.

Static distributed

  • Sometimes calledDirect call/dispatch.
  • If a method is dispatched statically, the compiler can find the instruction’s location at compile time. This way, when such a function is called, the system jumps directly to the function’s memory address to perform the operation. This direct behavior results in very fast execution and also allows the compiler to perform various optimizations, such asinline. In fact, because of the huge improvement in performance, there is a phase in the compilation pipeline where the compiler attempts to make the function static where applicable. This optimization is calledTo virtualization[1].

Dynamic dispatch

  • With this approach, the program does not know which implementation to choose until run time.
  • Although static distribution is extremely lightweight, it limits flexibility, especially in polymorphism. Is this why dynamic distribution is widely supported by OOP languages
  • Each language has its own mechanism to support dynamic scheduling. Swift provides two ways to achieve dynamism:Table distribution (table distribution)andMessage dispatch (message dispatch).

Provided by the Table(Form distributed)

  • This is the most common choice in compiled languages. In this way, a class is associated with a so-called virtual table, which contains an array of Pointers to functions corresponding to the actual implementation of the class.
  • Note that the Vtable is constructed at compile time. Therefore, there are really two additional instructions (readandjump). In theory, watches should also be distributed quickly.

The Message sent(Message distribution)

  • In fact, this mechanism (sometimes called messaging) is provided by Objective-C[2]Swift code uses only the Objective-C runtime. Every time an Objective-C method is called, the call is passed toobjc_msgSend, the latter is responsible for handling the search. Technically, the runtime starts with a given class and grabs the hierarchy of the class to determine which method to call.
  • Unlike table distribution,message passing dictionaryModifications can occur at run time, allowing us to adjust the behavior of the program at run time. And taking advantage of that,Method swizzlingBecome the most popular technology.
  • Messaging is the most dynamic of the three (actually four) types of messaging. In exchange, although the system implements a caching mechanism to ensure lookup performance, the cost of implementation may be slightly higher.
  • This mechanism is the cornerstone of the Cocoa framework. Look at the source code Swift, you will find that KVO is using Swizzling implementation.

Two questions about Swift distribution

For a given function, what distribution does it use? What is the evidence?

Methods for determining distribution mechanisms

As a sceptic, I’m more interested in the second part of the question. It’s easy to make a hypothesis, but it’s not easy to test it all the time. After hours of searching, I happened to know the SIL document [3], which reasonably explained the existence of a dispatch policy. Here’s a brief summary:

  1. If the function is dispatched using a table, it appears in the VTABLE (or witness_table for the protocol)

    sil_vtable Animal{#Animal.makeSound!1: (Animal) -> () -> () : main.Animal.makeSound() -> ()	// Animal.makeSound()
      .
    }
    Copy the code
  2. If the function is dispatched by message, the keyword volatile should appear in the call. In addition, you’ll find two tags foreign and objc_method, indicating that the function/method is called using the Objective-C runtime. Reference [4]

    %14 = class_method [volatile] %13 : $Dog, #Dog.goWild! 1.foreign : (Dog) -> () -> (), $@convention(objc_method) (Dog) -> ()Copy the code
  3. If neither of the above conditions occurs, then the function/method uses static scheduling.

trivia

  • First, a Struct or function of any value type must be dispatched statically. And that makes sense, because they’re never covered.

  • Clear implementation

    • Functions with the final keyword are also dispatched statically.

    • Functions with the dynamic keyword will be delivered via messaging — starting with Swift 4.0

      Functions with the dynamic keyword are implicitly visible to Objective-C. Also, Swift 4 requires you to declare it explicitly using the @objc attribute.

  • Normal extensions (that is, no final, dynamic, @objc) are distributed directly. Now, think back to a compilation error you might have encountered: declarations in Extensions cannot override yet. This is because these functions are, of course, statically distributed.

    You may be asking, “What if I want these extensions to be dynamic?” . You got it! If the extension is dynamic, it can be overridden.

    extension Animal {
    	func eat(a){}@objc dynamic func getWild(a){}}class Dog: Animal {
    	override func eat(a){}// Compiled error!
    	@objc dynamic override func getWild(a){}// Ok :)
    }
    Copy the code

Other situations

protocol Noisy {
	func makeNoise(a) -> Int	// TABLE
}
extension Noisy {
	func makeNoise(a) -> Int { return 0 }	// TABLE
	func isAnnoying(a) -> Bool { return true }	// STATIC
}
class Animal: Noisy {
	func makeNoise(a) -> Int { return 1 }	// TABLE
	func isAnnoying(a) -> Bool { return false } // TABLE
	@objc func sleep(a){}// Still TABLE
}
extension Animal {
	func eat(a){}// STATIC
	@objc func getWild(a){}// MESSAGE
}
Copy the code
  • Noisy.isannoying () and animal.getwild () are statically distributed because they are extensions.

  • Noisy. MakeNoise () uses table dispatch despite having a default implementation.

  • IsAnnoying () must be used carefully. Consider the following two usages.

    Animal2.isannoying () selects the implementation of the protocol extension (since it is a direct method, no look-up is required). Used in this way can be a source of error

    let animal1 = Animal(a)print(animal1.isAnnoying())	// Value: false
    let animal2: Noisy = Animal(a)print(animal2.isAnnoying())	// Value: true
    Copy the code

    Conversely, animal1.makenoise () and animal2.makenoise () produce the same result because the protocol is resolved by looking up tables.

    The @objc func sleep() modifier with the @objc keyword means that the function is visible to Objective-C. But that doesn’t necessarily mean that distribution should be executed in objective-C methods. From the SIL of the function call (see below), we can see $@convention(method), which means choosing the Swift method over the objC method.

    %9 = class_method %8 : $Animal, #Animal.sleep! 1 : (Animal) -> () -> (), $@convention(method) (@guaranteed Animal) -> () // user: %10Copy the code

What are the principles?

  • Direct invocation (static dispatch) is preferred.
  • If overwriting is required, table dispatch is the next candidate.
  • Do you need coverage and visibility in Objective-C? Then send the message.

Another key is better clarity. Implicit inferences (such as extensions with @objc) can change.

Here is a summary of some common cases. It is recommended that you double check by reading the generated SIL.

Direct call Table Message
Clear implementation final.static dynamic
Value types All the methods
agreement Methods in development Defined methods
class Methods in development Defined methods with@objcThe extension of the

Table 1. Summary of method distribution in Swift (read from top to bottom). Note that some cases are already mentioned above in explicit coercion, such as class extensions with @objc Dynamic. Many blog posts divide classes into two categories: NSObject subclasses and (general) classes. Although NSObject inherits many methods written on top of the Objective-C runtime, I see no reason to separate them.

conclusion

In this article, we learned what method dispatches are and the different types of dispatches in Swift. Let’s look at some examples to see how Swift resolves specific functions. In addition, by reading the SIL, we gather evidence about exactly which distributive assumptions the function follows.

  • Static distribution is becoming increasingly important because of its superior performance. That’s why Swift is, rightSwift(As opposed to Objective-C, a dynamic language).
  • While the performance of messaging may seem poor, it provides so much flexibility that it supports a range of cool technologies.
  • Understanding method distribution is critical. Not only does it help you write better code, it also avoids some weird errors.
  • In all of the above, compiler optimizations were abandoned. The compiler’s ability to optimize code depends largely on how we write it :).

Finally, things may be different in higher Swift versions. Don’t forget to check the validity of this article 😇

[5][6][7][8][9] I hope it will be helpful to you

The resources

Devirtualization in LLVM and Clang: blog.llvm.org/2017/03/dev…

The message passing:en.wikipedia.org/wiki/Messag…

Swift Intermediate Language (SIL) : github.com/apple/swift…

The dynamic dispatch:github.com/apple/swift…

Method Dispatch in Swift – by Brian King:www.raizlabs.com/dev/2016/12…

The Case for Message Passing in Swift – by Michael Buckley:www.buckleyisms.com/home/2014/6…

(swift) Dynamic keyword – by Srdan:dev.srdanstanic.com/ios/swift/2…

Friday 2014-07-04 Q&A: Secrets of Swift ‘s Speed:www.mikeash.com/pyblog/frid…

The Swift Programming Language (Swift) : Declaration Modifiers:developer.apple.com/library/con…


If you have any questions, please comment directly, and feel free to express anything wrong with the article. If you wish, you can spread the word by sharing this article.

Thank you for reading this! 🚀