| 1 | function Memory(stdlib, foreign, heap) { |
| 2 | "use asm"; |
| 3 | |
| 4 | var H32 = new stdlib.Int32Array(heap); |
| 5 | var offset = 1; |
| 6 | var length = H32.length | 0; |
| 7 | |
| 8 | // Malloc is very simple. If there is free space at the end, it uses that. |
| 9 | // If not, it looks for the next fitting empty slot, merging if needed. |
| 10 | function malloc(len) { |
| 11 | // len is length requested by user in bytes |
| 12 | len = len|0; |
| 13 | if (len === 0) return 0; |
| 14 | // size is size of block (including header) in words. |
| 15 | var size = (len + 7) >> 2; |
| 16 | var loop = 0; |
| 17 | for(;;) { |
| 18 | var v = H32[offset]|0; |
| 19 | |
| 20 | // If we're at the end of all used memory... |
| 21 | if (v === 0) { |
| 22 | // If there is still space, grab it. |
| 23 | if (((offset + size) | 0) < length) break; |
| 24 | // If this is the second time here, we're in trouble! |
| 25 | if (loop === 1) combine(); |
| 26 | else if (loop === 2) return 0; |
| 27 | // Otherwise, start over looking for leftovers. |
| 28 | loop = (loop + 1) | 0; |
| 29 | offset = 1; |
| 30 | continue; |
| 31 | } |
| 32 | |
| 33 | // If it's still in use, skip over it. |
| 34 | if (v > 0) { |
| 35 | offset = (offset + v) | 0; |
| 36 | continue; |
| 37 | } |
| 38 | |
| 39 | // If the slot is an exact fit, take it. |
| 40 | if (v === -size) break; |
| 41 | |
| 42 | // If there is room to split, then split it. |
| 43 | if (-v >= size + 2) { |
| 44 | H32[offset + size] = (v + size) | 0; |
| 45 | break; |
| 46 | } |
| 47 | offset = (offset - v) | 0; |
| 48 | } |
| 49 | |
| 50 | // Record this new slot |
| 51 | H32[offset] = size; |
| 52 | // Calculate the data offset in bytes for user data. |
| 53 | // Add in pointer type tag. |
| 54 | var ptr = (offset + 1) << 2; |
| 55 | // Increment the offset for the next malloc |
| 56 | offset = (offset + size) | 0; |
| 57 | return ptr; |
| 58 | } |
| 59 | |
| 60 | function combine() { |