Er «call site» noe autokode generert av kompilatoren – jeg kommer ofte over dette begrepet, og det høres ut som om kallemetoden bare blir referert til som «call site» – som bokstavelig talt høres bra ut, men jeg tror det har noen dypere forviklinger. Og hvis «ringeside» er kompilatorgenerert kode – under hvilke omstendigheter er dette nødvendig?
Selv om jeg snakker i sammenheng med C # .Net, men dette ser ut til å være standard terminologi. Vil sette pris på enhver klar / presis forklaring med noen eksempler.
Kommentarer
- Det er en forestilling om anropsside både i kildekoden og i auto -generert objektkode.
- Det kan være lurt å se på hvordan anropssider genereres for en dynamisk operasjon i C # 4 og over. De er ganske interessante.
- @EricLippert Takk. Heldigvis fant jeg lenke der du beskrev det ganske vakkert. Jeg kunne imidlertid ikke finne noen blogg fra deg som spesifikt beskriver generering av anropssider.
Svar
“Ring nettstedet ”Refererer til stedet der en funksjon eller metode kalles. Det er et vanlig begrep innen kompilatorkonstruksjon, og ikke spesifikt for C #.
foo(); // call site void foo() { ... } // function definition
Anropssiden er ikke noen spesiell generert kode. Men på anropssiden sender kompilatoren instruksjoner om å ringe funksjonen. Vanligvis disse:
- Lagre den nåværende konteksten i en stabelramme.
- Lagre alle argumenter i henhold til målfunksjonens anropskonvensjon.
- Ring målfunksjonen, som kan kreve metodeutsending.
- Hent returverdien i henhold til anropskonvensjonen.
- Gjenopprett konteksten fra stabelrammen.
Metodeutsending kan kreve komplisert kode å kjøre for å finne funksjonen som egentlig skal kalles. Dette er nødvendig når du ringer til virtual
metoder, spesielt metoder via et grensesnitt. Den fullstendige fremgangsmåten for utsending av metoden kan være ganske kostbar (ofte O (n) i antall implementerte grensesnitt, eller O (n) i antall tilgjengelige metoder). Men mesteparten av tiden (vanligvis 70–90%) vil et anropsside se objekter av samme type. Det er da fornuftig å cache resultatet av metodens oppslag. Kompilatoren kan da generere kode som denne på anropssiden:
static lastType = null; static lastMethod = null; if (type(instance) != lastType) { lastType = type(instance); lastMethod = performMethodLookup(instance, methodName); } result = lastMethod(instance, args);
Dette er kjent som en monomorf innebygd hurtigbuffer . .NET CLR utviklet en litt mer komplisert tilnærming kalt Virtual Stub Dispatch . I stedet for å gjøre forsendelsen på anropssiden, kompilerer runtime JIT stubmetoder. Det er forskjellige stubber for å utføre fullstendig metode for utsending av metoden og for bruk av en hurtigbufret metode. På anropssiden har vi bare en samtale til stubben, og stubben vil videresende samtalen til det faktiske målet. Avhengig av statistikken for dette anropssiden, vil maskinkoden på anropssiden bli lappet for å bruke en annen stub.
Svar
Den mest typiske bruken av anropssiden er sannsynligvis at som for øyeblikket erklært på Wikipedia : det er ikke noe mer enn stedet i en eller annen kode der en samtale til en funksjon eller subrutine er laget. Det er et helt generelt begrep som kan brukes på alle slags språk (og absolutt ingenting å gjøre med dynamisk programmering!).
Jeg hører vanligvis begrepet brukt (som motsetning til bare begrepet «kall») for å gjøre det klart at man diskuterer syntaksen og semantikken til koden der en funksjon / metode / underrutine kalles, i motsetning til den underliggende semantikken i samtalen, eller semantikken ved definisjon av funksjon / metode: i på denne måten handler det absolutt ikke om kompilatoren eller noen genereringskode (selv om begrepet fremdeles vil gjelde for koden generert av kompilatoren / kjøretiden, som jeg tror amon allerede har diskutert), er det om å bringe den spesifikke koden som oversettes til en samtale i kontekst, og noen ganger koden i umiddelbar nærhet.
Dette er den typen bilder jeg har i hodet:
call-site call call-target/method definition --> --> int.TryParse(str, out i); (runtime) public static bool TryPars(...
» Call-site «er et nyttig begrep for å snakke om syntaksen for å ringe, og semantikken som påvirker den som ringer (detaljert av amon). Tenk for eksempel på den nye in
modifikatoren i C #, et «kall» som sender et argument som «in» har visse semantikk knyttet til seg (det sendes av ref, muligens etter en kopi), men dette er ikke nødvendigvis klart fra syntaksen «på anropssiden», der in
ikke er obligatorisk. Tanken er at semantikk på anropssiden (dvs. atferd som påvirker innringeren / anropssiden) for å sende et argument med referanse med in
er nær nok til de som går forbi verdien, at den ikke trenger å være entydiggjort ved syntaks på anropssiden .Jeg er uenig i dette kravet, og jeg vil ha vanskelig for å diskutere det uten et begrep som «call-site»!
Et annet eksempel: en dynamisk samtale (f.eks. For en virtuell / grensesnittmetode) har noe komplisert atferd i kjøretid (igjen, detaljert av amon), og det er ikke kjent på kompileringstidspunkt hvilken metode som skal kalles, men alt «call-site» bryr seg om er semantikken ved å sende det anropet: hvis du ringer til ToString()
på en object
, bryr du deg ikke virkelig om at det faktisk er en string
på anropssiden; du bryr deg bare om at object
utsetter en virtuell ToString()
-metode (det er opp til kjøretiden for å finne ut hvilken metode du faktisk skal ringe). På anropssiden (f.eks. I C #) er det ikke nødvendigvis klart fra syntaksen om dette er et virtuelt anrop: skillet mellom et virtuelt og ikke-virtuelt anrop blir ofte ansett som uviktig nok ved samtalen – nettsted at det ikke trenger å være entydig for programmereren på anropssiden (selv om det er veldig viktig for kompilatoren / kjøretiden å foreta en meningsfull samtale)
Et siste eksempel: vurder C # «s ref
og C ++» s &
: semantikken på anropsstedet i begge språk er omtrent det samme på begge språk: en referanse sendes i stedet for en verdi, men hvert språk har forskjellig syntaks på anropssiden, der C # krever ref
og C ++ ikke krever &
(eller noe sånt). Igjen har språkdesignerne tatt noen syntaksbeslutninger om hvordan samtaler blir representert på anropssiden, informert av semantikken på anropsstedet. (Jeg foretrekker C # syntaks for anropssiden fordi den avslører semantikken for anropssiden, som jeg mener jeg som programmerer burde måtte erkjenne da jeg ringte et slikt anrop). Det er forhåpentligvis åpenbart at metodedefinisjonen trenger å vite at den mottar en parameter som referanse, fordi den endrer oppførselen til å endre den (f.eks. Med =
). Du kan imidlertid hevde at kjøretiden ikke bryr seg (på slike statisk typede språk, der kjøretidssending er nominelt informert): den må bare få denne verdien fra den som ringer til callee , det bryr seg ikke om det er en referanse eller ikke, det er en bekymring for anropssiden og anropsmålet.
Mer løst kan «anropsside» referere til koden som indikerer en samtale så vel som den «tilknyttede» koden rundt den (i motsetning til bare «samtalen»). I C # kan man for eksempel referere til å definere en dummyvariabel «på» et anropsside, f.eks. når du ringer til en TryParse
metode:
int dummy; bool looksLikeAnInt = int.TryParse(str, out dummy);
Hele denne «blokkeringen» kan betraktes som en del av anropssiden. Jeg anser dette som en mindre «presis» mening, men det hindrer meg ikke i å bruke det.