2017-07-28 2 views
3

J'essaie de comprendre le code natif généré à partir d'une boucle Java. Le code natif devrait être optimisé par le compilateur C2, mais sur mon exemple simple, il semble que certaines optimisations manquent.Quand l'optimisation de la prédiction de boucle Java est-elle déclenchée par le compilateur C2 JIT?

C'est la méthode Java j'ai écrit la base sur l'exemple minimal de https://wiki.openjdk.java.net/display/HotSpot/LoopPredication:

104 public static byte[] myLoop(int init, int limit, int stride, int scale, int offset, byte value, byte[] array) { 
105  for (int i = init; i < limit; i += stride) { 
106   array [ scale * i + offset] = value; 
107  } 
108  return array; 
109 } 

Ce sont les arguments donnés à la Java 8 Hotspot VM pour forcer la compilation C2:

-server 
-XX:-TieredCompilation 
-XX:CompileThreshold=5 
-XX:+UnlockDiagnosticVMOptions 
-XX:+PrintAssembly 
-XX:-UseCompressedOops 
-XX:+LogCompilation 
-XX:+TraceClassLoading 
-XX:+UseLoopPredicate 
-XX:+RangeCheckElimination 

Cette est le code natif amd64 généré par C2 ('myLoop' est appelé au moins 10000 fois):

# {method} {0x00007fcb5088ef38} 'myLoop' '(IIIIIB[B)[B' in 'MyClass'                                                                      
    # parm0: rsi  = int 
    # parm1: rdx  = int 
    # parm2: rcx  = int 
    # parm3: r8  = int 
    # parm4: r9  = int 
    # parm5: rdi  = byte 
    # parm6: [sp+0x40] = '[B' (sp of caller) 
    0x00007fcd44ee9fe0: mov  %eax,0xfffffffffffec000(%rsp) 
    0x00007fcd44ee9fe7: push %rbp 
    0x00007fcd44ee9fe8: sub  $0x30,%rsp  ;*synchronization entry 
               ; - MyClass::[email protected] (line 105) 

    0x00007fcd44ee9fec: cmp  %edx,%esi 
    0x00007fcd44ee9fee: jnl  0x7fcd44eea04a ;*if_icmplt 
               ; - MyClass::[email protected] (line 105) 

    0x00007fcd44ee9ff0: mov  0x40(%rsp),%rax 
    0x00007fcd44ee9ff5: mov  0x10(%rax),%r10d ;*bastore 
               ; - MyClass::[email protected] (line 106) 
               ; implicit exception: dispatches to 0x00007fcd44eea051 
    0x00007fcd44ee9ff9: nopl 0x0(%rax)   ;*aload 
               ; - MyClass::[email protected] (line 106) 

    0x00007fcd44eea000: mov  %esi,%ebx 
    0x00007fcd44eea002: imull %r8d,%ebx 
    0x00007fcd44eea006: add  %r9d,%ebx   ;*iadd 
               ; - MyClass::[email protected] (line 106) 

    0x00007fcd44eea009: cmp  %r10d,%ebx 
    0x00007fcd44eea00c: jnb  0x7fcd44eea02e ;*bastore 
               ; - MyClass::[email protected] (line 106) 

    0x00007fcd44eea00e: add  %ecx,%esi   ;*iadd 
               ; - MyClass::[email protected] (line 105) 

    0x00007fcd44eea010: movsxd %ebx,%r11 
    0x00007fcd44eea013: mov  %dil,0x18(%rax,%r11) ; OopMap{rax=Oop off=56} 
               ;*if_icmplt 
               ; - MyClass::[email protected] (line 105) 

    0x00007fcd44eea018: test %eax,0xa025fe2(%rip) ; {poll} 
    0x00007fcd44eea01e: cmp  %edx,%esi 
    0x00007fcd44eea020: jl  0x7fcd44eea000 ;*synchronization entry 
               ; - MyClass::[email protected] (line 105) 

    0x00007fcd44eea022: add  $0x30,%rsp 
    0x00007fcd44eea026: pop  %rbp 
    0x00007fcd44eea027: test %eax,0xa025fd3(%rip) ; {poll_return} 
    0x00007fcd44eea02d: retq 
    0x00007fcd44eea02e: movabs $0x7fcca3c810a8,%rsi ; {oop(a 'java/lang/ArrayIndexOutOfBoundsException')} 
    0x00007fcd44eea038: movq $0x0,0x18(%rsi) ;*bastore 
               ; - MyClass::[email protected] (line 106) 

    0x00007fcd44eea040: add  $0x30,%rsp 
    0x00007fcd44eea044: pop  %rbp 
    0x00007fcd44eea045: jmpq 0x7fcd44e529a0 ; {runtime_call} 
    0x00007fcd44eea04a: mov  0x40(%rsp),%rax 
    0x00007fcd44eea04f: jmp  0x7fcd44eea022 
    0x00007fcd44eea051: mov  %edx,%ebp 
    0x00007fcd44eea053: mov  %ecx,0x40(%rsp) 
    0x00007fcd44eea057: mov  %r8d,0x44(%rsp) 
    0x00007fcd44eea05c: mov  %r9d,(%rsp) 
    0x00007fcd44eea060: mov  %edi,0x4(%rsp) 
    0x00007fcd44eea064: mov  %rax,0x8(%rsp) 
    0x00007fcd44eea069: mov  %esi,0x10(%rsp) 
    0x00007fcd44eea06d: mov  $0xffffff86,%esi 
    0x00007fcd44eea072: nop 
    0x00007fcd44eea073: callq 0x7fcd44dea1a0 ; OopMap{[8]=Oop off=152} 
               ;*aload 
               ; - MyClass::[email protected] (line 106) 
               ; {runtime_call} 
    0x00007fcd44eea078: callq 0x7fcd4dc47c50 ;*aload 
               ; - MyClass::[email protected] (line 106) 
               ; {runtime_call} 
    0x00007fcd44eea07d: hlt 
    0x00007fcd44eea07e: hlt 
    0x00007fcd44eea07f: hlt 

Selon https://wiki.openjdk.java.net/display/HotSpot/LoopPredication, une optimisation, appelée "élimination de la gamme de tableaux", élimine les vérifications de la gamme de tableaux dans la boucle mais ajoute un prédicat de boucle avant la boucle. Il semble que cette optimisation n'ait pas été faite sur 'myLoop' par C2. est à 0x7fcd44eea020 et saute à 0x7fcd44eea000 saut en arrière de la boucle. Dans la boucle, il y a toujours un contrôle de plage à 0x7fcd44eea009-0x7fcd44eea00c.

  1. Pourquoi y a-t-il encore une vérification dans la boucle?
  2. Pourquoi l'optimisation de la prédiction de boucle n'a-t-elle pas été exécutée?
  3. Comment puis-je forcer toutes les optimisations?

Répondre

3

L'explication est là, sur les same page:

De l'exemple ci-dessus, les conditions requises pour exécuter la boucle prédicat pour l'élimination de contrôle de plage de réseau sont que init, limit, offset et array a sont invariants de boucle, et stride et scale sont des constantes de temps de compilation .

Dans votre exemple scale et stride sont pas constantes de compilation temps, donc l'optimisation échoue.

Cependant, si vous appelez cette méthode avec des arguments constants, HotSpot sera en mesure d'éliminer les contrôles de portée en raison de inling et optimisations de propagation constante.

+1

Aussi, vous n'avez pas besoin de spécifier '' UseLoopPredicate' et drapeaux RangeCheckElimination' - ils sont activés par défaut. – apangin