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

Я прочитал вопрос Как протестировать и разработать с asm.js?, а принятый ответ дает ссылку на http://kripken.github.com/mloc_emscripten_talk/.

Заключение этого слайд-шоу состоит в том, что "языки со статической типизацией и особенно C/C++ могут быть эффективно скомпилированы в JavaScript", поэтому мы можем "ожидать, что скорость скомпилированного C/C++ будет лишь в 2 раза медленнее, чем собственный код, или лучше позже в этом году".

Но как насчет нестатически типизированных языков, таких как обычный JavaScript? Можно ли его скомпилировать в asm.js?

7 ответов

Решение

Может ли сам JavaScript быть скомпилирован в asm.js?

Не совсем, из-за его динамического характера. Это та же проблема, что и при попытке скомпилировать ее в C или даже в нативный код - на самом деле вам нужно будет поставить вместе с ней виртуальную машину, чтобы позаботиться об этих нестатических аспектах. По крайней мере, такая ВМ возможна:

js.js - интерпретатор JavaScript в JavaScript. Вместо того чтобы пытаться создать интерпретатор с нуля, SpiderMonkey компилируется в LLVM, а затем http://emscripten.org/ переводит вывод в JavaScript.

Но если код asmjs работает быстрее, чем обычный JS, то имеет смысл скомпилировать JS в asmjs, нет?

Нет. Asm.js - это довольно ограниченное подмножество JS, которое можно легко перевести в байт-код. Тем не менее, сначала вам нужно разбить все расширенные возможности JS до этого подмножества, чтобы получить это преимущество - довольно сложная задача imo. Но механизмы JavaScript разработаны и оптимизированы для преобразования всех этих расширенных функций непосредственно в байт-код - так зачем беспокоиться о промежуточном шаге, таком как asm.js? Js.js утверждает, что он примерно в 200 раз медленнее, чем "нативный" JS.

А что насчет нестатически типизированных языков в целом?

Слайд-шоу говорит об этом из ... Просто C/C++? и далее. В частности:

Динамические Языки

Целые среды выполнения C / C++ могут быть скомпилированы, а исходный язык интерпретирован с правильной семантикой, но это не так просто

Компиляторы исходного кода из таких языков в JavaScript игнорируют семантические различия (например, числовые типы)

На самом деле, эти языки зависят от специальных виртуальных машин, чтобы быть эффективными

Компиляторы исходного кода для них проигрывают в оптимизации, проведенной на этих виртуальных машинах.

В ответ на общий вопрос "возможно ли это?" тогда ответ таков: конечно, и JavaScript, и подмножество asm.js завершены по Тьюрингу, поэтому существует перевод.

Нужно ли это делать и ожидать выигрыша в производительности - это другой вопрос. Краткий ответ: "Нет, ты не должен". Я сравниваю это с попыткой сжать сжатый файл; да, возможно запустить алгоритм сжатия, но в целом не следует ожидать, что результирующий файл будет меньше.

Краткий ответ: стоимость производительности динамически типизированных языков зависит от значения кода; программа статического типа с эквивалентным значением будет нести те же расходы.

Чтобы понять это, важно понять, почему asm.js вообще дает выигрыш в производительности; или, в более общем плане, почему статически типизированные языки работают лучше, чем динамически типизированные. Краткий ответ: "Проверка типов во время выполнения требует времени", а более длинный ответ может включать улучшенную возможность оптимизации статически типизированного кода. Например:

function a(x) { return x + 1; }
function b(x) { return x - 1; }
function c(x, y) { return a(x) + b(y); }

Если x а также y оба известны как целые числа, я могу оптимизировать функцию c пару инструкций машинного кода. Если бы они могли быть целыми числами или строками, проблема оптимизации становится намного сложнее; Я должен рассматривать их как добавление строки в некоторых случаях и дополнение в других случаях. В частности, существует четыре возможных интерпретации операции сложения, которая происходит в c; это может быть сложение, или добавление строки, или два разных варианта принудительного добавления строки и добавления. Когда вы добавляете больше возможных типов, количество возможных перестановок растет; в худшем случае для языка с динамической типизацией у вас есть k^n возможных интерпретаций выражения, включающего n терминов, каждый из которых может иметь любое количество k типов. В статически типизированном языке k=1, поэтому всегда есть 1 интерпретация любого данного выражения. Из-за этого оптимизаторы существенно более эффективны в оптимизации кода со статической типизацией, чем код с динамической типизацией: при поиске возможностей оптимизации следует учитывать меньше перестановок.

