Перевел справку по asm.js. Здесь публикуется только первая глава «Введение». Целиком статью в формате chm можно взять на файлообменнике. Для тех кому интересен другой формат, возьмите здесь архивированную папку с «разобранным» chm'-ом и переделывайте так, как вам нужно. При этом меня желательно не упоминать. В эту папку вложен файл проекта asm.hhp. При наличии установленной программы Microsoft HTML Help Workshop, с его помощью можно вновь собрать chm-файл, после внесенных изменений.

Собственно, справка по asm.js — это всего лишь черновик справки, подготавливаемый к asm.js первой версии. Поэтому, некоторые ссылки (немногие) не работают. Кроме этого, в теле самой справки имеется закомментированный текст — авторы справки готовились дополнить её. Некоторая часть из них мною переведена, но оставлена закомментированной. И ещё, дата последнего изменения оригинала — 18 августа 2014 года, возможно она уже просто заброшена.

1   Введение


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

Язык asm.js предоставляет абстракцию похожую на виртуальную машину C/C++: большая бинарная «куча» с эффективной загрузкой и хранением, арифметика целых чисел и чисел с плавающей запятой, определения функций первого порядка и указатели функций.

Модель программирования


Модель программирования asm.js выстроена вокруг арифметики целых чисел и чисел с плавающей запятой, а также виртуальной «кучи», представленной в виде типизированного массива (typed array).

Хотя JavaScript напрямую не предоставляет конструкций для работы с целыми числами, они могут быть сымитированы двумя обходными способами:

  • загрузка и хранение целых чисел может выполняться с помощью API типизированных массивов; и
  • целочисленная арифметика эквивалентна соединению из JavaScript'овских арифметических операторов для чисел с плавающей запятой и приведениям к целым числам, выполняемым побитовыми операторами.

Как пример вышеуказанного, если имеется представление Int32Array из «кучи» с названием HEAP32, то можно загрузить 32-битное целое число с байтовым смещением p:

HEAP32[p >> 2]|0

Сдвиг конвертирует байтовый сдвиг в сдвиг 32-битного элемента, а побитовое приведение обеспечивает, что обращение извне приведет значение undefined обратно к целому числу.

В качестве примера целочисленной арифметики, сложение может быть выполнено получением двух целочисленных значений, сложением их встроенным оператором сложения и приведением полученного результата обратно к целочисленному значению через побитовый оператор ИЛИ:

(x+y)|0

Данная модель программирования напрямую позаимствована от методов, впервые появившихся в компиляторах Emscripten и Mandreel.

Валидация


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

Проверка (валидация) кода asm.js разработана как «оплата по мере получения» в том, что она никогда не делается с кодом, которому она не требуется.

Модуль (module) asm.js запрашивает валидацию с помощью специальной вводной директивы (prologue directive), аналогичной strict mode (строгому режиму) в ECMAScript Edition 5 версии:

function MyAsmModule() {
    "use asm";
    // тело модуля
}

Такое прямое указание позволяет движкам JavaScript избегать выполнения бессмысленной и возможно затратной валидации в другом коде JavaScript, а также выдавать окна с сообщениями об ошибках валидации только когда это уместно.

«Ранняя» компиляция


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

Тем не менее, код asm.js прошедший валидацию поддается «ранней» (ahead-of-time — AOT) компиляции. Однако, код сгенерированный AOT-компилятором может быть довольно эффективным, показывая:

  • распакованные представления целых чисел и чисел с плавающей запятой;
  • отсутствие проверок типа во время выполнения;
  • отсутствие сборки мусора; и
  • эффективная загрузка и хранение «кучи» (с методами реализации, изменяющимися в зависимости от платформы).

Код, который не удается проверить должен вернуться к исполнению по традиционным меркам, например, интерпретации и/или оперативной компиляции.

Связывание


Использование модуля asm.js требует вызова его функции для получения объекта, содержащего экспортирование модуля; это называется связывание.

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

Этот рисунок отображает простейшую архитектуру AOT реализации, которая в противном случае использует обычный интерпретатор.
Если либо динамическая, либо статическая валидация не удается, реализация должна вернуться назад к интерпретатору.
Но если оба вида валидации выполнены успешно, вызывается экспортирование модуля, выполняющего бинарный исполняемый код, сгенерированный AOT компиляцией.



Внешний код и данные


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

