Scala2.10 bytecode problem hemplant Inc. @OE_uia / Taisuke Oe 13年3月14日木曜日
Q.以下のソースコードをコンパイルした際の bytecode、Scala2.10と2.9で 違うってご存知でしたか? 13年3月14日木曜日
Scala2.9.x javap -c Hello$delayedInit$body ------ public final class Hello$delayedInit$body extends scala.runtime.AbstractFunction0 implements scala.ScalaObject{ public final java.lang.Object apply(); Code: 0:new#7; //class Duck 3:dup 4:invokespecial#12; //Method Duck."<init>":()V 7:invokevirtual#15; //Method Duck.fly:()V 10:getstatic#21; //Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit; 13:areturn ...... } 13年3月14日木曜日
Scala2.10.x javap -c Hello$delayedInit$body ------ public final class Hello$delayedInit$body extends scala.runtime.AbstractFunction0{ public final java.lang.Object apply(); Code: 0:new#9; //class Duck 3:dup 4:invokespecial#13; //Method Duck."<init>":()V 7:invokevirtual#18; //Method Bird.fly:()V 10:getstatic#24; //Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit; 13:areturn ..... } 13年3月14日木曜日
Scala2.9.xでは子クラス(Duck)のメソッドとして呼び出 すbytecodeを生成するのに対し  7:invokevirtual#15; //Method Duck.fly:()V Scala 2.10.xではメソッドを実装した親クラス(Bird)の メソッドとして呼び出すbytecodeが生成される。  7:invokevirtual#18; //Method Bird.fly:()V 13年3月14日木曜日
何か問題でも? Android 4.1以上のライブラリ + Scala2.10.x  + Android4.0以下の端末 de NoSuchMethodError 13年3月14日木曜日
前提として • Android APIのクラスファイルは実行ファイ ル(apk)には含まれず、Android端末内のも のを参照する。 • AndroidのtargetSDKversionより、 minSDKversionが低いことはよくありま す。 (例: Android 4.1以上の場合は4.1で 追加された「ほげほげView」を使うけど、 Android 2.3では他のViewで代替する、な ど。) 13年3月14日木曜日
何か問題でも? Android 4.1以上のライブラリ + Scala2.10.x  + Android4.0以下の端末 だと.... 13年3月14日木曜日
SQLiteDatabaseを閉じれない!! threadid=1: thread exiting with uncaught exception (group=0x40abd210) FATAL EXCEPTION: main java.lang.NoSuchMethodError: android.database.sqlite.SQLiteClosable.close at com.hemplant.demo.no_such_method_in_2_10.DemoActivity.onCreate(DemoActivity.scala:18) at android.app.Activity.performCreate(Activity.java:4465) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) .... 13年3月14日木曜日
Why? SQLiteDatabase ・Android1.5からcloseメソ ッドを持っている。 ・closeメソッドを実装している クラスが、Android4.1から変 更された。 13年3月14日木曜日
Android4.0までは、SQLiteDatabaseで closeメソッドが実装されていた。 13年3月14日木曜日
Android4.1からはSQLiteDatabaseの親クラス SQLiteClosableでcloseメソッドが実装 され、SQLiteDatabaseは継承したcloseメソッドを 使用するように変更された。 13年3月14日木曜日
逆に言えばAndroid4.0までは、 SQLiteDatabaseの親クラス SQLiteClosableにcloseメソッドは無かった。 (名前がClosableなのに!) 13年3月14日木曜日
closeメソッドの実装まとめ ~Android 4.0 Android4.1~ SQLiteClosable × ⃝ .close SQLiteDatabase ⃝ 継承 .close 13年3月14日木曜日
ここでもう一度 13年3月14日木曜日
Scala2.9.xでは子クラス(Duck)のメソッドとして 呼び出すbytecodeを生成するのに対し  7:invokevirtual#15; //Method Duck.fly:()V Scala 2.10.xではメソッドを実装した親クラス (Bird)のメソッドとして呼び出すbytecodeが生成さ れる。  7:invokevirtual#18; //Method Bird.fly:()V 13年3月14日木曜日
(Android4.1以上をtargetにすると) Scala2.9.xだとSQLiteDatabaseのメソッドとして 呼び出すbytecodeを生成するのに対し、 58:invokevirtual#55; //Method android/database/sqlite/SQLiteDatabase.close:()V Scala 2.10.xだとSQLiteClosable(closeを実装した 親クラス)のメソッドとして呼び出すbytecodeを生成。 => Android4.0以下には無い!! => NoSuchMethodError 58:invokevirtual#55; //Method android/database/sqlite/SQLiteClosable.close:()V 13年3月14日木曜日
まとめ • Scala2.10からは、そのメソッドを実装したクラス(当該インス タンスのクラスor親クラス)のメソッドとしてinvokevirtualす るbytecodeが生成される。 • 実行環境と開発環境のクラスファイルが一致しないケースで、かつ メソッドを実装したクラスに違いがあると、一見イミフな NoSuchMethodErrorを吐き出すので注意。 • 具体的には、Android4.1以上をtarget SDK versionにし たら、Scala2.10.xを使わないか、minSdkVersionも4.1 以上を指定すること。 13年3月14日木曜日
最後に • Scala2.10.xで、なぜこんな変更をされたの か、経緯をご存知の方教えてください! (当面 codegenしてissuesに上げつつ、ソースの diff追います。) • 再現用プロジェクトLink: • https://github.com/taisukeoe/scala_2_10_android_error 13年3月14日木曜日

Scala2.10.x bytecode problems in Android

  • 1.
    Scala2.10 bytecode problem hemplant Inc. @OE_uia / Taisuke Oe 13年3月14日木曜日
  • 2.
    Q.以下のソースコードをコンパイルした際の bytecode、Scala2.10と2.9で 違うってご存知でしたか? 13年3月14日木曜日
  • 3.
    Scala2.9.x javap -c Hello$delayedInit$body ------ public final class Hello$delayedInit$body extends scala.runtime.AbstractFunction0 implements scala.ScalaObject{ public final java.lang.Object apply(); Code: 0:new#7; //class Duck 3:dup 4:invokespecial#12; //Method Duck."<init>":()V 7:invokevirtual#15; //Method Duck.fly:()V 10:getstatic#21; //Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit; 13:areturn ...... } 13年3月14日木曜日
  • 4.
    Scala2.10.x javap -c Hello$delayedInit$body ------ public final class Hello$delayedInit$body extends scala.runtime.AbstractFunction0{ public final java.lang.Object apply(); Code: 0:new#9; //class Duck 3:dup 4:invokespecial#13; //Method Duck."<init>":()V 7:invokevirtual#18; //Method Bird.fly:()V 10:getstatic#24; //Field scala/runtime/BoxedUnit.UNIT:Lscala/runtime/BoxedUnit; 13:areturn ..... } 13年3月14日木曜日
  • 5.
    Scala2.9.xでは子クラス(Duck)のメソッドとして呼び出 すbytecodeを生成するのに対し  7:invokevirtual#15; //Method Duck.fly:()V Scala2.10.xではメソッドを実装した親クラス(Bird)の メソッドとして呼び出すbytecodeが生成される。  7:invokevirtual#18; //Method Bird.fly:()V 13年3月14日木曜日
  • 6.
    何か問題でも? Android 4.1以上のライブラリ + Scala2.10.x  + Android4.0以下の端末 de NoSuchMethodError 13年3月14日木曜日
  • 7.
    前提として • Android APIのクラスファイルは実行ファイ ル(apk)には含まれず、Android端末内のも のを参照する。 • AndroidのtargetSDKversionより、 minSDKversionが低いことはよくありま す。 (例: Android 4.1以上の場合は4.1で 追加された「ほげほげView」を使うけど、 Android 2.3では他のViewで代替する、な ど。) 13年3月14日木曜日
  • 8.
    何か問題でも? Android 4.1以上のライブラリ + Scala2.10.x  + Android4.0以下の端末 だと.... 13年3月14日木曜日
  • 9.
    SQLiteDatabaseを閉じれない!! threadid=1: threadexiting with uncaught exception (group=0x40abd210) FATAL EXCEPTION: main java.lang.NoSuchMethodError: android.database.sqlite.SQLiteClosable.close at com.hemplant.demo.no_such_method_in_2_10.DemoActivity.onCreate(DemoActivity.scala:18) at android.app.Activity.performCreate(Activity.java:4465) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) .... 13年3月14日木曜日
  • 10.
    Why? SQLiteDatabase ・Android1.5からcloseメソ ッドを持っている。 ・closeメソッドを実装している クラスが、Android4.1から変 更された。 13年3月14日木曜日
  • 11.
    Android4.0までは、SQLiteDatabaseで closeメソッドが実装されていた。 13年3月14日木曜日
  • 12.
    Android4.1からはSQLiteDatabaseの親クラス SQLiteClosableでcloseメソッドが実装 され、SQLiteDatabaseは継承したcloseメソッドを 使用するように変更された。 13年3月14日木曜日
  • 13.
    逆に言えばAndroid4.0までは、 SQLiteDatabaseの親クラス SQLiteClosableにcloseメソッドは無かった。 (名前がClosableなのに!) 13年3月14日木曜日
  • 14.
    closeメソッドの実装まとめ ~Android 4.0 Android4.1~ SQLiteClosable × ⃝ .close SQLiteDatabase ⃝ 継承 .close 13年3月14日木曜日
  • 15.
  • 16.
    Scala2.9.xでは子クラス(Duck)のメソッドとして 呼び出すbytecodeを生成するのに対し  7:invokevirtual#15; //Method Duck.fly:()V Scala 2.10.xではメソッドを実装した親クラス (Bird)のメソッドとして呼び出すbytecodeが生成さ れる。  7:invokevirtual#18; //Method Bird.fly:()V 13年3月14日木曜日
  • 17.
    (Android4.1以上をtargetにすると) Scala2.9.xだとSQLiteDatabaseのメソッドとして 呼び出すbytecodeを生成するのに対し、 58:invokevirtual#55; //Method android/database/sqlite/SQLiteDatabase.close:()V Scala 2.10.xだとSQLiteClosable(closeを実装した 親クラス)のメソッドとして呼び出すbytecodeを生成。 => Android4.0以下には無い!! => NoSuchMethodError 58:invokevirtual#55; //Method android/database/sqlite/SQLiteClosable.close:()V 13年3月14日木曜日
  • 18.
    まとめ • Scala2.10からは、そのメソッドを実装したクラス(当該インス タンスのクラスor親クラス)のメソッドとしてinvokevirtualす るbytecodeが生成される。 • 実行環境と開発環境のクラスファイルが一致しないケースで、かつ メソッドを実装したクラスに違いがあると、一見イミフな NoSuchMethodErrorを吐き出すので注意。 • 具体的には、Android4.1以上をtarget SDK versionにし たら、Scala2.10.xを使わないか、minSdkVersionも4.1 以上を指定すること。 13年3月14日木曜日
  • 19.
    最後に • Scala2.10.xで、なぜこんな変更をされたの か、経緯をご存知の方教えてください! (当面 codegenしてissuesに上げつつ、ソースの diff追います。) • 再現用プロジェクトLink: • https://github.com/taisukeoe/scala_2_10_android_error 13年3月14日木曜日