Дело в том, что при преобразовании динамически типизированного кода в статически типизированный (как это было бы при переходе от JavaScript к asm.js), вы должны учитывать семантику исходного кода. Это означает, что проверка типов все еще происходит (она только что была прописана в статически типизированном коде), и все эти перестановки все еще присутствуют, чтобы задушить компилятор.

Несколько фактов о asm.js, которые, как мы надеемся, проясняют концепцию:

  1. Да, вы можете написать диалект asm.js от руки.

    Если вы посмотрите на примеры для asm.js, они очень далеки от удобства использования. Очевидно, Javascript не является языком интерфейса для создания этого кода.

  2. Перевод ванильного Javascript на диалект asm.js невозможен.

    Подумайте об этом - если вы уже можете перевести стандартный Javascript полностью статически, зачем вам нужен asm.js? Единственное существование asm.js означает, что некоторые JIT Javascript отказались от своего обещания, что Javascript будет работать быстрее без каких-либо усилий со стороны разработчика.

    Для этого есть несколько причин, но давайте просто скажем, что JIT было бы очень трудно понять динамический язык так же хорошо, как статический компилятор. И тогда, вероятно, для разработчиков, чтобы полностью понять JIT.

В конце концов, все сводится к использованию правильного инструмента для этой задачи. Если вы хотите статичный, очень производительный код, используйте C / C++ (/ Java) - если вы хотите динамический язык, используйте Javascript, Python,...

asm.js был создан из-за необходимости иметь небольшое подмножество javascript, которое можно легко оптимизировать. Если у вас есть возможность конвертировать javascript в javascript / asm.js, asm.js больше не нужен - этот метод может быть вставлен непосредственно в интерпретаторы js.

Может быть возможно преобразовать обычный JavaScript в ams.js, сначала скомпилировав его в C или C++, а затем скомпилировав сгенерированный код в asm.js, используя Emscripten. Я не уверен, будет ли это практичным, но, тем не менее, это интересная концепция.

Теоретически, можно преобразовать / скомпилировать / перенести любую операцию JavaScript в asm.js, если это можно выразить с помощью ограниченного подмножества языка, представленного в asm.js. На практике, однако, в настоящее время не существует инструмента, способного конвертировать обычный JavaScript в asm.js (июнь 2017 года).

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

Еще в 2013 году, когда asm.js был горячим, была попытка скомпилировать статически типизированный язык, похожий на JavaScript, но и язык, и компилятор, похоже, были заброшены.

Сегодня, в 2017 году, подмножества JavaScipt TypeScript и Flow будут подходящими кандидатами для преобразования в asm.js, но основные команды разработчиков ни на одном языке не заинтересованы в таком преобразовании. У LLJS была вилка, которая могла скомпилироваться в asm.js, но этот проект в значительной степени мертв. ThinScript - это более новая попытка, основанная на TypeScript, но она также не активна.

Итак, лучший и самый простой способ создания кода asm.js - это по-прежнему писать код на C/C++ и конвертировать / компилировать / переносить его. Однако еще неизвестно, хотим ли мы сделать это в обозримом будущем. Веб-сборка может вскоре полностью заменить asm.js, и уже появляются всплывающие языки, подобные TypeScript, такие как TurboScript и AssemblyScript, которые преобразуются в веб- сборку. Фактически, TurboScript изначально был основан на ThinScript и использовался для компиляции в asm.js, но они, похоже, отказались от этой функции.

Проверьте это http://badassjs.com/post/43420901994/asm-js-a-low-level-highly-optimizable-subset-of

в основном вам нужно проверить, что ваш код будет совместим с asm.js (без приведения или приведения типов, вам нужно управлять памятью и т. д.). Идея заключается в том, чтобы написать свой код в javascript, определить "бутылочное горлышко" и внести изменения в свой код для использования asm.js и компиляции aot вместо jit и динамической компиляции... это немного PITA, но вы все равно можете использовать javascript или другой такие языки, как с ++ или лучше.. в ближайшее время, lljs.....

Другие вопросы по тегам