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日木曜日