MacOSX(Intel)に実装されているJavaブリッジにバグを見つけてしまいました。
Objective-CからNSRectを戻り値とするJavaメソッドを呼ぶと、エラーが出てアプリが落ちてしまいます。
Objective-Cのメソッドの実装は、IMP型として定義されており、基本的にC言語の関数と一緒です。そして、このIMP型には、2種類の形態があります。
/*** IMP型 ***/
// 第一形態
typedef id (*IMP)(id, SEL, ...);
// 第二形態
typedef void (*IMP)(void*, id, SEL, ...);そして、第一形態のメソッドを呼ぶときはobjc_msgSend()、第二形態のメソッドを呼ぶときはobjc_msgSend_stret()と、それぞれ使用するObjective-Cのランタイム関数が異なります。
ちなみに、IMP型の第二形態については、実際にはどこにも定義されていません。これは、メソッドの戻り値の型からコンパイラが判断して、第一形態から第二形態へ自動変換されるからです。判断の基準は戻り値のバイト数で、32bit-PowerPCでは4バイト以上、64bit-PowerPCでは64バイト以上、IA-32(Intel CPU)では8バイト以上となっています。それぞれのCPUごとに判断基準が異なるため、Universal BinaryでObjective-Cのランタイム関数を使う場合は要注意です。
それで、呼び出し先のメソッドがObjective-Cだった場合は、objc_msgSend()やobjc_msgSend_stret()から直接目的のメソッドに処理が移ります。しかし、呼び出し先がJavaメソッドだった場合は、objc_msgSend()から_BRIDGEMethodImp()や_BRIDGEMethodImpStructReturn()、objc_msgSend_stret()から_BRIDGEMethodImpStructReturnInCallFrame()に処理が移り、最終的にJavaのメソッドが呼ばれます。
ところがMacOSX(Intel)の場合、ここでobjc_msgSend_stret()から_BRIDGEMethodImpStructReturn()へ処理が移ってしまうのです。_BRIDGEMethodImpStructReturn()と_BRIDGEMethodImpStructReturnInCallFrame()では、引数の型が違うので、エラーになってしまい、最終的にアプリが落ちる結果になります。
MacOSX(Intel)でメソッドが第二形態となる条件は、戻り値8バイト以上で、これはNSRect型などの構造体が該当します。Javaに構造体はありませんが、Objective-Cの呼び出しと整合が取れるようにJavaブリッジがうまく変換してくれます。MacOSX(Intel)では、どうもこの辺にバグがあるようです。
Cocoaフレームワークでは、NSTextInputやNSWindow.Delegateなどによって、フレームワーク側からこの手のメソッドが呼ばれることがあります。このバグの回避策はないので、場合によっては致命的なものとなります。