Is ' call site ' compiler automatische code gegenereerd?

Is “call site” een automatische code gegenereerd door de compiler – ik kom deze term vaak tegen en het klinkt alsof de aanroepmethode simpelweg wordt aangeduid als “call site” – wat letterlijk goed klinkt, maar ik geloof dat het wat diepere ingewikkeldheden heeft. En als “call site” door de compiler gegenereerde code is – onder welke omstandigheden is dit vereist?

Hoewel ik het heb in de context van C # .Net, maar dit lijkt standaardterminologie te zijn. Zou een duidelijke / nauwkeurige uitleg met enkele voorbeelden op prijs stellen.

Opmerkingen

  • Er is een idee van call-site zowel in de broncode als in de automatische -genereerde objectcode.
  • Misschien wilt u onderzoeken hoe oproepsites worden gegenereerd voor een dynamische bewerking in C # 4 en hoger. Ze zijn best interessant.
  • @EricLippert Bedankt. Gelukkig heb ik een link gevonden waar je het heel mooi hebt beschreven. Ik kon echter geen blog van jou vinden die specifiek over het genereren van oproepsites ging.

Answer

“Call site ”Verwijst naar de plaats waar een functie of methode wordt aangeroepen. Het is een veel voorkomende term in de compilerconstructie en niet specifiek voor C #.

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

De call-site is geen speciaal gegenereerde code. Maar op de call-site zendt de compiler instructies uit om de functie aan te roepen. Meestal zijn dit:

  • Sla de huidige context op in een stapelframe.
  • Sla alle argumenten op volgens de aanroepconventie van de doelfunctie.
  • Roep de doelfunctie aan, waarvoor het verzenden van de methode mogelijk vereist is.
  • Haal de retourwaarde op volgens de aanroepconventie.
  • Herstel de context uit het stapelframe.

Method dispatch kan ingewikkelde code vereisen om uit te voeren om de functie te vinden die eigenlijk aangeroepen zou moeten worden. Dit is nodig bij het aanroepen van virtual methoden, vooral methoden via een interface. De volledige procedure voor het verzenden van methoden kan nogal duur zijn (vaak O (n) in het aantal geïmplementeerde interfaces of O (n) in het aantal beschikbare methoden). Maar meestal (meestal 70-90%) ziet een oproepsite objecten van hetzelfde type. Het is dan logisch om het resultaat van de opzoekmethode in de cache op te slaan. De compiler kan dan de volgende code genereren op de call-site:

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

Dit staat bekend als een monomorf inline cache . De .NET CLR ontwikkelde een iets meer gecompliceerde benadering genaamd Virtual Stub Dispatch . In plaats van de verzending op de call-site uit te voeren, compileert de runtime JIT stub-methoden. Er zijn verschillende stubs voor het uitvoeren van de volledige methode-verzendprocedure en voor het gebruik van een cachemethode. Op de call-site hebben we dan alleen een oproep naar de stub en de stub zal de oproep doorsturen naar het daadwerkelijke doel. Afhankelijk van de statistieken voor deze oproepsite, wordt de machinecode op de oproepsite gepatcht om een andere stub te gebruiken.

Answer

Het meest typische gebruik van call-site is waarschijnlijk dat zoals momenteel verklaard op Wikipedia : het is niets meer dan de plaats in een code waar een oproep naar een functie of subroutine wordt gemaakt. Het is een volledig algemene term die op allerlei talen kan worden toegepast (en zeker niets te maken heeft met dynamisch programmeren!).


Ik hoor de term meestal gebruikt (in tegenstelling tot alleen de term “call”) om duidelijk te maken dat men de syntaxis en semantiek van de code bespreekt waar een functie / methode / subroutine wordt aangeroepen, in tegenstelling tot de onderliggende semantiek van de aanroep, of de semantiek bij functie / methode-definitie: in op deze manier gaat het absoluut niet over de compiler of over het genereren van code (hoewel de term nog steeds van toepassing is op de code die wordt gegenereerd door de compiler / runtime, zoals ik denk dat amon al heeft besproken), is het over het in context brengen van de specifieke code die naar een oproep vertaalt, en soms de code in de directe omgeving.

