2012-02-09 10 views
12

Il nostro progetto utilizza una strumentazione bytecode Java. E ci siamo imbattuti in qualche strano comportamento. Supponiamo che il seguente frammento di codice:Differenze nel bytecode java prodotto dai compilatori Oracle ed Eclipse

public void a() { 
    new Integer(2); 
    } 

javac di Oracle compila il sopra in quanto segue bytecode:

0: new #2; //class java/lang/Integer 
    3: dup 
    4: iconst_2 
    5: invokespecial #3; //Method java/lang/Integer."<init>":(I)V 
    8: pop 
    9: return 

e compilatore di Eclipse in:

0: new #15; //class java/lang/Integer 
    3: iconst_2 
    4: invokespecial #17; //Method java/lang/Integer."<init>":(I)V 
    7: return 

Come si può vedere, Oracle compilatore produce "dup" dopo "new", mentre Eclipse no. Il che è assolutamente corretto in questo caso d'uso, poiché l'istanza Integer appena creata non è affatto utilizzata, quindi non è richiesto alcun "dup".

Le mie domande sono:

  1. C'è qualche panoramica delle differenze tra i diversi compilatori? Un articolo/post di blog?
  2. Posso concludere in modo sicuro che se non c'è alcun "dup" tra "nuovo" e "invokespecial", l'oggetto non viene utilizzato dopo l'inizializzazione?
+4

Qual è il tuo obiettivo con lo strumenting del bytecode? Questa differenza ti crea un problema? Nota che non esiste alcuna garanzia su quale codice bytecode produrrà esattamente un compilatore Java.È del tutto possibile che in una versione futura '' javac' di Oracle produrrà qualcosa di diverso da quello che vedi ora - quindi non è una buona idea scrivere un programma che si basa fortemente sul bytecode esatto prodotto dal compilatore. – Jesper

+0

Usi JDK diversi per Eclipse? – Nishant

risposta

3
  1. Posso tranquillamente concludere, che se non c'è un "dup" tra "nuovo" e "invokespecial" allora oggetto non viene utilizzato dopo l'inizializzazione?

non sono sicuro che cosa si intende esattamente , ma un riferimento all'oggetto creato potrebbe essere immagazzinate da qualche parte dal costruttore. Pertanto, il metodo chiamante potrebbe non utilizzare l'oggetto dopo l'inizializzazione, ma l'oggetto potrebbe ancora essere raggiungibile e pertanto potrebbe non essere considerato obsoleto.

6

Se c'è un DUP tra nuovo e invokespecial allora l'oggetto è di solito utilizzato dopo la compilazione. Ad esempio, l'inizializzazione campo è di solito una sequenza di nuovo, dup, invokespecial & putfield. Tuttavia, nel tuo esempio l'ultima istruzione è pop che pulisce l'oggetto da stack dalla pila - questo è come si può supporre che questo oggetto non sia usato.

+0

Come sottolineato da A.H., il pop indica solo che non è utilizzato dal chiamante. L'oggetto stesso potrebbe dare riferimenti a se stesso nel ctor. – Antimony

1

Passando questo riferimento sarà rompere questo schema un po '

public class Bump { 

    Test t; 

    public Bump() { 
     new Test(this); 
    } 
    public void setT(Test t) { 
     this.t = t; 
    } 
    } 

E poi si potrebbe usare questo per memorizzare il risultato di nuovo :)

public class Test { 

    Bump b; 

    public Test(Bump b) { 
     this.b = b; 
     b.setT(this); 
    } 
    } 

Buon divertimento :)