~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to src/jsifier.js

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-09-20 22:44:35 UTC
  • mfrom: (4.1.1 sid)
  • Revision ID: package-import@ubuntu.com-20130920224435-apuwj4fsl3fqv1a6
Tags: 1.5.6~20130920~6010666-1
* New snapshot release
* Update the list of supported architectures to the same as libv8
  (Closes: #723129)
* emlibtool has been removed from upstream.
* Fix warning syntax-error-in-dep5-copyright
* Refresh of the patches

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
 
15
15
var SETJMP_LABEL = -1;
16
16
 
 
17
var INDENTATION = ' ';
 
18
 
 
19
var functionStubSigs = {};
 
20
 
17
21
// JSifier
18
22
function JSify(data, functionsOnly, givenFunctions) {
19
23
  var mainPass = !functionsOnly;
20
24
 
21
25
  if (mainPass) {
22
 
    var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB ? 'shell_sharedlib.js' : 'shell.js');
 
26
    var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'shell_sharedlib.js' : 'shell.js');
23
27
 
24
28
    if (phase == 'pre') {
25
29
      // We will start to print out the data, but must do so carefully - we are
42
46
      // things out as they are ready.
43
47
 
44
48
      var shellParts = read(shellFile).split('{{BODY}}');
45
 
      print(shellParts[0]);
46
 
      var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js';
 
49
      print(processMacros(preprocess(shellParts[0])));
 
50
      var preFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'preamble_sharedlib.js' : 'preamble.js';
47
51
      var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime())));
48
52
      print(pre);
49
53
 
 
54
      // Populate implementedFunctions. Note that this is before types, and will be updated later.
50
55
      data.unparsedFunctions.forEach(function(func) {
51
56
        Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type }));
52
57
      });
76
81
    if (phase == 'pre') {
77
82
      var libFuncsToInclude;
78
83
      if (INCLUDE_FULL_LIBRARY) {
79
 
        assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.')
 
84
        assert(!(BUILD_AS_SHARED_LIB || SIDE_MODULE), 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB/SIDE_MODULE set.')
80
85
        libFuncsToInclude = [];
81
86
        for (var key in LibraryManager.library) {
82
87
          if (!key.match(/__(deps|postset|inline|asm|sig)$/)) {
262
267
      assert(!item.lines); // FIXME remove this, after we are sure it isn't needed
263
268
      var ret = [item];
264
269
      if (item.ident == '_llvm_global_ctors') {
265
 
        item.JS = '\n__ATINIT__ = __ATINIT__.concat([\n' +
266
 
                    item.ctors.map(function(ctor) { return '  { func: function() { ' + ctor + '() } }' }).join(',\n') +
267
 
                  '\n]);\n';
 
270
        item.JS = '\n/* global initializers */ __ATINIT__.push(' +
 
271
                    item.ctors.map(function(ctor) { return '{ func: function() { ' + ctor + '() } }' }).join(',') +
 
272
                  ');\n';
268
273
        return ret;
269
274
      }
270
275
 
276
281
        // they would shadow similarly-named globals in the parent.
277
282
        item.JS = '';
278
283
      } else {
279
 
        item.JS = makeGlobalDef(item.ident);
 
284
        item.JS = makeGlobalDef(item.ident);
280
285
      }
281
286
 
282
287
      if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) {
283
288
        index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this
284
289
        allocator = 'ALLOC_NONE';
285
290
      }
286
 
      if (item.external) {
287
 
        if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
288
 
          constant = zeros(Runtime.getNativeFieldSize(item.type));
 
291
 
 
292
      Variables.globals[item.ident].named = item.named;
 
293
 
 
294
      if (ASM_JS && (MAIN_MODULE || SIDE_MODULE) && !item.private_ && !NAMED_GLOBALS && isIndexableGlobal(item.ident)) {
 
295
        // We need this to be named (and it normally would not be), so that it can be linked to and used from other modules
 
296
        Variables.globals[item.ident].linkable = 1;
 
297
      }
 
298
 
 
299
      if (isBSS(item)) {
 
300
        var length = calcAllocatedSize(item.type);
 
301
        length = Runtime.alignMemory(length);
 
302
 
 
303
        // If using indexed globals, go ahead and early out (no need to explicitly
 
304
        // initialize).
 
305
        if (!NAMED_GLOBALS) {
 
306
          return ret;
 
307
        }
 
308
        // If using named globals, we can at least shorten the call to allocate by
 
309
        // passing an integer representing the size of memory to alloc instead of
 
310
        // an array of 0s of size length.
 
311
        else {
 
312
          constant = length;
 
313
        }
 
314
      } else {
 
315
        if (item.external) {
 
316
          if (Runtime.isNumberType(item.type) || isPointerType(item.type)) {
 
317
            constant = zeros(Runtime.getNativeFieldSize(item.type));
 
318
          } else {
 
319
            constant = makeEmptyStruct(item.type);
 
320
          }
289
321
        } else {
290
 
          constant = makeEmptyStruct(item.type);
291
 
        }
292
 
      } else {
293
 
        constant = parseConst(item.value, item.type, item.ident);
294
 
      }
295
 
      assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);
296
 
 
297
 
      // This is a flattened object. We need to find its idents, so they can be assigned to later
298
 
      constant.forEach(function(value, i) {
299
 
        if (needsPostSet(value)) { // ident, or expression containing an ident
300
 
          ret.push({
301
 
            intertype: 'GlobalVariablePostSet',
302
 
            JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
303
 
          });
304
 
          constant[i] = '0';
305
 
        }
306
 
      });
307
 
 
308
 
      if (item.external) {
309
 
        // External variables in shared libraries should not be declared as
310
 
        // they would shadow similarly-named globals in the parent, so do nothing here.
311
 
        if (BUILD_AS_SHARED_LIB) return ret;
312
 
        // Library items need us to emit something, but everything else requires nothing.
313
 
        if (!LibraryManager.library[item.ident.slice(1)]) return ret;
314
 
      }
315
 
 
316
 
      // ensure alignment
317
 
      constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length));
318
 
 
319
 
      // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations
320
 
      if (item.ident.substr(0, 5) == '__ZTV') {
321
 
        constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE)));
 
322
          constant = parseConst(item.value, item.type, item.ident);
 
323
        }
 
324
        assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);
 
325
 
 
326
        // This is a flattened object. We need to find its idents, so they can be assigned to later
 
327
        var structTypes = null;
 
328
        constant.forEach(function(value, i) {
 
329
          if (needsPostSet(value)) { // ident, or expression containing an ident
 
330
            if (!structTypes) structTypes = generateStructTypes(item.type);
 
331
            ret.push({
 
332
              intertype: 'GlobalVariablePostSet',
 
333
              JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
 
334
            });
 
335
            constant[i] = '0';
 
336
          }
 
337
        });
 
338
 
 
339
        if (item.external) {
 
340
          // External variables in shared libraries should not be declared as
 
341
          // they would shadow similarly-named globals in the parent, so do nothing here.
 
342
          if (BUILD_AS_SHARED_LIB) return ret;
 
343
          if (SIDE_MODULE) return [];
 
344
          // Library items need us to emit something, but everything else requires nothing.
 
345
          if (!LibraryManager.library[item.ident.slice(1)]) return ret;
 
346
        }
 
347
 
 
348
        // ensure alignment
 
349
        constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length));
 
350
 
 
351
        // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations
 
352
        if (item.ident.substr(0, 5) == '__ZTV') {
 
353
          constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE)));
 
354
        }
322
355
      }
323
356
 
324
357
      // NOTE: This is the only place that could potentially create static
328
361
      var js = (index !== null ? '' : item.ident + '=') + constant;
329
362
      if (js) js += ';';
330
363
 
331
 
      if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) {
 
364
      if (!ASM_JS && NAMED_GLOBALS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) {
332
365
        js += '\nModule["' + item.ident + '"] = ' + item.ident + ';';
333
366
      }
334
367
      if (BUILD_AS_SHARED_LIB == 2 && !item.private_) {
354
387
      // Set the actual value in a postset, since it may be a global variable. We also order by dependencies there
355
388
      Variables.globals[item.ident].targetIdent = item.value.ident;
356
389
      var value = Variables.globals[item.ident].resolvedAlias = finalizeLLVMParameter(item.value);
357
 
      var fix = '';
358
 
      if (BUILD_AS_SHARED_LIB == 2 && !item.private_) {
359
 
        var target = item.ident;
360
 
        if (isFunctionType(item.type)) {
361
 
          target = item.value.ident; // the other side does not know this is an alias/function table index. So make it the alias target.
362
 
          var varData = Variables.globals[target];
363
 
          assert(!varData, 'multi-level aliasing does not work yet in shared lib 2 exports');
364
 
        }
365
 
        fix = '\nif (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + target + ' }'
 
390
      if ((MAIN_MODULE || SIDE_MODULE) && isFunctionType(item.type)) {
 
391
        var target = item.value.ident;
 
392
        if (!Functions.aliases[target]) Functions.aliases[target] = [];
 
393
        Functions.aliases[target].push(item.ident);
366
394
      }
367
 
      ret.push({
368
 
        intertype: 'GlobalVariablePostSet',
369
 
        ident: item.ident,
370
 
        dependencies: set([value]),
371
 
        JS: item.ident + ' = ' + value + ';' + fix
372
 
      });
373
395
      return ret;
374
396
    }
375
397
  });
391
413
  // functionStub
