Upgrade to Pro — share decks privately, control downloads, hide ads and more …

dex 039 или куда катится Android

dex 039 или куда катится Android

Александр Ефременков, Yandex.Taxi – MOSDROID #7 Nitrogen

MOSDROID

April 17, 2018
Tweet

More Decks by MOSDROID

Other Decks in Programming

Transcript

  1. Доклад о том, как в Android добавляли полноценную поддержку MethodHandle.

    Продолжение доклада “Invokedynamic in Oreo” и что изменилось с того времени. Познавательный, не про архитектуру. О чём 3
  2. What is invokedynamic? 5 “[invokedynamic] improves implementations of compilers and

    runtime systems for dynamic languages on the JVM. It does this by allowing the language implementer to define custom linkage behavior. This contrasts with other JVM instructions such as invokevirtual, in which linkage behavior specific to Java classes and interfaces is hard-wired by the JVM.” official Oracle documentation
  3. invoke-virtual (virtual methods = Java’s invokevirtual) 
 invoke-static (static methods

    = Java’s invokestatic)
 invoke-interface (interface types methods = Java’s invokeinterface) invoke-super (super-class methods = Java’s invokespecial)
 invoke-direct (constructors = Java’s invokespecia)
 invoke-polymorphic (method handle invoke = 1/2 of Java’s invokedynamic) invoke-custom (call site resolve/invoke = 2/2 of Java’s invokedynamic) Какие invok’и есть 6
  4. • Делает половину invokedynamic из Java
 • Вызывает методы которые

    были bootstrapped
 • Полезно для альтернативы reflection (side effect) invoke-polymorphic 9
  5. invoke-polymorphic 11 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dynamicMethod(); } void dynamicMethod() { MethodHandles.lookup() .findVirtual(MainActivity.class, "virtualMethod", MethodType.methodType(void.class)) .invoke(); } private void virtualMethod() { Log.d("logger", "virtual"); } }
  6. invoke-polymorphic 12 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dynamicMethod(); } void dynamicMethod() { MethodHandles.lookup() .findVirtual(MainActivity.class, "virtualMethod", MethodType.methodType(void.class)) .invoke(); } private void virtualMethod() { Log.d("logger", "virtual"); } }
  7. invoke-polymorphic 13 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); dynamicMethod(); } void dynamicMethod() { MethodHandles.lookup() .findVirtual(MainActivity.class, "virtualMethod", MethodType.methodType(void.class)) .invoke(); } private void virtualMethod() { Log.d("logger", "virtual"); } }
  8. invoke-polymorphic 14 .METHOD dynamicMethod : void .MODIFIERS .REGISTERS 5 .CODE

    114676 invoke-static {}, meth@781 //MethodHandles.lookup(); 114682 move-result-object v0 //anonymous variable 114684 const-class v1, type@71. //MainActivity.class 114688 const-string/jumbo v2, string@1810 //“virtualMethod” 114694 sget-object v3, field@923 //void.class 114698 invoke-static {v3}, meth@782 //MethodType.methodType(); 114704 move-result-object v3 //anonymous variable 114706 invoke-virtual {v0, v1, v2, v3}, meth@780 //.findVirtual(); 114712 move-result-object v0 //define variable 114714 invoke—polymorphic MethodHandle—>invoke([Object)Object, ()V, v0. //.invoke(); 114715 return-wide v10 114717 move/16 v0, v100 114722 return-void
  9. invoke-polymorphic 15 .METHOD dynamicMethod : void .MODIFIERS .REGISTERS 5 .CODE

    114676 invoke-static {}, meth@781 114682 move-result-object v0 114684 const-class v1, type@71. 114688 const-string/jumbo v2, string@1810 114694 sget-object v3, field@923 114698 invoke-static {v3}, meth@782 114704 move-result-object v3 114706 invoke-virtual {v0, v1, v2, v3}, meth@780 114712 move-result-object v0 114714 invoke—polymorphic MethodHandle—>invoke([Object)Object, ()V, v0. 114715 return-wide v10 114717 move/16 v0, v100 114722 return-void Why not invoke-virtual? [2]
  10. java.lang.invoke.MethodHandle.java 17 /** * Internal marker interface which distinguishes (to

    the Java compiler) * those methods which are <a href="MethodHandle.html#sigpoly">signature polymorphic</a>. */ @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @interface PolymorphicSignature { }
  11. java.lang.invoke.MethodHandle.java 18 /** * Internal marker interface which distinguishes (to

    the Java compiler) * those methods which are <a href="MethodHandle.html#sigpoly">signature polymorphic</a>. */ @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @interface PolymorphicSignature { } Interface now marked as package-private
  12. • Делает вторую половину invokedynamic из Java (бОльшую) • Создаёт

    CallSite ссылающийся на MethodHandle • Использует MethodHandle для вызова целевого метода • Полезен для лябмд invoke-custom 20
  13. Dispatch
 21 Resolve Call Site Caller Exec Call Site Execute


    Method Handle Call Method Const Pool Method Handle Search Call Site Linkage
  14. Dispatch
 22 Resolve Call Site Caller Exec Call Site Execute


    Method Handle Call Method Const Pool Method Handle Search Call Site Linkage Lambda Prepare
  15. Dispatch
 23 Resolve Call Site Caller Exec Call Site Execute


    Method Handle Call Method Const Pool Method Handle Search Call Site Linkage Lambda Body
  16. • D8, DX делает десахароз даже с minSdkVersion 26 •

    Jack compiler ПОДДЕРЖИВАЕТ(!) компиляцию с invoke-custom (@CalledByInvokeCustom) • Smali до сих пор не поддерживает invoke-custom/invoke-polymorphic 24 invoke-custom
  17. invoke-custom 27 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MethodHandles.lookup() .findStatic(MainActivity.class, "add", MethodType.methodType(int.class, int.class, int.class)) .invoke(2, 3); } static int add(int a, int b) { BiFunction<Integer, Integer, Integer> f = new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return add0(a, b); } }; return f.apply(a, b); } @CalledByInvokeCustom(invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC, enclosingType = MainActivity.class, name = "linkerMethod", argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}), name = "add0", returnType = Integer.class, argumentTypes = {Integer.class, Integer.class}) static Integer add0(Integer a, Integer b) { return a + b; } private static CallSite linkerMethod(MethodHandles.Lookup caller, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException { return new ConstantCallSite(caller.findStatic(caller.lookupClass(), name, methodType)); } }
  18. invoke-custom 28 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MethodHandles.lookup() .findStatic(MainActivity.class, "add", MethodType.methodType(int.class, int.class, int.class)) .invoke(2, 3); } static int add(int a, int b) { BiFunction<Integer, Integer, Integer> f = new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return add0(a, b); } }; return f.apply(a, b); } @CalledByInvokeCustom(invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC, enclosingType = MainActivity.class, name = "linkerMethod", argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}), name = "add0", returnType = Integer.class, argumentTypes = {Integer.class, Integer.class}) static Integer add0(Integer a, Integer b) { return a + b; } private static CallSite linkerMethod(MethodHandles.Lookup caller, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException { return new ConstantCallSite(caller.findStatic(caller.lookupClass(), name, methodType)); } }
  19. invoke-custom 29 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MethodHandles.lookup() .findStatic(MainActivity.class, "add", MethodType.methodType(int.class, int.class, int.class)) .invoke(2, 3); } static int add(int a, int b) { BiFunction<Integer, Integer, Integer> f = new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return add0(a, b); } }; return f.apply(a, b); } @CalledByInvokeCustom(invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC, enclosingType = MainActivity.class, name = "linkerMethod", argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}), name = "add0", returnType = Integer.class, argumentTypes = {Integer.class, Integer.class}) static Integer add0(Integer a, Integer b) { return a + b; } private static CallSite linkerMethod(MethodHandles.Lookup caller, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException { return new ConstantCallSite(caller.findStatic(caller.lookupClass(), name, methodType)); } }
  20. invoke-custom 30 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MethodHandles.lookup() .findStatic(MainActivity.class, "add", MethodType.methodType(int.class, int.class, int.class)) .invoke(2, 3); } static int add(int a, int b) { BiFunction<Integer, Integer, Integer> f = new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return add0(a, b); } }; return f.apply(a, b); } @CalledByInvokeCustom(invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC, enclosingType = MainActivity.class, name = "linkerMethod", argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}), name = "add0", returnType = Integer.class, argumentTypes = {Integer.class, Integer.class}) static Integer add0(Integer a, Integer b) { return a + b; } private static CallSite linkerMethod(MethodHandles.Lookup caller, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException { return new ConstantCallSite(caller.findStatic(caller.lookupClass(), name, methodType)); } }
  21. invoke-custom 31 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MethodHandles.lookup() .findStatic(MainActivity.class, "add", MethodType.methodType(int.class, int.class, int.class)) .invoke(2, 3); } static int add(int a, int b) { BiFunction<Integer, Integer, Integer> f = new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return add0(a, b); } }; return f.apply(a, b); } @CalledByInvokeCustom(invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC, enclosingType = MainActivity.class, name = "linkerMethod", argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}), name = "add0", returnType = Integer.class, argumentTypes = {Integer.class, Integer.class}) static Integer add0(Integer a, Integer b) { return a + b; } private static CallSite linkerMethod(MethodHandles.Lookup caller, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException { return new ConstantCallSite(caller.findStatic(caller.lookupClass(), name, methodType)); } }
  22. invoke-custom 32 public class MainActivity extends Activity { @Override protected

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MethodHandles.lookup() .findStatic(MainActivity.class, "add", MethodType.methodType(int.class, int.class, int.class)) .invoke(2, 3); } static int add(int a, int b) { BiFunction<Integer, Integer, Integer> f = new BiFunction<Integer, Integer, Integer>() { @Override public Integer apply(Integer integer, Integer integer2) { return add0(a, b); } }; return f.apply(a, b); } @CalledByInvokeCustom(invokeMethodHandle = @LinkerMethodHandle(kind = MethodHandleKind.INVOKE_STATIC, enclosingType = MainActivity.class, name = "linkerMethod", argumentTypes = {MethodHandles.Lookup.class, String.class, MethodType.class}), name = "add0", returnType = Integer.class, argumentTypes = {Integer.class, Integer.class}) static Integer add0(Integer a, Integer b) { return a + b; } private static CallSite linkerMethod(MethodHandles.Lookup caller, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException { return new ConstantCallSite(caller.findStatic(caller.lookupClass(), name, methodType)); } }
  23. invoke-custom 33 .METHOD add0 : int .MODIFIERS .REGISTERS 3 .CODE

    113112 iget v0, v2, ()I, field@0015 //declare a 113116 invoke-static {v0}, method@0030 //Integer.valueOf() 113122 move-result-object v0 //define a 113124 iget v1, v2, ,field@00022 //declare b 113128 invoke-static {v1}, method@0072 //Integer.valueOf() 113134 move-result-object v1 //define b 113136 invoke-custom {v0, v1}, call_site@0000 //add0(a, b); 113142 move-result-object v0 113144 return-object v0
  24. • Инструкции для получения Method Handle’s (Очень похоже на function

    pointers в C) • Инструкции для получения прототипов методов • Данные коды операций просто запрашивают прототипы и обрабатывают пулы. new op’s 36
  25. • Не оптимизированный DEX instruction set занимает 0 to 0xFF,

    в неопределённом диапазоне: 3E-43, 73, 79-7A, E3-FF • DEX 38 определяет диапазон FA-FD (4 новые invoke-xxx кода) • DEX 39 определяет диапазон FE-FF для новых кодов (2 новых const- method-xxx) Эволюция 37
  26. Move a reference to the method handle specified by the

    given index into the specified register. const-method-handle 39
  27. Move a reference to the method handle specified by the

    given index into the specified register. const-method-handle vAA, method_handle@BBBB A: destination register (8 bits) B: method handle index (16 bits) const-method-handle 40
  28. Move a reference to the method prototype specified by the

    given index into the specified register. const-method-type 42
  29. Move a reference to the method prototype specified by the

    given index into the specified register. const-method-type vAA, proto@BBBB A: destination register (8 bits) B: method prototype reference (16 bits) const-method-type 43
  30. В платформенный рантайм наконец-то добавили полноценное api для работы с

    динамическим кодом и работы с прототипами и обработчиками функций. Итог 52