diff options
-rw-r--r-- | src/intertyper.js | 27 | ||||
-rw-r--r-- | src/jsifier.js | 62 | ||||
-rw-r--r-- | src/library.js | 190 | ||||
-rw-r--r-- | src/parseTools.js | 13 | ||||
-rw-r--r-- | src/preamble.js | 8 | ||||
-rw-r--r-- | tests/cases/trunc.ll | 2 | ||||
-rw-r--r-- | tests/runner.py | 170 | ||||
-rw-r--r-- | tools/eliminator/eliminator.coffee | 82 | ||||
-rw-r--r-- | tools/shared.py | 2 |
9 files changed, 343 insertions, 213 deletions
diff --git a/src/intertyper.js b/src/intertyper.js index 232025cb..ed8d5099 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -461,22 +461,18 @@ function intertyper(data, parseFunctions, baseLineNum) { item.tokens = item.tokens.filter(function(token) { return !(token.text in LLVM.LINKAGES || token.text in LLVM.PARAM_ATTR || token.text in set('hidden', 'nounwind', 'define', 'inlinehint', '{') || token.text in LLVM.CALLING_CONVENTIONS); }); - var ret = { + var params = parseParamTokens(item.tokens[2].item.tokens); + return [{ intertype: 'function', ident: toNiceIdent(item.tokens[1].text), returnType: item.tokens[0].text, - params: parseParamTokens(item.tokens[2].item.tokens), - lineNum: item.lineNum - }; - 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]; + params: params, + hasVarArgs: hasVarArgs(params), + lineNum: item.lineNum, + paramIdents: params.map(function(param) { + return (param.intertype == 'varargs') ? null : toNiceIdent(param.ident); + }).filter(function(param) { return param != null; }) + }]; } }); // label @@ -798,11 +794,14 @@ function intertyper(data, parseFunctions, baseLineNum) { if (item.tokens[1].text in LLVM.LINKAGES || item.tokens[1].text in LLVM.PARAM_ATTR) { item.tokens.splice(1, 1); } + + var params = parseParamTokens(item.tokens[3].item.tokens); return [{ intertype: 'functionStub', ident: toNiceIdent(item.tokens[2].text), returnType: item.tokens[1], - params: item.tokens[3], + params: params, + hasVarArgs: hasVarArgs(params), lineNum: item.lineNum }]; } diff --git a/src/jsifier.js b/src/jsifier.js index 3da296f1..ab381a03 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -41,7 +41,8 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { var GLOBAL_VARIABLES = !mainPass ? givenGlobalVariables : data.globalVariables; - Functions.currFunctions = !mainPass ? givenFunctions : {}; + Functions.currFunctions = !mainPass ? givenFunctions.currFunctions : {}; + Functions.currExternalFunctions = !mainPass ? givenFunctions.currExternalFunctions : {}; // Now that first-pass analysis has completed (so we have basic types, etc.), we can get around to handling unparsedFunctions (!mainPass ? data.functions : data.unparsedFunctions.concat(data.functions)).forEach(function(func) { @@ -53,11 +54,22 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { }; }); + data.functionStubs.forEach(function(func) { + // Don't overwrite stubs that have more info. + if (!Functions.currExternalFunctions.hasOwnProperty(func.ident) || + !Functions.currExternalFunctions[func.ident].numParams === undefined) { + Functions.currExternalFunctions[func.ident] = { + hasVarArgs: func.hasVarArgs, + numParams: func.params && func.params.length + }; + } + }); + for (var i = 0; i < data.unparsedFunctions.length; i++) { var func = data.unparsedFunctions[i]; dprint('unparsedFunctions', '====================\n// Processing |' + func.ident + '|, ' + i + '/' + data.unparsedFunctions.length); //var t = Date.now(); - func.JS = JSify(analyzer(intertyper(func.lines, true, func.lineNum-1)), true, Functions.currFunctions, GLOBAL_VARIABLES); + func.JS = JSify(analyzer(intertyper(func.lines, true, func.lineNum-1)), true, Functions, GLOBAL_VARIABLES); //t = (Date.now()-t)/1000; //dprint('unparsedFunctions', 'unparsedFunction took ' + t + ' seconds.'); delete func.lines; // clean up memory as much as possible @@ -186,7 +198,13 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { '\n}\n'; return ret; } else { - item.JS = 'var ' + item.ident + ';'; + if (item.external && BUILD_AS_SHARED_LIB) { + // External variables in shared libraries should not be declared as + // they would shadow similarly-named globals in the parent. + item.JS = ''; + } else { + item.JS = 'var ' + item.ident + ';'; + } var constant = null; if (item.external) { return ret; @@ -267,6 +285,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { var snippet = LibraryManager.library[ident]; var redirectedIdent = null; var deps = LibraryManager.library[ident + '__deps'] || []; + var isFunction = false; if (typeof snippet === 'string') { if (LibraryManager.library[snippet]) { @@ -277,25 +296,24 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { snippet = '_' + snippet; } } else if (typeof snippet === 'object') { - // JSON.stringify removes functions, so we need to make sure they are added - var funcs = []; - var hasNonFunc = false; - for (var x in snippet) { - if (typeof snippet[x] === 'function') { - funcs.push(x + ': ' + snippet[x].toString()); - } else { - hasNonFunc = true; + if (snippet === null) { + snippet = 'null'; + } else { + var members = []; + for (var property in snippet) { + if (typeof snippet[property] === 'function') { + members.push(property + ': ' + snippet[property].toString()); + } else { + members.push(property + ': ' + JSON.stringify(snippet[property])); + } } - } - snippet = JSON.stringify(snippet); - if (funcs.length > 0) { - snippet = snippet.replace(/}$/, (hasNonFunc ? ', ' : '') + funcs.join(', ') + ' }'); + snippet = '{' + members.join(', ') + ' }'; } } else if (typeof snippet === 'function') { + isFunction = true; snippet = snippet.toString(); - if (/function ?\(/.exec(snippet)) { // name the function, if not already named - snippet = snippet.replace('function', 'function _' + ident); - } + // name the function; overwrite if it's already named + snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '('); } var postsetId = ident + '__postset'; @@ -317,7 +335,8 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { } else { ident = '_' + ident; } - var text = (deps ? '\n' + deps.map(addFromLibrary).join('\n') : '') + 'var ' + ident + '=' + snippet + ';'; + var text = (deps ? '\n' + deps.map(addFromLibrary).join('\n') : ''); + text += isFunction ? snippet : 'var ' + ident + '=' + snippet + ';'; if (ident in EXPORTED_FUNCTIONS) { text += '\nModule["' + ident + '"] = ' + ident + ';'; } @@ -755,7 +774,8 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { return ';'; } - var func = Functions.currFunctions[ident]; + var func = Functions.currFunctions[ident] || Functions.currExternalFunctions[ident]; + var args = []; var argsTypes = []; var varargs = []; @@ -763,7 +783,7 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { params.forEach(function(param, i) { var val = finalizeParam(param); - if (!func || !func.hasVarArgs || i < func.numParams-1) { // unrecognized functions (like library ones) cannot have varargs + if (!func || !func.hasVarArgs || i < func.numParams-1) { args.push(val); argsTypes.push(param.type); } else { diff --git a/src/library.js b/src/library.js index e6ca3851..ba82461b 100644 --- a/src/library.js +++ b/src/library.js @@ -393,10 +393,6 @@ LibraryManager.library = { // Once initialized, permissions start having effect. FS.ignorePermissions = false; - - // Allocate some necessary buffers now - FS.buffer1 = allocate([0], 'i8', ALLOC_STATIC); - FS.errno = allocate([0], 'i32', ALLOC_STATIC) } }, @@ -732,9 +728,7 @@ LibraryManager.library = { return -1; } else { var pathArray = intArrayFromString(FS.streams[fildes].path); - var pathPtr = allocate(pathArray, 'i8', ALLOC_STACK); - var result = _stat(pathPtr, buf); - return result; + return _stat(allocate(pathArray, 'i8', ALLOC_STACK), buf); } }, mknod__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'], @@ -794,9 +788,7 @@ LibraryManager.library = { return -1; } else { var pathArray = intArrayFromString(FS.streams[fildes].path); - var pathPtr = allocate(pathArray, 'i8', ALLOC_STACK); - var result = _chmod(pathPtr, mode); - return result; + return _chmod(allocate(pathArray, 'i8', ALLOC_STACK), mode); } }, umask__deps: ['$FS'], @@ -854,12 +846,14 @@ LibraryManager.library = { __flock_struct_layout: Runtime.generateStructInfo(null, '%struct.flock'), open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'], - open: function(path, oflag, mode) { + open: function(path, oflag, varargs) { // int open(const char *path, int oflag, ...); // http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html // NOTE: This implementation tries to mimic glibc rather that strictly // following the POSIX standard. + var mode = {{{ makeGetValue('varargs', 0, 'i32') }}}; + // Simplify flags. var accessMode = oflag & 0x3; // O_ACCMODE. var isWrite = accessMode != 0x0; // O_RDONLY. @@ -958,10 +952,10 @@ LibraryManager.library = { creat: function(path, mode) { // int creat(const char *path, mode_t mode); // http://pubs.opengroup.org/onlinepubs/009695399/functions/creat.html - return _open(path, 0x241, mode); // O_WRONLY | O_CREAT | O_TRUNC. + return _open(path, 0x241, allocate([mode, 0, 0, 0], 'i32', ALLOC_STACK)); // O_WRONLY | O_CREAT | O_TRUNC. }, fcntl__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__flock_struct_layout'], - fcntl: function(fildes, cmd, arg) { + fcntl: function(fildes, cmd, varargs) { // int fcntl(int fildes, int cmd, ...); // http://pubs.opengroup.org/onlinepubs/009695399/functions/fcntl.html if (!(fildes in FS.streams)) { @@ -971,6 +965,7 @@ LibraryManager.library = { var stream = FS.streams[fildes]; switch (cmd) { case 0: // F_DUPFD. + var arg = {{{ makeGetValue('varargs', 0, 'i32') }}}; if (arg < 0) { ___setErrNo(ERRNO_CODES.EINVAL); return -1; @@ -994,10 +989,12 @@ LibraryManager.library = { // Synchronization and blocking flags are irrelevant to us. return flags; case 4: // F_SETFL. + var arg = {{{ makeGetValue('varargs', 0, 'i32') }}}; stream.isAppend = Boolean(arg | 0x400); // O_APPEND. // Synchronization and blocking flags are irrelevant to us. return 0; case 5: // F_GETLK. + var arg = {{{ makeGetValue('varargs', 0, 'i32') }}}; var offset = ___flock_struct_layout.l_type; // We're always unlocked. {{{ makeSetValue('arg', 'offset', '2', 'i16') }}} // F_UNLCK. @@ -1147,7 +1144,7 @@ LibraryManager.library = { dup: function(fildes) { // int dup(int fildes); // http://pubs.opengroup.org/onlinepubs/000095399/functions/dup.html - return _fcntl(fildes, 0, 0); // F_DUPFD. + return _fcntl(fildes, 0, allocate([0, 0, 0, 0], 'i32', ALLOC_STACK)); // F_DUPFD. }, dup2__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'fcntl', 'close'], dup2: function(fildes, fildes2) { @@ -1160,7 +1157,7 @@ LibraryManager.library = { return fildes; } else { _close(fildes2); - return _fcntl(fildes, 0, fildes2); // F_DUPFD. + return _fcntl(fildes, 0, allocate([fildes2, 0, 0, 0], 'i32', ALLOC_STACK)); // F_DUPFD. } }, fchown__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'chown'], @@ -2121,13 +2118,14 @@ LibraryManager.library = { // ========================================================================== // TODO: Document. - _scanString: function(format, get, unget, args) { + _scanString: function(format, get, unget, varargs) { // Supports %x, %4x, %d.%d, %s. // TODO: Support all format specifiers. format = Pointer_stringify(format); var formatIndex = 0; var argsi = 0; var fields = 0; + var argIndex = 0; for (var formatIndex = 0; formatIndex < format.length; formatIndex++) { var next = get(); if (next <= 0) return fields; // End of input. @@ -2161,18 +2159,19 @@ LibraryManager.library = { } if (buffer.length === 0) return 0; // Failure. var text = buffer.join(''); + var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; + argIndex += Runtime.getNativeFieldSize('void*'); switch (type) { case 'd': - {{{ makeSetValue('args.shift()', '0', 'parseInt(text, 10)', 'i32') }}} + {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}} break; case 'x': - {{{ makeSetValue('args.shift()', '0', 'parseInt(text, 16)', 'i32') }}} + {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}} break; case 's': var array = intArrayFromString(text); - var buf = args.shift(); for (var j = 0; j < array.length; j++) { - {{{ makeSetValue('buf', 'j', 'array[j]', 'i8') }}} + {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}} } break; } @@ -2188,44 +2187,24 @@ LibraryManager.library = { return fields; }, // Performs prtinf-style formatting. - // isVarArgs: Whether the arguments are passed in varargs style, i.e. the - // third parameter is an address of the start of the argument list. // format: A pointer to the format string. + // varargs: A pointer to the start of the arguments list. // Returns the resulting string string as a character array. - _formatString: function(isVarArgs, format/*, ...*/) { + _formatString: function(format, varargs) { var textIndex = format; var argIndex = 0; - var getNextArg; - if (isVarArgs) { - var varArgStart = arguments[2]; - getNextArg = function(type) { - var ret; - if (type === 'double') { - ret = {{{ makeGetValue('varArgStart', 'argIndex', 'double') }}}; - } else if (type === 'float') { - ret = {{{ makeGetValue('varArgStart', 'argIndex', 'float') }}}; - } else if (type === 'i64') { - ret = {{{ makeGetValue('varArgStart', 'argIndex', 'i64') }}}; - } else if (type === 'i32') { - ret = {{{ makeGetValue('varArgStart', 'argIndex', 'i32') }}}; - } else if (type === 'i16') { - ret = {{{ makeGetValue('varArgStart', 'argIndex', 'i16') }}}; - } else if (type === 'i8') { - ret = {{{ makeGetValue('varArgStart', 'argIndex', 'i8') }}}; - } else if (type[type.length - 1] === '*') { - ret = {{{ makeGetValue('varArgStart', 'argIndex', 'void*') }}}; - } else { - throw new Error('Unknown formatString argument type: ' + type); - } - argIndex += Runtime.getNativeFieldSize(type); - return Number(ret); - }; - } else { - var args = arguments; - getNextArg = function() { - return Number(args[2 + argIndex++]); - }; - } + var getNextArg = function(type) { + // NOTE: Explicitly ignoring type safety. Otherwise this fails: + // int x = 4; printf("%c\n", (char)x); + var ret; + if (type === 'float' || type === 'double') { + ret = {{{ makeGetValue('varargs', 'argIndex', 'double', undefined, undefined, true) }}}; + } else { + ret = {{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}}; + } + argIndex += Runtime.getNativeFieldSize(type); + return Number(ret); + }; var ret = []; var curr, next, currArg; @@ -2632,13 +2611,14 @@ LibraryManager.library = { } }, fgetc__deps: ['$FS', 'read'], + fgetc__postset: '_fgetc.ret = allocate([0], "i8", ALLOC_STATIC);', fgetc: function(stream) { // int fgetc(FILE *stream); // http://pubs.opengroup.org/onlinepubs/000095399/functions/fgetc.html if (!(stream in FS.streams)) return -1; var streamObj = FS.streams[stream]; if (streamObj.eof || streamObj.error) return -1; - var ret = _read(stream, FS.buffer1, 1); + var ret = _read(stream, _fgetc.ret, 1); if (ret == 0) { streamObj.eof = true; return -1; @@ -2646,7 +2626,7 @@ LibraryManager.library = { streamObj.error = true; return -1; } else { - return {{{ makeGetValue('FS.buffer1', '0', 'i8') }}}; + return {{{ makeGetValue('_fgetc.ret', '0', 'i8') }}}; } }, getc: 'fgetc', @@ -2748,16 +2728,17 @@ LibraryManager.library = { ___setErrNo(ERRNO_CODES.EINVAL); return 0; } - var ret = _open(filename, flags, 0x1FF); // All creation permissions. + var ret = _open(filename, flags, allocate([0x1FF, 0, 0, 0], 'i32', ALLOC_STACK)); // All creation permissions. return (ret == -1) ? 0 : ret; }, fputc__deps: ['$FS', 'write'], + fputc__postset: '_fputc.ret = allocate([0], "i8", ALLOC_STATIC);', fputc: function(c, stream) { // int fputc(int c, FILE *stream); // http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html var chr = unSign(c & 0xFF); - {{{ makeSetValue('FS.buffer1', '0', 'chr', 'i8') }}} - var ret = _write(stream, FS.buffer1, 1); + {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}} + var ret = _write(stream, _fputc.ret, 1); if (ret == -1) { if (stream in FS.streams) FS.streams[stream].error = true; return -1; @@ -3035,43 +3016,38 @@ LibraryManager.library = { }, fscanf__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '_scanString', 'getc', 'ungetc'], - fscanf: function(stream, format/*, ...*/) { + fscanf: function(stream, format, varargs) { // int fscanf(FILE *restrict stream, const char *restrict format, ... ); // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html if (stream in FS.streams) { - var args = Array.prototype.slice.call(arguments, 2); var get = function() { return _fgetc(stream); }; var unget = function(c) { return _ungetc(c, stream); }; - return __scanString(format, get, unget, args); + return __scanString(format, get, unget, varargs); } else { return -1; } }, scanf__deps: ['fscanf'], - scanf: function(format/*, ...*/) { + scanf: function(format, varargs) { // int scanf(const char *restrict format, ... ); // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html - var args = Array.prototype.slice.call(arguments, 0); - args.unshift({{{ makeGetValue('_stdin', '0', 'void*') }}}); - return _fscanf.apply(null, args); + var stdin = {{{ makeGetValue('_stdin', '0', 'void*') }}}; + return _fscanf(stdin, format, varargs); }, sscanf__deps: ['_scanString'], - sscanf: function(s, format/*, ...*/) { + sscanf: function(s, format, varargs) { // int sscanf(const char *restrict s, const char *restrict format, ... ); // http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html var index = 0; var get = function() { return {{{ makeGetValue('s', 'index++', 'i8') }}}; }; var unget = function() { index--; }; - var args = Array.prototype.slice.call(arguments, 2); - return __scanString(format, get, unget, args); + return __scanString(format, get, unget, varargs); }, snprintf__deps: ['_formatString'], - snprintf: function(s, n, format/*, ... */) { + snprintf: function(s, n, format, varargs) { // int snprintf(char *restrict s, size_t n, const char *restrict format, ...); // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html - var args = Array.prototype.slice.call(arguments, 2); - args.unshift(false); - var result = __formatString.apply(null, args); + var result = __formatString(format, varargs); var limit = (n === undefined) ? result.length : Math.min(result.length, n - 1); for (var i = 0; i < limit; i++) { @@ -3081,65 +3057,29 @@ LibraryManager.library = { return result.length; }, fprintf__deps: ['fwrite', '_formatString'], - fprintf: function(stream, format/*, ... */) { + fprintf: function(stream, format, varargs) { // int fprintf(FILE *restrict stream, const char *restrict format, ...); // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html - var args = Array.prototype.slice.call(arguments, 1); - args.unshift(false); - var result = __formatString.apply(null, args); - var buffer = allocate(result, 'i8', ALLOC_STACK); - var ret = _fwrite(buffer, 1, result.length, stream); - return ret; + var result = __formatString(format, varargs); + return _fwrite(allocate(result, 'i8', ALLOC_STACK), 1, result.length, stream); }, printf__deps: ['fprintf'], - printf: function(format/*, ... */) { + printf: function(format, varargs) { // int printf(const char *restrict format, ...); // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html - var args = Array.prototype.slice.call(arguments, 0); - args.unshift({{{ makeGetValue('_stdout', '0', 'void*') }}}); - return _fprintf.apply(null, args); + var stdout = {{{ makeGetValue('_stdout', '0', 'void*') }}}; + return _fprintf(stdout, format, varargs); }, sprintf__deps: ['snprintf'], - sprintf: function(s, format/*, ... */) { + sprintf: function(s, format, varargs) { // int sprintf(char *restrict s, const char *restrict format, ...); // http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html - var args = [s, undefined].concat(Array.prototype.slice.call(arguments, 1)); - return _snprintf.apply(null, args); - }, - vfprintf__deps: ['fwrite', '_formatString'], - vfprintf: function(stream, format, ap) { - // int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap); - // http://pubs.opengroup.org/onlinepubs/000095399/functions/vprintf.html - var result = __formatString(true, format, ap); - var buffer = allocate(result, 'i8', ALLOC_STACK); - var ret = _fwrite(buffer, 1, result.length, stream); - return ret; - }, - vsnprintf__deps: ['_formatString'], - vsnprintf: function(s, n, format, ap) { - // int vsnprintf(char *restrict s, size_t n, const char *restrict format, va_list ap); - // http://pubs.opengroup.org/onlinepubs/000095399/functions/vprintf.html - var result = __formatString(true, format, ap); - var limit = (n === undefined) ? result.length - : Math.min(result.length, n - 1); - for (var i = 0; i < limit; i++) { - {{{ makeSetValue('s', 'i', 'result[i]', 'i8') }}}; - } - {{{ makeSetValue('s', 'i', '0', 'i8') }}}; - return result.length; - }, - vprintf__deps: ['vfprintf'], - vprintf: function(format, ap) { - // int vprintf(const char *restrict format, va_list ap); - // http://pubs.opengroup.org/onlinepubs/000095399/functions/vprintf.html - return _vfprintf({{{ makeGetValue('_stdout', '0', 'void*') }}}, format, ap); - }, - vsprintf__deps: ['vsnprintf'], - vsprintf: function(s, format, ap) { - // int vsprintf(char *restrict s, const char *restrict format, va_list ap); - // http://pubs.opengroup.org/onlinepubs/000095399/functions/vprintf.html - return _vsnprintf(s, undefined, format, ap); + return _snprintf(s, undefined, format, varargs); }, + vfprintf: 'fprintf', + vsnprintf: 'snprintf', + vprintf: 'printf', + vsprintf: 'sprintf', // TODO: Implement v*scanf(). __01fopen64_: 'fopen', __01fseeko64_: 'fseek', @@ -5085,16 +5025,16 @@ LibraryManager.library = { 26: 'Text file busy', 18: 'Invalid cross-device link' }, - __setErrNo__deps: ['$FS'], + __setErrNo__postset: '___setErrNo(0);', __setErrNo: function(value) { // For convenient setting and returning of errno. - var me = ___setErrNo; - {{{ makeSetValue('FS.errno', '0', 'value', 'i32') }}} + if (!___setErrNo.ret) ___setErrNo.ret = allocate([0], 'i32', ALLOC_STATIC); + {{{ makeSetValue('___setErrNo.ret', '0', 'value', 'i32') }}} return value; }, __errno_location__deps: ['__setErrNo'], __errno_location: function() { - return FS.errno; + return ___setErrNo.ret; }, // ========================================================================== diff --git a/src/parseTools.js b/src/parseTools.js index 4a2ff3a8..4b3e63e1 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -333,6 +333,15 @@ function parseParamTokens(params) { return ret; } +function hasVarArgs(params) { + for (var i = 0; i < params.length; i++) { + if (params[i].intertype == 'varargs') { + return true; + } + } + return false; +} + function finalizeParam(param) { if (param.intertype in PARSABLE_LLVM_FUNCTIONS) { return finalizeLLVMFunctionCall(param); @@ -687,7 +696,7 @@ function getHeapOffset(offset, type) { } // See makeSetValue -function makeGetValue(ptr, pos, type, noNeedFirst, unsigned) { +function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore) { if (isStructType(type)) { var typeData = Types.types[type]; var ret = []; @@ -701,7 +710,7 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned) { if (SAFE_HEAP) { if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"'; if (type[0] === '#') type = type.substr(1); - return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + (!checkSafeHeap()+0) + ')'; + return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')'; } else { return makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']'; } diff --git a/src/preamble.js b/src/preamble.js index 2cbd9cf0..59389e58 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -71,7 +71,7 @@ function SAFE_HEAP_STORE(dest, value, type, ignore) { print('SAFE_HEAP store: ' + [dest, type, value, ignore]); #endif - if (!ignore && !value && value !== 0 && value !== false) { // false can be the result of a mathop comparator + if (!ignore && !value && value !== 0 && value !== false && !isNaN(value)) { // false can be the result of a mathop comparator; NaN can be the result of a math function throw('Warning: Writing an invalid value of ' + JSON.stringify(value) + ' at ' + dest + ' :: ' + new Error().stack + '\n'); } SAFE_HEAP_ACCESS(dest, type, true, ignore); @@ -398,6 +398,7 @@ function Pointer_stringify(ptr) { } return ret; } +Module['Pointer_stringify'] = Pointer_stringify; function Array_stringify(array) { var ret = ""; @@ -406,6 +407,7 @@ function Array_stringify(array) { } return ret; } +Module['Array_stringify'] = Array_stringify; // Memory management @@ -537,12 +539,14 @@ function Array_copy(ptr, num) { #endif return HEAP.slice(ptr, ptr+num); } +Module['Array_copy'] = Array_copy; function String_len(ptr) { var i = 0; while ({{{ makeGetValue('ptr', 'i', 'i8') }}}) i++; // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds return i; } +Module['String_len'] = String_len; // Copies a C-style string, terminated by a zero, from the HEAP into // a normal JavaScript array of numbers @@ -553,6 +557,7 @@ function String_copy(ptr, addZero) { if (addZero) ret[len-1] = 0; return ret; } +Module['String_copy'] = String_copy; // Tools @@ -598,6 +603,7 @@ function intArrayToString(array) { } return ret.join(''); } +Module['intArrayToString'] = intArrayToString; {{{ unSign }}} {{{ reSign }}} diff --git a/tests/cases/trunc.ll b/tests/cases/trunc.ll index 6af3656c..b46436ff 100644 --- a/tests/cases/trunc.ll +++ b/tests/cases/trunc.ll @@ -5,7 +5,7 @@ target triple = "i386-pc-linux-gnu" @.str = private constant [8 x i8] c"*%d,%d*\0A\00", align 1 ; [#uses=1] ; [#uses=1] -declare i32 @printf(i8*) +declare i32 @printf(i8* noalias, ...) ; [#uses=0] define i32 @main() { diff --git a/tests/runner.py b/tests/runner.py index 39cab477..d3d483de 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -387,6 +387,7 @@ if 'benchmark' not in sys.argv: self.do_test(src, output, force_c=True) def test_bigint(self): + if USE_TYPED_ARRAYS != 0: return self.skip() # Typed arrays truncate i64. src = ''' #include <stdio.h> int main() @@ -1870,14 +1871,14 @@ if 'benchmark' not in sys.argv: typedef int (*CMP_TYPE)(const void*, const void*); - CMP_TYPE get_cmp() { + extern "C" CMP_TYPE get_cmp() { return lib_cmp; } ''' dirname = self.get_dir() filename = os.path.join(dirname, 'liblib.cpp') BUILD_AS_SHARED_LIB = 1 - EXPORTED_FUNCTIONS = ['__Z7get_cmpv'] + EXPORTED_FUNCTIONS = ['_get_cmp'] self.build(lib_src, dirname, filename) shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) @@ -1907,7 +1908,7 @@ if 'benchmark' not in sys.argv: printf("Could not load lib.\\n"); return 1; } - getter_ptr = (CMP_TYPE (*)()) dlsym(lib_handle, "_Z7get_cmpv"); + getter_ptr = (CMP_TYPE (*)()) dlsym(lib_handle, "get_cmp"); if (getter_ptr == NULL) { printf("Could not find func.\\n"); return 1; @@ -1964,7 +1965,7 @@ if 'benchmark' not in sys.argv: p_f(); } - void (*func(int x, void(*fptr)()))() { + extern "C" void (*func(int x, void(*fptr)()))() { printf("In func: %d\\n", x); fptr(); return lib_fptr; @@ -1973,7 +1974,7 @@ if 'benchmark' not in sys.argv: dirname = self.get_dir() filename = os.path.join(dirname, 'liblib.cpp') BUILD_AS_SHARED_LIB = 1 - EXPORTED_FUNCTIONS = ['__Z4funciPFvvE'] + EXPORTED_FUNCTIONS = ['_func'] EXPORTED_GLOBALS = ['_global'] self.build(lib_src, dirname, filename) shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) @@ -2006,9 +2007,9 @@ if 'benchmark' not in sys.argv: } // Test looked up function. - func_fptr = (FUNCTYPE*) dlsym(lib_handle, "_Z4funciPFvvE"); + func_fptr = (FUNCTYPE*) dlsym(lib_handle, "func"); // Load twice to test cache. - func_fptr = (FUNCTYPE*) dlsym(lib_handle, "_Z4funciPFvvE"); + func_fptr = (FUNCTYPE*) dlsym(lib_handle, "func"); if (func_fptr == NULL) { printf("Could not find func.\\n"); return 1; @@ -2043,6 +2044,108 @@ if 'benchmark' not in sys.argv: output_nicerizer=lambda x: x.replace('\n', '*'), post_build=add_pre_run_and_checks) + def test_dlfcn_alias(self): + global BUILD_AS_SHARED_LIB, EXPORTED_FUNCTIONS, INCLUDE_FULL_LIBRARY + lib_src = r''' + #include <stdio.h> + extern int parent_global; + extern "C" void func() { + printf("Parent global: %d.\n", parent_global); + } + ''' + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.cpp') + BUILD_AS_SHARED_LIB = 1 + EXPORTED_FUNCTIONS = ['_func'] + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + src = r''' + #include <dlfcn.h> + + int parent_global = 123; + + int main() { + void* lib_handle; + void (*fptr)(); + + lib_handle = dlopen("liblib.so", RTLD_NOW); + fptr = (void (*)())dlsym(lib_handle, "func"); + fptr(); + parent_global = 456; + fptr(); + + return 0; + } + ''' + BUILD_AS_SHARED_LIB = 0 + INCLUDE_FULL_LIBRARY = 1 + EXPORTED_FUNCTIONS = ['_main'] + def add_pre_run_and_checks(filename): + src = open(filename, 'r').read().replace( + '// {{PRE_RUN_ADDITIONS}}', + '''FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);''' + ) + open(filename, 'w').write(src) + self.do_test(src, 'Parent global: 123.*Parent global: 456.*', + output_nicerizer=lambda x: x.replace('\n', '*'), + post_build=add_pre_run_and_checks) + INCLUDE_FULL_LIBRARY = 0 + + def test_dlfcn_varargs(self): + global BUILD_AS_SHARED_LIB, EXPORTED_FUNCTIONS + lib_src = r''' + void print_ints(int n, ...); + extern "C" void func() { + print_ints(2, 13, 42); + } + ''' + dirname = self.get_dir() + filename = os.path.join(dirname, 'liblib.cpp') + BUILD_AS_SHARED_LIB = 1 + EXPORTED_FUNCTIONS = ['_func'] + self.build(lib_src, dirname, filename) + shutil.move(filename + '.o.js', os.path.join(dirname, 'liblib.so')) + + src = r''' + #include <stdarg.h> + #include <stdio.h> + #include <dlfcn.h> + + void print_ints(int n, ...) { + va_list args; + va_start(args, n); + for (int i = 0; i < n; i++) { + printf("%d\n", va_arg(args, int)); + } + va_end(args); + } + + int main() { + void* lib_handle; + void (*fptr)(); + + print_ints(2, 100, 200); + + lib_handle = dlopen("liblib.so", RTLD_NOW); + fptr = (void (*)())dlsym(lib_handle, "func"); + fptr(); + + return 0; + } + ''' + BUILD_AS_SHARED_LIB = 0 + EXPORTED_FUNCTIONS = ['_main'] + def add_pre_run_and_checks(filename): + src = open(filename, 'r').read().replace( + '// {{PRE_RUN_ADDITIONS}}', + '''FS.createLazyFile('/', 'liblib.so', 'liblib.so', true, false);''' + ) + open(filename, 'w').write(src) + self.do_test(src, '100*200*13*42*', + output_nicerizer=lambda x: x.replace('\n', '*'), + post_build=add_pre_run_and_checks) + def test_rand(self): src = r''' #include <stdio.h> @@ -2137,10 +2240,55 @@ if 'benchmark' not in sys.argv: self.do_test(src, re.sub(r'\n\s+', '\n', expected)) def test_printf(self): + if USE_TYPED_ARRAYS != 0: return self.skip() # Typed arrays truncate i64. src = open(path_from_root('tests', 'printf', 'test.c'), 'r').read() expected = open(path_from_root('tests', 'printf', 'output.txt'), 'r').read() self.do_test(src, expected) + def test_printf_types(self): + src = r''' + #include <stdio.h> + + int main() { + char c = '1'; + short s = 2; + int i = 3; + long long l = 4; + float f = 5.5; + double d = 6.6; + + printf("%c,%hd,%d,%lld,%.1f,%.1llf\n", c, s, i, l, f, d); + + return 0; + } + ''' + self.do_test(src, '1,2,3,4,5.5,6.6\n') + + def test_vprintf(self): + src = r''' + #include <stdio.h> + #include <stdarg.h> + + void print(char* |