10 puntos por GN⁺ 2025-08-05 | Aún no hay comentarios. | Compartir por WhatsApp
  • En el motor V8, mejoraron el rendimiento de la función JSON.stringify a más del doble, logrando una serialización de datos más rápida
  • Introdujeron una ruta de optimización para objetos sin efectos secundarios, omitiendo gran parte de la lógica defensiva de verificación y consiguiendo una mejora importante de velocidad en objetos de datos comunes
  • En el procesamiento de cadenas, aplicaron métodos más avanzados a nivel de hardware y memoria, como la distinción entre 1 byte/2 bytes, uso de SIMD y cambios en la estructura del búfer temporal
  • En el proceso de conversión numérica, reemplazaron el algoritmo Grisu3 por Dragonbox, lo que también permite conversiones más rápidas en las llamadas a Number.toString()
  • En algunos argumentos o formas vuelve a la ruta de serialización general, pero en la mayoría de los escenarios de desarrollo web se puede aprovechar la optimización automáticamente

Resumen general

  • JSON.stringify es una función clave para convertir datos en cadenas dentro de JavaScript
  • Mejorar el rendimiento de esta función también impacta positivamente tareas muy importantes en la web, como solicitudes de red o almacenamiento en localStorage
  • Gracias al trabajo de ingeniería más reciente en V8, la velocidad de esta función mejoró a más del doble, y aquí se presentan en detalle las principales optimizaciones

Ruta Fast Path sin efectos secundarios

  • La clave de la optimización es aplicar una ruta rápida de serialización que solo puede usarse en situaciones sin efectos secundarios (side effects)
  • En estos casos, el recorrido del objeto se hace con una estructura iterativa en lugar de recursiva, por lo que no se necesitan verificaciones de stack overflow y también es posible intentar serializar objetos más profundos
  • Cuando el objeto de datos es simple, V8 usa este Fast Path en lugar de la lógica general más lenta, omitiendo muchas verificaciones y acelerando el proceso

Manejo de distintas representaciones de cadenas

  • V8 almacena las cadenas de forma diferente según sean de 1 byte o 2 bytes (ASCII/no ASCII), y si aparece aunque sea un carácter no ASCII, todo se maneja como 2 bytes
  • Para mejorar el rendimiento de la serialización de cadenas, compilaron versiones separadas del algoritmo según el tipo de cadena
  • Como durante el procesamiento hay que verificar el tipo de instancia de la cadena, si se detecta una cadena de 2 bytes, el serializador apropiado de 2 bytes toma el control del estado
  • Gracias a esto, la sobrecarga por cambiar entre rutas según la codificación de la cadena es prácticamente nula
  • El resultado se genera creando por separado búferes de 1 byte y 2 bytes, que luego simplemente se combinan al final

Optimización de serialización de cadenas con SIMD

  • Las cadenas de JavaScript pueden incluir caracteres que necesitan escape al serializarse como JSON
  • Las cadenas largas se revisan varios bytes a la vez usando instrucciones SIMD de hardware (como ARM64 Neon)
  • Las cadenas cortas usan un enfoque SWAR, procesando varios caracteres al mismo tiempo mediante operaciones de bits en registros de propósito general
  • En cualquiera de los dos casos, la mayoría de las veces es posible copiar toda la cadena rápidamente sin transformaciones adicionales

Se agregó Express Lane (ruta ultrarrápida)

  • Incluso dentro del Fast Path, se preparó una Express Lane para poder serializar copiando solo las claves, sin trabajo repetitivo como verificaciones de propiedades
  • Aprovechando los flags de hidden class del objeto, si las claves no tienen Symbol, todas son enumerable y ya pueden serializarse sin necesidad de escape, se marca como fast-json-iterable
  • Al serializar otros objetos con la misma hidden class, las claves se copian directamente sin verificaciones adicionales
  • Esta técnica también se aplica en JSON.parse para comparaciones rápidas de claves

Un algoritmo más rápido de double-to-string

  • El proceso de convertir números a cadenas también es frecuente y complejo
  • Se reemplazó el algoritmo Grisu3 por Dragonbox, lo que mejora el rendimiento en las llamadas generales a Number.prototype.toString()

Optimización de la estructura del búfer temporal

  • Antes, al construir cadenas se usaba un único búfer continuo, lo que provocaba una sobrecarga por copiar todo el contenido cada vez que faltaba espacio
  • El nuevo enfoque usa una estructura de búfer segmentado, uniendo varios búferes pequeños según sea necesario
  • Gracias a esto, cuando no hay suficiente espacio, solo se asigna un nuevo búfer sin necesidad de copiar todo

Limitaciones

  • El Fast Path solo funciona para serialización simple de datos
  • Si no se cumplen las siguientes condiciones, se usa la ruta general
    • No se puede usar el argumento replacer ni space (sin Pretty-Print ni transformaciones)
    • Debe ser un objeto simple sin método personalizado toJSON
    • Si hay propiedades basadas en índice, pasa a la ruta lenta
    • No maneja cadenas especiales como ConsString
  • En la mayoría de usos comunes, como serialización de datos, generación de respuestas de API o caché de configuración, la optimización se aplica automáticamente

Conclusión

  • Al replantear el enfoque en todas las áreas, desde el diseño básico de JSON.stringify hasta el manejo de memoria y caracteres, lograron un aumento de velocidad de más de 2x en el benchmark JetStream2
  • Estas mejoras ya pueden experimentarse en V8 versión 13.8 (Chrome 138) o superior

Aún no hay comentarios.

Aún no hay comentarios.