Variablen während der Bytecode-Methode neu zeichnen, die durch ASM inlining ist

8

Ich mache eine Online-Bytecode-Methode, um die Optimierung mit ASM zu optimieren. Meine Änderungen basieren auf dem Beispiel 3.2.6 Inline Method ( Ссылка ). Das Testbeispiel (inline callee's calculate (int, int) bei Caller :: test) ist:

%Vor%

Basierend auf der Version ASM 5.0 lautet mein Code:

%Vor%

Im Code erweitern sowohl InliningAdapter als auch MethodCallInliner LocalVariablesSorter , wodurch lokale Variablen neu nummeriert werden. Und die Inline-Referenzen von called body von Callee :: calculate () an der Caller :: test :: invokevirtual (Calle :: calculate) Aufrufseite.

Die Bytecodes für Caller :: test (), Callee :: calculate und generated :: test lauten:

%Vor%

Das javap-Ergebnis der data.class zeigt, dass der Text von Callee :: calculate an der richtigen Stelle eingefügt wurde (Caller :: test line :: 15). Es gibt jedoch zwei Hauptprobleme:

  • Die obersten drei Stapelobjekte vor invokevirtual

    Angerufener :: berechnen (Zeile 15)             9: aload_0
               10: getfield # 14 // Feld _callee: Lcode / sxu / asm / Beispiel / Callee;            13: iload_1
               14: iload_2

    sollte nach dem Inline-Zugriff nicht auf dem Stapel sein.

  • Die Variable 0 im kopierten Textkörper (Callee :: calculate ()) sollte auf die richtige Zahl

  • abgebildet werden
  • Die Variablennummer ist nicht korrekt. Zuerst müssen die Variablennummern des kopierten Körpers von Callee :: calculate in der data.class (von Zeile 15 bis Zeile 42) beginnen 5 (statt 0). Zweitens sollten die Variablennummern nach Callee :: calculate () durch die Regel neu nummeriert werden: a) nicht ändern, wenn sie zwischen (0,4) liegt; b) neu nummerieren, wenn sie mit der Zahl in der kopierten Stelle von Aufrufer in Konflikt steht: : calculate ()

Ich habe die Implementierung der Basisklasse LocalVariablesSorter überprüft. Das Problem scheint bei der Konstruktion zu sein:

%Vor%

Mir scheint, dass die firstLocal immer bei 1+ args.length () beginnt (In diesem Fall ist es 3). Diese Klasse stellt auch private int remap(final int var, final Type type) bereit, wodurch neue lokale Variablen erstellt werden und die Zuordnung (von der vorhandenen Variablennummer zum neuen Index) im Mapping-Array beibehalten wird.

Mein Problem ist, wie man LocalVariablesSorter verwendet und die Bytecode-Methode (Callee :: calculate) korrekt inline einfügt. Jeder Vorschlag für effizientes Inline ist willkommen.

Für Parameter im Stack vor Inline (vor Zeile 15). Meine Idee ist, sie als neu erstellte lokale Variablen zu speichern, die durch den kopierten Körper von Callee :: calculate bezeichnet würden. Fügen Sie beispielsweise Folgendes hinzu:    %Code% nach     10: getfield # 14 // Feld _callee: Lcode / sxu / asm / Beispiel / Callee;

und fügen Sie astore 5 in mapping[0]=5+1

hinzu

Das Hauptproblem besteht jedoch darin, dass Benutzer LocalVariablesSorter (von der alten Variablennummer auf die neue Variable im Mapping-Array) nicht aktualisieren dürfen, weil LocalVariablesSorter::mapping array privat ist und der einzige Ort für ihre Aktualisierung in der Methode ist :

%Vor%

Update1 : Die datac.class nach dem Kommentarkonstruktor des InliningAdapter:

%Vor%

Die neuen gespeicherten drei Variablen (15,16,17) sollten als 5,6,7 anstelle von 2,1,0 nummeriert werden und das Mapping in mapping im Inline-Code sollte wie

%Vor%

