Source code

OCEval- hot implementation of ObjectiveC thermal recovery plan


OCEval

demand

Currently popular JSPatch/RN based on JavaScriptCore provides iOS hot repair and dynamic solutions. However, Objective-C must be invoked by sending Javascript scripts. In particular, JSPatch has written a large number of JS codes to call OC, which is inefficient in development. A better solution is to directly write Objective-C code to achieve hot repair or dynamic solutions. The development efficiency is higher and the code execution efficiency is higher.

In Python, JavaScript and other scripting languages, there is a Eval () function to execute the code directly and dynamically. So I realized. OCEval This library enables us to execute Objective-C code directly and dynamically. Examples are as follows:

 NSString *inputStr = @ return 1 + 3 < 4 & & [NSString string]! = nil; ;
NSNumber *result = [OCEval eval:inputStr]; / / result: @ (YES)

In order to achieve the same hot repair function as JSPatch, the method replacement is added. We can perform the thermal repair function by replacing the existing App with the Objective-C code.

 / / in the new imp, call the old method directly.
NSString *viewDidLoad2 = @ @ /
[originalInvocation invoke]; /
"
;

[OCEval hookClass: @ @ ViewController @
Selector: @ @ viewDidLoad @
ArgNames:@[]
IsClass: NO
Implementation:viewDidLoad2];

OCEval can even be used to complete a page or App, and send it down dynamically. I realized a simple page in iOS's Demo, and I saw the source code in detail.

Realization principle

The performance of C and C++ is high because the compiled language has generated machine code at compile time. It only needs to execute machine code at runtime, so its execution efficiency is high, but its dynamic performance is poor. The poor performance of JS is due to the fact that the runtime engine of JS is usually compiled before implementation. The advantage is good dynamic. Like Dart and python, etc., you can compile and execute packages or JIT (Just in time).

Unlike C and C++, Objective-C is a dynamic language. Objective-C's runtime uses message sending and forwarding to execute any method dynamically. At the same time, Objective-C is different from fully dynamic language such as JavaScript. Because most calls are determined at compile time, compile executable files (mach-O).

So we implemented a lightweight interpreter in OCEval, dynamically interpreted Objective-C code, and dynamically executed Objective-C code with OC runtime message forwarding, so that we could achieve a fully dynamic way similar to eval () function.

interpreter

The compilation process of Objective-C under LLVM:

Source code > AST > LLVM IR (middle language) > LLVM Bytecode > ASM > Native

The front end of LLVM is Clang, and Clang's job is to turn source code into AST syntax spanning tree.

The front-end compilation process of Clang:

  • Preprocesser Include: #include #import and other preprocessing, #if, #ifdef and other conditions, #define and other macro definitions

  • Lexer Lexical analysis, turning text into token (Tokenizer).

  • Parser Grammatical analysis, turning token into AST

But in OCEval, it is not so complicated because it is only for execution. So we only realized lexical analysis and grammatical analysis, and got the syntax spanning tree AST.

Runtime

When executed, each instruction is executed recursively. The runtime used here is mainly NSInvocation, making use of the calling convention of the methodSignature encapsulation method, which is exactly the same as that of JSPatch/RN.

 + ( ID InvokeWithCaller: ( ID Caller selectorName: ( NSString * selectorName argments: ( NSArray *) arguments
{
SEL selector = NSSelectorFromString (selectorName);
     NSInvocation *invocation;
     NSMethodSignature *methodSignature = [caller methodSignatureForSelector:selector];
Invocation= [ NSInvocation InvocationWithMethodSignature:methodSignature];
[invocation setTarget:caller];
[invocation setSelector:selector];
     NSUInteger NumberOfArguments = methodSignature.numberOfArguments;
     NSInteger InputArguments = [arguments count];
     If (inputArguments > numberOfArguments - Two {
         ID Result = invokeVariableParameterMethod (arguments, methodSignature, caller, selector); / / instead of calling objc_msgsend
         Return Result;
}
     Return [ Self InvokeWithInvocation:invocation argments:arguments];
}

Refer to JSPatch, similar to [NSString stringWithFormat:] This variable parameter method is used. Objc_msgsend because NSInvocation The number of uncertain parameters is not supported.

performance

Because the process of parameter passing with JavascriptCore is omitted, the single method invocation is faster than JSPatch/RN, 100% time consuming, half of JSPatch time consuming, multiple method invocation advantages are greater, and the time consuming time may be less than 30%.

The call of NSInvocation is almost the same as that of Native. However, because dynamic calls are very troublesome, entry parameters and calling conventions need to be dynamically defined, while contextual parameters are also slower in memory, so the whole is much slower than native (dynamically necessary sacrifices).

To examine

I have not tried to submit the AppStore audit, but in view of JSPatch's repeated rejection, the possibility of rejection is very great. Our App does not really need any hot fix.

Thank

Thank JSPatch, libff, Aspect

Github links in OCEval

Author: Soyo
Link: https://juejin.im/post/5c24a8396fb9a049d5198dfc
Copyright belongs to the author. For commercial retransmission, please contact the author for authorization.

Fabulous ( Zero )

This article is composed of Contributor Creation, article address: Https://blog.isoyu.com/archives/oceval-dongtaizhixingobjectivecderexiufufangan.html
Use Knowledge sharing signature 4 The international license agreement is licensed. In addition to the reprint / provenance, all originals or translations of this site must be signed before retransmission. The final editing time is January, 2, 2019 at 05:22 afternoon.

Hot articles

Comment

[required]

Invisibility?

Please wait three seconds after submission, so as not to cause unsuccessful successes and duplication.