Anweisungen in Java JVM neu anordnen

ich habe gelesendiese Blogeintrag.

Und der Autor sprach davon, das zu brechenhashCode() imString in Multithread-Umgebung.

Indem:

public int hashCode() {
     int h = hash;
     if (h == 0) {
         int off = offset;
         char val[] = value;
         int len = count;

         for (int i = 0; i < len; i++) {
             h = 31*h + val[off++];
         }
         hash = h;
     }
     return h;
 }

Gewechselt zu:

public int hashCode() {
     if (hash == 0) {
         int off = offset;
         char val[] = value;
         int len = count;

         int h = 0;
         for (int i = 0; i < len; i++) {
             h = 31*h + val[off++];
         }
         hash = h;
     }
     return hash;
 }

Was der Autor sagt und ich zitiere:

"Was ich hier getan habe, ist, eine zusätzliche Lektüre hinzuzufügen:das zweite Lesen von Hash vor der Rückkehr. So seltsam es klingt und so unwahrscheinlich es auch sein mag, der erste Lesevorgang kann den korrekt berechneten Hashwert und der zweite Lesevorgang 0 zurückgeben! Dies ist im Speichermodell zulässig, da das Modell eine umfassende Neuordnung von Operationen ermöglicht. Der zweite Lesevorgang kann in Ihrem Code verschoben werden, sodass Ihr Prozessor ihn vor dem ersten ausführt! "

Wenn Sie also die Kommentare durchgehen, sagt jemand, dass sie nachbestellt werden können

int h = hash;
if (hash == 0) {
  ...
}
return h;

Wie ist das möglich? Ich dachte, beim Neuordnen werden nur Programmanweisungen nach oben und unten verschoben. Nach welchen Regeln handelt es sich? Ich habe gegoogelt, die JSR133-FAQ gelesen, das Java Concurrency in Practice-Buch überprüft, aber ich kann anscheinend keinen Ort finden, der mir hilft, besonders beim Neuanordnen zu verstehen. Wenn jemand mich in die richtige Richtung weisen kann, würde ich es wirklich schätzen.

Dank Louis, der die Bedeutung von "Reordering" klarstellte, dachte ich nicht an "byteCode".

Ich verstehe jedoch immer noch nicht, warum es erlaubt ist, den 2. Lesevorgang nach vorne zu verschieben. Dies ist mein naiver Versuch, ihn in ein "Bytecode" -Format zu übersetzen.

Zur Vereinfachung werden Operationen, die zur Berechnung des Hashcodes verwendet werden, als ausgedrücktcalchash(). Deshalb drücke ich das Programm so aus:

if (hash == 0)  {       
    h = calchash();
    hash = h;
}
return hash;

Und mein Versuch, es in "Bytecode" -Form auszudrücken:

R1,R2,R3 are in the operands stack, or the registers
h is in the array of local variables

In Programmreihenfolge:

if (hash == 0)  {       ---------- R1 = read hash from memory (1st read)
                        ---------- Compare (R1 == 0)
    h = calchash();     ---------- R2 = calchash()
                        ---------- h = R2 (Storing the R2 to local variable h)
    hash = h;           ---------- Hash = h (write to hash)
}
return hash             ---------- R3 = read hash from memory again(2nd read)
                        ---------- return R3

Neu angeordnete Transformation (Meine Version basiert auf Kommentaren):

                        ---------- R3 = read hash from memory (2nd read) *moved*
if (hash == 0)  {       ---------- R1 = read hash from memory (1st read)
                        ---------- Compare (R1 == 0)
    h = calchash();     ---------- R2 = calchash()
                        ---------- h = R2 (Storing the R2 to local variable h)
    hash = h;           ---------- hash = h (write to hash)
}
return hash             ---------- return R3

Beim erneuten Überprüfen der Kommentare fand ich die Antwort des Autors:

Neu geordnete Transformation (Aus dem Blog)

r1 = hash;
if (hash == 0) {
  r1 = hash = // calculate hash
}
return r1;

Dieser Fall funktioniert tatsächlich für einen einzelnen Thread, aber es ist möglich, dass bei mehreren Threads ein Fehler auftritt.

Es scheint, dass die JVM Vereinfachungen basierend auf vornehmen

h = hash and it simplifies the use of R1, R2, R3 to single R1

Daher kann JVM nicht nur Befehle neu anordnen, sondern auch die Anzahl der verwendeten Register verringern.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage