aboutsummaryrefslogtreecommitdiff
path: root/src/runtime.js
blob: 43a522e484ee96755170a78aa843ef116bc63e76 (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
////////////QUANTUM_SIZE = GUARD_STACK = 1;
// Generates code that can be placed inline in generated code.
// This is not the cleanest way to write this kind of code - it is
// optimized for generating fast inline code.
RuntimeGenerator = {
  alloc: function(size, type) {
    var ret = type + 'TOP';
//    ret += '; for (var i = 0; i < ' + size + '; i++) HEAP[' + type + 'TOP+i] = 0';
    if (GUARD_MEMORY) {
      ret += '; assert(' + size + ' > 0)';
    }
    ret += '; ' + type + 'TOP += ' + size;
    if (QUANTUM_SIZE > 1) {
      ret += ';' + RuntimeGenerator.alignMemory(type + 'TOP', QUANTUM_SIZE);
    }
    return ret;
  },

  // An allocation that lives as long as the current function call
  stackAlloc: function(size) {
    var ret = RuntimeGenerator.alloc(size, 'STACK');
    if (GUARD_MEMORY) {
      ret += '; assert(STACKTOP < STACK_ROOT + STACK_MAX)';
    }
    return ret;
  },

  stackEnter: function(initial) {
    if (initial === 0) return ''; // XXX Note that we don't even push the stack! This is faster, but
                                  // means that we don't clear stack allocations done in this function
                                  // until the parent unwinds its stack. So potentially if we are in
                                  // a loop, we can use a lot of memory.
    var ret = 'var __stackBase__  = STACKTOP; STACKTOP += ' + initial;
    if (GUARD_MEMORY) {
      ret += '; assert(STACKTOP < STACK_MAX)';
    }
    return ret;
  },

  stackExit: function(initial) {
    if (initial === 0) return ''; // XXX See comment in stackEnter
    return 'STACKTOP = __stackBase__';
  },

  // An allocation that cannot be free'd
  staticAlloc: function(size) {
    return RuntimeGenerator.alloc(size, 'STATIC');
  },

  alignMemory: function(target, quantum) {
    if (typeof quantum !== 'number') {
      quantum = '(quantum ? quantum : QUANTUM_SIZE)';
    }
    return target + ' = Math.ceil(' + target + '/' + quantum + ')*' + quantum + ';';
  },
};

function unInline(name_, params) {
  var src = '(function ' + name_ + '(' + params + ') { var ret = ' + RuntimeGenerator[name_].apply(null, params) + '; return ret; })';
  //print('src: ' + src);
  return eval(src);
}

// Uses the RuntimeGenerator during compilation, in order to
//  1. Let the compiler access and run those functions during compilation
//  2. We expose the entire Runtime object to generated code, so it can
//     use that functionality in a non-inline manner.
Runtime = {
  stackAlloc: unInline('stackAlloc', ['size']),
  staticAlloc: unInline('staticAlloc', ['size']),
  alignMemory: unInline('alignMemory', ['size', 'quantum']),
};

function getRuntime() {
  var ret = '';
  for (i in Runtime) {
    ret += Runtime[i].toString() + '\n';
  }
  return ret + '\n';
}