typed arrays support; function __index__ing ; 36% speedup
This commit is contained in:
Родитель
5a4c4614b7
Коммит
425295d786
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -69,8 +73,19 @@ function Pointer_make(slab, pos, allocator) {
|
|||
for (var i = 0; i < slab.length - pos; i++) {
|
||||
#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 = '';
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -69,17 +69,19 @@ class RunnerCore(unittest.TestCase):
|
|||
output = Popen([LLVM_DIS, filename + '.o'] + LLVM_DIS_OPTS + ['-o=' + filename + '.o.ll'], stdout=PIPE, stderr=STDOUT).communicate()[0]
|
||||
|
||||
# Run Emscripten
|
||||
emscripten_settings = ['{ "QUANTUM_SIZE": %d, "RELOOP": %d, "OPTIMIZE": %d, "GUARD_MEMORY": %d }' % (QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY)]
|
||||
exported_settings = {}
|
||||
for setting in ['QUANTUM_SIZE', 'RELOOP', 'OPTIMIZE', 'GUARD_MEMORY', 'USE_TYPED_ARRAYS']:
|
||||
exported_settings[setting] = eval(setting)
|
||||
out = open(filename + '.o.js', 'w') if not OUTPUT_TO_SCREEN else None
|
||||
timeout_run(Popen([EMSCRIPTEN, filename + '.o.ll', PARSER_ENGINE] + emscripten_settings, stdout=out, stderr=STDOUT), 240, 'Compiling')
|
||||
timeout_run(Popen([EMSCRIPTEN, filename + '.o.ll', COMPILER_ENGINE[0], str(exported_settings).replace("'", '"')], stdout=out, stderr=STDOUT), 240, 'Compiling')
|
||||
output = open(filename + '.o.js').read()
|
||||
if output_processor is not None:
|
||||
output_processor(output)
|
||||
if output is not None and 'Traceback' in output: print output; assert 0
|
||||
|
||||
def run_generated_code(self, filename, args=[], check_timeout=True):
|
||||
return timeout_run(Popen([JS_ENGINE] + JS_ENGINE_OPTS + [filename] + ([] if JS_ENGINE == SPIDERMONKEY_ENGINE else ['--']) + args,
|
||||
stdout=PIPE, stderr=STDOUT), 120 if check_timeout else None, 'Execution')
|
||||
def run_generated_code(self, engine, filename, args=[], check_timeout=True):
|
||||
return timeout_run(Popen(engine + [filename] + ([] if engine == SPIDERMONKEY_ENGINE else ['--']) + args,
|
||||
stdout=PIPE, stderr=STDOUT), 30 if check_timeout else None, 'Execution')
|
||||
|
||||
if 'benchmark' not in sys.argv:
|
||||
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
|
||||
|
@ -92,12 +94,14 @@ if 'benchmark' not in sys.argv:
|
|||
if not no_build:
|
||||
self.build(src, dirname, filename, output_processor, main_file)
|
||||
|
||||
# Run
|
||||
js_output = self.run_generated_code(filename + '.o.js', args)
|
||||
if output_nicerizer is not None:
|
||||
js_output = output_nicerizer(js_output)
|
||||
self.assertContained(expected_output, js_output)
|
||||
self.assertNotContained('ERROR', js_output)
|
||||
# Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
|
||||
engines = [V8_ENGINE] if not OPTIMIZE else [V8_ENGINE, SPIDERMONKEY_ENGINE]
|
||||
for engine in engines:
|
||||
js_output = self.run_generated_code(engine, filename + '.o.js', args)
|
||||
if output_nicerizer is not None:
|
||||
js_output = output_nicerizer(js_output)
|
||||
self.assertContained(expected_output, js_output)
|
||||
self.assertNotContained('ERROR', js_output)
|
||||
|
||||
#shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
|
||||
|
||||
|
@ -475,6 +479,26 @@ if 'benchmark' not in sys.argv:
|
|||
'''
|
||||
self.do_test(src, '*11,74*')
|
||||
|
||||
def test_funcptr(self):
|
||||
src = '''
|
||||
#include <stdio.h>
|
||||
int calc1() { return 26; }
|
||||
int calc2() { return 90; }
|
||||
typedef int (*fp_t)();
|
||||
int main()
|
||||
{
|
||||
fp_t fp = calc1;
|
||||
void *vp = (void*)fp;
|
||||
fp_t fpb = (fp_t)vp;
|
||||
fp_t fp2 = calc2;
|
||||
void *vp2 = (void*)fp2;
|
||||
fp_t fpb2 = (fp_t)vp2;
|
||||
printf("*%d,%d,%d,%d*\\n", fp(), fpb(), fp2(), fpb2());
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
self.do_test(src, '*26,26,90,90*')
|
||||
|
||||
def test_emptyclass(self):
|
||||
src = '''
|
||||
#include <stdio.h>
|
||||
|
@ -849,7 +873,7 @@ if 'benchmark' not in sys.argv:
|
|||
def test_sauer(self):
|
||||
# XXX Warning: Running this in SpiderMonkey can lead to an extreme amount of memory being
|
||||
# used, see Mozilla bug 593659.
|
||||
assert PARSER_ENGINE != SPIDERMONKEY_ENGINE
|
||||
assert COMPILER_ENGINE != SPIDERMONKEY_ENGINE
|
||||
|
||||
self.do_test(path_from_root(['tests', 'sauer']), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp')
|
||||
|
||||
|
@ -857,15 +881,10 @@ if 'benchmark' not in sys.argv:
|
|||
def make_test(compiler, embetter):
|
||||
class TT(T):
|
||||
def setUp(self):
|
||||
global COMPILER
|
||||
global COMPILER, QUANTUM_SIZE, RELOOP, OPTIMIZE, GUARD_MEMORY, USE_TYPED_ARRAYS
|
||||
COMPILER = compiler['path']
|
||||
global QUANTUM_SIZE
|
||||
QUANTUM_SIZE = compiler['quantum_size']
|
||||
global RELOOP
|
||||
RELOOP = embetter
|
||||
global OPTIMIZE
|
||||
OPTIMIZE = embetter
|
||||
global GUARD_MEMORY
|
||||
RELOOP = OPTIMIZE = USE_TYPED_ARRAYS = embetter
|
||||
GUARD_MEMORY = 1-embetter
|
||||
return TT
|
||||
for embetter in [0,1]:
|
||||
|
@ -879,15 +898,14 @@ else:
|
|||
sys.argv = filter(lambda x: x != 'benchmark', sys.argv)
|
||||
|
||||
COMPILER = LLVM_GCC
|
||||
PARSER_ENGINE = V8_ENGINE
|
||||
JS_ENGINE = SPIDERMONKEY_ENGINE
|
||||
if JS_ENGINE == SPIDERMONKEY_ENGINE:
|
||||
JS_ENGINE_OPTS += ['-j', '-m'] # TODO: use this everywhere else
|
||||
#JS_ENGINE = V8_ENGINE
|
||||
|
||||
RELOOP = OPTIMIZE = 1
|
||||
GUARD_MEMORY = 0
|
||||
QUANTUM_SIZE = 1
|
||||
TEST_REPS = 20
|
||||
RELOOP = OPTIMIZE = USE_TYPED_ARRAYS = 1
|
||||
GUARD_MEMORY = 0
|
||||
|
||||
TEST_REPS = 10
|
||||
TOTAL_TESTS = 2
|
||||
|
||||
tests_done = 0
|
||||
|
@ -913,7 +931,7 @@ else:
|
|||
times = []
|
||||
for i in range(TEST_REPS):
|
||||
start = time.time()
|
||||
self.run_generated_code(filename + '.o.js', args, check_timeout=False)
|
||||
self.run_generated_code(JS_ENGINE, filename + '.o.js', args, check_timeout=False)
|
||||
curr = time.time()-start
|
||||
times.append(curr)
|
||||
total_times[i] += curr
|
||||
|
@ -936,7 +954,7 @@ else:
|
|||
self.do_benchmark(src, ['5', '64'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
for cmd in map(lambda compiler: compiler['path'], COMPILERS.values()) + [LLVM_DIS, PARSER_ENGINE, JS_ENGINE]:
|
||||
for cmd in map(lambda compiler: compiler['path'], COMPILERS.values()) + [LLVM_DIS, SPIDERMONKEY_ENGINE[0], V8_ENGINE[0]]:
|
||||
print "Checking for existence of", cmd
|
||||
assert(os.path.exists(cmd))
|
||||
print "Running Emscripten tests..."
|
||||
|
|
|
@ -25,18 +25,13 @@ LLVM_DIS_OPTS = []
|
|||
if '2.8' in LLVM_ROOT:
|
||||
LLVM_DIS_OPTS += ['-show-annotations']
|
||||
|
||||
SPIDERMONKEY_ENGINE=os.path.expanduser('~/Dev/mozilla-central/js/src/js')
|
||||
V8_ENGINE=os.path.expanduser('~/Dev/v8/d8')
|
||||
SPIDERMONKEY_ENGINE = [os.path.expanduser('~/Dev/mozilla-central/js/src/js'), '-m'] # No |-j| due to Mozilla bug XXX
|
||||
V8_ENGINE = [os.path.expanduser('~/Dev/v8/d8')]
|
||||
|
||||
# XXX Warning: Compiling the 'sauer' test in SpiderMonkey can lead to an extreme amount of memory being
|
||||
# used, see Mozilla bug 593659. Possibly also some other tests as well.
|
||||
#PARSER_ENGINE=SPIDERMONKEY_ENGINE
|
||||
PARSER_ENGINE=V8_ENGINE
|
||||
|
||||
#JS_ENGINE=SPIDERMONKEY_ENGINE
|
||||
JS_ENGINE=V8_ENGINE
|
||||
|
||||
JS_ENGINE_OPTS=[]
|
||||
#COMPILER_ENGINE=SPIDERMONKEY_ENGINE
|
||||
COMPILER_ENGINE=V8_ENGINE
|
||||
|
||||
OUTPUT_TO_SCREEN = 0 # useful for debugging specific tests, or for subjectively seeing what parts are slow
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче