2012-10-14 14 views
7

Diciamo che stai scrivendo un compilatore Java (o sottoinsieme di Java) e vuoi generare bytecode per un'espressione non unaria, !E. Hai passato il controllo di tipo in modo da sapere che è boolean, ad esempio, se si preme un 1 o uno 0 nella pila degli operandi.Generazione di un bytecode JVM per un'espressione non unaria

Un modo per farlo è qualcosa di simile (nella sintassi Jasmin):

E 
ifeq truelabel 
iconst_0 
goto stoplabel 
truelabel: 
iconst_1 
stoplabel: 

cioè se c'è uno 0 sulla spinta pila 1, altrimenti spinta 0. Un altro modo per farlo, approfittando del fatto che un boolean è solo un int con un valore 1 o 0, vale a dire !E = (E + 1) % 2 e generare

E 
iconst_1 
iadd 
iconst_2 
irem 

c'è un vantaggio di utilizzare uno sopra l'altro? O qualcos'altro interamente?

risposta

4

Non conterei sulla seguente definizione per mantenere true a livello di byte.

true == 1 

A livello binario (e la sua quasi indipendente dalla lingua), un valore booleano viene solitamente definita come

false == 0 
true != 0 

Il compilatore javac apparentemente segue anche questa definizione (tutti i controlli in javac bytecode che ho visto solo controlla sempre nuovamente ZERO, mai contro ONE).

Ed senso usare questa definizione per booleana invece solo trattamento 1 come vero, C definisce anche in questo modo (vero è proprio! = 0, non semplicemente 1), in codice assembly questa convenzione è anche comunemente usato. Quindi java, anche utilizzando questa definizione, consente di passare/passare i booleani java ad altri codici senza alcuna conversione speciale.

Sospetto che il tuo primo esempio di codice (con ifeq) sia l'unico modo per implementare correttamente il non operatore per i booleani. Il metodo^1 (xor con 1) fallirà se il valore booleano non è rappresentato in modo strisciante come 0/1. Qualsiasi altro valore int causerebbe un'espressione non corretta.

+0

La specifica JVM dice: "La Java virtual machine codifica i componenti dell'array booleano usando 1 per rappresentare true e 0 per rappresentare false. Dove i valori booleani del linguaggio di programmazione Java sono mappati dai compilatori ai valori del tipo di macchina virtuale Java int, i compilatori devono utilizzare il stessa codifica. " http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.3.4 –

+0

@isbadawi Descrive come la JVM codifica * array * di valori booleani e come i compilatori Java devono codifica booleans come ints * quando e se lo fanno affatto. * Non è immediatamente rilevante per la domanda. – EJP

+0

@EJP Mi sembra un po 'ambiguo. La prima frase riguarda gli array booleani, ma la seconda riguarda i valori booleani. Probabilmente ho sbagliato comunque. –

5

Una volta ho provato a scrivere un decompilatore Java, quindi ero solito sapere quale codice javac ha generato. Come ricordo, javac 1.0.x utilizzava !E = E ? false : true mentre javac 1.1 utilizzava !E = E^1 (bit XOR bit a bit).

+0

Non avevo pensato a '^ 1'; è decisamente meglio del secondo. Conoscete la logica alla base del passaggio dal primo al secondo, o perché "^ 1" non è stato utilizzato in primo luogo? –

+0

In realtà ho appena provato con 'javac 1.6.0_26' e ha generato il primo (eccetto' ifne' invece di 'ifeq'), quindi credo che siano tornati indietro. Immagino che mi stia ancora chiedendo i vantaggi dell'uno contro l'altro. –

+1

Questa è solo una supposizione sfrenata, ma forse hanno spostato questo tipo di micro-ottimizzazioni per il JIT, che probabilmente è il loro posto. – Neil

0

Ho sentito che le operazioni del modulo possono essere molto lente. Non ho una fonte per questo, ma ciò ha senso dato quanto è più semplice aggiungere che dividere. Inoltre, può darsi il caso che saltare il contatore del programma troppo spesso possa essere in discussione, nel qual caso l'approccio if/else non funzionerebbe troppo bene.

Con ciò detto, sospetterei che Neil's E^1 sia il più veloce, ma è solo una sensazione. Tutto quello che devi fare è passare il numero attraverso un circuito logico, e il gioco è fatto! Solo una operazione piuttosto che una manciata.

+0

^1 è decisamente * molto * meno intensivo dal punto di vista computazionale rispetto a div/rem e le ramificazioni condizionali sono anche alquanto costose (poiché possono causare penalità di malversazione del ramo con la maggior parte delle architetture CPU correnti). La domanda più grande è se è valido supporre che int serva per implementare il booleano è strettamente limitato ai valori 0/1. – Durandal

+0

Credo in Java, lo è. In ogni caso, potresti semplicemente fare '(E & 1)^1' se non lo sapessi. –

+0

(& 1)^1 converte da 0x2 a 0x1 (ad esempio). true ==! true non è esattamente ciò che ci si aspetta. Non conosco alcuna espressione semplice per ottenere l'OR logico di tutti i 32 bit di un int per collassare in un singolo bit. Entrambi i booleani sono * rigorosamente * costretti, o il metodo-^ non può essere usato. – Durandal

Problemi correlati