summaryrefslogtreecommitdiff
path: root/src/js/post.js
blob: c4df418650e4dea88310baf7690c82c24f2f7083 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

function integrateWasmJS(Module) {

  if (typeof WASM === 'object') {
    // Provide an "asm.js function" for the application, called to "link" the asm.js module. We instantiate
    // the wasm module at that time, and it receives imports and provides exports and so forth, the app
    // doesn't need to care that it is wasm and not asm.
    Module['asm'] = function(global, env, providedBuffer) {
      // Load the wasm module
      var binary = Module['readBinary'](Module['wasmCodeFile']);

      // Create an instance of the module using native support in the JS engine.
      var instance = WASM.instantiateModule(binary, {
        "global.Math": global.Math,
        "env": env
      });

      // The wasm instance creates its memory. But static init code might have written to
      // buffer already, and we must copy it over.
      // TODO: avoid this copy, by avoiding such static init writes
      // TODO: in shorter term, just copy up to the last static init write
      var oldBuffer = Module['buffer'];
      var newBuffer = instance.memory;
      assert(newBuffer.byteLength >= oldBuffer.byteLength, 'we might fail if we allocated more than TOTAL_MEMORY');
      // the wasm module does write out the memory initialization, in range STATIC_BASE..STATIC_BUMP, so avoid that
      (new Int8Array(newBuffer).subarray(0, STATIC_BASE)).set(new Int8Array(oldBuffer).subarray(0, STATIC_BASE));
      (new Int8Array(newBuffer).subarray(STATIC_BASE + STATIC_BUMP)).set(new Int8Array(oldBuffer).subarray(STATIC_BASE + STATIC_BUMP));
      updateGlobalBuffer(newBuffer);
      updateGlobalBufferViews();
      Module['reallocBuffer'] = function(size) {
        var old = Module['buffer'];
        wasmJS['asmExports']['__growWasmMemory'](size); // tiny wasm method that just does grow_memory
        return Module['buffer'] !== old ? Module['buffer'] : null; // if it was reallocated, it changed
      };

      return instance;
    };

    return;
  }

  // Use wasm.js to polyfill and execute code in a wasm interpreter.
  var wasmJS = WasmJS({});

  // XXX don't be confused. Module here is in the outside program. wasmJS is the inner wasm-js.cpp.
  wasmJS['outside'] = Module; // Inside wasm-js.cpp, Module['outside'] reaches the outside module.

  // Information for the instance of the module.
  var info = wasmJS['info'] = {
    global: null,
    env: null,
    asm2wasm: { // special asm2wasm imports
      "f64-rem": function(x, y) {
        return x % y;
      },
      "f64-to-int": function(x) {
        return x | 0;
      },
      "debugger": function() {
        debugger;
      },
    },
    parent: Module // Module inside wasm-js.cpp refers to wasm-js.cpp; this allows access to the outside program.
  };

  wasmJS['lookupImport'] = function(mod, base) {
    var lookup = info;
    if (mod.indexOf('.') < 0) {
      lookup = (lookup || {})[mod];
    } else {
      var parts = mod.split('.');
      lookup = (lookup || {})[parts[0]];
      lookup = (lookup || {})[parts[1]];
    }
    lookup = (lookup || {})[base];
    if (lookup === undefined) {
      abort('bad lookupImport to (' + mod + ').' + base);
    }
    return lookup;
  }

  // The asm.js function, called to "link" the asm.js module. At that time, we are provided imports
  // and respond with exports, and so forth.
  Module['asm'] = function(global, env, providedBuffer) {
    assert(providedBuffer === Module['buffer']); // we should not even need to pass it as a 3rd arg for wasm, but that's the asm.js way.

    // wasm code would create its own buffer, at this time. But static init code might have
    // written to the buffer already, and we must copy it over. We could just avoid
    // this copy in wasm.js polyfilling, but to be as close as possible to real wasm,
    // we do what wasm would do.
    // TODO: avoid this copy, by avoiding such static init writes
    // TODO: in shorter term, just copy up to the last static init write
    var oldBuffer = Module['buffer'];
    var newBuffer = ArrayBuffer(oldBuffer.byteLength);
    (new Int8Array(newBuffer)).set(new Int8Array(oldBuffer));
    updateGlobalBuffer(newBuffer);
    updateGlobalBufferViews();
    wasmJS['providedTotalMemory'] = Module['buffer'].byteLength;

    Module['reallocBuffer'] = function(size) {
      var old = Module['buffer'];
      wasmJS['asmExports']['__growWasmMemory'](size); // tiny wasm method that just does grow_memory
      return Module['buffer'] !== old ? Module['buffer'] : null; // if it was reallocated, it changed
    };

    // Prepare to generate wasm, using either asm2wasm or wasm-s-parser
    var method = Module['wasmJSMethod'] || 'asm2wasm';
    assert(method == 'asm2wasm' || method == 'wasm-s-parser');
    var code = Module['read'](method == 'asm2wasm' ? Module['asmjsCodeFile'] : Module['wasmCodeFile']);
    var temp = wasmJS['_malloc'](code.length + 1);
    wasmJS['writeAsciiToMemory'](code, temp);
    if (method == 'asm2wasm') {
      wasmJS['_load_asm2wasm'](temp);
    } else {
      wasmJS['_load_s_expr2wasm'](temp);
    }
    wasmJS['_free'](temp);

    wasmJS['_instantiate'](temp);

    // write the provided data to a location the wasm instance can get at it.
    info.global = global;
    info.env = env;
    wasmJS['_load_mapped_globals'](); // now that we have global and env, we can ready the provided imported globals, copying them to their mapped locations.
    return wasmJS['asmExports'];
  };
}