89
Koichi Sakata (阪田 浩一) @jyukutyo How Scala code is expressed in the JVM ScalaMatsuri 2016

How Scala code is expressed in the JVM

Embed Size (px)

Citation preview

Koichi  Sakata  (阪田  浩一)  @jyukutyo

How  Scala  code  is  expressed  in  the  JVM  

-­‐  ScalaMatsuri  2016  -­‐

関ジャバです!

2

@jyukutyo

produced three Java framework books one was translated into Korean

JUG Leader (KansaiJUG)

blog:Fight the Future http://jyukutyo.hatenablog.com/

FURYU CORPORATION

age: 36

Koichi Sakata (阪田 浩一)

フリューの阪田です 関ジャバの会長です

I  ♥  JVM

this  session  is  for  beginners  

about  JVM  byte  codesこのセッションは

JVMのバイトコード初心者向けです

Do  you  know  what  happens  

when  we  compile  Scala  code?

Scalaコードをコンパイルする時 何が起こるかご存じでしょうか?

Java

Scala

JRuby

Groovy

Compiler

Class  file

cafe babe 0000 0032 0017 0100

JVM

Class  fileClass  fileClass  fileClass  fileClass  file § Runs

§ Interprets § Translates bytecode into Native Machine Code

Have  you  ever  opened    

a  class  file?

クラスファイルを開いたことはありますか

First,    let's  try  opening    

a  class  file    from  a  simple    

Java  codeJavaのクラスファイルを開いてみましょう

Hello  World  (Java)  

public  class  HelloWorld  {      public  static  void  main(String[]  args)  {          System.out.println("Hello,  world!");      }  }  § Compiled  into...  

§ HelloWorld.class  

open  HelloWorld.class  

file    with  binary  editor  

e.g.)  hexl-­‐find-­‐file  (Emacs)

クラスファイルをバイナリエディタで開く

cafe  babe  0000  0032  0017  0100  0a48  656c  6c6f  576f  726c  6407  0001  0100  106a  6176  612f  6c61  6e67  2f4f  626a  6563  7407  0003  0100  1048  656c  6c6f  576f  726c  642e  7363  616c  6101  001e  4c73  6361  6c61  2f72  6566  6c65  6374  2f53  6361  6c61  5369  676e  6174  7572  653b  0100  0562  7974  6573  0100  ef06  0115  3a51  2101  0209  0215  0921  0253  336d  593e  3c76  4e1d  3765  1505  1911  6102  1f66  5b42  2418  5050  0201  2109  3171  2144  0103  0d15  4121  0123  010a  0529  4155  0d1c  3770  2f3e  1448  0e5a  0a03  0f29  0122  6103  080e  0331  5111  2144  0106  670e  0c47  2e59  0503  1f31  1161  2111  387a  2516  3407  2242  0908

you  will  close  the  editor  

right  away

すぐにエディタを閉じるでしょう

class  file  has  a  format

クラスファイルには フォーマットがあります

ClassFile  {      u4                          magic;      u2                          minor_version;      u2                          major_version;      u2                          constant_pool_count;      cp_info    constant_pool[constant_pool_count-­‐1];      u2                          access_flags;      u2                          this_class;      u2                          super_class;      u2                          interfaces_count;      u2            interfaces[interfaces_count];  ...  -­‐-­‐  u1  represents  one-­‐byte  quantity,        Hexadecimal  2  digit.

...      u2                          fields_count;      field_info          fields[fields_count];      u2                          methods_count;      method_info      methods[methods_count];      u2                          attributes_count;      attribute_info  attributes[attributes_count];  }  -­‐-­‐  u1  represents  one-­‐byte  quantity,        Hexadecimal  2  digit.

u1が1バイト 16進数では2桁になります

Let's  try  again

cafe  babe  0000  0032  0017  0100  0a48  656c  6c6f  576f  726c  6407  0001  0100  106a  6176  612f  6c61  6e67  2f4f  626a  6563  7407  0003  0100  1048  656c  6c6f  576f  726c  642e  7363  616c  6101  001e  4c73  6361  6c61  2f72  6566  6c65  6374  2f53  6361  6c61  5369  676e  6174  7572  653b  0100  0562  7974  6573  0100  ef06  0115  3a51  2101  0209  0215  0921  0253  336d  593e  3c76  4e1d  3765  1505  1911  6102  1f66  5b42  2418  5050  0201  2109  3171  2144  0103  0d15  4121  0123  010a  0529  4155  0d1c  3770  2f3e  1448  0e5a  0a03  0f29  0122  6103  080e  0331  5111  2144  0106  670e  0c47  2e59  0503  1f31  1161  2111  387a  2516  3407  2242  0908

