Frage

Die täuschend einfache Grundlage der dynamischen Codegenerierung innerhalb eines C / C ++ Framework bereits in eine andere Frage . Gibt es sanfte Einführung in Thema mit Code-Beispiele?

Meine Augen starren auf sehr komplizierten Open-Source-JIT-Compiler zu bluten beginnen, wenn meine Bedürfnisse sind viel bescheidener.

Gibt es gute Texte zu diesem Thema, die einen Doktortitel in Informatik nicht annehmen? Ich suche nach abgetragenen Muster, die Dinge zu achten gilt, Leistungsinformationen, usw. Elektronische oder Baum-basierte Ressourcen gleichermaßen wertvoll sein kann. Sie können eine gute Kenntnis von (nicht nur x86) Assemblersprache übernehmen.

War es hilfreich?

Lösung

Nun ein Muster, das ich in Emulatoren verwendet habe etwas geht:

typedef void (*code_ptr)();
unsigned long instruction_pointer = entry_point;
std::map<unsigned long, code_ptr> code_map;


void execute_block() {
    code_ptr f;
    std::map<unsigned long, void *>::iterator it = code_map.find(instruction_pointer);
    if(it != code_map.end()) {
        f = it->second
    } else {
        f = generate_code_block();
        code_map[instruction_pointer] = f;
    }
    f();
    instruction_pointer = update_instruction_pointer();
}

void execute() {
    while(true) {
        execute_block();
    }
}

Dies ist eine Vereinfachung, aber die Idee ist da. Grundsätzlich ist der Motor jedes Mal aufgefordert wird, einen „Basisblock“ (in der Regel ein alles bis zur nächsten Flusskontrolle op oder ganzer Funktion in möglich) auszuführen, wird es zu sehen, um zu sehen, ob es bereits erstellt wurde. Wenn ja, führen Sie es, sonst schaffen es, fügen Sie es und dann ausgeführt werden.

Spülenwiederholung:)

Wie für die Codegenerierung, die ein wenig kompliziert wird, aber die Idee ist, eine richtige „Funktion“ zu emittieren, das macht die Arbeit des Basisblockes im Rahmen Ihrer VM.

EDIT: beachten Sie, dass ich keine Optimierungen entweder unter Beweis gestellt haben, aber Sie bat um eine „sanfte Einführung“

EDIT 2: Ich habe vergessen, eine der unmittelbar produktiven Geschwindigkeit ups erwähnen Sie mit diesem Muster implementieren können. Grundsätzlich, wenn Sie nie entfernen, um einen Block von Ihrem Baum (man kann es umgehen, wenn Sie das tun, aber es ist viel einfacher, wenn man nie tun), dann können Sie „Kette“ Blöcke zusammen Lookups zu vermeiden. Hier ist das Konzept. Jedes Mal, wenn Sie von f () zurückgeben und sind über die „update_instruction_pointer“ zu tun, wenn der Block nur ausgeführt Sie entweder in ein Gespräch beendet, unbedingten Sprung, oder gar nicht alle in Flusssteuerung beenden, dann können Sie „fixup“ its RET-Befehl mit einem direkten JMP zum nächsten Block wird es ausführen (denn es ist immer das gleiche sein wird) , wenn Sie haben es bereits emited. Das macht es so ausgeführt werden Sie immer häufiger in der VM und immer weniger in der „execute_block“ Funktion.

Andere Tipps

Ich bin keine Kenntnis von Quellen speziell auf JITs verwandt, aber ich kann mir vorstellen, dass es ziemlich viel wie ein normaler Compiler ist, nur einfacher, wenn man sich keine Sorgen über die Leistung sind.

Der einfachste Weg ist mit einem VM-Interpreter zu starten. Dann wird für jeden Befehl VM, erzeugen die Assembly-Code, der Interpreter ausgeführt hätte.

, darüber hinauszugehen, ich stelle ich vor, dass Sie den VM-Byte-Codes analysieren würden und sie in eine Art von geeigneter Zwischenform umwandeln (drei Adresscode? SSA?) Und dann optimiert und Code wie in jedem anderen Compiler generiert.

Für einen Stapel basierten VM, kann es helfen, den Überblick über die „aktuelle“ Stack-Tiefe zu halten, wie Sie den Byte-Codes in Zwischenform zu übersetzen, und behandeln jede Stack-Position als Variable. Zum Beispiel, wenn Sie der Meinung sind, dass die aktuelle Stack-Tiefe ist 4, und Sie sehen eine „Push“ Anweisung, können Sie eine Zuordnung zu „stack_variable_5“ erzeugen und einen Kompilierung Stapelzähler, oder so ähnlich erhöhen. Ein "add", wenn die Stack-Tiefe 5 könnte den Code "stack_variable_4 = stack_variable_4 + stack_variable_5" und verringern Sie die Kompilierung Stapelzähler erzeugen.

Es ist auch möglich Stack-basierten Code in Syntaxbäume zu übersetzen. Pflegen Sie einen Compiler-Stack. Jeder „Push“ Befehl bewirkt eine Darstellung der Sache auf dem Stapel gespeichert werden geschoben. Operatoren erstellen Syntaxbaum-Knoten, die ihre Operanden umfassen. Zum Beispiel: "XY +" könnte der Stapel bewirken "var (X)", dann "var (X), var (Y)" enthalten, und dann die Plus beide var Referenzen off öffnet und drückt „plus (var (X), var (Y))“.

Holen Sie sich eine Kopie von Joel Pobar Buch über Rotor (wenn es aus), und tauchen Sie durch die Quelle auf die SSCLI . Hüten Sie sich vor, Wahnsinn liegt im Bereich:)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top