Cosa dovrebbe fare esattamente il bytecode JITed?

2

Sto lavorando su una VM (e su un linguaggio di scripting per questo) che ho intenzione di implementare per JITing. Sto solo lavorando al "plumbing" di esso ora, ma non voglio che il compilatore JIT sia un ripensamento. Tuttavia, mentre comprendo i fondamenti di ciò, sono un po 'confuso su cosa dovrebbe fare esattamente il JIT.

Ci sono due modi in cui posso pensare che sia implementato:

  1. Traduci il bytecode in "corretto" x86 proprio come farebbe qualsiasi compilatore, eliminando così la parte interprete / VM.
  2. Traduci il bytecode in x86 che chiama le funzioni VM per dirgli cosa fare eliminando così il passo di decodifica dell'opcode dell'interprete e andando direttamente a chiamare le funzioni interne della VM.

Il primo metodo sarebbe difficile da implementare semplicemente perché richiede conoscenze non solo sulla compilazione di un compilatore completo, ma sulla possibilità di compilare un linguaggio di alto livello che si basa normalmente sulle funzionalità di VM per essere compilato nel codice nativo.

Il secondo metodo sarebbe molto più semplice da implementare visto che non stai compilando il programma, stai solo creando dinamicamente un elenco di chiamate di funzioni C (alla VM interna) con gli operandi corrispondenti con le istruzioni x86 per chiamare il lo stesso ordine che avrebbe altrimenti richiesto a un interprete di "decodificare".

Tuttavia, mentre il secondo sembra chiaramente più sano da implementare, non sono sicuro di quanto (o meno) possa influire sulle prestazioni del programma. In quale direzione dovrei mirare? Qualsiasi pro e contro notevole?

    
posta Famand 25.07.2015 - 13:00
fonte

2 risposte

2

Hai ragione che il metodo 2 non ti darà un enorme incremento di prestazioni su un semplice ciclo di interpreti bytecode. I veri guadagni devono essere fatti usando il metodo 1. Detto questo, il metodo 1 non è così difficile oggigiorno, dato che ci sono biblioteche che possono aiutare.

Un approccio interessante che dovrebbe essere relativamente orientale e potrebbe dare buone prestazioni è usare LLVM per implementare il metodo 2, e usare un compilatore LLVM esistente (es. clang) per compilare le funzioni che stai chiamando al codice LLVM piuttosto che nativo - quindi eseguire i passaggi di ottimizzazione sul risultato, in particolare la funzione call inliner. Questo dovrebbe risultare in un codice nativo ragionevolmente buono, senza complicazioni.

    
risposta data 25.07.2015 - 13:59
fonte
0

Raccomando di utilizzare alcune librerie JIT esistenti, come GCCJIT , libjit , LLVM , asmjit , ... potresti anche considerare di tradurre il tuo bytecode in C, compilare dinamicamente quel codice C in una libreria condivisa in fase di esecuzione e dlopen -ing che plugin ecc ...

Dovrai capire alcune tecniche di compilazione e ottimizzazione per farlo (in particolare perché il tuo bytecode potrebbe essere semanticamente lontano dalle rappresentazioni interne richieste dalla libreria JIT che userai).

    
risposta data 25.07.2015 - 15:06
fonte

Leggi altre domande sui tag