Мы обнаружили серьезную проблему с интерпретацией нашего Javascript-кода, который встречается только на iOS 5/Safari 6 (а затем на нынешнем выпуске iPad), который, по нашему мнению, обусловлен критической ошибкой компилятора Just in Time JS в Safari. (См. обновления ниже для более уязвимых версий и версий, которые теперь содержат исправление).
Мы изначально обнаружили проблему в нашей онлайн-версии демонстрации нашей библиотеки: демоверсии более или менее случайны, но это происходит только во второй раз (или даже позже), что тот же код выполняется. То есть если вы запустите часть кода один раз, все будет работать нормально, однако последующие запускают сбой приложения.
Интересно, что выполнение одного и того же кода в Chrome для iOS не показывает проблему, которая, как мы полагаем, связана с отсутствующими возможностями JIT Webview, которые используются в Chrome для iOS.
После многих попыток мы, наконец, думаем, что нашли хотя бы один проблемный фрагмент кода:
var a = 0; // counter for index
for (var b = this.getStart(); b !== null; b = b.getNext()) // iterate over all cells
b.$f = a++; // assign index to cell and then increment
По сути, это простой цикл, который присваивает каждой ячейке в структуре данных связанного списка свой индекс. Проблема здесь в том, что операция после инкремента в теле цикла. Текущий счетчик присваивается полю и обновляется после вычисления выражения, в основном такой же, как при первом назначении a, а затем увеличивается на единицу.
Это работает ОК во всех проверенных нами браузерах и в Safari в течение первых двух раз, а затем внезапно кажется, что первая переменная счетчика а увеличивается, а затем результат присваивается, как и операция предварительного инкремента.
Я создал скрипку, которая показывает проблему здесь: http://jsfiddle.net/yGuy/L6t5G/
Запуск примера на iPad 2 с iOS 6 и все обновления, результат в порядке для первых двух запусков в моем случае, а в третьем идентификаторе запускается внезапно, последний элемент в списке имеет назначенное значение, которое отключено на один (выход при нажатии кнопки "кликнуть меня" изменяется от "от 0 до 500" до "от 0 до 501" )
Интересно, если вы переключите вкладки или подождите немного, это может случиться, что внезапно результаты верны для двух или более запусков! Кажется, что Safari иногда сбрасывает кеши JIT.
Итак, поскольку я думаю, что команда Safari может занять очень много времени, чтобы исправить эту ошибку (о которой я еще не сообщал), и могут быть другие подобные ошибки, подобные этой, скрывающейся в JIT, которые так же трудно найти, я хотел бы знать, есть ли способ отключить JIT-функциональность в Safari. Конечно, это замедлит наш код (который уже очень интенсивно работает с ЦП), но лучше медленнее, чем сбой.
Обновление:
Неудивительно, что это затронуло не только оператор post increment, но и оператор пост декремента. Менее удивительно и более тревожно то, что не имеет значения, назначено ли значение, поэтому поиска в существующем коде недостаточно. Например. следующий код b.$f = (a++ % 2 == 0) ? 1 : 2;
, где значение переменных не назначено, а просто используется для условия тернарного оператора, также "не удается" в том смысле, что иногда выбирается неправильная ветвь. В настоящее время кажется, что проблему можно избежать, только если почтовые операторы вообще не используются.
Обновление: Эта же проблема не только существует на устройствах iOS, но и также на Mac OSX в Safari 6 и последнем Safari 5: Они были протестированы и обнаружены в результате ошибки: Mac OS 10.7.4, Safari 5.1.7 Mac OS X 10.8.2, WebKit Ночной r132968: Safari 6.0.1 (8536.26.14, 537+). Интересно, что это не кажется затронутым: iPad 2 (Mobile) Safari 5.1.7 и iPad 1 Mobile Safari 5.1. Я сообщил об этих проблемах Apple, но пока не получил ответа.
Обновление: Об ошибке сообщается как ошибка Webkit 109036. Apple все еще не ответила на мой отчет об ошибках, все текущие версии (версии для Safari в феврале 2013 года) на iOS и MacOS по-прежнему подвержены этой проблеме.
Обновление 27 февраля 2013 года: Кажется, что ошибка была зафиксирована командой Webkit здесь! Это была действительно проблема с JIT и пост-операторами! Комментарии указывают на то, что ошибка может быть связана с большим количеством кода, поэтому возможно, что теперь были установлены более загадочные Heisenbugs!
Обновить октябрь 2013 г.: Исправление, наконец, превратило его в производственный код: iOS 7.0.2 по крайней мере на iPad2, похоже, больше не страдает от этой ошибки. Однако я не проверял все промежуточные версии, так как мы долго работали над проблемой.