Manipulieren des V8 ast

8

Ich beabsichtige, eine js-Codeabdeckung direkt im v8-Code zu implementieren. Mein anfängliches Ziel besteht darin, für jede Anweisung im abstrakten Syntaxbaum einen einfachen Ausdruck hinzuzufügen. Ich habe gesehen, dass es eine Klasse AstVisitor gibt, die es erlaubt, die AST zu durchlaufen. Meine Frage ist also, wie kann ich dem AST eine Aussage nach der Aussage hinzufügen, die der Besucher gerade besucht?

    
user2240085 03.04.2013, 11:01
quelle

1 Antwort

5

Ok, ich werde meine Experimente zusammenfassen. Erstens, was ich schreibe gilt für V8, wie es in der Chromium-Version r157275 verwendet wurde, so dass Dinge nicht mehr funktionieren können - aber ich werde trotzdem auf die Plätze in der aktuellen Version verlinken.

Wie gesagt, Sie benötigen Ihren eigenen AST-Besucher, sagen wir MyAstVisior , der von AstVisitor und von dort aus eine Reihe von VisitXYZ Methoden implementieren müssen. Der einzige Code, der benötigt wird, um den Code zu testen, ist VisitFunctionLiteral . Ausgeführter Code ist entweder eine Funktion oder eine Menge loser Anweisungen in einer Quelle (Datei), die V8 in eine Funktion einfügt, die dann ausgeführt wird.

Kurz bevor ein analysierter AST in Code konvertiert wird, hier (Zusammenstellung der Funktion aus den losen Aussagen) und hier (Kompilierung während der Laufzeit, wenn eine vordefinierte Funktion zum ersten Mal ausgeführt wird), übergeben Sie Ihren Besucher zum Funktionsliteral, das VisitFunctionLiteral auf dem Besucher aufruft:

%Vor%

Ich habe den CompilationInfo -Zeiger info an den benutzerdefinierten Besucher übergeben, weil dieser zum Ändern des AST benötigt wird. Der Konstruktor sieht so aus:

%Vor%

_ci, _nf und _z sind Zeiger auf CompilationInfo , AstNodeFactory<AstNullVisitor> und Zone .

Jetzt in VisitFunctionLiteral können Sie den Funktionskörper durchlaufen und bei Bedarf auch Anweisungen einfügen.

%Vor%

In der Methode rewriteStatement können Sie jetzt die Anweisung überprüfen. Der _stmts -Zeiger enthält eine Liste von Anweisungen, die am Ende den ursprünglichen Funktionskörper ersetzen. Um also nach jeder Anweisung eine print-Anweisung hinzuzufügen, fügen Sie zuerst die ursprüngliche Anweisung hinzu und fügen dann Ihre eigene print-Anweisung hinzu:

%Vor%

Der letzte Parameter von NewCall und NewUnresolved ist eine Zahl, die die Position im Skript angibt. Ich nehme an, dies wird für Debug / Fehlermeldungen verwendet, um zu sagen, wo ein Fehler passiert ist. Ich habe zumindest nie Probleme mit der Einstellung auf 0 (es gibt auch eine Konstante irgendwo kNoPosition).

Einige abschließende Worte: Dies fügt nicht wirklich eine Druckanweisung nach jeder Anweisung hinzu, weil Blocks (z. B. Schleifenkörper) Anweisungen sind, die eine Liste von Anweisungen darstellen, und Schleifen Anweisungen mit einem Bedingungsausdruck und einem Körperblock sind. Sie müssten also prüfen, welche Art von Anweisung derzeit behandelt wird und rekursiv nachsehen. Das Umschreiben von Blöcken ist im Prinzip dasselbe wie das Neuschreiben eines Funktionskörpers.

Sie werden jedoch Probleme bekommen, wenn Sie anfangen, vorhandene Anweisungen zu ersetzen oder zu modifizieren, weil die AST auch Informationen über Verzweigungen enthält. Wenn Sie also ein Sprungziel für eine Bedingung ersetzen, brechen Sie Ihren Code. Ich denke, dies könnte abgedeckt werden, wenn man die einzelnen Ausdrucks- und Anweisungstypen direkt umschreibt, anstatt neue zu erstellen, um sie zu ersetzen.

Bisher hoffe ich, dass es hilft.

    
Jonas 11.04.2013, 21:56
quelle