392
414
  substrate.addActor('FunctionStub', {
393
415
    processItem: function(item) {
 
416
      // note the signature
 
417
      if (item.returnType && item.params) {
 
418
        functionStubSigs[item.ident] = Functions.getSignature(item.returnType.text, item.params.map(function(arg) { return arg.type }), false);
 
419
      }
 
420
 
394
421
      function addFromLibrary(ident) {
395
422
        if (ident in addedLibraryItems) return '';
396
423
        addedLibraryItems[ident] = true;
431
458
 
432
459
        var postsetId = ident + '__postset';
433
460
        var postset = LibraryManager.library[postsetId];
434
 
        if (postset && !addedLibraryItems[postsetId]) {
 
461
        if (postset && !addedLibraryItems[postsetId] && !SIDE_MODULE) {
435
462
          addedLibraryItems[postsetId] = true;
436
463
          ret.push({
437
464
            intertype: 'GlobalVariablePostSet',
474
501
            Functions.libraryFunctions[ident.substr(1)] = 2;
475
502
          }
476
503
        }
 
504
        if (SIDE_MODULE) return ';'; // we import into the side module js library stuff from the outside parent 
477
505
        if ((!ASM_JS || phase == 'pre') &&
478
506
            (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS))) {
479
507
          contentText += '\nModule["' + ident + '"] = ' + ident + ';';
588
616
          var associatedSourceFile = "NO_SOURCE";
589
617
      }
590
618
      
 
619
      if (DLOPEN_SUPPORT) Functions.getIndex(func.ident);
 
620
 
591
621
      func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n';
592
622
 
593
623
      if (PGO) {
594
 
        func.JS += '  PGOMonitor.called["' + func.ident + '"] = 1;\n';
 
624
        func.JS += INDENTATION + 'PGOMonitor.called["' + func.ident + '"] = 1;\n';
595
625
      }
596
626
 
597
627
      if (ASM_JS) {
598
628
        // spell out argument types
599
629
        func.params.forEach(function(param) {
600
 
          func.JS += '  ' + param.ident + ' = ' + asmCoercion(param.ident, param.type) + ';\n';
 
630
          func.JS += INDENTATION + param.ident + ' = ' + asmCoercion(param.ident, param.type) + ';\n';
601
631
        });
602
632
 
603
633
        // spell out local variables
611
641
            i += chunkSize;
612
642
          }
613
643
          for (i = 0; i < chunks.length; i++) {
614
 
            func.JS += '  var ' + chunks[i].map(function(v) {
 
644
            func.JS += INDENTATION + 'var ' + chunks[i].map(function(v) {
615
645
              var type = getImplementationType(v);
616
646
              if (!isIllegalType(type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal
617
647
                return v.ident + ' = ' + asmInitializer(type); //, func.variables[v.ident].impl);
627
657
 
628
658
      if (true) { // TODO: optimize away when not needed
629
659
        if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
630
 
        func.JS += '  var label = 0;\n';
 
660
        func.JS += INDENTATION + 'var label = 0;\n';
631
661
      }
632
662
 
633
663
      if (ASM_JS) {
636
666
          hasByVal = hasByVal || param.byVal;
637
667
        });
638
668
        if (hasByVal) {
639
 
          func.JS += '  var tempParam = 0;\n';
 
669
          func.JS += INDENTATION + 'var tempParam = 0;\n';
640
670
        }
641
671
      }
642
672
 
 
673
      if (func.hasVarArgsCall) {
 
674
        func.JS += INDENTATION + 'var tempVarArgs = 0;\n';
 
675
      }
 
676
 
643
677
      // Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up.
644
 
      func.JS += '  ' + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n';
 
678
      func.JS += INDENTATION + RuntimeGenerator.stackEnter(func.initialStack, func.otherStackAllocations) + ';\n';
645
679
 
646
680
      // Make copies of by-value params
647
681
      // XXX It is not clear we actually need this. While without this we fail, it does look like
654
688
        if (param.byVal) {
655
689
          var type = removePointing(param.type);
656
690
          var typeInfo = Types.types[type];
657
 
          func.JS += '  ' + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' +
 
691
          func.JS += INDENTATION + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' +
658
692
                     makeCopyValues(param.ident, 'tempParam', typeInfo.flatSize, 'null', null, param.byVal) + ';\n';
659
693
        }
660
694
      });
693
727
              }
694
728
            }
695
729
            i++;
696
 
            return JS + (Debugging.on ? Debugging.getComment(line.lineNum) : '');
 
730
            // invoke instructions span two lines, and the debug info is located
 
731
            // on the second line, hence the +1
 
732
            return JS + (Debugging.on ? Debugging.getComment(line.lineNum + (line.intertype === 'invoke' ? 1 : 0)) : '');
697
733
          })
698
734
                                  .join('\n')
699
735
                                  .split('\n') // some lines include line breaks
728
764
            }
729
765
            ret += 'switch(' + asmCoercion('label', 'i32') + ') {\n';
730
766
            ret += block.labels.map(function(label) {
731
 
              return indent + '  case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
732
 
                            + getLabelLines(label, indent + '    ');
 
767
              return indent + INDENTATION + 'case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
 
768
                            + getLabelLines(label, indent + INDENTATION + INDENTATION);
733
769
            }).join('\n') + '\n';
734
770
            if (func.setjmpTable && ASM_JS) {
735
771
              // emit a label in which we write to the proper local variable, before jumping to the actual label
736
 
              ret += '  case ' + SETJMP_LABEL + ': ';
 
772
              ret += INDENTATION + 'case ' + SETJMP_LABEL + ': ';
737
773
              ret += func.setjmpTable.map(function(triple) { // original label, label we created for right after the setjmp, variable setjmp result goes into
738
774
                return 'if ((setjmpLabel|0) == ' + getLabelId(triple.oldLabel) + ') { ' + triple.assignTo + ' = threwValue; label = ' + triple.newLabel + ' }\n';
739
775
              }).join(' else ');
741
777
              ret += '__THREW__ = threwValue = 0;\n';
742
778
              ret += 'break;\n';
743
779
            }
744
 
            if (ASSERTIONS) ret += indent + '  default: assert(0' + (ASM_JS ? '' : ', "bad label: " + label') + ');\n';
 
780
            if (ASSERTIONS) ret += indent + INDENTATION + 'default: assert(0' + (ASM_JS ? '' : ', "bad label: " + label') + ');\n';
745
781
            ret += indent + '}\n';
746
782
            if (func.setjmpTable && !ASM_JS) {
747
783
              ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](e.value) }';
764
800
            var label = block.labels[i];
765
801
            var content = getLabelLines(label, '', true);
766
802
            //printErr(func.ident + ' : ' + label.ident + ' : ' + content + '\n');
767
 
            blockMap[label.ident] = Relooper.addBlock(content);
 
803
            var last = label.lines[label.lines.length-1];
 
804
            if (!last.signedIdent) {
 
805
              blockMap[label.ident] = Relooper.addBlock(content);
 
806
            } else {
 
807
              assert(last.intertype == 'switch');
 
808
              blockMap[label.ident] = Relooper.addBlock(content, last.signedIdent);
 
809
            }
768
810
          }
769
811
          // add branchings
770
812
          function relevant(x) { return x && x.length > 2 ? x : 0 } // ignores ';' which valueJS and label*JS can be if empty
797
839
        }
