2013-04-05 15 views
11

Sto usando un lettore RFID , che esegue Linux con la versione 1.5.0 jamvm su di esso (posso solo distribuire applicazioni ad esso - Non riesco a cambiare la Java VM o nulla così le mie opzioni sono limitate) - ecco quello che vedo quando controllo la versione:JamVM su Motorola FX9500 Problemi - cosa devo fare?

[[email protected] ~]$ /usr/bin/jamvm -version 
java version "1.5.0" 
JamVM version 1.5.4 
Copyright (C) 2003-2010 Robert Lougher <[email protected]> 

This program is free software; you can redistribute it and/or 
modify it under the terms of the GNU General Public License 
as published by the Free Software Foundation; either version 2, 
or (at your option) any later version. 

This program is distributed in the hope that it will be useful, 
but WITHOUT ANY WARRANTY; without even the implied warranty of 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
GNU General Public License for more details. 

Build information: 

Execution Engine: inline-threaded interpreter with stack-caching 
Compiled with: gcc 4.2.2 

Boot Library Path: /usr/lib/classpath 
Boot Class Path: /usr/local/jamvm/share/jamvm/classes.zip:/usr/share/classpath/glibj.zip 

ho bisogno di scrivere un'applicazione in modo ho afferrato l'Oracle Java SDK 1.5.0 e installato sul mio PC Windows 7, quindi ha questa versione:

C:\>javac -version 
javac 1.5.0 

Sono troppo idealista nel considerare che un'applicazione che compilo con quel compilatore funzionerebbe co rettamente su JamVM di cui sopra? In ogni caso, premendo sul nell'ignoranza scrivo questa piccola applicazione:

public final class TestApp { 
    public static void main(final String[] args) { 
     long p = Long.MIN_VALUE; 
     int o = (int)(-(p + 10) % 10); 
     System.out.println(o); 
    } 
} 

compilarlo con il suddetto compilatore javac e eseguirlo sul PC in questo modo:

C:\>javac TestApp.java 

C:\>java TestApp 
8 

lì tutto bene. La vita è bella, così prendo file .class e posizionarlo sul FX9500 ed eseguirlo in questo modo:

[[email protected] ~]$ /usr/bin/jamvm TestApp 
-2 

Eek, ciò che la ... come si può vedere - restituisce un risultato diverso.

Quindi, perché e chi ha torto o è qualcosa di simile alle specifiche non è chiaro su come gestire questo calcolo (sicuramente no)? Potrebbe essere che ho bisogno di compilarlo con un compilatore diverso?


Perché mi interessa di questo?

Il motivo sono venuto a questa situazione è che un calcolo esattamente come quello che accade dentro java.lang.Long.toString e ho un bug nel mio vero applicazioni dove sto logout un lungo e ottenere un java.lang.ArrayIndexOutOfBoundsException. Poiché il valore che desidero registrare potrebbe essere molto utile alle estremità di un Long.

Penso di poter aggirare il problema controllando Long.MIN_VALUE e Long.MAX_VALUE e registrando "Err, non posso dirvi il numero ma è davvero Long.XXX, credetemi, vorrei mentire a voi ?". Ma quando lo trovo, sento che la mia applicazione si basa su una base sabbiosa e deve essere davvero robusta. Sto seriamente pensando di dire semplicemente che JamVM non è all'altezza del compito e sta scrivendo l'applicazione in Python (dato che il lettore ha anche un runtime Python).

Sto sperando che qualcuno mi dica che sono un idiota e avrei dovuto compilarlo sul mio PC Windows come .... e poi funzionerebbe, quindi per favore dimmi che (se è vero , ovviamente)!


Aggiornamento

Noofiz mi ha fatto pensare (grazie) e ho messo incinta questa applicazione di test aggiuntiva:

public final class TestApp2 { 
    public static void main(final String[] args) { 

     long p = Long.MIN_VALUE + 10; 

     if (p != -9223372036854775798L) { 
      System.out.println("O....M.....G"); 
      return; 
     } 

     p = -p; 

     if (p != 9223372036854775798L) { 
      System.out.println("W....T.....F"); 
      return;    
     } 

     int o = (int)(p % 10); 

     if (o != 8) { 
      System.out.println("EEEEEK"); 
      return; 
     } 

     System.out.println("Phew, that was a close one"); 
    } 
} 

io, ancora una volta, compilo sulla macchina Windows ed eseguirlo.

Esso stampa Phew, that was a close one

ho copiare il file .class per l'aggeggio in questione ed eseguirlo.

Esso stampa ...

... attendere che si ...

W....T.....F

Oh cara. Mi sento un po 'stordita, penso di aver bisogno di una tazza di tè ...

Update 2

Un altra cosa ho provato, che non ha fatto alcuna differenza, è stato quello di copiare il classes.zip e glibj.zip file off del FX9500 al PC e poi fare una croce compilare in questo modo (che deve significare il file compilato dovrebbe andare bene giusto?):

javac -source 1.4 -target 1.4 -bootclasspath classes.zip;glibj.zip -extdirs "" TestApp2.java 

ma il file .class risultante, quando eseguito su il lettore stampa lo stesso messaggio.

+1

+1 per un filato ben filato (vale a dire una domanda ben scritta e divertente), penso. Non c'è un compilatore jamvm per Windows che potresti provare? Non sono sicuro che un normale compilatore SDK lo faccia ... –

+0

Grazie. Non sono riuscito a trovare un compilatore jamvm, penso che sia solo una macchina virtuale. – kmp

+1

Hai provato a utilizzare l'operazione modulo personalizzato. Intendo un - (a/b) * b invece di un% b. Potrebbe esserci qualche differenza nell'implementazione. Le operazioni di aggiunta e negazione sono semplici per causare problemi. – Mikhail

risposta

4

Ho scritto JamVM. Come probabilmente supporresti, tali errori sarebbero stati notati a questo punto, e JamVM non sarebbe riuscito a trasmettere nemmeno la più semplice delle suite di test (GNU Classpath ha il suo nome chiamato Mauve e OpenJDK ha jtreg). Eseguo regolarmente su ARM (l'FX9500 usa un PXA270 ARM) e x86-64, ma varie piattaforme vengono testate come parte di IcedTea.

Quindi non ho idea di cosa sia successo qui. Direi che influisce solo su Java long perché questi sono usati di rado e quindi molti programmi funzionano. JamVM mappa Java long a lunghi C, quindi la mia ipotesi sarebbe che il compilatore usato per compilare JamVM stia producendo codice errato per una gestione a lungo termine su ARM a 32 bit.

Sfortunatamente non c'è molto che si possa fare (a parte evitare i lunghi) se non è possibile sostituire la JVM. L'unica cosa che puoi fare è provare a disattivare il JIT (un semplice JIT che copia il codice, ovvero il threading inline). Per fare ciò usa -Xnoinlining sulla riga di comando, ad es.:

jamvm -Xnoinlining ...

+1

Uno dei tuoi commenti (kmp) implica che JamVM sia parte del software fornito con l'FX9500 da Motorola. È vero?Se lo è, non ci sono garanzie che JamVM non sia stato modificato e/o violato. Potresti provare a chiedere a Motorola la fonte, che deve essere disponibile quando rilascio JamVM sotto GPL ... – user2251099

+0

Grazie mille - Sono così sorpreso da questo - ho pensato che un errore in qualcosa di così semplice in jamvm sarebbe altamente improbabile - l'idea di come è stata costruita sembra verosimile - vorrei poterla sostituire io stessa ma è completamente bloccata, quindi ho chiesto aiuto a motorola – kmp

+0

Solo per aggiornarti - passare -Xnoinlining non fa alcuna differenza. – kmp

4

Il problema è in diverse implementazioni modulo:

public static long mod(long a, long b){ 
    long result = a % b; 
    if (result < 0) 
    { 
     result += b; 
    } 
    return result; 
} 

questo codice restituisce -2, mentre questo:

public static long mod2(long a, long b){ 
    long result = a % b; 
    if (result > 0 && a < 0) 
    { 
     result -= b; 
    } 
    return result; 
} 

rendimenti . I motivi per cui JamVM sta facendo in questo modo sono dietro la mia comprensione.

Da JLS:

15.17.3. Restante Operatore%

L'operazione resto per operandi sono interi dopo binario promozione numerico (§5.6.2) produce un valore tale per cui risultato (a/b) * b + (% B) è uguale a un .

In base a questo JamVM rompe le specifiche della lingua. Molto brutto.

+0

Bene, il codice sorgente di jamvm è disponibile, può sempre dare un'occhiata. Comunque non ricordo di aver avuto problemi di tipo con jamvm, ma l'ho compilato io stesso e solo per il target x86 (non so cosa sia in esecuzione il congegno di Motorola). – Archie

+0

Non penso che sia l'operatore modulo - vedi il mio aggiornamento alla domanda – kmp

+1

Questo è un vero WTF! Se JVM ha un'interpretazione così cablata delle specifiche sui tipi primitivi, non capisco come la userete per progetti di medie dimensioni. – Mikhail

2

avrei commentato, ma per qualche ragione, che richiede la reputazione.

La negazione lunga non funziona su questo dispositivo. Non capisco la sua natura esatta, ma se si eseguono due svantaggi unari si ritorna al punto di partenza, ad es. x = 10; == -x 4294967286; == -x 10. 4294967286 è molto vicino a Integer.MAX_VALUE * 2 (2147483647 * 2 = 4294967294). È ancora più vicino a Integer.MAX_VALUE * 2-10!

Sembra essere isolato per questa operazione e non influisce in modo sostanziale sui long. È semplice evitare l'operazione nel proprio codice e, con un abile abuso del percorso di boot, è possibile evitare le chiamate nel codice GNU Classpath, sostituendole con * -1s. Se è necessario avviare l'applicazione dalla GUI del dispositivo, è possibile includere -Xbootclasspath = ... passare al parametro args affinché venga passato a JamVM).

il bug è in realtà già fissato in quest'ultima (rispetto alla versione più recente) Codice jamvm: * https://github.com/ansoncat/jamvm/commit/736c2cb76baf1fedddc1eda5825908f5a0511373 * https://github.com/ansoncat/jamvm/commit/ac83bdc886ac4f6e60d684de1b4d0a5e90f1c489

anche se non ci aiuta con la versione fissa sul dispositivo. Rob Lougher ha menzionato questo problema come una ragione per rilasciare una nuova versione di JamVM, anche se non so quando questo sarebbe, o se Motorola sarebbe abbastanza convinto di aggiornare il proprio firmware.

L'FX9500 è in realtà un Sirit IN610 riconfezionato, il che significa che entrambi i dispositivi condividono questo bug. Sirit è molto più amichevole di Motorola e sta fornendo un aggiornamento del firmware, per essere disponibile nel prossimo futuro. Spero che Motorola includa anche la correzione, anche se non conosco i dettagli dell'accordo tra le due parti.

In entrambi i casi, abbiamo un'applicazione molto grande in esecuzione su FX9500 e la lunga operazione di negazione non si è dimostrata una barriera invalicabile.

Buona fortuna, Dan.

+0

Grazie Dan - soprattutto per il suggerimento su -Xbootclasspath. In realtà, l'unico posto in cui abbiamo avuto un problema era dove stavamo facendo un String.format ("% d", x) e x era un qualsiasi numero negativo (-1 lo farebbe) - quindi si sarebbe bloccato. Ho appena scritto il mio metodo String.format che non ha convertito internamente interi in long e li ha invece usati (lo abbiamo sempre usato solo scrivendo i messaggi di log - fortunatamente l'applicazione era piuttosto semplice). Se mai userò di nuovo lo stesso dispositivo per qualcosa di non banale, penso che utilizzerei l'interprete python. – kmp

Problemi correlati