Diese Zuordnung sollte im Array sein: *store/*load , das von der Methode LocalVariablesSorter::mapping aktualisiert wird. Es ist jedoch nicht möglich, sie in LocalVariablesSorter::remap() array einzufügen.

Es gibt zwei Arten von Neuanpassungen:

  • Neubelegung innerhalb des Inline-Codes (von Zeile 18 bis 45) und Variable Der Index beginnt bei 5. Der maximale Index ist k
  • Remapping nach inline Code (Von Zeile 46 bis zum Ende), und jeder Variablenindex sollte neu zugeordnet werden (neuer Index beginnt bei k + 1), wenn der ursprüngliche Index größer als 5
  • ist
shijie xu 22.04.2015, 15:22
quelle

1 Antwort

1

Beginnen Sie, wie bereits von @Holger vorgeschlagen, mit dem Auskommentieren der Zeilen in InliningAdapter .

  1. Um die Hauptprobleme anzugehen, die Sie aufgelistet haben: Die LocalVariablesSorter (erweitert um InliningAdapter ) denkt, dass die Argumente bereits in den lokalen Variablen an festen Orten gespeichert sind - dies ist die normale Situation beim Eingeben einer Methode. Es werden also überhaupt keine zugeordnet (siehe erste Zeile in LocalVariablesSorter.remap() - firstLocal wird im Konstruktor berechnet). In diesem Fall erhalten wir stattdessen die Argumente auf dem Stack und müssen die lokalen Variablen manuell zuweisen. Die Lösung besteht darin, LocalVariablesSorter mitzuteilen, dass in lokalen Variablen noch keine Parameter gespeichert sind (make firstLocal = 0 ). Dann behandelt es jede Bezugnahme auf sie als neue Variablen und weist ihnen neue lokale Variablen zu. Dies können wir erreichen, indem wir LocalVariablesSorter täuschen, um zu denken, dass es keine Argumente gibt und dass die Methode statisch ist (auch wenn es nicht wirklich ist). Also ändern wir die erste Zeile in InliningAdapter von

    %Vor%

    bis

    %Vor%

    Nun werden die Variablen 0, 1, 2, ... zu 5, 6, 7, ... oder ähnlich zugeordnet (es spielt keine Rolle, was sie sind, die LocalVariablesSorter von Caller (dh die MethodCallInliner instance) kümmert sich um die Zuordnung).

  2. Es gibt noch ein weiteres Problem, dass Sie die Klasse Callee auf Caller mappen, indem Sie InliningAdapter extend RemappingMethodAdaptor haben - aber ich denke, dass Sie die Variablen _a und _b in% beibehalten möchten. co_de% Instanz.

    • Wenn meine Schätzung richtig ist, sollten Sie die Referenzen von Callee auf Callee nicht neu zuordnen. Sie können stattdessen Caller extend InliningAdapter machen und den Remapper loswerden.
    • Wenn meine Schätzung falsch ist, dann denke ich, dass Sie wahrscheinlich auch die Variablen LocalVariableSorter in Callee einbetten müssen. In diesem Fall sollten Sie die Caller behalten, die Sie haben.
  3. Beim Debuggen des Inline-Codes sind die Zeilennummern aus RemappingMethodAdaptor nicht sinnvoll, da der Code in die Klasse Callee eingezeichnet wurde. Daher sollten alle Zeilennummern aus Caller wahrscheinlich durch die Zeilennummer der Zeile in Callee ersetzt werden, bei der der Inline-Aufruf aufgetreten ist. Leider können Sie in Java nicht zeilenweise unterschiedliche Quellcodedateien angeben (wie zB in C). Sie würden also Caller in visitLineNumber() überschreiben, indem Sie so etwas verwenden ( InliningAdapter würde an den Konstruktor von inlinedLine übergeben):

    %Vor%

    .. oder vielleicht überspringen Sie den Super-Anruf insgesamt, ich bin mir nicht 100% sicher.

Jonas Berlin 13.05.2015, 08:47
quelle