• Save
Jdk(java) 7 - 5. invoke-dynamic
Upcoming SlideShare
Loading in...5
×
 

Jdk(java) 7 - 5. invoke-dynamic

on

  • 4,177 views

 

Statistics

Views

Total Views
4,177
Views on SlideShare
3,325
Embed Views
852

Actions

Likes
2
Downloads
0
Comments
0

3 Embeds 852

http://knight76.tistory.com 846
https://duckduckgo.com 5
http://webcache.googleusercontent.com 1

Accessibility

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Jdk(java) 7 - 5. invoke-dynamic Jdk(java) 7 - 5. invoke-dynamic Presentation Transcript

    • JDK 7 출시 기념 (2011.7)JDK 7 소개 #5 invokedynamic
      김용환
      knight76.tistory.com
      Knight76 at gmail.com
      1
    • 좋은 레퍼런스
      http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html
      http://androidkr.blogspot.com/2010_07_01_archive.html
      http://cr.openjdk.java.net/~jrose/pres/200906-Cookbook.pdf
      http://download.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html
      Jsr문서
      dynamically_typed_lang-jdk7-final-oth-JSpecindex.html
    • For Who
      JAVA 1.6부터 다른 언어를 지원 (Rhino)
      정적 타입 언어 (非 자바)를 jvm에서 안정적이고, 빨리 실행시켜줄 수 있도록 지원 요청
    • Java language / JVM
      Java language 는 JVM과 다르다.
      특징
      Java compiler
      사람이 write한 java code를 JVM에서 실행가능하도록byte 코드를 생성
      HelloWorld.java -> HellowWorld.class
      Java Virtual Machine
      byte코드와 class 파일 포맷을 가지고 실행
      HellowWorld.class -> 실행
      이슈
      Java language 이슈가 아닌…
      정적 타입 언어를 바로 JVM 상에서 돌아가는 것 자체가 어려움 (interoperability)
      JVM (java virtual machine)의 실행 속도 이슈! (performance)
    • 기존 사례
      Groovy 코드 -> class로 컴파일 -> JVM실행
      JRuby코드 -> class로컴파일 (spring의 JRubyScriptUtils.createJRubyObject메소드) -> JVM 실행
      단점
      JVM에서 돌아갈 수 있도록 작업을 많이 해야 했음. JVM dependent code가 많았음
    • 둘의장점을 이용
      Ruby/Python
      (Dynamic Language)
      JVM 특징
      (고성능, 재활용,
      JIT, GC,
      다양한 OS 지원)
    • But, 이슈
      동적언어와 정적 언어 특징
      정적 타입 언어(java)는Compile 레벨에서 Type Checking이 엄격하게 이루어짐
      동적 타입 언어(dynamic type)는 Type Checking이 Runtime때 실행. 변수는 어떤 타입이든지 상관없음 (javascript, ruby, python..)
    • JVM 이슈 : 메소드
      JVM 이슈 : 메소드
      동적언어에서는메소드의파라미터 타입을 굳이 알 수 않아도 되지만, JVM은 byte code 명령어들을 이용하기 위해서 method, method안의 클래스 타입, descriptor 형식이 필요
      function max (x,y) {
      if x.lessThan(y) then y else x
      }
      동적언어메소드파라미터의 타입정보가 없는 메소드
    • 구현
      타입 정보가 없으면, reflection API를이용해서 java.lang.reflect.Method 클래스를 생성하고, Method 클래스의 invoke 메소드로 호출하는 형태(Proxy)
      Reflection 호출 자체가 실행속도에 안좋은 영향을 줌. 성능 저하
      예) Spring에서는 Proxy 개선 : CGLIB Proxy
      Reflection 없이 속도 향상!
    • 빠른 속도
      Reflection API를 쓰지 않아도 바로 invoke 해 줄 수있고, 속도도 빠른 새로운 API가 필요
      JVM 의 invoke 명령어 중 새로운 API를 추가하자!
    • 잠깐.. JVM byte code 공부
    • JVM byte code
      JVM에서 동작하는 native language (assembly와 비슷)
      JVM byte code
      Stack에 작업(push/pop/dup/swap)을 하고, 실행시키는 machanism
      Operand stack : byte code가 실행할 수 있는 임시용의 stack (cpu의 register stack)
    • JVM byte code의 instruction
      ldc/const : stack에 값을 push
      load/store : 로컬 변수 접근 관련
      aaload/*aload : array로부터 값을 얻기
      iinc : i++
      if_icmpge :conditional jump
      return
      Invoke
      virtual : 인터페이스가 아닌 메소드를 호출. (대부분)
      interface : 인터페이스 메소드를 호출
      static : static 호출
      special : 생성자와super class 메소드의 구현 메소드를 호출
    • Java ByteCode출력방법
      javap –c 클래스이름
    • 예제
      String s = "Hello World";
      System.out.println(s);
      java
      ldc #2 // ‘Hello World’ stack에 저장(push)한다.
      astore_1 //Stack에서 ‘Hellow World’를 꺼내 로컬변수 1에 저장한다.
      getstatic#3 //System.out에서 static field인 PrintStream클래스를 꺼낸다.
      aload_1 // 로컬변수 1에서 가르키는Stirng을 읽는다.
      invokevirtual #4 // PrintStream의 println을 호출한다.
      // java/io/PrintStream.println:(Ljava/lang/String;)V
      jvm
    • JVM invokevirtualinstuction이슈
      invokevirtual instruction은 메소드의파라미터의 클래스타입(descriptor)을 반드시 알아야 함
      invokevirtual <method-spec>
      classname, methodname,descriptor
      com/google/Myclass/myMethod(Ljava/lang/String;)V
      ----------------------- ---------------------
      -------------
      descriptor
      classname
      methodname
    • JVM invokevirtualinstuction예제
      Object x;
      ...
      x.equals("hello");
      java
      aload_1 ; 로컬 변수 ‘x’를 스택첫번째에 저장
      ldc"hello" ; 스택에‘hello’라는 Sting값을 저장
      ; ‘equals’ 메소드 호출
      ; 스택에 저장되는 값은 Boolgean값(Z)
      invokevirtual java/lang/Object/equals(Ljava/lang/Object;)Z
      jvm
    • invokestatic
    • invokestatic
      String s = System.getProperty("java.home");
      java
      ldc#2 //String ”java.home”을 stack에 저장
      invokestatic#3 //Method java/lang/System.getProperty:
      // (Ljava/lang/String;)Ljava/lang/String;
      astore_1
      jvm
    • invokestatic
    • invokestatic
    • invokevirtual
    • invokevirtual
      PrintStream out = System.out;
      out.println("Hello World");
      java
      getstatic #16
      astore_1
      aload_1
      ldc#2
      invokevirtual #4 //Method java/io/PrintStream.println:
      //(Ljava/lang/String;)V
      jvm
    • invokevirtual
      출처 : http://cr.openjdk.java.net/~jrose/pres/200906-Cookbook.pdf
    • invokevirtual
    • invokevirtual
    • invokedynamic
    • invokedynamic
      function max(x, y) {
      if (x.lessThan(y)) then y else x
      }
      동적
      타입
      언어
      aload_1; aload_2
      invokedynamic#3 // NameAndTypelessThan:
      // (Ljava/lang/Object;Ljava/lang/Object;)Z
      if_icmpeq
      jvm
      Boolean 리턴타입. Argument는 타입없는object
    • invokedynamic
      C언어의 함수 포인터와 비슷!
    • invokedynamic이후Bootstrap instruction 부트 로직
    • JVM 동작 순서
      invokedynamic명령어를 실행하기 전에 java.lang.invoke.CallSite를 확인
      CallSite가 없다면, 동적 타입 언어의 런타임에서 bootstrap 메소드를 호출
      Bootstrap 메소드는CallSite객체를 반환(invokedynamic은 CallSite에 링크됨)
      invokedynamic은 CallSite에 저장된 java.net.MethodHandle(MH)를 이용해서 메소드 호출
      CallSite가 이미 등록된 invokedynamic이 다시 실행되면, 위 과정 없이 바로 메소드 호출(invokedynamic이 구현에 대한 MethodHandle을 한번이라도 사용하면, 그 MethodHandle을 사용)
    • up call
      리눅스
      low level 이 high level에 있는 함수를 호출하는 것이죠. signal handler 같은 것
      JVM
      JVM의 invokedynamic이 bootstrap 메소드를 호출하는 것
    • 코드 구현 예제 #1
      public class HelloWorld {
      public static void main(String[] args) {
      //PSEUDOCODE FOR A JVM INSTRUCTION
      //invokedynamic[#bootstrapDynamic]("Hello World", 2, 3.14);
      }
      private static void printArgs(Object... args) {
      System.out.println(java.util.Arrays.deepToString(args));
      }
      private static MethodHandleprintArgs;
      static {
      MethodHandles.Lookuplookup = MethodHandles.lookup();
      Class thisClass = lookup.lookupClass();
      try {
      printArgs= lookup.findStatic(thisClass, "printArgs", MethodType.methodType(void.class,
      Object[].class));
      } catch (Exception e) {
      e.printStackTrace();
      }
      }
      private staticCallSitebootstrapDynamic(MethodHandles.Lookup caller, String name,
      MethodType type) {
      return new ConstantCallSite(printArgs.asType(type));
      }
      }
    • 코드 구현 예제 #2
      public class IntegerOps {
      public static Integer adder(Integer x, Integer y) {
      return x + y;
      }
      }
      public class Example {
      public static CallSitemybsm(MethodHandles.LookupcallerClass, String dynMethodName, MethodTypedynMethodType) throws Throwable {
      MethodHandlemh= callerClass.findStatic(Example.class, "IntegerOps.adder",
      MethodType.methodType(Integer.class, Integer.class, Integer.class));
      if (!dynMethodType.equals(mh.type())) {
      mh = mh.asType(dynMethodType);
      }
      return new ConstantCallSite(mh);
      }
      }
    • 코드 구현 예제 #2
      InvokeVirtual과 달리 메소드 호출을 위한 클래스 정보가 필요 없다. 대신 길다.
      Jvmbytecode
      invokedynamicinvokedynamic
      REF_invokestatic:
      Example.mybsm:
      "(Ljava/lang/invoke/MethodHandles/Lookup;
      Ljava/lang/String;
      Ljava/lang/invoke/MethodType;)
      Ljava/lang/invoke/CallSite;":
      +:
      "(Ljava/lang/Integer;
      Ljava/lang/Integer;)
      Ljava/lang/Integer;";
    • 코드 구현 예제 #2
      invokedynamicinvokedynamic
      REF_invokestatic:
      Example.mybsm:
      "(Ljava/lang/invoke/MethodHandles/Lookup;
      Ljava/lang/String;
      Ljava/lang/invoke/MethodType;)
      Ljava/lang/invoke/CallSite;":
      +:
      "(Ljava/lang/Integer;
      Ljava/lang/Integer;)
      Ljava/lang/Integer;";
      bootstrap 메소드가addr static 메소드를 호출
      1
      2
      Bootstrap의 Full Qualified name인 Example.mybsm
      3
      bootstrap 메소드가addr static 메소드를 호출
    • API
      java.lang.invoke..MethodHandle (MH)
      JVM 메소드에 대한 anonymous reference 을 가지고 있음
      MethodHandles.Lookup
      factory for creating method handles
      java.lang.invoke.CallSite
      MethodHandler변수를 가지고 있는 Holder
      ConstantCallSite, MutableCallSite
      BootstrapMethodError
      invokedynamic호출후bootstrap 메소드을못찾거나Call site을 리턴하지 못하면 에러 발생
    • JSR 292
      JSR292
    • JSR 292 -Spec.zip
    • JSR 292
      JRuby팀과협업
      enhanced bytecode + a new API
      invokedynamic
      java.lang.invoke
      MethodHandle(일종의 함수 포인터)
      Combinators
      provide adhoc classes: ClassValue(캐쉬), SwitchPoint (상태확인)
    • JVM Spec Changed
    • 참고
    • JRuby실전 테스트
      jruby에서 jvm버전을 변경하고 싶을 때는 JAVA_HOME을 변경하면 된다. (따로 properties 설정은 없다.)
      C:jruby-1.6.3-without-jvmbin>jruby.exe -v
      jruby 1.6.3 (ruby-1.8.7-p330) (2011-07-07 965162f) (Java HotSpot(TM) Client VM 1.7.0) [Windows 7-x86-java]
      C:jruby-1.6.3-without-jvmbin>java -classpath.;jruby.jar a.JRubyExample
      num: 6
      C:jruby-1.6.3-without-jvmbin>
    • JRuby실전 테스트
      myruby.rb
      def max(a,b)
      if a < b
      b
      else
      a
      end
      end
      defgetMax(number1, number2)
      f = max(number1, number2)
      return f
      end
    • JRuby실전 테스트
      a.JRubyExample.java
      public static void main(String[] args) throws Exception {
      ScriptEnginejruby = new ScriptEngineManager().getEngineByName("jruby");
      jruby.eval(new BufferedReader(new FileReader("myruby.rb")));
      jruby.put("number1", 6);
      jruby.put("number2", 9);
      long num = (Long) jruby.eval("getMax($number1, $number1)");
      System.out.println("num: " + num);
      }
    • JRuby실전 테스트
      C:jruby-1.6.3-without-jvmbin>jrubyc.bat myruby.rb
      public static org.jruby.runtime.builtin.IRubyObject method__0$RUBY$max(myruby,
      org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, org.jru
      by.runtime.builtin.IRubyObject, org.jruby.runtime.builtin.IRubyObject, org.jruby
      .runtime.Block);
      Code:
      0: aload_3
      1: astore 10
      3: aload 4
      5: astore 11
      7: aload_0
      8: invokevirtual #33 // Method getCallSite0:()Lorg/jruby/
      runtime/CallSite;
      11: aload_1
      12: aload_2
      13: aload 10
      15: aload 11
      17: invokevirtual #39 // Method org/jruby/runtime/CallSite
      .call:(Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;L
      org/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;)Lo
      rg/jruby/runtime/builtin/IRubyObject;
      20: invokeinterface #45, 1 // InterfaceMethod org/jruby/runtime
      /builtin/IRubyObject.isTrue:()Z
      25: ifeq 33
      28: aload 11
      30: goto 35
      33: aload 10
      35: areturn
      비슷한 구현이 이미 되어 있음
    • JRuby의 성능
      http://eyweb-images.s3.amazonaws.com/blog_crossimp.jpg
    • 정리
      Jruby
      1.6.3까지는 invokedynamic사용하지 않음. (invokedynamic테스트 버전은 따로 있음.)
      대신 내부적으로 invokedynamic비슷한 구현을 이미 하고 있음
      Groovy
      Jruby처럼 내부적으로는 invokedynamic비슷한 구현 함
      앞으로 많은 언어들이 쓸 수 있도록 배려했고, 비슷하게 구현한 것들은 조금 더 빠른 속도가 날 수 있으며, 더 많은 언어들이 이 기능을 사용할 수 있음
    • To be continued #6
      49