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:
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
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:
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
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 :
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
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:
Beginnen Sie, wie bereits von @Holger vorgeschlagen, mit dem Auskommentieren der Zeilen in InliningAdapter
.
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
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).
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.
Callee
auf Callee
nicht neu zuordnen. Sie können stattdessen Caller
extend InliningAdapter
machen und den Remapper loswerden. LocalVariableSorter
in Callee
einbetten müssen. In diesem Fall sollten Sie die Caller
behalten, die Sie haben. 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):
.. oder vielleicht überspringen Sie den Super-Anruf insgesamt, ich bin mir nicht 100% sicher.
Tags und Links java inline bytecode bytecode-manipulation java-bytecode-asm