798
840
        return ret;
799
841
      }
800
 
      func.JS += walkBlock(func.block, '  ');
 
842
      func.JS += walkBlock(func.block, INDENTATION);
801
843
      // Finalize function
802
844
      if (LABEL_DEBUG && functionNameFilterTest(func.ident)) func.JS += "  INDENT = INDENT.substr(0, INDENT.length-2);\n";
803
845
      // Ensure a return in a function with a type that returns, even if it lacks a return (e.g., if it aborts())
804
846
      if (RELOOP && func.lines.length > 0 && func.returnType != 'void') {
805
847
        var returns = func.labels.filter(function(label) { return label.lines[label.lines.length-1].intertype == 'return' }).length;
806
 
        if (returns == 0) func.JS += '  return ' + asmCoercion('0', func.returnType);
 
848
        if (returns == 0) func.JS += INDENTATION + 'return ' + asmCoercion('0', func.returnType);
807
849
      }
808
850
      func.JS += '}\n';
809
851
      
825
867
      }
826
868
 
827
869
      func.JS = func.JS.replace(/\n *;/g, '\n'); // remove unneeded lines
 
870
 
 
871
      if (MAIN_MODULE || SIDE_MODULE) {
 
872
        // Clone the function for each of its aliases. We do not know which name it will be used by in another module,
 
873
        // and we do not have a heavyweight metadata system to resolve aliases during linking
 
874
        var aliases = Functions.aliases[func.ident];
 
875
        if (aliases) {
 
876
          var body = func.JS.substr(func.JS.indexOf('('));
 
877
          aliases.forEach(function(alias) {
 
878
            func.JS += '\n' + 'function ' + alias + body;
 
879
          });
 
880
        }
 
881
      }
 
882
 
828
883
      return func;
829
884
    }
830
885
  });
1081
1136
    }
1082
1137
  });
1083
1138
  makeFuncLineActor('switch', function(item) {
1084
 
    var useIfs = RELOOP || item.switchLabels.length < 1024; // with a huge number of cases, if-else which looks nested to js parsers can cause problems
 
1139
    // use a switch if the range is not too big or sparse
 
1140
    var minn = Infinity, maxx = -Infinity;
 
1141
    item.switchLabels.forEach(function(switchLabel) {
 
1142
      var curr = Math.abs(parseInt(switchLabel.value));
 
1143
      minn = Math.min(minn, curr);
 
1144
      maxx = Math.max(maxx, curr);
 
1145
    });
 
1146
    var range = maxx - minn;
 
1147
    var useIfs = (item.switchLabels.length+1) < 6 || range > 10*1024 || (range/item.switchLabels.length) > 1024; // heuristics
 
1148
    if (VERBOSE && useIfs && item.switchLabels.length >= 6) {
 
1149
      warn('not optimizing llvm switch into js switch because range of values is ' + range + ', density is ' + range/item.switchLabels.length);
 
1150
    }
 
1151
 
1085
1152
    var phiSets = calcPhiSets(item);
1086
1153
    // Consolidate checks that go to the same label. This is important because it makes the relooper simpler and faster.
1087
1154
    var targetLabels = {}; // for each target label, the list of values going to it
1095
1162
    });
1096
1163
    var ret = '';
1097
1164
    var first = true;
1098
 
    var signedIdent = makeSignOp(item.ident, item.type, 're'); // we need to standardize for purpose of comparison
 
1165
    signedIdent = makeSignOp(item.ident, item.type, 're'); // we need to standardize for purpose of comparison
 
1166
    if (!useIfs) item.signedIdent = signedIdent;
1099
1167
    if (RELOOP) {
1100
1168
      item.groupedLabels = [];
1101
1169
    }
1121
1189
        ret += value + '{\n';
1122
1190
      }
1123
1191
      var phiSet = getPhiSetsForLabel(phiSets, targetLabel);
1124
 
      ret += '  ' + phiSet + makeBranch(targetLabel, item.currLabelId || null) + '\n';
 
1192
      ret += INDENTATION + '' + phiSet + makeBranch(targetLabel, item.currLabelId || null) + '\n';
1125
1193
      ret += '}\n';
1126
1194
      if (RELOOP) {
1127
1195
        item.groupedLabels.push({
1178
1246
    // in an assignment
1179
1247
    var disabled = DISABLE_EXCEPTION_CATCHING == 2  && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST); 
1180
1248
    var phiSets = calcPhiSets(item);
1181
 
    var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled);
 
1249
    var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone, true);
1182
1250
 
1183
1251
    var ret;
1184
1252
 
