diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler.js | 4 | ||||
-rw-r--r-- | src/jsifier.js | 82 | ||||
-rw-r--r-- | src/library.js | 35 | ||||
-rw-r--r-- | src/parseTools.js | 39 | ||||
-rw-r--r-- | src/postamble.js | 6 | ||||
-rw-r--r-- | src/preamble.js | 70 | ||||
-rw-r--r-- | src/settings.js | 1 |
7 files changed, 178 insertions, 59 deletions
diff --git a/src/compiler.js b/src/compiler.js index ba36f215..13b2d3cc 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -29,6 +29,10 @@ for (setting in settings) { this[setting] = settings[setting]; } +// Sanity of settings + +assert(!(USE_TYPED_ARRAYS && SAFE_HEAP)); + // Read llvm var lines = []; var line; diff --git a/src/jsifier.js b/src/jsifier.js index bcc436a4..547bde72 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -4,6 +4,10 @@ function JSify(data) { substrate = new Substrate('JSifyer'); var TYPES = data.types; + var FUNCTIONS = {}; + data.functions.forEach(function(func) { + FUNCTIONS[func.ident] = func; + }); // type substrate.addZyme('Type', { @@ -20,20 +24,29 @@ function JSify(data) { }); function makePointer(slab, pos, allocator, type) { // type is FFU - if (slab == 'HEAP') return pos; + if (slab in set('HEAP', 'IHEAP', 'FHEAP')) return pos; if (slab[0] != '[') { slab = '[' + slab + ']'; } return 'Pointer_make(' + slab + ', ' + (pos ? pos : 0) + (allocator ? ', ' + allocator : '') + ')'; } - function makeGetSlab(ptr) { - // return ptr + '.slab'; - return 'HEAP'; + function makeGetSlab(ptr, type) { + assert(type); + if (!USE_TYPED_ARRAYS) { + return 'HEAP'; + } else { + if (type in FLOAT_TYPES || type === 'int64') { + return 'FHEAP'; + } else if (type in INT_TYPES || isPointerType(type)) { + return 'IHEAP'; + } else { + return 'HEAP'; + } + } } function makeGetPos(ptr) { - // return ptr + '.pos'; return ptr; } @@ -43,15 +56,23 @@ function JSify(data) { } function makeGetValue(ptr, pos, noNeedFirst, type) { - return makeGetSlab(ptr) + '[' + calcFastOffset(ptr, pos, noNeedFirst) + ']'; + return makeGetSlab(ptr, type) + '[' + calcFastOffset(ptr, pos, noNeedFirst) + ']'; + } + + function indexizeFunctions(value) { // TODO: Also check for other functions (externals, library, etc.) + if (value in FUNCTIONS) { + value = value + '.__index__'; // Store integer value + } + return value; } function makeSetValue(ptr, pos, value, noNeedFirst, type) { + value = indexizeFunctions(value); var offset = calcFastOffset(ptr, pos, noNeedFirst); if (SAFE_HEAP) { return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ')'; } else { - return makeGetSlab(ptr) + '[' + offset + '] = ' + value; + return makeGetSlab(ptr, type) + '[' + offset + '] = ' + value; } } @@ -135,7 +156,7 @@ function JSify(data) { throw 'Invalid segment: ' + dump(segment); } }; - return splitTokenList(tokens).map(handleSegment).map(parseNumerical); + return splitTokenList(tokens).map(handleSegment).map(parseNumerical).map(indexizeFunctions); } if (value.item) { // list of items @@ -206,6 +227,17 @@ function JSify(data) { this.forwardItems(ret, 'FuncLineTriager'); }, }); + + var FUNCTION_INDEX = 0; + var FUNCTION_HASH = {}; + function getFunctionIndex(name_) { + if (!(name_ in FUNCTION_HASH)) { + FUNCTION_HASH[name_] = FUNCTION_INDEX; + FUNCTION_INDEX++; + } + return FUNCTION_HASH[name_]; + } + // function reconstructor & post-JS optimizer substrate.addZyme('FunctionReconstructor', { funcs: {}, @@ -339,14 +371,21 @@ function JSify(data) { // Finalize function if (LABEL_DEBUG) func.JS += " INDENT = INDENT.substr(0, INDENT.length-2);\n"; func.JS += '}\n'; + func.JS += func.ident + '.__index__ = ' + getFunctionIndex(func.ident) + ';\n'; + func.JS += 'FUNCTION_TABLE[' + getFunctionIndex(func.ident) + '] = ' + func.ident + ';\n'; func.__result__ = true; return func; }, }); - function getVarData(funcData, ident) { - if (funcData.variables[ident]) { - return funcData.variables[ident].impl; + function getVarData(funcData, ident) { // XXX - need to check globals as well! + return funcData.variables[ident]; + } + + function getVarImpl(funcData, ident) { + var data = getVarData(funcData, ident); + if (data) { + return data.impl; } else { return 'emulated'; // All global are emulated } @@ -383,7 +422,7 @@ function JSify(data) { var type = item.value.type; var value = parseNumerical(item.value.JS); //print("zz var: " + item.JS); - var impl = getVarData(item.funcData, item.ident); + var impl = getVarImpl(item.funcData, item.ident); switch (impl) { case VAR_NATIVE: { break; @@ -422,7 +461,7 @@ function JSify(data) { } var impl = VAR_EMULATED; if (item.pointer.intertype == 'value') { - impl = getVarData(item.funcData, item.ident); + impl = getVarImpl(item.funcData, item.ident); } switch (impl) { case VAR_NATIVIZED: @@ -537,7 +576,7 @@ function JSify(data) { }); makeFuncLineZyme('load', function(item) { var ident = toNiceIdent(item.ident); - var impl = getVarData(item.funcData, item.ident); + var impl = getVarImpl(item.funcData, item.ident); switch (impl) { case VAR_NATIVIZED: { return ident; // We have the actual value here @@ -721,7 +760,7 @@ function JSify(data) { function finalizeLLVMFunctionCall(item) { switch(item.intertype) { case 'getelementptr': - return makePointer(makeGetSlab(item.ident), getGetElementPtrIndexes(item), null, item.type); + return makePointer(makeGetSlab(item.ident, item.type), getGetElementPtrIndexes(item), null, item.type); case 'bitcast': case 'inttoptr': case 'ptrtoint': @@ -747,7 +786,7 @@ function JSify(data) { return ident; }); - function makeFunctionCall(ident, params) { + function makeFunctionCall(ident, params, funcData) { // Special cases if (ident == '_llvm_va_start') { var args = 'Array.prototype.slice.call(arguments, __numArgs__)'; @@ -755,7 +794,7 @@ function JSify(data) { if (SAFE_HEAP) { return 'SAFE_HEAP_STORE(' + params[0].ident + ', ' + data + ', 0)'; } else { - return 'HEAP[' + params[0].ident + '] = ' + data; + return 'IHEAP[' + params[0].ident + '] = ' + data; } } else if (ident == '_llvm_va_end') { return ';' @@ -767,12 +806,17 @@ function JSify(data) { } else { return toNiceIdent(param.ident); } - }); + }).map(indexizeFunctions); + + if (funcData && getVarData(funcData, ident)) { + ident = 'FUNCTION_TABLE[' + ident + ']'; + } + return ident + '(' + params.join(', ') + ')'; } makeFuncLineZyme('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) }); makeFuncLineZyme('call', function(item) { - return makeFunctionCall(item.ident, item.params) + (item.standalone ? ';' : ''); + return makeFunctionCall(item.ident, item.params, item.funcData) + (item.standalone ? ';' : ''); }); // Optimzed intertypes diff --git a/src/library.js b/src/library.js index 09c4d8f1..0663d6c1 100644 --- a/src/library.js +++ b/src/library.js @@ -19,11 +19,11 @@ var Library = { }, vsnprintf: function(dst, num, src, ptr) { - var args = Array_copy(ptr+1, HEAP[ptr]); // # of args in in first place + var args = Array_copy(ptr+1, IHEAP[ptr]); // # of args in in first place var text = __formatString.apply(null, [src].concat(args)); for (var i = 0; i < num; i++) { - HEAP[dst+i] = HEAP[text+i]; - if (HEAP[dst+i] == 0) break; + IHEAP[dst+i] = IHEAP[text+i]; + if (IHEAP[dst+i] == 0) break; } }, @@ -42,7 +42,7 @@ var Library = { strlen: function(p) { var q = p; - while (HEAP[q] != 0) q++; + while (IHEAP[q] != 0) q++; return q - p; }, @@ -65,22 +65,22 @@ var Library = { strcpy: function(pdest, psrc) { var i = 0; do { - HEAP[pdest+i] = HEAP[psrc+i]; + IHEAP[pdest+i] = IHEAP[psrc+i]; i ++; - } while (HEAP[psrc+i-1] != 0); + } while (IHEAP[psrc+i-1] != 0); }, strncpy: function(pdest, psrc, num) { var padding = false; for (var i = 0; i < num; i++) { - HEAP[pdest+i] = padding ? 0 : HEAP[psrc+i]; - padding = padding || HEAP[psrc+i] == 0; + IHEAP[pdest+i] = padding ? 0 : IHEAP[psrc+i]; + padding = padding || IHEAP[psrc+i] == 0; } }, strlen: function(ptr) { var i = 0; - while (HEAP[ptr+i] != 0) i++; + while (IHEAP[ptr+i] != 0) i++; return i; }, @@ -88,9 +88,9 @@ var Library = { var len = Pointer_stringify(pdest).length; // TODO: use strlen, but need dependencies system var i = 0; do { - HEAP[pdest+len+i] = HEAP[psrc+i]; + IHEAP[pdest+len+i] = IHEAP[psrc+i]; i ++; - } while (HEAP[psrc+i-1] != 0); + } while (IHEAP[psrc+i-1] != 0); }, strtol: function(ptr) { @@ -101,8 +101,8 @@ var Library = { strcmp: function(px, py) { var i = 0; while (true) { - var x = HEAP[px+i]; - var y = HEAP[py+i]; + var x = IHEAP[px+i]; + var y = IHEAP[py+i]; if (x == y && x == 0) return 0; if (x == 0) return -1; if (y == 0) return 1; @@ -132,13 +132,6 @@ var Library = { return 0; }, - llvm_memset_i32: function(ptr, value, num) { - for (var i = 0; i < num; i++) { - HEAP[ptr+i] = value; - } - }, - llvm_memset_p0i8_i32: 'llvm_memset_i32', - llvm_eh_exception: function() { return 'code-generated exception: ' + (new Error().stack); }, @@ -229,7 +222,7 @@ var Library = { time: function(ptr) { var ret = Math.floor(Date.now()/1000); if (ptr) { - HEAP[ptr] = ret; + IHEAP[ptr] = ret; } return ret; }, diff --git a/src/parseTools.js b/src/parseTools.js index c4dae65e..4d1ed438 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -8,26 +8,27 @@ function preprocess(text, constants) { } var lines = text.split('\n'); var ret = ''; - var show = true; + var showStack = []; for (var i = 0; i < lines.length; i++) { var line = lines[i]; if (line[0] != '#') { - if (show) { + if (showStack.indexOf(false) == -1) { ret += line + '\n'; } } else { if (line[1] == 'i') { // if var ident = line.substr(4); - show = !!this[ident] && this[ident] > 0; + showStack.push(!!this[ident] && this[ident] > 0); } else if (line[2] == 'l') { // else - show = !show; + showStack.push(!showStack.pop()); } else if (line[2] == 'n') { // endif - show = true; + showStack.pop(); } else { throw "Unclear preprocessor command: " + line; } } } + assert(showStack.length == 0); return ret; } @@ -47,6 +48,10 @@ function pointingLevels(type) { return ret; } +function removeAllPointing(type) { + return removePointing(type, pointingLevels(type)); +} + function toNiceIdent(ident) { assert(ident); if (parseFloat(ident) == ident) return ident; @@ -80,7 +85,7 @@ function isStructType(type) { return !isNumberType(type) && type[0] == '%'; } -function isPointerType(type) { // TODO! +function isPointerType(type) { return pointingLevels(type) > 0; } @@ -88,18 +93,13 @@ function isVoidType(type) { return type == 'void'; } -function isType(type) { // TODO! - return isVoidType(type) || isNumberType(type) || isStructType(type) || isPointerType(type); -} - // Detects a function definition, ([...|type,[type,...]]) function isFunctionDef(token) { var text = token.text; - var pointing = pointingLevels(text); - var nonPointing = removePointing(text, pointing); + var nonPointing = removeAllPointing(text); if (nonPointing[0] != '(' || nonPointing.substr(-1) != ')') return false; - if (nonPointing == '(...)') return true; + if (nonPointing in set('()', '(...)')) return true; if (!token.item) return false; var fail = false; splitTokenList(token.item[0].tokens).forEach(function(segment) { @@ -109,6 +109,19 @@ function isFunctionDef(token) { return !fail; } +function isFunctionType(type) { + var parts = type.split(' '); + if (parts.length != 2) return false; + if (pointingLevels(type) !== 1) return false; + var text = removeAllPointing(parts[1]); + var ret = isType(parts[0]) && isFunctionDef({ text: text, item: [{tokens: [{text: text.substr(1, text.length-2)}]}] }); + return ret; +} + +function isType(type) { // TODO! + return isVoidType(type) || isNumberType(type) || isStructType(type) || isPointerType(type) || isFunctionType(type); +} + function addIdent(token) { token.ident = token.text; return token; diff --git a/src/postamble.js b/src/postamble.js index 1329a1a4..07fe1d2e 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -23,7 +23,11 @@ function run(args) { _main(argc, argv); while( __ATEXIT__.length > 0) { - __ATEXIT__.pop()(); + var func = __ATEXIT__.pop(); + if (typeof func === 'number') { + func = FUNCTION_TABLE[func]; + } + func(); } } diff --git a/src/preamble.js b/src/preamble.js index 5496170d..1af1a6e9 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -3,6 +3,10 @@ function __globalConstructor__() { } +// Maps ints ==> functions. This lets us pass around ints, which are +// actually pointers to functions, and we convert at call()time +FUNCTION_TABLE = []; + var __THREW__ = false; // Used in checking for thrown exceptions. var __ATEXIT__ = []; @@ -43,7 +47,7 @@ function assert(condition, text) { } function Pointer_niceify(ptr) { - return { slab: HEAP, pos: ptr }; + return { slab: IHEAP, pos: ptr }; } // Creates a pointer for a certain slab and a certain address in that slab. @@ -70,8 +74,19 @@ function Pointer_make(slab, pos, allocator) { #if SAFE_HEAP SAFE_HEAP_STORE(ret + i, slab[pos + i]); #else +#if USE_TYPED_ARRAYS + // TODO: Check - also in non-typedarray case - for functions, and if so add |.__index__| + var curr = slab[pos + i]; + if (typeof curr === 'number') { + IHEAP[ret + i] = curr; // TODO: optimize. Can easily detect floats, but 1.0 might look like an int... + FHEAP[ret + i] = curr; + } else { + HEAP[ret + i] = curr; + } +#else HEAP[ret + i] = slab[pos + i]; #endif +#endif } return ret; } @@ -118,10 +133,28 @@ __ZdaPv = _free; // llvm-gcc function __initializeRuntime__() { HEAP = intArrayFromString('(null)'); // So printing %s of NULL gives '(null)' // Also this ensures we leave 0 as an invalid address, 'NULL' +#if USE_TYPED_ARRAYS + if (!this['TOTAL_MEMORY']) TOTAL_MEMORY = 50*1024*1024; + if (this['Int32Array']) { // check for engine support + IHEAP = new Int32Array(TOTAL_MEMORY); + for (var i = 0; i < HEAP.length; i++) { + IHEAP[i] = HEAP[i]; + } + } else { + IHEAP = HEAP; // fallback + } + if (this['Float64Array']) { // check for engine support + FHEAP = new Float64Array(TOTAL_MEMORY); + } else { + FHEAP = HEAP; // fallback + } +#else + IHEAP = HEAP; // We use that name in our runtime code that processes strings etc., see library.js +#endif STACK_STACK = []; STACK_ROOT = STACKTOP = alignMemoryPage(10); - if (!this['TOTAL_STACK']) TOTAL_STACK = 64*1024*100; // Reserved room for stack + if (!this['TOTAL_STACK']) TOTAL_STACK = 1024*1024; // Reserved room for stack STACK_MAX = STACK_ROOT + TOTAL_STACK; STATICTOP = alignMemoryPage(STACK_MAX); @@ -136,13 +169,22 @@ function __formatString() { var ret = []; var curr = -1; while (curr != 0) { +#if USE_TYPED_ARRAYS + curr = IHEAP[textIndex]; + next = IHEAP[textIndex+1]; +#else curr = HEAP[textIndex]; next = HEAP[textIndex+1]; +#endif if (curr == '%'.charCodeAt(0) && ['d', 'u', 'f', '.'].indexOf(String.fromCharCode(next)) != -1) { var argText = String(arguments[argIndex]); // Handle very very simply formatting, namely only %.Xf if (next == '.'.charCodeAt(0)) { +#if USE_TYPED_ARRAYS + var limit = parseInt(String.fromCharCode(IHEAP[textIndex+2])); +#else var limit = parseInt(String.fromCharCode(HEAP[textIndex+2])); +#endif var dotIndex = argText.indexOf('.'); if (dotIndex == -1) { dotIndex = argText.length; @@ -174,14 +216,16 @@ function __formatString() { // Copies a list of num items on the HEAP into a // a normal JavaScript array of numbers function Array_copy(ptr, num) { - // XXX hardcoded ptr impl - return HEAP.slice(ptr, ptr+num); +#if USE_TYPED_ARRAYS + return Array.prototype.slice.call(IHEAP.slice(ptr, ptr+num)); // Make a normal array out of the typed one +#else + return IHEAP.slice(ptr, ptr+num); +#endif } // Copies a C-style string, terminated by a zero, from the HEAP into // a normal JavaScript array of numbers function String_copy(ptr, addZero) { - // XXX hardcoded ptr impl return Array_copy(ptr, _strlen(ptr)).concat(addZero ? [0] : []); } @@ -199,6 +243,11 @@ function _llvm_memcpy_i32(dest, src, num, idunno) { SAFE_HEAP_STORE(dest + i, HEAP[src + i]); #else HEAP[dest + i] = HEAP[src + i]; +#if USE_TYPED_ARRAYS + // TODO: optimize somehow - this is slower than without typed arrays + IHEAP[dest + i] = IHEAP[src + i]; + FHEAP[dest + i] = FHEAP[src + i]; +#endif #endif } // dest = Pointer_niceify(dest); @@ -208,6 +257,17 @@ function _llvm_memcpy_i32(dest, src, num, idunno) { _llvm_memcpy_i64 = _llvm_memcpy_i32; _llvm_memcpy_p0i8_p0i8_i32 = _llvm_memcpy_i32; +function llvm_memset_i32(ptr, value, num) { + for (var i = 0; i < num; i++) { +#if USE_TYPED_ARRAYS + HEAP[ptr+i] = IHEAP[ptr+i] = FHEAP[ptr+i] = value; +#else + HEAP[ptr+i] = value; +#endif + } +} +_llvm_memset_p0i8_i32 = llvm_memset_i32; + // Tools PRINTBUFFER = ''; diff --git a/src/settings.js b/src/settings.js index d79869f1..6b621770 100644 --- a/src/settings.js +++ b/src/settings.js @@ -25,6 +25,7 @@ GUARD_MEMORY = 1; // Whether we should check that each allocation to the stack d // Code embetterments OPTIMIZE = 0; // Optimize llvm operations into js commands RELOOP = 0; // Recreate js native loops from llvm data +USE_TYPED_ARRAYS = 0; // Try to use typed arrays for the heap // Generated code debugging options SAFE_HEAP = 0; // Check each write to the heap against a list of blocked addresses |