4 puntos por GN⁺ 2023-11-04 | 1 comentarios | Compartir por WhatsApp
  • 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/free dentro 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-opt y 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
    • Pyodide para Python y Blazor para C# son ejemplos representativos
    • Blazor soporta compilación AOT y JIT
  • 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
    • dlmalloc ocupa 6K, y emmalloc, 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/free dentro de Wasm
    • En el benchmark fannkuch de un artículo anterior sobre WasmGC, WasmGC ocupó 2.3K, mientras que C/Rust quedaron en 6.1~9.6K

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/free en 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 $Node y 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

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 10 en un campo y luego devuelve el valor, lógicamente puede reducirse a return 10
    • En WasmMVP, la asignación se convierte en una llamada a malloc, y como malloc es 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
  • WasmGC también ofrece punteros de función explícitos ref.func, llamadas a través de ellos con call_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
  • 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
  • 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-opt aumentó 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.test pasa una comprobación de un tipo específico, entonces un ref.cast al mismo tipo debería tener éxito
    • En patrones como un downcast después de instanceof en Java, se puede eliminar el cast
  • 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 $Node y la forma de creación con struct.new
  • La wiki de Binaryen cubre cómo emitir código WasmGC que sea fácil de optimizar para el compilador

1 comentarios

 
GN⁺ 2023-11-04
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

    • https://github.com/cretz/asmble funciona bien, pero en su mayoría fue un proyecto hecho por diversión y ahora, en la práctica, ya no se mantiene.
      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.
    • GraalVM puede ejecutar archivos ejecutables de WASM: https://www.graalvm.org/latest/reference-manual/wasm/
    • En cierto modo, sigue los pasos del CLR con 22 años de atraso.
      “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...
    • Si somos un poco meticulosos, la JVM es un concepto más amplio que los recolectores de basura[^1]. Dicho eso, es cierto que la JVM ha sido un campo de experimentación para la recolección de basura.
      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.
    • Estrictamente hablando, los hilos ofrecen concurrencia, no necesariamente paralelismo. Por eso llamarlo paralelismo real suena raro.
      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/

    • Es un avance realmente grande.
      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

    • LLVM no es una máquina virtual, pero WASM sí es una máquina virtual
      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...
    • Vine a hacer una pregunta parecida
      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
    • Si miras algo como wasmtime, básicamente puedes crear programas nativos con plugins muy seguros que admiten varios lenguajes. Del mismo modo, también funciona en el navegador manteniendo el modelo de seguridad básico
      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
    • Más que “WASM es el nuevo LLVM”, diría que WASM es el nuevo JVM
    • Está más cerca de “wasm es el nuevo Emscripten”. Es un estándar mucho más formalizado en todos los navegadores
      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

    • La curva para hacer tu propio navegador no es solo demasiado empinada: es literalmente imposible. Es mucho más fácil hacer un sistema operativo completo que un navegador
    • Ni siquiera Google y Apple empezaron desde cero: usaron WebKit, es decir, KHTML de KDE
    • Hacer tu propio Linux también es imposible, pero no veo que todos se quejen de eso. Tampoco critican a Android porque no sea fácil hacerlo por cuenta propia
      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 cierto, pero este trabajo sirve como base para runtimes alternativos más simples que pueden ejecutarse sin un motor de navegador completo. Piensa en Node o Deno, que dependen de V8
    • Muchas cosas modernas ya llegaron a este punto. No puedes construir tu propio auto, y construir una casa completamente desde cero por tu cuenta es prácticamente imposible. Se necesita demasiado conocimiento especializado, como códigos de construcción
  • 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

    • Puede pasar un tiempo antes de que WasmGC sea realmente útil en .NET. Según la discusión, la primera versión de WasmGC no tiene una buena forma de cubrir algunos escenarios específicos de .NET, y esos escenarios están clasificados como “post-post-mvp” [0]
      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 include que 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
    • El equipo de Wasm de Chrome compiló en C, Rust y Java el benchmark Fannkuch, que asigna estructuras de datos durante la ejecución. Los binarios de C y Rust iban de 6.1K a 9.6K según las banderas del compilador, mientras que la versión en Java era mucho más pequeña, de 2.3K
      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

    • Me da curiosidad cómo funciona Compose Multiplatform en la web. Me pregunto si dibuja sobre Canvas como Flutter
      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
    • Cada vez que lo intenté, el desastre de Gradle me apagó el entusiasmo
  • 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

    • WasmGC no soporta punteros interiores (interior pointer), así que es difícil que Go se beneficie. Al menos no sin algo feo como fat pointers
  • 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

    • Desde un punto de vista práctico de ahorrar un poco de espacio, podría tener sentido. Pero desde una perspectiva de diseño, como no es una “funcionalidad mínima indispensable” que habilite algo que ya no se pueda hacer, especificarla como parte del estándar solo lo inflaría sin motivo
      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
    • La dificultad de ese enfoque es que el comportamiento de la biblioteca de asignación tendría que estar estandarizado y ser determinista
      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
    • Esto suena como una dirección inteligente. Bastaría con agregar alloc y funciones relacionadas como funciones del runtime para que el código tradicional las llame, y permitir que cualquier GC se construya encima de eso
  • Soy 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

    • Lo distinto esta vez es que WASM invirtió el orden temporal respecto de cómo lo intentaron la JVM de Sun y el CLR de Microsoft
      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
    • Es difícil decir que la JVM y el CLR hayan sido diseñados para admitir varios lenguajes. La JVM tiene un lenguaje anfitrión, Java, y otros lenguajes que quieran ejecutarse en la JVM cargan con una carga mayor cuanto más se alejan del sistema de tipos de Java
      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 i31ref
      Por estas razones, Wasm GC es más general que los intentos mencionados arriba precisamente porque es de más bajo nivel
    • El soporte de WASM-GC se mantiene deliberadamente lo más simple posible. Ver https://github.com/WebAssembly/gc/blob/main/proposals/gc/MVP...
      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
    • Creo que lo diferente es la importancia de este proyecto
      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
    • Lo que hace wasm es distinto de los intentos anteriores. La función de GC no se ofrece para la interoperabilidad con otros lenguajes ni para compartir recursos de desarrollo entre implementaciones de runtimes de lenguajes
      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

    • Es un artículo interesante
      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