“call site” è un codice automatico generato dal compilatore: mi imbatto frequentemente in questo termine e sembra che il metodo di chiamata sia semplicemente indicato come “call site” – che letteralmente suona bene ma credo che abbia alcune complessità più profonde. E se “call site” è un codice generato dal compilatore, in quali circostanze è richiesto?
Anche se sto parlando nel contesto di C # .Net, questa sembra essere una terminologia standard. Apprezzerei qualsiasi spiegazione chiara / precisa con alcuni esempi.
Commenti
- Cè una nozione di sito di chiamata sia nel codice sorgente che nellauto -generated object code.
- Potresti voler esaminare come vengono generati i siti di chiamata per unoperazione dinamica in C # 4 e versioni successive. Sono piuttosto interessanti.
- @EricLippert Grazie. Fortunatamente ho trovato link dove lhai descritto in modo molto bello. Tuttavia, non sono riuscito a trovare alcun tuo blog che descriva specificamente la generazione del sito di chiamata.
Rispondi
“Chiama sito “Si riferisce al luogo in cui viene chiamata una funzione o un metodo. È un termine comune nella costruzione del compilatore e non specifico di C #.
foo(); // call site void foo() { ... } // function definition
Il sito di chiamata non è un codice generato in modo speciale. Ma nel sito della chiamata, il compilatore emette istruzioni per chiamare la funzione. In genere, questi:
- Salva il contesto corrente in uno stack frame.
- Memorizza tutti gli argomenti in base alla convenzione di chiamata della funzione di destinazione.
- Chiama la funzione di destinazione, che potrebbe richiedere linvio del metodo.
- Recupera il valore restituito in base alla convenzione di chiamata.
- Ripristina il contesto dallo stack frame.
Linvio del metodo può richiedere lesecuzione di codice complicato per trovare la funzione che dovrebbe essere effettivamente chiamata. Ciò è necessario quando si chiamano i metodi virtual
, in particolare i metodi tramite uninterfaccia. La procedura di invio del metodo completo può essere piuttosto costosa (spesso O (n) nel numero di interfacce implementate o O (n) nel numero di metodi disponibili). Ma la maggior parte delle volte (in genere il 70–90%), un sito di chiamata vedrà oggetti dello stesso tipo. Ha quindi senso memorizzare nella cache il risultato della ricerca del metodo. Il compilatore potrebbe quindi generare codice come questo nel sito della chiamata:
static lastType = null; static lastMethod = null; if (type(instance) != lastType) { lastType = type(instance); lastMethod = performMethodLookup(instance, methodName); } result = lastMethod(instance, args);
Questo è noto come monomorfo cache in linea . .NET CLR ha sviluppato un approccio leggermente più complicato chiamato Virtual Stub Dispatch . Invece di eseguire linvio al sito della chiamata, il runtime JIT-compila i metodi stub. Esistono diversi stub per eseguire la procedura di invio del metodo completo e per utilizzare un metodo memorizzato nella cache. Nel sito della chiamata, avremo solo una chiamata allo stub e lo stub inoltrerà la chiamata al target effettivo. A seconda delle statistiche per questo sito di chiamata, il codice macchina nel sito di chiamata verrà corretto per utilizzare uno stub diverso.
Rispondi
Lutilizzo più tipico di call-site è probabilmente quello come attualmente dichiarato su Wikipedia : non è altro che il posto in un codice in cui una chiamata a un viene creata una funzione o una subroutine. È un termine completamente generale che può essere applicato a tutti i tipi di linguaggi (e certamente non ha nulla a che fare con la programmazione dinamica!).
Di solito sento il termine usato (in opposizione al solo termine “chiamata”) per chiarire che si sta discutendo la sintassi e la semantica del codice in cui viene chiamata una funzione / metodo / subroutine, in contrasto con la semantica sottostante della chiamata, o la semantica alla definizione di funzione / metodo: in in questo modo, non riguarda assolutamente il compilatore o qualsiasi codice di generazione (anche se il termine si applicherà comunque al codice generato dal compilatore / runtime, come penso che amon abbia già discusso), è sul portare il codice specifico che si traduce in una chiamata nel contesto e talvolta il codice nelle immediate vicinanze.
Questo è il tipo di immagine che ho in testa:
call-site call call-target/method definition --> --> int.TryParse(str, out i); (runtime) public static bool TryPars(...
” call-site “è un termine utile per parlare della sintassi per effettuare una chiamata e della semantica che influenza il chiamante (dettagliata da amon). Considera, ad esempio, il nuovo modificatore in
in C #, una “chiamata” che passa un argomento come “in” ha una certa semantica associata (viene passata da ref, possibilmente dopo una copia), ma questo non è “t necessariamente chiaro dalla sintassi” nel sito della chiamata “, dove in
non è” obbligatorio. Lidea è che la semantica call-site (cioè il comportamento che influenza il chiamante / call-site) di passare un argomento per riferimento con in
sia vicina abbastanza a quelli di passaggio per valore che non ha bisogno di essere disambiguato dalla sintassi nel sito di chiamata .Non sono daccordo con questa affermazione e avrei difficoltà a discuterne senza un termine come “call-site”!
Un altro esempio: una chiamata dinamica (ad es. Per un metodo virtual / interface) ha qualcosa comportamenti di runtime complicati (di nuovo, dettagliati da amon) e non è noto in fase di compilazione quale metodo verrà chiamato, ma tutto ciò che interessa al “sito di chiamata” è la semantica di inviare quella chiamata: se stai chiamando ToString()
su un object
, non ti interessa davvero che sia in realtà un string
nel sito di chiamata; ti interessa solo che object
esponga un metodo ToString()
virtuale (dipende dal runtime per capire quale metodo chiamare effettivamente). Infatti, nel sito della chiamata (ad esempio in C #) non è necessariamente chiaro dalla sintassi se si tratta di una chiamata virtuale: la distinzione tra una chiamata virtuale e non virtuale è spesso considerata abbastanza poco importante alla chiamata- sito che non ha bisogno di essere disambiguato per il programmatore nel sito di chiamata (anche se è di vitale importanza che il compilatore / runtime effettui una chiamata significativa)
Un ultimo esempio: considera C # “s ref
e C ++” s &
: la semantica nel sito di chiamata in entrambi i linguaggi sono più o meno gli stessi in entrambe le lingue: viene passato un riferimento anziché un valore, ma ogni lingua ha una sintassi diversa nel sito di chiamata, dove C # richiede ref
e C ++ no require &
(o qualcosa del genere). Di nuovo, i progettisti del linguaggio hanno preso alcune decisioni sulla sintassi su come le chiamate sono rappresentate nel sito della chiamata, informate dalla semantica nel sito della chiamata. (Preferisco la sintassi call-site C # perché espone la semantica call-site, che credo io come programmatore dovrei riconoscere quando ho effettuato una chiamata del genere). Si spera che sia ovvio che la definizione del metodo deve sapere che sta ricevendo un parametro per riferimento, perché cambia il comportamento di modificarlo (ad esempio con =
). Si potrebbe obiettare, tuttavia, che al runtime non interessa (in tali linguaggi tipizzati staticamente, dove linvio di runtime è nominalmente informato): deve solo ottenere questo valore dal chiamante al chiamato , non importa se si tratta di un riferimento o meno, che è una preoccupazione per il sito di chiamata e il target di chiamata.
Più liberamente, “sito di chiamata” potrebbe riferirsi a il codice che indica una chiamata così come il codice “associato” attorno ad essa (al contrario della sola “chiamata”). In C #, ad esempio, si potrebbe fare riferimento alla definizione di una variabile fittizia “in” un sito di chiamata, ad es. quando si chiama un metodo TryParse
:
int dummy; bool looksLikeAnInt = int.TryParse(str, out dummy);
Questo intero “blocco” potrebbe essere considerato parte del call-site. Lo considero un significato meno “preciso”, ma questo non mi impedisce di usarlo.