2013-04-05 49 views
11

我正在使用一個Motorola FX9500 RFID閱讀器,該閱讀器運行的Linux版本爲jamvm版本1.5.0(我只能部署應用程序 - 我無法更改Java VM或任何其他內容,因此我的選項有限) - 這是我所看到的當我檢查版本:摩托羅拉FX9500上的JamVM問題 - 我該怎麼辦?

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

我需要編寫一個應用程序,所以我抓住了甲骨文的Java SDK 1.5.0並安裝它在我的Windows 7 PC,所以它有這個版本:

C:\>javac -version 
javac 1.5.0 

我在考慮用編譯器編譯的應用程序時會過於理想化嗎?正確地在上述的JamVM上?不管怎樣,在無知壓在我寫這個小應用:

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

與上述javac編譯器編譯它,並在PC上運行它,就像這樣:

C:\>javac TestApp.java 

C:\>java TestApp 
8 

所有罰款那裏。生活是美好的,所以我採取.class文件,並將其放置在FX9500和像這樣運行:

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

伊克,什麼......你可以看到 - 它返回一個不同的結果。

那麼,爲什麼和誰的錯誤或者是這樣的規範是不清楚如何處理這個計算(當然不是)?難道我需要用不同的編譯器編譯它?


我爲什麼關心這個?

我來到這個局面的原因是,計算完全一樣發生內部java.lang.Long.toString和我在實際應用中,其中我退出了漫長而得到一個java.lang.ArrayIndexOutOfBoundsException的錯誤。因爲我想記錄的值很可能在Long的末尾。

我想我可以通過檢查Long.MIN_VALUE和Long.MAX_VALUE並記錄「Err,我不能告訴你這個數字,但它確實是Long.XXX,相信我,我會騙你?」。但是當我發現這一點時,我覺得現在我的應用程序是建立在沙地基礎上的,它需要非常強大。我正在認真考慮只是說JamVM不能勝任這項工作,並用Python編寫應用程序(因爲讀者也有Python運行時)。

我很希望有人告訴我,我是一個dullard,我應該把它編譯到我的Windows PC上,然後才能工作,所以請告訴我(如果它是真的, 當然)!


更新

Noofiz讓我思考(謝謝),我敲了這個額外的測試應用程序:

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

我再次編譯Windows機器上並運行它。

它打印Phew, that was a close one

我的.class文件複製到玩意兒有問題並運行它。

它打印...

...等待...

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

哦,親愛的。我覺得有點虛弱,我想我需要一杯茶......

更新2

一個我嘗試過其他的東西,這並沒有什麼差別,是複製classes.zip和glibj.zip文件從FX9500的PC,然後做一個交叉編譯像這樣(必須意味着編譯後的文件應該是罰款吧?):

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

但由此產生的.class文件,當運行讀者打印相同的信息。

+1

對於一種紡絲良好的紗線(即一個問題很好且有趣的書寫),我認爲是+1。沒有可用於Windows的jamvm編譯器嗎?不知道普通的SDK編譯器是否會這樣做... – 2013-04-05 08:13:26

+0

謝謝。我找不到一個jamvm編譯器 - 我認爲它只是一個虛擬機。 – kmp 2013-04-05 09:00:27

+1

您是否嘗試使用自定義模數操作。我的意思是 - (a/b)* b而不是%b。可能會有一些實施差異。添加和否定操作是直接導致問題。 – Mikhail 2013-04-05 09:00:35

回答

4

我寫了JamVM。正如你可能猜到的那樣,這樣的錯誤現在已經被注意到了,JamVM甚至不會通過最簡單的測試套件(GNU Classpath有自己的稱爲Mauve,而OpenJDK有jtreg)。我經常在ARM上運行(FX9500使用PXA270 ARM)和x86-64,但是各種平臺都是作爲IcedTea的一部分進行測試的。

所以我對這裏發生的事情沒有太多線索。我猜想它只會影響Java多頭,因爲這些很少使用,所以大多數程序都可以工作。 JamVM將Java longs映射爲C long long,所以我的猜測是編譯器用於構建JamVM的是在32位ARM上長時間處理時產生不正確的代碼。

不幸的是,如果你不能替換JVM,那麼你可以做的事情不多(除了避免多餘)。你唯一能做的就是試着關掉JIT(一個簡單的代碼複製JIT,也就是內聯線程)。爲此,請在命令行上使用-Xnoinlining,例如:

