Why Objc_msgsend must be implemented in a compilation

Source: Internet
Author: User

Translator Preface

I always see someone saying that the objc_msgsend is for speed, which is undeniable. But isn't there another reason? So I saw this article and translated it! = =

My own understanding is that the assembly is implemented in order to deal with different "calling convention", the function of the stack before the call and register parameters, state settings, to the compiler to deal with.

Let's take a look at the original.

Original Author: Ari Grant

Original link: Why Objc_msgsend must is written in Assembly

http://arigrant.com/blog/2014/2/12/why-objcmsgsend-must-be-written-in-assembly

Begin

For Objective-c, the method of invoking an object instance is also called "Sending a message" to the object instance, and each "message" is transformed into a call to the Objc_msgsend function at compile time, and the parameters of the call not only have all the parameters of the original message, There is also the receiver receiver of the message and the corresponding method selector. As an example, the following statement:

[receiver message: foo beforedate: Bar];

will be compiled into:

Objc_msgsend(receiver, @selector(message: beforedate:), Foo, bar);

For the realization principle of objc_msgsend function, the predecessors have done a lot of exploration. So, this article will focus on a point where objc_msgsend has not been much of a concern before:

Objc_msgsend can not be implemented in Objective-c, C, or C + +.

The return type– type

Let's look at the following two lines of code:

Nsuinteger N = [array count];

ID obj = [array objectatindex:6];

Intuitively, it will be compiled into

Nsuinteger N = objc_msgsend(array, @selector(count));

ID obj = objc_msgsend(array, @selector(objectatindex: ), 6);

But in reality this is not possible, because no function can satisfy both calls at the same time. And its return value cannot be both Nsuinteger and ID.

Also, the code above is not compiled. So, what about the type conversion?

Nsuinteger N = (nsuinteger (*) (ID, SEL))objc_ Msgsend(array, @selector(count));

ID obj = (ID (*) (ID, SEL, Nsuinteger ) )objc_msgsend(array, @selector(objectatindex:), 6);

This can be compiled through, though it doesn't look intuitive ...

Objc_msgsend is a public function, which declares that if you want to invoke it directly, you must follow the above format with the coercion type conversion, or else it cannot be compiled. But how exactly is objc_msgsend implemented to support various return types? It will be discussed later in this article.

The imp– method corresponds to the function pointer

The essence of the Objc_msgsend function is simple, passing in a Recipient object instance receiver and method name selector, which is performed as follows: (Translator note: Only the most sketchy step =. =

    • Get receiver Class

    • In the Class method list method table to find the corresponding selector implementation

    • If you find it, call it back.

    • Cannot find it in its parent class, repeat the previous step (until there is no parent class)

The whole process is simple, along the inheritance chain, find the method selector corresponding function pointer, that is, imp. At the same time, there are caches in each tier class, speeding up the subsequent method lookups. However, this is only the implementation details of the objc_msgsend, so go ahead and look down.

The ARG TYPES and count– parameter types and number

Simply put, once the objc_msgsend has found the corresponding function pointer, it can be called with the arguments passed in. All that remains is to find a way to invoke any function of any parameter type or quantity.

The number of parameters is easy to calculate. Then we can put all the parameters into VarArgs, and then call the function to pass in. In this case, however, each objective-c method must be extracted from the varargs within its prologue (the translator's note: The function performs a specific "task" before the preparation session).

The idea of packing the parameters into the varargs and then taking them out is obviously very bad and unnecessary.

In C, calling a function is compiled into the corresponding assembly language instruction, first setting the parameters (placing parameters on registers, stacks), and then jumping to the specific function code address with instructions such as jump or call. If we want to support any kind of function type, we have to write a switch statement, all the parameter combinations are included, so as to correctly set the parameters for any form of function (translator Note: In accordance with a certain "specification", "convention", the parameters are stored in the "Convention" Register, stack), This is obviously not extensible, and it is impossible.

Unwinding the call– disassembly call

The Objc_msgsend solution is based on the following: When Objc_msgsend is called, all parameters have been set.

In other words, the state, data, and the combination of the various registers, the data, and the state and data required to invoke the specific function pointer (IMP) are exactly the same when the objc_msgsend begins execution.

The following line of code:

ID obj = objc_msgsend(array, @selector(objectatindex:), 6);

When calling Objc_msgsend, you need to set three parameters, namely Callee Receiver, method name selector, and last integer parameter 6. This and the concrete method function Imp's parameter order, the type is identical, namely, before calls Objc_msgsend, sets the stack, the register state, the data is exactly calls the concrete method function the state which needs!

So, when Objc_msgsend finds a function to invoke to implement IMP, it simply needs to "pour" all the stack and register operations back into the state where the Objc_msgsend execution started (similar to the "finishing" work done before the function execution completes the return, That is, epilogue), directly jump/call to the address of the IMP function pointer, execute the instruction, because all the parameters have been set.

At the same time, when the selector corresponding IMP executes, the return value is also set correctly (on the x86 platform, the return value is set to the specified register Eax/rax, on arm, the R0 register), so we do not have to worry about the different types of return value issues mentioned earlier.

Wrap up– Summary

To synthesize all the explanations mentioned above, it is: to call a function in C, you must know the "state" of the call at compile time, and these "states" cannot be derived or handled correctly at runtime, so you must go to the bottom and use the assembly process. (Translator Note: Here do not know how to translate good =.) =, the original is: calling a function in C requires the signature to is known for each call-site at compile-time;doing so at run-time I s not possible and so one must drop to assembly and party there instead.)

update– Follow-up

It has been pointed out that objc_msgsend may have been implemented using the GCC extension method __builtin_apply_args,__builtin_apply, and __builtin_return. This also points to the fact that these builtins methods are very necessary because language alone cannot achieve these functions. The skills needed to implement objc_msgsend are also the skills needed to implement these builtins methods. The purpose of this article is not to be what is really C, what is not true C is clear, just to point out the special objc_msgsend.

Translator Summary

The beginning also said, my understanding is: with the assembly implementation, is to deal with different "calling convention", the function call before the stack and register parameters, state settings, to the compiler to deal with.

Well, don't talk about it in the future just to get it done. =

Why Objc_msgsend must be implemented in a compilation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.