LLVMは、可能な場合、Objective-Cメソッドをインライン関数に自動的に変換しますか?
(つまり、インラインで貼り付けることができるコードのブロックに対してObjective-Cメソッドを作成するのと同じくらいパフォーマンスが良いですか?)
LLVMがこの最適化を実行しない場合は、なぜですか?もしそうなら、(a)これを実現するために設定しなければならない特定のビルド設定はありますか?(b)Objective-Cメソッドがインライン化されるかどうかはどうすればわかりますか?
3 に答える
いいえ、そのような最適化を実行できるかどうかを Obj-C ランタイムのコンテキストで知ることは不可能だからです。覚えておくべきことは、Obj-C メソッドはメッセージ送信によって呼び出されるということです。これらのメッセージは、[myObject doSomething]
構文以外からも発生する可能性があります。
[obj performSelector:NSSelectorFromString(@"hello")]
これが発生する可能性があるという事実は、メソッドをインライン化することは不可能であることを意味すると考えてください。
メッセージがクラスによって受信されたときに発生する一連のイベントもあります。これらのイベントは、送信されるメッセージを再ルーティングしたり、変更したりすることさえあります。これは、メッセージ送信の下で透過的に発生します。
少しの間、コンパイラがメソッドをインライン化すると仮定しましょう。
@implementation AwesomeClass
- (void)doFoo OBJC_INLINE { // or some way to indicate "this is an inline method"
NSLog(@"doing foo!");
}
- (void)doBar {
[self doAwesomeStuff];
[self doFoo];
}
@end
そのため、-doBar
本質的に次のようになります。
- (void)doBar {
[self doAwesomeStuff];
{
NSLog(@"doing foo!");
}
}
すごい、それはもっと速いようですよね?を呼び出さないことで、十数の指示を節約できobjc_msgSend
ます。したがって、これをパッケージ化して、.aファイルとしてオンラインで投稿します。
NSCleverCoderがやって来て、「doFoo
でももう少しやりたい」と言ったので、彼はこうします。
@interface SuperAwesomeClass : AwesomeClass @end
@implementation SuperAwesomeClass
- (void)doFoo {
NSLog(@"doing more foo!");
[super doFoo];
}
@end
彼がこれを実行しようとするとAwesomeClass
、実際にメソッドを呼び出すことはないため、呼び出されることはありません-doFoo
。
「しかし、これは不自然な例です!」とあなたは言います。
いいえ、ちがいます。Objective-Cでは、アプリの開発または実行のどの時点でもこれを行うことは完全に合法です。コードを書くときにこれを行うことができます。ちなみに、サブクラスを動的に作成してメソッドのオーバーライドを追加することobjc_allocateClassPair
で、実行時にこれを行うこともできます。class_addMethod
メソッドの実装をスウィズルすることもできます。-doFoo
?の既存の実装が気に入らない カッコいい; 自分のものと交換してください。えっ、ちょっと待って; メソッドがインライン化されている場合、-doBar
実際にメソッドを呼び出すことはないため、新しい実装が呼び出されることはありません-doFoo
。
これが可能であることがわかったのは、オーバーライドできないものとしてメソッドに注釈を付ける何らかの方法があった場合だけです。しかし、それを行う方法はないので、その問題は議論の余地があります。そしてそれでも、それはまだ悪い考えです。コンパイラがそれを許可しないからといって、実行時にそれを回避できないという意味ではありません。そして再び、あなたは問題にぶつかるでしょう。
いいえ。メッセージのディスパッチ (Obj-Cではメッセージを送信し、メソッドを呼び出さないことを思い出してください) がコンパイル時ではなく実行時に動的に行われることは、Objective-C の重要な機能です。
このため、Obj-C でのメッセージ ディスパッチは、(関数がインライン化されていなくても) 純粋な関数呼び出しよりも常に少し遅くなります。