Se utilizzati come stack di chiamate, gli stack di spaghetti senza immondizia formano un DAG?


9

Sto esaminando le tecniche di implementazione per i linguaggi di programmazione, e di recente mi sono imbattuto in pile di spaghetti, che presumibilmente si adattano bene a un modello di stile di passaggio di continuazione (dato il loro uso ad esempio in Scheme e SML / NJ ). Per motivi di semplicità, consideriamo solo processi a thread singolo per questa domanda.

Tuttavia, sono un po 'confuso dal diagramma su Wikipedia (trovato anche altrove ). In particolare, non capisco come possa sorgere una situazione del genere. Posso solo immaginare che i rami in grigio sono irraggiungibili e dovrebbero essere raccolti. D'altra parte, con la mia vaga comprensione di come implementare CPS usando stack di spaghetti, non riesco a immaginare come si possa mai fare un giro in quella struttura. Devo concludere che, piuttosto che un "albero genitore-puntatore", è in realtà un grafico aciclico diretto, con tutte le fonti non spazzatura quanti sono i thread e tanti lavandini quanti sono (potenziali) "punti di uscita".

Ma la mia comprensione di questa implementazione è piuttosto vaga, quindi credo che probabilmente mi manchi qualcosa. Spero che qualcuno mi possa illuminare qui su "pile di chiamate spaghetti", con cui intendo la struttura dei dati utilizzata in Scheme e / o SML / NJ per implementare processi basati su CPS.

  1. Dato il seguente stack di chiamate spaghetti:

    [exit point] <-- ... <-- [frame A] <-- [frame B (active)]
                                    ^
                                     `---- [frame C]
    

    Per quanto ho capito, qualsiasi controllo di flusso da B distende lo stack saltando a un genitore (A diventa attivo, B irraggiungibile ora è immondizia) o sostituisce il frame attivo con un sottografo, collegato solo utilizzando riferimenti mantenuti da B o riferimenti ai nuovi frame. L'esecuzione non può fluire al frame C, il che significa che il frame C è immondizia.

  2. Piuttosto che la situazione precedente, penso che potrebbe sorgere la seguente situazione senza immondizia:

    [exit point] <-- ... <-- [frame W] <-- [frame X] <-- [frame Z (active)]
                                    ^                     |
                                     `---- [frame Y] <---´
    

    Ad esempio, posso immaginare che il fotogramma Z appartenga a una funzione di decisione, che continua con il fotogramma X o con il fotogramma Y (che ritornerebbe a W). Ciò significa che le pile di chiamate spaghetti non sono " alberi puntatore padre ".

  3. Tuttavia, non riesco a immaginare alcuna situazione in cui è possibile costruire un loop. Prendi la seguente situazione, ad esempio:

    [exit point] <-- ... <-- [frame P] --> [frame Q (active)]
                                    ^             |
                                    |             v
                                     `---- [frame R]
    

    So che i vincoli ricorsivi sono una cosa, ma dubito fortemente che sia sensato. Se Q dovesse tornare a R, il frame Q viene "speso". Se R dovesse tornare a P, e P non potesse semplicemente tornare a Q, poiché prima avrebbe bisogno di essere reinizializzato. Pertanto, i loop causerebbero stati incoerenti. (A meno che, ovviamente, non fraintenda lo scopo di questa struttura di dati, e useresti solo i nodi in esso come modello per il tuo frame attuale.)

Da queste osservazioni, devo concludere che uno stack di spaghetti (senza immondizia) è in realtà un DAG. È corretto? O sto fraintendendo lo scopo di questa struttura di dati?


aggiornamenti:

  • Ho sfogliato una copia del seguente documento:

    EA Hauck e BA Dent. 1968. Meccanismo stack B6500 / B7500 di Burroughs. In Atti del 30 aprile - 2 maggio 1968, conferenza informativa congiunta di primavera (AFIPS '68 (primavera)). ACM, New York, NY, USA, 245-251. DOI = http://dx.doi.org/10.1145/1468075.1468111

    Questo documento sembra definire il sistema di stack Suguaro. A quanto pare, questo sistema di stack Suguaro è uno stack di chiamate tradizionale che consente a più "lavori" di attraversare i frame di uno stack parzialmente condiviso; non è assolutamente correlato a continuazioni.

  • Il seguente documento (e il suo documento di accompagnamento del 1996) apparentemente spiega cosa sta succedendo nel compilatore SML / NJ:

    Zhong Shao e Andrew W. Appel. 2000. Conversione di chiusura efficiente e sicura per lo spazio. ACM Trans. Programma. Lang. Syst. 22, 1 (gennaio 2000), 129-161. DOI = http://dx.doi.org/10.1145/345099.345125

    Penso che dovrei leggere questo documento ( copia sul sito web dell'autore ) prima di fare qualsiasi altra cosa con questa domanda. Il concetto di "chiusure sicure" è molto simile al sistema di stack Suguaro, in quanto è sempre molto superficiale e destinato solo a condividere variabili libere:

    Il nostro nuovo algoritmo di conversione delle chiusure utilizza chiusure collegate in modo sicuro (la terza colonna nella Figura 1) che contengono solo le variabili effettivamente necessarie nella funzione ma evitano la copia delle chiusure raggruppando le variabili con la stessa durata in un record condivisibile. [...] A differenza delle chiusure collegate, il livello di nidificazione delle chiusure collegate in modo sicuro non supera mai più di due (uno strato per la chiusura stessa; un altro per i record con tempi di vita diversi), quindi godono comunque di tempi di accesso variabili molto rapidi.

    Il documento menziona inoltre esplicitamente che non utilizza "alcuna pila di runtime":

    Invece, trattiamo tutti i record di attivazione come chiusure per le funzioni di continuazione e li allociamo nei registri dell'heap.

    Penso di aver frainteso e / o frainteso l'articolo di Wikipedia, dal momento che le pile di spaghetti non vengono utilizzate per il controllo del flusso. Tuttavia, dopo un'attenta lettura degli articoli di Appel e Shao, potrei forse riaffermare la domanda in riferimento al grafico di dipendenza delle chiusure piuttosto che allo "stack di chiamate" (che apparentemente non è una cosa).


Ben fatto pensando a te stesso e mettendo in discussione le affermazioni in ciò che leggi. Spero che tu abbia una buona risposta, ma sospetto che farai bene anche senza. :) (E non dimenticare di rispondere alla tua domanda se sarai in grado di farlo in futuro!)
Wildcard

Risposte:


2

Gli spaghetti sono pile di alberi genitore-puntatore?

Sì, le pile di spaghetti sono alberi genitore-puntatore. Puoi pensare a uno stack di spaghetti con la stessa struttura di una raccolta di elenchi a collegamento singolo che condividono la struttura. Se vista nel suo insieme, la raccolta di elenchi forma un albero. Ma se visualizzati singolarmente, ogni elenco costituisce uno stack.

Ogni processo nel sistema avrà uno di questi elenchi, che rappresenta il suo stack di controllo. Il capo dell'elenco è in cima allo stack (ovvero, frame attivo). Il nextpuntatore fa riferimento al frame principale.

Quello che vedi nel diagramma è la struttura per più processi. Lo stack per il processo "attivo" è evidenziato. Le parti dell'albero che non fanno parte della pila attiva vengono visualizzate in grigio. Questi rappresentano stack per altri processi.

Le pile di spaghetti formano un DAG?

Dato che le pile di spaghetti sono alberi genitore-puntatore, sono davvero DAG. Ma solo i DAG che sono anche alberi possono essere pile di spaghetti. Quindi no, le pile di spaghetti non formano DAG che non sono alberi.

L'esempio di una funzione decisionale fonde la struttura di uno stack di controllo con i dati memorizzati nello stack. Certamente, qualsiasi struttura potrebbe essere formata se iniziamo a considerare i dati. Ma come una struttura di dati, ogni nodo in una pila di spaghetti avrà esattamente un genitore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.