aboutsummaryrefslogtreecommitdiff
path: root/src/library.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library.js')
-rw-r--r--src/library.js188
1 files changed, 155 insertions, 33 deletions
diff --git a/src/library.js b/src/library.js
index fd5e0fae..06661d59 100644
--- a/src/library.js
+++ b/src/library.js
@@ -2457,20 +2457,23 @@ LibraryManager.library = {
var argIndex = 0;
var next;
- next = 1;
mainLoop:
- for (var formatIndex = 0; formatIndex < format.length; formatIndex++) {
+ for (var formatIndex = 0; formatIndex < format.length;) {
+ if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') {
+ var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
+ argIndex += Runtime.getNativeFieldSize('void*');
+ {{{ makeSetValue('argPtr', 0, 'soFar', 'i32') }}};
+ formatIndex += 2;
+ continue;
+ }
+
// remove whitespace
while (1) {
next = get();
if (next == 0) return fields;
if (!(next in __scanString.whiteSpace)) break;
- }
- unget(next);
-
- if (next <= 0) return fields;
- var next = get();
- if (next <= 0) return fields; // End of input.
+ }
+ unget();
if (format[formatIndex] === '%') {
formatIndex++;
@@ -2504,6 +2507,7 @@ LibraryManager.library = {
// Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later
if (type == 'f') {
var last = 0;
+ next = get();
while (next > 0) {
buffer.push(String.fromCharCode(next));
if (__isFloat(buffer.join(''))) {
@@ -2511,12 +2515,12 @@ LibraryManager.library = {
}
next = get();
}
- unget(next);
- while (buffer.length > last) {
- unget(buffer.pop().charCodeAt(0));
+ for (var i = 0; i < buffer.length - last + 1; i++) {
+ unget();
}
+ buffer.length = last;
+ } else {
next = get();
- } else if (type != 'n') {
var first = true;
while ((curr < max_ || isNaN(max_)) && next > 0) {
if (!(next in __scanString.whiteSpace) && // stop on whitespace
@@ -2530,13 +2534,14 @@ LibraryManager.library = {
buffer.push(String.fromCharCode(next));
next = get();
curr++;
+ first = false;
} else {
break;
}
- first = false;
}
+ unget();
}
- if (buffer.length === 0 && type != 'n') return 0; // Failure.
+ if (buffer.length === 0) return 0; // Failure.
var text = buffer.join('');
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
argIndex += Runtime.getNativeFieldSize('void*');
@@ -2566,31 +2571,26 @@ LibraryManager.library = {
{{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}}
}
break;
- case 'n':
- {{{ makeSetValue('argPtr', 0, 'soFar-1', 'i32') }}}
- break;
}
- if (type != 'n') fields++;
- if (next <= 0) break mainLoop; // End of input.
+ fields++;
} else if (format[formatIndex] in __scanString.whiteSpace) {
+ next = get();
while (next in __scanString.whiteSpace) {
- next = get();
if (next <= 0) break mainLoop; // End of input.
+ next = get();
}
unget(next);
+ formatIndex++;
} else {
// Not a specifier.
+ next = get();
if (format[formatIndex].charCodeAt(0) !== next) {
unget(next);
break mainLoop;
}
+ formatIndex++;
}
}
- // 'n' is special in that it needs no input. so it can be at the end, even with nothing left to read
- if (format[formatIndex-1] == '%' && format[formatIndex] == 'n') {
- var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
- {{{ makeSetValue('argPtr', 0, 'soFar-1', 'i32') }}}
- }
return fields;
},
// Performs prtinf-style formatting.
@@ -2741,7 +2741,7 @@ LibraryManager.library = {
var signed = next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0);
argSize = argSize || 4;
var currArg = getNextArg('i' + (argSize * 8));
-#if PRECISE_I64_MATH == 1
+#if PRECISE_I64_MATH
var origArg = currArg;
#endif
var argText;
@@ -2760,12 +2760,12 @@ LibraryManager.library = {
var currAbsArg = Math.abs(currArg);
var prefix = '';
if (next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0)) {
-#if PRECISE_I64_MATH == 1
- if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1]); else
+#if PRECISE_I64_MATH
+ if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else
#endif
argText = reSign(currArg, 8 * argSize, 1).toString(10);
} else if (next == 'u'.charCodeAt(0)) {
-#if PRECISE_I64_MATH == 1
+#if PRECISE_I64_MATH
if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else
#endif
argText = unSign(currArg, 8 * argSize, 1).toString(10);
@@ -2774,6 +2774,9 @@ LibraryManager.library = {
argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
} else if (next == 'x'.charCodeAt(0) || next == 'X'.charCodeAt(0)) {
prefix = flagAlternative ? '0x' : '';
+#if PRECISE_I64_MATH
+ if (argSize == 8 && i64Math) argText = (origArg[1]>>>0).toString(16) + (origArg[0]>>>0).toString(16); else
+#endif
if (currArg < 0) {
// Represent negative numbers in hex as 2's complement.
currArg = -currArg;
@@ -3452,8 +3455,9 @@ LibraryManager.library = {
// int fscanf(FILE *restrict stream, const char *restrict format, ... );
// http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
if (FS.streams[stream]) {
- var get = function() { return _fgetc(stream); };
- var unget = function(c) { return _ungetc(c, stream); };
+ var stack = [];
+ var get = function() { var ret = _fgetc(stream); stack.push(ret); return ret };
+ var unget = function(c) { return _ungetc(stack.pop(), stream) };
return __scanString(format, get, unget, varargs);
} else {
return -1;
@@ -3735,6 +3739,7 @@ LibraryManager.library = {
strtod_l: 'strtod', // no locale support yet
strtold: 'strtod', // XXX add real support for long double
strtold_l: 'strtold', // no locale support yet
+ strtof: 'strtod', // use stdtod to handle strtof
_parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'],
_parseInt: function(str, endptr, base, min, max, bits, unsign) {
@@ -4035,6 +4040,10 @@ LibraryManager.library = {
return Math.floor(Math.random()*0x80000000);
},
+ drand48: function() {
+ return Math.random();
+ },
+
realpath__deps: ['$FS', '__setErrNo'],
realpath: function(file_name, resolved_name) {
// char *realpath(const char *restrict file_name, char *restrict resolved_name);
@@ -4742,6 +4751,10 @@ LibraryManager.library = {
return 32;
},
+ llvm_trap: function() {
+ throw 'trap! ' + new Error().stack;
+ },
+
__assert_fail: function(condition, file, line) {
ABORT = true;
throw 'Assertion failed: ' + Pointer_stringify(condition);//JSON.stringify(arguments)//condition;
@@ -5105,6 +5118,34 @@ LibraryManager.library = {
llvm_objectsize_i32: function() { return -1 }, // TODO: support this
// ==========================================================================
+ // llvm-mono integration
+ // ==========================================================================
+
+ llvm_mono_load_i8_p0i8: function(ptr) {
+ return {{{ makeGetValue('ptr', 0, 'i8') }}};
+ },
+
+ llvm_mono_store_i8_p0i8: function(value, ptr) {
+ {{{ makeSetValue('ptr', 0, 'value', 'i8') }}};
+ },
+
+ llvm_mono_load_i16_p0i16: function(ptr) {
+ return {{{ makeGetValue('ptr', 0, 'i16') }}};
+ },
+
+ llvm_mono_store_i16_p0i16: function(value, ptr) {
+ {{{ makeSetValue('ptr', 0, 'value', 'i16') }}};
+ },
+
+ llvm_mono_load_i32_p0i32: function(ptr) {
+ return {{{ makeGetValue('ptr', 0, 'i32') }}};
+ },
+
+ llvm_mono_store_i32_p0i32: function(value, ptr) {
+ {{{ makeSetValue('ptr', 0, 'value', 'i32') }}};
+ },
+
+ // ==========================================================================
// math.h
// ==========================================================================
@@ -5124,6 +5165,64 @@ LibraryManager.library = {
atan2f: 'Math.atan2',
exp: 'Math.exp',
expf: 'Math.exp',
+
+ // The erf and erfc functions are inspired from
+ // http://www.digitalmars.com/archives/cplusplus/3634.html
+ // and mruby source code at
+ // https://github.com/mruby/mruby/blob/master/src/math.c
+ erfc: function (x) {
+ var MATH_TOLERANCE = 1E-12;
+ var ONE_SQRTPI = 0.564189583547756287;
+ var a = 1;
+ var b = x;
+ var c = x;
+ var d = x * x + 0.5;
+ var n = 1.0;
+ var q2 = b / d;
+ var q1, t;
+
+ if (Math.abs(x) < 2.2) {
+ return 1.0 - _erf(x);
+ }
+ if (x < 0) {
+ return 2.0 - _erfc(-x);
+ }
+ do {
+ t = a * n + b * x;
+ a = b;
+ b = t;
+ t = c * n + d * x;
+ c = d;
+ d = t;
+ n += 0.5;
+ q1 = q2;
+ q2 = b / d;
+ } while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE);
+ return (ONE_SQRTPI * Math.exp(- x * x) * q2);
+ },
+ erfcf: 'erfcf',
+ erf: function (x) {
+ var MATH_TOLERANCE = 1E-12;
+ var TWO_SQRTPI = 1.128379167095512574;
+ var sum = x;
+ var term = x;
+ var xsqr = x*x;
+ var j = 1;
+
+ if (Math.abs(x) > 2.2) {
+ return 1.0 - _erfc(x);
+ }
+ do {
+ term *= xsqr / j;
+ sum -= term / (2 * j + 1);
+ ++j;
+ term *= xsqr / j;
+ sum += term / (2 * j + 1);
+ ++j;
+ } while (Math.abs(term / sum) > MATH_TOLERANCE);
+ return (TWO_SQRTPI * sum);
+ },
+ erff: 'erf',
log: 'Math.log',
logf: 'Math.log',
sqrt: 'Math.sqrt',
@@ -5266,7 +5365,7 @@ LibraryManager.library = {
},
fmaxf: 'fmax',
fmin: function(x, y) {
- return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y);
+ return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y);
},
fminf: 'fmin',
fma: function(x, y, z) {
@@ -5841,7 +5940,7 @@ LibraryManager.library = {
setjmp__inline: function(env) {
// Save the label
- return '(' + makeSetValue(env, '0', 'label', 'i32') + ', 0)';
+ return '(setjmped = true, ' + makeSetValue(env, '0', 'label', 'i32') + ', 0)';
},
longjmp: function(env, value) {
@@ -6404,6 +6503,17 @@ LibraryManager.library = {
_pthread_key_create.keys[key] = value;
},
+ pthread_cleanup_push: function(routine, arg) {
+ __ATEXIT__.push({ func: function() { FUNCTION_TABLE[routine](arg) } })
+ _pthread_cleanup_push.level = __ATEXIT__.length;
+ },
+
+ pthread_cleanup_pop: function() {
+ assert(_pthread_cleanup_push.level == __ATEXIT__.length, 'cannot pop if something else added meanwhile!');
+ __ATEXIT__.pop();
+ _pthread_cleanup_push.level = __ATEXIT__.length;
+ },
+
// ==========================================================================
// malloc.h
// ==========================================================================
@@ -6833,6 +6943,18 @@ LibraryManager.library = {
return eval(Pointer_stringify(ptr));
},
+ emscripten_run_script_string: function(ptr) {
+ var s = eval(Pointer_stringify(ptr));
+ var me = _emscripten_run_script_string;
+ if (!me.bufferSize || me.bufferSize < s.length+1) {
+ if (me.bufferSize) _free(me.buffer);
+ me.bufferSize = s.length+1;
+ me.buffer = _malloc(me.bufferSize);
+ }
+ writeStringToMemory(s, me.buffer);
+ return me.buffer;
+ },
+
emscripten_random: function() {
return Math.random();
},