Desactivación de JIT en Safari 6 para solucionar errores JIT de JavaScript graves
Encontramos un problema grave con la interpretación de nuestro código Javascript que solo ocurre en iOS 5 / Safari 6 (entonces la versión actual de iPad) que creemos que se debe a un error crítico en el compilador Just in Time JS en Safari. (Veractualizaciones a continuación para las versiones más afectadas y las versiones que parecen contener una solución).
Originalmente encontramos el problema en nuestro sitio web.población de nuestra biblioteca: las demostraciones fallan más o menos al azar, pero esto sucede solo la segunda vez (o incluso más tarde) que se ejecuta el mismo código. Es decir. Si ejecuta la parte del código una vez, todo funciona bien, sin embargo, las ejecuciones posteriores bloquean la aplicación.
Interesantemente, al ejecutar el mismo código en Chrome para iOS, el problema no se muestra, lo que creemos que se debe a las capacidades JIT que faltan en la vista web que se usa en Chrome para iOS.
Después de muchos problemas, finalmente creemos que encontramos al menos una pieza problemática de código:
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
En esencia, este es un bucle for simple que asigna su índice a cada celda en una lista de datos vinculados. El problema aquí es la operación de incremento posterior en el cuerpo del bucle. El recuento actual se asigna al campo y se actualiza después de evaluar la expresión, básicamente lo mismo que primero asignando a y luego incrementándolo en uno.
Esto funciona bien en todos los navegadores que probamos y en Safari las primeras veces, y luego, de repente, parece que la variable de contador a se incrementa primero y luego se asigna el resultado, como una operación de preincremento.
He creado un violín que muestra el problema aquí:http://jsfiddle.net/yGuy/L6t5G/
Al ejecutar el ejemplo en un iPad 2 con iOS 6 y todas las actualizaciones, el resultado es correcto para las primeras 2 ejecuciones en mi caso y en la tercera ejecución idéntica, el último elemento de la lista tiene un valor asignado que está desactivado en uno (el resultado cuando hace clic en el botón "haga clic en mí" cambia de "de 0 a 500" a "de 0 a 501")
Curiosamente, si cambia de pestaña o si espera un poco, puede suceder que de repente los resultados sean correctos durante dos o más carreras. Parece como si Safari a veces se restablece en cachés JIT.
Entonces, como creo que el equipo de Safari puede tardar mucho en solucionar este error (que aún no he informado) y puede haber otros errores similares como este que acechan en el JIT que son igualmente difíciles de encontrar, me gustaría saber si hay una manera de deshabilitar la funcionalidad JIT en Safari. Por supuesto, esto ralentizaría nuestro código (que ya requiere mucha CPU), pero es mejor lento que fallar.
Actualizar: Como era de esperar, no solo se ve afectado el operador de incremento posterior, sino también el operador de reducción posterior. Menos sorprendente y más preocupante es que no importa si se asigna el valor, por lo que buscar una asignación en el código existente no es suficiente. P.ej. el siguiente el códigob.$f = (a++ % 2 == 0) ? 1 : 2;
donde el valor de las variables no se asigna, sino que solo se usa para la condición de operador ternario, también "falla" en el sentido de que a veces se elige la rama incorrecta. Actualmente parece que el problema solo puede evitarse si los operadores de correos no se utilizan en absoluto.
Actualizar: El mismo problema no solo existe en dispositivos iOS, sino quetambién en Mac OSX en Safari 6 y en el último Safari 5: se han probado y se han visto afectados por el error: Mac OS 10.7.4, Safari 5.1.7 Mac OS X 10.8.2, WebKit Nightly r132968: Safari 6.0.1 (8536.26. 14, 537+). Curiosamente estos hacenno parece estar afectado: iPad 2 (Mobile) Safari 5.1.7 y iPad 1 Mobile Safari 5.1. He reportado estos problemas a Apple, pero aún no he recibido ninguna respuesta.
Actualizar: El error ha sido reportado como error de Webkit109036. Apple aún no ha respondido a mi informe de errores, todas las versiones actuales de Safari (febrero de 2013) en iOS y MacOS siguen afectadas por el problema.
Actualización 27 de febrero 2013: Parece que el error ha sidofijo por el equipo de Webkitaquí! ¡De hecho fue un problema con el JIT y los post-operadores! Los comentarios indican que el código podría haber afectado más código, por lo que podría ser que los Heisenbugs más misteriosos hayan sido corregidos, ¡ahora!
Actualización octubre 2013: La solución finalmente se convirtió en código de producción: iOS 7.0.2, al menos en iPad2, ya no parece sufrir este error. Sin embargo, no verifiqué todas las versiones intermedias, ya que solucionamos el problema hace mucho tiempo.