aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jsifier.js52
-rw-r--r--src/parseTools.js144
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;
+ }
+}
+