cafe  babe  0000  0032  

ClassFile  {      u4                          magic;      u2                          minor_version;      u2                          major_version;  

"magic"  is  always  "0xCAFEBABE"

major:  0x0032  =  50  minor:  0x0000  =  0  

50.0  means  Java  SE  6  51.0  is  7,  52.0  is  8...

Yes!

but,  this  is  purgatory

でもこれは苦行です

Never  mind!  We  have  

a  handy  tool!

便利なツールがあります!

javap  command  The  Java  Class  File  Disassembler  § included  in  JDK  § `javap  -­‐v  [FQCN]`  § Scala  REPL  § scala>  :javap  [FQCN]  § equivalent  to  `javap  -­‐v`  

http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javap.html

javap - Java クラスファイル逆アセンブラ

so,  a  class  file    can  be  

disassembled  to  Java  ClassesクラスファイルはJavaのクラスに 逆アセンブルできるのです

javap  -­‐v  HelloWorld

public  class  HelloWorld      minor  version:  0      major  version:  52  Constant  pool:        #1  =  Methodref                    #6.#15                  //  java/lang/Object."<init>":()V        #2  =  Fieldref                      #16.#17                //  java/lang/System.out:Ljava/io/PrintStream;        #3  =  String                          #18                        //  Hello,  world!        #4  =  Methodref                    #19.#20                //  java/io/PrintStream.println:(Ljava/lang/String;)V

Constant  pool  is  a  table  of  symbolic  

informationコンスタントプールは シンボル情報のテーブル

public  static  void  main(java.lang.String[]);  

 Code:                0:  getstatic          #2                                                    3:  ldc                      #3                                            5:  invokevirtual  #4                                            8:  return  

JVM  instructions  aaload aastore aconst_null aload

anewarray areturn arraylength astore

athrow baload bastore bipush

caload castore checkcast d2f

d2i d2l dadd daload

dastore dcmp<op> dconst_<d> ddiv

dload dmul dneg ...

about  200  instructions

Since  first  release  of  Java,  added  instruction  

is  ...Javaが最初にリリースされてから 追加されたJVM命令は...

only  ONE!

Initial  design    of  JVM    

is  excellent!

JVMは初期設計から優秀だった!

instructions  of  method  call  

invokevirtual invoke  instance  method;  dispatched  based  on  class

invokeinterface invoke  interface  method

invokestatic invoke  static  method

invokespecialinvoke  method;  

superclass,  private,  constructor...

invokedynamic invoke  dynamic  method

public  static  void  main(java.lang.String[]);  

 Code:                0:  getstatic          #2                                                    3:  ldc                      #3                                                    5:  invokevirtual  #4                                            8:  return  -­‐-­‐  #0  =  index  of  Constant  pool  

public  class  HelloWorld  Constant  pool:        #1  =  Methodref                    #6.#15                  //  java/lang/Object."<init>":()V        #2  =  Fieldref                      #16.#17                //  java/lang/System.out:Ljava/io/PrintStream;        #3  =  String                          #18                        //  Hello,  world!        #4  =  Methodref                    #19.#20                //  java/io/PrintStream.println:(Ljava/lang/String;)V  ...

OK!  It's  Scala's  turn!

Hello  world

Hello  World  (Scala)  

object  HelloWorld  {      def  main(args:  Array[String])  {          println("Hello,  world!")      }  }  § Compiled  into...  

§ HelloWorld.class  § HelloWorld$.class  

public  final  class  HelloWorld  Constant  pool:  

   #15  =  NameAndType                #13:#14                //  MODULE$:LHelloWorld$;      #16  =  Fieldref                      #12.#15                //  HelloWorld$.MODULE$:LHelloWorld$;      #17  =  NameAndType                #9:#10                  //  main:([Ljava/lang/String;)V      #18  =  Methodref                    #12.#17                //  HelloWorld$.main:  

([Ljava/lang/String;)V  ...

public  static  void    main(java.lang.String[]);  

   0:  getstatic          #16                                    //  Field  HelloWorld$.  

MODULE$:LHelloWorld$;      3:  aload_0      4:  invokevirtual  #18  //  Method  HelloWorld$.main:  

([Ljava/lang/String;)V      7:  return  

-­‐-­‐  4:  in  Java  HelloWorld$.MODULE$.main(arg);

public  final  class  HelloWorld$  -­‐-­‐  omit  Constant  pool  

   public  static  {};                    0:  new                      #2                                    //  class  HelloWorld$                    3:  invokespecial  #12                                  //  Method  "<init>":()V                    6:  return  

-­‐-­‐  <init>  means  constructor  

   public  void  main(java.lang.String[]);                    0:  getstatic          #19                                  //  Field  scala/Predef$.MODULE$:  

Lscala/Predef$;                    3:  ldc                      #21                                  //  String  Hello,  world!                    5:  invokevirtual  #25                                  //  Method  scala/Predef$.println:  

(Ljava/lang/Object;)V                    8:  return  

you  can  read  it!

The  following  samples  are  quoted    

from  tutorials    in  Scala  official  site  

http://docs.scala-­‐lang.org/tutorials/

これ以降で使用するサンプルは Scalaの公式サイトのチュートリアルです

Traits

trait  Similarity  {      def  isSimilar(x:  Any):  Boolean      def  isNotSimilar(x:  Any):  Boolean  =  

 !isSimilar(x)  }  class  Point(xc:  Int,  yc:  Int)    

extends  Similarity  {      var  x:  Int  =  xc      var  y:  Int  =  yc      def  isSimilar(obj:  Any)  =          obj.isInstanceOf[Point]  &&          obj.asInstanceOf[Point].x  ==  x  }  

§ Compiled  into...  § Similarity.class  § Similarity$class.class  § Point.class  

javap  -­‐v

public  interface  Similarity  

   public  abstract  boolean    isSimilar(java.lang.Object);  

         public  abstract  boolean    

isNotSimilar(java.lang.Object);  

public  abstract  class  Similarity$class      public  static  boolean    

isNotSimilar(Similarity,j.l.Object);                    0:  aload_0                    1:  aload_1                    2:  invokeinterface  #13,    2                      //  InterfaceMethod  Similarity.isSimilar:  

(Ljava/lang/Object;)Z                    7:  ifeq                    14                  10:  iconst_0                  11:  goto                    15                  14:  iconst_1                  15:  ireturn

a  trait  is    divided  into    

an  interface  and  an  abstract  classトレイトはインタフェースと 抽象クラスに分かれます

Case  Classes

abstract  class  Term  

case  class  Var(name:  String)    extends  Term  

case  class  Fun(arg:  String,  body:  Term)    extends  Term  

case  class  App(f:  Term,  v:  Term)    extends  Term  

§ Compiled  into...  § Term.class  § App.class  § App$.class  § Fun.class  § Fun$.class  § Var.class  § Var$.class  

javap  -­‐v

public  class  App  extends  Term    implements  s.Product,s.Serializable  

   public  static    s.Option<scala.Tuple2<Term,  Term>>  

unapply(App);      public  static  App  apply(Term,  Term);      public  ...  tupled();      public  ...  curried();      public  Term  f();      public  Term  v();      public  App  copy(Term,  Term);      public  j.l.String  productPrefix();      public  boolean  equals(j.l.Object);  ...

public  final  class  App$  extends    s.r.AbstractFunction2<Term,  Term,  App>  

implements  scala.Serializable      public  App  apply(Term,  Term);                    0:  new                      #23                                  //  class  App                    3:  dup                    4:  aload_1                    5:  aload_2                    6:  invokespecial  #26                                  //  Method  App."<init>":(LTerm;LTerm;)V                    9:  areturn  

Fun  and  Var  looks  the  same  as  App

FunとVarも同様の内容です

Scala  compiler  generates    

many  functions  from  few  snippets  

of  codeScalaコンパイラは少ないコードから 多くの機能を生成しています

Pattern  Matching

object  MatchTest2  extends  App  {      def  matchTest(x:  Any):  Any  =  x  match        {          case  1  =>  "one"          case  "two"  =>  2          case  y:  Int  =>  "scala.Int"      }  

   println(matchTest("two"))  }

§ Compiled  into...  § MatchTest2.class  § MatchTest2$.class  § MatchTest2$delayedInit$body.class  

javap  -­‐v

public  final  class  MatchTest2$    implements  scala.App  

                 7:  invokestatic    #67                                  //  Method  BoxesRunTime.equals:..                  10:  ifeq                    19                  13:  ldc                      #69                                  //  String  one                  15:  astore_3                  16:  goto                    46                  19:  ldc                      #71                                  //  String  two                  21:  aload_2                  22:  invokevirtual  #74                                  //  Method  java/lang/Object.equals:  

                                 19:  ldc                      #71                                  //  String  two                  21:  aload_2                  22:  invokevirtual  #74                                  //  Method  java/lang/Object.equals:  

(Ljava/lang/Object;)Z                  25:  ifeq                    36                  28:  iconst_2                  32:  astore_3                  33:  goto                    46

               36:  aload_2                  37:  instanceof        #76                                  //  class  java/lang/Integer                  40:  ifeq                    48                  43:  ldc                      #78                                  //  String  scala.Int                  45:  astore_3                  46:  aload_3                  47:  areturn  ...

Compiled  into  if  statements

if文へコンパイルしています

in  case  of  another  Pattern  Matching...

違うパターンマッチの場合

object  MatchTest1  {      def  matchTest(x:  Int):  String  =  x  match  {          case  1  =>  "one"          case  2  =>  "two"          case  _  =>  "many"      }      def  main(args:  Array[String])  {          println(matchTest(3))      }  }

javap  -­‐v

                 3:  tableswitch      {  //  1  to  2                                                1:  34                                                2:  29                                    default:  24                          }                  24:  ldc                      #16                                  //  String  many                  26:  goto                    36                  29:  ldc                      #18                                  //  String  two                  31:  goto                    36                  34:  ldc                      #20                                  //  String  one                  36:  areturn

Compiled  into  a  switch  statement

switch文にコンパイルしています

Currying

object  CurryTest  {      def  filter(xs:  List[Int],    

p:  Int  =>  Boolean):  List[Int]  =          if  (xs.isEmpty)  xs          else  if  (p(xs.head))    

xs.head  ::  filter(xs.tail,  p)          else  filter(xs.tail,  p)  

   def  modN(n:  Int)(x:  Int)  =    ((x  %  n)  ==  0)  

   def  main(args:  Array[String])  {          val  nums  =  List(1,  2,  3,  4,    

5,  6,  7,  8)          println(filter(nums,  modN(2)))          println(filter(nums,  modN(3)))      }  }  

§ Compiled  into...  § CurryTest.class  § CurryTest$.class  § CurryTest$$anonfun$main$1.class  § CurryTest$$anonfun$main$2.class  

javap  -­‐v

public  final  class    CurryTest$$anonfun$main$1  extends  

scala.runtime.AbstractFunction1$mcZI$sp  implements  scala.Serializable  

   public  boolean  apply$mcZI$sp(int);                    3:  iconst_2                    4:  iload_1                    5:  invokevirtual  #33                                  //  Method  CurryTest$.modN:(II)Z                    8:  ireturn  

public  final  class    CurryTest$$anonfun$main$2  extends  

scala.runtime.AbstractFunction1$mcZI$sp  implements  scala.Serializable  

   public  boolean  apply$mcZI$sp(int);                    3:  iconst_3                    4:  iload_1                    5:  invokevirtual  #33                                  //  Method  CurryTest$.modN:(II)Z                    8:  ireturn  

   def  main(args:  Array[String])  {          val  nums  =  List(1,  2,  3,  4,    

5,  6,  7,  8)          println(filter(nums,  modN(2)))          println(filter(nums,  modN(3)))      }  }  

each  partial  application  

creates    a  new  class部分適用の箇所ごとに クラスを生成しています

public  final  class  CurryTest$  ...      public  void  main(java.lang.String[]);                  63:  invokespecial  #82                                  //  Method  CurryTest$$anonfun$main$1.  

"<init>":()V                  66:  invokevirtual  #41                                  //  Method  filter:(Lscala/collection/  

immutable/List;Lscala/Function1;)  Lscala/collection/immutable/List;  

               69:  invokevirtual  #86                                  //  Method  scala/Predef$.println:  

(Ljava/lang/Object;)V

public  final  class    CurryTest$$anonfun$main$1  extends  

scala.runtime.AbstractFunction1$mcZI$sp  implements  scala.Serializable  

CurryTest$$anonfun$main$2  is  same

$2も同様です

               81:  invokespecial  #89                                  //  Method  CurryTest$$anonfun$main$2.  

"<init>":()V                                    84:  invokevirtual  #41                                  //  Method  filter:(Lscala/collection/  

immutable/List;Lscala/Function1;)  Lscala/collection/immutable/List;  

               87:  invokevirtual  #86                                  //  Method  scala/Predef$.println:  

(Ljava/lang/Object;)V  

§ Summary  § JVM  is  excellent!  § class  file  has  a  format  § javap  is  useful  to  understand      Scala  at  the  bytecode  level    

Try  typing  "javap"  after  you  compile  

Scala  code

Thank  you!