A ' hívóhely ' generálja a fordító automatikus kódját?

A “call site” valamilyen automatikus kód, amelyet a fordító generált – gyakran találkozom ezzel a kifejezéssel, és úgy hangzik, hogy a hívási módszert egyszerűen “call site” -nak nevezik – ami szó szerint jól hangzik, de úgy vélem, van benne néhány mélyebb bonyodalom. És ha a “call site” fordító által generált kód – milyen körülmények között van erre szükség?

Bár a C # .Net kontextusában beszélek, de ez szabványos terminológiának tűnik. Nagyra értékelné a világos / pontos magyarázatot néhány példával.

Megjegyzések

  • A hívási webhely fogalma van a forráskódban és az automatikus -generált objektumkód.
  • Érdemes megvizsgálni, hogyan generálódnak a hívási helyek egy dinamikus művelethez a C # 4-ben és a fentiekben. Nagyon érdekesek.
  • @EricLippert Köszönöm. Szerencsére találtam egy linket , ahol nagyon szépen leírta. Nem találtam azonban egyetlen blogot sem, amely részletesen leírta volna a hívás webhelyének létrehozását.

Válasz

“Webhely hívása ”Arra a helyre utal, ahol egy függvényt vagy metódust hívnak meg. Ez egy általános kifejezés a fordító felépítésében, és nem jellemző a C # kifejezésre.

foo(); // call site void foo() { ... } // function definition 

A hívási webhely nem különösebb generált kód. De a hívás helyén a fordító utasításokat ad ki a függvény meghívására. Jellemzően ezek:

  • Mentse az aktuális kontextust egy veremkeretbe.
  • Tárolja az összes argumentumot a célfüggvény hívási konvenciójának megfelelően.
  • Hívja meg a célfüggvényt, amely megkövetelheti a módszer elküldését.
  • A visszahívási érték beolvasása a hívási megállapodás szerint.
  • Állítsa vissza a kontextust a veremkeretről.

