ComPAS 2013 - JooFlux

ComPAS 2013 - JooFlux

Modification de code à chaud et injection d’aspects directement dans une JVM 7

2a4bd42b6a3db5858ff2250e236f9631?s=128

Frédéric Le Mouël

January 16, 2013
Tweet

Transcript

  1. Julien Ponge Frédéric Le Mouël JooFlux ComPAS 2013 mercredi 16

    janvier 13
  2. Objectifs JVM, invokedynamic Implémentation Évaluation Conclusions mercredi 16 janvier 13

  3. “Modification de code à chaud et injection d’aspects directement dans

    une JVM 7” mercredi 16 janvier 13
  4. (démo) mercredi 16 janvier 13

  5. AspectJ [Kiczales et al., 2001, CACM] Byteman [Dinn, 2011, AOSD]

    Steamloom [Bockisch et al., 2004, AOSD] JnVM [Thomas et al., 2008, SP+E] JVolve [Subramanian et al., 2009, PLDI] SafeWeave [Würthinger et al., 2011, OOPSLA] Outils VMs ad-hoc Travaux connexes mercredi 16 janvier 13
  6. Pas de langage d’aspects Pas de pré/post compilation Un agent

    Java JVM non-modifiée JooFlux Dév appli Runtime mercredi 16 janvier 13
  7. JVM, invokedynamic mercredi 16 janvier 13

  8. Machine à pile OpCodes invocation de méthode manipulation de pile

    get / set champs arithmétique allocation sauts lock (...) Constant pool (nombres, String, types) 0 java/lang/String 1 “Foo” 2 666 ... ... Variables locales 0 this (sauf static) 1 arg1 2 arg2 3 int i ... ... mercredi 16 janvier 13
  9. invokestatic public static int add(int a, int b) invokevirtual public

    int add(int a, int b) invokeinterface int add(int a, int b) invokespecial private int add(int a, int b) mercredi 16 janvier 13
  10. Object call (Object receiver, Object[] args) throws Throwable; Object call

    (Object receiver) throws Throwable; Object call (Object receiver, Object arg1) throws Throwable; Object call (Object receiver, Object arg1, Object arg2) throws Throwable; Object call (Object receiver, Object arg1, Object arg2, Object arg3) throws Throwable; Object call (Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable; Object callConstructor (Object receiver, Object [] args) throws Throwable; Object callConstructor (Object receiver) throws Throwable; Object callConstructor (Object receiver, Object arg1) throws Throwable; Object callConstructor (Object receiver, Object arg1, Object arg2) throws Throwable; Object callConstructor (Object receiver, Object arg1, Object arg2, Object arg3) throws Throwable; Object callConstructor (Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable; Comment résoudre à l’exécution ? (extrait de Groovy) mercredi 16 janvier 13
  11. public Object call(Object receiver, Object[] args) throws Throwable { return

    CallSiteArray.defaultCall(this, receiver, args); } public Object call(Object receiver) throws Throwable { return call(receiver, CallSiteArray.NOPARAM); } public Object call(Object receiver, Object arg1) throws Throwable { return call(receiver, ArrayUtil.createArray(arg1)); } public Object call(Object receiver, Object arg1, Object arg2) throws Throwable { return call(receiver, ArrayUtil.createArray(arg1, arg2)); } public Object call(Object receiver, Object arg1, Object arg2, Object arg3) throws Throwable { return call(receiver, ArrayUtil.createArray(arg1, arg2, arg3)); } public Object call(Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable { return call(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4)); } “Tous les chemins mènent à Rome” mercredi 16 janvier 13
  12. public static Object invoke(Object object, String methodName, Object[] parameters) {

    try { Class[] classTypes = new Class[parameters.length]; for (int i = 0; i < classTypes.length; i++) { classTypes[i] = parameters[i].getClass(); } Method method = object.getClass().getMethod(methodName, classTypes); return method.invoke(object, parameters); } catch (Throwable t) { return InvokerHelper.invokeMethod(object, methodName, parameters); } } Difficile pour le JIT ! CallSites génériques Réflexivité mercredi 16 janvier 13
  13. invokedynamic nom symbolique + signature + bootstrap CallSite Constant Mutable

    Volatile MethodHandle direct ou combinateurs branchements adaptation filtres (...) 7 mercredi 16 janvier 13
  14. Implémentation mercredi 16 janvier 13

  15. 1 2 3 4 Chargement des classes Interception Management Runtime

    mercredi 16 janvier 13
  16. (...) ldc #3 ldc #5 invokedynamic foo (II)I bootstraper (...)

    Call site JMX agent JooFlux bootstraper Modified bytecode Registry Target method combinators Load time action Run time action Original bytecode JVM agent 1 2 3 4 mercredi 16 janvier 13
  17. Réécriture de bytecode ASM + Agent Bootstrap JooFlux Casse la

    vérification de bytecode ! 1 mercredi 16 janvier 13
  18. sémantique champ volatile impact mesuré négligeable VolatileCallSite 2 mercredi 16

    janvier 13
  19. invokestatic invokespecial Method handle direct invokevirtual invokeinterface Method handle sur

    le premier receveur 3 mercredi 16 janvier 13
  20. invokeinterface Polymorphic inline-cache guardWithTest(Class1, obj) guardWithTest(Class2, obj) fallback(callsite, args[]) Class1#foo(II)I

    Class2#foo(II)I obj.foo(1, 2) 3 mercredi 16 janvier 13
  21. 4 public interface JooFluxManagementMXBean { public String getName(); public int

    getNumberOfRegisteredCallSites(); public Set<String> getRegisteredCallSiteKeys(); public String getCallSiteType(String target); public void changeCallSiteTarget(String methodType, String oldTarget, String newTarget); public void applyBeforeAspect(String callSitesKey, String aspectClass, String aspectMethod); public void applyAfterAspect(String callSitesKey, String aspectClass, String aspectMethod); } mercredi 16 janvier 13
  22. (...) ldc #3 ldc #5 invokedynamic foo (II)I bootstraper (...)

    Call site JMX agent JooFlux bootstraper Modified bytecode Registry Target method combinators Load time action Run time action Original bytecode JVM agent 4 Registre : 0 impact perfs Enregistré à la 1ère interception Modification via API mercredi 16 janvier 13
  23. Évaluation mercredi 16 janvier 13

  24. Interception / redirection de méthode Injection d’aspect ‘vide’ Langages dynamiques

    Plates-formes AOP Micro Fibonacci(40) Macro SCImark Fork/Join Clojure Benchmarks X V V V mercredi 16 janvier 13
  25. 0 2 4 6 8 Byteman Jooflux Avant Après Avant

    + Après Injection d’aspect ‘vide’ x 137 x 134 x 306 x 6 x 2 x 5 Microbench mercredi 16 janvier 13
  26. Interception/redirection méthode 0 5 10 15 Clojure JRuby Groovy Rhino

    JS Jython Java+JooFlux Min Max x 1 x 48 x 18 x 15 x 2,2 x 10 x 3 x 6 x 1,2 x 2 Microbench mercredi 16 janvier 13
  27. Interception/redirection méthode 0,9 1 1,1 SCIMark Fork/Join Clojure Min Max

    x 0,99 x 0,97 x 1,04 x 0,93 x 1,01 x 1,01 Macrobench mercredi 16 janvier 13
  28. Conclusion mercredi 16 janvier 13

  29. JVM généraliste Interception à grain fin Résultats initiaux encourageants Approche

    nouvelle, générique, sans langage dédié Bilan mercredi 16 janvier 13
  30. Injection atomique multi-aspects Rollback / versioning Vérification formelle pré-injection Aspects

    contextuels / Internet of Things Contrôle de ressources avec isolation adaptative Perspectives mercredi 16 janvier 13
  31. https://github.com/dynamid/jooflux Questions / réponses Julien Ponge Frédéric Le Mouël http://dynamid.citi-lab.fr/

    mercredi 16 janvier 13