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-JSpecndex.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가 많았음
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를 추가하자!
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
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;";
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을 리턴하지 못하면 에러 발생
40. JSR 292 JRuby팀과협업 enhanced bytecode + a new API invokedynamic java.lang.invoke MethodHandle(일종의 함수 포인터) Combinators provide adhoc classes: ClassValue(캐쉬), SwitchPoint (상태확인)
48. 정리 Jruby 1.6.3까지는 invokedynamic사용하지 않음. (invokedynamic테스트 버전은 따로 있음.) 대신 내부적으로 invokedynamic비슷한 구현을 이미 하고 있음 Groovy Jruby처럼 내부적으로는 invokedynamic비슷한 구현 함 앞으로 많은 언어들이 쓸 수 있도록 배려했고, 비슷하게 구현한 것들은 조금 더 빠른 속도가 날 수 있으며, 더 많은 언어들이 이 기능을 사용할 수 있음