Julia ASTs
Julia hat zwei Darstellungen von Code. Zuerst gibt es eine Oberflächensyntax-AST, die vom Parser zurückgegeben wird (z. B. die Meta.parse-Funktion) und von Makros manipuliert wird. Es ist eine strukturierte Darstellung von Code, wie er geschrieben ist, die von julia-parser.scm aus einem Zeichenstrom konstruiert wird. Als Nächstes gibt es eine abgesenkte Form oder IR (intermediate representation), die von der Typinferenz und der Codegenerierung verwendet wird. In der abgesenkten Form gibt es weniger Arten von Knoten, alle Makros sind erweitert, und alle Kontrollflüsse werden in explizite Verzweigungen und Sequenzen von Anweisungen umgewandelt. Die abgesenkte Form wird von julia-syntax.scm konstruiert.
Zuerst werden wir uns auf den AST konzentrieren, da er benötigt wird, um Makros zu schreiben.
Surface syntax AST
Frontend-ASTs bestehen fast ausschließlich aus Exprs und Atomen (z. B. Symbole, Zahlen). Es gibt im Allgemeinen einen anderen Ausdrucks-Kopf für jede visuell unterscheidbare syntaktische Form. Beispiele werden in s-Ausdruck-Syntax gegeben. Jede in Klammern gesetzte Liste entspricht einem Expr, wobei das erste Element der Kopf ist. Zum Beispiel entspricht (call f x) Expr(:call, :f, :x) in Julia.
Calls
| Input | AST |
|---|---|
f(x) | (call f x) |
f(x, y=1, z=2) | (call f x (kw y 1) (kw z 2)) |
f(x; y=1) | (call f (parameters (kw y 1)) x) |
f(x...) | (call f (... x)) |
do Syntax:
f(x) do a,b
body
endparst als (do (call f x) (-> (tuple a b) (block body))).
Operators
Die meisten Verwendungen von Operatoren sind einfach Funktionsaufrufe, daher werden sie mit dem Kopf call geparst. Einige Operatoren sind jedoch spezielle Formen (nicht unbedingt Funktionsaufrufe), und in diesen Fällen ist der Operator selbst der Ausdruckskopf. In julia-parser.scm werden diese als "syntaktische Operatoren" bezeichnet. Einige Operatoren (+ und *) verwenden N-ary Parsing; verkettete Aufrufe werden als ein einziger N-Argument-Aufruf geparst. Schließlich haben Ketten von Vergleichen ihre eigene spezielle Ausdrucksstruktur.
| Input | AST |
|---|---|
x+y | (call + x y) |
a+b+c+d | (call + a b c d) |
2x | (call * 2 x) |
a&&b | (&& a b) |
x += 1 | (+= x 1) |
a ? 1 : 2 | (if a 1 2) |
a,b | (tuple a b) |
a==b | (call == a b) |
1<i<=n | (comparison 1 < i <= n) |
a.b | (. a (quote b)) |
a.(b) | (. a (tuple b)) |
Bracketed forms
| Input | AST |
|---|---|
a[i] | (ref a i) |
t[i;j] | (typed_vcat t i j) |
t[i j] | (typed_hcat t i j) |
t[a b; c d] | (typed_vcat t (row a b) (row c d)) |
t[a b;;; c d] | (typed_ncat t 3 (row a b) (row c d)) |
a{b} | (curly a b) |
a{b;c} | (curly a (parameters c) b) |
[x] | (vect x) |
[x,y] | (vect x y) |
[x;y] | (vcat x y) |
[x y] | (hcat x y) |
[x y; z t] | (vcat (row x y) (row z t)) |
[x;y;; z;t;;;] | (ncat 3 (nrow 2 (nrow 1 x y) (nrow 1 z t))) |
[x for y in z, a in b] | (comprehension (generator x (= y z) (= a b))) |
T[x for y in z] | (typed_comprehension T (generator x (= y z))) |
(a, b, c) | (tuple a b c) |
(a; b; c) | (block a b c) |
Macros
| Input | AST |
|---|---|
@m x y | (macrocall @m (line) x y) |
Base.@m x y | (macrocall (. Base (quote @m)) (line) x y) |
@Base.m x y | (macrocall (. Base (quote @m)) (line) x y) |
Strings
| Input | AST |
|---|---|
"a" | "a" |
x"y" | (macrocall @x_str (line) "y") |
x"y"z | (macrocall @x_str (line) "y" "z") |
"x = $x" | (string "x = " x) |
`a b c` | (macrocall @cmd (line) "a b c") |
Docstring-Syntax:
"some docs"
f(x) = xparst als (macrocall (|.| Core '@doc) (line) "einige Dokumente" (= (call f x) (block x))).
Imports and such
| Input | AST |
|---|---|
import a | (import (. a)) |
import a.b.c | (import (. a b c)) |
import ...a | (import (. . . . a)) |
import a.b, c.d | (import (. a b) (. c d)) |
import Base: x | (import (: (. Base) (. x))) |
import Base: x, y | (import (: (. Base) (. x) (. y))) |
export a, b | (export a b) |
using hat die gleiche Darstellung wie import, jedoch mit dem Ausdrucksanfang :using anstelle von :import.
Numbers
Julia unterstützt mehr Zahlentypen als viele Scheme-Implementierungen, sodass nicht alle Zahlen direkt als Scheme-Zahlen im AST dargestellt werden.
| Input | AST |
|---|---|
11111111111111111111 | (macrocall @int128_str nothing "11111111111111111111") |
0xfffffffffffffffff | (macrocall @uint128_str nothing "0xfffffffffffffffff") |
1111...many digits... | (macrocall @big_str nothing "1111....") |
Block forms
Ein Block von Anweisungen wird als (block stmt1 stmt2 ...) geparst.
Wenn-Anweisung:
if a
b
elseif c
d
else
e
endparst als:
(if a (block (line 2) b)
(elseif (block (line 3) c) (block (line 4) d)
(block (line 6 e))))Eine while-Schleife wird als (while Bedingung Körper) interpretiert.
Eine for-Schleife wird als (for (= var iter) body) geparst. Wenn es mehr als eine Iterationsspezifikation gibt, werden sie als Block geparst: (for (block (= v1 iter1) (= v2 iter2)) body).
break und continue werden als 0-Argument-Ausdrücke (break) und (continue) interpretiert.
let wird als (let (= var val) body) oder (let (block (= var1 val1) (= var2 val2) ...) body) geparst, ähnlich wie for-Schleifen.
Eine grundlegende Funktionsdefinition wird als (function (call f x) body) analysiert. Ein komplexeres Beispiel:
function f(x::T; k = 1) where T
return x+1
endparst als:
(function (where (call f (parameters (kw k 1))
(:: x T))
T)
(block (line 2) (return (call + x 1))))Typdefinition:
mutable struct Foo{T<:S}
x::T
endparst als:
(struct true (curly Foo (<: T S))
(block (line 2) (:: x T)))Das erste Argument ist ein Boolean, der angibt, ob der Typ veränderlich ist.
try-Blöcke werden als (try try_block var catch_block finally_block) geparst. Wenn nach catch keine Variable vorhanden ist, ist var #f. Wenn keine finally-Klausel vorhanden ist, fehlt das letzte Argument.
Quote expressions
Julia-Quellsyntaxformen für Code-Zitierungen (quote und :( )) unterstützen die Interpolation mit $. In der Lisp-Terminologie bedeutet dies, dass sie tatsächlich "Backquote" oder "Quasiquote"-Formen sind. Intern gibt es auch die Notwendigkeit für Code-Zitierungen ohne Interpolation. In Julias Schemakode wird die nicht-interpolierende Zitierung mit dem Ausdrucks-Kopf inert dargestellt.
inert Ausdrücke werden in Julia QuoteNode Objekte umgewandelt. Diese Objekte umschließen einen einzelnen Wert beliebigen Typs und geben bei der Auswertung einfach diesen Wert zurück.
Ein quote-Ausdruck, dessen Argument ein Atom ist, wird ebenfalls in einen QuoteNode umgewandelt.
Line numbers
Quellortinformationen werden als (Zeile zeilen_num dateiname) dargestellt, wobei die dritte Komponente optional ist (und weggelassen wird, wenn sich die aktuelle Zeilennummer, aber nicht der Dateiname, ändert).
Diese Ausdrücke werden in Julia als LineNumberNodes dargestellt.
Macros
Makro-Hygiene wird durch den Ausdruck Kopf-Paar escape und hygienic-scope dargestellt. Das Ergebnis einer Makroerweiterung wird automatisch in (hygienic-scope block module) eingewickelt, um das Ergebnis des neuen Geltungsbereichs darzustellen. Der Benutzer kann (escape block) einfügen, um Code vom Aufrufer zu interpolieren.
Lowered form
Die abgesenkte Form (IR) ist für den Compiler wichtiger, da sie für Typinferenz, Optimierungen wie Inlining und Codegenerierung verwendet wird. Sie ist auch weniger offensichtlich für den Menschen, da sie aus einer erheblichen Umstrukturierung der Eingabesyntax resultiert.
Zusätzlich zu Symbols und einigen Zahlentypen existieren die folgenden Datentypen in gesenkter Form:
ExprHat einen Knotentyp, der durch das
head-Feld angezeigt wird, und einargs-Feld, das einVector{Any}von Unterausdrücken ist. Während fast jeder Teil eines Oberflächen-AST durch einExprdargestellt wird, verwendet das IR nur eine begrenzte Anzahl vonExprs, hauptsächlich für Aufrufe und einige nur auf oberster Ebene vorhandene Formen.SlotNummerIdentifiziert Argumente und lokale Variablen durch aufeinanderfolgende Nummerierung. Es hat ein ganzzahliges
id-Feld, das den Slot-Index angibt. Die Typen dieser Slots können imslottypes-Feld ihresCodeInfo-Objekts gefunden werden.ArgumentDas gleiche wie
SlotNumber, erscheint jedoch nur nach der Optimierung. Zeigt an, dass der referenzierte Slot ein Argument der umschließenden Funktion ist.CodeInfoUmhüllt die IR einer Gruppe von Anweisungen. Das
code-Feld ist ein Array von Ausdrücken, die ausgeführt werden sollen.GotoNodeUnbedingter Sprung. Das Argument ist das Sprungziel, dargestellt als ein Index im Code-Array, zu dem gesprungen werden soll.
GotoIfNotBedingte Verzweigung. Wenn das Feld
condauf falsch ausgewertet wird, geht es zu dem durch das Felddestidentifizierten Index.ReturnNodeGibt sein Argument (das
val-Feld) als den Wert der umschließenden Funktion zurück. Wenn dasval-Feld undefiniert ist, stellt dies eine unerreichbare Anweisung dar.ZitatKnotenWickelt einen beliebigen Wert, um ihn als Daten zu referenzieren. Zum Beispiel enthält die Funktion
f() = :aeinenQuoteNode, dessenvalue-Feld das Symbolaist, um das Symbol selbst zurückzugeben, anstatt es auszuwerten.GlobalRefBezieht sich auf die globale Variable
nameim Modulmod.SSAValueBezieht sich auf eine fortlaufend nummerierte (beginnend bei 1) statische Ein-Zuweisung (SSA) Variable, die vom Compiler eingefügt wurde. Die Nummer (
id) einesSSAValueist der Code-Array-Index des Ausdrucks, dessen Wert sie darstellt.NewvarNodeMarkiert einen Punkt, an dem eine Variable (Slot) erstellt wird. Dies hat zur Folge, dass eine Variable auf undefiniert zurückgesetzt wird.
Expr types
Diese Symbole erscheinen im head-Feld von Expr in kleingeschriebener Form.
anrufenFunktionsaufruf (dynamische Dispatch).
args[1]ist die aufzurufende Funktion,args[2:end]sind die Argumente.aufrufenFunktionsaufruf (statische Dispatch).
args[1]ist die MethodInstance, die aufgerufen werden soll,args[2:end]sind die Argumente (einschließlich der Funktion, die aufgerufen wird, beiargs[2]).statischer_parameterVerweisen Sie auf einen statischen Parameter nach Index.
=Aufgabe. Im IR ist das erste Argument immer eine
SlotNumberoder einGlobalRef.MethodeFügt einer generischen Funktion eine Methode hinzu und weist das Ergebnis bei Bedarf zu.
Hat eine 1-Argument-Form und eine 3-Argument-Form. Die 1-Argument-Form ergibt sich aus der Syntax
function foo end. In der 1-Argument-Form ist das Argument ein Symbol. Wenn dieses Symbol bereits eine Funktion im aktuellen Gültigkeitsbereich benennt, passiert nichts. Wenn das Symbol undefiniert ist, wird eine neue Funktion erstellt und dem durch das Symbol angegebenen Bezeichner zugewiesen. Wenn das Symbol definiert ist, aber eine Nicht-Funktion benennt, wird ein Fehler ausgelöst. Die Definition von "benennt eine Funktion" ist, dass die Bindung konstant ist und auf ein Objekt vom Singleton-Typ verweist. Der Grund dafür ist, dass eine Instanz eines Singleton-Typs den Typ eindeutig identifiziert, um die Methode hinzuzufügen. Wenn der Typ Felder hat, wäre es unklar, ob die Methode der Instanz oder ihrem Typ hinzugefügt wird.Die 3-Argument-Form hat die folgenden Argumente:
args[1]Ein Funktionsname oder
nichts, wenn unbekannt oder nicht benötigt. Wenn ein Symbol, verhält sich der Ausdruck zuerst wie die oben genannte 1-Argument-Form. Dieses Argument wird von da an ignoriert. Es kannnichtssein, wenn Methoden strikt nach Typ hinzugefügt werden,(::T)(x) = x, oder wenn eine Methode zu einer bestehenden Funktion hinzugefügt wird,MyModule.f(x) = x.args[2]Ein
SimpleVectordes Argumenttyps Daten.args[2][1]ist einSimpleVectorder Argumenttypen, undargs[2][2]ist einSimpleVectorder Typvariablen, die den statischen Parametern der Methode entsprechen.args[3]Ein
CodeInfoder Methode selbst. Für "außerhalb des Geltungsbereichs" liegende Methodendefinitionen (Hinzufügen einer Methode zu einer Funktion, die auch Methoden in verschiedenen Geltungsbereichen definiert hat) handelt es sich um einen Ausdruck, der zu einem:lambda-Ausdruck ausgewertet wird.
struct_typeEin 7-Argument-Ausdruck, der eine neue
structdefiniert:args[1]Der Name der
structargs[2]Ein
call-Ausdruck, der einenSimpleVectorerstellt und seine Parameter angibt.args[3]Ein
call-Ausdruck, der einenSimpleVectorerstellt und seine Feldnamen angibt.args[4]Ein
Symbol,GlobalRefoderExpr, der den Supertyp angibt (z. B.:Integer,GlobalRef(Core, :Any)oder:(Core.apply_type(AbstractArray, T, N)))args[5]Ein
call-Ausdruck, der einenSimpleVectorerstellt und seine Feldtypen angibt.args[6]Ein Bool, wahr wenn
mutableargs[7]Die Anzahl der Argumente zur Initialisierung. Dies wird die Anzahl der Felder sein oder die minimale Anzahl der Felder, die durch die
new-Anweisung eines inneren Konstruktors aufgerufen werden.
abstract_typeEin 3-Argument-Ausdruck, der einen neuen abstrakten Typ definiert. Die Argumente sind dieselben wie die Argumente 1, 2 und 4 von
struct_type-Ausdrücken.primitive_typeEin 4-Argumente-Ausdruck, der einen neuen primitiven Typ definiert. Die Argumente 1, 2 und 4 sind dieselben wie
struct_type. Argument 3 ist die Anzahl der Bits.Julia 1.5 struct_type,abstract_typeundprimitive_typewurden in Julia 1.5 entfernt und durch Aufrufe neuer Built-ins ersetzt.globalDeklariert eine globale Bindung.
constDeklariert eine (globale) Variable als konstant.
neuAllokiert ein neues struct-ähnliches Objekt. Das erste Argument ist der Typ. Die
newPseudo-Funktion wird darauf reduziert, und der Typ wird immer vom Compiler eingefügt. Dies ist eine sehr interne Funktion und führt keine Überprüfungen durch. Die Auswertung beliebigernew-Ausdrücke kann leicht zu einem Segfault führen.splatnewÄhnlich wie
new, außer dass die Feldwerte als ein einzelnes Tupel übergeben werden. Funktioniert ähnlich wiesplat(new), wennneweine erstklassige Funktion wäre, daher der Name.isdefinedExpr(:isdefined, :x)gibt einen Bool zurück, der angibt, obxim aktuellen Gültigkeitsbereich bereits definiert wurde.die_ausnahmeGibt die gefangene Ausnahme innerhalb eines
catch-Blocks zurück, wie vonjl_current_exception(ct)zurückgegeben.enterTritt in einen Ausnahmebehandler (
setjmp) ein.args[1]ist das Label des Catch-Blocks, zu dem bei einem Fehler gesprungen werden soll. Gibt ein Token zurück, das vonpop_exceptionverbraucht wird.UrlaubPop-Ausnahmebehandler.
args[1]ist die Anzahl der zu entfernenden Behandler.pop_exceptionPoppen Sie den Stapel der aktuellen Ausnahmen zurück in den Zustand beim zugehörigen
enter, wenn Sie einen Catch-Block verlassen.args[1]enthält das Token vom zugehörigenenter.Julia 1.1 pop_exceptionist neu in Julia 1.1.inboundsSteuert das Aktivieren oder Deaktivieren von Grenzprüfungen. Ein Stack wird verwaltet; wenn das erste Argument dieses Ausdrucks wahr oder falsch ist (
truebedeutet, dass die Grenzprüfungen deaktiviert sind), wird es auf den Stack gelegt. Wenn das erste Argument:popist, wird der Stack geleert.boundscheckHat den Wert
false, wenn es in einen Codeabschnitt eingefügt wird, der mit@inboundsgekennzeichnet ist, andernfalls hat es den Werttrue.loopinfoMarkiert das Ende einer Schleife. Enthält Metadaten, die an
LowerSimdLoopübergeben werden, um entweder die innere Schleife eines@simd-Ausdrucks zu kennzeichnen oder Informationen an LLVM-Schleifenpässe weiterzugeben.copyastTeil der Implementierung von Quasi-Zitaten. Das Argument ist ein Oberflächensyntax-AST, der einfach rekursiv kopiert und zur Laufzeit zurückgegeben wird.
metaMetadaten.
args[1]ist typischerweise ein Symbol, das die Art der Metadaten angibt, und die restlichen Argumente sind frei formatiert. Die folgenden Arten von Metadaten werden häufig verwendet::inlineund:noinline: Inlining-Hinweise.
foreigncallStatisch berechneter Container für
ccall-Informationen. Die Felder sind:args[1]: NameDer Ausdruck, der für die Fremdfunktion geparst wird.
args[2]::Type: RTDer (wörtliche) Rückgabetyp, der statisch berechnet wird, wenn die umgebende Methode definiert wurde.
args[3]::SimpleVector(von Typen) : ATDer (wörtliche) Vektor der Argumenttypen, der statisch berechnet wird, wenn die enthaltene Methode definiert wurde.
args[4]::Int: nreqDie Anzahl der erforderlichen Argumente für eine Varargs-Funktionsdefinition.
args[5]::QuoteNode{Symbol}: AufrufkonventionDie Aufrufkonvention für den Aufruf.
args[6:5+length(args[3])]: ArgumenteDie Werte für alle Argumente (mit den Typen von jedem in args[3] angegeben).
args[6+length(args[3])+1:end]: gc-wurzelnDie zusätzlichen Objekte, die während des Aufrufs gc-rooted werden müssen. Siehe Working with LLVM für die Herkunft und wie sie behandelt werden.
new_opaque_closureKonstruiert einen neuen undurchsichtigen Closure. Die Felder sind:
args[1]: SignaturDie Funktionssignatur des opaken Closures. Opake Closures nehmen nicht am Dispatch teil, aber die Eingabetypen können eingeschränkt werden.
args[2]: isvaGibt an, ob der Closure varargs akzeptiert.
args[3]: lbUntergrenze für den Ausgabetyp. (Standardmäßig
Union{})args[4]: ubObergrenze für den Ausgabetyp. (Standardmäßig
Any)args[5]: MethodeDie tatsächliche Methode als
opaque_closure_methodAusdruck.args[6:end]: erfasstDie Werte, die durch den undurchsichtigen Abschluss erfasst werden.
Julia 1.7 Intransparente Closures wurden in Julia 1.7 hinzugefügt.
Method
Ein einzigartiger Container, der die gemeinsamen Metadaten für eine einzelne Methode beschreibt.
name,modul,datei,zeile,sigMetadaten zur eindeutigen Identifizierung der Methode für den Computer und den Menschen.
ambigCache anderer Methoden, die mit dieser hier möglicherweise mehrdeutig sind.
spezialisierungenCache aller jemals für diese Methode erstellten MethodInstance, die zur Gewährleistung der Einzigartigkeit verwendet wird. Einzigartigkeit ist für die Effizienz erforderlich, insbesondere für die inkrementelle Vorabkompilierung und die Verfolgung der Ungültigkeit von Methoden.
QuelleDer ursprüngliche Quellcode (sofern verfügbar, normalerweise komprimiert).
GeneratorEin aufrufbares Objekt, das ausgeführt werden kann, um spezialisierten Quellcode für eine bestimmte Methodensignatur zu erhalten.
WurzelnZeiger auf Nicht-AST-Dinge, die in den AST interpoliert wurden, erforderlich durch die Kompression des AST, Typinferenz oder die Generierung von nativen Code.
nargs,isva,called,is_for_opaque_closure,Beschreibende Bitfelder für den Quellcode dieser Methode.
primäre_weltDas Weltzeitalter, das diese Methode "besitzt".
MethodInstance
Ein einzigartiger Container, der eine einzelne aufrufbare Signatur für eine Methode beschreibt. Siehe insbesondere Proper maintenance and care of multi-threading locks für wichtige Details, wie man diese Felder sicher ändern kann.
specTypesDer Primärschlüssel für diese MethodInstance. Die Eindeutigkeit wird durch eine
def.specializations-Suche garantiert.defDie
Methode, die diese Funktion beschreibt, ist eine Spezialisierung. Oder einModul, wenn dies ein top-level Lambda ist, das im Modul erweitert wurde und nicht Teil einer Methode ist.sparam_valsDie Werte der statischen Parameter in
specTypes. Für dieMethodInstancebeiMethod.unspecializedist dies der leereSimpleVector. Aber für eine Laufzeit-MethodInstanceaus demMethodTable-Cache wird dies immer definiert und indexierbar sein.uninferredDer unkomprimierte Quellcode für einen Top-Level-Thunk. Darüber hinaus ist dies für eine generierte Funktion einer von vielen Orten, an denen der Quellcode gefunden werden kann.
RückkantenWir speichern die Rückwärtsliste der Cache-Abhängigkeiten für eine effiziente Verfolgung der inkrementellen Neuanalyse/-kompilierungsarbeiten, die nach neuen Methodendefinitionen erforderlich sein können. Dies funktioniert, indem eine Liste der anderen
MethodInstancegeführt wird, die abgeleitet oder optimiert wurden, um einen möglichen Aufruf zu dieserMethodInstancezu enthalten. Diese Optimierungsergebnisse könnten irgendwo imcachegespeichert sein, oder es könnte das Ergebnis von etwas gewesen sein, das wir nicht cachen wollten, wie z. B. Konstantenpropagation. Daher fügen wir all diese Rückkanten zu verschiedenen Cache-Einträgen hier zusammen (es gibt fast immer nur den einen anwendbaren Cache-Eintrag mit einem Sentinelwert für max_world).CacheCache von
CodeInstance-Objekten, die diese Template-Instanziierung teilen.
CodeInstance
defDer
MethodInstance, von dem dieser Cache-Eintrag abgeleitet ist.BesitzerEin Token, das den Besitzer dieser
CodeInstancerepräsentiert. Wirdjl_egalverwenden, um Übereinstimmungen zu finden.
rettype/rettype_constDer abgeleitete Rückgabetyp für das Feld
specFunctionObject, das (in den meisten Fällen) auch der berechnete Rückgabetyp für die Funktion im Allgemeinen ist.abgeleitetKann einen Cache der abgeleiteten Quelle für diese Funktion enthalten, oder es könnte auf
nichtsgesetzt werden, um einfach anzuzeigen, dassrettypeabgeleitet ist.ftprDer generische jlcall-Einstiegspunkt.
jlcall_apiDie ABI, die beim Aufrufen von
fptrverwendet werden soll. Einige bedeutende sind:- 0 - Noch nicht kompiliert
- 1 -
JL_CALLABLEjl_value_t *(*)(jl_function_t *f, jl_value_t *args[nargs], uint32_t nargs) - 2 - Konstante (Wert, der in
rettype_constgespeichert ist) - 3 - Mit statischen Parametern weitergeleitet
jl_value_t *(*)(jl_svec_t *sparams, jl_function_t *f, jl_value_t *args[nargs], uint32_t nargs) - 4 - Führen Sie im Interpreter aus
jl_value_t *(*)(jl_method_instance_t *meth, jl_function_t *f, jl_value_t *args[nargs], uint32_t nargs)
min_world/max_worldDer Bereich der Weltalter, für den diese Methodeninstanz gültig ist, um aufgerufen zu werden. Wenn max_world der spezielle Tokenwert
-1ist, ist der Wert noch nicht bekannt. Er kann weiterhin verwendet werden, bis wir auf eine Rückkante stoßen, die uns zwingt, dies zu überdenken.
CodeInfo
Ein (normalerweise temporärer) Behälter zum Halten von gesenktem Quellcode.
codeEin
Any-Array von AussagenslotnamenEin Array von Symbolen, die Namen für jeden Slot (Argument oder lokale Variable) geben.
slotflagsEin
UInt8-Array von Slot-Eigenschaften, dargestellt als Bit-Flags:- 0x02 - zugewiesen (nur falsch, wenn es keine Zuweisungsanweisungen mit dieser Variablen auf der linken Seite gibt)
- 0x08 - verwendet (wenn es eine Lese- oder Schreiboperation des Slots gibt)
- 0x10 - statisch einmal zugewiesen
- 0x20 - könnte vor der Zuweisung verwendet werden. Dieses Flag ist nur nach der Typinferenz gültig.
ssavaluetypesEntweder ein Array oder ein
Int.Wenn es sich um ein
Inthandelt, gibt es die Anzahl der vom Compiler eingefügten temporären Speicherorte in der Funktion an (die Länge descode-Arrays). Wenn es sich um ein Array handelt, wird ein Typ für jeden Speicherort angegeben.ssaflagsAussageebene 32-Bit-Flags für jeden Ausdruck in der Funktion. Siehe die Definition von
jl_code_info_tin julia.h für weitere Details.linetableEin Array von Quellstandortobjekten
codelocsEin Array von ganzzahligen Indizes in die
linetable, das den Standort angibt, der mit jeder Anweisung verbunden ist.
Optionale Felder:
slottypesEin Array von Typen für die Slots.
rettypeDer abgeleitete Rückgabetyp der gesenkten Form (IR). Der Standardwert ist
Any.method_for_inference_limit_heuristicsDie
method_for_inference_heuristicswird den Generator der gegebenen Methode bei Bedarf während der Inferenz erweitern.ElternDas
MethodInstance, das dieses Objekt "besitzt" (falls zutreffend).KantenLeiten Sie Kanten zu Methodeninstanzen weiter, die ungültig gemacht werden müssen.
min_world/max_worldDer Bereich der Weltalter, für den dieser Code zum Zeitpunkt seiner Ableitung gültig war.
Boolesche Eigenschaften:
abgeleitetOb es durch Typinferenz erzeugt wurde.
inlineableOb es für das Inlining in Frage kommen sollte.
propagate_inboundsOb es
@inboundspropagieren sollte, wenn es zum Zweck des Auslassens von@boundscheck-Blöcken inlinet wird.
UInt8 Einstellungen:
constprop- 0 = Heuristik verwenden
- 1 = aggressiv
- 2 = keine
purityKonstruiert aus 5 Bit-Flags:- 0x01 << 0 = Diese Methode garantiert, dass sie konsistent zurückgibt oder terminiert (
:consistent) - 0x01 << 1 = Diese Methode ist frei von extern sichtbaren semantischen Nebenwirkungen (
:effect_free) - 0x01 << 2 = Diese Methode garantiert, dass keine Ausnahme ausgelöst wird (
:nothrow) - 0x01 << 3 = Diese Methode garantiert, dass sie terminiert (
:terminates_globally) - 0x01 << 4 = Der syntaktische Kontrollfluss innerhalb dieser Methode ist garantiert, dass er terminiert (
:terminates_locally)
Siehe die Dokumentation von
Base.@assume_effectsfür weitere Details.- 0x01 << 0 = Diese Methode garantiert, dass sie konsistent zurückgibt oder terminiert (