JamVM на Motorola FX9500 Проблемы - что мне делать?
Я использую RFID-считыватель Motorola FX9500, который работает под управлением Linux с jamvm версии 1.5.0 (я могу только развертывать приложения на нем - я не могу изменить виртуальную машину Java или что-то еще, поэтому мои возможности ограничены) - вот что я вижу, когда Я проверяю версию:
[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, поэтому он имеет следующую версию:
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 и запустите на ПК следующим образом:
C:\>javac TestApp.java
C:\>java TestApp
8
Все хорошо там. Жизнь хороша, поэтому я беру это .class
файл и поместите его на FX9500 и запустите его так:
[cliuser@FX9500D96335 ~]$ /usr/bin/jamvm TestApp
-2
Eek, что... как вы можете видеть - это возвращает другой результат.
Итак, почему и кто не прав или это что-то вроде спецификации не ясно, как поступить с этим расчетом (конечно, нет)? Может быть, мне нужно скомпилировать его с другим компилятором?
Почему я забочусь об этом?
Причина, по которой я пришел к этой ситуации, заключается в том, что такой же расчет происходит внутри java.lang.Long.toString
и у меня есть ошибка в моем реальном приложении, когда я долго выхожу из системы и получаю java.lang.ArrayIndexOutOfBoundsException
, Потому что значение, которое я хочу записать, вполне может быть в конце Long
,
Я думаю, что могу обойти это, проверив Long.MIN_VALUE и Long.MAX_VALUE и войдя в систему "Err, я не могу сказать вам номер, но это действительно Long.XXX, поверьте мне, я бы соврал вам?". Но когда я нахожу это, я чувствую, что мое приложение теперь построено на песчаном основании, и оно должно быть действительно надежным. Я серьезно думаю о том, чтобы просто сказать, что JamVM не подходит для работы, и написать приложение на Python (поскольку у читателя также есть среда выполнения Python).
Я отчасти надеюсь, что кто-то скажет мне, что я тупица, и мне следовало скомпилировать его на моем ПК с Windows, как.... и тогда это сработало бы, поэтому, пожалуйста, скажите мне (если это правда, конечно)!
Обновить
Ноофиз заставил меня задуматься (спасибо), и я запустил это дополнительное тестовое приложение:
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 на ПК, а затем выполнить кросс-компиляцию, как это (это должно означать, что скомпилированный файл должен быть в порядке). право?):
javac -source 1.4 -target 1.4 -bootclasspath classes.zip;glibj.zip -extdirs "" TestApp2.java
Но полученный файл.class при запуске на ридере печатает то же сообщение.
3 ответа
Я написал JamVM. Как вы, вероятно, догадались, такие ошибки уже были бы замечены, и JamVM не прошел бы даже с самыми простыми наборами тестов с ними (GNU Classpath имеет свой собственный Mauve, а OpenJDK имеет jtreg). Я регулярно работаю на ARM (FX9500 использует ARM PXA270) и x86-64, но различные платформы тестируются как часть IcedTea.
Так что я понятия не имею, что здесь произошло. Я предполагаю, что это влияет только на длинные позиции Java, так как они используются нечасто и поэтому большинство программ работают. JamVM отображает Java long в C long long, поэтому я предполагаю, что компилятор, использованный для сборки JamVM, генерирует некорректный код для обработки длинных длин на 32-битной ARM.
К сожалению, вы мало что можете сделать (кроме как избежать длинных), если не можете заменить JVM. Единственное, что вы можете сделать, это попытаться отключить JIT (простой JIT с копированием кода, он же inline-threading). Для этого используйте -Xnoinlining в командной строке, например:
jamvm -Xnoinlining...
Проблема в разных реализациях модуля:
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 нарушает спецификацию языка. Очень плохой.
Я бы прокомментировал, но по какой-то причине это требует репутации.
Длинное отрицание не работает на этом устройстве. Я не понимаю его точную природу, но если вы сделаете два унарных минуса, вы вернетесь к тому, с чего начали, например, x=10; -x==4294967286; -x==10. 4294967286 очень близко к Integer.MAX_VALUE*2 (2147483647*2 = 4294967294). Это еще ближе к Integer.MAX_VALUE*2-10!
Кажется, что он изолирован от этой одной операции и не влияет на длинные значения в более фундаментальном смысле. Это просто избежать операции в вашем собственном коде, и при некотором коварном злоупотреблении bootclasspath можно избежать вызовов в коде GNU Classpath, заменив их на *-1s. Если вам нужно запустить приложение из графического интерфейса устройства, вы можете включить параметр -Xbootclasspath=... в параметр args для его передачи в JamVM).
Эта ошибка на самом деле уже исправлена в последнем (кроме последнего выпуска) коде JamVM: * https://github.com/ansoncat/jamvm/commit/736c2cb76baf1fedddc1eda5825908f5a0511373* https://github.com/ansoncat/jamvm/commit/ac83bdc886ac4f6e60d684de1b4d0a5e90f1c489
хотя не помогает нам с фиксированной версией на устройстве. Роб Лугер назвал эту проблему причиной выпуска новой версии JamVM, хотя я не знаю, когда это произойдет, или будет ли Motorola достаточно убеждена, чтобы обновить свою прошивку.
FX9500 на самом деле является переупакованным Sirit IN610, что означает, что оба устройства разделяют эту ошибку. Sirit намного дружелюбнее, чем Motorola, и предлагает обновление прошивки, которое будет доступно в ближайшем будущем. Я надеюсь, что Motorola также внесет исправление, хотя я не знаю деталей соглашения между двумя сторонами.
В любом случае, у нас есть очень большое приложение, работающее на FX9500, и длительная операция отрицания не оказалась непреодолимой преградой.
Удачи тебе, Дэн.