Dit is het soort foto dat ik in mijn hoofd heb:

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

De” call-site “is een nuttige term om te praten over de syntaxis van het maken van een oproep, en de semantiek die de beller beïnvloedt (gedetailleerd door amon). Beschouw bijvoorbeeld de nieuwe in modifier in C #, een “call” die een argument doorgeeft als “in” heeft een bepaalde semantiek eraan gekoppeld (het wordt doorgegeven door ref, mogelijk na een kopie), maar dit is niet “per se duidelijk uit de syntaxis” op de call-site “, waar in niet” niet verplicht is. Het idee is dat de call-site-semantiek (dwz het gedrag dat de aanroeper / call-site beïnvloedt) van het doorgeven van een argument door middel van verwijzing met in dichtbij zijn genoeg voor degenen die waarde doorgeven dat het niet hoeft te worden ondubbelzinnig door syntaxis op de call-site .Ik ben het niet eens met deze bewering, en ik “zou het moeilijk hebben om erover te praten zonder een term als” call-site “!

Een ander voorbeeld: een dynamische oproep (bijv. Voor een virtuele / interfacemethode) heeft enigszins gecompliceerd runtime-gedrag (nogmaals, gedetailleerd door amon) en het is tijdens het compileren niet bekend welke methode zal worden aangeroepen, maar het enige waar de “call-site” om geeft, is de semantiek van het verzenden van die oproep: als je ToString() op een object, het maakt je niet echt uit dat het eigenlijk een string op de call-site; het kan je alleen schelen dat object een virtuele ToString() methode blootlegt (het is aan de runtime om uit te zoeken welke methode daadwerkelijk moet worden aangeroepen). Op de call-site (bijvoorbeeld in C #) is het inderdaad niet per se duidelijk uit de syntaxis of dit een virtuele call is: het onderscheid tussen een virtuele en niet-virtuele call wordt vaak als onbelangrijk genoeg beschouwd bij de call- site dat het niet voor de programmeur op de call-site gedisambigueerd hoeft te worden (ook al is het van vitaal belang voor de compiler / runtime om een zinvolle call te maken)

Een laatste voorbeeld: overweeg C # “s ref en C ++” s &: de semantiek op de call-site in beide taal zijn vrijwel hetzelfde in beide talen: een verwijzing wordt doorgegeven in plaats van een waarde, maar elke taal heeft een andere syntaxis op de call-site, waarbij C # ref vereist en C ++ niet vereisen & (of iets dergelijks). Nogmaals, de taalontwerpers hebben enkele syntaxisbeslissingen genomen over hoe oproepen worden weergegeven op de oproepsite, geïnformeerd door de semantiek op de oproepsite. (Ik geef de voorkeur aan de C # call-site-syntaxis omdat deze de call-site-semantiek blootlegt, wat ik als programmeur zou moeten erkennen wanneer ik zon oproep deed). Het is hopelijk duidelijk dat de methodedefinitie moet weten dat het een parameter door verwijzing ontvangt, omdat het het gedrag van het wijzigen ervan verandert (bijvoorbeeld met =). Je zou echter kunnen beargumenteren dat het de runtime niet kan schelen (in zulke statisch getypeerde talen, waar runtime-dispatch nominaal geïnformeerd is): het hoeft alleen deze waarde van de beller naar de gebelde te krijgen , het maakt niet uit of het een referentie is of niet, dat is een punt van zorg voor de call-site en call-target.


Losjes kan “call-site” verwijzen naar de code die een oproep aangeeft, evenals de “bijbehorende” code eromheen (in tegenstelling tot alleen de “oproep”). In C # kan men bijvoorbeeld verwijzen naar het definiëren van een dummy-variabele “op” een call-site, b.v. bij het aanroepen van een TryParse -methode:

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

Dit hele “blok” kan worden beschouwd als onderdeel van de call-site. Ik “zou dit een minder” precieze “betekenis vinden, maar dat weerhoudt me er niet van om het te gebruiken.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *