2013-04-05 7 views
11

Ich benutze einen Motorola FX9500 RFID-Leser, der Linux mit der jamvm Version 1.5.0 darauf läuft (ich kann nur Anwendungen bereitstellen - ich kann die Java VM oder irgendetwas nicht ändern, so dass meine Optionen begrenzt sind) - hier ist, was ich sehe wenn ich die Version überprüfen:JamVM auf Motorola FX9500 Probleme - was soll ich tun?

[[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 

ich brauche eine Anwendung zu schreiben, so packte ich die Oracle Java SDK 1.5.0 und installiert es auf meinem Windows 7-PC, so hat es diese Version:

C:\>javac -version 
javac 1.5.0 

Bin ich zu idealistisch, wenn ich bedenke, dass eine Anwendung, die ich mit diesem Compiler kompiliere, zusammen funktionieren würde direkt auf dem oben erwähnten JamVM? Wie dem auch sei, Aufpressen in Unkenntnis schreibe ich diese kleine Anwendung:

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); 
    } 
} 

es Kompilieren mit dem oben genannten javac Compiler und führen Sie es auf dem PC wie folgt:

C:\>javac TestApp.java 

C:\>java TestApp 
8 

Alle es in Ordnung. Das Leben ist gut, so dass ich nehmen, dass .class Datei und legen Sie es auf dem FX9500 und führen Sie es wie folgt:

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

Eek, was die ... wie Sie sehen können - es ein anderes Ergebnis liefert.

Also, warum und wer ist falsch oder ist das etwas wie die Spezifikation ist nicht klar, wie man mit dieser Berechnung (sicherlich nicht) umgehen? Könnte es sein, dass ich es mit einem anderen Compiler kompilieren muss?


Warum kümmere ich mich darum?

Der Grund, warum ich auf diese Situation gekommen ist, dass eine Berechnung genau so innerhalb java.lang.Long.toString passiert und ich habe einen Fehler in meiner realen Anwendung, wo ich ein lange bin abzumelden und ein java.lang.ArrayIndexOutOfBoundsException bekommen. Weil der Wert, den ich protokollieren möchte, sehr gut an den Enden einer 10 liegen kann.

Ich denke, ich kann umgehen, indem Sie nach Long.MIN_VALUE und Long.MAX_VALUE und Protokollierung "Err, ich kann Ihnen nicht die Nummer sagen, aber es ist wirklich Long.XXX, glaub mir, würde ich dich anlügen ? ". Aber wenn ich das finde, habe ich das Gefühl, dass meine Anwendung jetzt auf einer sandigen Grundlage gebaut ist und sehr robust sein muss. Ich überlege ernsthaft, nur zu sagen, dass JamVM dem Job nicht gewachsen ist und die Anwendung in Python geschrieben hat (da der Leser auch eine Python-Laufzeit hat).

Ich hoffe irgendwie, dass jemand mir sagt, ich bin ein Dummkopf und ich hätte es auf meinem Windows-PC wie ... kompiliert und dann würde es funktionieren, also bitte sagen Sie mir, dass (wenn es wahr ist , Na sicher)!


aktualisieren

Noofiz hat mir denken (vielen Dank) und ich schlug diese zusätzliche Testanwendung auf:

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"); 
    } 
} 

ich wieder auf der Maschine von Windows kompilieren und ausführen.

Er druckt Phew, that was a close one

ich die .class Datei auf den Apparat in Frage kopieren und ausführen.

Es druckt ...

... warten, bis es ...

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

lieber Oh. Ich fühle mich ein bisschen benebelt, ich glaube, ich brauche eine Tasse Tee ...

Update 2

Eine andere Sache, die ich versuchte, die keinen Unterschied machte, war die classes.zip zu kopieren und glibj.zip Dateien aus der FX9500 mit dem PC und führen Sie dann ein Kreuz kompilieren wie so (das muss die kompilierte Datei bedeuten sollte in Ordnung sein, oder?):

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

Aber die resultierenden .class-Datei, bei der Ausführung auf Der Leser druckt dieselbe Nachricht.

+1

+1 für ein Garn gut gesponnen (d. H. Eine Frage gut und unterhaltsam geschrieben), denke ich. Gibt es nicht einen Jamvm-Compiler für Windows, den Sie ausprobieren könnten? Nicht sicher, dass ein regulärer SDK-Compiler es tut ... –

+0

Danke. Ich konnte keinen jamvm-Compiler finden - ich denke, es ist nur eine virtuelle Maschine. – kmp

+1

Haben Sie versucht, benutzerdefinierte Modul-Operation zu verwenden? Ich meine a - (a/b) * b anstelle von% b. Möglicherweise gibt es einen Unterschied in der Implementierung. Add- und Neg-Operationen sind geradlinig, um Probleme zu verursachen. – Mikhail

Antwort

4

Ich schrieb JamVM. Wie Sie wahrscheinlich vermuten würden, wären solche Fehler inzwischen bemerkt worden, und JamVM würde nicht einmal die einfachsten Testsuites mit ihnen bestehen (GNU Classpath hat seinen eigenen Namen Mauve und OpenJDK hat jtreg). Ich laufe regelmäßig auf ARM (der FX9500 verwendet einen PXA270 ARM) und x86-64, aber verschiedene Plattformen werden als Teil von IcedTea getestet.

So habe ich nicht viel Ahnung, was hier passiert ist. Ich denke, es betrifft nur Java-Longs, da diese selten verwendet werden und die meisten Programme funktionieren. JamVM ordnet Java-Longs C-Longs zu, so dass ich vermute, dass der Compiler, der zum Erstellen von JamVM verwendet wird, falschen Code für eine lange, lange Verarbeitung auf dem 32-Bit-ARM produziert.

Leider können Sie nicht viel tun (abgesehen von Longs), wenn Sie die JVM nicht ersetzen können. Das einzige, was Sie tun können, ist zu versuchen, den JIT auszuschalten (ein einfacher Code-kopierender JIT, auch Inline-Threading genannt). Verwenden Sie dazu -Xnoinlining in der Befehlszeile, z.:

jamvm -Xnoinlining ...

+1

Einer Ihrer (kmp) Kommentare impliziert, dass JamVM Teil der Software ist, die mit dem FX9500 von Motorola geliefert wird. Ist das wahr?Wenn dies der Fall ist, gibt es keine Garantie dafür, dass JamVM nicht modifiziert und/oder gehackt wurde. Du könntest versuchen, Motorola nach der Quelle zu fragen, die verfügbar sein muss, während ich JamVM unter der GPL veröffentliche ... – user2251099

+0

Vielen Dank - ich bin so überrascht darüber - ich dachte ein Fehler in etwas so einfach in Jamvm wäre höchst unwahrscheinlich - die Idee, wie es gebaut wurde, scheint wahrscheinlich - ich wünschte, ich könnte es selbst ersetzen, aber es ist komplett gesperrt, also frage ich Motorola nach Hilfe – kmp

+0

Nur um Sie zu aktualisieren - Passing -Xnoinlining macht keinen Unterschied. – kmp

4

Das Problem ist in verschiedenen Implementationen Modulus:

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

Dieser Code gibt -2, während dies:

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

kehrt . Gründe, warum JamVM so vorgeht, liegen hinter meinem Verständnis.

Von JLS:

15.17.3. Rest Operator%

Die Restoperation für Operanden, die ganzen Zahlen nach binärer numerischer Förderung sind (§5.6.2) einen Ergebniswert, so dass (a/b) * b + (a% b) gleich a .

Entsprechend bricht JamVM Sprachspezifikation. Sehr schlecht.

+0

Nun, jamvm Quellcode ist verfügbar, kann immer einen Blick darauf werfen. Allerdings kann ich mich nicht erinnern, dass ich irgendwelche Probleme mit jamvm hatte, aber ich habe es selbst zusammengestellt und nur für das x86-Ziel (weiß nicht, was das Motorola-Gerät läuft). – Archie

+0

Ich denke nicht, dass es der Modulo-Operator ist - siehe mein Update auf die Frage – kmp

+1

Das ist ein echter WTF! Wenn JVM eine solche verdrahtete Interpretation von Spezifikationen über primitive Typen hat, verstehe ich nicht, wie Sie es für ein Projekt mittlerer Größe verwenden werden. – Mikhail

2

kommentierte ich hätte, aber aus irgendeinem Grund, der Ruf erfordert.

Lange Negation funktioniert bei diesem Gerät nicht. Ich verstehe seine genaue Natur nicht, aber wenn Sie zwei unäre Minuspunkte machen, kommen Sie zurück, wo Sie angefangen haben, z. x = 10; -x == 4294967286; -x == 10. 4294967286 ist sehr nah an Integer.MAX_VALUE * 2 (2147483647 * 2 = 4294967294). Es ist noch näher an Integer.MAX_VALUE * 2-10!

Es scheint zu dieser einen Operation isoliert zu sein, und beeinflusst Longs nicht in einer weiteren fundamentalen Weise. Es ist einfach, die Operation in Ihrem eigenen Code zu vermeiden, und mit einem gewissenhaften Missbrauch des bootclasspath können Sie die Aufrufe im GNU Classpath-Code vermeiden, indem Sie sie durch * -1s ersetzen. Wenn Sie Ihre Anwendung über die Geräte-GUI starten müssen, können Sie den Parameter -Xbootclasspath = ... in den Parameter args einfügen, damit er an JamVM übergeben wird.

Der Fehler ist behoben tatsächlich bereits in letzterem (als die neueste Version) JamVM Code: * https://github.com/ansoncat/jamvm/commit/736c2cb76baf1fedddc1eda5825908f5a0511373 * https://github.com/ansoncat/jamvm/commit/ac83bdc886ac4f6e60d684de1b4d0a5e90f1c489

wenn auch nicht mit uns auf dem Gerät mit der festen Version hilft. Rob Lougher hat dieses Problem als Grund für die Veröffentlichung einer neuen Version von JamVM erwähnt, obwohl ich nicht weiß, wann dies der Fall sein würde, oder ob Motorola genug überzeugt sein würde, seine Firmware zu aktualisieren.

Der FX9500 ist eigentlich ein neu verpackter Sirit IN610, was bedeutet, dass beide Geräte diesen Fehler teilen. Sirit ist viel freundlicher als Motorola und bietet ein Firmware-Upgrade, um in naher Zukunft verfügbar zu sein. Ich hoffe, dass Motorola den Fix mitbringt, obwohl ich die Details der Vereinbarung zwischen den beiden Parteien nicht kenne.

So oder so, wir haben eine sehr große Anwendung auf dem FX9500, und die lange Negation Operation hat sich nicht als unpassierbare Barriere erwiesen.

Viel Glück, Dan.

+0

Danke Dan - vor allem für den Tipp über -Xbootclasspath. Eigentlich war der einzige Ort, an dem wir ein Problem hatten, wo wir ein String.format ("% d", x) und x eine negative Zahl (-1 würde es tun) - dann würde es abstürzen. Ich habe gerade meine eigene String.format-Methode geschrieben, die Integer nicht intern in Longs umwandelte und diese stattdessen verwendete (wir verwendeten sie nur beim Schreiben von Log-Nachrichten - zum Glück war die Anwendung ziemlich einfach). Wenn ich jemals wieder das gleiche Gerät für alles andere als trivial benutze, würde ich stattdessen den Python-Interpreter verwenden. – kmp

Verwandte Themen