A módszer elküldéséhez bonyolult kódra lehet szükség a tényleges meghívandó funkció megtalálásához. Erre akkor van szükség, amikor meghívja az virtual metódusokat, különösen a metódusokat egy interfészen keresztül. A teljes módszer-elküldési eljárás meglehetősen költséges lehet (gyakran O (n) a megvalósított interfészek számában, vagy O (n) a rendelkezésre álló módszerek számában. De legtöbbször (általában 70–90%) egy hívóhely azonos típusú objektumokat fog látni. Ezután van értelme a metóduskeresés eredményének gyorsítótárba helyezését. A fordító ekkor létrehozhat egy ilyen kódot a hívás helyén:

static lastType = null; static lastMethod = null; if (type(instance) != lastType) { lastType = type(instance); lastMethod = performMethodLookup(instance, methodName); } result = lastMethod(instance, args); 

Ez monomorf néven ismert inline gyorsítótár . A .NET CLR egy kissé bonyolultabb megközelítést dolgozott ki Virtuális tönkdiszpécser néven. A futásidejű JIT a hívás helyén történő végrehajtás helyett a csonk módszereket fordítja le. Különböző tennivalók vannak a teljes módszeres diszpécser eljárás végrehajtásához és a gyorsítótárazott módszer használatához. A hívás helyén ekkor csak a csonkra hívunk, és a csonk továbbítja a hívást a tényleges cél felé. Ennek a hívási helynek a statisztikájától függően a hívás helyén lévő gép kódja javításra kerül, hogy egy másik csonkot használjon.

Válasz

A call-site legjellemzőbb használata valószínűleg az, hogy ahogyan azt a Wikipédia jelenleg deklarálja : ez nem más, mint egy kódban az a hely, ahol egy funkció vagy alprogram készül. Ez egy teljesen általános kifejezés, amely mindenféle nyelvre alkalmazható (és semmi köze a dinamikus programozáshoz!).


Általában hallom a kifejezést (ellentétben csak a “hívás” kifejezés) annak egyértelművé tétele érdekében, hogy az egyik a kód szintaxisát és szemantikáját tárgyalja, ahol egy függvényt / metódust / szubrutint hívnak meg, ellentétben a hívás mögöttes szemantikájával, vagy a függvény / módszer definíciójának szemantikájával: így abszolút nem a fordítóról vagy bármelyik generáló kódról van szó (annak ellenére, hogy ez a kifejezés továbbra is érvényes lesz a fordító / futásidejű által generált kódra, amint azt szerintem az amon már tárgyalta), ez arról, hogy a hívást lefordító konkrét kód kontextusba kerül, és néha a közvetlen szomszédságban.

Ez a fajta kép van a fejemben:

 call-site call call-target/method definition --> --> int.TryParse(str, out i); (runtime) public static bool TryPars(... 

A” call-site “hasznos kifejezés a hívás szintaxisáról és a hívót érintő szemantikáról (amon részletezi). Tekintsük például a C # új in módosítóját, egy “hívás”, amely egy argumentumot átad, mint “in”, bizonyos szemantikával van társítva (a ref átadja, esetleg egy példány), de ez “nem feltétlenül törölhető a szintaxisból” a hívás helyén “, ahol a in nem kötelező. Az elképzelés az, hogy az in hivatkozással átadott argumentum hívóhely szemantikája (azaz a hívót / hívó webhelyet befolyásoló viselkedés) közel van elég ahhoz, hogy az érték elhaladjon, ezért ezt nem kell szintaxissal megkülönböztetni a call-site n.Nem értek egyet ezzel az állítással, és “nehezen tudnám ezt megvitatni olyan kifejezés nélkül, mint a” call-site “!

Egy másik példa: egy dinamikus hívás (pl. Virtuális / interfészes módszer esetén) némileg bonyolult futásidejű viselkedések (ismételten amon részletezi), és a fordítás idején nem ismert, hogy melyik módszert hívják meg, de a “call-site” csak a hívás elküldésének szemantikája érdekli: ha ToString() object esetén nem érdekli, hogy valójában string a call-site-on; csak az érdekel, hogy object egy virtuális ToString() metódust tegyen ki (a futásig hogy melyik módszert hívják meg valójában). Valójában a hívóhelyen (pl. C # -ben) a szintaxisból nem feltétlenül derül ki, hogy ez virtuális hívás-e: a virtuális és a nem virtuális hívás megkülönböztetését gyakran eléggé lényegtelennek tekintik a híváskor site hogy ezt nem kell egyértelművé tenni a programozó számára a call-site nél (annak ellenére, hogy a fordító / futásidejű számára létfontosságú, hogy értelmes hívást indítson)

Egy utolsó példa: vegye figyelembe a C # “s ref és a C ++” s &: a call-site szemantikáját mindkettőben a nyelv mindkét nyelven nagyjából megegyezik: referencia kerül átadásra, nem pedig értékre, de mindegyik nyelvnek más a szintaxisa a call-site-on, ahol a C # megköveteli ref és a C ++ nem igényel & (vagy valami hasonló). A nyelvtervezők megint néhány szintaxis-döntést hoztak arról, hogy a hívások hogyan jelennek meg a hívás helyszínén, erről a hívás webhelyének szemantikája tájékoztat. (Inkább a C # call-site szintaxist részesítem előnyben, mert az kiteszi a call-site szemantikát, amelyet véleményem szerint programozónak tudomásul kell vennem, amikor ilyen hívást indítottam). Remélhetőleg nyilvánvaló, hogy a metódusdefiníciónak tudnia kell, hogy egy paramétert referenciaként kap, mert megváltoztatja annak módosításának viselkedését (például = -vel). Vitathatnád azonban, hogy a futásidejű nem “t érdekel (ilyen statikusan tipizált nyelveken, ahol a futási idő-küldés névlegesen tájékoztatott): csak ezt az értéket kell eljuttatnia a hívótól a hívott félig , nem érdekli, hogy hivatkozás-e vagy sem, ez aggasztja a hívóhelyet és a híváscélzást.


Ennél lazábban a „call-site” hivatkozhat a hívást jelző kód, valamint a körülötte levő “társított” kód (szemben csak a “hívással”). Például a C # -ben hivatkozhatunk egy dummy változó definiálására egy “call” webhelyen, pl. TryParse módszer meghívásakor:

int dummy; bool looksLikeAnInt = int.TryParse(str, out dummy); 

Ez az egész “blokk” a hívóhely részének tekinthető. Ezt kevésbé “pontos” jelentésnek tartanám, de ez nem állít meg a használatban.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük