Nota : questa domanda è in qualche modo correlata a In che modo esattamente il bytecode è "analizzato" ?, ma non è un duplicato di esso. In questa domanda, sto chiedendo una parte specifica di come viene generato bytecode, non di come "bytecode" viene "analizzato".
Come indicato nel titolo, in che modo i letterali (come stringhe, numeri interi, ecc.) sono codificati in file bytecode? La mia confusione deriva dal fatto che la rappresentazione in byte di ogni dato letterale è di lunghezza variabile. Ciò significa che una macchina virtuale non avrebbe idea di quanti byte ha bisogno di raccogliere per poter leggere l'intero letterale. Se la mia domanda non è ancora chiara, credo che un esempio visivo aiuterà a illustrare la mia confusione.
Considera questo esempio. Un parser ha appena costruito un albero di sintassi astratto. Ha convertito l'espressione 3 + 2
in:
+
/ \
3 2
Il tuo compilatore / interprete ora inizia a camminare sull'albero. Genera il seguente codice bytec:
PUSH 3 PUSH 2 ADD
| | | | |
|-----| |--------------| |-----| |----------| |-----|
b'\x00' b'\x00\x00\x00\' b'\x00' b'\x00\x00\' b'\x05'
La tua macchina virtuale inizia quindi a leggere nel file bytecode. Legge il primo byte e vede che è l'opcode PUSH. Ora ha bisogno di leggere l'argomento nell'opcode PUSH.
Ma ecco il problema . La macchina virtuale non ha modo di sapere quanti byte ha bisogno di leggere per ottenere l'intero argomento su PUSH. gli argomenti a PUSH sono un numero variabile di byte, quindi la macchina virtuale non sa quanti byte ha bisogno di leggere per ogni argomento. Come visto nello pseudo bytecode di cui sopra, il numero di byte utilizzati per rappresentare valori diversi può variare e non è coerente.
E mentre l'esempio precedente utilizza solo numeri interi, questo può valere anche per altre cose. Ad esempio stringhe o rappresentazioni di stringhe di nomi di identificatori.
Ho provato a cercare su vari blog e persino sulla documentazione ufficiale di qualche codice bytecode, ma non ho ancora trovato una spiegazione su come i letterali siano codificati.
Le informazioni sull'armadio che ho trovato sono state una frase di questa risposta dato da Ratchet Freak alla domanda a cui mi sono collegato nell'intestazione. Si legge:
To give an example that makes the bytes-per-operation very explicit there is SPIR-V. The first 4-byte word of each instruction is constructed as 2-byte length + 2-byte opcode.
Sembra che quello che sta dicendo è che SPIR-V force opcode tutti i loro argomenti da comprimere o espandere per riempire due byte. Mentre suppongo che potrebbe fare questo, sono abbastanza sicuro che questo non è ciò che intendeva.
Qual è la pratica comune quando si codificano valori letterali, le cui rappresentazioni di byte sono di lunghezza variabile, in file bytecode? Naturalmente, presumo che la loro sia una pratica comune, ma forse ogni lingua lo fa in modo diverso?