【问题标题】:JamVM on Motorola FX9500 Problems - what should I do?摩托罗拉 FX9500 上的 JamVM 问题 - 我该怎么办?
【发布时间】:2013-04-05 08:07:28
【问题描述】:

我正在使用Motorola 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 文件在阅读器上运行时会打印相同的消息。

【问题讨论】:

  • +1 表示纺得很好(即问题写得很好,写得很有趣),我想。没有可以尝试的适用于 Windows 的 jamvm 编译器吗?不确定常规的 SDK 编译器是否可以...
  • 谢谢。我找不到 jamvm 编译器 - 我认为它只是一个虚拟机。
  • 您是否尝试使用自定义模数运算。我的意思是 a - (a/b)*b 而不是 a%b。可能在实现上有一些差异。 add 和 neg 操作直接导致问题。

标签: java jamvm


【解决方案1】:

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

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

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

jamvm -Xnoinlining ...

【讨论】:

  • 您的一个 (kmp) cmets 暗示 JamVM 是摩托罗拉随 FX9500 提供的软件的一部分。这是真的?如果是,则无法保证 JamVM 没有被修改和/或黑客攻击。您可以尝试向摩托罗拉询问源代码,当我在 GPL 下发布 JamVM 时必须提供源代码...
  • 非常感谢 - 我对此感到非常惊讶 - 我认为 jamvm 中如此简单的东西中的错误极不可能 - 关于它是如何构建的想法似乎很可能 - 我希望我可以替换我自己,但它完全被锁定,所以我向摩托罗拉寻求帮助
  • 只是为了更新你 - 传递 -Xnoinlining 没有任何区别。
【解决方案2】:

问题在于不同的模数实现:

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 打破了语言规范。非常糟糕。

【讨论】:

  • 嗯,jamvm源码有,可以随时看看。但是我不记得我在使用 jamvm 时遇到过任何问题,但我自己编译了它,并且只针对 x86 目标(不知道摩托罗拉的装置在运行什么)。
  • 我不认为它是模运算符 - 请参阅我对问题的更新
  • 这是一个真正的 WTF!如果 JVM 对原始类型的规范有这样的有线解释,我不明白你将如何将它用于中等规模的项目。
  • 根据 JamVM 网页,它符合 JVM 规范第 2 版(蓝皮书)。也许联系 JamVM 开发人员讨论这个问题?
  • 是的,我现在真的真的很担心这个项目——谁知道我会遇到什么样的疯狂。我真的认为我能做的唯一合理的事情就是完全放弃 Java,并希望它所拥有的 Python 运行时也没有像这样的根本缺陷。我想摩托罗拉不太可能使用更好的 JVM 发布更新(作为设备的用户,我没有权限自己安装不同的 JVM,所以即使它已经在更新的 JamVM 中修复 - 它不会帮助我)。
【解决方案3】:

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

长否定在此设备上不起作用。我不明白它的确切性质,但如果你做两个一元减法,你会回到你开始的地方,例如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 上运行了一个非常大的应用程序,而且长期的否定操作并没有被证明是一个不可逾越的障碍。

祝你好运,丹。

【讨论】:

  • 感谢 Dan - 特别是关于 -Xbootclasspath 的提示。实际上,我们遇到问题的唯一地方是我们正在执行 String.format("%d",x) 并且 x 是任何负数(-1 会这样做) - 然后它会崩溃。我刚刚编写了自己的 String.format 方法,该方法没有在内部将整数转换为长整数,而是使用了它(我们只在编写日志消息时使用过它——幸运的是,应用程序非常简单)。如果我再次使用相同的设备做任何不平凡的事情,我想我会改用 python 解释器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多