📜 ⬆️ ⬇️

asm.js

Translated help on asm.js. Only the first chapter, Introduction, is published here. An entire article in chm format can be taken on a file sharing service . For those who are interested in a different format, take here the archived folder with the “parsed” chm'th and redo it as you need. In this case, it is advisable not to mention me. The project file asm.hhp is attached to this folder. If you have installed the program Microsoft® HTML Help Workshop, you can use it to re-assemble the chm-file after the changes are made.

Actually, the asm.js help is just a draft of a help, prepared for asm.js of the first version. Therefore, some links (few) do not work. In addition, there is a commented text in the body of the certificate itself - the authors of the certificate were preparing to supplement it. Some of them have been translated by me, but left commented out. And yet, the date of the last change to the original is August 18, 2014, maybe it’s already just abandoned.

1. Introduction


This description defines asm.js , a nested JavaScript complex that can be used as a low-level, rational target language for compilers.

The asm.js language provides an abstraction similar to a C / C ++ virtual machine: a large binary heap with efficient loading and storage, arithmetic of integers and floating point numbers, definitions of first-order functions and function pointers.
')

Programming model


The asm.js programming model is built around the arithmetic of integers and floating-point numbers, as well as a virtual heap, represented as a typed array .

Although JavaScript does not directly provide constructs for working with integers, they can be simulated by two ways:


As an example of the above, if there is an Heap32 Int32Array representation called HEAP32, then you can load a 32-bit integer with a byte offset p:

  HEAP32 [p >> 2] | 0

The shift converts the byte shift to the shift of the 32-bit element, and the bitwise cast ensures that reversing from the outside will result in the value undefined back to an integer.

As an example of integer arithmetic, addition can be performed by obtaining two integer values, adding them with the built-in addition operator and bringing the result back to an integer value via the bitwise OR operator:

  (x + y) | 0

This programming model is directly borrowed from the methods first introduced in the Emscripten and Mandreel compilers .

Validation


The dialect of the programming language asm.js is defined by a static type system, which can be checked during JavaScript parsing.

The verification (validation) of the asm.js code is designed as “pay as you receive” in that it is never done with code that does not require it.

The module (module) asm.js requests validation using a special introductory directive (prologue directive), similar to strict mode in ECMAScript Edition 5 version:

  function MyAsmModule () {
     "use asm";
     // module body
 }

Such a direct indication allows the JavaScript engines to avoid performing meaningless and possibly costly validation in other JavaScript code, and also to issue windows with validation error messages only when appropriate.

"Early" compilation


Since asm.js is a nested complex that strictly adheres to the rules of the JavaScript language, this specification defines only a logic check — semantic analysis is left to JavaScript.

However, the asm.js code that has been validated is amenable to “early” (ahead-of-time — AOT) compilation. However, the code generated by the AOT compiler can be quite effective, showing:


Code that fails to check should return to execution by traditional standards, for example, interpretation and / or operational compilation.

Binding


Using the asm.js module requires calling its function to obtain an object containing the export of the module; this is called binding .

The asm.js module, through binding, can also be given access to standard libraries and user-defined JavaScript functions.
An AOT implementation must perform certain dynamic checks to check, at compile time, assumptions about linking libraries for use in compiled code.

This figure represents the simplest AOT implementation architecture, which would otherwise use a common interpreter.
If either dynamic or static validation fails, the implementation should return to the interpreter.
But if both types of validation are successful, the export of the module that executes the binary executable code generated by the AOT compilation is called.



External code and data


Inside the asm.js module, all code is fully statically typed and limited to the very rigid asm.js dialect. However, it is possible to interact with recognized standard JavaScript libraries and even custom dynamic JavaScript functions.

The asm.js module can take up to three additional parameters, providing access to external JavaScript code and data:


These objects allow asm.js to make a call to external JavaScript (and use heaps buffer together with external JavaScript). Conversely, exporting an object returned from a module allows external JavaScript to make a call to asm.js.

So, in general, the declaration of the asm.js module looks like:

  function MyAsmModule (stdlib, foreign, heap) {
     "use asm"; <br>
     // module body ... <br>
     return {
         export1: f1,
         export2: f2,
         // ...
     };
 }

The function parameters in asm.js are supplied with type labels, by explicitly affecting the input of the function:

  function geometricMean (start, end) {
   start = start | 0;  // start variable of type int
   end = end | 0;  // end variable of int type
   return + exp (+ logSum (start, end) / + ((end - start) | 0));
 }

These labels serve two purposes: first, to provide the function type with a signature, so that the validator can ensure that all calls to the function are correctly typed;
secondly, to ensure that even if the function is exported and called by external JavaScript, its arguments are dynamically cast to the intended type.

This ensures that the AOT implementation can use the unpacked values ​​of the views, knowing that upon completion of the dynamic cast, the function body will never require any type checks at run time.

Put it all together


Below is a small but complete example of the asm.js module.

  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 switching 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};
 }

In a JavaScript engine that supports AOT compiling asm.js, invoking a module on its own global object and heap buffer will bind the exported object to use with statically compiled functions.

  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

On the other hand, calling a module on a standard library object containing something other than true, Math.exp or Math.log will not be able to produce AOT-compiled code.

  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

Source: https://habr.com/ru/post/271891/


All Articles