Entendiendo el Engine V8 de JavaScript

¿Qué es y cómo funciona?

Traña Michael
4 min readFeb 29, 2020
JavaScript. ¿Qué es y cómo funciona el Engine?

Hoy por hoy JavaScript es el lenguaje de programación con mayor popularidad entre los desarrolladores. Es común, cada día ver noticias o publicaciones sobre nuevas características en sus framework’s y librerías; o sobre la creación de nuevas herramientas basadas en este lenguaje. Prácticamente está presente en todas las aplicaciones web modernas de la actualidad. Forma parte del stack de desarrollo de grandes empresas de tecnología como Facebook, Google o Microsoft; quienes a su vez promueven constantemente mejoras en las herramientas del lenguaje. Pero, alguna vez te has preguntado ¿cómo se ejecuta el código de JavaScript? De eso se trata el presente post.

Cuando accedemos a una aplicación web desde un navegador, este descarga los archivos .js que contienen el código con las instrucciones a ejecutar. Pero acá tenemos un dilema, las computadoras solo entienden Machine Code o Código Máquina por lo que no podrá ejecutar directamente nuestras instrucciones JavaScript. Entonces, ¿como es que se ejecuta dicho código? ‍🤷‍♂️ Esta es la función del JavaScript Engine. El Engine se encuentra ubicado en el navegador y es el que hace de intermediario para resolver este problema. Cuando el navegador descarga los archivos JavaScript, este interpreta las instrucciones del código y emplea un proceso, en tiempo real, conocido como Just-In-Time Compiler (JIT Compiler) en dónde convierte dicho código en algo que sí puede entender nuestra computadora.

Como es de esperarse, debido a la variedad de navegadores también existe variedad de Engines, siendo los más importantes V8 empleado en Chrome, SpiderMonkey empleado en Mozilla y JavaScriptCore empleado en Safari. Sin embargo, este post se centrará únicamente en el Engine V8 de Chrome, ya que es el de mayor relevancia en la actualidad. A pesar de esto hay que mencionar que el proceso en los engines modernos es muy similar.

Motor V8

V8 es el Engine JavaScript líder en la actualidad, debido a su performance, estabilidad y evolución, siendo empleado en importantes herramientas como Chrome y NodeJS (y más recientemente en Microsoft Edge). Este nace en el año 2008 de la mano de Google y está desarrollado en C++. Con su llegada revoluciona la manera de ejecutar JavaScript, empleando una estrategia que combina un intérprete para transformar el código y un compilador para optimizar el resultado. Esta estrategia permitió que JavaScript se pudiera ejecutar mucho más rápido, algo que posteriormente replicarían los demás motores.

El proceso de compilación

El JavaScript Engine V8 funciona con un pipeline, por el cual pasará nuestro código hasta poder ser ejecutado por el computador. Comienza por hacer una conversión de nuestro código. Convirtiendo las instrucciones de JavaScript en una lista de token’s, que luego el parser o analizador utilizará para producir un Abstract Syntax Tree (AST). Antes de este proceso de análisis nuestras líneas de código se representan como texto que sigue las reglas del lenguaje de programación, pero después de este, dichas instrucciones se transforman en una representación en árbol de la estructura sintáctica de nuestro código. Este AST producido por el analizador servirá como punto de entrada del Interpreter Ignition. El intérprete cumple con dos roles importantes: el primero es generar Bytecode y el segundo es interpretar este Bytecode para poder ejecutarlo.

En el siguiente gráfico podemos apreciar mejor este proceso:

Ignition toma el AST producido por el analizador para generar Bytecode.

Aunque el Bytecode generado por Ignition sí es ejecutable en nuestro computador, aún falta un proceso en el pipeline; la optimización del Bytecode. Y es que V8 cuenta con un compilador llamado TurboFan, que se encargará de este problema. TurboFan es el compilador de optimización más reciente de V8, el cual funciona muy bien con el runtime y también presta su arquitectura para que el interprete pueda realizar su proceso de una mejor manera (por ejemplo, para generar Bytecode Handlers). Pero, su principal tarea es tomar las instrucciones retornadas por el intérprete, osea Ignition, y compilarlas para la arquitectura de destino (recordemos que V8 se emplea en múltiples plataformas, que varían entre computadoras y dispositivos móviles). Según la arquitectura de destino, Turbofan, también elige las instrucciones de bajo nivel, lo que resulta en una ejecución altamente optimizada del código JavaScript.

En el siguiente gráfico podemos apreciar la interacción de los distintos componentes del pipeline del motor V8.

El pipeline del JavaScript Engine V8

Nota #1: para explorar más sobre el Árbol de Sintaxis Abstracta puede ingresar al siguiente enlace https://astexplorer.net.

Ejemplo de un Árbol de Sintaxis Abstracta.

Nota #2: teniendo NodeJS instalado, puede ejecutar el siguiente comando, en una consola, para poder apreciar el Bytecode de un archivo JavaScript:

node --print-bytecode myJavascriptFile.js
Ejemplo de Bytecode de un archivo JavaScript.
Ejemplo de Bytecode de un archivo JavaScript.

Referencias

Si le ha parecido interesante y desea profundizar sobre el tema, puede consultar los siguientes enlaces:

--

--

Traña Michael

Programador y apasionado por la Tecnología. Cada día intento aprender algo.