aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-12-31 11:56:53 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-12-31 11:56:53 -0800
commit2325baf34e144586d71251f31c01c7f2abfdb8b7 (patch)
tree6dec7e37e75040034d443786d4701e62b38a4d6d
parent8aa6919b7acf0b4034735ac7ee597e946fefaf4d (diff)
parenta55c2a24a50a93fcf9035eb2a809d13d3a8d3555 (diff)
Merge branch 'incoming' into asm_js
Conflicts: src/library_browser.js
-rwxr-xr-xemcc2
-rw-r--r--src/compiler.html32
-rw-r--r--src/compiler.js84
-rw-r--r--src/intertyper.js12
-rw-r--r--src/jsifier.js13
-rw-r--r--src/library.js141
-rw-r--r--src/library_browser.js17
-rw-r--r--src/long.js45
-rw-r--r--src/modules.js2
-rw-r--r--system/include/emscripten/emscripten.h24
-rw-r--r--tests/cases/typestr.ll19
-rw-r--r--tests/emscripten_fs_api_browser.cpp50
-rw-r--r--tests/parseInt/output.txt37
-rwxr-xr-xtests/runner.py124
-rw-r--r--tools/autodebugger.py31
-rw-r--r--tools/autodebugger_js.py47
-rw-r--r--tools/eliminator/eliminator-test-output.js7
-rw-r--r--tools/eliminator/eliminator-test.js14
-rw-r--r--tools/file_packager.py12
-rw-r--r--tools/js-optimizer.js4
-rw-r--r--tools/js_optimizer.py8
-rwxr-xr-xtools/nativize_llvm.py9
-rw-r--r--tools/shared.py9
23 files changed, 622 insertions, 121 deletions
diff --git a/emcc b/emcc
index f891d1f3..c2b10862 100755
--- a/emcc
+++ b/emcc
@@ -1062,7 +1062,6 @@ try:
if not LEAVE_INPUTS_RAW:
link_opts = [] if keep_debug else ['-strip-debug']
if llvm_opts > 0:
- if DEBUG: print >> sys.stderr, 'emcc: LLVM -O%d' % llvm_opts
shared.Building.llvm_opt(in_temp(target_basename + '.bc'), llvm_opts)
if DEBUG: save_intermediate('opt', 'bc')
# Do LTO in a separate pass to work around LLVM bug XXX (see failure e.g. in cubescript)
@@ -1075,7 +1074,6 @@ try:
else:
# At minimum remove dead functions etc., this potentially saves a lot in the size of the generated code (and the time to compile it)
link_opts += shared.Building.get_safe_internalize() + ['-globaldce']
- if DEBUG: print >> sys.stderr, 'emcc: LLVM linktime:', link_opts
shared.Building.llvm_opt(in_temp(target_basename + '.bc'), link_opts)
if DEBUG: save_intermediate('linktime', 'bc')
diff --git a/src/compiler.html b/src/compiler.html
index fe045356..9ea1c0af 100644
--- a/src/compiler.html
+++ b/src/compiler.html
@@ -5,16 +5,44 @@ Open the web console to see stderr output
<hr>
<pre id="output"></pre>
<script>
- arguments = ['', '../freetype.ll'];
- //arguments = ['', '../tests/cases/phicubed.ll'];
+ arguments = [];
var outputElement = document.getElementById('output');
+ var compilerOutput = '';
print = function(x) {
//outputElement.innerHTML += x;
+ compilerOutput += x;
+ };
+
+ // For generated code
+ var Module = {
+ print: function(x) {
+ outputElement.innerHTML += x;
+ }
};
</script>
<script src="compiler.js">
</script>
+<textarea id="the_input" cols=50 rows=30>
+; ModuleID = 'tests/hello_world.bc'
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+target triple = "i386-pc-linux-gnu"
+
+@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*]
+
+; [#uses=0]
+define i32 @main() {
+entry:
+ %retval = alloca i32, align 4 ; [#uses=1 type=i32*]
+ store i32 0, i32* %retval
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0 type=i32]
+ ret i32 1
+}
+
+; [#uses=1]
+declare i32 @printf(i8*, ...)
+</textarea>
+<input type="button" value="run!" onclick="compile(document.getElementById('the_input').value); eval(compilerOutput)">
</body>
</html>
diff --git a/src/compiler.js b/src/compiler.js
index ecfd506e..118ca83a 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -76,10 +76,12 @@ if (ENVIRONMENT_IS_NODE) {
}
} else if (ENVIRONMENT_IS_WEB) {
- this['print'] = printErr = function(x) {
+ printErr = function(x) {
console.log(x);
};
+ if (!this['print']) this['print'] = printErr;
+
this['read'] = function(url) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, false);
@@ -220,42 +222,66 @@ NECESSARY_BLOCKADDRS = temp;
// Read llvm
-var raw = read(ll_file);
-if (FAKE_X86_FP80) {
- raw = raw.replace(/x86_fp80/g, 'double');
-}
-if (raw.search('\r\n') >= 0) {
- raw = raw.replace(/\r\n/g, '\n'); // fix windows line endings
-}
-var lines = raw.split('\n');
-raw = null;
+function compile(raw) {
+ if (FAKE_X86_FP80) {
+ raw = raw.replace(/x86_fp80/g, 'double');
+ }
+ if (raw.search('\r\n') >= 0) {
+ raw = raw.replace(/\r\n/g, '\n'); // fix windows line endings
+ }
+ var lines = raw.split('\n');
+ raw = null;
+
+ // Pre-process the LLVM assembly
+
+ Debugging.handleMetadata(lines);
+
+ function runPhase(currPhase) {
+ //printErr('// JS compiler in action, phase ' + currPhase + typeof lines + (lines === null));
+ phase = currPhase;
+ if (phase != 'pre') {
+ if (singlePhase) PassManager.load(read(forwardedDataFile));
-// Pre-process the LLVM assembly
+ if (phase == 'funcs') {
+ PreProcessor.eliminateUnneededIntrinsics(lines);
+ }
+ }
-//printErr('JS compiler in action, phase ' + phase);
+ // Do it
-Debugging.handleMetadata(lines);
+ var intertyped = intertyper(lines);
+ if (singlePhase) lines = null;
+ var analyzed = analyzer(intertyped);
+ intertyped = null;
+ JSify(analyzed);
-if (phase != 'pre') {
- PassManager.load(read(forwardedDataFile));
+ phase = null;
- if (phase == 'funcs') {
- PreProcessor.eliminateUnneededIntrinsics(lines);
+ if (DEBUG_MEMORY) {
+ print('zzz. last gc: ' + gc());
+ MemoryDebugger.dump();
+ print('zzz. hanging now!');
+ while(1){};
+ }
}
-}
-// Do it
+ // Normal operation is for each execution of compiler.js to run a single phase. The calling script sends us exactly the information we need, and it is easy to parallelize operation that way. However, it is also possible to run in an unoptimal multiphase mode, where a single invocation goes from ll to js directly. This is not recommended and will likely do a lot of duplicate processing.
+ singlePhase = !!phase;
-var intertyped = intertyper(lines);
-lines = null;
-var analyzed = analyzer(intertyped);
-intertyped = null;
-JSify(analyzed);
+ if (singlePhase) {
+ runPhase(phase);
+ } else {
+ runPhase('pre');
+ runPhase('funcs');
+ runPhase('post');
+ }
+}
-if (DEBUG_MEMORY) {
- print('zzz. last gc: ' + gc());
- MemoryDebugger.dump();
- print('zzz. hanging now!');
- while(1){};
+if (ll_file) {
+ if (ll_file.indexOf(String.fromCharCode(10)) == -1) {
+ compile(read(ll_file));
+ } else {
+ compile(ll_file); // we are given raw .ll
+ }
}
diff --git a/src/intertyper.js b/src/intertyper.js
index 2de6c6b9..5bca9236 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -61,7 +61,7 @@ function intertyper(data, sidePass, baseLineNums) {
var baseLineNumPosition = 0;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
- lines[i] = null; // lines may be very very large. Allow GCing to occur in the loop by releasing refs here
+ if (singlePhase) lines[i] = null; // lines may be very very large. Allow GCing to occur in the loop by releasing refs here
while (baseLineNumPosition < baseLineNums.length-1 && i >= baseLineNums[baseLineNumPosition+1][0]) {
baseLineNumPosition++;
@@ -69,11 +69,13 @@ function intertyper(data, sidePass, baseLineNums) {
if (mainPass && (line[0] == '%' || line[0] == '@')) {
// If this isn't a type, it's a global variable, make a note of the information now, we will need it later
- var testType = /[@%\w\d\.\" $-]+ = type .*/.exec(line);
+ var parts = line.split(' = ');
+ assert(parts.length >= 2);
+ var left = parts[0], right = parts.slice(1).join(' = ');
+ var testType = /^type .*/.exec(right);
if (!testType) {
- var global = /([@%\w\d\.\" $-]+) = .*/.exec(line);
- var globalIdent = toNiceIdent(global[1]);
- var testAlias = /[@%\w\d\.\" $-]+ = (hidden )?alias .*/.exec(line);
+ var globalIdent = toNiceIdent(left);
+ var testAlias = /^(hidden )?alias .*/.exec(right);
Variables.globals[globalIdent] = {
name: globalIdent,
alias: !!testAlias,
diff --git a/src/jsifier.js b/src/jsifier.js
index a7b5a9ec..5499910a 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -431,8 +431,8 @@ function JSify(data, functionsOnly, givenFunctions) {
// name the function; overwrite if it's already named
snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '(');
if (LIBRARY_DEBUG) {
- snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); ');
- snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; }';
+ snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.print("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); ');
+ snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.print(" [ return:" + Runtime.prettyPrint(ret)); return ret; }';
}
if (ASM_JS) Functions.libraryFunctions[ident] = 1;
}
@@ -1390,6 +1390,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// Print out global variables and postsets TODO: batching
if (phase == 'pre') {
+ var legalizedI64sDefault = legalizedI64s;
legalizedI64s = false;
var globalsData = analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true);
@@ -1412,9 +1413,13 @@ function JSify(data, functionsOnly, givenFunctions) {
var generated = itemsDict.functionStub.concat(itemsDict.GlobalVariablePostSet);
generated.forEach(function(item) { print(indentify(item.JS || '', 2)); });
+
+ legalizedI64s = legalizedI64sDefault;
} else {
- assert(data.unparsedGlobalss[0].lines.length == 0, dump([phase, data.unparsedGlobalss]));
- assert(itemsDict.functionStub.length == 0, dump([phase, itemsDict.functionStub]));
+ if (singlePhase) {
+ assert(data.unparsedGlobalss[0].lines.length == 0, dump([phase, data.unparsedGlobalss]));
+ assert(itemsDict.functionStub.length == 0, dump([phase, itemsDict.functionStub]));
+ }
}
if (phase == 'pre' || phase == 'funcs') {
diff --git a/src/library.js b/src/library.js
index 0e5919ad..7438b0ad 100644
--- a/src/library.js
+++ b/src/library.js
@@ -612,7 +612,7 @@ LibraryManager.library = {
},
deleteFile: function(path) {
- var path = FS.analyzePath(path);
+ path = FS.analyzePath(path);
if (!path.parentExists || !path.exists) {
throw 'Invalid path ' + path;
}
@@ -3549,21 +3549,42 @@ LibraryManager.library = {
* this implementation simply uses malloc underneath the call to
* mmap.
*/
+ if (!_mmap.mappings) _mmap.mappings = {};
if (stream == -1) {
var ptr = _malloc(num);
- _memset(ptr, 0, num);
- return ptr;
+ } else {
+ var info = FS.streams[stream];
+ if (!info) return -1;
+ var contents = info.object.contents;
+ contents = Array.prototype.slice.call(contents, offset, offset+num);
+ ptr = allocate(contents, 'i8', ALLOC_NORMAL);
+ }
+ // align to page size
+ var ret = ptr;
+ if (ptr % PAGE_SIZE != 0) {
+ var old = ptr;
+ ptr = _malloc(num + PAGE_SIZE);
+ ret = alignMemoryPage(ptr);
+ _memcpy(ret, old, num);
+ _free(old);
}
- var info = FS.streams[stream];
- if (!info) return -1;
- var contents = info.object.contents;
- contents = Array.prototype.slice.call(contents, offset, offset+num);
- return allocate(contents, 'i8', ALLOC_NORMAL);
+ if (stream == -1) {
+ _memset(ret, 0, num);
+ }
+ _mmap.mappings[ret] = { malloc: ptr, num: num };
+ return ret;
},
__01mmap64_: 'mmap',
munmap: function(start, num) {
- _free(start);
+ if (!_mmap.mappings) _mmap.mappings = {};
+ // TODO: support unmmap'ing parts of allocations
+ var info = _mmap.mappings[start];
+ if (!info) return 0;
+ if (num == info.num) {
+ _mmap.mappings[start] = null;
+ _free(info.malloc);
+ }
return 0;
},
@@ -3819,9 +3840,73 @@ LibraryManager.library = {
return ret;
},
- strtoll__deps: ['_parseInt'],
+#if USE_TYPED_ARRAYS == 2
+ _parseInt64__deps: ['isspace', '__setErrNo', '$ERRNO_CODES', function() { Types.preciseI64MathUsed = 1 }],
+ _parseInt64: function(str, endptr, base, min, max, unsign) {
+ var start = str;
+ // Skip space.
+ while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++;
+
+ // Check for a plus/minus sign.
+ if ({{{ makeGetValue('str', 0, 'i8') }}} == '-'.charCodeAt(0)) {
+ str++;
+ } else if ({{{ makeGetValue('str', 0, 'i8') }}} == '+'.charCodeAt(0)) {
+ str++;
+ }
+
+ // Find base.
+ var ok = false;
+ var finalBase = base;
+ if (!finalBase) {
+ if ({{{ makeGetValue('str', 0, 'i8') }}} == '0'.charCodeAt(0)) {
+ if ({{{ makeGetValue('str+1', 0, 'i8') }}} == 'x'.charCodeAt(0) ||
+ {{{ makeGetValue('str+1', 0, 'i8') }}} == 'X'.charCodeAt(0)) {
+ finalBase = 16;
+ str += 2;
+ } else {
+ finalBase = 8;
+ str++;
+ ok = true; // we saw an initial zero, perhaps the entire thing is just "0"
+ }
+ }
+ }
+ if (!finalBase) finalBase = 10;
+
+ // Get digits.
+ var chr;
+ while ((chr = {{{ makeGetValue('str', 0, 'i8') }}}) != 0) {
+ var digit = parseInt(String.fromCharCode(chr), finalBase);
+ if (isNaN(digit)) {
+ break;
+ } else {
+ str++;
+ ok = true;
+ }
+ }
+ if (!ok) {
+ ___setErrNo(ERRNO_CODES.EINVAL);
+ return [0, 0];
+ }
+
+ try {
+ i64Math.fromString(Pointer_stringify(start, str - start), finalBase, min, max, unsign);
+ } catch(e) {
+ ___setErrNo(ERRNO_CODES.ERANGE); // not quite correct
+ }
+
+ // Set end pointer.
+ if (endptr) {
+ {{{ makeSetValue('endptr', 0, 'str', '*') }}}
+ }
+
+ var ret = i64Math.result.slice(0);
+
+ return ret;
+ },
+#endif
+ strtoll__deps: ['_parseInt64'],
strtoll: function(str, endptr, base) {
- return __parseInt(str, endptr, base, -9223372036854775200, 9223372036854775200, 64); // LLONG_MIN, LLONG_MAX; imprecise.
+ return __parseInt64(str, endptr, base, '-9223372036854775808', '9223372036854775807'); // LLONG_MIN, LLONG_MAX.
},
strtoll_l: 'strtoll', // no locale support yet
strtol__deps: ['_parseInt'],
@@ -3834,9 +3919,9 @@ LibraryManager.library = {
return __parseInt(str, endptr, base, 0, 4294967295, 32, true); // ULONG_MAX.
},
strtoul_l: 'strtoul', // no locale support yet
- strtoull__deps: ['_parseInt'],
+ strtoull__deps: ['_parseInt64'],
strtoull: function(str, endptr, base) {
- return __parseInt(str, endptr, base, 0, 18446744073709551615, 64, true); // ULONG_MAX; imprecise.
+ return __parseInt64(str, endptr, base, 0, '18446744073709551615', true); // ULONG_MAX.
},
strtoull_l: 'strtoull', // no locale support yet
@@ -4746,6 +4831,17 @@ LibraryManager.library = {
return ((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24);
},
+ llvm_bswap_i64__deps: ['llvm_bswap_i32'],
+ llvm_bswap_i64: function(l, h) {
+ var retl = _llvm_bswap_i32(h)>>>0;
+ var reth = _llvm_bswap_i32(l)>>>0;
+#if USE_TYPED_ARRAYS == 2
+ return [retl, reth];
+#else
+ throw 'unsupported';
+#endif
+ },
+
llvm_ctlz_i32: function(x) {
for (var i=0; i<32; i++) {
if ( (x & (1 << (31-i))) != 0 ) {
@@ -4755,17 +4851,28 @@ LibraryManager.library = {
return 32;
},
+ llvm_ctlz_i64__deps: ['llvm_ctlz_i32'],
+ llvm_ctlz_i64: function(l, h) {
+ var ret = _llvm_ctlz_i32(h);
+ if (ret == 32) ret += _llvm_ctlz_i32(l);
+#if USE_TYPED_ARRAYS == 2
+ return [ret, 0];
+#else
+ return ret;
+#endif
+ },
+
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;
+ throw 'Assertion failed: ' + Pointer_stringify(condition) + ' at ' + new Error().stack;
},
__assert_func: function(filename, line, func, condition) {
- throw 'Assertion failed: ' + (condition ? Pointer_stringify(condition) : 'unknown condition') + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'];
+ throw 'Assertion failed: ' + (condition ? Pointer_stringify(condition) : 'unknown condition') + ', at: ' + [filename ? Pointer_stringify(filename) : 'unknown filename', line, func ? Pointer_stringify(func) : 'unknown function'] + ' at ' + new Error().stack;
},
__cxa_guard_acquire: function(variable) {
@@ -5091,8 +5198,8 @@ LibraryManager.library = {
return ret;
},
- llvm_expect_i32__inline: function(x, y) {
- return '((' + x + ')==(' + y + '))';
+ llvm_expect_i32__inline: function(val, expected) {
+ return '(' + val + ')';
},
llvm_lifetime_start: function() {},
diff --git a/src/library_browser.js b/src/library_browser.js
index ef8b4360..32a7d2cc 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -336,11 +336,11 @@ mergeInto(LibraryManager.library, {
xhr.send(null);
},
- asyncLoad: function(url, onload, onerror) {
+ asyncLoad: function(url, onload, onerror, noRunDep) {
Browser.xhrLoad(url, function(arrayBuffer) {
assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
onload(new Uint8Array(arrayBuffer));
- removeRunDependency('al ' + url);
+ if (!noRunDep) removeRunDependency('al ' + url);
}, function(event) {
if (onerror) {
onerror();
@@ -348,7 +348,7 @@ mergeInto(LibraryManager.library, {
throw 'Loading data file "' + url + '" failed.';
}
});
- addRunDependency('al ' + url);
+ if (!noRunDep) addRunDependency('al ' + url);
},
resizeListeners: [],
@@ -385,6 +385,17 @@ mergeInto(LibraryManager.library, {
);
},
+ emscripten_async_wget_data: function(url, arg, onload, onerror) {
+ Browser.asyncLoad(Pointer_stringify(url), function(byteArray) {
+ var buffer = _malloc(byteArray.length);
+ HEAPU8.set(byteArray, buffer);
+ FUNCTION_TABLE[onload](arg, buffer, byteArray.length);
+ _free(buffer);
+ }, function() {
+ if (onerror) FUNCTION_TABLE[onerror](arg);
+ }, true /* no need for run dependency, this is async but will not do any prepare etc. step */ );
+ },
+
emscripten_async_prepare: function(file, onload, onerror) {
var _file = Pointer_stringify(file);
var data = FS.analyzePath(_file);
diff --git a/src/long.js b/src/long.js
index 865540db..a5367b2c 100644
--- a/src/long.js
+++ b/src/long.js
@@ -1053,7 +1053,7 @@ var i64Math = (function() { // Emscripten wrapper
if(r != 0) return r;
var i = this.t;
r = i-a.t;
- if(r != 0) return r;
+ if(r != 0) return (this.s<0)?-r:r;
while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
return 0;
}
@@ -1551,9 +1551,15 @@ var i64Math = (function() { // Emscripten wrapper
HEAP32[tempDoublePtr>>2] = ret.low_;
HEAP32[tempDoublePtr+4>>2] = ret.high_;
},
- makeTwo32: function() {
+ ensureTemps: function() {
+ if (Wrapper.ensuredTemps) return;
+ Wrapper.ensuredTemps = true;
Wrapper.two32 = new BigInteger();
Wrapper.two32.fromString('4294967296', 10);
+ Wrapper.two64 = new BigInteger();
+ Wrapper.two64.fromString('18446744073709551616', 10);
+ Wrapper.temp1 = new BigInteger();
+ Wrapper.temp2 = new BigInteger();
},
lh2bignum: function(l, h) {
var a = new BigInteger();
@@ -1567,7 +1573,7 @@ var i64Math = (function() { // Emscripten wrapper
return d;
},
divide: function(xl, xh, yl, yh, unsigned) {
- if (!Wrapper.two32) Wrapper.makeTwo32();
+ Wrapper.ensureTemps();
if (!unsigned) {
var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh);
@@ -1588,7 +1594,7 @@ var i64Math = (function() { // Emscripten wrapper
}
},
modulo: function(xl, xh, yl, yh, unsigned) {
- if (!Wrapper.two32) Wrapper.makeTwo32();
+ Wrapper.ensureTemps();
if (!unsigned) {
var x = new goog.math.Long(xl, xh);
var y = new goog.math.Long(yl, yh);
@@ -1612,10 +1618,7 @@ var i64Math = (function() { // Emscripten wrapper
var ret = new goog.math.Long(l, h).toString();
if (unsigned && ret[0] == '-') {
// unsign slowly using jsbn bignums
- if (!Wrapper.two64) {
- Wrapper.two64 = new BigInteger();
- Wrapper.two64.fromString('18446744073709551616', 10);
- }
+ Wrapper.ensureTemps();
var bignum = new BigInteger();
bignum.fromString(ret, 10);
ret = new BigInteger();
@@ -1623,6 +1626,32 @@ var i64Math = (function() { // Emscripten wrapper
ret = ret.toString(10);
}
return ret;
+ },
+ fromString: function(str, base, min, max, unsigned) {
+ Wrapper.ensureTemps();
+ var bignum = new BigInteger();
+ bignum.fromString(str, base);
+ var bigmin = new BigInteger();
+ bigmin.fromString(min, 10);
+ var bigmax = new BigInteger();
+ bigmax.fromString(max, 10);
+ if (unsigned && bignum.compareTo(BigInteger.ZERO) < 0) {
+ var temp = new BigInteger();
+ bignum.addTo(Wrapper.two64, temp);
+ bignum = temp;
+ }
+ var error = false;
+ if (bignum.compareTo(bigmin) < 0) {
+ bignum = bigmin;
+ error = true;
+ } else if (bignum.compareTo(bigmax) > 0) {
+ bignum = bigmax;
+ error = true;
+ }
+ var ret = goog.math.Long.fromString(bignum.toString()); // min-max checks should have clamped this to a range goog.math.Long can handle well
+ Wrapper.result[0] = ret.low_;
+ Wrapper.result[1] = ret.high_;
+ if (error) throw 'range error';
}
};
return Wrapper;
diff --git a/src/modules.js b/src/modules.js
index 5c1d6a1d..dd027f73 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -307,7 +307,7 @@ var LibraryManager = {
loaded: false,
load: function() {
- assert(!this.library);
+ if (this.library) return;
var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js'].concat(additionalLibraries);
for (var i = 0; i < libraries.length; i++) {
diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h
index 3eefe0b8..926fe2e5 100644
--- a/system/include/emscripten/emscripten.h
+++ b/system/include/emscripten/emscripten.h
@@ -187,6 +187,30 @@ float emscripten_random();
void emscripten_async_wget(const char* url, const char* file, void (*onload)(const char*), void (*onerror)(const char*));
/*
+ * Data version of emscripten_async_wget. Instead of writing
+ * to a file, it writes to a buffer directly in memory.
+ * This avoids the overhead of using the emulated
+ * filesystem, note however that since files are not used,
+ * It cannot do the 'prepare' stage to set things up for
+ * IMG_Load and so forth (IMG_Load etc. work on files).
+ *
+ * @param arg User-defined data that is passed to the callbacks,
+ *
+ * @param onload Callback on success, with the @arg that
+ * was provided to this function, a pointer
+ * to a buffer with the data, and the size
+ * of the buffer. As in the worker API, the
+ * data buffer only lives during the
+ * callback, so you should use it or copy
+ * it during that time and not later.
+ *
+ * @param onerror An optional callback on failure, with the
+ * @arg that was provided to this function.
+ *
+ */
+void emscripten_async_wget_data(const char* url, void *arg, void (*onload)(void*, void*, int), void (*onerror)(void*));
+
+/*
* Prepare a file in asynchronous way. This does just the
* preparation part of emscripten_async_wget, that is, it
* works on file data already present, and asynchronously
diff --git a/tests/cases/typestr.ll b/tests/cases/typestr.ll
new file mode 100644
index 00000000..49074637
--- /dev/null
+++ b/tests/cases/typestr.ll
@@ -0,0 +1,19 @@
+; ModuleID = 'tests/hello_world.bc'
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+target triple = "i386-pc-linux-gnu"
+
+@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*]
+@.str1227 = private unnamed_addr constant [9 x i8] c" = type \00", align 1
+
+; [#uses=0]
+define i32 @main() {
+entry:
+ %retval = alloca i32, align 4 ; [#uses=1 type=i32*]
+ store i32 0, i32* %retval
+ %call0 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([9 x i8]* @.str1227, i32 0, i32 0)) ; [#uses=0 type=i32]
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0 type=i32]
+ ret i32 1
+}
+
+; [#uses=1]
+declare i32 @printf(i8*, ...)
diff --git a/tests/emscripten_fs_api_browser.cpp b/tests/emscripten_fs_api_browser.cpp
index a2a82160..0355287a 100644
--- a/tests/emscripten_fs_api_browser.cpp
+++ b/tests/emscripten_fs_api_browser.cpp
@@ -9,13 +9,58 @@ extern "C" {
int result = 1;
int get_count = 0;
+int data_ok = 0;
+int data_bad = 0;
+void onLoadedData(void *arg, void *buffer, int size) {
+ printf("onLoadedData %d\n", (int)arg);
+ get_count++;
+ assert(size == 329895);
+ assert((int)arg == 135);
+ unsigned char *b = (unsigned char*)buffer;
+ assert(b[0] == 137);
+ assert(b[1122] == 128);
+ assert(b[1123] == 201);
+ assert(b[202125] == 218);
+ data_ok = 1;
+}
+
+void onErrorData(void *arg) {
+ printf("onErrorData %d\n", (int)arg);
+ get_count++;
+ assert((int)arg == 246);
+ data_bad = 1;
+}
+
+int counter = 0;
void wait_wgets() {
+ if (counter++ == 60) {
+ printf("%d\n", get_count);
+ counter = 0;
+ }
+
if (get_count == 3) {
+ static bool fired = false;
+ if (!fired) {
+ fired = true;
+ emscripten_async_wget_data(
+ "http://localhost:8888/screenshot.png",
+ (void*)135,
+ onLoadedData,
+ onErrorData);
+ emscripten_async_wget_data(
+ "http://localhost:8888/fail_me",
+ (void*)246,
+ onLoadedData,
+ onErrorData);
+ }
+ } else if (get_count == 5) {
assert(IMG_Load("/tmp/screen_shot.png"));
+ assert(data_ok == 1 && data_bad == 1);
emscripten_cancel_main_loop();
REPORT_RESULT();
}
+ assert(get_count <= 5);
}
void onLoaded(const char* file) {
@@ -23,8 +68,6 @@ void onLoaded(const char* file) {
result = 0;
}
- printf("loaded: %s\n", file);
-
if (FILE * f = fopen(file, "r")) {
printf("exists: %s\n", file);
int c = fgetc (f);
@@ -39,6 +82,7 @@ void onLoaded(const char* file) {
}
get_count++;
+ printf("onLoaded %s\n", file);
}
void onError(const char* file) {
@@ -46,8 +90,8 @@ void onError(const char* file) {
result = 0;
}
- printf("error: %s\n", file);
get_count++;
+ printf("onError %s\n", file);
}
int main() {
diff --git a/tests/parseInt/output.txt b/tests/parseInt/output.txt
index 7ab00631..c1406949 100644
--- a/tests/parseInt/output.txt
+++ b/tests/parseInt/output.txt
@@ -1,52 +1,50 @@
strtol("-9223372036854775809") = -2147483648
ERR 34
-strtoll("-9223372036854775809") = -9223372036854775000
+strtoll("-9223372036854775809") = -9223372036854775808
ERR 34
strtoul("-9223372036854775809") = 4294967295
ERR 34
-strtoull("-9223372036854775809") = 9223372036854774000
+strtoull("-9223372036854775809") = 9223372036854775807
strtol("-9223372036854775808") = -2147483648
ERR 34
-strtoll("-9223372036854775808") = -9223372036854775000
-ERR 34
+strtoll("-9223372036854775808") = -9223372036854775808
strtoul("-9223372036854775808") = 4294967295
ERR 34
-strtoull("-9223372036854775808") = 9223372036854774000
+strtoull("-9223372036854775808") = 9223372036854775808
strtol("-9223372036854775807") = -2147483648
ERR 34
-strtoll("-9223372036854775807") = -9223372036854775000
-ERR 34
+strtoll("-9223372036854775807") = -9223372036854775807
strtoul("-9223372036854775807") = 4294967295
ERR 34
-strtoull("-9223372036854775807") = 9223372036854774000
+strtoull("-9223372036854775807") = 9223372036854775809
strtol("-2147483649") = -2147483648
ERR 34
strtoll("-2147483649") = -2147483649
strtoul("-2147483649") = 2147483647
-strtoull("-2147483649") = 18446744071562068000
+strtoull("-2147483649") = 18446744071562067967
strtol("-2147483648") = -2147483648
strtoll("-2147483648") = -2147483648
strtoul("-2147483648") = 2147483648
-strtoull("-2147483648") = 18446744071562068000
+strtoull("-2147483648") = 18446744071562067968
strtol("-2147483647") = -2147483647
strtoll("-2147483647") = -2147483647
strtoul("-2147483647") = 2147483649
-strtoull("-2147483647") = 18446744071562068000
+strtoull("-2147483647") = 18446744071562067969
strtol("-5") = -5
strtoll("-5") = -5
strtoul("-5") = 4294967291
-strtoull("-5") = 18446744069414584000
+strtoull("-5") = 18446744073709551611
strtol("-1") = -1</