jamvm -Xnoinlining ...

+1

您的(kmp)評論之一暗示JamVM是Motorola提供的FX9500軟件的一部分。這是真的?如果是這樣,則不能保證JamVM未被修改和/或黑客入侵。您可以嘗試向摩托羅拉索取源代碼,該代碼必須可用,因爲我在GPL下發布了JamVM ... – user2251099 2013-04-06 02:06:57

+0

非常感謝 - 我對此感到非常驚訝 - 我認爲在jamvm中發生如此簡單的bug是極不可能的 - 關於它如何構建的想法似乎很可能 - 我希望我可以自己更換它,但它完全鎖定,所以我問摩托羅拉尋求幫助 – kmp 2013-04-06 07:36:31

+0

只是爲了更新你 - 傳遞-Xnoinlining沒有任何區別。 – kmp 2013-04-08 07:26:25

4

的問題是在不同的彈性模量的實現:

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

這個代碼返回-2,而這樣的:

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

返回。 JamVM爲什麼這樣做是因爲我理解的原因。

從JLS:

15.17.3。餘運算符%

對於那些經過二進制 數值提升整數的操作數的餘數運算(§5.6.2)產生的結果值,使得 (A/B)* B +(A%B)是等於一個。

據此JamVM打破語言規範。很壞。

+0

好吧,jamvm源代碼可用,可以隨時查看。不過我不記得我有任何與jamvm有關的問題,但我自己編譯了它,並且只針對x86目標(不知道摩托羅拉的裝置運行情況如何)。 – Archie 2013-04-05 09:18:43

+0

我不認爲這是模數運算符 - 請參閱我對該問題的更新 – kmp 2013-04-05 10:31:22

+1

這是一個真正的WTF!如果JVM對原始類型的規範有這樣的有線解釋,我不明白你打算如何將它用於中等規模的項目。 – Mikhail 2013-04-05 10:42:57

2

我會評論,但由於某些原因,需要的聲譽。

長否定在此設備上不起作用。我不明白它的確切性質,但是如果你做了兩個一元化的錯誤,你會回到你開始的地方,例如X = 10; -x == 4294967286; -x == 10。 4294967286非常接近Integer.MAX_VALUE * 2(2147483647 * 2 = 4294967294)。它更接近Integer.MAX_VALUE * 2-10!

它似乎與這一個操作隔離,並且不會以更深層次的基本方式影響多頭。在自己的代碼中避免操作很簡單,而且對bootclasspath的一些錯誤濫用可以避免GNU Classpath代碼中的調用,用* -1s代替它們。如果您需要從設備GUI啓動應用程序,則可以將-Xbootclasspath = ...開關包含到args參數中,以便將其傳遞給JamVM)。

的錯誤實際上是已經固定的後者(比最新發布)JamVM代碼: * https://github.com/ansoncat/jamvm/commit/736c2cb76baf1fedddc1eda5825908f5a0511373 * https://github.com/ansoncat/jamvm/commit/ac83bdc886ac4f6e60d684de1b4d0a5e90f1c489

雖然並不能幫助我們在設備上固定的版本。 Rob Lougher提到這個問題是發佈JamVM新版本的原因,儘管我不知道這是什麼時候,或者摩托羅拉是否足以說服他們更新固件。

FX9500實際上是一個重新包裝的Sirit IN610,這意味着兩個設備共享這個錯誤。 Sirit與摩托羅拉比較友好,並提供固件升級,並將於近期推出。我希望摩托羅拉也會包括這個修復,但我不知道雙方之間的安排細節。無論哪種方式,我們都有一個運行在FX9500上的非常大的應用程序,長期否定操作並未證明是不可逾越的障礙。

祝你好運,丹。

+0

感謝Dan--特別是關於-Xbootclasspath的提示。實際上,我們遇到問題的唯一地方就是我們在做String.format(「%d」,x)的位置,而x是任何負數(-1會這樣做) - 那麼它會崩潰。我只寫了我自己的String.format方法,它沒有內部地將整數轉換成長整型,而是用它來代替(我們在編寫日誌消息時只使用它 - 幸運的是應用程序非常簡單)。如果我曾經使用相同的設備再次使用任何不重要的東西,我想我會使用python解釋器。 – kmp 2013-09-04 17:32:14