Este „site-ul de apelare” un cod automat generat de compilator – întâlnesc frecvent acest termen și se pare că metoda de apelare este numită pur și simplu „site-ul de apelare” – care literalmente sună bine, dar cred că are unele complexități mai profunde. Și dacă „site-ul apelului” este cod generat de compilator – în ce circumstanțe este necesar acest lucru?
Deși vorbesc în contextul C # .Net, dar acesta pare a fi o terminologie standard. Aș aprecia orice explicație clară / precisă cu câteva exemple.
Comentarii
- Există o noțiune de site de apel atât în codul sursă, cât și în auto -cod de obiect generat.
- S-ar putea să doriți să căutați cum sunt generate site-urile de apeluri pentru o operație dinamică în C # 4 și mai sus. Sunt destul de interesante.
- @EricLippert Mulțumesc. Din fericire am găsit link unde l-ai descris destul de frumos. Cu toate acestea, nu am găsit niciun blog specificat de dvs. în legătură cu generarea site-ului de apel.
Răspuns
„Apelați site-ul ”Se referă la locul unde se numește o funcție sau o metodă. Este un termen obișnuit în construcția compilatorului și nu este specific pentru C #.
foo(); // call site void foo() { ... } // function definition
Site-ul apelului nu este un cod generat special. Dar la site-ul apelului, compilatorul emite instrucțiuni pentru a apela funcția. De obicei, acestea:
- Salvați contextul actual într-un cadru de stivă.
- Stocați toate argumentele conform convenției de apelare a funcției țintă.
- Apelați funcția țintă, care poate necesita expediere metodă.
- Preluarea valorii returnate conform convenției de apelare.
- Restabiliți contextul din cadrul stivei.
Expedierea metodei poate necesita executarea unui cod complicat pentru a găsi funcția care ar trebui efectiv apelată. Acest lucru este necesar atunci când se apelează metodele virtual
, în special metodele printr-o interfață. Procedura completă de expediere a metodei poate fi destul de costisitoare (adesea O (n) în numărul de interfețe implementate sau O (n) în numărul de metode disponibile). Dar de cele mai multe ori (de obicei 70-90%), un site de apeluri va vedea obiecte de același tip. Apoi, are sens să cache rezultatul căutării metodei. Compilatorul ar putea genera un cod ca acesta la site-ul apelului:
static lastType = null; static lastMethod = null; if (type(instance) != lastType) { lastType = type(instance); lastMethod = performMethodLookup(instance, methodName); } result = lastMethod(instance, args);
Acest lucru este cunoscut sub numele de monomorf cache inline . .NET CLR a dezvoltat o abordare puțin mai complicată numită Virtual Stub Dispatch . În loc să efectueze expedierea la site-ul apelului, runtime-ul JIT-compilează metodele stub. Există diferite butoane pentru efectuarea procedurii complete de expediere a metodei și pentru utilizarea unei metode cache. La site-ul apelului, atunci avem doar un apel către stub, iar stub va redirecționa apelul către ținta reală. În funcție de statisticile pentru acest site de apel, codul mașinii de pe site-ul apelului va fi corecționat pentru a utiliza un alt buton.
Răspuns
Cea mai tipică utilizare a apelului-site este probabil că așa cum este declarat în prezent pe Wikipedia : nu este altceva decât locul dintr-un cod în care un apel către un se realizează funcția sau subrutina. Este un termen complet general care poate fi aplicat la orice fel de limbaje (și cu siguranță nu are nimic de-a face cu programarea dinamică!).
De obicei aud termenul folosit (ca opoziție doar pentru termenul „apel”) pentru a clarifica faptul că se discută despre sintaxa și semantica codului unde se numește o funcție / metodă / subrutină, pentru a se opune semanticii subiacente a apelului sau semanticii la definiția funcției / metodei: în în acest fel, nu este absolut nu despre compilator sau orice cod generat (chiar dacă termenul se va aplica în continuare codului generat de compilator / runtime, așa cum cred că amon a discutat deja), este despre aducerea codului specific care se traduce printr-un apel în context și, uneori, codul din imediata apropiere.
Acesta este genul de imagine pe care o am în cap:
call-site call call-target/method definition --> --> int.TryParse(str, out i); (runtime) public static bool TryPars(...
” Call-site „este un termen util pentru a vorbi despre sintaxa efectuării unui apel și despre semantica care afectează apelantul (detaliat de amon). Luați în considerare, de exemplu, noul modificator in
din C #, un „apel” care trece un argument ca „în” are asociată o anumită semantică (este trecută de ref, posibil după o copie), dar acest lucru nu este „neapărat clar din sintaxa” la site-ul apelului „, unde in
nu este obligatoriu. Ideea este că semantica call-site (adică comportamentul care influențează apelantul / call-site-ul) de a transmite un argument prin referință cu in
suficient pentru cei care trec prin valoare încât nu trebuie să fie dezambiguați de sintaxa la apel-site .Nu sunt de acord cu această afirmație și mi-ar fi greu să o discut fără un termen precum „call-site”!
Un alt exemplu: un apel dinamic (de exemplu, pentru o metodă virtuală / de interfață) are comportamente de rulare complicate (din nou, detaliate de amon) și nu se știe la momentul compilării ce metodă va fi apelată, dar tot ceea ce îi pasă de „site-ul apelului” este semantica expedierii acelui apel: dacă sunteți ToString()
pe un object
, nu îți pasă cu adevărat că este de fapt un string
la site-ul de apel; vă pasă doar că object
expune o metodă virtuală ToString()
(este până la runtime) pentru a stabili ce metodă să apelați efectiv). Într-adevăr, la site-ul apelului (de exemplu, în C #) nu este neapărat clar din sintaxă dacă acesta este un apel virtual: distincția dintre un apel virtual și non-virtual este adesea considerată suficient de lipsită de importanță la apel- site că nu trebuie să fie dezambiguat pentru programator la apel-site (chiar dacă este extrem de important pentru compilator / runtime să efectueze un apel semnificativ)
Un ultim exemplu: luați în considerare C # „s ref
și C ++” s &
: semantica de la site-ul de apel în ambele limba este cam aceeași în ambele limbi: o referință este transmisă mai degrabă decât o valoare, dar fiecare limbă are o sintaxă diferită la site-ul apelului, unde C # necesită ref
, iar C ++ nu necesită &
(sau ceva de genul asta). Din nou, proiectanții de limbă au luat câteva decizii de sintaxă cu privire la modul în care sunt reprezentate apelurile la site-ul de apel, informați de semantica de la site-ul de apel. (Prefer sintaxa C-call-site deoarece expune semantica call-site, pe care cred că, în calitate de programator, ar trebui să o recunosc atunci când am făcut un astfel de apel). Sperăm că este evident că definiția metodei trebuie să știe că primește un parametru prin referință, deoarece schimbă comportamentul modificării acestuia (de exemplu, cu =
). Ați putea susține, totuși, că timpul de execuție nu are grijă (în astfel de limbi tipizate static, în care expedierea timpului de execuție este informată nominal): trebuie doar să obțină această valoare de la apelant la apelant , nu-i pasă dacă este o referință sau nu, aceasta este o preocupare pentru site-ul de apel și țintă de apel.
Mai vag, „call-site” s-ar putea referi la codul care indică un apel, precum și codul „asociat” din jurul acestuia (spre deosebire de doar „apel”). În C #, de exemplu, s-ar putea referi la definirea unei variabile fictive „la” un site de apel, de ex. când se apelează o metodă TryParse
:
int dummy; bool looksLikeAnInt = int.TryParse(str, out dummy);
Tot acest „bloc” ar putea fi considerat parte a site-ului de apelare. Aș considera acest sens mai puțin „precis”, dar asta nu mă oprește să îl folosesc.