1185
1253
    if (disabled) {
1186
1254
      ret = call_ + ';';
1187
1255
    } else if (ASM_JS) {
 
1256
      if (item.type != 'void') call_ = asmCoercion(call_, item.type); // ensure coercion to ffi in comma operator
1188
1257
      call_ = call_.replace('; return', ''); // we auto-add returns when aborting, but do not need them here
1189
 
      ret = '(__THREW__ = 0,' +  call_ + ');';
 
1258
      if (item.type == 'void') {
 
1259
        ret = '__THREW__ = 0;' +  call_ + ';';
 
1260
      } else {
 
1261
        ret = '(__THREW__ = 0,' +  call_ + ');';
 
1262
      }
1190
1263
    } else {
1191
1264
      ret = '(function() { try { __THREW__ = 0; return '
1192
1265
          + call_ + ' '
1196
1269
          + (EXCEPTION_DEBUG ? 'Module.print("Exception: " + e + ", currently at: " + (new Error().stack)); ' : '')
1197
1270
          + 'return null } })();';
1198
1271
    }
 
1272
    ret = makeVarArgsCleanup(ret);
1199
1273
 
1200
1274
    if (item.assignTo) {
1201
1275
      ret = 'var ' + item.assignTo + ' = ' + ret;
1227
1301
      case 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type, null, null, null, null, ',') + ',tempValue)';
1228
1302
      case 'cmpxchg': {
1229
1303
        var param3 = finalizeLLVMParameter(item.params[2]);
1230
 
        return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==(' + param2 + '|0) ? ' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ' : 0),tempValue)';
 
1304
        return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==(' + param2 + '|0) ? ' + asmCoercion(makeSetValue(param1, 0, param3, type, null, null, null, null, ','), 'i32') + ' : 0),tempValue)';
1231
1305
      }
1232
1306
      default: throw 'unhandled atomic op: ' + item.op;
1233
1307
    }
1301
1375
  makeFuncLineActor('alloca', function(item) {
1302
1376
    if (typeof item.allocatedIndex === 'number') {
1303
1377
      if (item.allocatedSize === 0) return ''; // This will not actually be shown - it's nativized
1304
 
      return asmCoercion(getFastValue('__stackBase__', '+', item.allocatedIndex.toString()), 'i32');
 
1378
      return asmCoercion(getFastValue('sp', '+', item.allocatedIndex.toString()), 'i32');
1305
1379
    } else {
1306
1380
      return RuntimeGenerator.stackAlloc(getFastValue(calcAllocatedSize(item.allocatedType), '*', item.allocatedNum));
1307
1381
    }
1310
1384
    assert(TARGET_LE32);
1311
1385
    var ident = item.value.ident;
1312
1386
    var move = Runtime.STACK_ALIGN;
1313
 
    return '(tempInt=' + makeGetValue(ident, 4, '*') + ',' +
1314
 
                         makeSetValue(ident, 4, 'tempInt + ' + move, '*') + ',' +
 
1387
    
 
1388
    // store current list offset in tempInt, advance list offset by STACK_ALIGN, return list entry stored at tempInt
 
1389
    return '(tempInt=' + makeGetValue(ident, Runtime.QUANTUM_SIZE, '*') + ',' +
 
1390
                         makeSetValue(ident, Runtime.QUANTUM_SIZE, 'tempInt + ' + move, '*') + ',' +
1315
1391
                         makeGetValue(makeGetValue(ident, 0, '*'), 'tempInt', item.type) + ')';
1316
1392
  });
1317
1393
 
1328
1404
    return ret;
1329
1405
  });
1330
1406
 
1331
 
  function makeFunctionCall(ident, params, funcData, type, forceByPointer) {
 
1407
  function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn, invoke) {
1332
1408
    // We cannot compile assembly. See comment in intertyper.js:'Call'
1333
1409
    assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
1334
1410
 
 
1411
    var extCall = false;
 
1412
 
1335
1413
    if (ASM_JS && funcData.setjmpTable) forceByPointer = true; // in asm.js mode, we must do an invoke for each call
 
1414
    if (ASM_JS && DLOPEN_SUPPORT && !invoke && !funcData.setjmpTable) extCall = true; // go out, to be able to access other modules TODO: optimize
1336
1415
 
1337
1416
    ident = Variables.resolveAliasToIdent(ident);
1338
1417
    var shortident = ident.slice(1);
1393
1472
 
1394
1473
    args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) });
1395
1474
    if (ASM_JS) {
1396
 
      if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || funcData.setjmpTable) {
 
1475
      if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || invoke || extCall || funcData.setjmpTable) {
1397
1476
        args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) });
1398
1477
      } else {
1399
1478
        args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) });
1406
1485
    });
1407
1486
 
