10

我正在使用摩托罗拉 FX9500 RFID 阅读器,它运行带有jamvm 1.5.0 版的 Linux(我只能向其部署应用程序 - 我无法更改 Java VM 或任何东西,因此我的选择受到限制) - 这就是我看到的我检查版本:

[cliuser@FX9500D96335 ~]$ /usr/bin/jamvm -version
java version "1.5.0"
JamVM version 1.5.4
Copyright (C) 2003-2010 Robert Lougher <rob@jamvm.org.uk>

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

我需要编写一个应用程序,因此我获取了 Oracle 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上,然后像这样运行它:

[cliuser@FX9500D96335 ~]$ /usr/bin/jamvm TestApp
-2

哎呀,什么......正如你所看到的 - 它返回不同的结果。

那么,为什么以及谁错了,或者像规范一样不清楚如何处理这个计算(肯定不是)?难道是我需要用不同的编译器编译它?


我为什么要关心这个?

我遇到这种情况的原因是内部发生了完全一样的计算,java.lang.Long.toString并且我的实际应用程序中有一个错误,我正在注销很长一段时间并获得java.lang.ArrayIndexOutOfBoundsException. 因为我想要记录的值很可能在Long.

我想我可以通过检查 Long.MIN_VALUE 和 Long.MAX_VALUE 并记录“错误,我不能告诉你这个数字,但它真的是 Long.XXX,相信我,我会骗你吗?”来解决这个问题。但是当我发现这一点时,我觉得我的应用程序现在是建立在一个坚实的基础上的,它需要非常健壮。我正在认真考虑只是说 JamVM 不能胜任这项工作并用 Python 编写应用程序(因为读者也有 Python 运行时)。

我有点希望有人告诉我我是个笨蛋,我应该像....那样在我的 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

我尝试的另一件事没有任何区别,是将 FX9500 上的 classes.zip 和 glibj.zip 文件复制到 PC,然后像这样进行交叉编译(这一定意味着编译后的文件应该没问题对?):

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

但是生成的 .class 文件在阅读器上运行时会打印相同的消息。

4

3 回答 3

5

我写了 JamVM。正如您可能猜到的那样,这些错误现在已经注意到了,而且 JamVM 甚至无法通过最简单的测试套件(GNU Classpath 有自己的 Mauve,OpenJDK 有 jtreg)。我经常在 ARM(FX9500 使用 PXA270 ARM)和 x86-64 上运行,但各种平台都作为 IcedTea 的一部分进行了测试。

所以我对这里发生了什么一无所知。我猜它只会影响 Java long,因为它们不经常使用,所以大多数程序都可以工作。JamVM 将 Java long 映射到 C long long,所以我的猜测是用于构建 JamVM 的编译器在 32 位 ARM 上为 long long 处理生成了不正确的代码。

不幸的是,如果您无法替换 JVM,那么您无能为力(除了避免多头)。您唯一能做的就是尝试关闭 JIT(一个简单的代码复制 JIT,也就是内联线程)。为此,请在命令行上使用 -Xnoinlining,例如:

jamvm -Xnoinlining ...

于 2013-04-06T01:14:45.833 回答
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;
}

返回8。JamVM 这样做的原因是我无法理解的。

来自 JLS:

15.17.3。余数运算符 %

在二进制数值提升(第 5.6.2 节)之后,整数操作数的余数运算产生一个结果值,使得 (a/b)*b+(a%b) 等于 a。

根据这个 JamVM 打破了语言规范。很坏。

于 2013-04-05T09:13:54.453 回答
2

我会发表评论,但出于某种原因,这需要声誉。

长否定在此设备上不起作用。我不明白它的确切性质,但如果你做两个一元减法,你会回到你开始的地方,例如 x=10; -x==4294967286;-x==10。4294967286 非常接近 Integer.MAX_VALUE*2 (2147483647*2 = 4294967294)。它更接近 Integer.MAX_VALUE*2-10!

它似乎与这一操作无关,并且不会以更基本的方式影响多头。避免在您自己的代码中进行操作很简单,并且通过对引导类路径的一些灵巧滥用可以避免 GNU 类路径代码中的调用,将它们替换为 *-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,这意味着两个设备都有这个 bug。Sirit 比摩托罗拉更友好,并提供固件升级,将在不久的将来推出。我希望摩托罗拉也将修复包括在内,尽管我不知道双方之间安排的细节。

无论哪种方式,我们都在 FX9500 上运行了一个非常大的应用程序,而且长期的否定操作并没有被证明是一个不可逾越的障碍。

祝你好运,丹。

于 2013-09-04T14:33:39.063 回答