Модуль asm.js может принимать до трех дополнительных параметров, предоставляя доступ к внешнему JavaScript'овским коду и данным:

  • объект стандартная библиотека (standard library), предоставляет доступ к ограниченному вложенному набору JavaScript'овских стандартных библиотек;
  • интерфейс внешней функции (foreign function interface — FFI), предоставляет доступ к пользовательским внешним JavaScript функциям; и
  • буфер «кучи» (heap buffer), предоставляет отдельный ArrayBuffer, действующий в качестве asm.js «кучи».

Эти объекты позволяют asm.js делать вызов во внешний JavaScript (и совместно с внешним JavaScript'ом использовать буфер «кучи»). И наоборот, экспортирование объекта, возвращенного из модуля позволяет внешнему JavaScript'у делать вызов в asm.js.

Так что в общем случае, объявление asm.js модуля выглядит как:

function MyAsmModule(stdlib, foreign, heap) {
    "use asm";<br>
    // тело модуля...<br>
    return {
        export1: f1,
        export2: f2,
        // ...
    };
}

Параметры функций в asm.js снабжаются метками типа, посредством явного воздействия на входе функции:

function geometricMean(start, end) {
  start = start|0; // переменная start типа int
  end = end|0;     // переменная end типа int
  return +exp(+logSum(start, end) / +((end - start)|0));
}

Эти метки служат двум целям: во-первых, для снабжения типа функции сигнатурой, так чтобы валидатор мог обеспечить соблюдение того, что все вызовы к функции правильно типизированы;
во-вторых, для гарантии, что даже если функция экспортирована и вызывается внешним JavaScript'ом, её аргументы динамически приводятся к предполагаемому типу.

Это гарантирует, что реализация AOT может использовать неупакованные значения представлений, зная, что по завершении динамического приведения, тело функции никогда не потребует каких-либо проверок типа во время выполнения.

Сложим все вместе


Ниже небольшой, но полный пример модуля asm.js.

function GeometricMean(stdlib, foreign, buffer) {
  "use asm";
  var exp = stdlib.Math.exp;
  var log = stdlib.Math.log;
  var values = new stdlib.Float64Array(buffer);
  function logSum(start, end) {
    start = start|0;
    end = end|0;
    var sum = 0.0, p = 0, q = 0;<br>
    // asm.js forces byte addressing of the heap by requiring shifting by 3
    for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {
      sum = sum + +log(values[p>>3]);
    }
    return +sum;
  }
  function geometricMean(start, end) {
    start = start|0;
    end = end|0;
    return +exp(+logSum(start, end) / +((end - start)|0));
  }
  return { geometricMean: geometricMean };
}

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

var heap = new ArrayBuffer(0x10000);          // 64k heap
init(heap, START, END);                       // fill a region with input values
var fast = GeometricMean(window, null, heap); // produce exports object linked to AOT-compiled code
fast.geometricMean(START, END);               // computes geometric mean of input values

С другой стороны, вызов модуля на объекте стандартной библиотеки, содержащей нечто другое чем истина, Math.exp или Math.log будут не в состоянии произвести AOT-компилированный код.

var bogusGlobal = {
  Math: {
    exp: function(x) { return x; },
    log: function(x) { return x; }
  },
  Float64Array: Float64Array
};

var slow = GeometricMean(bogusGlobal, null, heap); // produces purely-interpreted/JITted version
console.log(slow.geometricMean(START, END));       // computes bizarro-geometric mean thanks to bogusGlobal

Комментарии (9)


  1. Yeah
    08.12.2015 12:48
    +11

    .rar — серьёзно?


    1. denis_g
      08.12.2015 21:24
      +4

      .chm — серьёзно?


      1. v673
        08.12.2015 22:42

        Судя по комментариям в профиле автора он просто .chm-евангелист. :)


  1. rbobot
    08.12.2015 13:08
    +10

    Лучше на гитхаб чем вот так в файликах на обменниках, где файлы проживут месяц.


  1. bromzh
    08.12.2015 13:28
    +16

    .chm, .rar, файлопомойки…

    readthedocs.org
    github.com


    1. Keyten
      08.12.2015 17:17
      +5

      .chm, .rar, файлопомойки…

      Как будто лет на 5 в прошлое


  1. Stepanow
    08.12.2015 14:57
    +2

    1. Stepanow
      08.12.2015 15:28

      Кстати, вывести все книги Gibook на русском языке можно так: www.gitbook.com/search?q=language%3Aru


  1. mibori
    08.12.2015 15:07
    +9

    Желание быть непричастным к созданию какого-либо перевода/документации именно в теме javascript выглядит весьма интересно.