Asm.js, универсальная совместимость приложений

Это подмножество JavaScript, определенное Mozilla, дает приложениям и играм почти скорость нативного кода.

Значение виртуальной машины в браузере, позволяющей компилировать и запускать разные языки во всех операционных системах, давно рассматривалось. Эта идея оформилась благодаря разработчикам Mozilla, и Asm.js был реализован в SpiderMonkey в 2013 году.

Capture of Unreal Engine 3 video with Asm.js

Unreal Engine 3 с видео Asm.js

Это не фактический байт-код, а подмножество JavaScript, которое скомпилировано и оптимизировано для скорости. Код Asm.js компилируется AOT (раз и навсегда - до смены исходников), в то время как код JavaScript компилируется JIT, на лету.

Различные статически типизированные языки могут быть скомпилированы в биткод LLVM, затем с помощью Emscriptem преобразовать его в Asm.js. Так как исходный код уже оптимизирован, это производит более быстрый JavaScript, и Asm.js также обеспечивает скорость, которая в два раза медленнее, чем бинарный, но в десять раз быстрее, чем JavaScript .
Целое приложение может быть преобразовано в Asm.js, или просто библиотека с другого языка может использоваться JavaScript-программой.

Вместе с производителем игр Epic компания Mozilla реализовала в Asm.js (видео) 3D-движок Unreal Engine 3. Это побудило разработчиков V8 оптимизировать компиляторы JavaScript Chrome и Node.js для Asm.js. Opera также оптимизирована под код Asm.js. Microsoft, со своей стороны, объявила о внедрении Asm.js в Windows 10 и сотрудничает с Mozilla для достижения этой цели.

С момента последней оптимизации в декабре 2013 года для выполнения одной и той же программы коду Asm.js требуется в 1,5 раза больше времени, чем нативному коду.

Asm.js реализован в новом браузере Edge от Microsoft, с помощью Mozilla. Это обсуждалось в нескольких сообщениях компании, в том числе под названием: Bringing Asm.js to Chackra в Microsoft Edge.

Особенности

Diagram of compilation to Asm.js
Из C в LLVM биткод в Asm.js

Asm.js совместим с JavaScript и не предоставляет дополнительной функциональности. Однако для проверки и компиляции он должен содержать только подмножество, определенное спецификацией.

Воспользоваться Asm.js можно только в том случае, если компилируемый язык имеет статические типы, ведь именно здесь Asm.js находит свою скорость. Вместо этого динамический язык должен быть скомпилирован в простой JavaScript для запуска в браузере.

Asm.js против Native Client против WebAssembly

Какое решение предпочесть: Asm.js или NaCl, проще говоря, программы, скомпилированные в биткод для LLVM, которые тоже запускаются в браузере?

Программа под NaCl, даже если она работает в браузере, должна быть скомпилирована под каждую операционную систему. Поэтому создатель должен предоставить несколько версий, чего нет в Asm.js, который одинаково работает на всех системах. Зная, что Mozilla не хочет внедрять NaCl, это исключает его из Firefox, и, видимо, из Internet Explorer в том числе.

Asm.js работает автоматически, так как JS-компилятор уже существует в каждом браузере. Мы знаем, как его оптимизировать, и для его работы на V8 или других JIT (Just-In-Time) или AOT (Ahead-Of-Time) фреймворках требуется лишь несколько незначительных модификаций.

Анонс WebAssembly в июне 2015 года делает NaCl устаревшим, тем более что он будет поддерживаться всеми браузерами, тогда как NaCl - нет. только Chrome. Но это не так для Asm.js, с которым он будет сосуществовать. Фактически код WebAssembly будет похож на код Asm.js изначально, до расхождения. Wasm можно конвертировать в Asm.js для работы на старых браузерах. Он также может использоваться в модулях JavaScript или Asm.js.

Пример кода

Определяем функцию strlen и выводим буквы строки.

JavaScript:

function strlen(ptr)
{
var curr = ptr;
while(MEM8[curr] != 0)
curr++;
return (curr - ptr);
}

var ptr = "demo";
var len = strlen(ptr);
for(var i = 0; i < len; i++)
{ 
document.write(ptr[i]);
}

Asm.js:

function strlen(ptr)
{ 
ptr = ptr | 0; 
var curr = 0; 
curr = ptr; 
while (MEM8[curr]|0 != 0) 
{ 
curr = (curr + 1) | 0; 
} 
return (curr - ptr) | 0;
}

var ptr = "demo";
var len = strlen(ptr) | 0;
for(var i = 0; i < len; i++)
{ 
document.write(ptr[i]);
}

I do not guarantee that document.write is validated, it is there for demonstration.

Emscriptem with the ASM_JS=1 option produces Asm.js code instead of JavaScript.

Documentation