- Al llevar lenguajes con GC como Java, Kotlin, Dart, Python y C# a WebAssembly, WasmGC no recompila una VM existente, sino que aprovecha las estructuras, arreglos y el sistema de tipos con GC propios de Wasm
- El port tradicional a WasmMVP facilita reutilizar la VM existente y sus optimizaciones, pero tiene el costo de incluir GC o
malloc/freedentro de la memoria lineal, además de restricciones por referencias en la pila, referencias cíclicas y fragmentación - Con WasmGC, la VM administra directamente los objetos y la memoria, lo que puede reducir el tamaño del binario; en el benchmark
fannkuch, WasmGC ocupó 2.3K, menos que los 6.1~9.6K de C/Rust - Como WasmGC es una representación intermedia de más alto nivel, son importantes Binaryen
wasm-opty las optimizaciones en runtime de V8; hay casos de mejora promedio de 1.9× en benchmarks de Java y de alrededor de 30% en Google Sheets Calc Engine - La estandarización y el soporte en navegadores ya avanzaron, pero como no se trata de compilar tal cual una VM existente, hace falta nuevo trabajo de toolchain para bajar las estructuras del lenguaje a primitivas de WasmGC
Dos formas de llevar lenguajes con GC a Wasm
- Los ports de lenguajes con GC a WebAssembly se dividen, en términos generales, en dos caminos
- Port tradicional: compilar la VM existente del lenguaje a WasmMVP, el WebAssembly Minimum Viable Product lanzado en 2017
- Port a WasmGC: compilar el lenguaje a las estructuras de GC de Wasm definidas en la propuesta de GC
- El port tradicional se parece más al modelo de llevar un lenguaje a una nueva arquitectura de CPU: se comparten el parser, el soporte de bibliotecas, el GC y el optimizador de la VM, y se agrega solo un nuevo backend
- El port a WasmGC se parece más a llevar el lenguaje a una nueva VM que a una nueva arquitectura
- Como J2CL, que compila Java a JavaScript, representa los objetos del lenguaje como objetos de la VM destino y los deja bajo la gestión del GC de esa VM
- WasmGC apunta a un nivel más bajo que una VM de JavaScript, la JVM o el CLR, pero es de más alto nivel que WasmMVP porque ofrece estructuras y arreglos administrados por la VM, además de relaciones de tipos
Ventajas y límites del port tradicional a WasmMVP
- La mayor ventaja del port tradicional es que permite reutilizar casi tal cual el código de la VM existente, la implementación del lenguaje y sus optimizaciones
- Los artefactos de WasmMVP usan las estructuras básicas de WasmMVP, como memoria lineal, tablas y funciones
- Muchas veces Wasm se ejecuta dentro de una VM que ya tiene GC, como un navegador, Node.js, workerd, Deno o Bun
- En ese entorno, incluir una implementación de GC en el binario Wasm produce un aumento innecesario de tamaño
- Incluso los lenguajes que usan memoria lineal, como C, C++ y Rust, si realizan asignaciones significativas deben incluir también código de
malloc/free dlmallococupa 6K, yemmalloc, que prioriza el tamaño, también supera 1K
- Como WasmGC deja que la VM administre la memoria automáticamente, no hace falta incluir GC ni
malloc/freedentro de Wasm- En el benchmark
fannkuchde un artículo anterior sobre WasmGC, WasmGC ocupó 2.3K, mientras que C/Rust quedaron en 6.1~9.6K
- En el benchmark
Recolección de ciclos, referencias en la pila y fragmentación
- En el navegador, Wasm interactúa con frecuencia con JavaScript y las Web API, pero solo con WasmMVP y reference types es difícil hacer una recolección cíclica fina en enlaces bidireccionales entre Wasm y JS
- Los enlaces a objetos JS solo pueden colocarse en tablas de Wasm
- Los enlaces que vuelven de JS a Wasm pueden referenciar toda la instancia Wasm como si fuera un objeto grande
- WasmGC define objetos Wasm reconocidos por la VM, lo que permite crear referencias adecuadas entre Wasm y JavaScript
- Los lenguajes con GC también deben reconocer referencias en la pila, como variables locales dentro del scope de una llamada
- En el port tradicional, por el sandboxing de Wasm, el programa no puede inspeccionar su propia pila
- Como alternativa, puede usarse una shadow stack, o ejecutar el GC solo cuando no haya referencias en la pila, por ejemplo entre turns del event loop de JavaScript
- El soporte futuro de stack scanning en Wasm podría ayudar a los ports tradicionales
- Hoy, la forma de manejar automáticamente referencias en la pila sin overhead es WasmGC
malloc/freeen la memoria lineal de WasmMVP puede generar fragmentación de memoria en programas de larga ejecución- Aunque haya suficiente memoria total sin usar, una asignación grande puede fallar si no existe un bloque contiguo grande
- La fragmentación puede hacer que el módulo Wasm tenga que crecer su memoria con más frecuencia, lo que deriva en overhead y errores de out-of-memory
- WasmGC puede evitar la fragmentación porque la VM puede mover objetos para compactar el heap de GC
Herramientas de desarrollo y semántica del lenguaje
- En el port tradicional a WasmMVP, los objetos se ubican como bytes en la memoria lineal, por lo que a las herramientas de desarrollo les cuesta ver información de tipos de alto nivel
- En WasmGC, como la VM administra los objetos de GC, la integración con herramientas se vuelve más fácil
- En la pestaña Memory de Chrome DevTools se puede ver un heap snapshot de un programa WasmGC
- En el ejemplo de lista enlazada se muestra el nombre de tipo
$Nodey el campo$next, que referencia el siguiente objeto - También se ofrece información habitual de heap snapshots, como cantidad de objetos, shallow size y retained size
- El debugger de Chrome DevTools también funciona con objetos WasmGC
- El port tradicional recompila una VM existente, por lo que suele ser más fácil obtener la semántica esperada del lenguaje tal cual
- En un port a WasmGC hay que representar las estructuras del lenguaje con los nuevos tipos de GC, estructuras y arreglos, por lo que quizá sea necesario hacer compromisos semánticos por eficiencia
- Los campos de las estructuras WasmGC tienen índices y tipos fijos, así que los lenguajes que quieran acceder a campos de forma más dinámica pueden tener dificultades
- WasmGC actualmente no tiene interior pointers, y se espera que este tipo de limitaciones mejore con el tiempo
- En otros casos de compilación hacia una VM destino también existen decisiones semánticas
- El comportamiento numérico de dart2js difiere del de la VM de Dart
- Las cadenas de IronPython se comportan como cadenas de C#
- En cambio, dart2wasm funciona sin comprometer la semántica numérica porque Wasm puede representar eficientemente los tipos numéricos que Dart necesita
Trabajo de toolchain necesario para portar a WasmGC
- Portar a WasmGC no consiste simplemente en recompilar una VM existente
- Parte del código que no se integra directamente con el GC en runtime, como la lógica del parser o las optimizaciones AOT, puede reutilizarse
- En general, hace falta mucho código nuevo para bajar las estructuras del lenguaje a estructuras y arreglos de WasmGC
- Una VM como la de Lua, escrita en C, puede compilarse a Wasm en minutos, pero un port de Lua a WasmGC debe decidir e implementar cómo representar las estructuras de Lua dentro de las restricciones del sistema de tipos de WasmGC
- La gran desventaja de portar a WasmGC es el esfuerzo de toolchain
- El estado ideal sería que el sistema de tipos de WasmGC soportara eficientemente todos los lenguajes y que cada lenguaje implementara su port a WasmGC
- Las futuras funciones del sistema de tipos de WasmGC pueden ayudar con la primera parte
- Compartir trabajo común de toolchain puede reducir la carga de la segunda parte
Por qué WasmGC puede optimizarse mejor
- WasmGC es una representación intermedia de más alto nivel que WasmMVP, por lo que hay más margen de optimización
- En una función de ejemplo, el código que asigna dos veces objetos de GC, guarda
10en un campo y luego devuelve el valor, lógicamente puede reducirse areturn 10- En WasmMVP, la asignación se convierte en una llamada a
malloc, y comomalloces una función compleja con efectos secundarios en la memoria lineal, al optimizador le cuesta estar seguro de que la segunda asignación no cambia el campo del primer objeto - En WasmGC, la asignación se expresa con la instrucción
struct.new, y al poder inferirse como una operación de la VM, se pueden rastrear referencias y valores de campos
- En WasmMVP, la asignación se convierte en una llamada a
- WasmGC también ofrece punteros de función explícitos
ref.func, llamadas a través de ellos concall_ref, y tipos de campos para estructuras y arreglos - La razón por la que WasmMVP puede alcanzar velocidades cercanas a nativo suele ser que compiladores optimizadores potentes como LLVM realizan la mayoría de las optimizaciones antes de generar Wasm
- LLVM no soporta WasmGC, y muchos lenguajes con GC tampoco usan LLVM, así que WasmGC necesita otro modelo de optimización
Optimizaciones de Binaryen y wasm-opt
- WasmGC permite realizar optimizaciones de propósito general después de bajar a Wasm, de modo que toolchains de distintos lenguajes puedan compartir un optimizador común de Wasm a Wasm
- El equipo de V8 invirtió en soporte de WasmGC en Binaryen, un proyecto de optimización de toolchains de WebAssembly
- Cada toolchain puede usar Binaryen mediante la herramienta de línea de comandos
wasm-opt
- Cada toolchain puede usar Binaryen mediante la herramienta de línea de comandos
- Binaryen ya cuenta con optimizaciones para WasmMVP como inlining, propagación de constantes y eliminación de código muerto, y la mayoría de ellas también se aplican a WasmGC
- Las principales optimizaciones agregadas para WasmGC son las siguientes
- Escape analysis: mover asignaciones del heap a locales
- Devirtualization: convertir llamadas indirectas en llamadas directas
- Eliminación global de código muerto más potente
- Whole-program type-aware content flow analysis, GUFA
- Optimizaciones de casts: eliminar casts redundantes y mover la ubicación de casts
- Type pruning
- Type merging
- Refinamiento de tipos para locales, globales, campos y firmas
- Las nuevas optimizaciones de GC de Binaryen y su uso están documentados en la documentación de Binaryen
- Al medir el rendimiento de Java en la salida de J2Wasm,
wasm-optaumentó la velocidad en cada benchmark y logró una mejora promedio de 1.9×
Optimizaciones de WasmGC en V8
- Los lenguajes con GC tienen un modelo de rendimiento distinto al de lenguajes como C, C++ y Rust, que dependen mucho del inlining en tiempo de compilación
- Lenguajes con GC como Java y Dart normalmente dejan que la VM realice inlining y optimizaciones en runtime
- En Java, todas las llamadas empiezan como llamadas indirectas
- Las clases hijas pueden sobrescribir funciones de la clase padre, y lo mismo ocurre al llamar a un hijo mediante una referencia del tipo padre
- Si el toolchain convierte llamadas indirectas en directas, se obtiene beneficio, pero en código Java real hay muchos caminos donde es difícil inferir estáticamente que una llamada sea directa
- V8 implementa speculative inlining para WasmGC
- Observa llamadas indirectas en runtime
- Si un punto de llamada específico muestra un comportamiento simple, como pocos destinos de llamada, lo inlinea junto con una verificación de guardia
- Google Sheets Calc Engine es una base de código Java que calcula fórmulas de hojas de cálculo y antes se compilaba a JavaScript con J2CL
- El equipo de V8 colaboró con Sheets y J2CL para portar ese código a WasmGC
- En ese código, speculative inlining fue la optimización individual implementada por V8 en WasmGC que tuvo el mayor impacto
- Mostró una mejora de velocidad de alrededor de 30%, mayor que la de todas las demás optimizaciones medibles en conjunto
- Otras optimizaciones de WasmGC en V8 incluyen load elimination, type-based optimizations, branch elimination, constant folding, escape analysis y common subexpression elimination
- La información de tipos de WasmGC también se usa para optimizaciones en runtime
- Si
ref.testpasa una comprobación de un tipo específico, entonces unref.castal mismo tipo debería tener éxito - En patrones como un downcast después de
instanceofen Java, se puede eliminar el cast
- Si
- En WasmMVP, la separación de roles entre optimizaciones del toolchain y de la VM era relativamente clara, pero en WasmGC pueden superponerse más debido a las características de los lenguajes con GC y a las posibilidades de optimización de la representación WasmGC
Estado actual y punto de partida
- WasmGC llegó a phase 4 en el W3C, por lo que es un estándar completo y finalizado
- Chrome 119 incluye soporte para WasmGC
- Se espera que Firefox 120 se lance con soporte para WasmGC a fines del mismo mes
- En la demo de Flutter, Dart compilado a WasmGC ejecuta lógica de aplicación que incluye widgets, layout y animaciones
- Los toolchains que soportan WasmGC son los siguientes
- El pequeño ejemplo de la sección de herramientas de desarrollo, cuyo código fuente está disponible, es un programa WasmGC “hello world” escrito a mano
- Permite ver la definición del tipo
$Nodey la forma de creación construct.new
- Permite ver la definición del tipo
- La wiki de Binaryen cubre cómo emitir código WasmGC que sea fácil de optimizar para el compilador
- GC Implementation - Lowering Tips
- También se pueden consultar los pases y flags de Binaryen usados por los toolchains de Java, Dart y Kotlin
1 comentarios
Comentarios de Hacker News
WASM parece un ejemplo de cintura delgada (thin waist) y, si se le suma un recolector de basura, la estructura pasa a ser N+M en lugar de N×M. Es decir, se puede ir hacia N lenguajes + M máquinas virtuales + G recolectores de basura, y V8 ya cuenta con un recolector de basura maduro.
Me preguntaba si existía alguna herramienta para ir de WASM a la JVM, y encontré una en GitHub. No la he probado personalmente; la busqué porque la JVM también tiene recolectores de basura maduros y paralelos.
No pensé que WASMGC fuera a llegar tan rápido, así que ahora también espero WASM Threads para tener paralelismo real, no solo paralelismo de entrada/salida.
Si surge la oportunidad de resolver eficazmente la asincronía, el paralelismo y la recolección de basura, WASM se volverá más fuerte y podría dejar de ser una fuente de confusión o dificultad para los desarrolladores. Creo que WASI también es importante porque ofrece la oportunidad de definir una API tan estable como POSIX.
1: https://www.oilshell.org/blog/2022/02/diagrams.html
2: https://github.com/cretz/asmble
Espero que las ideas y explicaciones sobre cómo se mapeó la representación intermedia de WASM a bytecode de la JVM sirvan a quienes construyan una implementación más oficial. Actualmente no hay planes de admitir WASM GC.
“Más de 20 proveedores de herramientas de programación ofrecen en .NET alrededor de 26 lenguajes de programación, incluidos C++, Perl, Python, Java, COBOL, RPG y Haskell”.
Fuente: https://news.microsoft.com/2001/10/22/massive-industry-and-d...
No tanto porque el mundo académico haya sido especialmente audaz con la JVM, sino porque los programas de la JVM se usan ampliamente y con frecuencia de maneras que ponen bajo presión una única técnica de recolección de basura.
[^1]: https://www.baeldung.com/jvm-garbage-collectors. Azul JVM también tiene otro recolector de basura distinto. Estos son solo los que conozco; seguramente se me escapan bastantes.
Supongo que lo dice en comparación con las corrutinas, pero las corrutinas son secuenciales. Aunque el orden de ejecución pueda ser arbitrario, se puede confiar en que no se ejecutan al mismo tiempo.
Si wasm adopta hilos, me parece que será otra lamentable situación de “Worse is Better”. Los hilos están cerca de ser el peor modelo de concurrencia que hemos ideado. Claro, dejando de lado cosas como concurrent COMEFROM.
Las herramientas WASM de Julia pueden crear apps que admitan o necesiten esta función. Por ejemplo, hay un ejemplo de compilación de un solver de ODE a WASM en https://tshort.github.io/WebAssemblyCompiler.jl/stable/examp...
Para que funcione de inmediato se necesita Chrome v119, porque esa fue la primera versión que activó el soporte de recolección de basura. Hay más detalles en la página principal del compilador WASM: https://tshort.github.io/WebAssemblyCompiler.jl/stable/
Ojalá el nuevo tipo
Memory{T}permita compilar más código.Se siente como “wasm es el nuevo LLVM”. Me pregunto si alguien más lo siente parecido
Entiendo qué intenta hacer y he visto demos que muestran su potencia, pero en gran parte sigue siendo técnicamente de muy bajo nivel y, para usarlo en la práctica, muchas veces termina volviéndose bastante engorroso
Me pregunto cuándo creen que estará listo para una adopción más amplia como para elegirlo como objetivo en lugar del enfoque actual
Por el nombre surge un malentendido común: LLVM al principio pretendía ser una máquina virtual, pero en realidad nunca lo fue y tampoco lo es ahora. Incluso la primera frase de su página lo deja claro: https://llvm.org/
Básicamente, es un conjunto de bibliotecas en C++ que implementan una representación intermedia que cambia con el tiempo, y una herramienta que ayuda a escribir compiladores
Hace unos 10 años Google tenía un proyecto que apuntaba a un área parecida a WASM, y creo que cayó en este malentendido. Pensaban en LLVM como una máquina virtual. Probablemente era algo como PNaCl
Es un poco parecido a cómo LuaJIT fijó Lua en Lua 5.1. Lua no era un estándar, pero para reimplementarlo se puede fijar una versión concreta. El problema evidente de ese enfoque es que quien reimplementa no conoce todos los bugs que también está fijando en el tiempo
Algunas de las “concesiones” de WASM me han hecho levantar una ceja, pero algo indudable es que WASM realmente es una máquina virtual
Vi la presentación de WASM GC, y quienes lo crearon hablaron con honestidad sobre los compromisos. Por ejemplo, que al inicio se necesitan casts en tiempo de ejecución y que la sobrecarga medida es razonable. Esa actitud, de hecho, me da confianza
https://old.reddit.com/r/ProgrammingLanguages/comments/17crk...
Sinceramente, no entiendo bien wasm. No me queda claro exactamente qué problema estamos intentando resolver
Me pregunto si el objetivo es escribir aplicaciones en lenguajes que no sean JavaScript ni código convertido a JavaScript. No sé si eso incluye la parte de interactuar con la capa de presentación del DOM del navegador. Según entiendo, en realidad no se puede hacer eso; si es así, me pregunto si el objetivo es ejecutar aplicaciones en un canvas dedicado dentro del DOM, como Flash. En ese caso, no sé qué tan grande es ese nicho
En otro hilo también se hablaba de usar wasm en Cloudflare Workers. Supongo que es porque funciona a través del intérprete de JavaScript. Pero si la gente quiere escribir Cloudflare Workers con runtimes arbitrarios, pensaría que Cloudflare simplemente podría agregar soporte para otros runtimes. Capacidad para eso seguramente tienen
O bien me pregunto si, más allá de la conexión con el ecosistema JavaScript, wasm tiene algo intrínsecamente excelente como bytecode
Siento que me perdí algún material introductorio que explique por qué esta tecnología es interesante, pero a estas alturas me da un poco de pena preguntar
LLVM no ofrece una “sandbox de seguridad básicamente fácil” sin bastante trabajo de programación. Wasmer tiene un backend de LLVM, pero personalmente creo que este es el mayor diferenciador de WASM
Va en la misma dirección que LLVM, pero todavía está lejos de eso
Por más impresionante que sea y por muchas posibilidades que abra, no dejo de pensar en que los navegadores de hoy son extremadamente complejos y que la barrera de entrada para hacer uno propio es casi demasiado empinada
No entiendo por qué la plataforma de hipermedia más exitosa y accesible del mundo tendría que ser fácil de implementar. Naturalmente, el sistema en línea más exitoso del mundo es complejo y tiene muchas funciones. Por eso lo usamos, y por eso ganó
Es impresionante que esto al final se haya construido y lanzado. Durante años se habló del plan de meter GC en WASM, y no estaba seguro de que realmente fuera a pasar
Me pregunto cuánto ayudará en los casos de lenguajes que apuntan a WASM y tienen el problema de que los binarios se vuelven grandes por incluir el runtime. Si mal no recuerdo, Blazor necesitaba alrededor de 1 MB incluso para un hello world, y no sé si WasmGC ayudaría con eso
Claro que lo preocupante es que, si son funciones que solo necesita .NET, no hay mucho incentivo para agregarlas. Llegado ese punto, una función tipo
includeque permita cachear una versión específica del GC y que otros ensamblados WASM puedan cargarla podría ser más útil, aunque genere dolor[0] - https://github.com/WebAssembly/gc/issues/77
C y Rust no incluyen un recolector de basura, pero aun así tienen que empaquetar malloc/free para la gestión de memoria. La razón por la que Java queda más chico aquí es que no necesita empaquetar código de gestión de memoria en absoluto
https://developer.chrome.com/blog/wasmgc/
En el caso de Blazor, solo ayudaría con el GC. Si mal no recuerdo, Blazor tiene que enviar todo el runtime de dotnet junto con la app
El nuevo soporte de wasm en Kotlin se ve bastante prometedor. Hay una versión experimental de Compose Multiplatform que puede apuntar al navegador, y está previsto que use WASM
Compose Multiplatform básicamente es Google Jetpack Compose para Android con soporte agregado para otras plataformas
Hasta hace unos días, el soporte para iOS estaba en alfa y se espera que pase a beta el año que viene. El soporte para Android y escritorio ya es estable. Cuando todo eso se estabilice, en la práctica se podrán escribir aplicaciones de UI que funcionen en cualquier plataforma
El compilador a wasm se lanzará junto con la próxima versión mayor de Kotlin, Kotlin 2.0, que incluye el nuevo compilador k2. Parece probable para comienzos del año que viene. k2 actualmente está disponible en beta y se puede activar en Kotlin 1.9.x
Lo bueno del ecosistema multiplataforma de Kotlin es que ya hay muchas bibliotecas que funcionan en varias plataformas. Así que el compilador wasm también pasará rápidamente a formar parte de eso y heredará buenas bibliotecas. En general, basta con cambiar la configuración de build para apuntar a ese ecosistema e implementar el comportamiento específico de plataforma que falte
Otro punto interesante en esta área es usar y enlazar bibliotecas escritas en distintos lenguajes. Por ejemplo, es muy probable que muchas partes específicas de plataforma dependan de bibliotecas existentes en C o Rust. En muchos casos podrían ser las mismas bibliotecas que usa Kotlin Native
También me pregunto si usa los mismos widgets en escritorio, web, iOS y Android. Entiendo que en Android es nativo. No sé si en otras plataformas imita otros estilos. La pregunta clave es cómo se siente una app de Compose Multiplatform en plataformas que no son Android
Por ejemplo, Dart en la web a mí me da una sensación muy trabada, y Electron en escritorio también. Dart en escritorio está bien, pero las apps suelen tener botones y márgenes grandes, así que se sienten más como una app Android corriendo en un emulador que como una app nativa real
También me pregunto si valdría la pena recomendar Kotlin como lenguaje para un proyecto nuevo
Me pregunto si alguien puede explicar por qué esta entrada del blog y el anuncio de Chrome no mencionan Go
Go también usa recolección de basura, y da la impresión de que no puede beneficiarse de este cambio
Me pregunto si tendría sentido que el runtime exponga una biblioteca de asignación integrada que C/C++/Rust puedan usar
Los programas podrían elegir esa biblioteca en vez de empaquetar su propia biblioteca de asignación
Las primitivas de Wasm GC se diseñaron para obtener la mayor mejora posible con el menor agregado posible. También cuando se agregan otras primitivas, como SIMD, es porque son las “primitivas más o menos mínimas” para lograr esa funcionalidad. Aquí se necesitan los bloques de construcción más pequeños posibles
Pero una API de asignador de memoria como malloc/free no es una funcionalidad mínima. Un asignador de memoria en realidad es un conjunto de políticas y decisiones de diseño, y los algoritmos se derivan de eso. El bloque de construcción básico en esa área es “un fragmento de memoria lineal propiedad del asignador”, y eso es la memoria lineal que WASM tiene desde el primer día
Puede tener sentido que runtimes individuales lo ofrezcan. Por ejemplo, pasando parte de la memoria lineal a un import integrado de wasm y dejando que lo maneje un asignador implementado por el runtime. Pero creo que es muy poco probable que se estandarice. Además, la mayoría de las herramientas para lenguajes Wasm sin GC están orientadas a portar bases de código existentes y sus asignadores. Al final, sería más código que mantener para una implementación puntual, así que podría no valer el esfuerzo invertido
Si no es determinista, las diferencias en el comportamiento del programa pueden volverse importantes. Por ejemplo, si algún navegador incluye un asignador “inteligente” que reutiliza mejor la memoria, un programa que en otros navegadores se queda sin memoria por fragmentación de la memoria lineal podría funcionar en ese navegador. Históricamente, los navegadores se han esforzado mucho por estandarizar el comportamiento para evitar ese tipo de diferencias
Estandarizar el comportamiento de una implementación de malloc/free también es complicado por varias razones. Primero, hay mucha complejidad: cómo se maneja la free list, qué tamaños de chunks se usan, etc. Es demasiado para ponerlo en una especificación. Segundo, si se estandariza un comportamiento concreto, ya no se puede mejorar, y todavía hoy siguen apareciendo mejores ideas para malloc/free
Por estas razones, soy escéptico de que esto llegue a entrar en la especificación de wasm
En cambio, GC evita estos problemas. Como los valores de los punteros no son observables, no hay nada que especificar
allocy funciones relacionadas como funciones del runtime para que el código tradicional las llame, y permitir que cualquier GC se construya encima de esoSoy un poco escéptico respecto de esta dirección. Está aumentando mucho la complejidad de WebAssembly
Los recolectores de basura son abstracciones con fugas. Algunos admiten punteros internos y otros no. Algunos admiten trabajos paralelos que comparten memoria y otros no. Algunos necesitan compactación, lo que vuelve más difícil la FFI con C, y otros no. Algunos tienen que integrarse profundamente con los mecanismos usados para procesos/hilos verdes y pilas escalables, y otros no
Si se miran lenguajes como Erlang, JavaScript, Python o Go, las decisiones a nivel de lenguaje se reflejan en cierta medida en el recolector de basura
La idea de una máquina virtual universal/genérica que admita múltiples lenguajes se ha intentado varias veces con la JVM, el CLR, Parrot, etc., y tuvo un éxito limitado. Me pregunto qué es distinto esta vez
La JVM/CLR primero crearon una máquina virtual, una especificación de instrucciones de lenguaje intermedio y un runtime, y luego intentaron distribuirlo lo más ampliamente posible esperando una adopción universal en clientes. Es decir, esperaban que la “VM de lenguaje intermedio” fuera tan atractiva que se extendiera por toda la industria. Esa expectativa solo se cumplió parcialmente. La JVM/CLR se difundieron en escritorio y servidores, pero en los navegadores web fracasaron Java Applet y Microsoft Silverlight, y tampoco lograron una adopción amplia en plataformas móviles
WASM va en el orden contrario. Parte hacia atrás desde algo que ya está distribuido y adoptado en toda la industria, es decir JavaScript, para crear una “máquina virtual, especificación de instrucciones de lenguaje intermedio y runtime”
Desde este punto de vista, el llamado “lenguaje de juguete” JavaScript fue un caballo de Troya de 20 años para desplegarse primero de forma masiva en todos los clientes. Ahora la industria básicamente dice: “¿Alguien notó que ya tenemos JavaScript como runtime universal en servidor + escritorio + navegador + móvil? Hagamos un runtime de lenguaje intermedio para hacerlo rápido”
También hubo algunos problemas técnicos. La JVM de Sun no tenía punteros primitivos, por lo que era difícil que fuera un buen destino de alto rendimiento para lenguajes basados en punteros como C/C++, y el CLR de MS no estaba disponible en macOS. El CLR mínimo de Silverlight fue una excepción. Pero más que esas limitaciones técnicas, la secuencia temporal en la que JavaScript se distribuyó como un caballo de Troya inofensivo explica más
Wasm es de más bajo nivel que la mayoría de los formatos de bytecode mencionados arriba. Incluso incluyendo Wasm GC, que agrega structs y arrays tipados estáticamente, y la propuesta function-references, que introduce funciones tipadas. Wasm GC también tiene soporte explícito para el puntero etiquetado
i31refPor estas razones, Wasm GC es más general que los intentos mencionados arriba precisamente porque es de más bajo nivel
Crear una VM “universal” o “genérica” que admita varios lenguajes de forma equivalente y fluida no es un objetivo explícito de WASM-GC. Se asume que cada implementación puede necesitar sus propios hacks y semánticas especiales sobre el soporte básico que ofrece WASM, y consideran que está bien porque la FFI y la interoperabilidad entre lenguajes son problemas completamente separados
La recolección de basura de JavaScript va a seguir existiendo, y parece ser la más arraigada de los ejemplos mencionados
En muchos casos, aunque sea inferior, otros lenguajes y aplicaciones/librerías tendrán que adaptarse a ella
wasm ofrece la función de GC para que los lenguajes de runtime con memoria administrada puedan apuntar al entorno wasm sin sufrir por las limitaciones de un modelo de memoria restringido y, secundariamente, para reducir el tamaño del bundle
wasm probablemente pueda admitir parámetros de GC más ajustables para adaptarse mejor a las características del lenguaje invitado. Además, a diferencia de los runtimes de lenguajes de propósito general con los que se compara, quienes implementan lenguajes directamente no tienen la opción de crear un runtime personalizado
Aquí se abordan varias preocupaciones sobre la viabilidad actual de WASM GC. Traducción al inglés de Google Translate:
https://habr-com.translate.goog/ru/articles/757182/?_x_tr_sl...
Original:
https://habr.com/ru/articles/757182/
Es un artículo del autor de TeaVM, que lleva 10 años trabajando en hacer que Java y el código JVM se ejecuten eficientemente en el navegador. https://teavm.org/
La conversión existente de Java a JavaScript de TeaVM tiene buen rendimiento aun usando el GC de JS del navegador. Será interesante ver si WASM GC madura más y logra ser más rápido que eso
Dejando algunas notas sobre los problemas tratados en el artículo: el problema de necesitar una pila sombra manual queda resuelto con WasmGC. Es igual a cómo funciona en JS, como se menciona en el enlace
La falta de try-catch queda resuelta por la propuesta de manejo de excepciones de Wasm, que ya llegó a los navegadores: https://github.com/WebAssembly/exception-handling/blob/main/...
Las comprobaciones de null también se resuelven en gran medida con WasmGC. La especificación define tipos locales no anulables, y la VM puede optimizar usando señales, como la técnica mencionada en el artículo. Por ejemplo, Wizard lo hace así
La inicialización de clases es un problema difícil, como dice el artículo. J2Wasm y Binaryen están trabajando para optimizarlo mediante análisis estático a nivel de toolchain. Un PR que escribí recientemente avanzó en esa dirección: https://github.com/WebAssembly/binaryen/pull/6061
El overhead de vtable mencionado en el artículo puede ser un problema. Sin embargo, todavía no conozco buenas mediciones. Hay algunas ideas de soluciones post-MVP para el despacho de métodos, pero aún no hay nada concreto
Sobre las comprobaciones de null y los traps, hubo discusiones sobre variantes de instrucciones de GC que lancen excepciones en lugar de traps. Pero, según las mediciones, por ahora no aparece como un gran problema, así que tiene baja prioridad
El autor tiene razón al decir que el stack walking, las señales y el control de memoria son áreas importantes
En general, gracias a WasmGC y al manejo de excepciones, el Java que J2Wasm emite hoy está en una posición bastante buena. Normalmente es más rápido que J2CL compilando Java a JavaScript. Aun así, claramente hay margen de mejora