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.