¡Sorpresa! Mozilla puede producir un rendimiento casi nativo en la Web

Publicado el 24 mayo 2013 por Davinci2411
En un intento por hacer que JavaScript funcionar cada vez más rápido, Mozilla ha desarrollado asm.js. Es una simplificada subconjunto limitado de JavaScript que la compañía afirma que ofrecerá el rendimiento que está dentro de un factor de dos de los nativos lo suficientemente bueno para usar el navegador para casi cualquier aplicación. ¿Puede realmente JavaScript empezar a competir con el rendimiento del código nativo? Hemos estado tomando una mirada más cercana.
La búsqueda de JavaScript más rápido
Rendimiento de JavaScript se convirtió en un gran negocio en el año 2008. Antes de esto, los motores de JavaScript que se encuentran en los navegadores web comunes tienden a ser bastante lento. Eran lo suficientemente bueno para la programación básica de que el Web utilizando en el momento, pero era claramente insuficiente para aquellos que quieran utilizar la Web como una plataforma de aplicaciones ricas. En 2008, sin embargo, Google lanzó Chrome con su motor JavaScript V8. Casi al mismo tiempo, Apple sacó Safari 4 con el motor Nitro (Squirrelfish née Extreme). Estos motores trajeron algo nuevo en el mundo de JavaScript: alto rendimiento logra a través de justo a tiempo de compilación (JIT). V8 y nitro convertirían JavaScript en trozos de código ejecutable que la CPU puede ejecutar directamente, mejorando el rendimiento en un factor de tres o más. Mozilla y Microsoft hicieron lo mismo. Mozilla introdujo TraceMonkey en Firefox 3.5 en el 2009 y Microsoft lanzó Chakra en 2011.
Compilación JIT proporcionado grandes oportunidades para acelerar el rendimiento de los programas de JavaScript, pero tiene sus límites. El problema es en sí misma JavaScript. El comportamiento de la lengua hace que sea difícil de optimizar. En lenguajes como C y C + +, el comportamiento de un programa se cuece en el momento de elaborar el programa. Lenguajes como Java y C # agrega un poco más de flexibilidad, pero la mayoría del tiempo que comparten la misma característica. Las funciones y los datos que componen una determinada clase se fijan cuando se compila el programa.
Esto no es cierto de JavaScript. En JavaScript, la forma de un objeto está destinado a comportarse puede cambiar en más o menos cualquier momento. Un motor JIT podría producir código ejecutable para hacer que un objeto se comportan de una manera, y a continuación, ese objeto puede ser modificado para invalidar el código ejecutable. Esto significa que el código ejecutable tiene que ser bastante conservadora para protegerse contra este tipo de modificación. De vez en cuando, los insectos han surgido que causan mal código que se generará.
Los desarrolladores de navegadores son, por lo tanto, en una posición frustrante. Ellos quieren que los motores de secuencias de comandos que son más rápidos para que el navegador para ser utilizado para una amplia gama de aplicaciones, pero sus esfuerzos para mejorar el rendimiento están limitados por sí JavaScript. El lenguaje simplemente no está diseñado para la optimización de alto rendimiento.
Rompiendo los límites de velocidad al cambiar las reglas
Todo esto ha dado lugar a una serie de esfuerzos para cambiar la propia JavaScript. La primera notable es Google Dart. Google Dart es un lenguaje de scripting que se dirige a la misma clase de programas como JavaScript se utiliza actualmente para, con una sintaxis que es ampliamente conocido que los desarrolladores de JavaScript, pero sin muchos de los rasgos que dificultan JavaScript para optimizar.
Ambición original de Google era tener Dart integrado en el navegador, utilizando un motor de Dart-específica cuando estén disponibles o que se traduce en JavaScript cuando no. Google también ha desarrollado Dartium , un tenedor de su navegador de cromo (cromo es la contraparte de código abierto de Chrome) que incluye el motor de Dart. En la práctica, conseguir los desarrolladores Web y el navegador para abrazar un totalmente nuevo lenguaje con un totalmente nuevo motor es una lucha cuesta arriba. JavaScript no va a desaparecer en el corto plazo, por lo que añadir más idiomas, simplemente aumenta la complejidad de los navegadores y de los recursos de desarrollo se extiende más delgadas.
asm.js
Mozilla propone una alternativa. En lugar de utilizar un nuevo lenguaje, Mozilla define un subconjunto estricto de JavaScript que llama asm.js . El subconjunto asm.js de JavaScript es muy limitada. Se evita, por ejemplo, las construcciones orientadas a objetos de JavaScript. Como resultado de ello, sino que también evita muchas de las capacidades difíciles de optimizar la dinámica de JavaScript.
En lugar de utilizar los objetos y clases, programas asm.js manipular una gran matriz que representa la “memoria” de una manera no totalmente diferente a la forma en que los programas de C y C + + manipular la memoria del sistema. Esto no quiere decir que los conceptos tales como objetos y clases no se pueden utilizar. Esto significa que en lugar de que deben ser implementados y utilizados por programas asm.js de la misma manera que C + + compiladores aplican y utilizan. En un programa C + +, un objeto en la memoria se representa típicamente por la dirección de memoria de tabla v de la clase (una tabla de todas las funciones que pertenecen a la clase del objeto) seguido por el almacenamiento de los datos del objeto. Así también en asm.js: la matriz de memoria podría contener, elementos consecutivos, el índice de la matriz de la mesa v y luego los datos del objeto.
asm.js también contiene indicaciones especiales para indicar que se están utilizando los tipos de datos. En JavaScript tradicional, los números pueden comportarse de manera más o menos como números enteros, o más o menos como números de punto flotante. Los cambios de comportamiento en función de las operaciones que se realizan. Por ejemplo, JavaScript le permitirá realizar operaciones a nivel de bits en números de punto flotante por coaccionar a los números enteros en primera. Esta coerción ocurre automáticamente y de manera implícita, lo que significa que los compiladores JIT no se puede asumir con seguridad que un número es de un tipo u otro. asm.js utiliza indicadores explícitos para especificar si los números (y las operaciones sobre los números) deben utilizar el comportamiento entero-como o flotante puntual.
Esta representación es de nivel mucho menor que la encontrada en los programas JavaScript tradicionales, pero tiene una limitación importante: es, sin embargo, todavía JavaScript. La matriz de memoria grande utiliza (relativamente introducido recientemente) de JavaScript Matrices con tipo . Fue creado originalmente para WebGL, pero llegó a estar disponible en todos los navegadores modernos, incluyendo el WebGL-menos Internet Explorer 10. Los indicadores de tipo de número igualmente utilizar construcciones de JavaScript. Por ejemplo, para indicar que un número es un entero, asm.js utiliza “bit a bit o cero” (una operación que obliga JavaScript para coaccionar a entero-como, pero que no cambia el valor del número).
El resultado es que, a diferencia de los programas de dardo que necesitan un motor de dardo o traducción explícita a JavaScript, programas asm.js ya se ejecutan en cualquier navegador. Son programas sólo JavaScript, si bien los programas JavaScript extraños que no se parecen a nada de lo que un humano podría nunca producir.
Menos características significa un mejor rendimiento
Los navegadores que reconocer y contar con el apoyo explícito de asm.js pueden, sin embargo, aprovechar este conocimiento para llevar a cabo una mejor optimización. Un motor que conoce asm.js también sabe que los programas asm.js tienen prohibido el uso de muchas funciones de JavaScript. Como resultado, se puede producir mucho más eficiente código. JIT JavaScript regulares deben tener guardas para detectar este tipo de comportamiento dinámico. ECI asm.js no; asm.js prohíbe este tipo de comportamiento dinámico, por lo que los equipos conjuntos de investigación no tiene que manejar la situación. Este modelo-no simple comportamiento dinámico, hay una asignación de memoria o cancelación de asignación, sólo un pequeño conjunto de enteros y de punto flotante bien definidos operaciones permite mucho mayor optimización.
El hecho de que asm.js no parece JavaScript produciría ningún ser humano puede parecer un problema. Escasos pocos desarrolladores de programas de código nativo usan ensamblador y asm.js es aún más características privó de lenguajes ensambladores más reales. Mozilla no tiene realmente la intención de que los desarrolladores escribir programas asm.js directamente, sin embargo. En cambio, la idea es que los compiladores usan asm.js como el objetivo, con programas propios escritos en otro idioma.
Ese lenguaje es normalmente C o C + +, y el compilador utilizado para producir programas asm.js es otro proyecto de Mozilla: Emscripten. Emscripten es un compilador basado en la infraestructura de compilador LLVM y Clang C / C + + para el usuario. El compilador Clang lee C y el código fuente de C + + y ensamblador produce una salida similar independiente de la plataforma intermedia llamada LLVM representación intermedia. LLVM optimiza el LLVM IR. LLVM IR se alimenta entonces en un generador de código de fondo-la parte que realmente produce código ejecutable. Tradicionalmente, este generador de código emitiría código x86.
Con Emscripten, se utiliza para producir JavaScript.
Emscripten se puede utilizar en dos modos. Puede producir JavaScript regular y que puede producir asm.js JavaScript. En ambos casos, la salida no se puede describir como legible por humanos. Al igual que con asm.js, el JavaScript regulares utiliza el concepto básico de una gran matriz para representar “memoria” con las operaciones realizadas en esa matriz. Fue el éxito de este enfoque que llevó al desarrollo de asm.js: asm.js es un conjunto formal de reglas de cómo este estilo de JavaScript debe estar escrito.
Así que eso es lo que es asm.js. La verdadera pregunta, sin embargo, es qué tan rápido se va? Hemos construido una serie de puntos de referencia comunes usando Emscripten a echar un vistazo.