El que no corre, v8ela.

No pienso irme a la cama le dije a mi novia para gran sorpresa suya. Los niños nunca están dispuestos a irse a la cama, pero los adultos como mi novia se mueren por reunirse con sus almohadas y sus edredones nada más terminar de cenar—. ¡No pienso irme a la cama! —repetí con tal ímpetu que mi novia comprendió que estaba muy, muy emocionado.

Ya escribí en su momento una pequeña introducción a los internals de V8. Digamos que hace tiempo empecé un documento para ir recolectando todo lo que tenía que ver con los internals del motor JavaScript V8. Por pura curiosidad y ansia de aprender.

Por eso mi novia entendió que un nuevo compilador optimizador en V8 era suficiente motivo como para no irme a dormir esa noche tan pronto.

"Me gusta estar en compañía de exploradores." - J.M Barrie

Turbofan

Así es el nombre del nuevo compilador optimizador de V8, turbofan. Podrían haberle puesto de nombre "Saxofón" o incluso "Cocoon", pero decidieron llamarlo Turbofan.

¿Qué nos trae Turbofan?

Un nuevo compilador optimizador para (probablemente) sustituir al actual crankshaft. Además de eso lleva soporte built-in para asm.js, eso en mi pueblo se llama performance brutal de serie (aunque esto a @mraleph no le guste).

Este nuevo compilador optimizador se encuentra todavía muy verde, hasta donde he podido investigar en el código fuente, todavía no hay OSR implementado y ni siquiera deoptimización del byte code generado, vamos que ni las técnicas más básicas de optimización están todavía incuídas en el nuevo compilador.

¿Y qué es lo que tenemos hasta ahora?

Pues un nuevo optimizador que descarta automáticamente dead code desde el momento de la generación del AST, no más heurística en el núcleo del motor para encontrar dead code y un mar de dudas muy grande sobre el que investigar.

Un mar de dudas

Si dispusiera de 8 horas para cortar un árbol, emplearía 6 en afilar el hacha.

Con la llegada de Turbofan pasamos de un compilador (Hydrogen) basado en SSA a un compilador basado en un "mar de nodos", podéis leer una comparación del funcionamiento de cada uno aquí.

El mar de nodos de este nuevo compilador no es más que un lenguaje intermedio entre el AST generado en base a un código JavaScript, y el byte code final ejecutado por la máquina virtual.

En este 'mar de nodos' cada nodo se representa como una parte de un gráfico. Todos los nodos producen un valor. Por ejemplo 1 + 2 = 3. Además cada nodo apunta a sus operandos (en este caso 1 y 2) y no hay más información más allá de esto, sencillo y conciso.

¿Qué ventajas conlleva el 'mar de nodos' respecto a otros lenguajes intermedios?

  • Búsqueda rápida de constantes que son globales o tener una sola referencia a un nodo que representa una constante, e.j número 2. Gracias a esto no duplicamos nodos.
  • Búsqueda de dead code, cualquier nodo que no tiene dependencias es automáticamente marcado como dead code (código que no se ejecuta puesto que hace nada), por ejemplo:
function test (num){  
    var a = 14 + num; // Dead code, porque el resultado de su ejecución no produce nada.
    return 20 + 20;
}
  • Optimización de nodos global. Insertar un nodo en el lugar más óptimo dentro del gráfico del 'mar de nodos', así en la generación de byte code no hay que recorrer closures hasta llegar a el valor de un nodo puesto que su primitivo ya que encuentra en el lugar correcto.

Pero ojo, que el equipo de V8 no ha inventado nada nuevo, esta técnica del 'mar de nodos' ya se usaba desde hace tiempo por el Hotspot compiler de Java.
¿Qué tengo que hacer para probarlo?

Nunca hagas el corral antes de tener las ovejas.

No me ha llevado mucho tiempo poner en marcha Turbofan en mi Macbook, estos pasos deberían servirte si quieres probarlo.

Bájate turbofan desde la rama bleending_edge:
$ git clone -b bleeding_edge https://github.com/v8/v8.git

Instala las dependencias necesarias para trabajar con V8 (mejor vete a hacer la cena mientras haces esto):
$ make dependencies

Compila V8:
$ make native

Y una vez hecho esto, puedes usar la shell que se encuentra en out/native/d8, aunque a mí personalmente me gusta utilizar Xcode porque así puedo poner breakpoints en los internals y debuggear. Para generar un proyecto de Xcode ejecuta:
$ build/gyp_v8 -Dtarget_arch=ia32

Y en la carpeta build/ tendrás un all.xcodeproj preparado para ser utilizado en Xcode.

Si te apetece investigar un poco, éstos son algunos de los flags que he encontrado para observar cómo funciona turbofan:

turbo_filter - "optimization filter for TurboFan compiler"  
trace_turbo - "trace generated TurboFan IR"  
trace_turbo_types - "trace generated TurboFan types"  
trace_turbo_scheduler - "trace generated TurboFan scheduler"  
turbo_asm - "enable TurboFan for asm.js code"  
turbo_verify - "verify TurboFan graphs at each phase"  
turbo_stats - "print TurboFan statistics"  
turbo_types - "use typed lowering in TurboFan"  
turbo_source_positions - "track source code positions when building TurboFan IR"  
context_specialization - "enable context specialization in TurboFan"  
turbo_deoptimization - "enable deoptimization in TurboFan"  
turbo_inlining - "enable inlining in TurboFan"  
trace_turbo_inlining - "trace TurboFan inlining"  

Y estos son los flags que he utilizado yo cuando he estado investigando los internals de turbofan:

--always-opt --turbo-stats --trace-turbo --turbo-types --turbo-filter=function_name

Reemplaza function_name por el nombre de una función que tu mismo declares.

Recuerda utilizar siempre -always-opt para que todo código ejecutado sea optimizado por Turbofan, si no haces esto, solo el código identificado por el runtime profiler se optimizará (loops y cosas así).

No seas perro sin oficio

Siempre hay que intentar mejorar un poco, ahora es un buen momento para empezar a leer sobre como funciona JavaScript o cualquier cosa que te inquiete. Dedícate tiempo a tí mismo, y a tu familia, aprende de una vez por qué el cuerpo de una función en JavaScript puede ralentizar tu programa si éste tiene un comentario en su interior, léete un libro sobre recetas de cocina que te hará bien y vuelve a comprarte ese juguete que te encantaba de pequeño para volver a pasar tiempo haciendo lo que te gusta.