Er ' call site ' compiler genereret automatisk kode?

Er “call site” noget automatisk kode genereret af kompilatoren – jeg støder ofte på dette udtryk, og det lyder som om kaldemetode simpelthen kaldes “call site” – hvilket bogstaveligt talt lyder fint, men jeg tror, det har nogle dybere indviklinger. Og hvis “call site” er en compilergenereret kode – under hvilke omstændigheder kræves dette?

Selvom jeg taler i sammenhæng med C # .Net, men det ser ud til at være standardterminologi. Vil sætte pris på enhver klar / præcis forklaring med nogle eksempler.

Kommentarer

  • Der er en opfattelse af kaldeside både i kildekoden og i auto -genereret objektkode.
  • Det kan være en god idé at undersøge, hvordan opkaldssider genereres til en dynamisk handling i C # 4 og derover. De er ret interessante.
  • @EricLippert Tak. Heldigvis fandt jeg link , hvor du beskrev det ganske smukt. Jeg kunne dog ikke finde nogen blog, som du specifikt beskriver omkring generering af opkaldssite.

Svar

“Ring til websted ”Henviser til det sted, hvor en funktion eller metode kaldes. Det er et almindeligt udtryk i kompilerkonstruktion og ikke specifikt for C #.

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

Opkaldssiden er ikke nogen specielt genereret kode. Men på opkaldsstedet udsender compileren instruktioner om at ringe til funktionen. Typisk disse:

  • Gem den aktuelle kontekst i en stakramme.
  • Gem alle argumenter i henhold til målfunktionens opkaldskonvention.
  • Ring til målfunktionen, som muligvis kræver metoden forsendelse.
  • Hent returværdien i henhold til opkaldskonventionen.
  • Gendan konteksten fra stakrammen.

Metodeforsendelse kan kræve kompliceret kode for at køre for at finde den funktion, der rent faktisk skal kaldes. Dette er nødvendigt, når du kalder virtual metoder, især metoder via en grænseflade. Den komplette metodeudsendelsesprocedure kan være ret dyr (ofte O (n) i antallet af implementerede grænseflader eller O (n) i antallet af tilgængelige metoder). Men det meste af tiden (typisk 70–90%) vil et opkaldssted se objekter af samme type. Det giver mening at cache resultatet af metoden opslag. Compileren kan derefter generere kode som denne på opkaldsstedet:

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

Dette er kendt som en monomorf indbygget cache . .NET CLR udviklede en lidt mere kompliceret tilgang kaldet Virtual Stub Dispatch . I stedet for at sende forsendelsen på opkaldsstedet kompilerer runtime JIT-stubmetoder. Der er forskellige stubber til at udføre den fulde metode afsendelsesprocedure og til at bruge en cache-metode. På opkaldsstedet har vi kun et opkald til stubben, og stubben videresender opkaldet til det aktuelle mål. Afhængigt af statistikken for dette opkaldsside patches maskinkoden på opkaldsstedet for at bruge en anden stub.

Svar

Den mest typiske brug af call-site er sandsynligvis, at som i øjeblikket erklæret på Wikipedia : det er intet andet end stedet i en kode, hvor et opkald til en funktion eller subrutine foretages. Det er et helt generelt udtryk, der kan anvendes på alle sprog (og bestemt intet at gøre med dynamisk programmering!).


Jeg hører normalt det anvendte udtryk (som modsætning til udtryk “kald”) for at gøre det klart, at man diskuterer kodenes syntaks og semantik, hvor en funktion / metode / subrutine kaldes, i modsætning til den underliggende semantik i opkaldet eller semantikken ved definition af funktion / metode: i på denne måde handler det absolut ikke om compileren eller nogen genereringskode (selvom udtrykket stadig gælder for den kode, der genereres af compileren / runtime, som jeg tror amon allerede har diskuteret), er det om at bringe den specifikke kode, der oversættes til et opkald i kontekst, og undertiden koden i umiddelbar nærhed.

Dette er den slags billede, jeg har i mit hoved:

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

” Call-site “er et nyttigt udtryk for at tale om syntaksen for at foretage et opkald og semantikken, der påvirker den, der ringer op (detaljeret af amon). Overvej for eksempel den nye in -modifikator i C #, et “opkald”, der sender et argument som “in”, har visse semantik tilknyttet (det sendes af ref, muligvis efter en kopi), men dette er ikke nødvendigvis klart fra syntaksen “på opkaldsstedet”, hvor in ikke er obligatorisk. Tanken er, at semantikken på call-site (dvs. den adfærd, der påvirker den, der ringer op / call-site) for at sende et argument med reference med in er tæt på nok til dem, der passerer værdi, at det ikke behøver at være entydigt ved syntaks på opkaldsstedet .Jeg er uenig i dette krav, og jeg ville have svært ved at diskutere det uden et udtryk som “call-site”!

Et andet eksempel: et dynamisk opkald (f.eks. Til en virtuel / interface-metode) har noget kompliceret runtime-adfærd (igen, detaljeret af amon), og det vides ikke på kompileringstidspunktet, hvilken metode der kaldes, men alt det “call-site” bryr sig om er semantikken ved at sende det opkald: hvis du ringer til ToString() på en object, bryder du dig ikke virkelig om at det faktisk er en string på call-site; du er kun opmærksom på, at object udsætter en virtuel ToString() -metode (det er op til runtime for at finde ud af, hvilken metode man rent faktisk skal ringe til). Faktisk er det på opkaldsstedet (f.eks. I C #) ikke nødvendigvis klart af syntaksen, om dette er et virtuelt opkald: sondringen mellem et virtuelt og ikke-virtuelt opkald betragtes ofte som uvigtig nok ved opkaldet- site at det ikke behøver at være entydigt for programmøren på call-site (selvom det er meget vigtigt for compileren / runtime at foretage et meningsfuldt opkald)

Et sidste eksempel: overvej C # “s ref og C ++” s &: semantikken på opkaldsstedet i begge sprog er næsten det samme på begge sprog: en reference sendes snarere end en værdi, men hvert sprog har forskellige syntaks på opkaldsstedet, hvor C # kræver ref og C ++ ikke kræve & (eller noget lignende). Igen har sprogdesignerne taget nogle syntaksbeslutninger om, hvordan opkald repræsenteres på opkaldsstedet, informeret af semantikken på opkaldsstedet. (Jeg foretrækker C # call-site syntaks, fordi den afslører call-site semantikken, som jeg mener, at jeg som programmør skulle være nødt til at anerkende, da jeg foretog et sådant opkald). Det er forhåbentlig indlysende, at metodedefinitionen skal vide, at den modtager en parameter som reference, fordi den ændrer adfærd for at ændre den (f.eks. Med =). Du kan dog hævde, at runtime ikke bekymrer sig (på sådanne statisk typede sprog, hvor runtime-forsendelse er nominelt informeret): det skal bare få denne værdi fra den, der ringer til callee , det er ligeglad med, om det er en reference eller ej, der er en bekymring for call-site og call-target.


Mere løst henviser “call-site” muligvis til koden, der angiver et opkald såvel som den “tilknyttede” kode omkring det (i modsætning til bare “opkaldet”). I C # kan man for eksempel henvise til at definere en dummy-variabel “ved” et opkaldssted, f.eks. når du kalder en TryParse metode:

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

Hele denne “blok” kan betragtes som en del af call-site. Jeg ville betragte dette som en mindre “præcis” betydning, men det forhindrer mig ikke i at bruge det.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *