asm.js
Este artigo resulta, no todo ou em parte, de uma tradução do artigo «asm.js» na Wikipédia em inglês, na versão original. |
asm.js | |
---|---|
Surgido em | 21 de março de 2013[1] |
Criado por | Mozilla |
Influenciada por | JavaScript |
Influenciou | WebAssembly |
Sistema operacional | Multiplataforma |
Página oficial | asmjs |
asm.js é um subconjunto de JavaScript projetado para permitir que software de computador escrito em linguagens como C sejam executados como aplicativos da web, enquanto mantém características de desempenho consideravelmente melhores do que o JavaScript padrão, que é a linguagem típica usada para tais aplicativos.
o asm.js consiste em um subconjunto estrito de JavaScript, para o qual o código escrito em linguagens estaticamente tipadas com gerenciamento de memória manual (como C) é traduzido por um compilador de fonte para fonte como o Emscripten (baseado em LLVM).[2] O desempenho é melhorado ao limitar os recursos da linguagem àqueles que podem ser otimizados com antecedência e outras melhorias de desempenho.
O Mozilla Firefox foi o primeiro navegador da web a implementar otimizações específicas para o asm.js, a partir da versão 22.[3]
O asm.js foi substituído por WebAssembly. Consulte § Deprecação abaixo.
Design
[editar | editar código-fonte]O asm.js permite melhorias significativas de desempenho para aplicativos da web, mas não tem como objetivo melhorar o desempenho do código JavaScript escrito à mão, nem permite nada além do desempenho aprimorado.
Destina-se a ter características de desempenho mais próximas das do código nativo do que o JavaScript padrão, limitando os recursos da linguagem àqueles passíveis de otimização antecipada e outras melhorias de desempenho.[4] Ao usar um subconjunto de JavaScript, o asm.js é amplamente compatível com todos os principais navegadores da web,[5] ao contrário de abordagens alternativas como o Google Native Client.
Geração de código
[editar | editar código-fonte]O asm.js normalmente não é escrito diretamente: em vez disso, como uma linguagem intermediária, ele é gerado por meio do uso de um compilador que pega o código-fonte em uma linguagem como C++ e gera asm.js.
Por exemplo, dado o seguinte código em C:
int f(int i) {
return i + 1;
}
Emscripten produziria o seguinte código em JS:
function f(i) {
i = i|0;
return (i + 1)|0;
}
Observe a adição de |0
e a falta de especificadores de tipo. Em JavaScript, os operadores bit a bit convertem seus operandos em inteiros assinados de 32 bits e fornecem resultados inteiros. Isso significa que um OR bit a bit com zero converte um valor em um inteiro (uma apresentação "conceitual" muito simples de operadores bit a bit pode não lidar com a conversão de tipo, mas toda linguagem de programação define operadores para sua própria conveniência, como o Javascript faz aqui) . Ao fazer isso para cada parâmetro, isso garante que, se a função for chamada de um código externo, o valor será convertido para o tipo correto. Isso também é usado no valor de retorno, neste caso, para garantir que o resultado da adição de 1 a i seja um número inteiro (caso contrário, ele poderia se tornar muito grande) e para marcar o tipo de retorno da função. Essas conversões são exigidas pelo asm.js, para que um compilador otimizador possa produzir código nativo ahead-of-time altamente eficiente. Nesse compilador otimizador, nenhuma conversão é executada quando o código asm.js chama outro código asm.js, pois os especificadores de tipo necessários significam que é garantido que os valores já terão o tipo correto. Além disso, em vez de realizar uma adição de ponto flutuante e converter para um número inteiro, ele pode simplesmente fazer uma operação de número inteiro nativo. Juntos, isso leva a benefícios em desempenho significativos.
Aqui está outro exemplo para calcular o comprimento de uma string:
size_t strlen(char *ptr) {
char *curr = ptr;
while (*curr != 0) {
curr++;
}
return (curr - ptr);
}
Isso resultaria no seguinte código em asm.js:
function strlen(ptr) {
ptr = ptr|0;
var curr = 0;
curr = ptr;
while ((MEM8[curr>>0]|0) != 0) {
curr = (curr + 1)|0;
}
return (curr - ptr)|0;
}
No código gerado, a variável MEM8 é na verdade uma "visualização" byte a byte de um buffer tipado, que serve como o "heap" do código em asm.js.
Desempenho
[editar | editar código-fonte]Como o asm.js é executado em um navegador, o desempenho depende muito do navegador e do hardware. Os benchmarks preliminares de programas C compilados para asm.js estão geralmente em um fator de lentidão de 2 em relação à compilação nativa com Clang.[6]
Muito desse ganho de desempenho em relação ao JavaScript normal é devido a 100% de consistência de tipo e virtualmente nenhuma coleta de lixo (a memória é gerenciada manualmente em uma grande matriz tipada). Este modelo mais simples, sem comportamento dinâmico, sem alocação ou desalocação de memória, apenas um conjunto estreito de inteiros bem definidos e operações de ponto flutuante permite um desempenho muito maior e potencial de otimização.
O benchmark da Mozilla de dezembro de 2013 mostrou melhorias significativas: "Firefox com otimizações float32 pode rodar todos esses benchmarks em cerca de 1,5× mais lento do que o nativo, ou melhor."[7] A Mozilla aponta que o desempenho do código compilado nativamente não é uma medida única, mas sim um intervalo, com diferentes compiladores nativos (neste caso Clang e GCC) entregando código de desempenho diferente. "Na verdade, em alguns benchmarks, como Box2D, FASTA e cópia, asm.js é tão próximo ou mais próximo do Clang do que o Clang está do GCC. Em um caso, o asm.js até supera o Clang por pouco no Box2D."[7]
Implementações
[editar | editar código-fonte]O projeto Emscripten fornece ferramentas que podem ser usadas para compilar bases de código C e C ++ (ou qualquer outra linguagem que possa ser convertida para LLVM IR) em asm.js.[2]
Todos os navegadores com suporte para ECMAScript 6 devem ser capazes de executar o código asm.js, pois é um subconjunto dessa especificação. No entanto, como os recursos foram adicionados nessa edição para habilitar o suporte completo para asm.js (Math.fround()
), navegadores mais antigos sem esses recursos podem encontrar problemas.
Algumas implementações de navegador são especialmente otimizadas para asm.js:
- Mozilla Firefox foi o primeiro navegador da web a implementar otimizações específicas do asm.js, começando com o Firefox 22.[3] OdinMonkey, o compilador asm.js da Mozilla usado no Firefox, é um componente do IonMonkey, o compilador JIT do SpiderMonkey.
- A Microsoft está implementando suporte para asm.js em Chakra, o mecanismo JavaScript usado pelo Microsoft Edge, realizando validação para produzir código JIT altamente otimizado.[8]
- As otimizações do motor JavaScript V8 do Google Chrome no Chrome 28 fizeram benchmarks do asm.js mais de duas vezes mais rápido do que as versões anteriores do Chrome,[9] embora o V8 do Chrome não use compilação antecipada.
Adoção
[editar | editar código-fonte]Quase todos os aplicativos atuais baseados em asm.js são aplicativos C/C++ compilados em asm.js usando Emscripten ou Mandreel. Com isso em mente, o tipo de aplicativo que terá como alvo o asm.js em um futuro próximo são aqueles que se beneficiarão da portabilidade de execução em um navegador, mas que têm um nível de complexidade para o qual um porte direto para JavaScript seria inviável.
Até agora, uma série de linguagens de programação, frameworks de aplicativos, programas, bibliotecas, jogos, motores de jogos e outros softwares já foram portados.[10] Alguns deles são listados abaixo.
Linguagens de programação
[editar | editar código-fonte]- C/C++: Clang e LLVM
- Rust: tem como alvo o Emscripten
- Lua VM: Máquina virtual Lua[11]
- Perl: porte de (micro)perl-5.16.3[12]
- Python – porte de CPython[13]
- Ruby – porte de Ruby[14]
Frameworks de aplicativos
[editar | editar código-fonte]- pepper.js: Portes de diversos apps PNaCl (earth, voronoi, bullet, etc.)[15]
- Qt: portes de vários demos da Qt, mais os aplicativos do KDE, como o Kate[16]
Programas e bibliotecas
[editar | editar código-fonte]- OpenGL, SDL, e SDL2[17]
- Vim (Vi IMproved)[18]
- FreeType: renderização de fontes TrueType em JavaScript, usando FreeType[19]
- SQLite[20]
- GNU Privacy Guard[21]
- ctags[22]
- gnuplot[23]
- Graphviz[24]
- zlib[25]
Motores de jogo
[editar | editar código-fonte]- Unreal Engine 3: foi portado em 4 dias[26][27]
- Unreal Engine 4
- Unity[28]
- ScummVM, que suporta vários jogos clássicos de aventura[29]
- Godot[30]
Jogos
[editar | editar código-fonte]- Doom: os ativos do jogo em código aberto Freedoom em execução no PrBoom, que é baseado no código em código aberto Doom[31]
- SuperTux[32]
- Dune II via OpenDune[33]
- BananaBread baseado em Cube 2[34]
- Todos os jogos do Humble Mozilla Bundle[35] (Super Hexagon, AaAaAA! for the Awesome, Osmos, Zen Bound 2, Dustforce DX, Voxatron, FTL: Advanced Edition and Democracy 3)
Emuladores
[editar | editar código-fonte]- EM-DOSBox: um porte do DOSBox para o Emscripten[36]
- Start9.io: uma plataforma de emulação da web visando múltiplas arquiteturas de jogos
- JSMESS: um porte do emulador MESS para muitos consoles de jogos e sistemas de computadores[37]
Matemática
[editar | editar código-fonte]- HTML5 Fractal Playground[38] – desenha fractais gerados por função iterativa, como o conjunto de Mandelbrot.
Deprecação
[editar | editar código-fonte]O asm.js se tornou obsoleto principalmente com a introdução do WebAssembly (wasm), que tem um formato de bytecode que é mais rápido de analisar.[39] Os esforços para estender o JavaScript com mais recursos de baixo nível, como SIMD.js, também foram suspensos desde 2017.[40]
o asm.js permanece útil principalmente como um "substituto" para o wasm, por meio de um programa escrito pela organização WebAssembly que converte o wasm em asm.js. Não há um conversor dedicado de asm.js para wasm, mas os compiladores TypeScript-para-wasm podem ser usados parcialmente.[41] O emissor WebAssembly de referência binaryen costumava conter um módulo asm2wasm
, mas foi removido depois que o Emscripten parou de usá-lo.[42]
Ver também
[editar | editar código-fonte]- Alchemy
- Emscripten
- Google Native Client (NaCl)
- PyPy
- WebAssembly - um bytecode para navegadores, destinado a ser mais rápido de analisar do que asm.js
- ↑ «asm.js in Firefox Nightly». Luke Wagner's blog. 21 de março de 2013. Consultado em 12 de maio de 2021
- ↑ a b «kripken/emscripten · GitHub». Github.com. Consultado em 12 de maio de 2021
- ↑ a b «Firefox 22.0 release notes». Mozilla. Consultado em 12 de maio de 2021
- ↑ «Asm.js». Asm.js. Consultado em 12 de maio de 2021
- ↑ «asm.js — frequently asked questions». Asmjs.org. 26 de julho de 2014
- ↑ «asm.js». Asm.js. Consultado em 12 de maio de 2021
- ↑ a b Alon Zakai; Robert Nyman (20 de dezembro de 2013). «Gap between asm.js and native performance gets even narrower with float32 optimizations». Consultado em 12 de maio de 2021
- ↑ «Bringing Asm.js to Chakra and Microsoft Edge». Microsoft. 7 de maio de 2015. Consultado em 12 de maio de 2021
- ↑ «Chrome 28 Beta: A more immersive web, everywhere». Google. Consultado em 12 de maio de 2021
- ↑ «Home — Demos — Games and Game Engines»
- ↑ «Lua REPL». Kripken.github.io. Consultado em 12 de maio de 2021. Arquivado do original em 8 de junho de 2013
- ↑ «plu». Themucker.github.io. Consultado em 12 de maio de 2021. Arquivado do original em 3 de agosto de 2013
- ↑ «repl.it — Python». Repl.it. Consultado em 12 de maio de 2021
- ↑ «repl.it — Ruby». Repl.it. Consultado em 12 de maio de 2021
- ↑ «pepper.js Examples». Trypepperjs.appspot.com. Consultado em 12 de maio de 2021
- ↑ «emscripten-qt — Demos». Vps.etotheipiplusone.com. Consultado em 12 de maio de 2021
- ↑ «About Emscripten»
- ↑ «Vim.js — JavaScript port of Vim». Coolwanglu.github.io. Consultado em 12 de maio de 2021
- ↑ «TrueType Fonts in JavaScript». Consultado em 12 de maio de 2021. Cópia arquivada em 12 de outubro de 2012
- ↑ «Port of SQLite to Javascript». Github.com. Consultado em 12 de maio de 2021
- ↑ «GnuPG.js». Manuuels.github.io. Consultado em 12 de maio de 2021
- ↑ «ctags in the browser». Github.com. Consultado em 12 de maio de 2021
- ↑ «Gnuplot online». Gnuplot.respawned.com. Consultado em 12 de maio de 2021
- ↑ «A hack to put GraphViz on the web.». Github.com. Consultado em 12 de maio de 2021
- ↑ «JavaScript port of ZLib DEFLATE for the browser». Github.com. Consultado em 12 de maio de 2021
- ↑ «Epic Games Releases 'Epic Citadel' on the Web». UnrealEngine.com (Nota de imprensa). 2 de maio de 2013. Consultado em 12 de maio de 2021. Arquivado do original em 30 de novembro de 2016
- ↑ «Unreal Engine 3 ported to JavaScript and WebGL, works in any modern browser». ExtremeTech. Ziff Davis. Consultado em 12 de maio de 2021
- ↑ «On the future of Web publishing in Unity». Blogs.unity3d.com. 29 de abril de 2014
- ↑ «HTML5». Clb.demon.fi. Consultado em 12 de maio de 2021. Arquivado do original em 6 de março de 2015
- ↑ «Compiling for the Web». godotengine.org. 10 de novembro de 2016
- ↑ «Emscripten-Generated Code». Kripken.github.io. Consultado em 12 de maio de 2021
- ↑ «Emscripten-Generated Code». Forandom.github.io. Consultado em 12 de maio de 2021
- ↑ Guryanov Aleksander. «Dune 2 - Online (browser version)». Epicport. Consultado em 12 de maio de 2021
- ↑ «Mozilla Banana Bread Demo». Developer.mozilla.org. Consultado em 12 de maio de 2021
- ↑ «Humble Mozilla Bundle pushes WebGL-powered browser gaming». Ars Technica. 15 de outubro de 2014. Consultado em 12 de maio de 2021
- ↑ «EM-Dosbox on Github». Consultado em 12 de maio de 2021
- ↑ «Page Redirection». Jsmess.textfiles.com. Consultado em 12 de maio de 2021
- ↑ «HTML5 Fractal Playground». Danielsadvernture.info. Consultado em 12 de maio de 2021. Arquivado do original em 22 de fevereiro de 2015
- ↑ «FAQ». WebAssembly
- ↑ «TC39 proposal for SIMD.js». Ecma TC39. 23 de junho de 2020
- ↑ «WebAssembly/binaryen». GitHub. WebAssembly. 25 de junho de 2020.
AssemblyScript which compiles TypeScript to Binaryen IR; wasm2js which compiles WebAssembly to JS
- ↑ «Binaryen Changelog». GitHub (em inglês).
v97: Remove asm2wasm, which supported Emscripten's fastcomp backend, after fastcomp was removed.
(Ver também PR#3042.)