diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/jsifier.js | 52 | ||||
-rw-r--r-- | src/parseTools.js | 144 |
2 files changed, 129 insertions, 67 deletions
diff --git a/src/jsifier.js b/src/jsifier.js index 97a25188..ce089334 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -311,20 +311,21 @@ function JSify(data, functionsOnly, givenFunctions) { if (!LibraryManager.library[item.ident.slice(1)]) return ret; } + // ensure alignment + constant = constant.concat(zeros(Runtime.alignMemory(constant.length) - constant.length)); + + // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations + if (item.ident.substr(0, 5) == '__ZTV') { + constant = constant.concat(zeros(Runtime.alignMemory(QUANTUM_SIZE))); + } + // NOTE: This is the only place that could potentially create static // allocations in a shared library. constant = makePointer(constant, null, allocator, item.type, index); - var js; - js = (index !== null ? '' : item.ident + '=') + constant + ';'; + var js = (index !== null ? '' : item.ident + '=') + constant; + if (js) js += ';'; - // Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations - if (item.ident.substr(0, 5) == '__ZTV') { - if (index !== null) { - index = getFastValue(index, '+', Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type))); - } - js += '\n' + makePointer([0], null, allocator, ['void*'], index) + ';'; - } if (!ASM_JS && (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS))) { js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; } @@ -1497,8 +1498,36 @@ function JSify(data, functionsOnly, givenFunctions) { print('assert(STATICTOP < TOTAL_MEMORY);\n'); } } - var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable).concat(itemsDict.GlobalVariablePostSet); - if (!DEBUG_MEMORY) print(generated.map(function(item) { return item.JS }).join('\n')); + var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable); + print(generated.map(function(item) { return item.JS }).join('\n')); + + if (phase == 'pre') { + if (memoryInitialization.length > 0) { + // apply postsets directly into the big memory initialization + itemsDict.GlobalVariablePostSet = itemsDict.GlobalVariablePostSet.filter(function(item) { + var m; + if (m = /^HEAP([\dFU]+)\[([()>\d]+)\] *= *([()|\d{}\w_' ]+);?$/.exec(item.JS)) { + var type = getTypeFromHeap(m[1]); + var bytes = Runtime.getNativeTypeSize(type); + var target = eval(m[2]) << log2(bytes); + var value = m[3]; + try { + value = eval(value); + } catch(e) { + // possibly function table {{{ FT_* }}} etc. + if (value.indexOf('{{ ') < 0) return true; + } + writeInt8s(memoryInitialization, target - TOTAL_STACK, 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(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); return; } @@ -1520,7 +1549,6 @@ function JSify(data, functionsOnly, givenFunctions) { } }); } - JSify(globalsData, true, Functions); globalsData = null; data.unparsedGlobalss = null; diff --git a/src/parseTools.js b/src/parseTools.js index 6818e442..20049094 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1457,7 +1457,44 @@ function makeGetPos(ptr) { var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP'); -function makePointer(slab, pos, allocator, type, ptr) { +var temp64f = new Float64Array(1); +var temp32f = new Float32Array(temp64f.buffer); +var temp32 = new Uint32Array(temp64f.buffer); +var temp16 = new Uint16Array(temp64f.buffer); +var temp8 = new Uint8Array(temp64f.buffer); +var memoryInitialization = []; + +function writeInt8s(slab, i, value, type) { + var currSize; + switch (type) { + case 'i1': + case 'i8': temp8[0] = value; currSize = 1; break; + case 'i16': temp16[0] = value; currSize = 2; break; + case 'float': temp32f[0] = value; currSize = 4; break; + case 'double': temp64f[0] = value; currSize = 8; break; + case 'i64': // fall through, i64 is two i32 chunks + case 'i32': // fall through, i32 can be a pointer + default: { + if (type == 'i32' || type == 'i64' || type[type.length-1] == '*') { + if (!isNumber(value)) { // function table stuff, etc. + slab[i] = value; + slab[i+1] = slab[i+2] = slab[i+3] = 0; + return 4; + } + temp32[0] = value; + currSize = 4; + } else { + throw 'what? ' + types[i]; + } + } + } + for (var j = 0; j < currSize; j++) { + slab[i+j] = temp8[j]; + } + return currSize; +} + +function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization) { assert(type, 'makePointer requires type info'); if (typeof slab == 'string' && (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP))) return pos; var types = generateStructTypes(type); @@ -1472,19 +1509,19 @@ function makePointer(slab, pos, allocator, type, ptr) { } } // compress type info and data if possible - var de; - try { - // compress all-zeros into a number (which will become zeros(..)). - // note that we cannot always eval the slab, e.g., if it contains ident,0,0 etc. In that case, no compression TODO: ensure we get arrays here, not str - var evaled = typeof slab === 'string' ? eval(slab) : slab; - de = dedup(evaled); - if (de.length === 1 && de[0] == 0) { - slab = types.length; - } - // TODO: if not all zeros, at least filter out items with type === 0. requires cleverness to know how to skip at runtime though. also - // be careful of structure padding - } catch(e){} if (USE_TYPED_ARRAYS != 2) { + var de; + try { + // compress all-zeros into a number (which will become zeros(..)). + // note that we cannot always eval the slab, e.g., if it contains ident,0,0 etc. In that case, no compression TODO: ensure we get arrays here, not str + var evaled = typeof slab === 'string' ? eval(slab) : slab; + de = dedup(evaled); + if (de.length === 1 && de[0] == 0) { + slab = types.length; + } + // TODO: if not all zeros, at least filter out items with type === 0. requires cleverness to know how to skip at runtime though. also + // be careful of structure padding + } catch(e){} de = dedup(types); if (de.length === 1) { types = de[0]; @@ -1496,50 +1533,32 @@ function makePointer(slab, pos, allocator, type, ptr) { } } } else { // USE_TYPED_ARRAYS == 2 - var fail = false; - if (typeof slab === 'object') { - // flatten out into i8 values, so we can just to typed array .set() - for (var i = 0; i < slab.length; i++) { - if (!isNumber(slab[i])) { fail = true; break } + if (!finalMemoryInitialization) { + // XXX This heavily assumes the target endianness is the same as our current endianness! XXX + var i = 0; + while (i < slab.length) { + var currType = types[i]; + if (!currType) { i++; continue } + i += writeInt8s(slab, i, slab[i], currType); } - if (!fail) { - // XXX This heavily assumes the target endianness is the same as our current endianness! XXX - var i = 0; - var temp64f = new Float64Array(1); - var temp32f = new Float32Array(temp64f.buffer); - var temp32 = new Uint32Array(temp64f.buffer); - var temp16 = new Uint16Array(temp64f.buffer); - var temp8 = new Uint8Array(temp64f.buffer); - while (i < slab.length) { - var currType = types[i]; - if (!currType) { i++; continue } - var currSize = 0, currValue = slab[i]; - switch (currType) { - case 'i8': i++; continue; - case 'i16': temp16[0] = currValue; currSize = 2; break; - case 'i64': // fall through, i64 is two i32 chunks - case 'i32': temp32[0] = currValue; currSize = 4; break; - case 'float': temp32f[0] = currValue; currSize = 4; break; - case 'double': temp64f[0] = currValue; currSize = 8; break; - default: { - if (currType[currType.length-1] == '*') { - temp32[0] = currValue; - currSize = 4; - } else { - throw 'what? ' + types[i]; - } - } - } - for (var j = 0; j < currSize; j++) { - slab[i+j] = temp8[j]; - } - i += currSize; - } + types = 'i8'; + } + } + if (allocator == 'ALLOC_NONE' && USE_TYPED_ARRAYS == 2) { + if (!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 + for (var i = 0; i < slab.length; i++) { + memoryInitialization[offset + i] = slab[i]; } + return ''; } - if (!fail) types = 'i8'; + // This is the final memory initialization + types = 'i8'; } - if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; + // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime var chunkSize = 10240; function chunkify(array) { @@ -1552,14 +1571,18 @@ function makePointer(slab, pos, allocator, type, ptr) { } return ret; } - if (typeof slab == 'string' && evaled && evaled.length > chunkSize && slab.length > chunkSize) { - slab = chunkify(evaled); + if (typeof slab == 'object' && slab.length > chunkSize) { + slab = chunkify(slab); + } + if (typeof types == 'object') { + while (types.length < slab.length) types.push(0); } if (typeof types != 'string' && types.length > chunkSize) { types = chunkify(types); } else { types = JSON.stringify(types); } + if (typeof slab == 'object') slab = '[' + slab.join(',') + ']'; return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')'; } @@ -2326,3 +2349,14 @@ function charCode(char) { return char.charCodeAt(0); } +function getTypeFromHeap(suffix) { + switch (suffix) { + case '8': return 'i8'; + case '16': return 'i16'; + case '32': return 'i32'; + case 'F32': return 'float'; + case 'F64': return 'double'; + default: throw 'getTypeFromHeap? ' + suffix; + } +} + |