Jdk(java) 7 - 5. invoke-dynamic

  • 3,733 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
3,733
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
0
Comments
0
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. JDK 7 출시 기념 (2011.7)JDK 7 소개 #5 invokedynamic
    김용환
    knight76.tistory.com
    Knight76 at gmail.com
    1
  • 2. 좋은 레퍼런스
    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
  • 3. For Who
    JAVA 1.6부터 다른 언어를 지원 (Rhino)
    정적 타입 언어 (非 자바)를 jvm에서 안정적이고, 빨리 실행시켜줄 수 있도록 지원 요청
  • 4. 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)
  • 5. 기존 사례
    Groovy 코드 -> class로 컴파일 -> JVM실행
    JRuby코드 -> class로컴파일 (spring의 JRubyScriptUtils.createJRubyObject메소드) -> JVM 실행
    단점
    JVM에서 돌아갈 수 있도록 작업을 많이 해야 했음. JVM dependent code가 많았음
  • 6. 둘의장점을 이용
    Ruby/Python
    (Dynamic Language)
    JVM 특징
    (고성능, 재활용,
    JIT, GC,
    다양한 OS 지원)
  • 7. But, 이슈
    동적언어와 정적 언어 특징
    정적 타입 언어(java)는Compile 레벨에서 Type Checking이 엄격하게 이루어짐
    동적 타입 언어(dynamic type)는 Type Checking이 Runtime때 실행. 변수는 어떤 타입이든지 상관없음 (javascript, ruby, python..)
  • 8. JVM 이슈 : 메소드
    JVM 이슈 : 메소드
    동적언어에서는메소드의파라미터 타입을 굳이 알 수 않아도 되지만, JVM은 byte code 명령어들을 이용하기 위해서 method, method안의 클래스 타입, descriptor 형식이 필요
    function max (x,y) {
    if x.lessThan(y) then y else x
    }
    동적언어메소드파라미터의 타입정보가 없는 메소드
  • 9. 구현
    타입 정보가 없으면, reflection API를이용해서 java.lang.reflect.Method 클래스를 생성하고, Method 클래스의 invoke 메소드로 호출하는 형태(Proxy)
    Reflection 호출 자체가 실행속도에 안좋은 영향을 줌. 성능 저하
    예) Spring에서는 Proxy 개선 : CGLIB Proxy
    Reflection 없이 속도 향상!
  • 10. 빠른 속도
    Reflection API를 쓰지 않아도 바로 invoke 해 줄 수있고, 속도도 빠른 새로운 API가 필요
    JVM 의 invoke 명령어 중 새로운 API를 추가하자!
  • 11. 잠깐.. JVM byte code 공부
  • 12. JVM byte code
    JVM에서 동작하는 native language (assembly와 비슷)
    JVM byte code
    Stack에 작업(push/pop/dup/swap)을 하고, 실행시키는 machanism
    Operand stack : byte code가 실행할 수 있는 임시용의 stack (cpu의 register stack)
  • 13. 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 메소드의 구현 메소드를 호출
  • 14. Java ByteCode출력방법
    javap –c 클래스이름
  • 15. 예제
    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
  • 16. JVM invokevirtualinstuction이슈
    invokevirtual instruction은 메소드의파라미터의 클래스타입(descriptor)을 반드시 알아야 함
    invokevirtual <method-spec>
    classname, methodname,descriptor
    com/google/Myclass/myMethod(Ljava/lang/String;)V
    ----------------------- ---------------------
    -------------
    descriptor
    classname
    methodname
  • 17. 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
  • 18. invokestatic
  • 19. 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
  • 20. invokestatic
  • 21. invokestatic
  • 22. invokevirtual
  • 23. 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
  • 24. invokevirtual
    출처 : http://cr.openjdk.java.net/~jrose/pres/200906-Cookbook.pdf
  • 25. invokevirtual
  • 26. invokevirtual
  • 27. invokedynamic
  • 28. 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
  • 29. invokedynamic
    C언어의 함수 포인터와 비슷!
  • 30. invokedynamic이후Bootstrap instruction 부트 로직
  • 31. JVM 동작 순서
    invokedynamic명령어를 실행하기 전에 java.lang.invoke.CallSite를 확인
    CallSite가 없다면, 동적 타입 언어의 런타임에서 bootstrap 메소드를 호출
    Bootstrap 메소드는CallSite객체를 반환(invokedynamic은 CallSite에 링크됨)
    invokedynamic은 CallSite에 저장된 java.net.MethodHandle(MH)를 이용해서 메소드 호출
    CallSite가 이미 등록된 invokedynamic이 다시 실행되면, 위 과정 없이 바로 메소드 호출(invokedynamic이 구현에 대한 MethodHandle을 한번이라도 사용하면, 그 MethodHandle을 사용)
  • 32. up call
    리눅스
    low level 이 high level에 있는 함수를 호출하는 것이죠. signal handler 같은 것
    JVM
    JVM의 invokedynamic이 bootstrap 메소드를 호출하는 것
  • 33. 코드 구현 예제 #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));
    }
    }
  • 34. 코드 구현 예제 #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);
    }
    }
  • 35. 코드 구현 예제 #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;";
  • 36. 코드 구현 예제 #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 메소드를 호출
  • 37. 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을 리턴하지 못하면 에러 발생
  • 38. JSR 292
    JSR292
  • 39. JSR 292 -Spec.zip
  • 40. JSR 292
    JRuby팀과협업
    enhanced bytecode + a new API
    invokedynamic
    java.lang.invoke
    MethodHandle(일종의 함수 포인터)
    Combinators
    provide adhoc classes: ClassValue(캐쉬), SwitchPoint (상태확인)
  • 41. JVM Spec Changed
  • 42. 참고
  • 43. 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>
  • 44. 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
  • 45. 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);
    }
  • 46. 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
    비슷한 구현이 이미 되어 있음
  • 47. JRuby의 성능
    http://eyweb-images.s3.amazonaws.com/blog_crossimp.jpg
  • 48. 정리
    Jruby
    1.6.3까지는 invokedynamic사용하지 않음. (invokedynamic테스트 버전은 따로 있음.)
    대신 내부적으로 invokedynamic비슷한 구현을 이미 하고 있음
    Groovy
    Jruby처럼 내부적으로는 invokedynamic비슷한 구현 함
    앞으로 많은 언어들이 쓸 수 있도록 배려했고, 비슷하게 구현한 것들은 조금 더 빠른 속도가 날 수 있으며, 더 많은 언어들이 이 기능을 사용할 수 있음
  • 49. To be continued #6
    49