diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler.js | 6 | ||||
-rw-r--r-- | src/jsifier.js | 43 | ||||
-rw-r--r-- | src/library.js | 74 | ||||
-rw-r--r-- | src/library_gc.js | 7 | ||||
-rw-r--r-- | src/parseTools.js | 5 | ||||
-rw-r--r-- | src/postamble.js | 6 | ||||
-rw-r--r-- | src/preamble.js | 59 | ||||
-rw-r--r-- | src/runtime.js | 17 | ||||
-rw-r--r-- | src/settings.js | 3 |
9 files changed, 120 insertions, 100 deletions
diff --git a/src/compiler.js b/src/compiler.js index 313fd5f7..8b9606f1 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -184,6 +184,7 @@ if (ASM_JS) { assert((TOTAL_MEMORY&(TOTAL_MEMORY-1)) == 0, 'asm.js heap must be power of 2'); } assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB)); // shared libraries must have named globals +assert(!BUILD_AS_SHARED_LIB, 'shared libs are deprecated'); // Output some info and warnings based on settings @@ -208,7 +209,10 @@ load('parseTools.js'); load('intertyper.js'); load('analyzer.js'); load('jsifier.js'); -if (RELOOP) load(RELOOPER) +if (RELOOP) { + load(RELOOPER); + assert(typeof Relooper != 'undefined'); +} globalEval(processMacros(preprocess(read('runtime.js')))); Runtime.QUANTUM_SIZE = QUANTUM_SIZE; diff --git a/src/jsifier.js b/src/jsifier.js index c21e7995..8270b443 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1546,13 +1546,9 @@ function JSify(data, functionsOnly, givenFunctions) { if (!mainPass) { if (phase == 'pre' && !Variables.generatedGlobalBase) { Variables.generatedGlobalBase = true; - if (Variables.nextIndexedOffset > 0) { - // Variables have been calculated, get to base stuff before we print them - // GLOBAL_BASE is statically known to be equal to STACK_MAX and to TOTAL_STACK, assert on this - print('assert(STATICTOP == STACK_MAX); assert(STACK_MAX == TOTAL_STACK);\n'); - print('STATICTOP += ' + Variables.nextIndexedOffset + ';\n'); - print('assert(STATICTOP < TOTAL_MEMORY);\n'); - } + // Globals are done, here is the rest of static memory + print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n'); + print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n'); } var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable); print(generated.map(function(item) { return item.JS }).join('\n')); @@ -1573,13 +1569,13 @@ function JSify(data, functionsOnly, givenFunctions) { // possibly function table {{{ FT_* }}} etc. if (value.indexOf('{{ ') < 0) return true; } - writeInt8s(memoryInitialization, target - TOTAL_STACK, value, type); + writeInt8s(memoryInitialization, target - Runtime.GLOBAL_BASE, value, type); return false; } return true; }); // write out the singleton big memory initialization value - print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE + print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE', true)); } else { print('/* no memory initializer */'); // test purposes } @@ -1589,6 +1585,27 @@ function JSify(data, functionsOnly, givenFunctions) { print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); print('}\n'); print('if (!awaitingMemoryInitializer) runPostSets();\n'); // if we load the memory initializer, this is done later + + if (USE_TYPED_ARRAYS == 2) { + print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n'); + print('assert(tempDoublePtr % 8 == 0);\n'); + print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n'); + print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n'); + print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n'); + print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n'); + print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n'); + print('}\n'); + print('function copyTempDouble(ptr) {\n'); + print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n'); + print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n'); + print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n'); + print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n'); + print(' HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n'); + print(' HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n'); + print(' HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n'); + print(' HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n'); + print('}\n'); + } } return; @@ -1622,6 +1639,12 @@ function JSify(data, functionsOnly, givenFunctions) { legalizedI64s = legalizedI64sDefault; + print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n'); + print('staticSealed = true; // seal the static portion of memory\n'); + print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n'); + print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n'); + print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n'); + if (asmLibraryFunctions.length > 0) { print('// ASM_LIBRARY FUNCTIONS'); function fix(f) { // fix indenting to not confuse js optimizer @@ -1631,6 +1654,7 @@ function JSify(data, functionsOnly, givenFunctions) { } print(asmLibraryFunctions.map(fix).join('\n')); } + } else { if (singlePhase) { assert(data.unparsedGlobalss[0].lines.length == 0, dump([phase, data.unparsedGlobalss])); @@ -1664,6 +1688,7 @@ function JSify(data, functionsOnly, givenFunctions) { assert(typeof dep == 'function'); var text = dep(); assert(text.indexOf('\n') < 0); + text = text.replace('ALLOC_STATIC', 'ALLOC_DYNAMIC'); print('/* PRE_ASM */ ' + text + '\n'); }); } diff --git a/src/library.js b/src/library.js index dc0dcdd2..e984b1eb 100644 --- a/src/library.js +++ b/src/library.js @@ -15,16 +15,18 @@ // object. For convenience, the short name appears here. Note that if you add a // new function with an '_', it will not be found. +// Memory allocated during startup, in postsets, should only be ALLOC_STATIC + LibraryManager.library = { // ========================================================================== // File system base. // ========================================================================== // keep this low in memory, because we flatten arrays with them in them - stdin: 'allocate(1, "i32*", ALLOC_STACK)', - stdout: 'allocate(1, "i32*", ALLOC_STACK)', - stderr: 'allocate(1, "i32*", ALLOC_STACK)', - _impure_ptr: 'allocate(1, "i32*", ALLOC_STACK)', + stdin: 'allocate(1, "i32*", ALLOC_STATIC)', + stdout: 'allocate(1, "i32*", ALLOC_STATIC)', + stderr: 'allocate(1, "i32*", ALLOC_STATIC)', + _impure_ptr: 'allocate(1, "i32*", ALLOC_STATIC)', $FS__deps: ['$ERRNO_CODES', '__setErrNo', 'stdin', 'stdout', 'stderr', '_impure_ptr'], $FS__postset: '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' + @@ -573,7 +575,7 @@ LibraryManager.library = { eof: false, ungotten: [] }; - assert(Math.max(_stdin, _stdout, _stderr) < 1024); // make sure these are low, we flatten arrays with these + // TODO: put these low in memory like we used to assert on: assert(Math.max(_stdin, _stdout, _stderr) < 15000); // make sure these are low, we flatten arrays with these {{{ makeSetValue(makeGlobalUse('_stdin'), 0, 1, 'void*') }}}; {{{ makeSetValue(makeGlobalUse('_stdout'), 0, 2, 'void*') }}}; {{{ makeSetValue(makeGlobalUse('_stderr'), 0, 3, 'void*') }}}; @@ -590,11 +592,11 @@ LibraryManager.library = { FS.streams[_stderr] = FS.streams[3]; #if ASSERTIONS FS.checkStreams(); - assert(FS.streams.length < 1024); // at this early stage, we should not have a large set of file descriptors - just a few + // see previous TODO on stdin etc.: assert(FS.streams.length < 1024); // at this early stage, we should not have a large set of file descriptors - just a few #endif allocate([ allocate( {{{ Runtime.QUANTUM_SIZE === 4 ? '[0, 0, 0, 0, _stdin, 0, 0, 0, _stdout, 0, 0, 0, _stderr, 0, 0, 0]' : '[0, _stdin, _stdout, _stderr]' }}}, - 'void*', ALLOC_STATIC) ], 'void*', ALLOC_NONE, {{{ makeGlobalUse('__impure_ptr') }}}); + 'void*', ALLOC_DYNAMIC) ], 'void*', ALLOC_NONE, {{{ makeGlobalUse('__impure_ptr') }}}); }, quit: function() { @@ -2425,22 +2427,17 @@ LibraryManager.library = { // Implement a Linux-like 'memory area' for our 'process'. // Changes the size of the memory area by |bytes|; returns the // address of the previous top ('break') of the memory area - - // We need to make sure no one else allocates unfreeable memory! - // We must control this entirely. So we don't even need to do - // unfreeable allocations - the HEAP is ours, from STATICTOP up. - // TODO: We could in theory slice off the top of the HEAP when - // sbrk gets a negative increment in |bytes|... + // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP var self = _sbrk; if (!self.called) { - STATICTOP = alignMemoryPage(STATICTOP); // make sure we start out aligned + DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned self.called = true; -#if GC_SUPPORT - _sbrk.DYNAMIC_START = STATICTOP; -#endif + assert(Runtime.dynamicAlloc); + self.alloc = Runtime.dynamicAlloc; + Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') }; } - var ret = STATICTOP; - if (bytes != 0) Runtime.staticAlloc(bytes); + var ret = DYNAMICTOP; + if (bytes != 0) self.alloc(bytes); return ret; // Previous break location. }, open64: 'open', @@ -3007,16 +3004,20 @@ LibraryManager.library = { } case 's': { // String. - var arg = getNextArg('i8*') || nullString; - var argLength = _strlen(arg); + var arg = getNextArg('i8*'); + var argLength = arg ? _strlen(arg) : '(null)'.length; if (precisionSet) argLength = Math.min(argLength, precision); if (!flagLeftAlign) { while (argLength < width--) { ret.push({{{ charCode(' ') }}}); } } - for (var i = 0; i < argLength; i++) { - ret.push({{{ makeGetValue('arg++', 0, 'i8', null, true) }}}); + if (arg) { + for (var i = 0; i < argLength; i++) { + ret.push({{{ makeGetValue('arg++', 0, 'i8', null, true) }}}); + } + } else { + ret = ret.concat(intArrayFromString('(null)'.substr(0, argLength), true)); } if (flagLeftAlign) { while (argLength < width--) { @@ -3750,7 +3751,7 @@ LibraryManager.library = { * implementation (replaced by dlmalloc normally) so * not an issue. */ - var ptr = Runtime.staticAlloc(bytes + 8); + var ptr = Runtime.dynamicAlloc(bytes + 8); return (ptr+8) & 0xFFFFFFF8; }, free: function(){}, @@ -4029,7 +4030,7 @@ LibraryManager.library = { _free(temp); }, - environ: 'allocate(1, "i32*", ALLOC_STACK)', + environ: 'allocate(1, "i32*", ALLOC_STATIC)', __environ__deps: ['environ'], __environ: '_environ', __buildEnvironment__deps: ['__environ'], @@ -4925,7 +4926,7 @@ LibraryManager.library = { } return 8; } - return 'var ctlz_i8 = allocate([' + range(256).map(function(x) { return ctlz(x) }).join(',') + '], "i8", ALLOC_STACK);'; + return 'var ctlz_i8 = allocate([' + range(256).map(function(x) { return ctlz(x) }).join(',') + '], "i8", ALLOC_STATIC);'; }], llvm_ctlz_i32__asm: true, llvm_ctlz_i32__sig: 'ii', @@ -4961,7 +4962,7 @@ LibraryManager.library = { } return 8; } - return 'var cttz_i8 = allocate([' + range(256).map(function(x) { return cttz(x) }).join(',') + '], "i8", ALLOC_STACK);'; + return 'var cttz_i8 = allocate([' + range(256).map(function(x) { return cttz(x) }).join(',') + '], "i8", ALLOC_STATIC);'; }], llvm_cttz_i32__asm: true, llvm_cttz_i32__sig: 'ii', @@ -5919,11 +5920,11 @@ LibraryManager.library = { ['i32', 'tm_gmtoff'], ['i32', 'tm_zone']]), // Statically allocated time struct. - __tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STACK)', + __tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)', // Statically allocated timezone strings. __tm_timezones: {}, // Statically allocated time strings. - __tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STACK)', + __tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)', mktime__deps: ['__tm_struct_layout', 'tzset'], mktime: function(tmPtr) { @@ -6057,9 +6058,9 @@ LibraryManager.library = { // TODO: Initialize these to defaults on startup from system settings. // Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm) - _tzname: 'allocate({{{ 2*Runtime.QUANTUM_SIZE }}}, "i32*", ALLOC_STACK)', - _daylight: 'allocate(1, "i32*", ALLOC_STACK)', - _timezone: 'allocate(1, "i32*", ALLOC_STACK)', + _tzname: 'allocate({{{ 2*Runtime.QUANTUM_SIZE }}}, "i32*", ALLOC_STATIC)', + _daylight: 'allocate(1, "i32*", ALLOC_STATIC)', + _timezone: 'allocate(1, "i32*", ALLOC_STATIC)', tzset__deps: ['_tzname', '_daylight', '_timezone'], tzset: function() { // TODO: Use (malleable) environment variables instead of system settings. @@ -6756,15 +6757,18 @@ LibraryManager.library = { 26: 'Text file busy', 18: 'Invalid cross-device link' }, - __setErrNo__postset: '___setErrNo(0);', __setErrNo: function(value) { // For convenient setting and returning of errno. - if (!___setErrNo.ret) ___setErrNo.ret = allocate([0], 'i32', ALLOC_STATIC); + if (!___setErrNo.ret) ___setErrNo.ret = allocate([0], 'i32', ALLOC_NORMAL); {{{ makeSetValue('___setErrNo.ret', '0', 'value', 'i32') }}} return value; }, __errno_location__deps: ['__setErrNo'], __errno_location: function() { + if (!___setErrNo.ret) { + ___setErrNo.ret = allocate([0], 'i32', ALLOC_NORMAL); + {{{ makeSetValue('___setErrNo.ret', '0', '0', 'i32') }}} + } return ___setErrNo.ret; }, __errno: '__errno_location', @@ -6877,7 +6881,7 @@ LibraryManager.library = { void **restrict stackaddr, size_t *restrict stacksize); */ /*FIXME: assumes that there is only one thread, and that attr is the current thread*/ - {{{ makeSetValue('stackaddr', '0', 'STACK_ROOT', 'i8*') }}} + {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}} {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}} return 0; }, diff --git a/src/library_gc.js b/src/library_gc.js index f6db74d8..2a164250 100644 --- a/src/library_gc.js +++ b/src/library_gc.js @@ -148,12 +148,9 @@ if (GC_SUPPORT) { prep: function() { // Clear reachables and scan for roots GC.reachable = {}; // 1 if reachable. XXX GC.reachableList = []; // each reachable is added once to this. XXX - // static data areas - var staticStart = STACK_MAX; - var staticEnd = _sbrk.DYNAMIC_START || STATICTOP; // after DYNAMIC_START, sbrk manages it (but it might not exist yet) - GC.scan(staticStart, staticEnd); + GC.scan(STATIC_BASE, STATICTOP); // TODO: scan stack and registers. Currently we assume we run from a timeout or such, so no stack/regs - // stack: STACK_ROOT to STACKTOP + // stack: STACK_BASE to STACKTOP // registers: call scanners }, diff --git a/src/parseTools.js b/src/parseTools.js index 5cbefdb1..db834206 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -465,8 +465,7 @@ function makeGlobalUse(ident) { UNINDEXABLE_GLOBALS[ident] = 1; return ident; } - // We know and assert on TOTAL_STACK being equal to GLOBAL_BASE - return (TOTAL_STACK + index).toString(); + return (Runtime.GLOBAL_BASE + index).toString(); } return ident; } @@ -1594,7 +1593,7 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) // writing out into memory, without a normal allocation. We put all of these into a single big chunk. assert(typeof slab == 'object'); assert(slab.length % QUANTUM_SIZE == 0, slab.length); // must be aligned already - var offset = ptr - TOTAL_STACK; // we assert on GLOBAL_BASE being equal to TOTAL_STACK + var offset = ptr - Runtime.GLOBAL_BASE; for (var i = 0; i < slab.length; i++) { memoryInitialization[offset + i] = slab[i]; } diff --git a/src/postamble.js b/src/postamble.js index 8dd01589..12471a19 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -15,14 +15,14 @@ Module.callMain = function callMain(args) { argv.push(0); } } - var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_STATIC) ]; + var argv = [allocate(intArrayFromString("/bin/this.program"), 'i8', ALLOC_NORMAL) ]; pad(); for (var i = 0; i < argc-1; i = i + 1) { - argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_STATIC)); + argv.push(allocate(intArrayFromString(args[i]), 'i8', ALLOC_NORMAL)); pad(); } argv.push(0); - argv = allocate(argv, 'i32', ALLOC_STATIC); + argv = allocate(argv, 'i32', ALLOC_NORMAL); #if BENCHMARK var start = Date.now(); diff --git a/src/preamble.js b/src/preamble.js index cac0be4c..d10771e3 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -38,14 +38,14 @@ var ACCEPTABLE_SAFE_HEAP_ERRORS = 0; function SAFE_HEAP_ACCESS(dest, type, store, ignore, storeValue) { //if (dest === A_NUMBER) Module.print ([dest, type, store, ignore, storeValue] + ' ' + new Error().stack); // Something like this may be useful, in debugging - assert(dest >= STACK_ROOT, 'segmentation fault: null pointer, or below normal memory'); + assert(dest > 0, 'segmentation fault'); #if USE_TYPED_ARRAYS // When using typed arrays, reads over the top of TOTAL_MEMORY will fail silently, so we must // correct that by growing TOTAL_MEMORY as needed. Without typed arrays, memory is a normal // JS array so it will work (potentially slowly, depending on the engine). - assert(ignore || dest < STATICTOP); - assert(ignore || STATICTOP <= TOTAL_MEMORY); + assert(ignore || dest < Math.max(DYNAMICTOP, STATICTOP)); + assert(ignore || DYNAMICTOP <= TOTAL_MEMORY); #endif #if USE_TYPED_ARRAYS == 2 @@ -417,10 +417,12 @@ Module['getValue'] = getValue; var ALLOC_NORMAL = 0; // Tries to use _malloc() var ALLOC_STACK = 1; // Lives for the duration of the current function call var ALLOC_STATIC = 2; // Cannot be freed -var ALLOC_NONE = 3; // Do not allocate +var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk +var ALLOC_NONE = 4; // Do not allocate Module['ALLOC_NORMAL'] = ALLOC_NORMAL; Module['ALLOC_STACK'] = ALLOC_STACK; Module['ALLOC_STATIC'] = ALLOC_STATIC; +Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC; Module['ALLOC_NONE'] = ALLOC_NONE; // allocate(): This is for internal use. You can use it yourself as well, but the interface @@ -452,7 +454,7 @@ function allocate(slab, types, allocator, ptr) { if (allocator == ALLOC_NONE) { ret = ptr; } else { - ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length)); + ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length)); } if (zeroinit) { @@ -573,8 +575,10 @@ var FHEAP; var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64; #endif -var STACK_ROOT, STACKTOP, STACK_MAX; -var STATICTOP; +var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area +var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area +var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk + #if USE_TYPED_ARRAYS function enlargeMemory() { #if ALLOW_MEMORY_GROWTH == 0 @@ -584,13 +588,13 @@ function enlargeMemory() { abort('Cannot enlarge memory arrays in asm.js. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value, or (2) set Module.TOTAL_MEMORY before the program runs.'); #endif #else - // TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top. + // TOTAL_MEMORY is the current size of the actual array, and DYNAMICTOP is the new top. #if ASSERTIONS - Module.printErr('Warning: Enlarging memory arrays, this is not fast, and ALLOW_MEMORY_GROWTH is not fully tested with all optimizations on! ' + [STATICTOP, TOTAL_MEMORY]); // We perform safe elimination instead of elimination in this mode, but if you see this error, try to disable it and other optimizations entirely - assert(STATICTOP >= TOTAL_MEMORY); + Module.printErr('Warning: Enlarging memory arrays, this is not fast, and ALLOW_MEMORY_GROWTH is not fully tested with all optimizations on! ' + [DYNAMICTOP, TOTAL_MEMORY]); // We perform safe elimination instead of elimination in this mode, but if you see this error, try to disable it and other optimizations entirely + assert(DYNAMICTOP >= TOTAL_MEMORY); assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite #endif - while (TOTAL_MEMORY <= STATICTOP) { // Simple heuristic. Override enlargeMemory() if your program has something more optimal for it + while (TOTAL_MEMORY <= DYNAMICTOP) { // Simple heuristic. Override enlargeMemory() if your program has something more optimal for it TOTAL_MEMORY = alignMemoryPage(2*TOTAL_MEMORY); } assert(TOTAL_MEMORY <= Math.pow(2, 30)); // 2^30==1GB is a practical maximum - 2^31 is already close to possible negative numbers etc. @@ -680,35 +684,6 @@ Module['HEAPF32'] = HEAPF32; Module['HEAPF64'] = HEAPF64; #endif -STACK_ROOT = STACKTOP = Runtime.alignMemory(1); -STACK_MAX = TOTAL_STACK; // we lose a little stack here, but TOTAL_STACK is nice and round so use that as the max - -#if USE_TYPED_ARRAYS == 2 -var tempDoublePtr = Runtime.alignMemory(allocate(12, 'i8', ALLOC_STACK), 8); -assert(tempDoublePtr % 8 == 0); -function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much - HEAP8[tempDoublePtr] = HEAP8[ptr]; - HEAP8[tempDoublePtr+1] = HEAP8[ptr+1]; - HEAP8[tempDoublePtr+2] = HEAP8[ptr+2]; - HEAP8[tempDoublePtr+3] = HEAP8[ptr+3]; -} -function copyTempDouble(ptr) { - HEAP8[tempDoublePtr] = HEAP8[ptr]; - HEAP8[tempDoublePtr+1] = HEAP8[ptr+1]; - HEAP8[tempDoublePtr+2] = HEAP8[ptr+2]; - HEAP8[tempDoublePtr+3] = HEAP8[ptr+3]; - HEAP8[tempDoublePtr+4] = HEAP8[ptr+4]; - HEAP8[tempDoublePtr+5] = HEAP8[ptr+5]; - HEAP8[tempDoublePtr+6] = HEAP8[ptr+6]; - HEAP8[tempDoublePtr+7] = HEAP8[ptr+7]; -} -#endif - -STATICTOP = STACK_MAX; -assert(STATICTOP < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY - -var nullString = allocate(intArrayFromString('(null)'), 'i8', ALLOC_STACK); - function callRuntimeCallbacks(callbacks) { while(callbacks.length > 0) { var callback = callbacks.shift(); @@ -907,9 +882,9 @@ var awaitingMemoryInitializer = false; function loadMemoryInitializer(filename) { function applyData(data) { #if USE_TYPED_ARRAYS == 2 - HEAPU8.set(data, TOTAL_STACK); + HEAPU8.set(data, STATIC_BASE); #else - allocate(data, 'i8', ALLOC_NONE, TOTAL_STACK); + allocate(data, 'i8', ALLOC_NONE, STATIC_BASE); #endif runPostSets(); } diff --git a/src/runtime.js b/src/runtime.js index 9daab820..9bedfe68 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -61,8 +61,16 @@ var RuntimeGenerator = { // An allocation that cannot normally be free'd (except through sbrk, which once // called, takes control of STATICTOP) staticAlloc: function(size) { + if (ASSERTIONS) size = '(assert(!staticSealed),' + size + ')'; // static area must not be sealed var ret = RuntimeGenerator.alloc(size, 'STATIC', INIT_HEAP); - if (USE_TYPED_ARRAYS) ret += '; if (STATICTOP >= TOTAL_MEMORY) enlargeMemory();' + return ret; + }, + + // allocation on the top of memory, adjusted dynamically by sbrk + dynamicAlloc: function(size) { + if (ASSERTIONS) size = '(assert(DYNAMICTOP > 0),' + size + ')'; // dynamic area must be ready + var ret = RuntimeGenerator.alloc(size, 'DYNAMIC', INIT_HEAP); + if (USE_TYPED_ARRAYS) ret += '; if (DYNAMICTOP >= TOTAL_MEMORY) enlargeMemory();' return ret; }, @@ -466,6 +474,7 @@ var Runtime = { Runtime.stackAlloc = unInline('stackAlloc', ['size']); Runtime.staticAlloc = unInline('staticAlloc', ['size']); +Runtime.dynamicAlloc = unInline('dynamicAlloc', ['size']); Runtime.alignMemory = unInline('alignMemory', ['size', 'quantum']); Runtime.makeBigInt = unInline('makeBigInt', ['low', 'high', 'unsigned']); @@ -529,3 +538,9 @@ function reSign(value, bits, ignore, sig) { return value; } +// The address globals begin at. Very low in memory, for code size and optimization opportunities. +// Above 0 is static memory, starting with globals. +// Then the stack. +// Then 'dynamic' memory for sbrk. +Runtime.GLOBAL_BASE = Runtime.alignMemory(1); + diff --git a/src/settings.js b/src/settings.js index 2e4c2550..ba1f6a83 100644 --- a/src/settings.js +++ b/src/settings.js @@ -279,7 +279,8 @@ var PRINT_SPLIT_FILE_MARKER = 0; // Prints markers in Javascript generation to s var BUILD_AS_SHARED_LIB = 0; // Whether to build the code as a shared library // 0 here means this is not a shared lib: It is a main file. - // 1 means this is a normal shared lib, load it with dlopen(). + // All shared library options (1 and 2) are currently deprecated XXX + // 1 means this is a normal shared lib, load it with dlopen() // 2 means this is a shared lib that will be linked at runtime, // which means it will insert its functions into // the global namespace. See STATIC_LIBS_TO_LOAD. |