diff options
author | Alon Zakai <azakai@mozilla.com> | 2010-11-26 16:55:02 -0800 |
---|---|---|
committer | Alon Zakai <azakai@mozilla.com> | 2010-11-26 16:55:02 -0800 |
commit | 74e61fc15af507cbcb53003ca5556105eaaa7e18 (patch) | |
tree | 733cb077609f55d98aca55801c298f7b82f93fd6 | |
parent | 760f8dba70c9a108ff7cacd9950464fde26b54c1 (diff) |
improve varargs support
-rw-r--r-- | src/intertyper.js | 21 | ||||
-rw-r--r-- | src/jsifier.js | 49 | ||||
-rw-r--r-- | src/library.js | 3 | ||||
-rw-r--r-- | src/preamble.js | 42 | ||||
-rw-r--r-- | tests/runner.py | 27 |
5 files changed, 104 insertions, 38 deletions
diff --git a/src/intertyper.js b/src/intertyper.js index 16c83130..8c0136a3 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -65,11 +65,14 @@ function intertyper(data, parseFunctions, baseLineNum) { if (!parseFunctions && /^}.*/.test(line)) { inFunction = false; if (!parseFunctions) { + var func = funcHeader.processItem(tokenizer.processItem({ lineText: currFunctionLines[0] }, true))[0]; unparsedFunctions.push({ __result__: true, intertype: 'unparsedFunction', - // We need this early, to know all function idents - ident: toNiceIdent(funcHeader.processItem(tokenizer.processItem({ lineText: currFunctionLines[0] }, true))[0].ident), + // We need this early, to know basic function info - ident, params, varargs + ident: toNiceIdent(func.ident), + params: func.params, + hasVarArgs: func.hasVarArgs, lineNum: currFunctionLineNum, lines: currFunctionLines, }); @@ -385,15 +388,23 @@ function intertyper(data, parseFunctions, baseLineNum) { item.tokens = item.tokens.filter(function(token) { return !(token.text in LLVM.LINKAGES || token.text in set('noalias', 'hidden', 'signext', 'zeroext', 'nounwind', 'define', 'inlinehint', '{', 'fastcc')); }); - var ret = [{ + var ret = { __result__: true, intertype: 'function', ident: item.tokens[1].text, returnType: item.tokens[0], params: parseParamTokens(item.tokens[2].item.tokens), lineNum: item.lineNum, - }]; - return ret; + }; + ret.hasVarArgs = false; + ret.paramIdents = ret.params.map(function(param) { + if (param.intertype == 'varargs') { + ret.hasVarArgs = true; + return null; + } + return toNiceIdent(param.ident); + }).filter(function(param) { return param != null });; + return [ret]; }, }); // label diff --git a/src/jsifier.js b/src/jsifier.js index 15428e78..f525c067 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -9,7 +9,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { // Now that analysis has completed, we can get around to handling unparsedFunctions (functionsOnly ? data.functions : data.unparsedFunctions.concat(data.functions)).forEach(function(func) { - FUNCTIONS[func.ident] = true; + FUNCTIONS[func.ident] = func; }); for (var i = 0; i < data.unparsedFunctions.length; i++) { @@ -323,16 +323,7 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { // We have this function all reconstructed, go and finalize it's JS! - var hasVarArgs = false; - var params = func.params.map(function(param) { - if (param.intertype == 'varargs') { - hasVarArgs = true; - return null; - } - return toNiceIdent(param.ident); - }).filter(function(param) { return param != null });; - - func.JS = '\nfunction ' + func.ident + '(' + params.join(', ') + ') {\n'; + func.JS = '\nfunction ' + func.ident + '(' + func.paramIdents.join(', ') + ') {\n'; func.JS += ' ' + RuntimeGenerator.stackEnter(func.initialStack) + ';\n'; @@ -341,8 +332,8 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { if (true) { // TODO: optimize away when not needed func.JS += ' var __label__;\n'; } - if (hasVarArgs) { - func.JS += ' var __numArgs__ = ' + params.length + ';\n'; + if (func.hasVarArgs) { + func.JS += ' var __numArgs__ = ' + func.paramIdents.length + ';\n'; } if (func.hasPhi) { func.JS += ' var __lastLabel__ = null;\n'; @@ -892,9 +883,8 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { function makeFunctionCall(ident, params, funcData) { // Special cases if (ident == '_llvm_va_start') { - // varargs - var args = 'Array.prototype.slice.call(arguments, __numArgs__)'; - var data = 'Pointer_make([' + args + '.length].concat(' + args + '), 0)'; + // varargs - we received a pointer to the varargs as a final parameter + var data = 'arguments[__numArgs__]'; if (SAFE_HEAP) { return 'SAFE_HEAP_STORE(' + params[0].ident + ', ' + data + ', null)'; } else { @@ -904,19 +894,36 @@ function JSify(data, functionsOnly, givenTypes, givenFunctions) { return ';' } - var params = params.map(function(param) { + var func = FUNCTIONS[ident]; + var args = []; + var varargs = []; + + params.forEach(function(param, i) { + var val; if (param.intertype in PARSABLE_LLVM_FUNCTIONS) { - return finalizeLLVMFunctionCall(param); + val = finalizeLLVMFunctionCall(param); + } else { + val = toNiceIdent(param.ident); + } + if (!func || !func.hasVarArgs || i < func.params.length-1) { // unrecognized functions (like library ones) cannot have varargs + args.push(val); } else { - return toNiceIdent(param.ident); + varargs.push(val); + varargs = varargs.concat(zeros(getNativeFieldSize(param.type)-1)); } - }).map(indexizeFunctions); + }); + + args = args.map(indexizeFunctions); + varargs = varargs.map(indexizeFunctions); + if (varargs.length > 0) { + varargs = makePointer(varargs, 0, 'ALLOC_STACK'); + } if (getVarData(funcData, ident)) { ident = 'FUNCTION_TABLE[' + ident + ']'; } - return ident + '(' + params.join(', ') + ')'; + return ident + '(' + args.concat(varargs).join(', ') + ')'; } makeFuncLineZyme('getelementptr', function(item) { return finalizeLLVMFunctionCall(item) }); makeFuncLineZyme('call', function(item) { diff --git a/src/library.js b/src/library.js index 6e41b547..542fe7e3 100644 --- a/src/library.js +++ b/src/library.js @@ -63,8 +63,7 @@ var Library = { }, vsnprintf: function(dst, num, src, ptr) { - var args = Array_copy(ptr+1, IHEAP[ptr]); // # of args in in first place - var text = __formatString.apply(null, [src].concat(args)); + var text = __formatString(-src, ptr); // |-|src tells formatstring to use C-style params (typically they are from varargs) for (var i = 0; i < num; i++) { IHEAP[dst+i] = IHEAP[text+i]; if (IHEAP[dst+i] == 0) break; diff --git a/src/preamble.js b/src/preamble.js index 976e3c90..6958068f 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -229,15 +229,37 @@ function __shutdownRuntime__() { // C-style: we work on ints on the HEAP. function __formatString() { + var cStyle = false; var textIndex = arguments[0]; var argIndex = 1; + if (textIndex < 0) { + cStyle = true; + textIndex = -textIndex; + slab = null; + argIndex = arguments[1]; + } else { + var _arguments = arguments; + } + function getNextArg(type) { + var ret; + if (!cStyle) { + ret = _arguments[argIndex]; + argIndex++; + } else { + ret = (type === 'f' ? FHEAP : IHEAP)[argIndex]; + argIndex += type === 'l'.charCodeAt(0) ? 8 : 4; // XXX hardcoded native sizes + } + return ret; + } + var ret = []; - var curr = -1; + var curr = -1, next, currArg; while (curr) { // Note: should be curr != 0, technically. But this helps catch bugs with undefineds curr = IHEAP[textIndex]; next = IHEAP[textIndex+1]; if (curr == '%'.charCodeAt(0) && ['d', 'u', 'f', '.'].indexOf(String.fromCharCode(next)) != -1) { - var argText = String(+arguments[argIndex]); // +: boolean=>int + var currArg; + var argText; // Handle very very simply formatting, namely only %.Xf if (next == '.'.charCodeAt(0)) { var limit = 0; @@ -249,6 +271,9 @@ function __formatString() { textIndex++; } textIndex--; + next = IHEAP[textIndex+1]; + currArg = getNextArg(next); + argText = String(+currArg); // +: boolean=>int var dotIndex = argText.indexOf('.'); if (dotIndex == -1) { dotIndex = argText.length; @@ -258,20 +283,21 @@ function __formatString() { argText = argText.substr(0, dotIndex+1+limit); textIndex += 2; } else if (next == 'u'.charCodeAt(0)) { - argText = String(unSign(arguments[argIndex], 32)); + currArg = getNextArg(next); + argText = String(unSign(currArg, 32)); + } else { + currArg = getNextArg(next); + argText = String(+currArg); // +: boolean=>int } argText.split('').forEach(function(chr) { ret.push(chr.charCodeAt(0)); }); - argIndex += 1; textIndex += 2; } else if (curr == '%'.charCodeAt(0) && next == 's'.charCodeAt(0)) { - ret = ret.concat(String_copy(arguments[argIndex])); - argIndex += 1; + ret = ret.concat(String_copy(getNextArg(next))); textIndex += 2; } else if (curr == '%'.charCodeAt(0) && next == 'c'.charCodeAt(0)) { - ret = ret.concat(arguments[argIndex]); - argIndex += 1; + ret = ret.concat(getNextArg(next)); textIndex += 2; } else { ret.push(curr); diff --git a/tests/runner.py b/tests/runner.py index f58f3d7b..4749cea6 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -817,7 +817,7 @@ if 'benchmark' not in sys.argv: def test_varargs(self): src = ''' #include <stdio.h> - #include "stdarg.h" + #include <stdarg.h> void vary(const char *s, ...) { @@ -840,13 +840,36 @@ if 'benchmark' not in sys.argv: va_end(v); } + #define GETMAX(pref, type) \ + type getMax##pref(int num, ...) \ + { \ + va_list vv; \ + va_start(vv, num); \ + type maxx = va_arg(vv, type); \ + for (int i = 1; i < num; i++) \ + { \ + type curr = va_arg(vv, type); \ + maxx = curr > maxx ? curr : maxx; \ + } \ + va_end(vv); \ + return maxx; \ + } + GETMAX(i, int); + GETMAX(D, double); + int main() { vary("*cheez: %d+%d*", 0, 24); // Also tests that '0' is not special as an array ender vary2('Q', "%d*", 85); + + int maxxi = getMaxi(6, 2, 5, 21, 4, -10, 19); + printf("maxxi:%d*\\n", maxxi); + double maxxD = getMaxD(6, (double)2.1, (double)5.1, (double)22.1, (double)4.1, (double)-10.1, (double)19.1); + printf("maxxD:%.2f*\\n", (float)maxxD); + return 0; } ''' - self.do_test(src, '*cheez: 0+24*\nQ85*') + self.do_test(src, '*cheez: 0+24*\nQ85*\nmaxxi:21*\nmaxxD:22.10*\n') def test_stdlibs(self): src = ''' |