1408
1487
    if (hasVarArgs && !useJSArgs) {
 
1488
      funcData.hasVarArgsCall = true;
1409
1489
      if (varargs.length === 0) {
1410
1490
        varargs = [0];
1411
1491
        varargsTypes = ['i32'];
1412
1492
      }
1413
1493
      var offset = 0;
1414
 
      varargs = '(tempInt=' + RuntimeGenerator.stackAlloc(varargs.length, ',') + ',' +
 
1494
      varargs = '(tempVarArgs=' + RuntimeGenerator.stackAlloc(varargs.length, ',') + ',' +
1415
1495
                varargs.map(function(arg, i) {
1416
1496
                  var type = varargsTypes[i];
1417
1497
                  if (type == 0) return null;
1419
1499
                  var ret;
1420
1500
                  assert(offset % Runtime.STACK_ALIGN == 0); // varargs must be aligned
1421
1501
                  if (!varargsByVals[i]) {
1422
 
                    ret = makeSetValue(getFastValue('tempInt', '+', offset), 0, arg, type, null, null, Runtime.STACK_ALIGN, null, ',');
 
1502
                    ret = makeSetValue(getFastValue('tempVarArgs', '+', offset), 0, arg, type, null, null, Runtime.STACK_ALIGN, null, ',');
1423
1503
                    offset += Runtime.alignMemory(Runtime.getNativeFieldSize(type), Runtime.STACK_ALIGN);
1424
1504
                  } else {
1425
1505
                    var size = calcAllocatedSize(removeAllPointing(type));
1426
 
                    ret = makeCopyValues(getFastValue('tempInt', '+', offset), arg, size, null, null, varargsByVals[i], ',');
 
1506
                    ret = makeCopyValues(getFastValue('tempVarArgs', '+', offset), arg, size, null, null, varargsByVals[i], ',');
1427
1507
                    offset += Runtime.forceAlign(size, Runtime.STACK_ALIGN);
1428
1508
                  }
1429
1509
                  return ret;
1430
1510
                }).filter(function(arg) {
1431
1511
                  return arg !== null;
1432
 
                }).join(',') + ',tempInt)';
 
1512
                }).join(',') + ',tempVarArgs)';
1433
1513
      varargs = asmCoercion(varargs, 'i32');
1434
1514
    }
1435
1515
 
1436
1516
    args = args.concat(varargs);
1437
 
    var argsText = args.join(', ');
1438
1517
 
1439
1518
    // Inline if either we inline whenever we can (and we can), or if there is no noninlined version
1440
1519
    var inline = LibraryManager.library[simpleIdent + '__inline'];
1443
1522
      return inline.apply(null, args); // Warning: inlining does not prevent recalculation of the arguments. They should be simple identifiers
1444
1523
    }
1445
1524
 
1446
 
    if (ASM_JS) {
1447
 
      // remove unneeded arguments, which the asm sig can show us. this lets us alias memset with llvm.memset, we just
 
1525
    if (ASM_JS && ident.indexOf('llvm_') >= 0) {
 
1526
      // remove unneeded arguments in llvm intrinsic functions, which the asm sig can show us. this lets us alias memset with llvm.memset, we just
1448
1527
      // drop the final 2 args so things validate properly in asm
1449
1528
      var libsig = LibraryManager.library[simpleIdent + '__sig'];
1450
1529
      if (libsig) {
1456
1535
      }
1457
1536
    }
1458
1537
 
1459
 
    var returnType;
1460
 
    if (byPointer || ASM_JS) {
 
1538
    if (callIdent in Functions.implementedFunctions) {
 
1539
      // LLVM sometimes bitcasts for no reason. We must call using the exact same type as the actual function is generated as.
 
1540
      var numArgs = Functions.implementedFunctions[callIdent].length - 1;
 
1541
      if (numArgs !== args.length) {
 
1542
        if (VERBOSE) warnOnce('Fixing function call arguments based on signature, on ' + [callIdent, args.length, numArgs]);
 
1543
        while (args.length > numArgs) { args.pop(); argsTypes.pop() }
 
1544
        while (args.length < numArgs) { args.push('0'); argsTypes.push('i32') }
 
1545
      }
 
1546
    }
 
1547
 
 
1548
    var returnType = 'void';
 
1549
    if ((byPointer || ASM_JS) && hasReturn) {
1461
1550
      returnType = getReturnType(type);
 
1551
      if (callIdent in Functions.implementedFunctions) {
 
1552
        // LLVM sometimes bitcasts for no reason. We must call using the exact same type as the actual function is generated as
 
1553
        var trueType = Functions.getSignatureReturnType(Functions.implementedFunctions[callIdent]);
 
1554
        if (trueType !== returnType && !isIdenticallyImplemented(trueType, returnType)) {
 
1555
          if (VERBOSE) warnOnce('Fixing function call based on return type from signature, on ' + [callIdent, returnType, trueType]);
 
1556
          returnType = trueType;
 
1557
        }
 
1558
      }
1462
1559
    }
1463
1560
 
1464
1561
    if (byPointer) {
1465
1562
      var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs);
1466
1563
      if (ASM_JS) {
1467
1564
        assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out)
1468
 
        if (!byPointerForced && !funcData.setjmpTable) {
 
1565
        Functions.neededTables[sig] = 1;
 
1566
        var functionTableCall = !byPointerForced && !funcData.setjmpTable && !invoke && !extCall;
 
1567
        if (functionTableCall) {
1469
1568
          // normal asm function pointer call
1470
1569
          callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py
1471
 
          Functions.neededTables[sig] = 1;
1472
1570
        } else {
1473
 
          // This is a call through an invoke_*, either a forced one, or a setjmp-required one
 
1571
          // This is a call through an invoke_* or extCall, either a forced one, or a setjmp-required one
1474
1572
          // note: no need to update argsTypes at this point
1475
1573
          if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig;
1476
 
          args.unshift(byPointerForced ? Functions.getIndex(callIdent) : asmCoercion(callIdent, 'i32'));
1477
 
          callIdent = 'invoke_' + sig;
 
1574
          args.unshift(byPointerForced ? Functions.getIndex(callIdent, sig) : asmCoercion(callIdent, 'i32'));
 
1575
          callIdent = (extCall ? 'extCall' : 'invoke') + '_' + sig;
1478
1576
        }
1479
1577
      } else if (SAFE_DYNCALLS) {
1480
1578
        assert(!ASM_JS, 'cannot emit safe dyncalls in asm');
1481
1579
        callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)';
1482
1580
      }
1483
 
      if (!ASM_JS || (!byPointerForced && !funcData.setjmpTable)) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
 
1581
      if (!ASM_JS || functionTableCall) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
1484
1582
    }
1485
1583
 
1486
1584
    var ret = callIdent + '(' + args.join(', ') + ')';
1499
1597
 
1500
1598
    return ret;
1501
1599
  }
 
1600
 
 
1601
  function makeVarArgsCleanup(js) {
 
1602
    if (js.indexOf('(tempVarArgs=') >= 0) {
 
1603
      if (js[js.length-1] == ';') {
 
1604
        return js + ' STACKTOP=tempVarArgs;';
 
1605
      } else {
 
1606
        assert(js.indexOf(';') < 0);
 
1607
        return '((' + js + '), STACKTOP=tempVarArgs)';
 
1608
      }
 
1609
    }
 
1610
    return js;
 
1611
  }
 
1612
 
1502
1613
  makeFuncLineActor('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) });
1503
1614
  makeFuncLineActor('call', function(item) {
1504
1615
    if (item.standalone && LibraryManager.isStubFunction(item.ident)) return ';';
1505
 
    return makeFunctionCall(item.ident, item.params, item.funcData, item.type) + (item.standalone ? ';' : '');
 
1616
    var ret = makeFunctionCall(item.ident, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : '');
 
1617
    return makeVarArgsCleanup(ret);
1506
1618
  });
1507
1619
 
1508
1620
  makeFuncLineActor('unreachable', function(item) {
1550
1662
    //
1551
1663
 
1552
1664
    if (!mainPass) {
1553
 
      if (phase == 'pre' && !Variables.generatedGlobalBase) {
 
1665
      if (phase == 'pre' && !Variables.generatedGlobalBase && !BUILD_AS_SHARED_LIB) {
1554
1666
        Variables.generatedGlobalBase = true;
1555
1667
        // Globals are done, here is the rest of static memory
1556
 
        print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n');
1557
 
        print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n');
 
1668
        assert((TARGET_LE32 && Runtime.GLOBAL_BASE == 8) || (TARGET_X86 && Runtime.GLOBAL_BASE == 4)); // this is assumed in e.g. relocations for linkable modules
 
1669
        if (!SIDE_MODULE) {
 
1670
          print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n');
 
1671
          print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n');
 
1672
        } else {
 
1673
          print('H_BASE = parentModule["_malloc"](' + Runtime.alignMemory(Variables.nextIndexedOffset) + ' + Runtime.GLOBAL_BASE);\n');
 
1674
          print('// STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n'); // comment as metadata only
 
1675
        }
1558
1676
      }
1559
1677
      var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable);
1560
 
      print(generated.map(function(item) { return item.JS }).join('\n'));
 
1678
      print(generated.map(function(item) { return item.JS; }).join('\n'));
1561
1679
 
1562
1680
      if (phase == 'pre') {
1563
1681
        if (memoryInitialization.length > 0) {
1581
1699
            return true;
1582
1700
          });
1583
1701
          // write out the singleton big memory initialization value
1584
 
          print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE', true));
 
1702
          print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE' + (SIDE_MODULE ? '+H_BASE' : ''), true));
1585
1703
        } else {
1586
1704
          print('/* no memory initializer */'); // test purposes
1587
1705
        }
1588
1706
 
1589
 
        // Run postsets right before main, and after the memory initializer has been set up
 
1707
        // Define postsets. These will be run in ATINIT, right before global initializers (which might need the postsets). We cannot
 
1708
        // run them now because the memory initializer might not have been applied yet.
1590
1709
        print('function runPostSets() {\n');
1591
1710
        print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n'));
1592
1711
        print('}\n');
1593
 
        print('if (!awaitingMemoryInitializer) runPostSets();\n'); // if we load the memory initializer, this is done later
1594
1712
 
1595
1713
        if (USE_TYPED_ARRAYS == 2) {
1596
 
          print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n');
1597
 
          print('assert(tempDoublePtr % 8 == 0);\n');
1598
 
          print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n');
1599
 
          print('  HEAP8[tempDoublePtr] = HEAP8[ptr];\n');
1600
 
          print('  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n');
1601
 
          print('  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n');
1602
 
          print('  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n');
1603
 
          print('}\n');
1604
 
          print('function copyTempDouble(ptr) {\n');
1605
 
          print('  HEAP8[tempDoublePtr] = HEAP8[ptr];\n');
1606
 
          print('  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n');
1607
 
          print('  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n');
1608
 
          print('  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n');
1609
 
          print('  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n');
1610
 
          print('  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n');
1611
 
          print('  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n');
1612
 
          print('  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n');
1613
 
          print('}\n');
 
1714
          if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) {
 
1715
            print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n');
 
1716
            print('assert(tempDoublePtr % 8 == 0);\n');
 
1717
            print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n');
 
1718
            print('  HEAP8[tempDoublePtr] = HEAP8[ptr];\n');
 
1719
            print('  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n');
 
1720
            print('  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n');
 
1721
            print('  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n');
 
1722
            print('}\n');
 
1723
            print('function copyTempDouble(ptr) {\n');
 
1724
            print('  HEAP8[tempDoublePtr] = HEAP8[ptr];\n');
 
1725
            print('  HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n');
 
1726
            print('  HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n');
 
1727
            print('  HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n');
 
1728
            print('  HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n');
 
1729
            print('  HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n');
 
1730
            print('  HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n');
 
1731
            print('  HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n');
 
1732
            print('}\n');
 
1733
          }
1614
1734
        }
1615
1735
      }
1616
1736
 
1645
1765
 
1646
1766
      legalizedI64s = legalizedI64sDefault;
1647
1767
 
1648
 
      print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n');
1649
 
      print('staticSealed = true; // seal the static portion of memory\n');
1650
 
      print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n');
1651
 
      print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n');
1652
 
      print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n');
 
1768
      if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) {
 
1769
        print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n');
 
1770
        print('staticSealed = true; // seal the static portion of memory\n');
 
1771
        print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n');
 
1772
        print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n');
 
1773
        print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n');
 
1774
      }
1653
1775
 
1654
1776
      if (asmLibraryFunctions.length > 0) {
1655
1777
        print('// ASM_LIBRARY FUNCTIONS');
1668
1790
      }
1669
1791
    }
1670
1792
 
1671
 
    if (abortExecution) throw 'Aborting compilation due to previous warnings';
 
1793
    if (abortExecution) throw 'Aborting compilation due to previous errors';
1672
1794
 
1673
1795
    if (phase == 'pre' || phase == 'funcs') {
1674
1796
      PassManager.serialize();
1700
1822
            }
1701
1823
          }
1702
1824
        });
1703
 
        print(read('fastLong.js'));
1704
1825
      }
 
1826
      print(read('fastLong.js'));
1705
1827
      print('// EMSCRIPTEN_END_FUNCS\n');
1706
1828
      print(read('long.js'));
1707
1829
    } else {
1711
1833
    }
1712
1834
 
1713
1835
    if (CORRUPTION_CHECK) {
1714
 
      assert(!ASM_JS); // cannot monkeypatch asm!
 
1836
      assert(!ASM_JS, 'corruption checker is not compatible with asm.js');
1715
1837
      print(processMacros(read('corruptionCheck.js')));
1716
1838
    }
1717
1839
    if (HEADLESS) {
1718
1840
      print('if (!ENVIRONMENT_IS_WEB) {');
1719
 
      print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace('%s,', 'null,').replace('%d', '0'));
 
1841
      print(read('headlessCanvas.js'));
 
1842
      print('\n');
 
1843
      print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace("'?%s'", "'/'").replace('%s,', 'null,').replace('%d', '0'));
1720
1844
      print('}');
1721
1845
    }
 
1846
    if (PROXY_TO_WORKER) {
 
1847
      print(read('proxyWorker.js'));
 
1848
    }
1722
1849
    if (RUNTIME_TYPE_INFO) {
1723
1850
      Types.cleanForRuntime();
1724
1851
      print('Runtime.typeInfo = ' + JSON.stringify(Types.types));
1725
1852
      print('Runtime.structMetadata = ' + JSON.stringify(Types.structMetadata));
1726
1853
    }
1727
 
    var postFile = BUILD_AS_SHARED_LIB ? 'postamble_sharedlib.js' : 'postamble.js';
 
1854
    var postFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'postamble_sharedlib.js' : 'postamble.js';
1728
1855
    var postParts = processMacros(preprocess(read(postFile))).split('{{GLOBAL_VARS}}');
1729
1856
    print(postParts[0]);
1730
1857
 
1738
1865
    print(postParts[1]);
1739
1866
 
1740
1867
    var shellParts = read(shellFile).split('{{BODY}}');
1741
 
    print(shellParts[1]);
 
1868
    print(processMacros(preprocess(shellParts[1])));
1742
1869
    // Print out some useful metadata
1743
1870
    if (EMIT_GENERATED_FUNCTIONS || PGO) {
1744
1871
      var generatedFunctions = JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) {
1760
1887
  // Data
1761
1888
 
1762
1889
  if (mainPass) {
 
1890
    if (phase == 'pre') {
 
1891
      // types have been parsed, so we can figure out function signatures (which can use types)
 
1892
      data.unparsedFunctions.forEach(function(func) {
 
1893
        Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type }));
 
1894
      });
 
1895
    }
1763
1896
    substrate.addItems(data.functionStubs, 'FunctionStub');
1764
1897
    assert(data.functions.length == 0);
1765
1898
  } else {
 
1899
    if (phase == 'pre') {
 
1900
      // ensure there is a global ctors, for runPostSets
 
1901
      if ('_llvm_global_ctors' in data.globalVariables) {
 
1902
        data.globalVariables._llvm_global_ctors.ctors.unshift('runPostSets'); // run postsets right before global initializers
 
1903
        hasCtors = true;
 
1904
      } else {
 
1905
        substrate.addItems([{
 
1906
          intertype: 'GlobalVariableStub',
 
1907
          ident: '_llvm_global_ctors',
 
1908
          type: '[1 x { i32, void ()* }]',
 
1909
          ctors: ["runPostSets"],
 
1910
        }], 'GlobalVariable');
 
1911
      }
 
1912
    }
 
1913
 
1766
1914
    substrate.addItems(sortGlobals(data.globalVariables), 'GlobalVariable');
1767
1915
    substrate.addItems(data.aliass, 'Alias');
1768
1916
    substrate.addItems(data.functions, 'FunctionSplitter');