Sto facendo un sondaggio di funzionalità in preparazione per un progetto di ricerca.Lingue e macchine virtuali: funzionalità difficili da ottimizzare e perché
Denominare una lingua o una lingua tradizionale che è difficile da ottimizzare, e perché la funzione è o non vale il prezzo pagato, o, invece, solo ridimensionare le mie teorie di seguito con prove aneddotiche. Prima che qualcuno segnali questo come soggettivo, sto chiedendo esempi specifici di lingue o funzionalità e idee per l'ottimizzazione di queste funzionalità o caratteristiche importanti che non ho considerato. Inoltre, ogni riferimento a implementazioni che dimostrino le mie teorie giuste o sbagliate.
superiore sulla mia lista di difficile da ottimizzare le caratteristiche e le mie teorie (alcune delle mie teorie sono testati e sono basate su esperimenti di pensiero):
1) Runtime overloading dei metodi (aka multi-metodo di spedizione o la firma spedizione base). È difficile ottimizzare se combinato con funzionalità che consentono la ricompilazione o l'aggiunta di un metodo. O è solo difficile, comunque? Chiamare il caching del sito è una ottimizzazione comune per molti sistemi runtime, ma i multi-metodi aggiungono complessità aggiuntiva e rendono meno pratico i metodi in linea.
2) Tipo morphing/varianti tipizzazione basato (aka valore al contrario di variabile in funzione) ottimizzazioni tradizionali semplicemente non può essere applicato quando non si sa se il tipo di someting può cambiare in un blocco di base. Combinato con multi-metodi, l'inlining deve essere fatto con attenzione se non del tutto, e probabilmente solo per una data soglia di dimensione del callee. vale a dire. è facile prendere in considerazione la creazione di fasci di proprietà semplici (getter/setter), ma l'integrazione di metodi complessi può causare un aumento di codice. L'altro problema è che non posso semplicemente assegnare una variante a un registro e JIT alle istruzioni native perché devo portare in giro le informazioni sul tipo, o ogni variabile ha bisogno di 2 registri invece di 1. Su IA-32 questo è scomodo, anche se migliorato con i registri extra di x64. Questa è probabilmente la mia caratteristica preferita dei linguaggi dinamici, in quanto semplifica moltissime cose dal punto di vista del programmatore.
3) continuazioni di prima classe - Ci sono diversi modi per la loro attuazione, e mi hanno fatto in entrambi gli approcci più comuni, uno è la copia dello stack e l'altro come attuare il runtime di utilizzare lo stile continuazione di passaggio, pile di cactus, cornici stack copy-on-write e garbage collection. Le continuazioni di prima classe hanno problemi di gestione delle risorse, es. dobbiamo salvare tutto, nel caso in cui la continuazione sia ripresa, e non sono a conoscenza se alcune lingue supportano il fatto di lasciare una continuazione con "intento" (cioè. "Non tornerò qui, quindi puoi scartare questa copia del mondo"). Avendo programmato nel modello di threading e nel modello di contination, so che entrambi possono ottenere la stessa cosa, ma l'eleganza delle continuazioni impone una notevole complessità al runtime e può anche influire sull'efficienza della cache (la localizzazione delle modifiche dello stack più con l'uso di continuazioni e co-routine). L'altro problema è che non si associano all'hardware. Ottimizzare le continuazioni si sta ottimizzando per il caso meno comune e, come sappiamo, il caso comune dovrebbe essere veloce e i casi meno comuni dovrebbero essere corretti.
4) Aritmetica del puntatore e possibilità di mascherare i puntatori (memorizzazione in numeri interi, ecc.) Doveva lanciare questo, ma potrei davvero vivere senza questo abbastanza facilmente.
I miei sentimenti sono che molte delle funzioni di alto livello, in particolare nelle lingue dinamiche , semplicemente non si associano all'hardware. Le implementazioni del microprocessore hanno miliardi di dollari di ricerca dietro le ottimizzazioni sul chip, tuttavia la scelta delle caratteristiche linguistiche può marginalizzare molte di queste caratteristiche (funzionalità come la cache, aliasing top of stack da registrare, parallelismo delle istruzioni, buffer degli indirizzi di ritorno, loop buffer e previsione dei rami).Le macro-applicazioni di micro-funzioni non si espandono necessariamente come piace pensare a qualche sviluppatore, e l'implementazione di molti linguaggi in una VM finisce per mappare le operazioni native in chiamate di funzione (ad esempio, più una lingua è dinamica e più dobbiamo cercare/cache in fase di runtime, nulla può essere assunto, quindi il nostro mix di istruzioni è costituito da una percentuale maggiore di branching non locale rispetto al codice compilato staticamente tradizionale e l'unica cosa che possiamo davvero bene JIT è la valutazione dell'espressione di tipi non dinamici e operazioni su tipi costanti o immediati. A mio parere, le macchine virtuali e i core JIT del codice byte non sono forse sempre giustificati per alcune lingue.
Apprezzo le tue risposte.
Forse dovrebbe essere CW? –