Domanda

Sto scrivendo il mio linguaggio di scripting in C #, con alcune funzionalità che mi piacciono e ho scelto di utilizzare MSIL come bytecode dell'output (Reflection.Emit è abbastanza utile e non devo pensare a un altro bytecode). Funziona, emette eseguibile, che può essere eseguito (anche decompilato con Reflector :)) ed è abbastanza veloce.

Ma - Voglio eseguire più 'processi' in un processo + un thread e controllare manualmente il tempo assegnato alla CPU (implementare anche un IPC molto più robusto offerto da .NET framework) Esiste un modo per disabilitare completamente JIT e creare la propria macchina virtuale, passo dopo passo istruzioni usando .NET framework (e controllare l'utilizzo della memoria, ecc.), senza bisogno di scrivere nulla per conto mio, o per raggiungere questo obiettivo devo scrivere l'intero interpret MSIL?

EDIT 1): so che interpretare IL non è la cosa più veloce nell'universo :)

EDIT 2): per chiarire - voglio che la mia macchina virtuale sia una sorta di "sistema operativo" - prende un po 'di tempo della CPU e la divide tra processi, controlla l'allocazione della memoria per loro e così via. Non deve essere veloce, né efficace, ma solo una prova di concetto per alcuni dei miei esperimenti. Non ho bisogno di implementarlo a livello di elaborazione di ogni istruzione - se questo dovrebbe essere fatto da .NET, non mi dispiace, voglio solo dire: passo un'istruzione, e attendere fino a quando ti ho detto di passare al passo successivo.

EDIT 3): mi sono reso conto che ICorDebug può forse soddisfare le mie esigenze, ora guardando l'implementazione del runtime di Mono.

È stato utile?

Soluzione

Potresti usare Mono - credo che permetta un'opzione per interpretare l'IL invece di JIT . Il fatto che sia open source significa (soggetto a licenza) che dovresti essere in grado di modificarlo anche in base alle tue esigenze.

Mono non ha tutte le funzionalità di .NET, è vero - ma può fare tutto il necessario.

Altri suggerimenti

Attenzione che MSIL è stato progettato per essere analizzato da un compilatore JIT. Non è molto adatto per un interprete. Un buon esempio è forse l'istruzione ADD. Viene utilizzato per aggiungere un'ampia varietà di valori del tipo di valore: byte, short, int32, int64, ushort, uint32, uint64. Il tuo compilatore sa quale tipo di aggiunta è richiesta ma perderai le informazioni di quel tipo quando generi MSIL.

Ora è necessario trovarlo di nuovo in fase di runtime e ciò richiede il controllo dei tipi di valori nello stack di valutazione. Molto lento.

Un IL facilmente interpretabile ha istruzioni ADD dedicate come ADD8, ADD16, ecc.

L'implementazione di MicroSoft di Common Language Runtime ha un solo sistema di esecuzione, il JIT. Mono, invece, viene fornito con entrambi, un JIT e un interprete.

Tuttavia, non capisco perfettamente cosa esattamente vuoi fare da solo e cosa vorresti lasciare all'implementazione di Microsofts:

  

Esiste un modo per disabilitare completamente JIT e creare la propria VM?

e

  

... senza bisogno di scrivere nulla per conto mio, o per raggiungere questo obiettivo devo scrivere l'intero interpret di MSIL?

è in qualche modo contraddittorio.

Se pensi di poter scrivere un sistema di esecuzione migliore rispetto a microsoft JIT, dovrai scriverlo da zero. Tieni presente, tuttavia, che sia microsoft che monos JIT sono compilatori altamente ottimizzati. (Shootout del linguaggio di programmazione)

Essere in grado di pianificare esattamente il tempo della CPU per i processi del sistema operativo non è possibile dalla modalità utente. Questa è l'attività dei sistemi operativi.

Alcune implementazioni di thread verdi potrebbero essere un'idea, ma questo è sicuramente un argomento per il codice non gestito. Se è quello che vuoi, dai un'occhiata all'API di hosting CLR.

Suggerirei di provare a implementare la tua lingua in CIL. Dopotutto, viene compilato in raw x86. Se non ti interessa la verificabilità, puoi utilizzare i puntatori dove necessario.

Una cosa che potresti considerare di fare è generare codice in uno stile macchina a stati. Lasciami spiegare cosa intendo con questo.

Quando si scrivono metodi generatori in C # con return return, il metodo viene compilato in una classe IEnumerator interna che implementa una macchina a stati. Il codice del metodo viene compilato in blocchi logici che terminano con un'istruzione return return o yield break e ogni blocco corrisponde a uno stato numerato. Poiché ogni rendimento restituito deve fornire un valore, ogni blocco termina memorizzando un valore in un campo locale. L'oggetto enumeratore, al fine di generare il valore successivo, chiama un metodo che consiste in un'istruzione switch gigante sul numero di stato corrente per eseguire il blocco corrente, quindi avanza lo stato e restituisce il valore del campo locale.

Il linguaggio di scripting potrebbe generare i suoi metodi in uno stile simile, in cui un metodo corrisponde a un oggetto macchina a stati e la VM alloca il tempo facendo avanzare la macchina a stati durante il tempo assegnato. Alcune parti difficili di questo metodo: implementare cose come le chiamate al metodo e provare / infine i blocchi sono più difficili della generazione di MSIL semplice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top