aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/intertyper.js27
-rw-r--r--src/jsifier.js62
-rw-r--r--src/library.js190
-rw-r--r--src/parseTools.js13
-rw-r--r--src/preamble.js8
-rw-r--r--tests/cases/trunc.ll2
-rw-r--r--tests/runner.py170
-rw-r--r--tools/eliminator/eliminator.coffee82
-rw-r--r--tools/shared.py2
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*