summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js34
-rw-r--r--src/compiler.js15
-rw-r--r--src/compiler_phase.html33
-rw-r--r--src/fastLong.js12
-rw-r--r--src/intertyper.js168
-rw-r--r--src/jsifier.js216
-rw-r--r--src/library.js845
-rw-r--r--src/library_fs.js83
-rw-r--r--src/library_gl.js168
-rw-r--r--src/library_idbfs.js216
-rw-r--r--src/library_memfs.js23
-rw-r--r--src/library_nodefs.js234
-rw-r--r--src/library_sdl.js465
-rw-r--r--src/library_sockfs.js12
-rw-r--r--src/modules.js28
-rw-r--r--src/parseTools.js314
-rw-r--r--src/preamble.js31
-rw-r--r--src/runtime.js19
-rw-r--r--src/settings.js444
-rw-r--r--src/struct_info.json1045
-rw-r--r--src/utility.js11
21 files changed, 3029 insertions, 1387 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 750f2a4c..17ad26ad 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -30,6 +30,8 @@ function analyzer(data, sidePass) {
var item = { items: data };
var data = item;
+ var newTypes = {};
+
// Gather
// Single-liners
['globalVariable', 'functionStub', 'unparsedFunction', 'unparsedGlobals', 'unparsedTypes', 'alias'].forEach(function(intertype) {
@@ -42,6 +44,7 @@ function analyzer(data, sidePass) {
temp.splitOut.forEach(function(type) {
//dprint('types', 'adding defined type: ' + type.name_);
Types.types[type.name_] = type;
+ newTypes[type.name_] = 1;
if (QUANTUM_SIZE === 1) {
Types.fatTypes[type.name_] = copy(type);
}
@@ -780,13 +783,14 @@ function analyzer(data, sidePass) {
assert(PRECISE_I64_MATH, 'Must have precise i64 math for non-constant 64-bit shifts');
Types.preciseI64MathUsed = 1;
value.intertype = 'value';
- value.ident = 'var ' + value.assignTo + '$0 = ' +
+ value.ident = makeVarDef(value.assignTo) + '$0=' +
asmCoercion('_bitshift64' + value.op[0].toUpperCase() + value.op.substr(1) + '(' +
asmCoercion(sourceElements[0].ident, 'i32') + ',' +
asmCoercion(sourceElements[1].ident, 'i32') + ',' +
asmCoercion(value.params[1].ident + '$0', 'i32') + ')', 'i32'
) + ';' +
- 'var ' + value.assignTo + '$1 = tempRet0;';
+ makeVarDef(value.assignTo) + '$1=tempRet0;';
+ value.vars = [[value.assignTo + '$0', 'i32'], [value.assignTo + '$1', 'i32']];
value.assignTo = null;
i++;
continue;
@@ -897,7 +901,7 @@ function analyzer(data, sidePass) {
});
}
- function addTypeInternal(type, data) {
+ function addTypeInternal(type) {
if (type.length == 1) return;
if (Types.types[type]) return;
if (['internal', 'hidden', 'inbounds', 'void'].indexOf(type) != -1) return;
@@ -908,8 +912,9 @@ function analyzer(data, sidePass) {
// to look at the underlying type - it was not defined explicitly
// anywhere else.
var nonPointing = removeAllPointing(type);
+ if (Types.types[nonPointing]) return;
var check = /^\[(\d+)\ x\ (.*)\]$/.exec(nonPointing);
- if (check && !Types.types[nonPointing]) {
+ if (check) {
var num = parseInt(check[1]);
num = Math.max(num, 1); // [0 x something] is used not for allocations and such of course, but
// for indexing - for an |array of unknown length|, basically. So we
@@ -917,7 +922,7 @@ function analyzer(data, sidePass) {
// check that we never allocate with this (either as a child structure
// in the analyzer, or in calcSize in alloca).
var subType = check[2];
- addTypeInternal(subType, data); // needed for anonymous structure definitions (see below)
+ addTypeInternal(subType); // needed for anonymous structure definitions (see below)
// Huge structural types are represented very inefficiently, both here and in generated JS. Best to avoid them - for example static char x[10*1024*1024]; is bad, while static char *x = malloc(10*1024*1024) is fine.
if (num >= 10*1024*1024) warnOnce('warning: very large fixed-size structural type: ' + type + ' - can you reduce it? (compilation may be slow)');
@@ -926,6 +931,7 @@ function analyzer(data, sidePass) {
fields: range(num).map(function() { return subType }),
lineNum: '?'
};
+ newTypes[nonPointing] = 1;
// Also add a |[0 x type]| type
var zerod = '[0 x ' + subType + ']';
if (!Types.types[zerod]) {
@@ -934,6 +940,7 @@ function analyzer(data, sidePass) {
fields: [subType, subType], // Two, so we get the flatFactor right. We care about the flatFactor, not the size here
lineNum: '?'
};
+ newTypes[zerod] = 1;
}
return;
}
@@ -964,6 +971,7 @@ function analyzer(data, sidePass) {
packed: packed,
lineNum: '?'
};
+ newTypes[type] = 1;
return;
}
@@ -975,13 +983,14 @@ function analyzer(data, sidePass) {
flatSize: 1,
lineNum: '?'
};
+ newTypes[type] = 1;
}
- function addType(type, data) {
- addTypeInternal(type, data);
+ function addType(type) {
+ addTypeInternal(type);
if (QUANTUM_SIZE === 1) {
Types.flipTypes();
- addTypeInternal(type, data);
+ addTypeInternal(type);
Types.flipTypes();
}
}
@@ -992,7 +1001,7 @@ function analyzer(data, sidePass) {
// which handles type definitions, and later. Doing so before the first side pass will result in
// making bad guesses about types which are actually defined
for (var type in Types.needAnalysis) {
- if (type) addType(type, data);
+ if (type) addType(type);
}
Types.needAnalysis = {};
}
@@ -1021,17 +1030,18 @@ function analyzer(data, sidePass) {
var more = true;
while (more) {
more = false;
- for (var typeName in types) {
+ for (var typeName in newTypes) {
var type = types[typeName];
if (type.flatIndexes) continue;
var ready = true;
type.fields.forEach(function(field) {
if (isStructType(field)) {
if (!types[field]) {
- addType(field, item);
+ addType(field);
ready = false;
} else {
if (!types[field].flatIndexes) {
+ newTypes[field] = 1;
ready = false;
}
}
@@ -1058,6 +1068,8 @@ function analyzer(data, sidePass) {
Runtime.QUANTUM_SIZE = trueQuantumSize;
Types.flipTypes();
}
+
+ newTypes = null;
}
// Variable analyzer
diff --git a/src/compiler.js b/src/compiler.js
index 4f16986c..90060837 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -206,6 +206,11 @@ if (phase == 'pre') {
if (VERBOSE) printErr('VERBOSE is on, this generates a lot of output and can slow down compilation');
+// Load struct and define information.
+var temp = JSON.parse(read(STRUCT_INFO));
+C_STRUCTS = temp.structs;
+C_DEFINES = temp.defines;
+
// Load compiler code
load('modules.js');
@@ -215,7 +220,12 @@ load('analyzer.js');
load('jsifier.js');
if (phase == 'funcs' && RELOOP) { // XXX handle !singlePhase
RelooperModule = { TOTAL_MEMORY: ceilPowerOfTwo(2*RELOOPER_BUFFER_SIZE) };
- load(RELOOPER);
+ try {
+ load(RELOOPER);
+ } catch(e) {
+ printErr('cannot load relooper at ' + RELOOPER + ' : ' + e + ', trying in current dir');
+ load('relooper.js');
+ }
assert(typeof Relooper != 'undefined');
}
globalEval(processMacros(preprocess(read('runtime.js'))));
@@ -269,6 +279,9 @@ function compile(raw) {
intertyped = null;
JSify(analyzed);
+ //dumpInterProf();
+ //printErr(phase + ' paths (fast, slow): ' + [fastPaths, slowPaths]);
+
phase = null;
if (DEBUG_MEMORY) {
diff --git a/src/compiler_phase.html b/src/compiler_phase.html
new file mode 100644
index 00000000..8ca631e8
--- /dev/null
+++ b/src/compiler_phase.html
@@ -0,0 +1,33 @@
+<html>
+<body>
+<h2>Run the emscripten compiler in a web page, just for laughs</h2>
+Open the web console to see stderr output
+<hr>
+<pre id="output"></pre>
+<script>
+ arguments = ['tmp/emscripten_temp/tmpbTF9CI.txt', 'tmp/emscripten_temp/tmpz8Yvie.pre.ll', 'pre']; // copy from emscripten.py output
+
+ var outputElement = document.getElementById('output');
+ print = function(x) {
+ outputElement.innerHTML += 'output hidden, profiling mode';
+ print = function(){};
+ //outputElement.innerHTML += x;
+ };
+
+ // For generated code
+ var Module = {
+ print: function(x) {
+ throw 'what?'
+ }
+ };
+
+ var startTime = Date.now();
+</script>
+<script src="compiler.js">
+</script>
+<script>
+ outputElement.innerHTML += '<br>total time: ' + (Date.now() - startTime);
+</script>
+</body>
+</html>
+
diff --git a/src/fastLong.js b/src/fastLong.js
index 4f6efd9f..2b70b2fb 100644
--- a/src/fastLong.js
+++ b/src/fastLong.js
@@ -5,12 +5,12 @@ function ___muldsi3($a, $b) {
var $1 = 0, $2 = 0, $3 = 0, $6 = 0, $8 = 0, $11 = 0, $12 = 0;
$1 = $a & 65535;
$2 = $b & 65535;
- $3 = Math.imul($2, $1) | 0;
+ $3 = Math_imul($2, $1) | 0;
$6 = $a >>> 16;
- $8 = ($3 >>> 16) + (Math.imul($2, $6) | 0) | 0;
+ $8 = ($3 >>> 16) + (Math_imul($2, $6) | 0) | 0;
$11 = $b >>> 16;
- $12 = Math.imul($11, $1) | 0;
- return (tempRet0 = (($8 >>> 16) + (Math.imul($11, $6) | 0) | 0) + ((($8 & 65535) + $12 | 0) >>> 16) | 0, 0 | ($8 + $12 << 16 | $3 & 65535)) | 0;
+ $12 = Math_imul($11, $1) | 0;
+ return (tempRet0 = (($8 >>> 16) + (Math_imul($11, $6) | 0) | 0) + ((($8 & 65535) + $12 | 0) >>> 16) | 0, 0 | ($8 + $12 << 16 | $3 & 65535)) | 0;
}
function ___divdi3($a$0, $a$1, $b$0, $b$1) {
$a$0 = $a$0 | 0;
@@ -63,8 +63,8 @@ function ___muldi3($a$0, $a$1, $b$0, $b$1) {
$y_sroa_0_0_extract_trunc = $b$0;
$1$0 = ___muldsi3($x_sroa_0_0_extract_trunc, $y_sroa_0_0_extract_trunc) | 0;
$1$1 = tempRet0;
- $2 = Math.imul($a$1, $y_sroa_0_0_extract_trunc) | 0;
- return (tempRet0 = ((Math.imul($b$1, $x_sroa_0_0_extract_trunc) | 0) + $2 | 0) + $1$1 | $1$1 & 0, 0 | $1$0 & -1) | 0;
+ $2 = Math_imul($a$1, $y_sroa_0_0_extract_trunc) | 0;
+ return (tempRet0 = ((Math_imul($b$1, $x_sroa_0_0_extract_trunc) | 0) + $2 | 0) + $1$1 | $1$1 & 0, 0 | $1$0 & -1) | 0;
}
function ___udivdi3($a$0, $a$1, $b$0, $b$1) {
$a$0 = $a$0 | 0;
diff --git a/src/intertyper.js b/src/intertyper.js
index e43cc298..09bdaa33 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -3,6 +3,8 @@
// LLVM assembly => internal intermediate representation, which is ready
// to be processed by the later stages.
+var fastPaths = 0, slowPaths = 0;
+
// Line tokenizer
function tokenizer(item, inner) {
//assert(item.lineNum != 40000);
@@ -373,6 +375,14 @@ function intertyper(lines, sidePass, baseLineNums) {
// Line parsers to intermediate form
// globals: type or variable
+ function noteGlobalVariable(ret) {
+ if (!NAMED_GLOBALS) {
+ Variables.globals[ret.ident].type = ret.type;
+ Variables.globals[ret.ident].external = ret.external;
+ }
+ Types.needAnalysis[ret.type] = 0;
+ }
+
function globalHandler(item) {
function scanConst(value, type) {
// Gets an array of constant items, separated by ',' tokens
@@ -497,7 +507,6 @@ function intertyper(lines, sidePass, baseLineNums) {
external = true;
item.tokens.splice(2, 1);
}
- Types.needAnalysis[item.tokens[2].text] = 0;
var ret = {
intertype: 'globalVariable',
ident: toNiceIdent(ident),
@@ -507,11 +516,7 @@ function intertyper(lines, sidePass, baseLineNums) {
named: named,
lineNum: item.lineNum
};
- if (!NAMED_GLOBALS) {
- Variables.globals[ret.ident].type = ret.type;
- Variables.globals[ret.ident].external = external;
- }
- Types.needAnalysis[ret.type] = 0;
+ noteGlobalVariable(ret);
if (ident == '@llvm.global_ctors') {
ret.ctors = [];
if (item.tokens[3].item) {
@@ -845,6 +850,7 @@ function intertyper(lines, sidePass, baseLineNums) {
// TODO: also remove 2nd param?
} else if (item.op in LLVM.COMPS) {
item.type = 'i1';
+ if (item.params[1].intertype === 'type') item.params[1].intertype = 'value'; // parsed as type, but comparisons have just values there
}
if (USE_TYPED_ARRAYS == 2) {
// Some specific corrections, since 'i64' is special
@@ -984,11 +990,150 @@ function intertyper(lines, sidePass, baseLineNums) {
return ret;
}
+ // Fast paths - quick parses of common patterns, avoid tokenizing entirely
+
+ function tryFastPaths(line) {
+ var m, ret;
+ if (phase === 'pre') {
+ // string constant
+ if (0) { // works, but not worth it m = /([@\.\w\d_]+) = (private )?(unnamed_addr )?(constant )?(\[\d+ x i8\]) c"([^"]+)".*/.exec(line.lineText)) {
+ if (m[1] === '@llvm.global_ctors') return ret;
+ ret = {
+ intertype: 'globalVariable',
+ ident: toNiceIdent(m[1]),
+ type: m[5],
+ external: false,
+ private_: m[2] !== null,
+ named: m[3] === null,
+ lineNum: line.lineNum,
+ value: {
+ intertype: 'string',
+ text: m[6]
+ }
+ };
+ noteGlobalVariable(ret);
+ }
+ } else if (phase === 'funcs') {
+ // TODO: (void)call, store
+ if (m = /^ (%[\w\d\._]+) = (getelementptr|load|icmp) ([%\w\d\._ ,\*\-@]+)$/.exec(line.lineText)) {
+ var assignTo = m[1];
+ var intertype = m[2];
+ var args = m[3];
+ switch (intertype) {
+ case 'getelementptr': {
+ if (args[0] === 'i' && args.indexOf('inbounds ') === 0) {
+ args = args.substr(9);
+ }
+ var params = args.split(', ').map(function(param) {
+ var parts = param.split(' ');
+ assert(parts.length === 2);
+ Types.needAnalysis[parts[0]] = 0;
+ return {
+ intertype: 'value',
+ type: parts[0],
+ ident: toNiceIdent(parts[1]),
+ byVal: 0
+ }
+ });
+ ret = {
+ intertype: 'getelementptr',
+ lineNum: line.lineNum,
+ assignTo: toNiceIdent(assignTo),
+ ident: params[0].ident,
+ type: '*',
+ params: params
+ };
+ break;
+ }
+ case 'load': {
+ if (m = /(^[%\w\d\._\-@\*]+) ([%\w\d\._\-@]+)(, align \d+)?$/.exec(args)) {
+ var ident = toNiceIdent(m[2]);
+ var type = m[1];
+ assert(type[type.length-1] === '*', type);
+ var valueType = type.substr(0, type.length-1);
+ ret = {
+ intertype: 'load',
+ lineNum: line.lineNum,
+ assignTo: toNiceIdent(assignTo),
+ ident: ident,
+ type: valueType,
+ valueType: valueType,
+ pointerType: type,
+ pointer: {
+ intertype: 'value',
+ ident: ident,
+ type: type,
+ },
+ align: parseAlign(m[3])
+ };
+ }
+ break;
+ }
+ case 'icmp': {
+ var parts = args.split(' ');
+ assert(parts.length === 4);
+ ret = {
+ intertype: 'mathop',
+ op: 'icmp',
+ variant: parts[0],
+ lineNum: line.lineNum,
+ assignTo: toNiceIdent(assignTo),
+ params: [{
+ intertype: 'value',
+ ident: toNiceIdent(parts[2].substr(0, parts[2].length-1)),
+ type: parts[1]
+ }, {
+ intertype: 'value',
+ ident: toNiceIdent(parts[3]),
+ type: parts[1]
+ }],
+ type: 'i1',
+ };
+ break;
+ }
+ default: throw 'unexpected fast path type ' + intertype;
+ }
+ }
+ //else if (line.lineText.indexOf(' = icmp ') > 0) printErr('close: ' + JSON.stringify(line.lineText));
+ }
+ if (ret) {
+ if (COMPILER_ASSERTIONS) {
+ //printErr(['\n', dump(ret), '\n', dump(triager(tokenizer(line)))]);
+ var normal = triager(tokenizer(line));
+ delete normal.tokens;
+ delete normal.indent;
+ assert(sortedJsonCompare(normal, ret), 'fast path: ' + dump(normal) + '\n vs \n' + dump(ret));
+ }
+ }
+ return ret;
+ }
+
// Input
lineSplitter().forEach(function(line) {
+ var item;
+ if (COMPILER_FASTPATHS) {
+ item = tryFastPaths(line);
+ if (item) {
+ finalResults.push(item);
+ fastPaths++;
+ return;
+ }
+ }
+ slowPaths++;
+
+ //var time = Date.now();
+
var t = tokenizer(line);
- var item = triager(t);
+ item = triager(t);
+
+ /*
+ var type = item ? item.intertype + (item.op ? ':' + item.op : ''): 'none';
+ if (!interProf[type]) interProf[type] = { ms: 0, n: 0 };
+ interProf[type].ms += Date.now() - time;
+ interProf[type].n++;
+ */
+
if (!item) return;
finalResults.push(item);
if (item.tokens) item.tokens = null; // We do not need tokens, past the intertyper. Clean them up as soon as possible here.
@@ -996,3 +1141,12 @@ function intertyper(lines, sidePass, baseLineNums) {
return finalResults;
}
+// intertyper profiler
+
+/*
+var interProf = {};
+function dumpInterProf() {
+ printErr('\nintertyper/' + phase + ' (ms | n): ' + JSON.stringify(keys(interProf).sort(function(x, y) { return interProf[y].ms - interProf[x].ms }).map(function(x) { return x + ' : ' + interProf[x].ms + ' | ' + interProf[x].n }), null, ' ') + '\n');
+}
+*/
+
diff --git a/src/jsifier.js b/src/jsifier.js
index 96cb8d9a..0e5f8ef3 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -347,7 +347,7 @@ function JSify(data, functionsOnly, givenFunctions) {
js += 'if (globalScope) { assert(!globalScope["' + item.ident + '"]); globalScope["' + item.ident + '"] = ' + item.ident + ' }';
}
if (item.external && !NAMED_GLOBALS) {
- js = 'var ' + item.ident + ' = ' + js; // force an explicit naming, even if unnamed globals, for asm forwarding
+ js = 'var ' + item.ident + '=' + js; // force an explicit naming, even if unnamed globals, for asm forwarding
}
itemsDict.GlobalVariableStub.push({
intertype: 'GlobalVariable',
@@ -418,7 +418,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
// In asm, we need to know about library functions. If there is a target, though, then no
// need to consider this a library function - we will call directly to it anyhow
- if (ASM_JS && !redirectedIdent && (typeof target == 'function' || /Math\.\w+/.exec(snippet))) {
+ if (ASM_JS && !redirectedIdent && (typeof target == 'function' || /Math_\w+/.exec(snippet))) {
Functions.libraryFunctions[ident] = 1;
}
} else if (typeof snippet === 'object') {
@@ -537,6 +537,7 @@ function JSify(data, functionsOnly, givenFunctions) {
default: throw 'what is this line? ' + dump(line);
}
assert(line.JS);
+ //if (ASM_JS) assert(line.JS.indexOf('var ') < 0, dump(line));
if (line.assignTo) makeAssign(line);
Framework.currItem = null;
});
@@ -584,7 +585,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (DLOPEN_SUPPORT) Functions.getIndex(func.ident);
- func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n';
+ func.JS += 'function ' + func.ident + '(' + paramIdents.join(',') + '){\n';
if (PGO) {
func.JS += INDENTATION + 'PGOMonitor.called["' + func.ident + '"] = 1;\n';
@@ -593,13 +594,23 @@ function JSify(data, functionsOnly, givenFunctions) {
if (ASM_JS) {
// spell out argument types
func.params.forEach(function(param) {
- func.JS += INDENTATION + param.ident + ' = ' + asmCoercion(param.ident, param.type) + ';\n';
+ func.JS += INDENTATION + param.ident + '=' + deParen(asmCoercion(param.ident, param.type)) + ';\n';
});
+ addVariable('label', 'i32', func);
+
+ if (func.setjmpTable) {
+ addVariable('setjmpLabel', 'i32', func);
+ addVariable('setjmpTable', 'i32', func);
+ }
+
// spell out local variables
- var vars = values(func.variables).filter(function(v) { return v.origin != 'funcparam' });
+ var vars = values(func.variables).filter(function(v) {
+ return v.origin !== 'funcparam' &&
+ (!isIllegalType(getImplementationType(v)) || v.ident.indexOf('$', 1) > 0); // not illegal, or a broken up illegal (we have illegal chunks explicitly anyhow)
+ });
if (vars.length > 0) {
- var chunkSize = 8;
+ var chunkSize = 20;
var chunks = [];
var i = 0;
while (i < vars.length) {
@@ -608,22 +619,15 @@ function JSify(data, functionsOnly, givenFunctions) {
}
for (i = 0; i < chunks.length; i++) {
func.JS += INDENTATION + 'var ' + chunks[i].map(function(v) {
- var type = getImplementationType(v);
- if (!isIllegalType(type) || v.ident.indexOf('$', 1) > 0) { // not illegal, or a broken up illegal
- return v.ident + ' = ' + asmInitializer(type); //, func.variables[v.ident].impl);
- } else {
- return range(Math.ceil(getBits(type)/32)).map(function(i) {
- return v.ident + '$' + i + '= 0';
- }).join(',');
- }
- }).join(', ') + ';\n';
+ return v.ident + '=' + asmInitializer(getImplementationType(v)); //, func.variables[v.ident].impl);
+ }).join(',') + ';\n';
}
}
}
- if (true) { // TODO: optimize away when not needed
- if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
- func.JS += INDENTATION + 'var label = 0;\n';
+ if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */';
+ if (!ASM_JS) {
+ func.JS += INDENTATION + 'var label=0;\n';
}
if (ASM_JS) {
@@ -632,12 +636,12 @@ function JSify(data, functionsOnly, givenFunctions) {
hasByVal = hasByVal || param.byVal;
});
if (hasByVal) {
- func.JS += INDENTATION + 'var tempParam = 0;\n';
+ func.JS += INDENTATION + 'var tempParam=0;\n';
}
}
if (func.hasVarArgsCall) {
- func.JS += INDENTATION + 'var tempVarArgs = 0;\n';
+ func.JS += INDENTATION + 'var tempVarArgs=0;\n';
}
// Prepare the stack, if we need one. If we have other stack allocations, force the stack to be set up.
@@ -654,7 +658,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (param.byVal) {
var type = removePointing(param.type);
var typeInfo = Types.types[type];
- func.JS += INDENTATION + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + ' = ' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' +
+ func.JS += INDENTATION + (ASM_JS ? '' : 'var ') + 'tempParam = ' + param.ident + '; ' + param.ident + '=' + RuntimeGenerator.stackAlloc(typeInfo.flatSize) + ';' +
makeCopyValues(param.ident, 'tempParam', typeInfo.flatSize, 'null', null, param.byVal) + ';\n';
}
});
@@ -665,14 +669,14 @@ function JSify(data, functionsOnly, givenFunctions) {
function walkBlock(block, indent) {
if (!block) return '';
dprint('relooping', 'walking block: ' + block.type + ',' + block.entries + ' : ' + block.labels.length);
- function getLabelLines(label, indent, relooping) {
+ function getLabelLines(label, relooping) {
if (!label) return '';
var ret = '';
if ((LABEL_DEBUG >= 2) && functionNameFilterTest(func.ident)) {
- ret += indent + "Module.print(INDENT + '" + func.ident + ":" + label.ident + "');\n";
+ ret += INDENTATION + "Module.print(INDENT + '" + func.ident + ":" + label.ident + "');\n";
}
if (EXECUTION_TIMEOUT > 0) {
- ret += indent + 'if (Date.now() - START_TIME >= ' + (EXECUTION_TIMEOUT*1000) + ') throw "Timed out!" + (new Error().stack);\n';
+ ret += INDENTATION + 'if (Date.now() - START_TIME >= ' + (EXECUTION_TIMEOUT*1000) + ') throw "Timed out!" + (new Error().stack);\n';
}
if (PRINT_SPLIT_FILE_MARKER && Debugging.on && Debugging.getAssociatedSourceFile(label.lines[label.lines.length-1].lineNum)) {
@@ -685,6 +689,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var i = 0;
return ret + label.lines.map(function(line) {
var JS = line.JS;
+ if (!relooping) JS = INDENTATION + JS;
if (relooping && i == label.lines.length-1) {
if (line.intertype == 'branch' || line.intertype == 'switch') {
JS = ''; // just branching operations - done in the relooper, so nothing need be done here
@@ -695,12 +700,10 @@ function JSify(data, functionsOnly, givenFunctions) {
i++;
// invoke instructions span two lines, and the debug info is located
// on the second line, hence the +1
- return JS + (Debugging.on ? Debugging.getComment(line.lineNum + (line.intertype === 'invoke' ? 1 : 0)) : '');
- })
- .join('\n')
- .split('\n') // some lines include line breaks
- .map(function(line) { return indent + line })
- .join('\n');
+ if (Debugging.on) JS += Debugging.getComment(line.lineNum + (line.intertype === 'invoke' ? 1 : 0));
+ //assert(JS.indexOf('\n') < 0, JS);
+ return JS;
+ }).join('\n');
}
var ret = '';
if (!RELOOP || func.forceEmulated) { // TODO: also if just 1 label?
@@ -719,19 +722,19 @@ function JSify(data, functionsOnly, givenFunctions) {
ret += 'dummy: 0';
ret += '};\n';
} else {
- ret += 'var setjmpLabel = 0;\n';
- ret += 'var setjmpTable = ' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n';
+ ret += makeVarDef('setjmpLabel') + '=0;\n';
+ ret += makeVarDef('setjmpTable') + '=' + RuntimeGenerator.stackAlloc(4 * (MAX_SETJMPS + 1) * 2) + ';\n';
ret += makeSetValue('setjmpTable', '0', '0', 'i32') + ';'; // initialize first entry to 0
}
}
- ret += indent + 'while(1) ';
+ ret += indent + 'while(1)';
if (func.setjmpTable && !ASM_JS) {
ret += 'try { ';
}
- ret += 'switch(' + asmCoercion('label', 'i32') + ') {\n';
+ ret += 'switch(' + asmCoercion('label', 'i32') + '){\n';
ret += block.labels.map(function(label) {
- return indent + INDENTATION + 'case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
- + getLabelLines(label, indent + INDENTATION + INDENTATION);
+ return INDENTATION + 'case ' + getLabelId(label.ident) + ': ' + (SHOW_LABELS ? '// ' + getOriginalLabelId(label.ident) : '') + '\n'
+ + getLabelLines(label);
}).join('\n') + '\n';
if (func.setjmpTable && ASM_JS) {
// emit a label in which we write to the proper local variable, before jumping to the actual label
@@ -748,8 +751,16 @@ function JSify(data, functionsOnly, givenFunctions) {
if (func.setjmpTable && !ASM_JS) {
ret += ' } catch(e) { if (!e.longjmp || !(e.id in mySetjmpIds)) throw(e); setjmpTable[setjmpLabels[e.id]](e.value) }';
}
+ if (ASM_JS && func.returnType !== 'void') {
+ // Add a return
+ if (func.returnType in Runtime.FLOAT_TYPES) {
+ ret += ' return +0;\n';
+ } else {
+ ret += ' return 0;\n';
+ }
+ }
} else {
- ret += (SHOW_LABELS ? indent + '/* ' + block.entries[0] + ' */' : '') + '\n' + getLabelLines(block.labels[0], indent);
+ ret += (SHOW_LABELS ? indent + '/* ' + block.entries[0] + ' */' : '') + '\n' + getLabelLines(block.labels[0]);
}
ret += '\n';
} else {
@@ -764,7 +775,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// add blocks
for (var i = 0; i < block.labels.length; i++) {
var label = block.labels[i];
- var content = getLabelLines(label, '', true);
+ var content = getLabelLines(label, true);
//printErr(func.ident + ' : ' + label.ident + ' : ' + content + '\n');
var last = label.lines[label.lines.length-1];
if (!last.signedIdent) {
@@ -810,9 +821,17 @@ function JSify(data, functionsOnly, givenFunctions) {
// Finalize function
if (LABEL_DEBUG && functionNameFilterTest(func.ident)) func.JS += " INDENT = INDENT.substr(0, INDENT.length-2);\n";
// Ensure a return in a function with a type that returns, even if it lacks a return (e.g., if it aborts())
- if (RELOOP && func.lines.length > 0 && func.returnType != 'void') {
- var returns = func.labels.filter(function(label) { return label.lines[label.lines.length-1].intertype == 'return' }).length;
- if (returns == 0) func.JS += INDENTATION + 'return ' + asmCoercion('0', func.returnType);
+ if (RELOOP && ASM_JS && func.lines.length > 0 && func.returnType != 'void') {
+ var lastCurly = func.JS.lastIndexOf('}');
+ var lastReturn = func.JS.lastIndexOf('return ');
+ if ((lastCurly < 0 && lastReturn < 0) || // no control flow, no return
+ (lastCurly >= 0 && lastReturn < lastCurly)) { // control flow, no return past last join
+ if (func.returnType in Runtime.FLOAT_TYPES) {
+ func.JS += ' return +0;\n';
+ } else {
+ func.JS += ' return 0;\n';
+ }
+ }
}
func.JS += '}\n';
@@ -898,6 +917,11 @@ function JSify(data, functionsOnly, givenFunctions) {
// Function lines
function valueHandler(item) {
+ if (item.vars) {
+ item.vars.forEach(function(v) {
+ addVariable(v[0], v[1]);
+ });
+ }
return item.ident;
}
function noopHandler(item) {
@@ -959,7 +983,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var parts = label.split('|');
var trueLabel = parts[1] || '';
var oldLabel = parts[2] || '';
- var labelSetting = oldLabel ? 'label = ' + getLabelId(oldLabel) + ';' +
+ var labelSetting = oldLabel ? 'label=' + getLabelId(oldLabel) + ';' +
(SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(oldLabel)) + ' */' : '') : ''; // TODO: optimize away the setting
if (label[1] == 'R') {
if (label[2] == 'N') { // BRNOL: break, no label setting
@@ -980,7 +1004,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
} else {
if (!labelIsVariable) label = getLabelId(label);
- return pre + 'label = ' + label + ';' + (SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(label)) + ' */' : '') + ' break;';
+ return pre + 'label=' + label + ';' + (SHOW_LABELS ? ' /* to: ' + getOriginalLabelId(cleanLabel(label)) + ' */' : '') + 'break;';
}
}
@@ -1002,14 +1026,14 @@ function JSify(data, functionsOnly, givenFunctions) {
var labelSets = phiSets[label];
// FIXME: Many of the |var |s here are not needed, but without them we get slowdowns with closure compiler. TODO: remove this workaround.
if (labelSets.length == 1) {
- return (ASM_JS ? '' : 'var ') + labelSets[0].ident + ' = ' + labelSets[0].valueJS + ';';
+ return (ASM_JS ? '' : 'var ') + labelSets[0].ident + '=' + labelSets[0].valueJS + ';';
}
// TODO: eliminate unneeded sets (to undefined etc.)
var deps = {}; // for each ident we will set, which others it depends on
- var valueJSes = {};
+ var map = {};
labelSets.forEach(function(labelSet) {
deps[labelSet.ident] = {};
- valueJSes[labelSet.ident] = labelSet.valueJS;
+ map[labelSet.ident] = labelSet;
});
labelSets.forEach(function(labelSet) {
walkInterdata(labelSet.value, function mark(item) {
@@ -1028,14 +1052,18 @@ function JSify(data, functionsOnly, givenFunctions) {
}
for (var i = 0; i < idents.length; i++) {
if (keys(deps[idents[i]]).length == 0) {
- post = 'var ' + idents[i] + ' = ' + valueJSes[idents[i]] + ';' + post;
+ post = idents[i] + '=' + map[idents[i]].valueJS + ';' + post;
+ if (!ASM_JS) post = 'var ' + post;
+ else addVariable(idents[i], map[idents[i]].value.type);
remove(idents[i]);
continue mainLoop;
}
}
// If we got here, we have circular dependencies, and must break at least one.
- pre += 'var ' + idents[0] + '$phi = ' + valueJSes[idents[0]] + ';';
- post += 'var ' + idents[0] + ' = ' + idents[0] + '$phi;';
+ pre += makeVarDef(idents[0]) + '$phi=' + map[idents[0]].valueJS + ';';
+ post += makeVarDef(idents[0]) + '=' + idents[0] + '$phi;';
+ addVariable(idents[0] + '$phi', map[idents[0]].value.type);
+ addVariable(idents[0], map[idents[0]].value.type);
remove(idents[0]);
}
return pre + post;
@@ -1062,10 +1090,10 @@ function JSify(data, functionsOnly, givenFunctions) {
var labelTrue = (item.labelTrueJS = getPhiSetsForLabel(phiSets, item.labelTrue)) + makeBranch(item.labelTrue, item.currLabelId);
var labelFalse = (item.labelFalseJS = getPhiSetsForLabel(phiSets, item.labelFalse)) + makeBranch(item.labelFalse, item.currLabelId);
if (labelTrue == ';' && labelFalse == ';') return ';';
- var head = 'if (' + condition + ') { ';
- var head2 = 'if (!(' + condition + ')) { ';
- var else_ = ' } else { ';
- var tail = ' }';
+ var head = 'if(' + condition + '){';
+ var head2 = 'if(!(' + condition + ')){';
+ var else_ = '}else{';
+ var tail = '}';
if (labelTrue == ';') {
return head2 + labelFalse + tail;
} else if (labelFalse == ';') {
@@ -1112,7 +1140,7 @@ function JSify(data, functionsOnly, givenFunctions) {
item.groupedLabels = [];
}
if (!useIfs) {
- ret += 'switch(' + signedIdent + ') {\n';
+ ret += 'switch(' + signedIdent + '){';
}
// process target labels, sorting them so output is consistently ordered
keys(targetLabels).sort().forEach(function(targetLabel) {
@@ -1125,17 +1153,17 @@ function JSify(data, functionsOnly, givenFunctions) {
if (useIfs) {
value = targetLabels[targetLabel].map(function(value) {
return makeComparison(signedIdent, '==', makeSignOp(value, item.type, 're'), item.type)
- }).join(' | ');
- ret += 'if (' + value + ') {\n';
+ }).join('|');
+ ret += 'if(' + value + '){';
} else {
value = targetLabels[targetLabel].map(function(value) {
return 'case ' + makeSignOp(value, item.type, 're') + ':';
- }).join(' ');
- ret += value + '{\n';
+ }).join('');
+ ret += value + '{';
}
var phiSet = getPhiSetsForLabel(phiSets, targetLabel);
- ret += INDENTATION + '' + phiSet + makeBranch(targetLabel, item.currLabelId || null) + '\n';
- ret += '}\n';
+ ret += INDENTATION + '' + phiSet + makeBranch(targetLabel, item.currLabelId || null);
+ ret += '}';
if (RELOOP) {
item.groupedLabels.push({
label: targetLabel,
@@ -1146,15 +1174,15 @@ function JSify(data, functionsOnly, givenFunctions) {
});
var phiSet = item.defaultLabelJS = getPhiSetsForLabel(phiSets, item.defaultLabel);
if (useIfs) {
- if (item.switchLabels.length > 0) ret += 'else {\n';
- ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '\n';
- if (item.switchLabels.length > 0) ret += '}\n';
+ if (item.switchLabels.length > 0) ret += 'else{';
+ ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '';
+ if (item.switchLabels.length > 0) ret += '}';
} else {
- ret += 'default: {\n';
- ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '\n';
- ret += '}\n';
+ ret += 'default:{';
+ ret += phiSet + makeBranch(item.defaultLabel, item.currLabelId) + '';
+ ret += '}';
- ret += '} break; \n'; // finish switch and break, to move control flow properly (breaks from makeBranch just broke out of the switch)
+ ret += '}break;'; // finish switch and break, to move control flow properly (breaks from makeBranch just broke out of the switch)
}
if (item.value) {
ret += ' ' + toNiceIdent(item.value);
@@ -1162,10 +1190,11 @@ function JSify(data, functionsOnly, givenFunctions) {
return ret;
}
function returnHandler(item) {
- var ret = RuntimeGenerator.stackExit(item.funcData.initialStack, item.funcData.otherStackAllocations) + ';\n';
+ var ret = RuntimeGenerator.stackExit(item.funcData.initialStack, item.funcData.otherStackAllocations);
+ if (ret.length > 0) ret += ';';
if (LABEL_DEBUG && functionNameFilterTest(item.funcData.ident)) {
- ret += "Module.print(INDENT + 'Exiting: " + item.funcData.ident + "');\n"
- + "INDENT = INDENT.substr(0, INDENT.length-2);\n";
+ ret += "Module.print(INDENT + 'Exiting: " + item.funcData.ident + "');"
+ + "INDENT = INDENT.substr(0, INDENT.length-2);";
}
ret += 'return';
var value = item.value ? finalizeLLVMParameter(item.value) : null;
@@ -1191,7 +1220,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// in an assignment
var disabled = DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST);
var phiSets = calcPhiSets(item);
- var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone, true);
+ var call_ = makeFunctionCall(item, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone, true);
var ret;
@@ -1217,11 +1246,16 @@ function JSify(data, functionsOnly, givenFunctions) {
ret = makeVarArgsCleanup(ret);
if (item.assignTo) {
- ret = 'var ' + item.assignTo + ' = ' + ret;
- if (USE_TYPED_ARRAYS == 2 && isIllegalType(item.type)) {
+ var illegal = USE_TYPED_ARRAYS == 2 && isIllegalType(item.type);
+ var assignTo = illegal ? item.assignTo + '$r' : item.assignTo;
+ ret = makeVarDef(assignTo) + '=' + ret;
+ if (ASM_JS) addVariable(assignTo, item.type);
+ if (illegal) {
var bits = getBits(item.type);
for (var i = 0; i < bits/32; i++) {
- ret += 'var ' + item.assignTo + '$' + i + ' = ' + (i == 0 ? item.assignTo : 'tempRet' + (i-1)) + ';'
+ var v = item.assignTo + '$' + i;
+ ret += makeVarDef(v) + '=' + (i == 0 ? assignTo : 'tempRet' + (i-1)) + ';'
+ if (ASM_JS) addVariable(v, 'i32');
}
}
item.assignTo = null;
@@ -1252,8 +1286,12 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
function landingpadHandler(item) {
+ if (ASM_JS) {
+ addVariable(item.assignTo + '$0', 'i32');
+ addVariable(item.assignTo + '$1', 'i32');
+ }
if (DISABLE_EXCEPTION_CATCHING && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST) && USE_TYPED_ARRAYS == 2) {
- ret = makeVarDef(item.assignTo) + '$0 = 0; ' + item.assignTo + '$1 = 0;';
+ ret = makeVarDef(item.assignTo) + '$0 = 0; ' + makeVarDef(item.assignTo) + '$1 = 0;';
item.assignTo = null;
if (VERBOSE) warnOnce('landingpad, but exceptions are disabled!');
return ret;
@@ -1261,7 +1299,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(',');
var ret = asmCoercion('___cxa_find_matching_catch(-1, -1' + (catchTypeArray.length > 0 ? ',' + catchTypeArray : '') +')', 'i32');
if (USE_TYPED_ARRAYS == 2) {
- ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + item.assignTo + '$1 = tempRet0;';
+ ret = makeVarDef(item.assignTo) + '$0 = ' + ret + '; ' + makeVarDef(item.assignTo) + '$1 = tempRet0;';
item.assignTo = null;
}
return ret;
@@ -1307,13 +1345,14 @@ function JSify(data, functionsOnly, givenFunctions) {
item.ident = 'tempValue';
ret += item.ident + ' = [' + makeEmptyStruct(item.type) + '], ';
}
- return ret + item.ident + '.f' + item.indexes[0][0].text + ' = ' + finalizeLLVMParameter(item.value) + ', ' + item.ident + ')';
+ return ret + item.ident + '.f' + item.indexes[0][0].text + '=' + finalizeLLVMParameter(item.value) + ', ' + item.ident + ')';
}
function indirectbrHandler(item) {
var phiSets = calcPhiSets(item);
- var js = 'var ibr = ' + finalizeLLVMParameter(item.value) + ';\n';
+ var js = makeVarDef('ibr') + '=' + finalizeLLVMParameter(item.value) + ';';
+ if (ASM_JS) addVariable('ibr', 'i32');
for (var targetLabel in phiSets) {
- js += 'if (' + makeComparison('ibr', '==', targetLabel, 'i32') + ') { ' + getPhiSetsForLabel(phiSets, targetLabel) + ' }\n';
+ js += 'if(' + makeComparison('ibr', '==', targetLabel, 'i32') + '){' + getPhiSetsForLabel(phiSets, targetLabel) + '}';
}
return js + makeBranch('ibr', item.currLabelId, true);
}
@@ -1349,7 +1388,9 @@ function JSify(data, functionsOnly, givenFunctions) {
return ret;
}
- function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn, invoke) {
+ function makeFunctionCall(item, params, funcData, type, forceByPointer, hasReturn, invoke) {
+ var ident = item.ident;
+
// We cannot compile assembly. See comment in intertyper.js:'Call'
assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
@@ -1368,7 +1409,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var callIdent = LibraryManager.getRootIdent(simpleIdent);
if (callIdent) {
simpleIdent = callIdent; // ident may not be in library, if all there is is ident__inline, but in this case it is
- if (callIdent.indexOf('.') < 0) {
+ if (callIdent.indexOf('Math_') !== 0) {
callIdent = '_' + callIdent; // Not Math.*, so add the normal prefix
}
} else {
@@ -1499,6 +1540,9 @@ function JSify(data, functionsOnly, givenFunctions) {
if (trueType !== returnType && !isIdenticallyImplemented(trueType, returnType)) {
if (VERBOSE) warnOnce('Fixing function call based on return type from signature, on ' + [callIdent, returnType, trueType]);
returnType = trueType;
+ if (trueType === 'void') {
+ item.assignTo = null;
+ }
}
}
}
@@ -1526,7 +1570,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (!ASM_JS || functionTableCall) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
}
- var ret = callIdent + '(' + args.join(', ') + ')';
+ var ret = callIdent + '(' + args.join(',') + ')';
if (ASM_JS) { // TODO: do only when needed (library functions and Math.*?) XXX && simpleIdent in Functions.libraryFunctions) {
ret = asmCoercion(ret, returnType);
if (simpleIdent == 'abort' && funcData.returnType != 'void') {
@@ -1537,7 +1581,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (ASM_JS && funcData.setjmpTable) {
// check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to a special label to handle it.
// otherwise, just return - the call to us must also have been an invoke, so the setjmp propagates that way
- ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) != 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = ' + SETJMP_LABEL + '; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n';
+ ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) != 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = ' + SETJMP_LABEL + '; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;';
}
return ret;
@@ -1558,7 +1602,7 @@ function JSify(data, functionsOnly, givenFunctions) {
function getelementptrHandler(item) { return finalizeLLVMFunctionCall(item) }
function callHandler(item) {
if (item.standalone && LibraryManager.isStubFunction(item.ident)) return ';';
- var ret = makeFunctionCall(item.ident, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : '');
+ var ret = makeFunctionCall(item, item.params, item.funcData, item.type, false, !!item.assignTo || !item.standalone) + (item.standalone ? ';' : '');
return makeVarArgsCleanup(ret);
}
@@ -1805,14 +1849,14 @@ function JSify(data, functionsOnly, givenFunctions) {
var shellParts = read(shellFile).split('{{BODY}}');
print(processMacros(preprocess(shellParts[1])));
// Print out some useful metadata
- if (EMIT_GENERATED_FUNCTIONS || PGO) {
+ if (RUNNING_JS_OPTS || PGO) {
var generatedFunctions = JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) {
return IGNORED_FUNCTIONS.indexOf(func.ident) < 0;
}));
if (PGO) {
print('PGOMonitor.allGenerated = ' + generatedFunctions + ';\nremoveRunDependency("pgo");\n');
}
- if (EMIT_GENERATED_FUNCTIONS) {
+ if (RUNNING_JS_OPTS) {
print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + generatedFunctions + '\n');
}
}
diff --git a/src/library.js b/src/library.js
index 5c2c858d..5e71b087 100644
--- a/src/library.js
+++ b/src/library.js
@@ -28,13 +28,7 @@ LibraryManager.library = {
// dirent.h
// ==========================================================================
- __dirent_struct_layout: Runtime.generateStructInfo([
- ['i32', 'd_ino'],
- ['i32', 'd_off'],
- ['i16', 'd_reclen'],
- ['i8', 'd_type'],
- ['b256', 'd_name']]),
- opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout', 'open'],
+ opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'open'],
opendir: function(dirname) {
// DIR *opendir(const char *dirname);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/opendir.html
@@ -90,7 +84,7 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/rewinddir.html
_seekdir(dirp, 0);
},
- readdir_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
+ readdir_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
readdir_r: function(dirp, entry, result) {
// int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/readdir_r.html
@@ -123,14 +117,14 @@ LibraryManager.library = {
FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link.
8; // DT_REG, regular file.
}
- {{{ makeSetValue('entry', '___dirent_struct_layout.d_ino', 'id', 'i32') }}}
- {{{ makeSetValue('entry', '___dirent_struct_layout.d_off', 'offset', 'i32') }}}
- {{{ makeSetValue('entry', '___dirent_struct_layout.d_reclen', 'name.length + 1', 'i32') }}}
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}}
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}}
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}}
for (var i = 0; i < name.length; i++) {
- {{{ makeSetValue('entry + ___dirent_struct_layout.d_name', 'i', 'name.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}}
}
- {{{ makeSetValue('entry + ___dirent_struct_layout.d_name', 'i', '0', 'i8') }}}
- {{{ makeSetValue('entry', '___dirent_struct_layout.d_type', 'type', 'i8') }}}
+ {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}}
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}}
{{{ makeSetValue('result', '0', 'entry', 'i8*') }}}
stream.position++;
return 0;
@@ -145,7 +139,7 @@ LibraryManager.library = {
return 0;
}
// TODO Is it supposed to be safe to execute multiple readdirs?
- if (!_readdir.entry) _readdir.entry = _malloc(___dirent_struct_layout.__size__);
+ if (!_readdir.entry) _readdir.entry = _malloc({{{ C_STRUCTS.dirent.__size__ }}});
if (!_readdir.result) _readdir.result = _malloc(4);
var err = _readdir_r(dirp, _readdir.entry, _readdir.result);
if (err) {
@@ -161,17 +155,14 @@ LibraryManager.library = {
// utime.h
// ==========================================================================
- __utimbuf_struct_layout: Runtime.generateStructInfo([
- ['i32', 'actime'],
- ['i32', 'modtime']]),
- utime__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__utimbuf_struct_layout'],
+ utime__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
utime: function(path, times) {
// int utime(const char *path, const struct utimbuf *times);
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/utime.h.html
var time;
if (times) {
// NOTE: We don't keep track of access timestamps.
- var offset = ___utimbuf_struct_layout.modtime;
+ var offset = {{{ C_STRUCTS.utimbuf.modtime }}};
time = {{{ makeGetValue('times', 'offset', 'i32') }}}
time *= 1000;
} else {
@@ -253,27 +244,7 @@ LibraryManager.library = {
// sys/stat.h
// ==========================================================================
- __stat_struct_layout: Runtime.generateStructInfo([
- ['i32', 'st_dev'],
- ['i32', '__st_dev_padding'],
- ['i32', '__st_ino_truncated'],
- ['i32', 'st_mode'],
- ['i32', 'st_nlink'],
- ['i32', 'st_uid'],
- ['i32', 'st_gid'],
- ['i32', 'st_rdev'],
- ['i32', '__st_rdev_padding'],
- ['i32', 'st_size'],
- ['i32', 'st_blksize'],
- ['i32', 'st_blocks'],
- ['i32', 'st_atim_secs'],
- ['i32', 'st_atim_nsecs'],
- ['i32', 'st_mtim_secs'],
- ['i32', 'st_mtim_nsecs'],
- ['i32', 'st_ctim_secs'],
- ['i32', 'st_ctim_nsecs'],
- ['i32', 'st_ino']]),
- stat__deps: ['$FS', '__stat_struct_layout'],
+ stat__deps: ['$FS'],
stat: function(path, buf, dontResolveLastLink) {
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
// int stat(const char *path, struct stat *buf);
@@ -282,25 +253,25 @@ LibraryManager.library = {
path = typeof path !== 'string' ? Pointer_stringify(path) : path;
try {
var stat = dontResolveLastLink ? FS.lstat(path) : FS.stat(path);
- {{{ makeSetValue('buf', '___stat_struct_layout.st_dev', 'stat.dev', 'i32') }}};
- {{{ makeSetValue('buf', '___stat_struct_layout.__st_dev_padding', '0', 'i32') }}};
- {{{ makeSetValue('buf', '___stat_struct_layout.__st_ino_truncated', 'stat.ino', 'i32') }}};
- {{{ makeSetValue('buf', '___stat_struct_layout.st_mode', 'stat.mode', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_nlink', 'stat.nlink', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_uid', 'stat.uid', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_gid', 'stat.gid', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_rdev', 'stat.rdev', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.__st_rdev_padding', '0', 'i32') }}};
- {{{ makeSetValue('buf', '___stat_struct_layout.st_size', 'stat.size', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_blksize', '4096', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_blocks', 'stat.blocks', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_atim_secs', 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_atim_nsecs', '0', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_mtim_secs', 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_mtim_nsecs', '0', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_ctim_secs', 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_ctim_nsecs', '0', 'i32') }}}
- {{{ makeSetValue('buf', '___stat_struct_layout.st_ino', 'stat.ino', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_dev, 'stat.dev', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.__st_dev_padding, '0', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.__st_ino_truncated, 'stat.ino', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.__st_rdev_padding, '0', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}}
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -436,43 +407,23 @@ LibraryManager.library = {
// sys/statvfs.h
// ==========================================================================
- __statvfs_struct_layout: Runtime.generateStructInfo([
- ['i32', 'f_bsize'],
- ['i32', 'f_frsize'],
- ['i32', 'f_blocks'],
- ['i32', 'f_bfree'],
- ['i32', 'f_bavail'],
- ['i32', 'f_files'],
- ['i32', 'f_ffree'],
- ['i32', 'f_favail'],
- ['i32', 'f_fsid'],
- ['i32', '__padding'],
- ['i32', 'f_flag'],
- ['i32', 'f_namemax'],
- ['i32', '__reserved_1'],
- ['i32', '__reserved_2'],
- ['i32', '__reserved_3'],
- ['i32', '__reserved_4'],
- ['i32', '__reserved_5'],
- ['i32', '__reserved_6']]),
- statvfs__deps: ['$FS', '__statvfs_struct_layout'],
+ statvfs__deps: ['$FS'],
statvfs: function(path, buf) {
// http://pubs.opengroup.org/onlinepubs/009695399/functions/statvfs.html
// int statvfs(const char *restrict path, struct statvfs *restrict buf);
- var offsets = ___statvfs_struct_layout;
// NOTE: None of the constants here are true. We're just returning safe and
// sane values.
- {{{ makeSetValue('buf', 'offsets.f_bsize', '4096', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_frsize', '4096', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_blocks', '1000000', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_bfree', '500000', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_bavail', '500000', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_files', 'FS.nextInode', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_ffree', '1000000', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_favail', '1000000', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_fsid', '42', 'i32') }}}
- {{{ makeSetValue('buf', 'offsets.f_flag', '2', 'i32') }}} // ST_NOSUID
- {{{ makeSetValue('buf', 'offsets.f_namemax', '255', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}} // ST_NOSUID
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}}
return 0;
},
fstatvfs__deps: ['statvfs'],
@@ -488,13 +439,7 @@ LibraryManager.library = {
// fcntl.h
// ==========================================================================
- __flock_struct_layout: Runtime.generateStructInfo([
- ['i16', 'l_type'],
- ['i16', 'l_whence'],
- ['i32', 'l_start'],
- ['i32', 'l_len'],
- ['i16', 'l_pid']]),
- open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
+ open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
open: function(path, oflag, varargs) {
// int open(const char *path, int oflag, ...);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
@@ -514,16 +459,19 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/009695399/functions/creat.html
return _open(path, {{{ cDefine('O_WRONLY') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_TRUNC') }}}, allocate([mode, 0, 0, 0], 'i32', ALLOC_STACK));
},
- mkstemp__deps: ['creat'],
- mkstemp: function(template) {
- if (!_mkstemp.counter) _mkstemp.counter = 0;
- var c = (_mkstemp.counter++).toString();
+ mktemp: function(template) {
+ if (!_mktemp.counter) _mktemp.counter = 0;
+ var c = (_mktemp.counter++).toString();
var rep = 'XXXXXX';
while (c.length < rep.length) c = '0' + c;
writeArrayToMemory(intArrayFromString(c), template + Pointer_stringify(template).indexOf(rep));
- return _creat(template, 0600);
+ return template;
+ },
+ mkstemp__deps: ['creat', 'mktemp'],
+ mkstemp: function(template) {
+ return _creat(_mktemp(template), 0600);
},
- fcntl__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__flock_struct_layout'],
+ fcntl__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
fcntl: function(fildes, cmd, varargs, dup2) {
// int fcntl(int fildes, int cmd, ...);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/fcntl.html
@@ -559,7 +507,7 @@ LibraryManager.library = {
case {{{ cDefine('F_GETLK') }}}:
case {{{ cDefine('F_GETLK64') }}}:
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
- var offset = ___flock_struct_layout.l_type;
+ var offset = {{{ C_STRUCTS.flock.l_type }}};
// We're always unlocked.
{{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}}
return 0;
@@ -621,20 +569,15 @@ LibraryManager.library = {
// ==========================================================================
__DEFAULT_POLLMASK: {{{ cDefine('POLLIN') }}} | {{{ cDefine('POLLOUT') }}},
- __pollfd_struct_layout: Runtime.generateStructInfo([
- ['i32', 'fd'],
- ['i16', 'events'],
- ['i16', 'revents']]),
- poll__deps: ['$FS', '__DEFAULT_POLLMASK', '__pollfd_struct_layout'],
+ poll__deps: ['$FS', '__DEFAULT_POLLMASK'],
poll: function(fds, nfds, timeout) {
// int poll(struct pollfd fds[], nfds_t nfds, int timeout);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/poll.html
- var offsets = ___pollfd_struct_layout;
var nonzero = 0;
for (var i = 0; i < nfds; i++) {
- var pollfd = fds + ___pollfd_struct_layout.__size__ * i;
- var fd = {{{ makeGetValue('pollfd', 'offsets.fd', 'i32') }}};
- var events = {{{ makeGetValue('pollfd', 'offsets.events', 'i16') }}};
+ var pollfd = fds + {{{ C_STRUCTS.pollfd.__size__ }}} * i;
+ var fd = {{{ makeGetValue('pollfd', C_STRUCTS.pollfd.fd, 'i32') }}};
+ var events = {{{ makeGetValue('pollfd', C_STRUCTS.pollfd.events, 'i16') }}};
var mask = {{{ cDefine('POLLNVAL') }}};
var stream = FS.getStream(fd);
if (stream) {
@@ -645,7 +588,7 @@ LibraryManager.library = {
}
mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}};
if (mask) nonzero++;
- {{{ makeSetValue('pollfd', 'offsets.revents', 'mask', 'i16') }}}
+ {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}}
}
return nonzero;
},
@@ -688,24 +631,13 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/000095399/functions/chdir.html
// NOTE: The path argument may be a string, to simplify fchdir().
if (typeof path !== 'string') path = Pointer_stringify(path);
- var lookup;
try {
- lookup = FS.lookupPath(path, { follow: true });
+ FS.chdir(path);
+ return 0;
} catch (e) {
FS.handleFSError(e);
return -1;
}
- if (!FS.isDir(lookup.node.mode)) {
- ___setErrNo(ERRNO_CODES.ENOTDIR);
- return -1;
- }
- var err = FS.nodePermissions(lookup.node, 'x');
- if (err) {
- ___setErrNo(err);
- return -1;
- }
- FS.currentPath = lookup.path;
- return 0;
},
chown__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
chown: function(path, owner, group, dontResolveLastLink) {
@@ -909,12 +841,14 @@ LibraryManager.library = {
if (size == 0) {
___setErrNo(ERRNO_CODES.EINVAL);
return 0;
- } else if (size < FS.currentPath.length + 1) {
+ }
+ var cwd = FS.cwd();
+ if (size < cwd.length + 1) {
___setErrNo(ERRNO_CODES.ERANGE);
return 0;
} else {
- for (var i = 0; i < FS.currentPath.length; i++) {
- {{{ makeSetValue('buf', 'i', 'FS.currentPath.charCodeAt(i)', 'i8') }}}
+ for (var i = 0; i < cwd.length; i++) {
+ {{{ makeSetValue('buf', 'i', 'cwd.charCodeAt(i)', 'i8') }}}
}
{{{ makeSetValue('buf', 'i', '0', 'i8') }}}
return buf;
@@ -1660,12 +1594,6 @@ LibraryManager.library = {
__scanString.whiteSpace[{{{ charCode('\v') }}}] = 1;
__scanString.whiteSpace[{{{ charCode('\f') }}}] = 1;
__scanString.whiteSpace[{{{ charCode('\r') }}}] = 1;
- __scanString.whiteSpace[' '] = 1;
- __scanString.whiteSpace['\t'] = 1;
- __scanString.whiteSpace['\n'] = 1;
- __scanString.whiteSpace['\v'] = 1;
- __scanString.whiteSpace['\f'] = 1;
- __scanString.whiteSpace['\r'] = 1;
}
// Supports %x, %4x, %d.%d, %lld, %s, %f, %lf.
// TODO: Support all format specifiers.
@@ -1903,7 +1831,7 @@ LibraryManager.library = {
break;
}
fields++;
- } else if (format[formatIndex] in __scanString.whiteSpace) {
+ } else if (format[formatIndex].charCodeAt(0) in __scanString.whiteSpace) {
next = get();
while (next in __scanString.whiteSpace) {
if (next <= 0) break mainLoop; // End of input.
@@ -1974,6 +1902,7 @@ LibraryManager.library = {
var flagLeftAlign = false;
var flagAlternative = false;
var flagZeroPad = false;
+ var flagPadSign = false;
flagsLoop: while (1) {
switch (next) {
case {{{ charCode('+') }}}:
@@ -1992,6 +1921,9 @@ LibraryManager.library = {
flagZeroPad = true;
break;
}
+ case {{{ charCode(' ') }}}:
+ flagPadSign = true;
+ break;
default:
break flagsLoop;
}
@@ -2158,14 +2090,20 @@ LibraryManager.library = {
}
// Add sign if needed
- if (flagAlwaysSigned) {
- if (currArg < 0) {
- prefix = '-' + prefix;
- } else {
+ if (currArg >= 0) {
+ if (flagAlwaysSigned) {
prefix = '+' + prefix;
+ } else if (flagPadSign) {
+ prefix = ' ' + prefix;
}
}
+ // Move sign to prefix so we zero-pad after the sign
+ if (argText.charAt(0) == '-') {
+ prefix = '-' + prefix;
+ argText = argText.substr(1);
+ }
+
// Add padding.
while (prefix.length + argText.length < width) {
if (flagLeftAlign) {
@@ -2248,8 +2186,12 @@ LibraryManager.library = {
if (next == {{{ charCode('E') }}}) argText = argText.toUpperCase();
// Add sign.
- if (flagAlwaysSigned && currArg >= 0) {
- argText = '+' + argText;
+ if (currArg >= 0) {
+ if (flagAlwaysSigned) {
+ argText = '+' + argText;
+ } else if (flagPadSign) {
+ argText = ' ' + argText;
+ }
}
}
@@ -2887,6 +2829,13 @@ LibraryManager.library = {
asprintf: function(s, format, varargs) {
return _sprintf(-s, format, varargs);
},
+ dprintf__deps: ['_formatString', 'write'],
+ dprintf: function(fd, format, varargs) {
+ var result = __formatString(format, varargs);
+ var stack = Runtime.stackSave();
+ var ret = _write(fd, allocate(result, 'i8', ALLOC_STACK), result.length);
+ Runtime.stackRestore(stack);
+ },
#if TARGET_X86
// va_arg is just like our varargs
@@ -2895,6 +2844,7 @@ LibraryManager.library = {
vprintf: 'printf',
vsprintf: 'sprintf',
vasprintf: 'asprintf',
+ vdprintf: 'dprintf',
vscanf: 'scanf',
vfscanf: 'fscanf',
vsscanf: 'sscanf',
@@ -2922,6 +2872,10 @@ LibraryManager.library = {
vasprintf: function(s, format, va_arg) {
return _asprintf(s, format, {{{ makeGetValue('va_arg', 0, '*') }}});
},
+ vdprintf__deps: ['dprintf'],
+ vdprintf: function (fd, format, va_arg) {
+ return _dprintf(fd, format, {{{ makeGetValue('va_arg', 0, '*') }}});
+ },
vscanf__deps: ['scanf'],
vscanf: function(format, va_arg) {
return _scanf(format, {{{ makeGetValue('va_arg', 0, '*') }}});
@@ -3054,8 +3008,8 @@ LibraryManager.library = {
return ret;
},
- abs: 'Math.abs',
- labs: 'Math.abs',
+ abs: 'Math_abs',
+ labs: 'Math_abs',
#if USE_TYPED_ARRAYS == 2
llabs__deps: [function() { Types.preciseI64MathUsed = 1 }],
llabs: function(lo, hi) {
@@ -3792,6 +3746,7 @@ LibraryManager.library = {
},
// We always assume ASCII locale.
strcoll: 'strcmp',
+ strcoll_l: 'strcmp',
strcasecmp__asm: true,
strcasecmp__sig: 'iii',
@@ -3847,8 +3802,8 @@ LibraryManager.library = {
p1 = p1|0; p2 = p2|0; num = num|0;
var i = 0, v1 = 0, v2 = 0;
while ((i|0) < (num|0)) {
- var v1 = {{{ makeGetValueAsm('p1', 'i', 'i8', true) }}};
- var v2 = {{{ makeGetValueAsm('p2', 'i', 'i8', true) }}};
+ v1 = {{{ makeGetValueAsm('p1', 'i', 'i8', true) }}};
+ v2 = {{{ makeGetValueAsm('p2', 'i', 'i8', true) }}};
if ((v1|0) != (v2|0)) return ((v1|0) > (v2|0) ? 1 : -1)|0;
i = (i+1)|0;
}
@@ -4058,6 +4013,7 @@ LibraryManager.library = {
}
},
_toupper: 'toupper',
+ toupper_l: 'toupper',
tolower__asm: true,
tolower__sig: 'ii',
@@ -4068,54 +4024,65 @@ LibraryManager.library = {
return (chr - {{{ charCode('A') }}} + {{{ charCode('a') }}})|0;
},
_tolower: 'tolower',
+ tolower_l: 'tolower',
// The following functions are defined as macros in glibc.
islower: function(chr) {
return chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}};
},
+ islower_l: 'islower',
isupper: function(chr) {
return chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}};
},
+ isupper_l: 'isupper',
isalpha: function(chr) {
return (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) ||
(chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}});
},
+ isalpha_l: 'isalpha',
isdigit: function(chr) {
return chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}};
},
- isdigit_l: 'isdigit', // no locale support yet
+ isdigit_l: 'isdigit',
isxdigit: function(chr) {
return (chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}) ||
(chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('f') }}}) ||
(chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('F') }}});
},
- isxdigit_l: 'isxdigit', // no locale support yet
+ isxdigit_l: 'isxdigit',
isalnum: function(chr) {
return (chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}) ||
(chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) ||
(chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}});
},
+ isalnum_l: 'isalnum',
ispunct: function(chr) {
return (chr >= {{{ charCode('!') }}} && chr <= {{{ charCode('/') }}}) ||
(chr >= {{{ charCode(':') }}} && chr <= {{{ charCode('@') }}}) ||
(chr >= {{{ charCode('[') }}} && chr <= {{{ charCode('`') }}}) ||
(chr >= {{{ charCode('{') }}} && chr <= {{{ charCode('~') }}});
},
+ ispunct_l: 'ispunct',
isspace: function(chr) {
return (chr == 32) || (chr >= 9 && chr <= 13);
},
+ isspace_l: 'isspace',
isblank: function(chr) {
return chr == {{{ charCode(' ') }}} || chr == {{{ charCode('\t') }}};
},
+ isblank_l: 'isblank',
iscntrl: function(chr) {
return (0 <= chr && chr <= 0x1F) || chr === 0x7F;
},
+ iscntrl_l: 'iscntrl',
isprint: function(chr) {
return 0x1F < chr && chr < 0x7F;
},
+ isprint_l: 'isprint',
isgraph: function(chr) {
return 0x20 < chr && chr < 0x7F;
},
+ isgraph_l: 'isgraph',
// Lookup tables for glibc ctype implementation.
__ctype_b_loc: function() {
// http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---ctype-b-loc.html
@@ -4216,7 +4183,7 @@ LibraryManager.library = {
llvm_va_end: function() {},
llvm_va_copy: function(ppdest, ppsrc) {
- // copy the list start
+ // copy the list start
{{{ makeCopyValues('ppdest', 'ppsrc', Runtime.QUANTUM_SIZE, 'null', null, 1) }}};
// copy the list's current offset (will be advanced with each call to va_arg)
@@ -4260,9 +4227,9 @@ LibraryManager.library = {
var ret = 0;
ret = {{{ makeGetValueAsm('ctlz_i8', 'x >>> 24', 'i8') }}};
if ((ret|0) < 8) return ret|0;
- var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 16)&0xff', 'i8') }}};
+ ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 16)&0xff', 'i8') }}};
if ((ret|0) < 8) return (ret + 8)|0;
- var ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 8)&0xff', 'i8') }}};
+ ret = {{{ makeGetValueAsm('ctlz_i8', '(x >> 8)&0xff', 'i8') }}};
if ((ret|0) < 8) return (ret + 16)|0;
return ({{{ makeGetValueAsm('ctlz_i8', 'x&0xff', 'i8') }}} + 24)|0;
},
@@ -4296,9 +4263,9 @@ LibraryManager.library = {
var ret = 0;
ret = {{{ makeGetValueAsm('cttz_i8', 'x & 0xff', 'i8') }}};
if ((ret|0) < 8) return ret|0;
- var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 8)&0xff', 'i8') }}};
+ ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 8)&0xff', 'i8') }}};
if ((ret|0) < 8) return (ret + 8)|0;
- var ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 16)&0xff', 'i8') }}};
+ ret = {{{ makeGetValueAsm('cttz_i8', '(x >> 16)&0xff', 'i8') }}};
if ((ret|0) < 8) return (ret + 16)|0;
return ({{{ makeGetValueAsm('cttz_i8', 'x >>> 24', 'i8') }}} + 24)|0;
},
@@ -4735,30 +4702,30 @@ LibraryManager.library = {
// math.h
// ==========================================================================
- cos: 'Math.cos',
- cosf: 'Math.cos',
- cosl: 'Math.cos',
- sin: 'Math.sin',
- sinf: 'Math.sin',
- sinl: 'Math.sin',
- tan: 'Math.tan',
- tanf: 'Math.tan',
- tanl: 'Math.tan',
- acos: 'Math.acos',
- acosf: 'Math.acos',
- acosl: 'Math.acos',
- asin: 'Math.asin',
- asinf: 'Math.asin',
- asinl: 'Math.asin',
- atan: 'Math.atan',
- atanf: 'Math.atan',
- atanl: 'Math.atan',
- atan2: 'Math.atan2',
- atan2f: 'Math.atan2',
- atan2l: 'Math.atan2',
- exp: 'Math.exp',
- expf: 'Math.exp',
- expl: 'Math.exp',
+ cos: 'Math_cos',
+ cosf: 'Math_cos',
+ cosl: 'Math_cos',
+ sin: 'Math_sin',
+ sinf: 'Math_sin',
+ sinl: 'Math_sin',
+ tan: 'Math_tan',
+ tanf: 'Math_tan',
+ tanl: 'Math_tan',
+ acos: 'Math_acos',
+ acosf: 'Math_acos',
+ acosl: 'Math_acos',
+ asin: 'Math_asin',
+ asinf: 'Math_asin',
+ asinl: 'Math_asin',
+ atan: 'Math_atan',
+ atanf: 'Math_atan',
+ atanl: 'Math_atan',
+ atan2: 'Math_atan2',
+ atan2f: 'Math_atan2',
+ atan2l: 'Math_atan2',
+ exp: 'Math_exp',
+ expf: 'Math_exp',
+ expl: 'Math_exp',
// The erf and erfc functions are inspired from
// http://www.digitalmars.com/archives/cplusplus/3634.html
@@ -4820,32 +4787,32 @@ LibraryManager.library = {
},
erff: 'erf',
erfl: 'erf',
- log: 'Math.log',
- logf: 'Math.log',
- logl: 'Math.log',
- sqrt: 'Math.sqrt',
- sqrtf: 'Math.sqrt',
- sqrtl: 'Math.sqrt',
- fabs: 'Math.abs',
- fabsf: 'Math.abs',
- fabsl: 'Math.abs',
- ceil: 'Math.ceil',
- ceilf: 'Math.ceil',
- ceill: 'Math.ceil',
- floor: 'Math.floor',
- floorf: 'Math.floor',
- floorl: 'Math.floor',
- pow: 'Math.pow',
- powf: 'Math.pow',
- powl: 'Math.pow',
- llvm_sqrt_f32: 'Math.sqrt',
- llvm_sqrt_f64: 'Math.sqrt',
- llvm_pow_f32: 'Math.pow',
- llvm_pow_f64: 'Math.pow',
- llvm_log_f32: 'Math.log',
- llvm_log_f64: 'Math.log',
- llvm_exp_f32: 'Math.exp',
- llvm_exp_f64: 'Math.exp',
+ log: 'Math_log',
+ logf: 'Math_log',
+ logl: 'Math_log',
+ sqrt: 'Math_sqrt',
+ sqrtf: 'Math_sqrt',
+ sqrtl: 'Math_sqrt',
+ fabs: 'Math_abs',
+ fabsf: 'Math_abs',
+ fabsl: 'Math_abs',
+ ceil: 'Math_ceil',
+ ceilf: 'Math_ceil',
+ ceill: 'Math_ceil',
+ floor: 'Math_floor',
+ floorf: 'Math_floor',
+ floorl: 'Math_floor',
+ pow: 'Math_pow',
+ powf: 'Math_pow',
+ powl: 'Math_pow',
+ llvm_sqrt_f32: 'Math_sqrt',
+ llvm_sqrt_f64: 'Math_sqrt',
+ llvm_pow_f32: 'Math_pow',
+ llvm_pow_f64: 'Math_pow',
+ llvm_log_f32: 'Math_log',
+ llvm_log_f64: 'Math_log',
+ llvm_exp_f32: 'Math_exp',
+ llvm_exp_f64: 'Math_exp',
ldexp: function(x, exp_) {
return x * Math.pow(2, exp_);
},
@@ -5068,17 +5035,11 @@ LibraryManager.library = {
{{{ makeSetValue('cosine', '0', 'cosineVal', 'float') }}};
},
- __div_t_struct_layout: Runtime.generateStructInfo([
- ['i32', 'quot'],
- ['i32', 'rem'],
- ]),
- div__deps: ['__div_t_struct_layout'],
div: function(divt, numer, denom) {
var quot = Math.floor(numer / denom);
var rem = numer - quot * denom;
- var offset = ___div_t_struct_layout.rem;
- {{{ makeSetValue('divt', '0', 'quot', 'i32') }}};
- {{{ makeSetValue('divt', 'offset', 'rem', 'i32') }}};
+ {{{ makeSetValue('divt', C_STRUCTS.div_t.quot, 'quot', 'i32') }}};
+ {{{ makeSetValue('divt', C_STRUCTS.div_t.rem, 'rem', 'i32') }}};
return divt;
},
@@ -5097,19 +5058,12 @@ LibraryManager.library = {
// sys/utsname.h
// ==========================================================================
- __utsname_struct_layout: Runtime.generateStructInfo([
- ['b65', 'sysname'],
- ['b65', 'nodename'],
- ['b65', 'release'],
- ['b65', 'version'],
- ['b65', 'machine'],
- ['b65', 'domainname']]),
- uname__deps: ['__utsname_struct_layout'],
uname: function(name) {
// int uname(struct utsname *name);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/uname.html
+ var layout = {{{ JSON.stringify(C_STRUCTS.utsname) }}};
function copyString(element, value) {
- var offset = ___utsname_struct_layout[element];
+ var offset = layout[element];
for (var i = 0; i < value.length; i++) {
{{{ makeSetValue('name', 'offset + i', 'value.charCodeAt(i)', 'i8') }}}
}
@@ -5405,62 +5359,48 @@ LibraryManager.library = {
return time1 - time0;
},
- __tm_struct_layout: Runtime.generateStructInfo([
- ['i32', 'tm_sec'],
- ['i32', 'tm_min'],
- ['i32', 'tm_hour'],
- ['i32', 'tm_mday'],
- ['i32', 'tm_mon'],
- ['i32', 'tm_year'],
- ['i32', 'tm_wday'],
- ['i32', 'tm_yday'],
- ['i32', 'tm_isdst'],
- ['i32', 'tm_gmtoff'],
- ['i8*', 'tm_zone']]),
// Statically allocated time struct.
- __tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)',
+ __tm_current: 'allocate({{{ C_STRUCTS.tm.__size__ }}}, "i8", ALLOC_STATIC)',
// Statically allocated timezone string. We only use GMT as a timezone.
__tm_timezone: 'allocate(intArrayFromString("GMT"), "i8", ALLOC_STATIC)',
// Statically allocated time strings.
- __tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)',
+ __tm_formatted: 'allocate({{{ C_STRUCTS.tm.__size__ }}}, "i8", ALLOC_STATIC)',
- mktime__deps: ['__tm_struct_layout', 'tzset'],
+ mktime__deps: ['tzset'],
mktime: function(tmPtr) {
_tzset();
- var offsets = ___tm_struct_layout;
- var year = {{{ makeGetValue('tmPtr', 'offsets.tm_year', 'i32') }}};
+ var year = {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}};
var timestamp = new Date(year >= 1900 ? year : year + 1900,
- {{{ makeGetValue('tmPtr', 'offsets.tm_mon', 'i32') }}},
- {{{ makeGetValue('tmPtr', 'offsets.tm_mday', 'i32') }}},
- {{{ makeGetValue('tmPtr', 'offsets.tm_hour', 'i32') }}},
- {{{ makeGetValue('tmPtr', 'offsets.tm_min', 'i32') }}},
- {{{ makeGetValue('tmPtr', 'offsets.tm_sec', 'i32') }}},
+ {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}},
+ {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'i32') }}},
+ {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'i32') }}},
+ {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}},
+ {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}},
0).getTime() / 1000;
- {{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'new Date(timestamp).getDay()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}}
var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
return timestamp;
},
timelocal: 'mktime',
- gmtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'gmtime_r'],
+ gmtime__deps: ['malloc', '__tm_current', 'gmtime_r'],
gmtime: function(time) {
return _gmtime_r(time, ___tm_current);
},
- gmtime_r__deps: ['__tm_struct_layout', '__tm_timezone'],
+ gmtime_r__deps: ['__tm_timezone'],
gmtime_r: function(time, tmPtr) {
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
- var offsets = ___tm_struct_layout;
- {{{ makeSetValue('tmPtr', 'offsets.tm_sec', 'date.getUTCSeconds()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_min', 'date.getUTCMinutes()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_hour', 'date.getUTCHours()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_mday', 'date.getUTCDate()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_mon', 'date.getUTCMonth()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_year', 'date.getUTCFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'date.getUTCDay()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_gmtoff', '0', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_isdst', '0', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}
var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC
start.setUTCDate(1);
start.setUTCMonth(0);
@@ -5469,8 +5409,8 @@ LibraryManager.library = {
start.setUTCSeconds(0);
start.setUTCMilliseconds(0);
var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezone', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}
return tmPtr;
},
@@ -5484,33 +5424,32 @@ LibraryManager.library = {
return ret;
},
- localtime__deps: ['malloc', '__tm_struct_layout', '__tm_current', 'localtime_r'],
+ localtime__deps: ['malloc', '__tm_current', 'localtime_r'],
localtime: function(time) {
return _localtime_r(time, ___tm_current);
},
- localtime_r__deps: ['__tm_struct_layout', '__tm_timezone', 'tzset'],
+ localtime_r__deps: ['__tm_timezone', 'tzset'],
localtime_r: function(time, tmPtr) {
_tzset();
- var offsets = ___tm_struct_layout;
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
- {{{ makeSetValue('tmPtr', 'offsets.tm_sec', 'date.getSeconds()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_min', 'date.getMinutes()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_hour', 'date.getHours()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_mday', 'date.getDate()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_mon', 'date.getMonth()', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_year', 'date.getFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_wday', 'date.getDay()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}
var start = new Date(date.getFullYear(), 0, 1);
var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_gmtoff', 'start.getTimezoneOffset() * 60', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}}
var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
- {{{ makeSetValue('tmPtr', 'offsets.tm_isdst', 'dst', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}}
- {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezone', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}
return tmPtr;
},
@@ -5621,21 +5560,21 @@ LibraryManager.library = {
return newDate;
},
- strftime__deps: ['__tm_struct_layout', '_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'],
+ strftime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'],
strftime: function(s, maxsize, format, tm) {
// size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html
var date = {
- tm_sec: {{{ makeGetValue('tm', '___tm_struct_layout.tm_sec', 'i32') }}},
- tm_min: {{{ makeGetValue('tm', '___tm_struct_layout.tm_min', 'i32') }}},
- tm_hour: {{{ makeGetValue('tm', '___tm_struct_layout.tm_hour', 'i32') }}},
- tm_mday: {{{ makeGetValue('tm', '___tm_struct_layout.tm_mday', 'i32') }}},
- tm_mon: {{{ makeGetValue('tm', '___tm_struct_layout.tm_mon', 'i32') }}},
- tm_year: {{{ makeGetValue('tm', '___tm_struct_layout.tm_year', 'i32') }}},
- tm_wday: {{{ makeGetValue('tm', '___tm_struct_layout.tm_wday', 'i32') }}},
- tm_yday: {{{ makeGetValue('tm', '___tm_struct_layout.tm_yday', 'i32') }}},
- tm_isdst: {{{ makeGetValue('tm', '___tm_struct_layout.tm_isdst', 'i32') }}}
+ tm_sec: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_sec, 'i32') }}},
+ tm_min: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_min, 'i32') }}},
+ tm_hour: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_hour, 'i32') }}},
+ tm_mday: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_mday, 'i32') }}},
+ tm_mon: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_mon, 'i32') }}},
+ tm_year: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_year, 'i32') }}},
+ tm_wday: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_wday, 'i32') }}},
+ tm_yday: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_yday, 'i32') }}},
+ tm_isdst: {{{ makeGetValue('tm', C_STRUCTS.tm.tm_isdst, 'i32') }}}
};
var pattern = Pointer_stringify(format);
@@ -5918,7 +5857,7 @@ LibraryManager.library = {
},
strftime_l: 'strftime', // no locale support yet
- strptime__deps: ['__tm_struct_layout', '_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'],
+ strptime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'],
strptime: function(buf, format, tm) {
// char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html
@@ -5996,12 +5935,12 @@ LibraryManager.library = {
return (typeof value !== 'number' || isNaN(value)) ? min : (value>=min ? (value<=max ? value: max): min);
};
return {
- year: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_year', 'i32', 0, 0, 1) }}} + 1900 , 1970, 9999),
- month: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_mon', 'i32', 0, 0, 1) }}}, 0, 11),
- day: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_mday', 'i32', 0, 0, 1) }}}, 1, 31),
- hour: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_hour', 'i32', 0, 0, 1) }}}, 0, 23),
- min: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_min', 'i32', 0, 0, 1) }}}, 0, 59),
- sec: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_sec', 'i32', 0, 0, 1) }}}, 0, 59)
+ year: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_year, 'i32', 0, 0, 1) }}} + 1900 , 1970, 9999),
+ month: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_mon, 'i32', 0, 0, 1) }}}, 0, 11),
+ day: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_mday, 'i32', 0, 0, 1) }}}, 1, 31),
+ hour: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_hour, 'i32', 0, 0, 1) }}}, 0, 23),
+ min: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_min, 'i32', 0, 0, 1) }}}, 0, 59),
+ sec: fixup({{{ makeGetValue('tm', C_STRUCTS.tm.tm_sec, 'i32', 0, 0, 1) }}}, 0, 59)
};
};
@@ -6141,15 +6080,15 @@ LibraryManager.library = {
*/
var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0);
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_sec', 'fullDate.getSeconds()', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_min', 'fullDate.getMinutes()', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_hour', 'fullDate.getHours()', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_mday', 'fullDate.getDate()', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_mon', 'fullDate.getMonth()', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_year', 'fullDate.getFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_wday', 'fullDate.getDay()', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_yday', '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_isdst', '0', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}
// we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F
// TODO: not sure that intArrayFromString handles all unicode characters correctly
@@ -6174,25 +6113,21 @@ LibraryManager.library = {
// sys/time.h
// ==========================================================================
- __timespec_struct_layout: Runtime.generateStructInfo([
- ['i32', 'tv_sec'],
- ['i32', 'tv_nsec']]),
- nanosleep__deps: ['usleep', '__timespec_struct_layout'],
+ nanosleep__deps: ['usleep'],
nanosleep: function(rqtp, rmtp) {
// int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
- var seconds = {{{ makeGetValue('rqtp', '___timespec_struct_layout.tv_sec', 'i32') }}};
- var nanoseconds = {{{ makeGetValue('rqtp', '___timespec_struct_layout.tv_nsec', 'i32') }}};
- {{{ makeSetValue('rmtp', '___timespec_struct_layout.tv_sec', '0', 'i32') }}}
- {{{ makeSetValue('rmtp', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}
+ var seconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_sec, 'i32') }}};
+ var nanoseconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
+ {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}}
+ {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}}
return _usleep((seconds * 1e6) + (nanoseconds / 1000));
},
// TODO: Implement these for real.
- clock_gettime__deps: ['__timespec_struct_layout'],
clock_gettime: function(clk_id, tp) {
// int clock_gettime(clockid_t clk_id, struct timespec *tp);
var now = Date.now();
- {{{ makeSetValue('tp', '___timespec_struct_layout.tv_sec', 'Math.floor(now/1000)', 'i32') }}}; // seconds
- {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '(now % 1000) * 1000 * 1000', 'i32') }}}; // nanoseconds (really milliseconds)
+ {{{ makeSetValue('tp', C_STRUCTS.timespec.tv_sec, 'Math.floor(now/1000)', 'i32') }}}; // seconds
+ {{{ makeSetValue('tp', C_STRUCTS.timespec.tv_nsec, '(now % 1000) * 1000 * 1000', 'i32') }}}; // nanoseconds (really milliseconds)
return 0;
},
clock_settime: function(clk_id, tp) {
@@ -6200,41 +6135,31 @@ LibraryManager.library = {
// Nothing.
return 0;
},
- clock_getres__deps: ['__timespec_struct_layout'],
clock_getres: function(clk_id, res) {
// int clock_getres(clockid_t clk_id, struct timespec *res);
- {{{ makeSetValue('res', '___timespec_struct_layout.tv_sec', '1', 'i32') }}}
- {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '1000 * 1000', 'i32') }}} // resolution is milliseconds
+ {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}}
+ {{{ makeSetValue('res', C_STRUCTS.timespec.tv_nsec, '1000 * 1000', 'i32') }}} // resolution is milliseconds
return 0;
},
// http://pubs.opengroup.org/onlinepubs/000095399/basedefs/sys/time.h.html
gettimeofday: function(ptr) {
- // %struct.timeval = type { i32, i32 }
- {{{ (LibraryManager.structs.gettimeofday = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] }), null) }}}
var now = Date.now();
- {{{ makeSetValue('ptr', LibraryManager.structs.gettimeofday[0], 'Math.floor(now/1000)', 'i32') }}}; // seconds
- {{{ makeSetValue('ptr', LibraryManager.structs.gettimeofday[1], 'Math.floor((now-1000*Math.floor(now/1000))*1000)', 'i32') }}}; // microseconds
+ {{{ makeSetValue('ptr', C_STRUCTS.timeval.tv_sec, 'Math.floor(now/1000)', 'i32') }}}; // seconds
+ {{{ makeSetValue('ptr', C_STRUCTS.timeval.tv_usec, 'Math.floor((now-1000*Math.floor(now/1000))*1000)', 'i32') }}}; // microseconds
return 0;
},
// ==========================================================================
// sys/timeb.h
// ==========================================================================
-
- __timeb_struct_layout: Runtime.generateStructInfo([
- ['i32', 'time'],
- ['i16', 'millitm'],
- ['i16', 'timezone'],
- ['i16', 'dstflag']
- ]),
- ftime__deps: ['__timeb_struct_layout'],
+
ftime: function(p) {
var millis = Date.now();
- {{{ makeSetValue('p', '___timeb_struct_layout.time', 'Math.floor(millis/1000)', 'i32') }}};
- {{{ makeSetValue('p', '___timeb_struct_layout.millitm', 'millis % 1000', 'i16') }}};
- {{{ makeSetValue('p', '___timeb_struct_layout.timezone', '0', 'i16') }}}; // TODO
- {{{ makeSetValue('p', '___timeb_struct_layout.dstflag', '0', 'i16') }}}; // TODO
+ {{{ makeSetValue('p', C_STRUCTS.timeb.time, 'Math.floor(millis/1000)', 'i32') }}};
+ {{{ makeSetValue('p', C_STRUCTS.timeb.millitm, 'millis % 1000', 'i16') }}};
+ {{{ makeSetValue('p', C_STRUCTS.timeb.timezone, '0', 'i16') }}}; // TODO
+ {{{ makeSetValue('p', C_STRUCTS.timeb.dstflag, '0', 'i16') }}}; // TODO
return 0;
},
@@ -6242,18 +6167,13 @@ LibraryManager.library = {
// sys/times.h
// ==========================================================================
- __tms_struct_layout: Runtime.generateStructInfo([
- ['i32', 'tms_utime'],
- ['i32', 'tms_stime'],
- ['i32', 'tms_cutime'],
- ['i32', 'tms_cstime']]),
- times__deps: ['__tms_struct_layout', 'memset'],
+ times__deps: ['memset'],
times: function(buffer) {
// clock_t times(struct tms *buffer);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/times.html
// NOTE: This is fake, since we can't calculate real CPU time usage in JS.
if (buffer !== 0) {
- _memset(buffer, 0, ___tms_struct_layout.__size__);
+ _memset(buffer, 0, {{{ C_STRUCTS.tms.__size__ }}});
}
return 0;
},
@@ -6435,11 +6355,15 @@ LibraryManager.library = {
// locale.h
// ==========================================================================
+ newlocale__deps: ['malloc'],
newlocale: function(mask, locale, base) {
- return 0;
+ return _malloc({{{ QUANTUM_SIZE}}});
},
- freelocale: function(locale) {},
+ freelocale__deps: ['free'],
+ freelocale: function(locale) {
+ _free(locale);
+ },
uselocale: function(locale) {
return 0;
@@ -6911,14 +6835,10 @@ LibraryManager.library = {
// ==========================================================================
// TODO: Implement for real.
- __rlimit_struct_layout: Runtime.generateStructInfo([
- ['i32', 'rlim_cur'],
- ['i32', 'rlim_max']]),
- getrlimit__deps: ['__rlimit_struct_layout'],
getrlimit: function(resource, rlp) {
// int getrlimit(int resource, struct rlimit *rlp);
- {{{ makeSetValue('rlp', '___rlimit_struct_layout.rlim_cur', '-1', 'i32') }}} // RLIM_INFINITY
- {{{ makeSetValue('rlp', '___rlimit_struct_layout.rlim_max', '-1', 'i32') }}} // RLIM_INFINITY
+ {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_cur, '-1', 'i32') }}} // RLIM_INFINITY
+ {{{ makeSetValue('rlp', C_STRUCTS.rlimit.rlim_max, '-1', 'i32') }}} // RLIM_INFINITY
return 0;
},
setrlimit: function(resource, rlp) {
@@ -6928,33 +6848,12 @@ LibraryManager.library = {
__01getrlimit64_: 'getrlimit',
// TODO: Implement for real. We just do time used, and no useful data
- __rusage_struct_layout: Runtime.generateStructInfo([
- ['i64', 'ru_utime'],
- ['i64', 'ru_stime'],
- ['i32', 'ru_maxrss'],
- ['i32', 'ru_ixrss'],
- ['i32', 'ru_idrss'],
- ['i32', 'ru_isrss'],
- ['i32', 'ru_minflt'],
- ['i32', 'ru_majflt'],
- ['i32', 'ru_nswap'],
- ['i32', 'ru_inblock'],
- ['i32', 'ru_oublock'],
- ['i32', 'ru_msgsnd'],
- ['i32', 'ru_msgrcv'],
- ['i32', 'ru_nsignals'],
- ['i32', 'ru_nvcsw'],
- ['i32', 'ru_nivcsw']]),
- getrusage__deps: ['__rusage_struct_layout'],
getrusage: function(resource, rlp) {
- // %struct.timeval = type { i32, i32 }
- var timeval = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] });
-
// int getrusage(int resource, struct rusage *rlp);
- {{{ makeSetValue('rlp', '___rusage_struct_layout.ru_utime+timeval[0]', '1', 'i32') }}}
- {{{ makeSetValue('rlp', '___rusage_struct_layout.ru_utime+timeval[1]', '2', 'i32') }}}
- {{{ makeSetValue('rlp', '___rusage_struct_layout.ru_stime+timeval[0]', '3', 'i32') }}}
- {{{ makeSetValue('rlp', '___rusage_struct_layout.ru_stime+timeval[1]', '4', 'i32') }}}
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}}
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}}
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}}
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}}
return 0;
},
@@ -7462,25 +7361,6 @@ LibraryManager.library = {
},
// note: lots of leaking here!
- __hostent_struct_layout: Runtime.generateStructInfo([
- ['i8*', 'h_name'],
- ['i8**', 'h_aliases'],
- ['i32', 'h_addrtype'],
- ['i32', 'h_length'],
- ['i8**', 'h_addr_list'],
- ]),
-
- _addrinfo_layout: Runtime.generateStructInfo([
- ['i32', 'ai_flags'],
- ['i32', 'ai_family'],
- ['i32', 'ai_socktype'],
- ['i32', 'ai_protocol'],
- ['i32', 'ai_addrlen'],
- ['*', 'ai_addr'],
- ['*', 'ai_canonname'],
- ['*', 'ai_next']
- ]),
-
gethostbyaddr__deps: ['$DNS', 'gethostbyname', '_inet_ntop4_raw'],
gethostbyaddr: function (addr, addrlen, type) {
if (type !== {{{ cDefine('AF_INET') }}}) {
@@ -7497,40 +7377,40 @@ LibraryManager.library = {
return _gethostbyname(hostp);
},
- gethostbyname__deps: ['$DNS', '__hostent_struct_layout', '_inet_pton4_raw'],
+ gethostbyname__deps: ['$DNS', '_inet_pton4_raw'],
gethostbyname: function(name) {
name = Pointer_stringify(name);
// generate hostent
- var ret = _malloc(___hostent_struct_layout.__size__); // XXX possibly leaked, as are others here
+ var ret = _malloc({{{ C_STRUCTS.hostent.__size__ }}}); // XXX possibly leaked, as are others here
var nameBuf = _malloc(name.length+1);
writeStringToMemory(name, nameBuf);
- {{{ makeSetValue('ret', '___hostent_struct_layout.h_name', 'nameBuf', 'i8*') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}}
var aliasesBuf = _malloc(4);
{{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}}
- {{{ makeSetValue('ret', '___hostent_struct_layout.h_aliases', 'aliasesBuf', 'i8**') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}}
var afinet = {{{ cDefine('AF_INET') }}};
- {{{ makeSetValue('ret', '___hostent_struct_layout.h_addrtype', 'afinet', 'i32') }}}
- {{{ makeSetValue('ret', '___hostent_struct_layout.h_length', '4', 'i32') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}}
var addrListBuf = _malloc(12);
{{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}}
{{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}}
{{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}}
- {{{ makeSetValue('ret', '___hostent_struct_layout.h_addr_list', 'addrListBuf', 'i8**') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}}
return ret;
},
gethostbyname_r__deps: ['gethostbyname'],
gethostbyname_r: function(name, ret, buf, buflen, out, err) {
var data = _gethostbyname(name);
- _memcpy(ret, data, ___hostent_struct_layout.__size__);
+ _memcpy(ret, data, {{{ C_STRUCTS.hostent.__size__ }}});
_free(data);
{{{ makeSetValue('err', '0', '0', 'i32') }}};
{{{ makeSetValue('out', '0', 'ret', '*') }}};
return 0;
},
- getaddrinfo__deps: ['$Sockets', '$DNS', '_addrinfo_layout', '_inet_pton4_raw', '_inet_ntop4_raw', '_inet_pton6_raw', '_inet_ntop6_raw', '_write_sockaddr', 'htonl'],
+ getaddrinfo__deps: ['$Sockets', '$DNS', '_inet_pton4_raw', '_inet_ntop4_raw', '_inet_pton6_raw', '_inet_ntop6_raw', '_write_sockaddr', 'htonl'],
getaddrinfo: function(node, service, hint, out) {
var addrs = [];
var canon = null;
@@ -7547,8 +7427,8 @@ LibraryManager.library = {
var res;
salen = family === {{{ cDefine('AF_INET6') }}} ?
- Sockets.sockaddr_in6_layout.__size__ :
- Sockets.sockaddr_in_layout.__size__;
+ {{{ C_STRUCTS.sockaddr_in6.__size__ }}} :
+ {{{ C_STRUCTS.sockaddr_in.__size__ }}};
addr = family === {{{ cDefine('AF_INET6') }}} ?
__inet_ntop6_raw(addr) :
__inet_ntop4_raw(addr);
@@ -7556,28 +7436,28 @@ LibraryManager.library = {
res = __write_sockaddr(sa, family, addr, port);
assert(!res.errno);
- ai = _malloc(__addrinfo_layout.__size__);
- {{{ makeSetValue('ai', '__addrinfo_layout.ai_family', 'family', 'i32') }}};
- {{{ makeSetValue('ai', '__addrinfo_layout.ai_socktype', 'type', 'i32') }}};
- {{{ makeSetValue('ai', '__addrinfo_layout.ai_protocol', 'proto', 'i32') }}};
+ ai = _malloc({{{ C_STRUCTS.addrinfo.__size__ }}});
+ {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_family, 'family', 'i32') }}};
+ {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_socktype, 'type', 'i32') }}};
+ {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_protocol, 'proto', 'i32') }}};
if (canon) {
- {{{ makeSetValue('ai', '__addrinfo_layout.ai_canonname', 'canon', 'i32') }}};
+ {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_canonname, 'canon', 'i32') }}};
}
- {{{ makeSetValue('ai', '__addrinfo_layout.ai_addr', 'sa', '*') }}};
+ {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addr, 'sa', '*') }}};
if (family === {{{ cDefine('AF_INET6') }}}) {
- {{{ makeSetValue('ai', '__addrinfo_layout.ai_addrlen', 'Sockets.sockaddr_in6_layout.__size__', 'i32') }}};
+ {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in6.__size__, 'i32') }}};
} else {
- {{{ makeSetValue('ai', '__addrinfo_layout.ai_addrlen', 'Sockets.sockaddr_in_layout.__size__', 'i32') }}};
+ {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in.__size__, 'i32') }}};
}
return ai;
}
if (hint) {
- flags = {{{ makeGetValue('hint', '__addrinfo_layout.ai_flags', 'i32') }}};
- family = {{{ makeGetValue('hint', '__addrinfo_layout.ai_family', 'i32') }}};
- type = {{{ makeGetValue('hint', '__addrinfo_layout.ai_socktype', 'i32') }}};
- proto = {{{ makeGetValue('hint', '__addrinfo_layout.ai_protocol', 'i32') }}};
+ flags = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}};
+ family = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_family, 'i32') }}};
+ type = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_socktype, 'i32') }}};
+ proto = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_protocol, 'i32') }}};
}
if (type && !proto) {
proto = type === {{{ cDefine('SOCK_DGRAM') }}} ? {{{ cDefine('IPPROTO_UDP') }}} : {{{ cDefine('IPPROTO_TCP') }}};
@@ -7593,7 +7473,7 @@ LibraryManager.library = {
{{{ cDefine('AI_NUMERICSERV') }}}|{{{ cDefine('AI_V4MAPPED') }}}|{{{ cDefine('AI_ALL') }}}|{{{ cDefine('AI_ADDRCONFIG') }}})) {
return {{{ cDefine('EAI_BADFLAGS') }}};
}
- if (({{{ makeGetValue('hint', '__addrinfo_layout.ai_flags', 'i32') }}} & {{{ cDefine('AI_CANONNAME') }}}) && !node) {
+ if (({{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}} & {{{ cDefine('AI_CANONNAME') }}}) && !node) {
return {{{ cDefine('EAI_BADFLAGS') }}};
}
if (flags & {{{ cDefine('AI_ADDRCONFIG') }}}) {
@@ -7689,14 +7569,14 @@ LibraryManager.library = {
return 0;
},
- freeaddrinfo__deps: ['$Sockets', '_addrinfo_layout'],
+ freeaddrinfo__deps: ['$Sockets'],
freeaddrinfo: function(ai) {
- var sa = {{{ makeGetValue('ai', '__addrinfo_layout.ai_addr', '*') }}};
+ var sa = {{{ makeGetValue('ai', C_STRUCTS.addrinfo.ai_addr, '*') }}};
_free(sa);
_free(ai);
},
- getnameinfo__deps: ['$Sockets', '$DNS', '__hostent_struct_layout', '_read_sockaddr'],
+ getnameinfo__deps: ['$Sockets', '$DNS', '_read_sockaddr'],
getnameinfo: function (sa, salen, node, nodelen, serv, servlen, flags) {
var info = __read_sockaddr(sa, salen);
if (info.errno) {
@@ -7763,33 +7643,7 @@ LibraryManager.library = {
localAddr: 0xfe00000a, // Local address is always 10.0.0.254
addrPool: [ 0x0200000a, 0x0300000a, 0x0400000a, 0x0500000a,
0x0600000a, 0x0700000a, 0x0800000a, 0x0900000a, 0x0a00000a,
- 0x0b00000a, 0x0c00000a, 0x0d00000a, 0x0e00000a], /* 0x0100000a is reserved */
- sockaddr_in_layout: Runtime.generateStructInfo([
- ['i16', 'sin_family'],
- ['i16', 'sin_port'],
- ['i32', 'sin_addr'],
- ['b8', 'sin_zero'],
- ]),
- sockaddr_in6_layout: Runtime.generateStructInfo([
- ['i16', 'sin6_family'],
- ['i16', 'sin6_port'],
- ['i32', 'sin6_flowinfo'],
- ['b16', 'sin6_addr'],
- ['i32', 'sin6_scope_id']
- ]),
- msghdr_layout: Runtime.generateStructInfo([
- ['*', 'msg_name'],
- ['i32', 'msg_namelen'],
- ['*', 'msg_iov'],
- ['i32', 'msg_iovlen'],
- ['*', 'msg_control'],
- ['i32', 'msg_controllen'],
- ['i32', 'msg_flags'],
- ]),
- iovec_layout: Runtime.generateStructInfo([
- ['i8*', 'iov_base'],
- ['i32', 'iov_len']
- ])
+ 0x0b00000a, 0x0c00000a, 0x0d00000a, 0x0e00000a] /* 0x0100000a is reserved */
},
#if SOCKET_WEBRTC
@@ -7953,8 +7807,8 @@ LibraryManager.library = {
var info = FS.getStream(fd);
if (!info) return -1;
if (addr) {
- info.port = _ntohs(getValue(addr + Sockets.sockaddr_in_layout.sin_port, 'i16'));
- // info.addr = getValue(addr + Sockets.sockaddr_in_layout.sin_addr, 'i32');
+ info.port = _ntohs(getValue(addr + {{{ C_STRUCTS.sockaddr_in.sin_port }}}, 'i16'));
+ // info.addr = getValue(addr + {{{ C_STRUCTS.sockaddr_in.sin_addr.s_addr }}}, 'i32');
}
if (!info.port) {
info.port = _mkport();
@@ -7978,10 +7832,10 @@ LibraryManager.library = {
_bind(fd);
}
- var name = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_name', '*') }}};
+ var name = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_name, '*') }}};
assert(name, 'sendmsg on non-connected socket, and no name/address in the message');
- var port = _ntohs(getValue(name + Sockets.sockaddr_in_layout.sin_port, 'i16'));
- var addr = getValue(name + Sockets.sockaddr_in_layout.sin_addr, 'i32');
+ var port = _ntohs(getValue(name + {{{ C_STRUCTS.sockaddr_in.sin_port }}}, 'i16'));
+ var addr = getValue(name + {{{ C_STRUCTS.sockaddr_in.sin_addr.s_addr }}}, 'i32');
var connection = Sockets.connections[addr];
// var host = __inet_ntop4_raw(addr);
@@ -7990,8 +7844,8 @@ LibraryManager.library = {
return -1;
}
- var iov = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iov', 'i8*') }}};
- var num = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iovlen', 'i32') }}};
+ var iov = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_iov, 'i8*') }}};
+ var num = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}};
#if SOCKET_DEBUG
Module.print('sendmsg vecs: ' + num);
#endif
@@ -8052,13 +7906,13 @@ LibraryManager.library = {
Module.print('recvmsg bytes: ' + bytes + ' | ' + Array.prototype.slice.call(buffer));
#endif
// write source
- var name = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_name', '*') }}};
- {{{ makeSetValue('name', 'Sockets.sockaddr_in_layout.sin_addr', 'addr', 'i32') }}};
- {{{ makeSetValue('name', 'Sockets.sockaddr_in_layout.sin_port', '_htons(header[0])', 'i16') }}};
+ var name = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_name, '*') }}};
+ {{{ makeSetValue('name', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'addr', 'i32') }}};
+ {{{ makeSetValue('name', C_STRUCTS.sockaddr_in.sin_port, '_htons(header[0])', 'i16') }}};
// write data
var ret = bytes;
- var iov = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iov', 'i8*') }}};
- var num = {{{ makeGetValue('msg', 'Sockets.msghdr_layout.msg_iovlen', 'i32') }}};
+ var iov = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_iov, 'i8*') }}};
+ var num = {{{ makeGetValue('msg', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}};
var bufferPos = 0;
for (var i = 0; i < num && bytes > 0; i++) {
var currNum = {{{ makeGetValue('iov', '8*i + 4', 'i32') }}};
@@ -8112,9 +7966,9 @@ LibraryManager.library = {
var info = FS.getStream(fd);
if (!info) return -1;
if (addr) {
- setValue(addr + Sockets.sockaddr_in_layout.sin_addr, info.addr, 'i32');
- setValue(addr + Sockets.sockaddr_in_layout.sin_port, info.port, 'i32');
- setValue(addrlen, Sockets.sockaddr_in_layout.__size__, 'i32');
+ setValue(addr + {{{ C_STRUCTS.sockaddr_in.sin_addr.s_addr }}}, info.addr, 'i32');
+ setValue(addr + {{{ C_STRUCTS.sockaddr_in.sin_port }}}, info.port, 'i32');
+ setValue(addrlen, {{{ C_STRUCTS.sockaddr_in.__size__ }}}, 'i32');
}
return fd;
},
@@ -8180,27 +8034,27 @@ LibraryManager.library = {
_read_sockaddr__deps: ['$Sockets', '_inet_ntop4_raw', '_inet_ntop6_raw'],
_read_sockaddr: function (sa, salen) {
// family / port offsets are common to both sockaddr_in and sockaddr_in6
- var family = {{{ makeGetValue('sa', 'Sockets.sockaddr_in_layout.sin_family', 'i16') }}};
- var port = _ntohs({{{ makeGetValue('sa', 'Sockets.sockaddr_in_layout.sin_port', 'i16') }}});
+ var family = {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_family, 'i16') }}};
+ var port = _ntohs({{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_port, 'i16') }}});
var addr;
switch (family) {
case {{{ cDefine('AF_INET') }}}:
- if (salen !== Sockets.sockaddr_in_layout.__size__) {
+ if (salen !== {{{ C_STRUCTS.sockaddr_in.__size__ }}}) {
return { errno: ERRNO_CODES.EINVAL };
}
- addr = {{{ makeGetValue('sa', 'Sockets.sockaddr_in_layout.sin_addr', 'i32') }}};
+ addr = {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'i32') }}};
addr = __inet_ntop4_raw(addr);
break;
case {{{ cDefine('AF_INET6') }}}:
- if (salen !== Sockets.sockaddr_in6_layout.__size__) {
+ if (salen !== {{{ C_STRUCTS.sockaddr_in6.__size__ }}}) {
return { errno: ERRNO_CODES.EINVAL };
}
addr = [
- {{{ makeGetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_addr+0', 'i32') }}},
- {{{ makeGetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_addr+4', 'i32') }}},
- {{{ makeGetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_addr+8', 'i32') }}},
- {{{ makeGetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_addr+12', 'i32') }}}
+ {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+0, 'i32') }}},
+ {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+4, 'i32') }}},
+ {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+8, 'i32') }}},
+ {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+12, 'i32') }}}
];
addr = __inet_ntop6_raw(addr);
break;
@@ -8215,18 +8069,18 @@ LibraryManager.library = {
switch (family) {
case {{{ cDefine('AF_INET') }}}:
addr = __inet_pton4_raw(addr);
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in_layout.sin_family', 'family', 'i16') }}};
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in_layout.sin_addr', 'addr', 'i32') }}};
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in_layout.sin_port', '_htons(port)', 'i16') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_family, 'family', 'i16') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'addr', 'i32') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_port, '_htons(port)', 'i16') }}};
break;
case {{{ cDefine('AF_INET6') }}}:
addr = __inet_pton6_raw(addr);
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_family', 'family', 'i32') }}};
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_addr+0', 'addr[0]', 'i32') }}};
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_addr+4', 'addr[1]', 'i32') }}};
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_addr+8', 'addr[2]', 'i32') }}};
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_addr+12', 'addr[3]', 'i32') }}};
- {{{ makeSetValue('sa', 'Sockets.sockaddr_in6_layout.sin6_port', '_htons(port)', 'i16') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_family, 'family', 'i32') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+0, 'addr[0]', 'i32') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+4, 'addr[1]', 'i32') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+8, 'addr[2]', 'i32') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+12, 'addr[3]', 'i32') }}};
+ {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_port, '_htons(port)', 'i16') }}};
break;
default:
return { errno: ERRNO_CODES.EAFNOSUPPORT };
@@ -8472,14 +8326,14 @@ LibraryManager.library = {
return -1;
}
- var iov = {{{ makeGetValue('message', 'Sockets.msghdr_layout.msg_iov', '*') }}};
- var num = {{{ makeGetValue('message', 'Sockets.msghdr_layout.msg_iovlen', 'i32') }}};
+ var iov = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iov, '*') }}};
+ var num = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}};
// read the address and port to send to
var addr;
var port;
- var name = {{{ makeGetValue('message', 'Sockets.msghdr_layout.msg_name', '*') }}};
- var namelen = {{{ makeGetValue('message', 'Sockets.msghdr_layout.msg_namelen', 'i32') }}};
+ var name = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_name, '*') }}};
+ var namelen = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_namelen, 'i32') }}};
if (name) {
var info = __read_sockaddr(name, namelen);
if (info.errno) {
@@ -8493,13 +8347,13 @@ LibraryManager.library = {
// concatenate scatter-gather arrays into one message buffer
var total = 0;
for (var i = 0; i < num; i++) {
- total += {{{ makeGetValue('iov', '(Sockets.iovec_layout.__size__ * i) + Sockets.iovec_layout.iov_len', 'i32') }}};
+ total += {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}};
}
var view = new Uint8Array(total);
var offset = 0;
for (var i = 0; i < num; i++) {
- var iovbase = {{{ makeGetValue('iov', '(Sockets.iovec_layout.__size__ * i) + Sockets.iovec_layout.iov_base', 'i8*') }}};
- var iovlen = {{{ makeGetValue('iov', '(Sockets.iovec_layout.__size__ * i) + Sockets.iovec_layout.iov_len', 'i32') }}};
+ var iovbase = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_base, 'i8*') }}};
+ var iovlen = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}};
for (var j = 0; j < iovlen; j++) {
view[offset++] = {{{ makeGetValue('iovbase', 'j', 'i8') }}};
}
@@ -8522,13 +8376,13 @@ LibraryManager.library = {
return -1;
}
- var iov = {{{ makeGetValue('message', 'Sockets.msghdr_layout.msg_iov', 'i8*') }}};
- var num = {{{ makeGetValue('message', 'Sockets.msghdr_layout.msg_iovlen', 'i32') }}};
+ var iov = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iov, 'i8*') }}};
+ var num = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}};
// get the total amount of data we can read across all arrays
var total = 0;
for (var i = 0; i < num; i++) {
- total += {{{ makeGetValue('iov', '(Sockets.iovec_layout.__size__ * i) + Sockets.iovec_layout.iov_len', 'i32') }}};
+ total += {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}};
}
// try to read total data
@@ -8554,7 +8408,7 @@ LibraryManager.library = {
// Requests that the function block until the full amount of data requested can be returned. The function may return a smaller amount of data if a signal is caught, if the connection is terminated, if MSG_PEEK was specified, or if an error is pending for the socket.
// write the source address out
- var name = {{{ makeGetValue('message', 'Sockets.msghdr_layout.msg_name', '*') }}};
+ var name = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_name, '*') }}};
if (name) {
var res = __write_sockaddr(name, sock.family, DNS.lookup_name(msg.addr), msg.port);
assert(!res.errno);
@@ -8564,8 +8418,8 @@ LibraryManager.library = {
var bytesRemaining = msg.buffer.byteLength;
for (var i = 0; bytesRemaining > 0 && i < num; i++) {
- var iovbase = {{{ makeGetValue('iov', '(Sockets.iovec_layout.__size__ * i) + Sockets.iovec_layout.iov_base', 'i8*') }}};
- var iovlen = {{{ makeGetValue('iov', '(Sockets.iovec_layout.__size__ * i) + Sockets.iovec_layout.iov_len', 'i32') }}};
+ var iovbase = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_base, 'i8*') }}};
+ var iovlen = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}};
if (!iovlen) {
continue;
}
@@ -8759,6 +8613,15 @@ LibraryManager.library = {
Runtime.stackAlloc(-4*i); // free up the stack space we know is ok to free
},
+ emscripten_asm_const: function(code) {
+ // code is a constant string on the heap, so we can cache these
+ if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+ var func = Runtime.asmConstCache[code];
+ if (func) return func();
+ func = Runtime.asmConstCache[code] = eval('(function(){ ' + Pointer_stringify(code) + ' })'); // new Function does not allow upvars in node
+ return func();
+ },
+
//============================
// i64 math
//============================
@@ -8854,7 +8717,7 @@ function autoAddDeps(object, name) {
}
// Add aborting stubs for various libc stuff needed by libc++
-['pthread_cond_signal', 'pthread_equal', 'wcstol', 'wcstoll', 'wcstoul', 'wcstoull', 'wcstof', 'wcstod', 'wcstold', 'swprintf', 'pthread_join', 'pthread_detach', 'strcoll_l', 'strxfrm_l', 'wcscoll_l', 'toupper_l', 'tolower_l', 'iswspace_l', 'iswprint_l', 'iswcntrl_l', 'iswupper_l', 'iswlower_l', 'iswalpha_l', 'iswdigit_l', 'iswpunct_l', 'iswxdigit_l', 'iswblank_l', 'wcsxfrm_l', 'towupper_l', 'towlower_l', 'catgets', 'catopen', 'catclose'].forEach(function(aborter) {
+['pthread_cond_signal', 'pthread_equal', 'wcstol', 'wcstoll', 'wcstoul', 'wcstoull', 'wcstof', 'wcstod', 'wcstold', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose', 'fputwc', '__lockfile', '__unlockfile'].forEach(function(aborter) {
LibraryManager.library[aborter] = function() { throw 'TODO: ' + aborter };
});
diff --git a/src/library_fs.js b/src/library_fs.js
index 84a5245b..dc5c20f8 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -1,5 +1,5 @@
mergeInto(LibraryManager.library, {
- $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$VFS', '$PATH', '$TTY', '$MEMFS', 'stdin', 'stdout', 'stderr', 'fflush'],
+ $FS__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo', '$VFS', '$PATH', '$TTY', '$MEMFS', '$IDBFS', '$NODEFS', 'stdin', 'stdout', 'stderr', 'fflush'],
$FS__postset: 'FS.staticInit();' +
'__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' +
'__ATMAIN__.push({ func: function() { FS.ignorePermissions = false } });' +
@@ -14,6 +14,7 @@ mergeInto(LibraryManager.library, {
'Module["FS_createDevice"] = FS.createDevice;',
$FS: {
root: null,
+ mounts: [],
devices: [null],
streams: [null],
nextInode: 1,
@@ -50,11 +51,8 @@ mergeInto(LibraryManager.library, {
//
// paths
//
- cwd: function() {
- return FS.currentPath;
- },
lookupPath: function(path, opts) {
- path = PATH.resolve(FS.currentPath, path);
+ path = PATH.resolve(FS.cwd(), path);
opts = opts || { recurse_count: 0 };
if (opts.recurse_count > 8) { // max recursive lookup of 8
@@ -122,6 +120,11 @@ mergeInto(LibraryManager.library, {
//
hashName: function(parentid, name) {
var hash = 0;
+
+#if CASE_INSENSITIVE_FS
+ name = name.toLowerCase();
+#endif
+
for (var i = 0; i < name.length; i++) {
hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
}
@@ -153,8 +156,15 @@ mergeInto(LibraryManager.library, {
throw new FS.ErrnoError(err);
}
var hash = FS.hashName(parent.id, name);
+#if CASE_INSENSITIVE_FS
+ name = name.toLowerCase();
+#endif
for (var node = FS.nameTable[hash]; node; node = node.name_next) {
- if (node.parent.id === parent.id && node.name === name) {
+ var nodeName = node.name;
+#if CASE_INSENSITIVE_FS
+ nodeName = nodeName.toLowerCase();
+#endif
+ if (node.parent.id === parent.id && nodeName === name) {
return node;
}
}
@@ -309,7 +319,7 @@ mergeInto(LibraryManager.library, {
if (!FS.isDir(node.mode)) {
return ERRNO_CODES.ENOTDIR;
}
- if (FS.isRoot(node) || FS.getPath(node) === FS.currentPath) {
+ if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
return ERRNO_CODES.EBUSY;
}
} else {
@@ -422,17 +432,45 @@ mergeInto(LibraryManager.library, {
//
// core
//
+ syncfs: function(populate, callback) {
+ if (typeof(populate) === 'function') {
+ callback = populate;
+ populate = false;
+ }
+
+ var completed = 0;
+ var total = FS.mounts.length;
+ var done = function(err) {
+ if (err) {
+ return callback(err);
+ }
+ if (++completed >= total) {
+ callback(null);
+ }
+ };
+
+ // sync all mounts
+ for (var i = 0; i < FS.mounts.length; i++) {
+ var mount = FS.mounts[i];
+ if (!mount.type.syncfs) {
+ done(null);
+ continue;
+ }
+ mount.type.syncfs(mount, populate, done);
+ }
+ },
mount: function(type, opts, mountpoint) {
+ var lookup;
+ if (mountpoint) {
+ lookup = FS.lookupPath(mountpoint, { follow: false });
+ mountpoint = lookup.path; // use the absolute path
+ }
var mount = {
type: type,
opts: opts,
mountpoint: mountpoint,
root: null
};
- var lookup;
- if (mountpoint) {
- lookup = FS.lookupPath(mountpoint, { follow: false });
- }
// create a root node for the fs
var root = type.mount(mount);
root.mount = mount;
@@ -446,6 +484,8 @@ mergeInto(LibraryManager.library, {
FS.root = mount.root;
}
}
+ // add to our cached list of mounts
+ FS.mounts.push(mount);
return root;
},
lookup: function(parent, name) {
@@ -759,7 +799,6 @@ mergeInto(LibraryManager.library, {
follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}})
});
node = lookup.node;
- path = lookup.path;
} catch (e) {
// ignore
}
@@ -791,10 +830,13 @@ mergeInto(LibraryManager.library, {
if ((flags & {{{ cDefine('O_TRUNC')}}})) {
FS.truncate(node, 0);
}
+ // we've already handled these, don't pass down to the underlying vfs
+ flags &= ~({{{ cDefine('O_EXCL') }}} | {{{ cDefine('O_TRUNC') }}});
+
// register the stream with the filesystem
var stream = FS.createStream({
- path: path,
node: node,
+ path: FS.getPath(node), // we want the absolute path to the node
flags: flags,
seekable: true,
position: 0,
@@ -959,8 +1001,21 @@ mergeInto(LibraryManager.library, {
//
// module-level FS code
- // TODO move to pre/postamble
//
+ cwd: function() {
+ return FS.currentPath;
+ },
+ chdir: function(path) {
+ var lookup = FS.lookupPath(path, { follow: true });
+ if (!FS.isDir(lookup.node.mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);
+ }
+ var err = FS.nodePermissions(lookup.node, 'x');
+ if (err) {
+ throw new FS.ErrnoError(err);
+ }
+ FS.currentPath = lookup.path;
+ },
createDefaultDirectories: function() {
FS.mkdir('/tmp');
},
diff --git a/src/library_gl.js b/src/library_gl.js
index 16ea5531..83e68777 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -217,6 +217,23 @@ var LibraryGL = {
throw 'Invalid format (' + format + ')';
}
break;
+ case 0x1403 /* GL_UNSIGNED_SHORT */:
+ if (format == 0x1902 /* GL_DEPTH_COMPONENT */) {
+ sizePerPixel = 2;
+ } else {
+ throw 'Invalid format (' + format + ')';
+ }
+ break;
+ case 0x1405 /* GL_UNSIGNED_INT */:
+ if (format == 0x1902 /* GL_DEPTH_COMPONENT */) {
+ sizePerPixel = 4;
+ } else {
+ throw 'Invalid format (' + format + ')';
+ }
+ break;
+ case 0x84FA /* UNSIGNED_INT_24_8_WEBGL */:
+ sizePerPixel = 4;
+ break;
case 0x8363 /* GL_UNSIGNED_SHORT_5_6_5 */:
case 0x8033 /* GL_UNSIGNED_SHORT_4_4_4_4 */:
case 0x8034 /* GL_UNSIGNED_SHORT_5_5_5_1 */:
@@ -244,6 +261,8 @@ var LibraryGL = {
pixels = {{{ makeHEAPView('U8', 'pixels', 'pixels+bytes') }}};
} else if (type == 0x1406 /* GL_FLOAT */) {
pixels = {{{ makeHEAPView('F32', 'pixels', 'pixels+bytes') }}};
+ } else if (type == 0x1405 /* GL_UNSIGNED_INT */ || type == 0x84FA /* UNSIGNED_INT_24_8_WEBGL */) {
+ pixels = {{{ makeHEAPView('U32', 'pixels', 'pixels+bytes') }}};
} else {
pixels = {{{ makeHEAPView('U16', 'pixels', 'pixels+bytes') }}};
}
@@ -291,6 +310,9 @@ var LibraryGL = {
Module.ctx.bufferSubData(Module.ctx.ARRAY_BUFFER,
0,
HEAPU8.subarray(cb.ptr, cb.ptr + size));
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(cb.size, cb.type, cb.stride, 0);
+#endif
Module.ctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0);
}
},
@@ -302,6 +324,56 @@ var LibraryGL = {
},
#endif
+#if GL_ASSERTIONS
+ validateGLObjectID: function(objectHandleArray, objectID, callerFunctionName, objectReadableType) {
+ if (objectID != 0) {
+ if (objectHandleArray[objectID] === null) {
+ console.error(callerFunctionName + ' called with an already deleted ' + objectReadableType + ' ID ' + objectID + '!');
+ } else if (!objectHandleArray[objectID]) {
+ console.error(callerFunctionName + ' called with an invalid ' + objectReadableType + ' ID ' + objectID + '!');
+ }
+ }
+ },
+ // Validates that user obeys GL spec #6.4: http://www.khronos.org/registry/webgl/specs/latest/1.0/#6.4
+ validateVertexAttribPointer: function(dimension, dataType, stride, offset) {
+ var sizeBytes = 1;
+ switch(dataType) {
+ case 0x1400 /* GL_BYTE */:
+ case 0x1401 /* GL_UNSIGNED_BYTE */:
+ sizeBytes = 1;
+ break;
+ case 0x1402 /* GL_SHORT */:
+ case 0x1403 /* GL_UNSIGNED_SHORT */:
+ sizeBytes = 2;
+ break;
+ case 0x1404 /* GL_INT */:
+ case 0x1405 /* GL_UNSIGNED_INT */:
+ case 0x1406 /* GL_FLOAT */:
+ sizeBytes = 4;
+ break;
+ case 0x140A /* GL_DOUBLE */:
+ sizeBytes = 8;
+ break;
+ default:
+ console.error('Invalid vertex attribute data type GLenum ' + dataType + ' passed to GL function!');
+ }
+ if (dimension == 0x80E1 /* GL_BGRA */) {
+ console.error('WebGL does not support size=GL_BGRA in a call to glVertexAttribPointer! Please use size=4 and type=GL_UNSIGNED_BYTE instead!');
+ } else if (dimension < 1 || dimension > 4) {
+ console.error('Invalid dimension='+dimension+' in call to glVertexAttribPointer, must be 1,2,3 or 4.');
+ }
+ if (stride < 0 || stride > 255) {
+ console.error('Invalid stride='+stride+' in call to glVertexAttribPointer. Note that maximum supported stride in WebGL is 255!');
+ }
+ if (offset % sizeBytes != 0) {
+ console.error('GL spec section 6.4 error: vertex attribute data offset of ' + offset + ' bytes should have been a multiple of the data type size that was used: GLenum ' + dataType + ' has size of ' + sizeBytes + ' bytes!');
+ }
+ if (stride % sizeBytes != 0) {
+ console.error('GL spec section 6.4 error: vertex attribute data stride of ' + stride + ' bytes should have been a multiple of the data type size that was used: GLenum ' + dataType + ' has size of ' + sizeBytes + ' bytes!');
+ }
+ },
+#endif
+
initExtensions: function() {
if (GL.initExtensions.done) return;
GL.initExtensions.done = true;
@@ -334,6 +406,10 @@ var LibraryGL = {
GL.elementIndexUintExt = Module.ctx.getExtension('OES_element_index_uint');
GL.standardDerivativesExt = Module.ctx.getExtension('OES_standard_derivatives');
+
+ GL.depthTextureExt = Module.ctx.getExtension("WEBGL_depth_texture") ||
+ Module.ctx.getExtension("MOZ_WEBGL_depth_texture") ||
+ Module.ctx.getExtension("WEBKIT_WEBGL_depth_texture");
}
},
@@ -588,6 +664,9 @@ var LibraryGL = {
glBindTexture__sig: 'vii',
glBindTexture: function(target, texture) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.textures, texture, 'glBindTexture', 'texture');
+#endif
Module.ctx.bindTexture(target, texture ? GL.textures[texture] : null);
},
@@ -710,6 +789,9 @@ var LibraryGL = {
glBindRenderbuffer__sig: 'vii',
glBindRenderbuffer: function(target, renderbuffer) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glBindRenderbuffer', 'renderbuffer');
+#endif
Module.ctx.bindRenderbuffer(target, renderbuffer ? GL.renderbuffers[renderbuffer] : null);
},
@@ -727,6 +809,9 @@ var LibraryGL = {
glGetUniformfv__sig: 'viii',
glGetUniformfv: function(program, location, params) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetUniformfv', 'program');
+#endif
var data = Module.ctx.getUniform(GL.programs[program], GL.uniforms[location]);
if (typeof data == 'number') {
{{{ makeSetValue('params', '0', 'data', 'float') }}};
@@ -739,6 +824,9 @@ var LibraryGL = {
glGetUniformiv__sig: 'viii',
glGetUniformiv: function(program, location, params) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetUniformiv', 'program');
+#endif
var data = Module.ctx.getUniform(GL.programs[program], GL.uniforms[location]);
if (typeof data == 'number' || typeof data == 'boolean') {
{{{ makeSetValue('params', '0', 'data', 'i32') }}};
@@ -751,6 +839,9 @@ var LibraryGL = {
glGetUniformLocation__sig: 'iii',
glGetUniformLocation: function(program, name) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetUniformLocation', 'program');
+#endif
name = Pointer_stringify(name);
var ptable = GL.uniformTable[program];
if (!ptable) ptable = GL.uniformTable[program] = {};
@@ -810,6 +901,9 @@ var LibraryGL = {
glGetActiveUniform__sig: 'viiiiiii',
glGetActiveUniform: function(program, index, bufSize, length, size, type, name) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniform', 'program');
+#endif
program = GL.programs[program];
var info = Module.ctx.getActiveUniform(program, index);
@@ -1018,6 +1112,9 @@ var LibraryGL = {
glBindBuffer__sig: 'vii',
glBindBuffer: function(target, buffer) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.buffers, buffer, 'glBindBuffer', 'buffer');
+#endif
var bufferObj = buffer ? GL.buffers[buffer] : null;
if (target == Module.ctx.ARRAY_BUFFER) {
@@ -1062,6 +1159,9 @@ var LibraryGL = {
glGetActiveAttrib__sig: 'viiiiiii',
glGetActiveAttrib: function(program, index, bufSize, length, size, type, name) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetActiveAttrib', 'program');
+#endif
program = GL.programs[program];
var info = Module.ctx.getActiveAttrib(program, index);
@@ -1094,6 +1194,9 @@ var LibraryGL = {
glGetAttachedShaders__sig: 'viiii',
glGetAttachedShaders: function(program, maxCount, count, shaders) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetAttachedShaders', 'program');
+#endif
var result = Module.ctx.getAttachedShaders(GL.programs[program]);
var len = result.length;
if (len > maxCount) {
@@ -1109,12 +1212,18 @@ var LibraryGL = {
glShaderSource__sig: 'viiii',
glShaderSource: function(shader, count, string, length) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glShaderSource', 'shader');
+#endif
var source = GL.getSource(shader, count, string, length);
Module.ctx.shaderSource(GL.shaders[shader], source);
},
glGetShaderSource__sig: 'viiii',
glGetShaderSource: function(shader, bufSize, length, source) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderSource', 'shader');
+#endif
var result = Module.ctx.getShaderSource(GL.shaders[shader]);
result = result.slice(0, Math.max(0, bufSize - 1));
writeStringToMemory(result, source);
@@ -1125,11 +1234,17 @@ var LibraryGL = {
glCompileShader__sig: 'vi',
glCompileShader: function(shader) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glCompileShader', 'shader');
+#endif
Module.ctx.compileShader(GL.shaders[shader]);
},
glGetShaderInfoLog__sig: 'viiii',
glGetShaderInfoLog: function(shader, maxLength, length, infoLog) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderInfoLog', 'shader');
+#endif
var log = Module.ctx.getShaderInfoLog(GL.shaders[shader]);
// Work around a bug in Chromium which causes getShaderInfoLog to return null
if (!log) {
@@ -1144,6 +1259,9 @@ var LibraryGL = {
glGetShaderiv__sig: 'viii',
glGetShaderiv : function(shader, pname, p) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderiv', 'shader');
+#endif
if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
{{{ makeSetValue('p', '0', 'Module.ctx.getShaderInfoLog(GL.shaders[shader]).length + 1', 'i32') }}};
} else {
@@ -1153,6 +1271,9 @@ var LibraryGL = {
glGetProgramiv__sig: 'viii',
glGetProgramiv : function(program, pname, p) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetProgramiv', 'program');
+#endif
if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH
{{{ makeSetValue('p', '0', 'Module.ctx.getProgramInfoLog(GL.programs[program]).length + 1', 'i32') }}};
} else {
@@ -1187,12 +1308,20 @@ var LibraryGL = {
glAttachShader__sig: 'vii',
glAttachShader: function(program, shader) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glAttachShader', 'program');
+ GL.validateGLObjectID(GL.shaders, shader, 'glAttachShader', 'shader');
+#endif
Module.ctx.attachShader(GL.programs[program],
GL.shaders[shader]);
},
glDetachShader__sig: 'vii',
glDetachShader: function(program, shader) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glDetachShader', 'program');
+ GL.validateGLObjectID(GL.shaders, shader, 'glDetachShader', 'shader');
+#endif
Module.ctx.detachShader(GL.programs[program],
GL.shaders[shader]);
},
@@ -1206,12 +1335,18 @@ var LibraryGL = {
glLinkProgram__sig: 'vi',
glLinkProgram: function(program) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glLinkProgram', 'program');
+#endif
Module.ctx.linkProgram(GL.programs[program]);
GL.uniformTable[program] = {}; // uniforms no longer keep the same names after linking
},
glGetProgramInfoLog__sig: 'viiii',
glGetProgramInfoLog: function(program, maxLength, length, infoLog) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glGetProgramInfoLog', 'program');
+#endif
var log = Module.ctx.getProgramInfoLog(GL.programs[program]);
// Work around a bug in Chromium which causes getProgramInfoLog to return null
if (!log) {
@@ -1226,11 +1361,17 @@ var LibraryGL = {
glUseProgram__sig: 'vi',
glUseProgram: function(program) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glUseProgram', 'program');
+#endif
Module.ctx.useProgram(program ? GL.programs[program] : null);
},
glValidateProgram__sig: 'vi',
glValidateProgram: function(program) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glValidateProgram', 'program');
+#endif
Module.ctx.validateProgram(GL.programs[program]);
},
@@ -1243,12 +1384,18 @@ var LibraryGL = {
glBindAttribLocation__sig: 'viii',
glBindAttribLocation: function(program, index, name) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.programs, program, 'glBindAttribLocation', 'program');
+#endif
name = Pointer_stringify(name);
Module.ctx.bindAttribLocation(GL.programs[program], index, name);
},
glBindFramebuffer__sig: 'vii',
glBindFramebuffer: function(target, framebuffer) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.framebuffers, framebuffer, 'glBindFramebuffer', 'framebuffer');
+#endif
Module.ctx.bindFramebuffer(target, framebuffer ? GL.framebuffers[framebuffer] : null);
},
@@ -1276,12 +1423,18 @@ var LibraryGL = {
glFramebufferRenderbuffer__sig: 'viiii',
glFramebufferRenderbuffer: function(target, attachment, renderbuffertarget, renderbuffer) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glFramebufferRenderbuffer', 'renderbuffer');
+#endif
Module.ctx.framebufferRenderbuffer(target, attachment, renderbuffertarget,
GL.renderbuffers[renderbuffer]);
},
glFramebufferTexture2D__sig: 'viiiii',
glFramebufferTexture2D: function(target, attachment, textarget, texture, level) {
+#if GL_ASSERTIONS
+ GL.validateGLObjectID(GL.textures, texture, 'glFramebufferTexture2D', 'texture');
+#endif
Module.ctx.framebufferTexture2D(target, attachment, textarget,
GL.textures[texture], level);
},
@@ -3161,6 +3314,9 @@ var LibraryGL = {
var clientAttributes = GL.immediate.clientAttributes;
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(positionSize, positionType, GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset);
+#endif
Module.ctx.vertexAttribPointer(this.positionLocation, positionSize, positionType, false,
GL.immediate.stride, clientAttributes[GL.immediate.VERTEX].offset);
Module.ctx.enableVertexAttribArray(this.positionLocation);
@@ -3173,6 +3329,9 @@ var LibraryGL = {
if (attribLoc === undefined || attribLoc < 0) continue;
if (texUnitID < textureSizes.length && textureSizes[texUnitID]) {
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(textureSizes[texUnitID], textureTypes[texUnitID], GL.immediate.stride, GL.immediate.clientAttributes[GL.immediate.TEXTURE0 + texUnitID].offset);
+#endif
Module.ctx.vertexAttribPointer(attribLoc, textureSizes[texUnitID], textureTypes[texUnitID], false,
GL.immediate.stride, GL.immediate.clientAttributes[GL.immediate.TEXTURE0 + texUnitID].offset);
Module.ctx.enableVertexAttribArray(attribLoc);
@@ -3189,6 +3348,9 @@ var LibraryGL = {
}
}
if (colorSize) {
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(colorSize, colorType, GL.immediate.stride, clientAttributes[GL.immediate.COLOR].offset);
+#endif
Module.ctx.vertexAttribPointer(this.colorLocation, colorSize, colorType, true,
GL.immediate.stride, clientAttributes[GL.immediate.COLOR].offset);
Module.ctx.enableVertexAttribArray(this.colorLocation);
@@ -3197,6 +3359,9 @@ var LibraryGL = {
Module.ctx.vertexAttrib4fv(this.colorLocation, GL.immediate.clientColor);
}
if (this.hasNormal) {
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(normalSize, normalType, GL.immediate.stride, clientAttributes[GL.immediate.NORMAL].offset);
+#endif
Module.ctx.vertexAttribPointer(this.normalLocation, normalSize, normalType, true,
GL.immediate.stride, clientAttributes[GL.immediate.NORMAL].offset);
Module.ctx.enableVertexAttribArray(this.normalLocation);
@@ -4176,6 +4341,9 @@ var LibraryGL = {
}
cb.clientside = false;
#endif
+#if GL_ASSERTIONS
+ GL.validateVertexAttribPointer(size, type, stride, ptr);
+#endif
Module.ctx.vertexAttribPointer(index, size, type, normalized, stride, ptr);
},
diff --git a/src/library_idbfs.js b/src/library_idbfs.js
new file mode 100644
index 00000000..9031bad8
--- /dev/null
+++ b/src/library_idbfs.js
@@ -0,0 +1,216 @@
+mergeInto(LibraryManager.library, {
+ $IDBFS__deps: ['$FS', '$MEMFS', '$PATH'],
+ $IDBFS: {
+ dbs: {},
+ indexedDB: function() {
+ return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+ },
+ DB_VERSION: 20,
+ DB_STORE_NAME: 'FILE_DATA',
+ // reuse all of the core MEMFS functionality
+ mount: function(mount) {
+ return MEMFS.mount.apply(null, arguments);
+ },
+ // the only custom function IDBFS implements is to handle
+ // synchronizing the wrapped MEMFS with a backing IDB instance
+ syncfs: function(mount, populate, callback) {
+ IDBFS.getLocalSet(mount, function(err, local) {
+ if (err) return callback(err);
+
+ IDBFS.getRemoteSet(mount, function(err, remote) {
+ if (err) return callback(err);
+
+ var src = populate ? remote : local;
+ var dst = populate ? local : remote;
+
+ IDBFS.reconcile(src, dst, callback);
+ });
+ });
+ },
+ reconcile: function(src, dst, callback) {
+ var total = 0;
+
+ var create = {};
+ for (var key in src.files) {
+ if (!src.files.hasOwnProperty(key)) continue;
+ var e = src.files[key];
+ var e2 = dst.files[key];
+ if (!e2 || e.timestamp > e2.timestamp) {
+ create[key] = e;
+ total++;
+ }
+ }
+
+ var remove = {};
+ for (var key in dst.files) {
+ if (!dst.files.hasOwnProperty(key)) continue;
+ var e = dst.files[key];
+ var e2 = src.files[key];
+ if (!e2) {
+ remove[key] = e;
+ total++;
+ }
+ }
+
+ if (!total) {
+ // early out
+ return callback(null);
+ }
+
+ var completed = 0;
+ var done = function(err) {
+ if (err) return callback(err);
+ if (++completed >= total) {
+ return callback(null);
+ }
+ };
+
+ // create a single transaction to handle and IDB reads / writes we'll need to do
+ var db = src.type === 'remote' ? src.db : dst.db;
+ var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
+ transaction.onerror = function() { callback(this.error); };
+ var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+
+ for (var path in create) {
+ if (!create.hasOwnProperty(path)) continue;
+ var entry = create[path];
+
+ if (dst.type === 'local') {
+ // save file to local
+ try {
+ if (FS.isDir(entry.mode)) {
+ FS.mkdir(path, entry.mode);
+ } else if (FS.isFile(entry.mode)) {
+ var stream = FS.open(path, 'w+', 0666);
+ FS.write(stream, entry.contents, 0, entry.contents.length, 0, true /* canOwn */);
+ FS.close(stream);
+ }
+ done(null);
+ } catch (e) {
+ return done(e);
+ }
+ } else {
+ // save file to IDB
+ var req = store.put(entry, path);
+ req.onsuccess = function() { done(null); };
+ req.onerror = function() { done(this.error); };
+ }
+ }
+
+ for (var path in remove) {
+ if (!remove.hasOwnProperty(path)) continue;
+ var entry = remove[path];
+
+ if (dst.type === 'local') {
+ // delete file from local
+ try {
+ if (FS.isDir(entry.mode)) {
+ // TODO recursive delete?
+ FS.rmdir(path);
+ } else if (FS.isFile(entry.mode)) {
+ FS.unlink(path);
+ }
+ done(null);
+ } catch (e) {
+ return done(e);
+ }
+ } else {
+ // delete file from IDB
+ var req = store.delete(path);
+ req.onsuccess = function() { done(null); };
+ req.onerror = function() { done(this.error); };
+ }
+ }
+ },
+ getLocalSet: function(mount, callback) {
+ var files = {};
+
+ var isRealDir = function(p) {
+ return p !== '.' && p !== '..';
+ };
+ var toAbsolute = function(root) {
+ return function(p) {
+ return PATH.join(root, p);
+ }
+ };
+
+ var check = FS.readdir(mount.mountpoint)
+ .filter(isRealDir)
+ .map(toAbsolute(mount.mountpoint));
+
+ while (check.length) {
+ var path = check.pop();
+ var stat, node;
+
+ try {
+ var lookup = FS.lookupPath(path);
+ node = lookup.node;
+ stat = FS.stat(path);
+ } catch (e) {
+ return callback(e);
+ }
+
+ if (FS.isDir(stat.mode)) {
+ check.push.apply(check, FS.readdir(path)
+ .filter(isRealDir)
+ .map(toAbsolute(path)));
+
+ files[path] = { mode: stat.mode, timestamp: stat.mtime };
+ } else if (FS.isFile(stat.mode)) {
+ files[path] = { contents: node.contents, mode: stat.mode, timestamp: stat.mtime };
+ } else {
+ return callback(new Error('node type not supported'));
+ }
+ }
+
+ return callback(null, { type: 'local', files: files });
+ },
+ getDB: function(name, callback) {
+ // look it up in the cache
+ var db = IDBFS.dbs[name];
+ if (db) {
+ return callback(null, db);
+ }
+ var req;
+ try {
+ req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
+ } catch (e) {
+ return onerror(e);
+ }
+ req.onupgradeneeded = function() {
+ db = req.result;
+ db.createObjectStore(IDBFS.DB_STORE_NAME);
+ };
+ req.onsuccess = function() {
+ db = req.result;
+ // add to the cache
+ IDBFS.dbs[name] = db;
+ callback(null, db);
+ };
+ req.onerror = function() {
+ callback(this.error);
+ };
+ },
+ getRemoteSet: function(mount, callback) {
+ var files = {};
+
+ IDBFS.getDB(mount.mountpoint, function(err, db) {
+ if (err) return callback(err);
+
+ var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
+ transaction.onerror = function() { callback(this.error); };
+
+ var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
+ store.openCursor().onsuccess = function(event) {
+ var cursor = event.target.result;
+ if (!cursor) {
+ return callback(null, { type: 'remote', db: db, files: files });
+ }
+
+ files[cursor.key] = cursor.value;
+ cursor.continue();
+ };
+ });
+ }
+ }
+});
diff --git a/src/library_memfs.js b/src/library_memfs.js
index 28178d9f..4e56d996 100644
--- a/src/library_memfs.js
+++ b/src/library_memfs.js
@@ -5,18 +5,10 @@ mergeInto(LibraryManager.library, {
CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it, without copying (note: someone else needs to free() it, if that is necessary)
CONTENT_FLEXIBLE: 2, // has been modified or never set to anything, and is a flexible js array that can grow/shrink
CONTENT_FIXED: 3, // contains some fixed-size content written into it, in a typed array
- ensureFlexible: function(node) {
- if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
- var contents = node.contents;
- node.contents = Array.prototype.slice.call(contents);
- node.contentMode = MEMFS.CONTENT_FLEXIBLE;
- }
- },
-
mount: function(mount) {
- return MEMFS.create_node(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
+ return MEMFS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
},
- create_node: function(parent, name, mode, dev) {
+ createNode: function(parent, name, mode, dev) {
if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
// no supported
throw new FS.ErrnoError(ERRNO_CODES.EPERM);
@@ -74,6 +66,13 @@ mergeInto(LibraryManager.library, {
}
return node;
},
+ ensureFlexible: function(node) {
+ if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
+ var contents = node.contents;
+ node.contents = Array.prototype.slice.call(contents);
+ node.contentMode = MEMFS.CONTENT_FLEXIBLE;
+ }
+ },
node_ops: {
getattr: function(node) {
var attr = {};
@@ -121,7 +120,7 @@ mergeInto(LibraryManager.library, {
throw new FS.ErrnoError(ERRNO_CODES.ENOENT);
},
mknod: function(parent, name, mode, dev) {
- return MEMFS.create_node(parent, name, mode, dev);
+ return MEMFS.createNode(parent, name, mode, dev);
},
rename: function(old_node, new_dir, new_name) {
// if we're overwriting a directory at new_name, make sure it's empty.
@@ -163,7 +162,7 @@ mergeInto(LibraryManager.library, {
return entries;
},
symlink: function(parent, newname, oldpath) {
- var node = MEMFS.create_node(parent, newname, 0777 | {{{ cDefine('S_IFLNK') }}}, 0);
+ var node = MEMFS.createNode(parent, newname, 0777 | {{{ cDefine('S_IFLNK') }}}, 0);
node.link = oldpath;
return node;
},
diff --git a/src/library_nodefs.js b/src/library_nodefs.js
new file mode 100644
index 00000000..d8df1689
--- /dev/null
+++ b/src/library_nodefs.js
@@ -0,0 +1,234 @@
+mergeInto(LibraryManager.library, {
+ $NODEFS__deps: ['$FS', '$PATH'],
+ $NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); }',
+ $NODEFS: {
+ mount: function (mount) {
+ assert(ENVIRONMENT_IS_NODE);
+ return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
+ },
+ createNode: function (parent, name, mode, dev) {
+ if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+ var node = FS.createNode(parent, name, mode);
+ node.node_ops = NODEFS.node_ops;
+ node.stream_ops = NODEFS.stream_ops;
+ return node;
+ },
+ getMode: function (path) {
+ var stat;
+ try {
+ stat = fs.lstatSync(path);
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ return stat.mode;
+ },
+ realPath: function (node) {
+ var parts = [];
+ while (node.parent !== node) {
+ parts.push(node.name);
+ node = node.parent;
+ }
+ parts.push(node.mount.opts.root);
+ parts.reverse();
+ return PATH.join.apply(null, parts);
+ },
+ node_ops: {
+ getattr: function(node) {
+ var path = NODEFS.realPath(node);
+ var stat;
+ try {
+ stat = fs.lstatSync(path);
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ return {
+ dev: stat.dev,
+ ino: stat.ino,
+ mode: stat.mode,
+ nlink: stat.nlink,
+ uid: stat.uid,
+ gid: stat.gid,
+ rdev: stat.rdev,
+ size: stat.size,
+ atime: stat.atime,
+ mtime: stat.mtime,
+ ctime: stat.ctime,
+ blksize: stat.blksize,
+ blocks: stat.blocks
+ };
+ },
+ setattr: function(node, attr) {
+ var path = NODEFS.realPath(node);
+ try {
+ if (attr.mode !== undefined) {
+ fs.chmodSync(path, attr.mode);
+ // update the common node structure mode as well
+ node.mode = attr.mode;
+ }
+ if (attr.timestamp !== undefined) {
+ var date = new Date(attr.timestamp);
+ fs.utimesSync(path, date, date);
+ }
+ if (attr.size !== undefined) {
+ fs.truncateSync(path, attr.size);
+ }
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ lookup: function (parent, name) {
+ var path = PATH.join(NODEFS.realPath(parent), name);
+ var mode = NODEFS.getMode(path);
+ return NODEFS.createNode(parent, name, mode);
+ },
+ mknod: function (parent, name, mode, dev) {
+ var node = NODEFS.createNode(parent, name, mode, dev);
+ // create the backing node for this in the fs root as well
+ var path = NODEFS.realPath(node);
+ try {
+ if (FS.isDir(node.mode)) {
+ fs.mkdirSync(path, node.mode);
+ } else {
+ fs.writeFileSync(path, '', { mode: node.mode });
+ }
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ return node;
+ },
+ rename: function (oldNode, newDir, newName) {
+ var oldPath = NODEFS.realPath(oldNode);
+ var newPath = PATH.join(NODEFS.realPath(newDir), newName);
+ try {
+ fs.renameSync(oldPath, newPath);
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ unlink: function(parent, name) {
+ var path = PATH.join(NODEFS.realPath(parent), name);
+ try {
+ fs.unlinkSync(path);
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ rmdir: function(parent, name) {
+ var path = PATH.join(NODEFS.realPath(parent), name);
+ try {
+ fs.rmdirSync(path);
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ readdir: function(node) {
+ var path = NODEFS.realPath(node);
+ try {
+ return fs.readdirSync(path);
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ symlink: function(parent, newName, oldPath) {
+ var newPath = PATH.join(NODEFS.realPath(parent), newName);
+ try {
+ fs.symlinkSync(oldPath, newPath);
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ readlink: function(node) {
+ var path = NODEFS.realPath(node);
+ try {
+ return fs.readlinkSync(path);
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ },
+ stream_ops: {
+ open: function (stream) {
+ var path = NODEFS.realPath(stream.node);
+ try {
+ if (FS.isFile(stream.node.mode)) {
+ stream.nfd = fs.openSync(path, stream.flags);
+ }
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ close: function (stream) {
+ try {
+ if (FS.isFile(stream.node.mode)) {
+ fs.closeSync(stream.nfd);
+ }
+ } catch (e) {
+ if (!e.code) throw e;
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ },
+ read: function (stream, buffer, offset, length, position) {
+ // FIXME this is terrible.
+ var nbuffer = new Buffer(length);
+ var res;
+ try {
+ res = fs.readSync(stream.nfd, nbuffer, 0, length, position);
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ if (res > 0) {
+ for (var i = 0; i < res; i++) {
+ buffer[offset + i] = nbuffer[i];
+ }
+ }
+ return res;
+ },
+ write: function (stream, buffer, offset, length, position) {
+ // FIXME this is terrible.
+ var nbuffer = new Buffer(buffer.subarray(offset, offset + length));
+ var res;
+ try {
+ res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ return res;
+ },
+ llseek: function (stream, offset, whence) {
+ var position = offset;
+ if (whence === 1) { // SEEK_CUR.
+ position += stream.position;
+ } else if (whence === 2) { // SEEK_END.
+ if (FS.isFile(stream.node.mode)) {
+ try {
+ var stat = fs.fstatSync(stream.nfd);
+ position += stat.size;
+ } catch (e) {
+ throw new FS.ErrnoError(ERRNO_CODES[e.code]);
+ }
+ }
+ }
+
+ if (position < 0) {
+ throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
+ }
+
+ stream.position = position;
+ return position;
+ }
+ }
+ }
+}); \ No newline at end of file
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 116bf547..27f2c0da 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -35,7 +35,7 @@ var LibrarySDL = {
volume: 1.0
},
mixerFrequency: 22050,
- mixerFormat: 0x8010, // AUDIO_S16LSB
+ mixerFormat: {{{ cDefine('AUDIO_S16LSB') }}}, //0x8010, // AUDIO_S16LSB
mixerNumChannels: 2,
mixerChunkSize: 1024,
channelMinimumNumber: 0,
@@ -151,89 +151,12 @@ var LibrarySDL = {
305: 224, // ctrl
308: 226, // alt
},
-
- structs: {
- Rect: Runtime.generateStructInfo([
- ['i32', 'x'], ['i32', 'y'], ['i32', 'w'], ['i32', 'h'],
- ]),
- PixelFormat: Runtime.generateStructInfo([
- ['i32', 'format'],
- ['void*', 'palette'], ['i8', 'BitsPerPixel'], ['i8', 'BytesPerPixel'],
- ['i8', 'padding1'], ['i8', 'padding2'],
- ['i32', 'Rmask'], ['i32', 'Gmask'], ['i32', 'Bmask'], ['i32', 'Amask'],
- ['i8', 'Rloss'], ['i8', 'Gloss'], ['i8', 'Bloss'], ['i8', 'Aloss'],
- ['i8', 'Rshift'], ['i8', 'Gshift'], ['i8', 'Bshift'], ['i8', 'Ashift']
- ]),
- KeyboardEvent: Runtime.generateStructInfo([
- ['i32', 'type'],
- ['i32', 'windowID'],
- ['i8', 'state'],
- ['i8', 'repeat'],
- ['i8', 'padding2'],
- ['i8', 'padding3'],
- ['i32', 'keysym']
- ]),
- keysym: Runtime.generateStructInfo([
- ['i32', 'scancode'],
- ['i32', 'sym'],
- ['i16', 'mod'],
- ['i32', 'unicode']
- ]),
- TextInputEvent: Runtime.generateStructInfo([
- ['i32', 'type'],
- ['i32', 'windowID'],
- ['b256', 'text'],
- ]),
- MouseMotionEvent: Runtime.generateStructInfo([
- ['i32', 'type'],
- ['i32', 'windowID'],
- ['i8', 'state'],
- ['i8', 'padding1'],
- ['i8', 'padding2'],
- ['i8', 'padding3'],
- ['i32', 'x'],
- ['i32', 'y'],
- ['i32', 'xrel'],
- ['i32', 'yrel']
- ]),
- MouseButtonEvent: Runtime.generateStructInfo([
- ['i32', 'type'],
- ['i32', 'windowID'],
- ['i8', 'button'],
- ['i8', 'state'],
- ['i8', 'padding1'],
- ['i8', 'padding2'],
- ['i32', 'x'],
- ['i32', 'y']
- ]),
- ResizeEvent: Runtime.generateStructInfo([
- ['i32', 'type'],
- ['i32', 'w'],
- ['i32', 'h']
- ]),
- AudioSpec: Runtime.generateStructInfo([
- ['i32', 'freq'],
- ['i16', 'format'],
- ['i8', 'channels'],
- ['i8', 'silence'],
- ['i16', 'samples'],
- ['i32', 'size'],
- ['void*', 'callback'],
- ['void*', 'userdata']
- ]),
- version: Runtime.generateStructInfo([
- ['i8', 'major'],
- ['i8', 'minor'],
- ['i8', 'patch']
- ])
- },
-
loadRect: function(rect) {
return {
- x: {{{ makeGetValue('rect + SDL.structs.Rect.x', '0', 'i32') }}},
- y: {{{ makeGetValue('rect + SDL.structs.Rect.y', '0', 'i32') }}},
- w: {{{ makeGetValue('rect + SDL.structs.Rect.w', '0', 'i32') }}},
- h: {{{ makeGetValue('rect + SDL.structs.Rect.h', '0', 'i32') }}}
+ x: {{{ makeGetValue('rect + ' + C_STRUCTS.SDL_Rect.x, '0', 'i32') }}},
+ y: {{{ makeGetValue('rect + ' + C_STRUCTS.SDL_Rect.y, '0', 'i32') }}},
+ w: {{{ makeGetValue('rect + ' + C_STRUCTS.SDL_Rect.w, '0', 'i32') }}},
+ h: {{{ makeGetValue('rect + ' + C_STRUCTS.SDL_Rect.h, '0', 'i32') }}}
};
},
@@ -261,35 +184,35 @@ var LibrarySDL = {
makeSurface: function(width, height, flags, usePageCanvas, source, rmask, gmask, bmask, amask) {
flags = flags || 0;
- var surf = _malloc(15*Runtime.QUANTUM_SIZE); // SDL_Surface has 15 fields of quantum size
+ var surf = _malloc({{{ C_STRUCTS.SDL_Surface.__size__ }}}); // SDL_Surface has 15 fields of quantum size
var buffer = _malloc(width*height*4); // TODO: only allocate when locked the first time
- var pixelFormat = _malloc(18*Runtime.QUANTUM_SIZE);
+ var pixelFormat = _malloc({{{ C_STRUCTS.SDL_PixelFormat.__size__ }}});
flags |= 1; // SDL_HWSURFACE - this tells SDL_MUSTLOCK that this needs to be locked
//surface with SDL_HWPALETTE flag is 8bpp surface (1 byte)
var is_SDL_HWPALETTE = flags & 0x00200000;
var bpp = is_SDL_HWPALETTE ? 1 : 4;
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*0', '0', 'flags', 'i32') }}} // SDL_Surface.flags
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*1', '0', 'pixelFormat', 'void*') }}} // SDL_Surface.format TODO
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*2', '0', 'width', 'i32') }}} // SDL_Surface.w
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*3', '0', 'height', 'i32') }}} // SDL_Surface.h
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*4', '0', 'width * bpp', 'i32') }}} // SDL_Surface.pitch, assuming RGBA or indexed for now,
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.flags, 'flags', 'i32') }}} // SDL_Surface.flags
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.format, 'pixelFormat', 'void*') }}} // SDL_Surface.format TODO
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.w, 'width', 'i32') }}} // SDL_Surface.w
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.h, 'height', 'i32') }}} // SDL_Surface.h
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pitch, 'width * bpp', 'i32') }}} // SDL_Surface.pitch, assuming RGBA or indexed for now,
// since that is what ImageData gives us in browsers
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*5', '0', 'buffer', 'void*') }}} // SDL_Surface.pixels
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*6', '0', '0', 'i32*') }}} // SDL_Surface.offset
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}} // SDL_Surface.pixels
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}} // SDL_Surface.offset
- {{{ makeSetValue('surf+Runtime.QUANTUM_SIZE*14', '0', '1', 'i32') }}}
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}}
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.format', '0', '-2042224636', 'i32') }}} // SDL_PIXELFORMAT_RGBA8888
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.palette', '0', '0', 'i32') }}} // TODO
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BitsPerPixel', '0', 'bpp * 8', 'i8') }}}
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.BytesPerPixel', '0', 'bpp', 'i8') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}} // SDL_PIXELFORMAT_RGBA8888
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}} // TODO
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}}
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.Rmask', '0', 'rmask || 0x000000ff', 'i32') }}}
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.Gmask', '0', 'gmask || 0x0000ff00', 'i32') }}}
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.Bmask', '0', 'bmask || 0x00ff0000', 'i32') }}}
- {{{ makeSetValue('pixelFormat + SDL.structs.PixelFormat.Amask', '0', 'amask || 0xff000000', 'i32') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}}
// Decide if we want to use WebGL or not
var useWebGL = (flags & 0x04000000) != 0; // SDL_OPENGL
@@ -367,7 +290,7 @@ var LibrarySDL = {
},
freeSurface: function(surf) {
- var refcountPointer = surf + Runtime.QUANTUM_SIZE * 14;
+ var refcountPointer = surf + {{{ C_STRUCTS.SDL_Surface.refcount }}};
var refcount = {{{ makeGetValue('refcountPointer', '0', 'i32') }}};
if (refcount > 1) {
{{{ makeSetValue('refcountPointer', '0', 'refcount - 1', 'i32') }}};
@@ -608,7 +531,7 @@ var LibrarySDL = {
makeCEvent: function(event, ptr) {
if (typeof event === 'number') {
// This is a pointer to a native C event that was SDL_PushEvent'ed
- _memcpy(ptr, event, SDL.structs.KeyboardEvent.__size__); // XXX
+ _memcpy(ptr, event, {{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}); // XXX
return;
}
@@ -631,52 +554,52 @@ var LibrarySDL = {
scan = SDL.scanCodes[key] || key;
}
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.state', 'down ? 1 : 0', 'i8') }}}
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.repeat', '0', 'i8') }}} // TODO
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.scancode', 'scan', 'i32') }}}
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.sym', 'key', 'i32') }}}
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.mod', 'SDL.modState', 'i16') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.repeat, '0', 'i8') }}} // TODO
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.mod, 'SDL.modState', 'i16') }}}
// some non-character keys (e.g. backspace and tab) won't have keypressCharCode set, fill in with the keyCode.
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.keysym + SDL.structs.keysym.unicode', 'event.keypressCharCode || key', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}}
break;
}
case 'keypress': {
- {{{ makeSetValue('ptr', 'SDL.structs.TextInputEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
// Not filling in windowID for now
var cStr = intArrayFromString(String.fromCharCode(event.charCode));
for (var i = 0; i < cStr.length; ++i) {
- {{{ makeSetValue('ptr', 'SDL.structs.TextInputEvent.text + i', 'cStr[i]', 'i8') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.text + ' + i', 'cStr[i]', 'i8') }}};
}
break;
}
case 'mousedown': case 'mouseup': case 'mousemove': {
if (event.type != 'mousemove') {
var down = event.type === 'mousedown';
- {{{ makeSetValue('ptr', 'SDL.structs.MouseButtonEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseButtonEvent.button', 'event.button+1', 'i8') }}}; // DOM buttons are 0-2, SDL 1-3
- {{{ makeSetValue('ptr', 'SDL.structs.MouseButtonEvent.state', 'down ? 1 : 0', 'i8') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseButtonEvent.x', 'Browser.mouseX', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseButtonEvent.y', 'Browser.mouseY', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.button, 'event.button+1', 'i8') }}}; // DOM buttons are 0-2, SDL 1-3
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.state, 'down ? 1 : 0', 'i8') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.x, 'Browser.mouseX', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseButtonEvent.y, 'Browser.mouseY', 'i32') }}};
} else {
- {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.state', 'SDL.buttonState', 'i8') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.x', 'Browser.mouseX', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.y', 'Browser.mouseY', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.xrel', 'Browser.mouseMovementX', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.MouseMotionEvent.yrel', 'Browser.mouseMovementY', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.state, 'SDL.buttonState', 'i8') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.x, 'Browser.mouseX', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.y, 'Browser.mouseY', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.xrel, 'Browser.mouseMovementX', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_MouseMotionEvent.yrel, 'Browser.mouseMovementY', 'i32') }}};
}
break;
}
case 'unload': {
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
break;
}
case 'resize': {
- {{{ makeSetValue('ptr', 'SDL.structs.KeyboardEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.ResizeEvent.w', 'event.w', 'i32') }}};
- {{{ makeSetValue('ptr', 'SDL.structs.ResizeEvent.h', 'event.h', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_ResizeEvent.w, 'event.w', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_ResizeEvent.h, 'event.h', 'i32') }}};
break;
}
default: throw 'Unhandled SDL event: ' + event.type;
@@ -704,7 +627,7 @@ var LibrarySDL = {
// since the browser engine handles that for us. Therefore, in JS we just
// maintain a list of channels and return IDs for them to the SDL consumer.
allocateChannels: function(num) { // called from Mix_AllocateChannels and init
- if (SDL.numChannels && SDL.numChannels >= num) return;
+ if (SDL.numChannels && SDL.numChannels >= num && num != 0) return;
SDL.numChannels = num;
SDL.channels = [];
for (var i = 0; i < num; i++) {
@@ -740,10 +663,10 @@ var LibrarySDL = {
SDL_Linked_Version: function() {
if (SDL.version === null) {
- SDL.version = _malloc(SDL.structs.version.__size__);
- {{{ makeSetValue('SDL.version + SDL.structs.version.major', '0', '1', 'i8') }}}
- {{{ makeSetValue('SDL.version + SDL.structs.version.minor', '0', '3', 'i8') }}}
- {{{ makeSetValue('SDL.version + SDL.structs.version.patch', '0', '0', 'i8') }}}
+ SDL.version = _malloc({{{ C_STRUCTS.SDL_version.__size__ }}});
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}}
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}}
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}}
}
return SDL.version;
},
@@ -887,7 +810,7 @@ var LibrarySDL = {
// SDL_Surface has the following fields: Uint32 flags, SDL_PixelFormat *format; int w, h; Uint16 pitch; void *pixels; ...
// So we have fields all of the same size, and 5 of them before us.
// TODO: Use macros like in library.js
- {{{ makeSetValue('surf', '5*Runtime.QUANTUM_SIZE', 'surfData.buffer', 'void*') }}};
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'surfData.buffer', 'void*') }}};
if (surf == SDL.screen && Module.screenIsReadOnly && surfData.image) return 0;
@@ -1131,7 +1054,10 @@ var LibrarySDL = {
} else {
dr = { x: 0, y: 0, w: -1, h: -1 };
}
+ var oldAlpha = dstData.ctx.globalAlpha;
+ dstData.ctx.globalAlpha = srcData.alpha/255;
dstData.ctx.drawImage(srcData.canvas, sr.x, sr.y, sr.w, sr.h, dr.x, dr.y, sr.w, sr.h);
+ dstData.ctx.globalAlpha = oldAlpha;
if (dst != SDL.screen) {
// XXX As in IMG_Load, for compatibility we write out |pixels|
console.log('WARNING: copying canvas data to memory for compatibility');
@@ -1454,60 +1380,240 @@ var LibrarySDL = {
// SDL_Audio
- // TODO fix SDL_OpenAudio, and add some tests for it. It's currently broken.
SDL_OpenAudio: function(desired, obtained) {
- SDL.allocateChannels(32);
-
- SDL.audio = {
- freq: {{{ makeGetValue('desired', 'SDL.structs.AudioSpec.freq', 'i32', 0, 1) }}},
- format: {{{ makeGetValue('desired', 'SDL.structs.AudioSpec.format', 'i16', 0, 1) }}},
- channels: {{{ makeGetValue('desired', 'SDL.structs.AudioSpec.channels', 'i8', 0, 1) }}},
- samples: {{{ makeGetValue('desired', 'SDL.structs.AudioSpec.samples', 'i16', 0, 1) }}},
- callback: {{{ makeGetValue('desired', 'SDL.structs.AudioSpec.callback', 'void*', 0, 1) }}},
- userdata: {{{ makeGetValue('desired', 'SDL.structs.AudioSpec.userdata', 'void*', 0, 1) }}},
- paused: true,
- timer: null
- };
-
- if (obtained) {
- {{{ makeSetValue('obtained', 'SDL.structs.AudioSpec.freq', 'SDL.audio.freq', 'i32') }}}; // no good way for us to know if the browser can really handle this
- {{{ makeSetValue('obtained', 'SDL.structs.AudioSpec.format', 33040, 'i16') }}}; // float, signed, 16-bit
- {{{ makeSetValue('obtained', 'SDL.structs.AudioSpec.channels', 'SDL.audio.channels', 'i8') }}};
- {{{ makeSetValue('obtained', 'SDL.structs.AudioSpec.silence', makeGetValue('desired', 'SDL.structs.AudioSpec.silence', 'i8', 0, 1), 'i8') }}}; // unclear if browsers can provide this
- {{{ makeSetValue('obtained', 'SDL.structs.AudioSpec.samples', 'SDL.audio.samples', 'i16') }}};
- {{{ makeSetValue('obtained', 'SDL.structs.AudioSpec.callback', 'SDL.audio.callback', '*') }}};
- {{{ makeSetValue('obtained', 'SDL.structs.AudioSpec.userdata', 'SDL.audio.userdata', '*') }}};
- }
-
- var totalSamples = SDL.audio.samples*SDL.audio.channels;
- SDL.audio.bufferSize = totalSamples*2; // hardcoded 16-bit audio
- SDL.audio.buffer = _malloc(SDL.audio.bufferSize);
- SDL.audio.caller = function() {
- Runtime.dynCall('viii', SDL.audio.callback, [SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize]);
- SDL.audio.pushAudio(SDL.audio.buffer, SDL.audio.bufferSize);
- };
- // Mozilla Audio API. TODO: Other audio APIs
try {
- SDL.audio.mozOutput = new Audio();
- SDL.audio.mozOutput['mozSetup'](SDL.audio.channels, SDL.audio.freq); // use string attributes on mozOutput for closure compiler
- SDL.audio.mozBuffer = new Float32Array(totalSamples);
- SDL.audio.pushAudio = function(ptr, size) {
- var mozBuffer = SDL.audio.mozBuffer;
- for (var i = 0; i < totalSamples; i++) {
- mozBuffer[i] = ({{{ makeGetValue('ptr', 'i*2', 'i16', 0, 0) }}}) / 0x8000; // hardcoded 16-bit audio, signed (TODO: reSign if not ta2?)
+ SDL.audio = {
+ freq: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.freq, 'i32', 0, 1) }}},
+ format: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.format, 'i16', 0, 1) }}},
+ channels: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.channels, 'i8', 0, 1) }}},
+ samples: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.samples, 'i16', 0, 1) }}}, // Samples in the CB buffer per single sound channel.
+ callback: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.callback, 'void*', 0, 1) }}},
+ userdata: {{{ makeGetValue('desired', C_STRUCTS.SDL_AudioSpec.userdata, 'void*', 0, 1) }}},
+ paused: true,
+ timer: null
+ };
+ // The .silence field tells the constant sample value that corresponds to the safe un-skewed silence value for the wave data.
+ if (SDL.audio.format == 0x0008 /*AUDIO_U8*/) {
+ SDL.audio.silence = 128; // Audio ranges in [0, 255], so silence is half-way in between.
+ } else if (SDL.audio.format == 0x8010 /*AUDIO_S16LSB*/) {
+ SDL.audio.silence = 0; // Signed data in range [-32768, 32767], silence is 0.
+ } else {
+ throw 'Invalid SDL audio format ' + SDL.audio.format + '!';
+ }
+ // Round the desired audio frequency up to the next 'common' frequency value.
+ // Web Audio API spec states 'An implementation must support sample-rates in at least the range 22050 to 96000.'
+ if (SDL.audio.freq <= 0) {
+ throw 'Unsupported sound frequency ' + SDL.audio.freq + '!';
+ } else if (SDL.audio.freq <= 22050) {
+ SDL.audio.freq = 22050; // Take it safe and clamp everything lower than 22kHz to that.
+ } else if (SDL.audio.freq <= 32000) {
+ SDL.audio.freq = 32000;
+ } else if (SDL.audio.freq <= 44100) {
+ SDL.audio.freq = 44100;
+ } else if (SDL.audio.freq <= 48000) {
+ SDL.audio.freq = 48000;
+ } else if (SDL.audio.freq <= 96000) {
+ SDL.audio.freq = 96000;
+ } else {
+ throw 'Unsupported sound frequency ' + SDL.audio.freq + '!';
+ }
+ if (SDL.audio.channels == 0) {
+ SDL.audio.channels = 1; // In SDL both 0 and 1 mean mono.
+ } else if (SDL.audio.channels < 0 || SDL.audio.channels > 32) {
+ throw 'Unsupported number of audio channels for SDL audio: ' + SDL.audio.channels + '!';
+ } else if (SDL.audio.channels != 1 && SDL.audio.channels != 2) { // Unsure what SDL audio spec supports. Web Audio spec supports up to 32 channels.
+ console.log('Warning: Using untested number of audio channels ' + SDL.audio.channels);
+ }
+ if (SDL.audio.samples < 1024 || SDL.audio.samples > 524288 /* arbitrary cap */) {
+ throw 'Unsupported audio callback buffer size ' + SDL.audio.samples + '!';
+ } else if ((SDL.audio.samples & (SDL.audio.samples-1)) != 0) {
+ throw 'Audio callback buffer size ' + SDL.audio.samples + ' must be a power-of-two!';
+ }
+
+ var totalSamples = SDL.audio.samples*SDL.audio.channels;
+ SDL.audio.bytesPerSample = (SDL.audio.format == 0x0008 /*AUDIO_U8*/ || SDL.audio.format == 0x8008 /*AUDIO_S8*/) ? 1 : 2;
+ SDL.audio.bufferSize = totalSamples*SDL.audio.bytesPerSample;
+ SDL.audio.buffer = _malloc(SDL.audio.bufferSize);
+
+ // Create a callback function that will be routinely called to ask more audio data from the user application.
+ SDL.audio.caller = function() {
+ if (!SDL.audio) {
+ return;
}
- SDL.audio.mozOutput['mozWriteAudio'](mozBuffer);
+ Runtime.dynCall('viii', SDL.audio.callback, [SDL.audio.userdata, SDL.audio.buffer, SDL.audio.bufferSize]);
+ SDL.audio.pushAudio(SDL.audio.buffer, SDL.audio.bufferSize);
+ };
+
+ SDL.audio.audioOutput = new Audio();
+ // As a workaround use Mozilla Audio Data API on Firefox until it ships with Web Audio and sound quality issues are fixed.
+ if (typeof(SDL.audio.audioOutput['mozSetup'])==='function') {
+ SDL.audio.audioOutput['mozSetup'](SDL.audio.channels, SDL.audio.freq); // use string attributes on mozOutput for closure compiler
+ SDL.audio.mozBuffer = new Float32Array(totalSamples);
+ SDL.audio.nextPlayTime = 0;
+ SDL.audio.pushAudio = function(ptr, size) {
+ var mozBuffer = SDL.audio.mozBuffer;
+ // The input audio data for SDL audio is either 8-bit or 16-bit interleaved across channels, output for Mozilla Audio Data API
+ // needs to be Float32 interleaved, so perform a sample conversion.
+ if (SDL.audio.format == 0x8010 /*AUDIO_S16LSB*/) {
+ for (var i = 0; i < totalSamples; i++) {
+ mozBuffer[i] = ({{{ makeGetValue('ptr', 'i*2', 'i16', 0, 0) }}}) / 0x8000;
+ }
+ } else if (SDL.audio.format == 0x0008 /*AUDIO_U8*/) {
+ for (var i = 0; i < totalSamples; i++) {
+ var v = ({{{ makeGetValue('ptr', 'i', 'i8', 0, 0) }}});
+ mozBuffer[i] = ((v >= 0) ? v-128 : v+128) /128;
+ }
+ }
+ // Submit the audio data to audio device.
+ SDL.audio.audioOutput['mozWriteAudio'](mozBuffer);
+
+ // Compute when the next audio callback should be called.
+ var curtime = Date.now() / 1000.0 - SDL.audio.startTime;
+ if (curtime > SDL.audio.nextPlayTime && SDL.audio.nextPlayTime != 0) {
+ console.log('warning: Audio callback had starved sending audio by ' + (curtime - SDL.audio.nextPlayTime) + ' seconds.');
+ }
+ var playtime = Math.max(curtime, SDL.audio.nextPlayTime);
+ var buffer_duration = SDL.audio.samples / SDL.audio.freq;
+ SDL.audio.nextPlayTime = playtime + buffer_duration;
+ // Schedule the next audio callback call.
+ SDL.audio.timer = Browser.safeSetTimeout(SDL.audio.caller, 1000.0 * (playtime-curtime));
+ }
+ } else {
+ // Initialize Web Audio API if we haven't done so yet. Note: Only initialize Web Audio context ever once on the web page,
+ // since initializing multiple times fails on Chrome saying 'audio resources have been exhausted'.
+ if (!SDL.audioContext) {
+ if (typeof(AudioContext) === 'function') {
+ SDL.audioContext = new AudioContext();
+ } else if (typeof(webkitAudioContext) === 'function') {
+ SDL.audioContext = new webkitAudioContext();
+ } else {
+ throw 'Web Audio API is not available!';
+ }
+ }
+ SDL.audio.soundSource = new Array(); // Use an array of sound sources as a ring buffer to queue blocks of synthesized audio to Web Audio API.
+ SDL.audio.nextSoundSource = 0; // Index of the next sound buffer in the ring buffer queue to play.
+ SDL.audio.nextPlayTime = 0; // Time in seconds when the next audio block is due to start.
+
+ // The pushAudio function with a new audio buffer whenever there is new audio data to schedule to be played back on the device.
+ SDL.audio.pushAudio=function(ptr,sizeBytes) {
+ try {
+ --SDL.audio.numAudioTimersPending;
+
+ var sizeSamples = sizeBytes / SDL.audio.bytesPerSample; // How many samples fit in the callback buffer?
+ var sizeSamplesPerChannel = sizeSamples / SDL.audio.channels; // How many samples per a single channel fit in the cb buffer?
+ if (sizeSamplesPerChannel != SDL.audio.samples) {
+ throw 'Received mismatching audio buffer size!';
+ }
+ // Allocate new sound buffer to be played.
+ var source = SDL.audioContext['createBufferSource']();
+ if (SDL.audio.soundSource[SDL.audio.nextSoundSource]) {
+ SDL.audio.soundSource[SDL.audio.nextSoundSource]['disconnect'](); // Explicitly disconnect old source, since we know it shouldn't be running anymore.
+ }
+ SDL.audio.soundSource[SDL.audio.nextSoundSource] = source;
+ var soundBuffer = SDL.audioContext['createBuffer'](SDL.audio.channels,sizeSamplesPerChannel,SDL.audio.freq);
+ SDL.audio.soundSource[SDL.audio.nextSoundSource]['connect'](SDL.audioContext['destination']);
+
+ // The input audio data is interleaved across the channels, i.e. [L, R, L, R, L, R, ...] and is either 8-bit or 16-bit as
+ // supported by the SDL API. The output audio wave data for Web Audio API must be in planar buffers of [-1,1]-normalized Float32 data,
+ // so perform a buffer conversion for the data.
+ var numChannels = SDL.audio.channels;
+ for(var i = 0; i < numChannels; ++i) {
+ var channelData = soundBuffer['getChannelData'](i);
+ if (channelData.length != sizeSamplesPerChannel) {
+ throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + sizeSamplesPerChannel + ' samples!';
+ }
+ if (SDL.audio.format == 0x8010 /*AUDIO_S16LSB*/) {
+ for(var j = 0; j < sizeSamplesPerChannel; ++j) {
+ channelData[j] = ({{{ makeGetValue('ptr', '(j*numChannels + i)*2', 'i16', 0, 0) }}}) / 0x8000;
+ }
+ } else if (SDL.audio.format == 0x0008 /*AUDIO_U8*/) {
+ for(var j = 0; j < sizeSamplesPerChannel; ++j) {
+ var v = ({{{ makeGetValue('ptr', 'j*numChannels + i', 'i8', 0, 0) }}});
+ channelData[j] = ((v >= 0) ? v-128 : v+128) /128;
+ }
+ }
+ }
+ // Workaround https://bugzilla.mozilla.org/show_bug.cgi?id=883675 by setting the buffer only after filling. The order is important here!
+ source['buffer'] = soundBuffer;
+
+ // Schedule the generated sample buffer to be played out at the correct time right after the previously scheduled
+ // sample buffer has finished.
+ var curtime = SDL.audioContext['currentTime'];
+// if (curtime > SDL.audio.nextPlayTime && SDL.audio.nextPlayTime != 0) {
+// console.log('warning: Audio callback had starved sending audio by ' + (curtime - SDL.audio.nextPlayTime) + ' seconds.');
+// }
+ var playtime = Math.max(curtime, SDL.audio.nextPlayTime);
+ SDL.audio.soundSource[SDL.audio.nextSoundSource]['start'](playtime);
+ var buffer_duration = sizeSamplesPerChannel / SDL.audio.freq;
+ SDL.audio.nextPlayTime = playtime + buffer_duration;
+ SDL.audio.nextSoundSource = (SDL.audio.nextSoundSource + 1) % 4;
+ var secsUntilNextCall = playtime-curtime;
+
+ // Queue the next audio frame push to be performed when the previously queued buffer has finished playing.
+ if (SDL.audio.numAudioTimersPending == 0) {
+ var preemptBufferFeedMSecs = buffer_duration/2.0;
+ SDL.audio.timer = Browser.safeSetTimeout(SDL.audio.caller, Math.max(0.0, 1000.0*secsUntilNextCall-preemptBufferFeedMSecs));
+ ++SDL.audio.numAudioTimersPending;
+ }
+
+ // If we are risking starving, immediately queue an extra second buffer.
+ if (secsUntilNextCall <= buffer_duration && SDL.audio.numAudioTimersPending <= 1) {
+ ++SDL.audio.numAudioTimersPending;
+ Browser.safeSetTimeout(SDL.audio.caller, 1.0);
+ }
+ } catch(e) {
+ console.log('Web Audio API error playing back audio: ' + e.toString());
+ }
+ }
+ }
+
+ if (obtained) {
+ // Report back the initialized audio parameters.
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.freq, 'SDL.audio.freq', 'i32') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.format, 'SDL.audio.format', 'i16') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.channels, 'SDL.audio.channels', 'i8') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.silence, 'SDL.audio.silence', 'i8') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.samples, 'SDL.audio.samples', 'i16') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.callback, 'SDL.audio.callback', '*') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.userdata, 'SDL.audio.userdata', '*') }}};
}
+ SDL.allocateChannels(32);
+
} catch(e) {
+ console.log('Initializing SDL audio threw an exception: "' + e.toString() + '"! Continuing without audio.');
SDL.audio = null;
+ SDL.allocateChannels(0);
+ if (obtained) {
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.freq, 0, 'i32') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.format, 0, 'i16') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.channels, 0, 'i8') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.silence, 0, 'i8') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.samples, 0, 'i16') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.callback, 0, '*') }}};
+ {{{ makeSetValue('obtained', C_STRUCTS.SDL_AudioSpec.userdata, 0, '*') }}};
+ }
+ }
+ if (!SDL.audio) {
+ return -1;
}
- if (!SDL.audio) return -1;
return 0;
},
SDL_PauseAudio: function(pauseOn) {
- if (SDL.audio.paused !== pauseOn) {
- SDL.audio.timer = pauseOn ? SDL.audio.timer && clearInterval(SDL.audio.timer) : Browser.safeSetInterval(SDL.audio.caller, 1/35);
+ if (!SDL.audio) {
+ return;
+ }
+ if (pauseOn) {
+ if (SDL.audio.timer !== undefined) {
+ clearTimeout(SDL.audio.timer);
+ SDL.audio.numAudioTimersPending = 0;
+ SDL.audio.timer = undefined;
+ }
+ } else if (!SDL.audio.timer) {
+ // Start the audio playback timer callback loop.
+ SDL.audio.numAudioTimersPending = 1;
+ SDL.audio.timer = Browser.safeSetTimeout(SDL.audio.caller, 1);
+ SDL.audio.startTime = Date.now() / 1000.0; // Only used for Mozilla Audio Data API. Not needed for Web Audio API.
}
SDL.audio.paused = pauseOn;
},
@@ -1515,9 +1621,18 @@ var LibrarySDL = {
SDL_CloseAudio__deps: ['SDL_PauseAudio', 'free'],
SDL_CloseAudio: function() {
if (SDL.audio) {
+ try{
+ for(var i = 0; i < SDL.audio.soundSource.length; ++i) {
+ if (!(typeof(SDL.audio.soundSource[i]==='undefined'))) {
+ SDL.audio.soundSource[i].stop(0);
+ }
+ }
+ } catch(e) {}
+ SDL.audio.soundSource = null;
_SDL_PauseAudio(1);
_free(SDL.audio.buffer);
SDL.audio = null;
+ SDL.allocateChannels(0);
}
},
diff --git a/src/library_sockfs.js b/src/library_sockfs.js
index b11c6495..af29d11b 100644
--- a/src/library_sockfs.js
+++ b/src/library_sockfs.js
@@ -5,12 +5,6 @@ mergeInto(LibraryManager.library, {
mount: function(mount) {
return FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 0777, 0);
},
- nextname: function() {
- if (!SOCKFS.nextname.current) {
- SOCKFS.nextname.current = 0;
- }
- return 'socket[' + (SOCKFS.nextname.current++) + ']';
- },
createSocket: function(family, type, protocol) {
var streaming = type == {{{ cDefine('SOCK_STREAM') }}};
if (protocol) {
@@ -95,6 +89,12 @@ mergeInto(LibraryManager.library, {
sock.sock_ops.close(sock);
}
},
+ nextname: function() {
+ if (!SOCKFS.nextname.current) {
+ SOCKFS.nextname.current = 0;
+ }
+ return 'socket[' + (SOCKFS.nextname.current++) + ']';
+ },
// backend-specific stream ops
websocket_sock_ops: {
//
diff --git a/src/modules.js b/src/modules.js
index 1029b233..cc9ca549 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -234,7 +234,7 @@ var Types = {
preciseI64MathUsed: (PRECISE_I64_MATH == 2)
};
-var firstTableIndex = (ASM_JS ? 2*RESERVED_FUNCTION_POINTERS : 0) + 2;
+var firstTableIndex = FUNCTION_POINTER_ALIGNMENT * ((ASM_JS ? RESERVED_FUNCTION_POINTERS : 0) + 1);
var Functions = {
// All functions that will be implemented in this file. Maps id to signature
@@ -287,7 +287,7 @@ var Functions = {
ret = this.indexedFunctions[ident];
if (!ret) {
ret = this.nextIndex;
- this.nextIndex += 2; // Need to have indexes be even numbers, see |polymorph| test
+ this.nextIndex += FUNCTION_POINTER_ALIGNMENT;
this.indexedFunctions[ident] = ret;
}
ret = ret.toString();
@@ -340,7 +340,7 @@ var Functions = {
if (table[i]) {
var libName = LibraryManager.getRootIdent(table[i].substr(1));
if (libName && typeof libName == 'string') {
- table[i] = (libName.indexOf('.') < 0 ? '_' : '') + libName;
+ table[i] = (libName.indexOf('Math_') < 0 ? '_' : '') + libName;
}
}
if (ASM_JS) {
@@ -373,27 +373,17 @@ var Functions = {
}
}
}
- if (table.length > 20) {
- // add some newlines in the table, for readability
- var j = 10;
- while (j+10 < table.length) {
- table[j] += '\n';
- j += 10;
- }
- }
maxTable = Math.max(maxTable, table.length);
}
if (ASM_JS) maxTable = ceilPowerOfTwo(maxTable);
for (var t in tables) {
if (t == 'pre') continue;
var table = tables[t];
- if (ASM_JS) {
- // asm function table mask must be power of two
- // if nonaliasing, then standardize function table size, to avoid aliasing pointers through the &M mask (in a small table using a big index)
- var fullSize = ALIASING_FUNCTION_POINTERS ? ceilPowerOfTwo(table.length) : maxTable;
- for (var i = table.length; i < fullSize; i++) {
- table[i] = 0;
- }
+ // asm function table mask must be power of two, and non-asm must be aligned
+ // if nonaliasing, then standardize function table size, to avoid aliasing pointers through the &M mask (in a small table using a big index)
+ var fullSize = ASM_JS ? (ALIASING_FUNCTION_POINTERS ? ceilPowerOfTwo(table.length) : maxTable) : ((table.length+FUNCTION_POINTER_ALIGNMENT-1)&-FUNCTION_POINTER_ALIGNMENT);
+ for (var i = table.length; i < fullSize; i++) {
+ table[i] = 0;
}
// finalize table
var indices = table.toString().replace('"', '');
@@ -422,7 +412,7 @@ var LibraryManager = {
load: function() {
if (this.library) return;
- var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_memfs.js', 'library_sockfs.js', 'library_tty.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', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries);
+ var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.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', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries);
for (var i = 0; i < libraries.length; i++) {
eval(processMacros(preprocess(read(libraries[i]))));
}
diff --git a/src/parseTools.js b/src/parseTools.js
index c55c895d..addf0f21 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -5,11 +5,12 @@
// Does simple 'macro' substitution, using Django-like syntax,
// {{{ code }}} will be replaced with |eval(code)|.
+// NOTE: Be careful with that ret check. If ret is |0|, |ret ? ret.toString() : ''| would result in ''!
function processMacros(text) {
return text.replace(/{{{([^}]|}(?!}))+}}}/g, function(str) {
str = str.substr(3, str.length-6);
var ret = eval(str);
- return ret ? ret.toString() : '';
+ return ret !== null ? ret.toString() : '';
});
}
@@ -110,12 +111,22 @@ function isNiceIdent(ident, loose) {
}
function isJSVar(ident) {
- return /^\(?[$_]?[\w$_\d ]*\)+$/.test(ident);
-
+ if (ident[0] === '(') {
+ if (ident[ident.length-1] !== ')') return false;
+ ident = ident.substr(1, ident.length-2);
+ }
+ return /^[$_]?[\w$_\d]* *$/.test(ident);
}
function isLocalVar(ident) {
- return ident[0] == '$';
+ return ident[0] === '$';
+}
+
+// Simple variables or numbers, or things already quoted, do not need to be quoted
+function needsQuoting(ident) {
+ if (/^[-+]?[$_]?[\w$_\d]*$/.test(ident)) return false; // number or variable
+ if (ident[0] === '(' && ident[ident.length-1] === ')' && ident.indexOf('(', 1) < 0) return false; // already fully quoted
+ return true;
}
function isStructPointerType(type) {
@@ -752,10 +763,10 @@ function splitI64(value, floatConversion) {
if (floatConversion && ASM_JS) lowInput = asmFloatToInt(lowInput);
var low = lowInput + '>>>0';
var high = makeInlineCalculation(
- asmCoercion('Math.abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' +
+ asmCoercion('Math_abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' +
'(VALUE > ' + asmEnsureFloat('0', 'double') + ' ? ' +
- asmCoercion('Math.min(' + asmCoercion('Math.floor((VALUE)/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0' +
- ' : ' + asmFloatToInt(asmCoercion('Math.ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'float') + ')', 'double')) + '>>>0' +
+ asmCoercion('Math_min(' + asmCoercion('Math_floor((VALUE)/' + asmEnsureFloat(4294967296, 'float') + ')', 'double') + ', ' + asmEnsureFloat(4294967295, 'float') + ')', 'i32') + '>>>0' +
+ ' : ' + asmFloatToInt(asmCoercion('Math_ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'float') + ')', 'double')) + '>>>0' +
')' +
' : 0',
value,
@@ -919,7 +930,10 @@ function parseNumerical(value, type) {
}
if (isNumber(value)) {
var ret = parseFloat(value); // will change e.g. 5.000000e+01 to 50
- if (type in Runtime.FLOAT_TYPES && value[0] == '-' && ret === 0) return '-0'; // fix negative 0, toString makes it 0
+ if (type in Runtime.FLOAT_TYPES) {
+ if (value[0] === '-' && ret === 0) return '-.0'; // fix negative 0, toString makes it 0
+ if (!RUNNING_JS_OPTS) ret = asmEnsureFloat(ret, type);
+ }
return ret.toString();
} else {
return value;
@@ -932,12 +946,12 @@ function parseLLVMString(str) {
var ret = [];
var i = 0;
while (i < str.length) {
- var chr = str[i];
- if (chr != '\\') {
- ret.push(chr.charCodeAt(0));
+ var chr = str.charCodeAt(i);
+ if (chr !== 92) { // 92 === '//'.charCodeAt(0)
+ ret.push(chr);
i++;
} else {
- ret.push(eval('0x' + str[i+1]+str[i+2]));
+ ret.push(parseInt(str[i+1]+str[i+2], '16'));
i += 3;
}
}
@@ -1125,7 +1139,16 @@ function asmEnsureFloat(value, type) { // ensures that a float type has either 5
if (!ASM_JS) return value;
// coerce if missing a '.', or if smaller than 1, so could be 1e-5 which has no .
if (type in Runtime.FLOAT_TYPES && isNumber(value) && (value.toString().indexOf('.') < 0 || Math.abs(value) < 1)) {
- return '(+(' + value + '))';
+ if (RUNNING_JS_OPTS) {
+ return '(+' + value + ')'; // JS optimizer will run, we must do +x, and it will be corrected later
+ } else {
+ // ensure a .
+ value = value.toString();
+ if (value.indexOf('.') >= 0 || /[IN]/.test(value)) return value; // if already dotted, or Infinity or NaN, nothing to do here
+ var e = value.indexOf('e');
+ if (e < 0) return value + '.0';
+ return value.substr(0, e) + '.0' + value.substr(e);
+ }
} else {
return value;
}
@@ -1133,7 +1156,11 @@ function asmEnsureFloat(value, type) { // ensures that a float type has either 5
function asmInitializer(type, impl) {
if (type in Runtime.FLOAT_TYPES) {
- return '+0';
+ if (RUNNING_JS_OPTS) {
+ return '+0';
+ } else {
+ return '.0';
+ }
} else {
return '0';
}
@@ -1348,6 +1375,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
value = indexizeFunctions(value, type);
var offset = calcFastOffset(ptr, pos, noNeedFirst);
+ if (phase === 'pre' && isNumber(offset)) offset += ' '; // avoid pure numeric strings, seem to be perf issues with overly-aggressive interning or slt in pre processing of heap inits
if (SAFE_HEAP && !noSafe) {
var printType = type;
if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"';
@@ -1464,77 +1492,97 @@ function makeHEAPView(which, start, end) {
return 'HEAP' + which + '.subarray((' + start + ')' + mod + ',(' + end + ')' + mod + ')';
}
-var PLUS_MUL = set('+', '*');
-var MUL_DIV = set('*', '/');
-var PLUS_MINUS = set('+', '-');
var TWO_TWENTY = Math.pow(2, 20);
// Given two values and an operation, returns the result of that operation.
// Tries to do as much as possible at compile time.
// Leaves overflows etc. unhandled, *except* for integer multiply, in order to be efficient with Math.imul
function getFastValue(a, op, b, type) {
- a = a.toString();
- b = b.toString();
- a = a == 'true' ? '1' : (a == 'false' ? '0' : a);
- b = b == 'true' ? '1' : (b == 'false' ? '0' : b);
- if (isNumber(a) && isNumber(b)) {
- if (op == 'pow') {
- return Math.pow(a, b).toString();
- } else {
- var value = eval(a + op + '(' + b + ')'); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12"
- if (op == '/' && type in Runtime.INT_TYPES) value = value|0; // avoid emitting floats
- return value.toString();
+ a = a === 'true' ? '1' : (a === 'false' ? '0' : a);
+ b = b === 'true' ? '1' : (b === 'false' ? '0' : b);
+
+ var aNumber = null, bNumber = null;
+ if (typeof a === 'number') {
+ aNumber = a;
+ a = a.toString();
+ } else if (isNumber(a)) aNumber = parseFloat(a);
+ if (typeof b === 'number') {
+ bNumber = b;
+ b = b.toString();
+ } else if (isNumber(b)) bNumber = parseFloat(b);
+
+ if (aNumber !== null && bNumber !== null) {
+ switch (op) {
+ case '+': return (aNumber + bNumber).toString();
+ case '-': return (aNumber - bNumber).toString();
+ case '*': return (aNumber * bNumber).toString();
+ case '/': {
+ if (type[0] === 'i') {
+ return ((aNumber / bNumber)|0).toString();
+ } else {
+ return (aNumber / bNumber).toString();
+ }
+ }
+ case '%': return (aNumber % bNumber).toString();
+ case '|': return (aNumber | bNumber).toString();
+ case '>>>': return (aNumber >>> bNumber).toString();
+ case '&': return (aNumber & bNumber).toString();
+ case 'pow': return Math.pow(aNumber, bNumber).toString();
+ default: throw 'need to implement getFastValue pn ' + op;
}
}
- if (op == 'pow') {
- if (a == '2' && isIntImplemented(type)) {
+ if (op === 'pow') {
+ if (a === '2' && isIntImplemented(type)) {
return '(1 << (' + b + '))';
}
- return 'Math.pow(' + a + ', ' + b + ')';
+ return 'Math_pow(' + a + ', ' + b + ')';
}
- if (op in PLUS_MUL && isNumber(a)) { // if one of them is a number, keep it last
+ if ((op === '+' || op === '*') && aNumber !== null) { // if one of them is a number, keep it last
var c = b;
b = a;
a = c;
- }
- if (op in MUL_DIV) {
- if (op == '*') {
- if (a == 0 || b == 0) {
- return '0';
- } else if (a == 1) {
- return b;
- } else if (b == 1) {
- return a;
- } else if (isNumber(b) && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) {
- var shifts = Math.log(parseFloat(b))/Math.LN2;
- if (shifts % 1 == 0) {
- return '(' + a + '<<' + shifts + ')';
- }
+ var cNumber = bNumber;
+ bNumber = aNumber;
+ aNumber = cNumber;
+ }
+ if (op === '*') {
+ // We can't eliminate where a or b are 0 as that would break things for creating
+ // a negative 0.
+ if ((aNumber === 0 || bNumber === 0) && !(type in Runtime.FLOAT_TYPES)) {
+ return '0';
+ } else if (aNumber === 1) {
+ return b;
+ } else if (bNumber === 1) {
+ return a;
+ } else if (bNumber !== null && type && isIntImplemented(type) && Runtime.getNativeTypeSize(type) <= 32) {
+ var shifts = Math.log(bNumber)/Math.LN2;
+ if (shifts % 1 === 0) {
+ return '(' + a + '<<' + shifts + ')';
}
- if (!(type in Runtime.FLOAT_TYPES)) {
- // if guaranteed small enough to not overflow into a double, do a normal multiply
- var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes
- // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there
- if ((isNumber(a) && Math.abs(a) < TWO_TWENTY) || (isNumber(b) && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) {
- return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this
- }
- return '(Math.imul(' + a + ',' + b + ')|0)';
+ }
+ if (!(type in Runtime.FLOAT_TYPES)) {
+ // if guaranteed small enough to not overflow into a double, do a normal multiply
+ var bits = getBits(type) || 32; // default is 32-bit multiply for things like getelementptr indexes
+ // Note that we can emit simple multiple in non-asm.js mode, but asm.js will not parse "16-bit" multiple, so must do imul there
+ if ((aNumber !== null && Math.abs(a) < TWO_TWENTY) || (bNumber !== null && Math.abs(b) < TWO_TWENTY) || (bits < 32 && !ASM_JS)) {
+ return '(((' + a + ')*(' + b + '))&' + ((Math.pow(2, bits)-1)|0) + ')'; // keep a non-eliminatable coercion directly on this
}
- } else {
- if (a == '0') {
- return '0';
- } else if (b == 1) {
- return a;
- } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky
- }
- } else if (op in PLUS_MINUS) {
- if (b[0] == '-') {
- op = op == '+' ? '-' : '+';
+ return '(Math_imul(' + a + ',' + b + ')|0)';
+ }
+ } else if (op === '/') {
+ if (a === '0' && !(type in Runtime.FLOAT_TYPES)) { // careful on floats, since 0*NaN is not 0
+ return '0';
+ } else if (b === 1) {
+ return a;
+ } // Doing shifts for division is problematic, as getting the rounding right on negatives is tricky
+ } else if (op === '+' || op === '-') {
+ if (b[0] === '-') {
+ op = op === '+' ? '-' : '+';
b = b.substr(1);
}
- if (a == 0) {
- return op == '+' ? b : '(-' + b + ')';
- } else if (b == 0) {
+ if (aNumber === 0) {
+ return op === '+' ? b : '(-' + b + ')';
+ } else if (bNumber === 0) {
return a;
}
}
@@ -1563,12 +1611,8 @@ function getFastValues(list, op, type) {
}
function calcFastOffset(ptr, pos, noNeedFirst) {
- var offset = noNeedFirst ? '0' : makeGetPos(ptr);
- return getFastValue(offset, '+', pos, 'i32');
-}
-
-function makeGetPos(ptr) {
- return ptr;
+ assert(!noNeedFirst);
+ return getFastValue(ptr, '+', pos, 'i32');
}
var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP');
@@ -1758,7 +1802,7 @@ function checkBitcast(item) {
} else {
warnOnce('Casting a function pointer type to a potentially incompatible one (use -s VERBOSE=1 to see more)');
}
- warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidlinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts');
+ warnOnce('See https://github.com/kripken/emscripten/wiki/CodeGuidelinesAndLimitations#function-pointer-issues for more information on dangerous function pointer casts');
if (ASM_JS) warnOnce('Incompatible function pointer casts are very dangerous with ASM_JS=1, you should investigate and correct these');
}
if (oldCount != newCount && oldCount && newCount) showWarning();
@@ -1805,7 +1849,7 @@ function getGetElementPtrIndexes(item) {
// struct, and possibly further substructures, all embedded
// can also be to 'blocks': [8 x i32]*, not just structs
type = removePointing(type);
- var indexes = [makeGetPos(ident)];
+ var indexes = [ident];
var offset = item.params[1];
if (offset != 0) {
if (isStructType(type)) {
@@ -1860,8 +1904,10 @@ function handleOverflow(text, bits) {
if (CHECK_OVERFLOWS) return 'CHECK_OVERFLOW(' + text + ', ' + bits + ', ' + Math.floor(correctSpecificOverflow()) + ')';
if (!correct) return text;
if (bits == 32) {
+ if (isNumber(text)) return text | 0;
return '((' + text + ')|0)';
} else if (bits < 32) {
+ if (isNumber(text)) return text & (Math.pow(2, bits) - 1);
return '((' + text + ')&' + (Math.pow(2, bits) - 1) + ')';
} else {
return text; // We warned about this earlier
@@ -1951,7 +1997,7 @@ function makeComparison(a, op, b, type) {
return asmCoercion(a, type) + op + asmCoercion(b, type);
} else {
assert(type == 'i64');
- return asmCoercion(a + '$0', 'i32') + op + asmCoercion(b + '$0', 'i32') + ' & ' +
+ return asmCoercion(a + '$0', 'i32') + op + asmCoercion(b + '$0', 'i32') + '&' +
asmCoercion(a + '$1', 'i32') + op + asmCoercion(b + '$1', 'i32');
}
}
@@ -1960,13 +2006,12 @@ function makeSignOp(value, type, op, force, ignore) {
if (USE_TYPED_ARRAYS == 2 && type == 'i64') {
return value; // these are always assumed to be two 32-bit unsigneds.
}
-
if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints
if (!value) return value;
var bits, full;
if (type in Runtime.INT_TYPES) {
bits = parseInt(type.substr(1));
- full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || (correctSpecificSign())) + ')';
+ full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || correctSpecificSign()) + ')';
// Always sign/unsign constants at compile time, regardless of CHECK/CORRECT
if (isNumber(value)) {
return eval(full).toString();
@@ -1974,23 +2019,25 @@ function makeSignOp(value, type, op, force, ignore) {
}
if ((ignore || !correctSigns()) && !CHECK_SIGNS && !force) return value;
if (type in Runtime.INT_TYPES) {
+ // this is an integer, but not a number (or we would have already handled it)
// shortcuts
if (!CHECK_SIGNS || ignore) {
+ if (value === 'true') {
+ value = '1';
+ } else if (value === 'false') {
+ value = '0';
+ } else if (needsQuoting(value)) value = '(' + value + ')';
if (bits === 32) {
if (op === 're') {
- return '(' + getFastValue(value, '|', '0') + ')';
+ return '(' + value + '|0)';
} else {
-
- return '(' + getFastValue(value, '>>>', '0') + ')';
- // Alternatively, we can consider the lengthier
- // return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + ' + VALUE', value, 'tempBigInt');
- // which does not always turn us into a 32-bit *un*signed value
+ return '(' + value + '>>>0)';
}
} else if (bits < 32) {
if (op === 're') {
- return makeInlineCalculation('(VALUE << ' + (32-bits) + ') >> ' + (32-bits), value, 'tempInt');
+ return '((' + value + '<<' + (32-bits) + ')>>' + (32-bits) + ')';
} else {
- return '(' + getFastValue(value, '&', Math.pow(2, bits)-1) + ')';
+ return '(' + value + '&' + (Math.pow(2, bits)-1) + ')';
}
} else { // bits > 32
if (op === 're') {
@@ -2018,12 +2065,12 @@ function makeRounding(value, bits, signed, floatConversion) {
// as |0, but &-1 hints to the js optimizer that this is a rounding correction
// Do Math.floor, which is reasonably fast, if we either don't care, or if we can be sure
// the value is non-negative
- if (!correctRoundings() || (!signed && !floatConversion)) return 'Math.floor(' + value + ')';
+ if (!correctRoundings() || (!signed && !floatConversion)) return 'Math_floor(' + value + ')';
// We are left with >32 bits signed, or a float conversion. Check and correct inline
// Note that if converting a float, we may have the wrong sign at this point! But, we have
// been rounded properly regardless, and we will be sign-corrected later when actually used, if
// necessary.
- return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
+ return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR');
} else {
// asm.js mode, cleaner refactoring of this function as well. TODO: use in non-asm case, most of this
if (floatConversion && bits <= 32) {
@@ -2038,9 +2085,9 @@ function makeRounding(value, bits, signed, floatConversion) {
}
}
// Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned)
- if (!correctRoundings() || !signed) return 'Math.floor(' + value + ')';
+ if (!correctRoundings() || !signed) return 'Math_floor(' + value + ')';
// We are left with >32 bits
- return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
+ return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR');
}
}
@@ -2051,7 +2098,7 @@ function makeIsNaN(value) {
function makeFloat(value, type) {
if (TO_FLOAT32 && type == 'float') {
- return 'Math.toFloat32(' + value + ')';
+ return 'Math_toFloat32(' + value + ')';
}
return value;
}
@@ -2080,7 +2127,7 @@ function processMathop(item) {
if (item.params[i]) {
paramTypes[i] = item.params[i].type || type;
idents[i] = finalizeLLVMParameter(item.params[i]);
- if (!isNumber(idents[i]) && !isNiceIdent(idents[i])) {
+ if (needsQuoting(idents[i])) {
idents[i] = '(' + idents[i] + ')'; // we may have nested expressions. So enforce the order of operations we want
}
} else {
@@ -2127,7 +2174,13 @@ function processMathop(item) {
// If this is in legalization mode, steal the assign and assign into two vars
if (legalizedI64s) {
assert(item.assignTo);
- var ret = 'var ' + item.assignTo + '$0 = ' + result[0] + '; var ' + item.assignTo + '$1 = ' + result[1] + ';';
+ if (ASM_JS) {
+ var ret = item.assignTo + '$0=' + result[0] + ';' + item.assignTo + '$1=' + result[1] + ';';
+ addVariable(item.assignTo + '$0', 'i32');
+ addVariable(item.assignTo + '$1', 'i32');
+ } else {
+ var ret = 'var ' + item.assignTo + '$0=' + result[0] + ';var ' + item.assignTo + '$1=' + result[1] + ';';
+ }
item.assignTo = null;
return ret;
} else {
@@ -2278,7 +2331,7 @@ function processMathop(item) {
dprint('Warning: 64 bit OR - precision limit may be hit on llvm line ' + item.lineNum);
return 'Runtime.or64(' + idents[0] + ', ' + idents[1] + ')';
}
- return idents[0] + ' | ' + idents[1];
+ return idents[0] + '|' + idents[1];
}
case 'and': {
if (bits > 32) {
@@ -2286,7 +2339,7 @@ function processMathop(item) {
dprint('Warning: 64 bit AND - precision limit may be hit on llvm line ' + item.lineNum);
return 'Runtime.and64(' + idents[0] + ', ' + idents[1] + ')';
}
- return idents[0] + ' & ' + idents[1];
+ return idents[0] + '&' + idents[1];
}
case 'xor': {
if (bits > 32) {
@@ -2294,21 +2347,21 @@ function processMathop(item) {
dprint('Warning: 64 bit XOR - precision limit may be hit on llvm line ' + item.lineNum);
return 'Runtime.xor64(' + idents[0] + ', ' + idents[1] + ')';
}
- return idents[0] + ' ^ ' + idents[1];
+ return idents[0] + '^' + idents[1];
}
case 'shl': {
if (bits > 32) return idents[0] + '*' + getFastValue(2, 'pow', idents[1]);
- return idents[0] + ' << ' + idents[1];
+ return idents[0] + '<<' + idents[1];
}
case 'ashr': {
if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1]));
- if (bits === 32) return originalIdents[0] + ' >> ' + idents[1]; // No need to reSign in this case
- return idents[0] + ' >> ' + idents[1];
+ if (bits === 32) return originalIdents[0] + '>>' + idents[1]; // No need to reSign in this case
+ return idents[0] + '>>' + idents[1];
}
case 'lshr': {
if (bits > 32) return integerizeBignum(idents[0] + '/' + getFastValue(2, 'pow', idents[1]));
- if (bits === 32) return originalIdents[0] + ' >>> ' + idents[1]; // No need to unSign in this case
- return idents[0] + ' >>> ' + idents[1];
+ if (bits === 32) return originalIdents[0] + '>>>' + idents[1]; // No need to unSign in this case
+ return idents[0] + '>>>' + idents[1];
}
// basic float ops
case 'fadd': return makeFloat(getFastValue(idents[0], '+', idents[1], item.type), item.type);
@@ -2323,10 +2376,10 @@ function processMathop(item) {
// Note that with typed arrays, these become 0 when written. So that is a potential difference with non-typed array runs.
case 'icmp': {
switch (variant) {
- case 'uge': case 'sge': return idents[0] + ' >= ' + idents[1];
- case 'ule': case 'sle': return idents[0] + ' <= ' + idents[1];
- case 'ugt': case 'sgt': return idents[0] + ' > ' + idents[1];
- case 'ult': case 'slt': return idents[0] + ' < ' + idents[1];
+ case 'uge': case 'sge': return idents[0] + '>=' + idents[1];
+ case 'ule': case 'sle': return idents[0] + '<=' + idents[1];
+ case 'ugt': case 'sgt': return idents[0] + '>' + idents[1];
+ case 'ult': case 'slt': return idents[0] + '<' + idents[1];
// We use loose comparisons, which allows false == 0 to be true, etc. Ditto in fcmp
case 'ne': case 'eq': {
// We must sign them, so we do not compare -1 to 255 (could have unsigned them both too)
@@ -2342,14 +2395,14 @@ function processMathop(item) {
switch (variant) {
// TODO 'o' ones should be 'ordered (no NaN) and',
// 'u' ones should be 'unordered or'.
- case 'uge': case 'oge': return idents[0] + ' >= ' + idents[1];
- case 'ule': case 'ole': return idents[0] + ' <= ' + idents[1];
- case 'ugt': case 'ogt': return idents[0] + ' > ' + idents[1];
- case 'ult': case 'olt': return idents[0] + ' < ' + idents[1];
- case 'une': case 'one': return idents[0] + ' != ' + idents[1];
- case 'ueq': case 'oeq': return idents[0] + ' == ' + idents[1];
- case 'ord': return '!' + makeIsNaN(idents[0]) + ' & !' + makeIsNaN(idents[1]);
- case 'uno': return makeIsNaN(idents[0]) + ' | ' + makeIsNaN(idents[1]);
+ case 'uge': case 'oge': return idents[0] + '>=' + idents[1];
+ case 'ule': case 'ole': return idents[0] + '<=' + idents[1];
+ case 'ugt': case 'ogt': return idents[0] + '>' + idents[1];
+ case 'ult': case 'olt': return idents[0] + '<' + idents[1];
+ case 'une': case 'one': return idents[0] + '!=' + idents[1];
+ case 'ueq': case 'oeq': return idents[0] + '==' + idents[1];
+ case 'ord': return '!' + makeIsNaN(idents[0]) + '&!' + makeIsNaN(idents[1]);
+ case 'uno': return makeIsNaN(idents[0]) + '|' + makeIsNaN(idents[1]);
case 'true': return '1';
default: throw 'Unknown fcmp variant: ' + variant;
}
@@ -2365,7 +2418,7 @@ function processMathop(item) {
}
case 'fpext': case 'sext': return idents[0];
case 'fptrunc': return idents[0];
- case 'select': return idents[0] + ' ? ' + asmEnsureFloat(idents[1], item.type) + ' : ' + asmEnsureFloat(idents[2], item.type);
+ case 'select': return idents[0] + '?' + asmEnsureFloat(idents[1], item.type) + ':' + asmEnsureFloat(idents[2], item.type);
case 'ptrtoint': case 'inttoptr': {
var ret = '';
if (QUANTUM_SIZE == 1) {
@@ -2383,7 +2436,7 @@ function processMathop(item) {
// truncating can change the number, e.g. by truncating to an i1
// in order to get the first bit
assert(bitsLeft <= 32, 'Cannot truncate to more than 32 bits, since we use a native & op');
- return '((' + idents[0] + ') & ' + (Math.pow(2, bitsLeft)-1) + ')';
+ return '((' + idents[0] + ')&' + (Math.pow(2, bitsLeft)-1) + ')';
}
case 'bitcast': {
// Most bitcasts are no-ops for us. However, the exception is int to float and float to int
@@ -2519,3 +2572,34 @@ function makePrintChars(s, sep) {
return ret;
}
+function parseAlign(text) { // parse ", align \d+"
+ if (!text) return QUANTUM_SIZE;
+ return parseInt(text.substr(8));
+}
+
+function deParen(text) {
+ if (text[0] === '(') return text.substr(1, text.length-2);
+ return text;
+}
+
+function addVariable(ident, type, funcData) {
+ funcData = funcData || Framework.currItem.funcData;
+ assert(type);
+ var old = funcData.variables[ident];
+ if (old) {
+ assert(old.type === type);
+ } else {
+ funcData.variables[ident] = {
+ ident: ident,
+ type: type,
+ origin: 'added',
+ lineNum: 0,
+ rawLinesIndex: 0,
+ hasValueTaken: false,
+ pointingLevels: 0,
+ uses: 0,
+ impl: VAR_EMULATED
+ };
+ }
+}
+
diff --git a/src/preamble.js b/src/preamble.js
index acff665f..88aaff77 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -299,11 +299,10 @@ function ccallFunc(func, returnType, argTypes, args) {
function toC(value, type) {
if (type == 'string') {
if (value === null || value === undefined || value === 0) return 0; // null string
- if (!stack) stack = Runtime.stackSave();
- var ret = Runtime.stackAlloc(value.length+1);
- writeStringToMemory(value, ret);
- return ret;
- } else if (type == 'array') {
+ value = intArrayFromString(value);
+ type = 'array';
+ }
+ if (type == 'array') {
if (!stack) stack = Runtime.stackSave();
var ret = Runtime.stackAlloc(value.length);
writeArrayToMemory(value, ret);
@@ -645,7 +644,7 @@ Module['stringToUTF32'] = stringToUTF32;
var PAGE_SIZE = 4096;
function alignMemoryPage(x) {
- return ((x+4095)>>12)<<12;
+ return (x+4095)&-4096;
}
var HEAP;
@@ -717,7 +716,7 @@ var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}};
// Initialize the runtime's memory
#if USE_TYPED_ARRAYS
// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
-assert(!!Int32Array && !!Float64Array && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
+assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
'Cannot fallback to non-typed array case: Code is too specialized');
#if USE_TYPED_ARRAYS == 1
@@ -944,6 +943,24 @@ if (!Math['toFloat32']) Math['toFloat32'] = function(x) {
Math.toFloat32 = Math['toFloat32'];
#endif
+var Math_abs = Math.abs;
+var Math_cos = Math.cos;
+var Math_sin = Math.sin;
+var Math_tan = Math.tan;
+var Math_acos = Math.acos;
+var Math_asin = Math.asin;
+var Math_atan = Math.atan;
+var Math_atan2 = Math.atan2;
+var Math_exp = Math.exp;
+var Math_log = Math.log;
+var Math_sqrt = Math.sqrt;
+var Math_ceil = Math.ceil;
+var Math_floor = Math.floor;
+var Math_pow = Math.pow;
+var Math_imul = Math.imul;
+var Math_toFloat32 = Math.toFloat32;
+var Math_min = Math.min;
+
// A counter of dependencies for calling run(). If we need to
// do asynchronous work before running, increment this and
// decrement it. Incrementing must happen in a place like
diff --git a/src/runtime.js b/src/runtime.js
index 00031fed..e36068c8 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -32,8 +32,8 @@ var RuntimeGenerator = {
stackEnter: function(initial, force) {
if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return '';
- var ret = 'var sp = ' + (ASM_JS ? '0; sp = ' : '') + 'STACKTOP';
- if (initial > 0) ret += '; STACKTOP = (STACKTOP + ' + initial + ')|0';
+ var ret = 'var sp=' + (ASM_JS ? '0;sp=' : '') + 'STACKTOP';
+ if (initial > 0) ret += ';STACKTOP=(STACKTOP+' + initial + ')|0';
if (USE_TYPED_ARRAYS == 2) {
assert(initial % Runtime.STACK_ALIGN == 0);
if (ASSERTIONS && Runtime.STACK_ALIGN == 4) {
@@ -43,9 +43,6 @@ var RuntimeGenerator = {
if (ASSERTIONS) {
ret += '; (assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')|0)';
}
- if (false) {
- ret += '; _memset(' + asmCoercion('sp', 'i32') + ', 0, ' + initial + ')';
- }
return ret;
},
@@ -55,7 +52,7 @@ var RuntimeGenerator = {
if (SAFE_HEAP) {
ret += 'var i = sp; while ((i|0) < (STACKTOP|0)) { SAFE_HEAP_CLEAR(i|0); i = (i+1)|0 }';
}
- return ret += 'STACKTOP = sp';
+ return ret += 'STACKTOP=sp';
},
// An allocation that cannot normally be free'd (except through sbrk, which once
@@ -112,8 +109,7 @@ var Runtime = {
if (isNumber(target) && isNumber(quantum)) {
return Math.ceil(target/quantum)*quantum;
} else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
- var logg = log2(quantum);
- return '((((' +target + ')+' + (quantum-1) + ')>>' + logg + ')<<' + logg + ')';
+ return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
}
return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
},
@@ -347,22 +343,23 @@ var Runtime = {
for (var i = 0; i < Runtime.functionPointers.length; i++) {
if (!Runtime.functionPointers[i]) {
Runtime.functionPointers[i] = func;
- return 2 + 2*i;
+ return {{{ FUNCTION_POINTER_ALIGNMENT }}}*(1 + i);
}
}
throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
#else
var table = FUNCTION_TABLE;
var ret = table.length;
+ assert(ret % {{{ FUNCTION_POINTER_ALIGNMENT }}} === 0);
table.push(func);
- table.push(0);
+ for (var i = 0; i < {{{ FUNCTION_POINTER_ALIGNMENT }}}-1; i++) table.push(0);
return ret;
#endif
},
removeFunction: function(index) {
#if ASM_JS
- Runtime.functionPointers[(index-2)/2] = null;
+ Runtime.functionPointers[(index-{{{ FUNCTION_POINTER_ALIGNMENT }}})/{{{ FUNCTION_POINTER_ALIGNMENT }}}] = null;
#else
var table = FUNCTION_TABLE;
table[index] = null;
diff --git a/src/settings.js b/src/settings.js
index 15bca4db..d2b47dc8 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -170,6 +170,12 @@ var ALIASING_FUNCTION_POINTERS = 0; // Whether to allow function pointers to ali
// a different type. This can greatly decrease table sizes
// in asm.js, but can break code that compares function
// pointers across different types.
+var FUNCTION_POINTER_ALIGNMENT = 2; // Byte alignment of function pointers - we will fill the
+ // tables with zeros on aligned values. 1 means all values
+ // are aligned and all will be used (which is optimal).
+ // Sadly 1 breaks on &Class::method function pointer calls,
+ // which llvm assumes have the lower bit zero (see
+ // test_polymorph and issue #1692).
var ASM_HEAP_LOG = 0; // Simple heap logging, like SAFE_HEAP_LOG but cheaper, and in asm.js
@@ -202,6 +208,7 @@ var SOCKET_WEBRTC = 0; // Select socket backend, either webrtc or websockets.
var OPENAL_DEBUG = 0; // Print out debugging information from our OpenAL implementation.
+var GL_ASSERTIONS = 0; // Adds extra checks for error situations in the GL library. Can impact performance.
var GL_DEBUG = 0; // Print out all calls into WebGL. As with LIBRARY_DEBUG, you can set a runtime
// option, in this case GL.debug.
var GL_TESTING = 0; // When enabled, sets preserveDrawingBuffer in the context, to allow tests to work (but adds overhead)
@@ -265,6 +272,8 @@ var CORRECT_ROUNDINGS = 1; // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS ha
var FS_LOG = 0; // Log all FS operations. This is especially helpful when you're porting
// a new project and want to see a list of file system operations happening
// so that you can create a virtual file system with all of the required files.
+var CASE_INSENSITIVE_FS = 0; // If set to nonzero, the provided virtual filesystem if treated case-insensitive, like
+ // Windows and OSX do. If set to 0, the VFS is case-sensitive, like on Linux.
var USE_BSS = 1; // https://en.wikipedia.org/wiki/.bss
// When enabled, 0-initialized globals are sorted to the end of the globals list,
@@ -418,13 +427,16 @@ var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i3
var NECESSARY_BLOCKADDRS = []; // List of (function, block) for all block addresses that are taken.
-var EMIT_GENERATED_FUNCTIONS = 0; // whether to emit the list of generated functions, needed for external JS optimization passes
-
var JS_CHUNK_SIZE = 10240; // Used as a maximum size before breaking up expressions and lines into smaller pieces
var EXPORT_NAME = 'Module'; // Global variable to export the module as for environments without a standardized module
// loading system (e.g. the browser and SM shell).
+var RUNNING_JS_OPTS = 0; // whether js opts will be run, after the main compiler
+
+var COMPILER_ASSERTIONS = 0; // costly (slow) compile-time assertions
+var COMPILER_FASTPATHS = 1; // use fast-paths to speed up compilation
+
// Compiler debugging options
var DEBUG_TAGS_SHOWING = [];
// Some useful items:
@@ -438,427 +450,7 @@ var DEBUG_TAGS_SHOWING = [];
// metadata
// legalizer
-// A cached set of defines, generated from the header files. This
-// lets the emscripten libc (library.js) see the right values.
-// If you modify the headers or use different ones, you will need
-// to override this.
-var C_DEFINES = {
- 'ABDAY_1': '131072',
- 'ABDAY_2': '131073',
- 'ABDAY_3': '131074',
- 'ABDAY_4': '131075',
- 'ABDAY_5': '131076',
- 'ABDAY_6': '131077',
- 'ABDAY_7': '131078',
- 'ABMON_1': '131086',
- 'ABMON_10': '131095',
- 'ABMON_11': '131096',
- 'ABMON_12': '131097',
- 'ABMON_2': '131087',
- 'ABMON_3': '131088',
- 'ABMON_4': '131089',
- 'ABMON_5': '131090',
- 'ABMON_6': '131091',
- 'ABMON_7': '131092',
- 'ABMON_8': '131093',
- 'ABMON_9': '131094',
- 'AF_INET': '2',
- 'AF_INET6': '10',
- 'AF_UNSPEC': '0',
- 'AI_ADDRCONFIG': '32',
- 'AI_ALL': '16',
- 'AI_CANONNAME': '2',
- 'AI_NUMERICHOST': '4',
- 'AI_NUMERICSERV': '1024',
- 'AI_PASSIVE': '1',
- 'AI_V4MAPPED': '8',
- 'ALT_DIGITS': '131119',
- 'AM_STR': '131110',
- 'CLOCKS_PER_SEC': '1000000',
- 'CODESET': '14',
- 'CRNCYSTR': '262159',
- 'DAY_1': '131079',
- 'DAY_2': '131080',
- 'DAY_3': '131081',
- 'DAY_4': '131082',
- 'DAY_5': '131083',
- 'DAY_6': '131084',
- 'DAY_7': '131085',
- 'D_FMT': '131113',
- 'D_T_FMT': '131112',
- 'E2BIG': '7',
- 'EACCES': '13',
- 'EADDRINUSE': '98',
- 'EADDRNOTAVAIL': '99',
- 'EADV': '68',
- 'EAFNOSUPPORT': '97',
- 'EAGAIN': '11',
- 'EAI_BADFLAGS': '-1',
- 'EAI_FAMILY': '-6',
- 'EAI_NONAME': '-2',
- 'EAI_OVERFLOW': '-12',
- 'EAI_SERVICE': '-8',
- 'EAI_SOCKTYPE': '-7',
- 'EALREADY': '114',
- 'EBADE': '52',
- 'EBADF': '9',
- 'EBADFD': '77',
- 'EBADMSG': '74',
- 'EBADR': '53',
- 'EBADRQC': '56',
- 'EBADSLT': '57',
- 'EBFONT': '59',
- 'EBUSY': '16',
- 'ECANCELED': '125',
- 'ECHILD': '10',
- 'ECHRNG': '44',
- 'ECOMM': '70',
- 'ECONNABORTED': '103',
- 'ECONNREFUSED': '111',
- 'ECONNRESET': '104',
- 'EDEADLK': '35',
- 'EDEADLOCK': '35',
- 'EDESTADDRREQ': '89',
- 'EDOM': '33',
- 'EDOTDOT': '73',
- 'EDQUOT': '122',
- 'EEXIST': '17',
- 'EFAULT': '14',
- 'EFBIG': '27',
- 'EHOSTDOWN': '112',
- 'EHOSTUNREACH': '113',
- 'EIDRM': '43',
- 'EILSEQ': '84',
- 'EINPROGRESS': '115',
- 'EINTR': '4',
- 'EINVAL': '22',
- 'EIO': '5',
- 'EISCONN': '106',
- 'EISDIR': '21',
- 'EL2HLT': '51',
- 'EL2NSYNC': '45',
- 'EL3HLT': '46',
- 'EL3RST': '47',
- 'ELIBACC': '79',
- 'ELIBBAD': '80',
- 'ELIBEXEC': '83',
- 'ELIBMAX': '82',
- 'ELIBSCN': '81',
- 'ELNRNG': '48',
- 'ELOOP': '40',
- 'EMFILE': '24',
- 'EMLINK': '31',
- 'EMSGSIZE': '90',
- 'EMULTIHOP': '72',
- 'ENAMETOOLONG': '36',
- 'ENETDOWN': '100',
- 'ENETRESET': '102',
- 'ENETUNREACH': '101',
- 'ENFILE': '23',
- 'ENOANO': '55',
- 'ENOBUFS': '105',
- 'ENOCSI': '50',
- 'ENODATA': '61',
- 'ENODEV': '19',
- 'ENOENT': '2',
- 'ENOEXEC': '8',
- 'ENOLCK': '37',
- 'ENOLINK': '67',
- 'ENOMEDIUM': '123',
- 'ENOMEM': '12',
- 'ENOMSG': '42',
- 'ENONET': '64',
- 'ENOPKG': '65',
- 'ENOPROTOOPT': '92',
- 'ENOSPC': '28',
- 'ENOSR': '63',
- 'ENOSTR': '60',
- 'ENOSYS': '38',
- 'ENOTBLK': '15',
- 'ENOTCONN': '107',
- 'ENOTDIR': '20',
- 'ENOTEMPTY': '39',
- 'ENOTRECOVERABLE': '131',
- 'ENOTSOCK': '88',
- 'ENOTSUP': '95',
- 'ENOTTY': '25',
- 'ENOTUNIQ': '76',
- 'ENXIO': '6',
- 'EOF': '-1',
- 'EOPNOTSUPP': '95',
- 'EOVERFLOW': '75',
- 'EOWNERDEAD': '130',
- 'EPERM': '1',
- 'EPFNOSUPPORT': '96',
- 'EPIPE': '32',
- 'EPROTO': '71',
- 'EPROTONOSUPPORT': '93',
- 'EPROTOTYPE': '91',
- 'ERA': '131116',
- 'ERANGE': '34',
- 'ERA_D_FMT': '131118',
- 'ERA_D_T_FMT': '131120',
- 'ERA_T_FMT': '131121',
- 'EREMCHG': '78',
- 'EREMOTE': '66',
- 'EROFS': '30',
- 'ESHUTDOWN': '108',
- 'ESOCKTNOSUPPORT': '94',
- 'ESPIPE': '29',
- 'ESRCH': '3',
- 'ESRMNT': '69',
- 'ESTALE': '116',
- 'ESTRPIPE': '86',
- 'ETIME': '62',
- 'ETIMEDOUT': '110',
- 'ETOOMANYREFS': '109',
- 'ETXTBSY': '26',
- 'EUNATCH': '49',
- 'EUSERS': '87',
- 'EWOULDBLOCK': '11',
- 'EXDEV': '18',
- 'EXFULL': '54',
- 'FIONREAD': '21531',
- 'FP_INFINITE': '1',
- 'FP_NAN': '0',
- 'FP_NORMAL': '4',
- 'FP_ZERO': '2',
- 'F_DUPFD': '0',
- 'F_GETFD': '1',
- 'F_GETFL': '3',
- 'F_GETLK': '12',
- 'F_GETLK64': '12',
- 'F_GETOWN': '9',
- 'F_SETFD': '2',
- 'F_SETFL': '4',
- 'F_SETLK': '13',
- 'F_SETLK64': '13',
- 'F_SETLKW': '14',
- 'F_SETLKW64': '14',
- 'F_SETOWN': '8',
- 'F_UNLCK': '2',
- 'INADDR_LOOPBACK': '2130706433',
- 'IPPROTO_TCP': '6',
- 'IPPROTO_UDP': '17',
- 'MAP_PRIVATE': '2',
- 'MON_1': '131098',
- 'MON_10': '131107',
- 'MON_11': '131108',
- 'MON_12': '131109',
- 'MON_2': '131099',
- 'MON_3': '131100',
- 'MON_4': '131101',
- 'MON_5': '131102',
- 'MON_6': '131103',
- 'MON_7': '131104',
- 'MON_8': '131105',
- 'MON_9': '131106',
- 'NI_NAMEREQD': '8',
- 'NI_NUMERICHOST': '1',
- 'NOEXPR': '327681',
- 'O_ACCMODE': '2097155',
- 'O_APPEND': '1024',
- 'O_CREAT': '64',
- 'O_EXCL': '128',
- 'O_NOFOLLOW': '131072',
- 'O_RDONLY': '0',
- 'O_RDWR': '2',
- 'O_SYNC': '1052672',
- 'O_TRUNC': '512',
- 'O_WRONLY': '1',
- 'PM_STR': '131111',
- 'POLLERR': '8',
- 'POLLHUP': '16',
- 'POLLIN': '1',
- 'POLLNVAL': '32',
- 'POLLOUT': '4',
- 'POLLPRI': '2',
- 'POLLRDNORM': '64',
- 'RADIXCHAR': '65536',
- 'R_OK': '4',
- 'SEEK_END': '2',
- 'SEEK_SET': '0',
- 'SOCK_DGRAM': '2',
- 'SOCK_STREAM': '1',
- 'S_IALLUGO': '4095',
- 'S_IFBLK': '24576',
- 'S_IFCHR': '8192',
- 'S_IFDIR': '16384',
- 'S_IFIFO': '4096',
- 'S_IFLNK': '40960',
- 'S_IFMT': '61440',
- 'S_IFREG': '32768',
- 'S_IFSOCK': '49152',
- 'S_IRUGO': '292',
- 'S_IRWXO': '7',
- 'S_IRWXUGO': '511',
- 'S_ISVTX': '512',
- 'S_IWUGO': '146',
- 'S_IXUGO': '73',
- 'THOUSEP': '65537',
- 'T_FMT': '131114',
- 'T_FMT_AMPM': '131115',
- 'W_OK': '2',
- 'X_OK': '1',
- 'YESEXPR': '327680',
- '_CS_GNU_LIBC_VERSION': '2',
- '_CS_GNU_LIBPTHREAD_VERSION': '3',
- '_CS_PATH': '0',
- '_CS_POSIX_V6_ILP32_OFF32_CFLAGS': '1116',
- '_CS_POSIX_V6_ILP32_OFF32_LDFLAGS': '1117',
- '_CS_POSIX_V6_ILP32_OFF32_LIBS': '1118',
- '_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS': '1120',
- '_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS': '1121',
- '_CS_POSIX_V6_ILP32_OFFBIG_LIBS': '1122',
- '_CS_POSIX_V6_LP64_OFF64_CFLAGS': '1124',
- '_CS_POSIX_V6_LP64_OFF64_LDFLAGS': '1125',
- '_CS_POSIX_V6_LP64_OFF64_LIBS': '1126',
- '_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS': '1128',
- '_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS': '1129',
- '_CS_POSIX_V6_LPBIG_OFFBIG_LIBS': '1130',
- '_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS': '1',
- '_PC_2_SYMLINKS': '20',
- '_PC_ALLOC_SIZE_MIN': '18',
- '_PC_ASYNC_IO': '10',
- '_PC_CHOWN_RESTRICTED': '6',
- '_PC_FILESIZEBITS': '13',
- '_PC_LINK_MAX': '0',
- '_PC_MAX_CANON': '1',
- '_PC_MAX_INPUT': '2',
- '_PC_NAME_MAX': '3',
- '_PC_NO_TRUNC': '7',
- '_PC_PATH_MAX': '4',
- '_PC_PIPE_BUF': '5',
- '_PC_PRIO_IO': '11',
- '_PC_REC_INCR_XFER_SIZE': '14',
- '_PC_REC_MAX_XFER_SIZE': '15',
- '_PC_REC_MIN_XFER_SIZE': '16',
- '_PC_REC_XFER_ALIGN': '17',
- '_PC_SOCK_MAXBUF': '12',
- '_PC_SYMLINK_MAX': '19',
- '_PC_SYNC_IO': '9',
- '_PC_VDISABLE': '8',
- '_SC_2_CHAR_TERM': '95',
- '_SC_2_C_BIND': '47',
- '_SC_2_C_DEV': '48',
- '_SC_2_FORT_DEV': '49',
- '_SC_2_FORT_RUN': '50',
- '_SC_2_LOCALEDEF': '52',
- '_SC_2_PBS': '168',
- '_SC_2_PBS_ACCOUNTING': '169',
- '_SC_2_PBS_CHECKPOINT': '175',
- '_SC_2_PBS_LOCATE': '170',
- '_SC_2_PBS_MESSAGE': '171',
- '_SC_2_PBS_TRACK': '172',
- '_SC_2_SW_DEV': '51',
- '_SC_2_UPE': '97',
- '_SC_2_VERSION': '46',
- '_SC_ADVISORY_INFO': '132',
- '_SC_AIO_LISTIO_MAX': '23',
- '_SC_AIO_MAX': '24',
- '_SC_AIO_PRIO_DELTA_MAX': '25',
- '_SC_ARG_MAX': '0',
- '_SC_ASYNCHRONOUS_IO': '12',
- '_SC_ATEXIT_MAX': '87',
- '_SC_BARRIERS': '133',
- '_SC_BC_BASE_MAX': '36',
- '_SC_BC_DIM_MAX': '37',
- '_SC_BC_SCALE_MAX': '38',
- '_SC_BC_STRING_MAX': '39',
- '_SC_CHILD_MAX': '1',
- '_SC_CLK_TCK': '2',
- '_SC_CLOCK_SELECTION': '137',
- '_SC_COLL_WEIGHTS_MAX': '40',
- '_SC_CPUTIME': '138',
- '_SC_DELAYTIMER_MAX': '26',
- '_SC_EXPR_NEST_MAX': '42',
- '_SC_FSYNC': '15',
- '_SC_GETGR_R_SIZE_MAX': '69',
- '_SC_GETPW_R_SIZE_MAX': '70',
- '_SC_HOST_NAME_MAX': '180',
- '_SC_IOV_MAX': '60',
- '_SC_IPV6': '235',
- '_SC_JOB_CONTROL': '7',
- '_SC_LINE_MAX': '43',
- '_SC_LOGIN_NAME_MAX': '71',
- '_SC_MAPPED_FILES': '16',
- '_SC_MEMLOCK': '17',
- '_SC_MEMLOCK_RANGE': '18',
- '_SC_MEMORY_PROTECTION': '19',
- '_SC_MESSAGE_PASSING': '20',
- '_SC_MONOTONIC_CLOCK': '149',
- '_SC_MQ_OPEN_MAX': '27',
- '_SC_MQ_PRIO_MAX': '28',
- '_SC_NGROUPS_MAX': '3',
- '_SC_NPROCESSORS_ONLN': '84',
- '_SC_OPEN_MAX': '4',
- '_SC_PAGE_SIZE': '30',
- '_SC_PRIORITIZED_IO': '13',
- '_SC_PRIORITY_SCHEDULING': '10',
- '_SC_RAW_SOCKETS': '236',
- '_SC_READER_WRITER_LOCKS': '153',
- '_SC_REALTIME_SIGNALS': '9',
- '_SC_REGEXP': '155',
- '_SC_RE_DUP_MAX': '44',
- '_SC_RTSIG_MAX': '31',
- '_SC_SAVED_IDS': '8',
- '_SC_SEMAPHORES': '21',
- '_SC_SEM_NSEMS_MAX': '32',
- '_SC_SEM_VALUE_MAX': '33',
- '_SC_SHARED_MEMORY_OBJECTS': '22',
- '_SC_SHELL': '157',
- '_SC_SIGQUEUE_MAX': '34',
- '_SC_SPAWN': '159',
- '_SC_SPIN_LOCKS': '154',
- '_SC_SPORADIC_SERVER': '160',
- '_SC_STREAM_MAX': '5',
- '_SC_SYMLOOP_MAX': '173',
- '_SC_SYNCHRONIZED_IO': '14',
- '_SC_THREADS': '67',
- '_SC_THREAD_ATTR_STACKADDR': '77',
- '_SC_THREAD_ATTR_STACKSIZE': '78',
- '_SC_THREAD_CPUTIME': '139',
- '_SC_THREAD_DESTRUCTOR_ITERATIONS': '73',
- '_SC_THREAD_KEYS_MAX': '74',
- '_SC_THREAD_PRIORITY_SCHEDULING': '79',
- '_SC_THREAD_PRIO_INHERIT': '80',
- '_SC_THREAD_PRIO_PROTECT': '81',
- '_SC_THREAD_PROCESS_SHARED': '82',
- '_SC_THREAD_SAFE_FUNCTIONS': '68',
- '_SC_THREAD_SPORADIC_SERVER': '161',
- '_SC_THREAD_STACK_MIN': '75',
- '_SC_THREAD_THREADS_MAX': '76',
- '_SC_TIMEOUTS': '164',
- '_SC_TIMERS': '11',
- '_SC_TIMER_MAX': '35',
- '_SC_TRACE': '181',
- '_SC_TRACE_EVENT_FILTER': '182',
- '_SC_TRACE_EVENT_NAME_MAX': '242',
- '_SC_TRACE_INHERIT': '183',
- '_SC_TRACE_LOG': '184',
- '_SC_TRACE_NAME_MAX': '243',
- '_SC_TRACE_SYS_MAX': '244',
- '_SC_TRACE_USER_EVENT_MAX': '245',
- '_SC_TTY_NAME_MAX': '72',
- '_SC_TYPED_MEMORY_OBJECTS': '165',
- '_SC_TZNAME_MAX': '6',
- '_SC_V6_ILP32_OFF32': '176',
- '_SC_V6_ILP32_OFFBIG': '177',
- '_SC_V6_LP64_OFF64': '178',
- '_SC_V6_LPBIG_OFFBIG': '179',
- '_SC_VERSION': '29',
- '_SC_XBS5_ILP32_OFF32': '125',
- '_SC_XBS5_ILP32_OFFBIG': '126',
- '_SC_XBS5_LP64_OFF64': '127',
- '_SC_XBS5_LPBIG_OFFBIG': '128',
- '_SC_XOPEN_CRYPT': '92',
- '_SC_XOPEN_ENH_I18N': '93',
- '_SC_XOPEN_LEGACY': '129',
- '_SC_XOPEN_REALTIME': '130',
- '_SC_XOPEN_REALTIME_THREADS': '131',
- '_SC_XOPEN_SHM': '94',
- '_SC_XOPEN_STREAMS': '246',
- '_SC_XOPEN_UNIX': '91',
- '_SC_XOPEN_VERSION': '89'
-};
-
+// The list of defines (C_DEFINES) was moved into struct_info.json in the same directory.
+// That file is automatically parsed by tools/gen_struct_info.py.
+// If you modify the headers, just clear your cache and emscripten libc should see
+// the new values.
diff --git a/src/struct_info.json b/src/struct_info.json
new file mode 100644
index 00000000..5b4726e8
--- /dev/null
+++ b/src/struct_info.json
@@ -0,0 +1,1045 @@
+[
+ // ===========================================
+ // libc
+ // ===========================================
+ {
+ "file": "libc/dirent.h",
+ "defines": [],
+ "structs": {
+ "dirent": [
+ "d_ino",
+ "d_off",
+ "d_reclen",
+ "d_type",
+ "d_name"
+ ]
+ }
+ },
+ {
+ "file": "libc/utime.h",
+ "defines": [],
+ "structs": {
+ "utimbuf": [
+ "actime",
+ "modtime"
+ ]
+ }
+ },
+ {
+ "file": "libc/sys/stat.h",
+ "defines": [
+ "S_IFDIR",
+ "S_IFREG",
+ "S_IFMT",
+ "S_IFIFO",
+ "S_IFSOCK",
+ "S_IFBLK",
+ "S_IFLNK",
+ "S_IFCHR"
+ ],
+ "structs": {
+ "stat": [
+ "st_dev",
+ "__st_dev_padding",
+ "__st_ino_truncated",
+ "st_mode",
+ "st_nlink",
+ "st_uid",
+ "st_gid",
+ "st_rdev",
+ "__st_rdev_padding",
+ "st_size",
+ "st_blksize",
+ "st_blocks",
+ {
+ "st_atim": [
+ "tv_sec",
+ "tv_nsec"
+ ]
+ },
+ {
+ "st_mtim": [
+ "tv_sec",
+ "tv_nsec"
+ ]
+ },
+ {
+ "st_ctim": [
+ "tv_sec",
+ "tv_nsec"
+ ]
+ },
+ "st_ino"
+ ]
+ }
+ },
+ {
+ "file": "libc/sys/statvfs.h",
+ "defines": [],
+ "structs": {
+ "statvfs": [
+ "f_bsize",
+ "f_frsize",
+ "f_blocks",
+ "f_bfree",
+ "f_bavail",
+ "f_files",
+ "f_ffree",
+ "f_favail",
+ "f_fsid",
+ "f_flag",
+ "f_namemax"
+ ]
+ }
+ },
+ {
+ "file": "libc/fcntl.h",
+ "defines": [
+ "F_UNLCK",
+ "O_RDWR",
+ "S_IRWXO",
+ "F_GETLK64",
+ "F_SETLKW64",
+ "F_SETLKW",
+ "F_SETLK64",
+ "F_GETLK",
+ "S_ISVTX",
+ "O_RDONLY",
+ "O_ACCMODE",
+ "F_DUPFD",
+ "F_SETLK",
+ "O_WRONLY"
+ ],
+ "structs": {
+ "flock": [
+ "l_type",
+ "l_whence",
+ "l_start",
+ "l_len",
+ "l_pid"
+ ]
+ }
+ },
+ {
+ "file": "libc/poll.h",
+ "defines": [
+ "POLLHUP",
+ "POLLERR",
+ "POLLRDNORM",
+ "POLLPRI",
+ "POLLIN",
+ "POLLOUT",
+ "POLLNVAL"
+ ],
+ "structs": {
+ "pollfd": [
+ "fd",
+ "events",
+ "revents"
+ ]
+ }
+ },
+ {
+ "file": "libc/stdlib.h",
+ "defines": [],
+ "structs": {
+ // NOTE: The hash sign at the end of this name is a hint to the processor that it mustn't prefix "struct " to the name to reference this struct.
+ // It will be stripped away when writing the compiled JSON file. You can just refer to it as C_STRUCTS.div_t when using it in the JS code.
+ // For more information see gen_inspect_code() in tools/gen_struct_info.py .
+ "div_t#": [
+ "quot",
+ "rem"
+ ]
+ }
+ },
+ {
+ "file": "libc/sys/utsname.h",
+ "defines": [],
+ "structs": {
+ "utsname": [
+ "sysname",
+ "nodename",
+ "release",
+ "version",
+ "machine",
+ "domainname"
+ ]
+ }
+ },
+ {
+ "file": "libc/time.h",
+ "defines": [
+ ["li", "CLOCKS_PER_SEC"]
+ ],
+ "structs": {
+ "timezone": [
+ "tz_minuteswest",
+ "tz_dsttime"
+ ],
+ "tm": [
+ "tm_sec",
+ "tm_min",
+ "tm_hour",
+ "tm_mday",
+ "tm_mon",
+ "tm_year",
+ "tm_wday",
+ "tm_yday",
+ "tm_isdst",
+ "tm_gmtoff",
+ "tm_zone"
+ ],
+ "itimerspec": [
+ {
+ "it_interval": [
+ "tv_sec",
+ "tv_nsec"
+ ]
+ },
+ {
+ "it_value": [
+ "tv_sec",
+ "tv_nsec"
+ ]
+ }
+ ],
+ "timespec": [
+ "tv_sec",
+ "tv_nsec"
+ ],
+ "timeval": [
+ "tv_sec",
+ "tv_usec"
+ ]
+ }
+ },
+ {
+ "file": "libc/sys/times.h",
+ "defines": [],
+ "structs": {
+ "tms": [
+ "tms_utime",
+ "tms_stime",
+ "tms_cutime",
+ "tms_cstime"
+ ]
+ }
+ },
+ {
+ "defines": [],
+ "file": "compat/sys/timeb.h",
+ "structs": {
+ "timeb": [
+ "time",
+ "millitm",
+ "timezone",
+ "dstflag"
+ ]
+ }
+ },
+ {
+ "file": "libc/sys/resource.h",
+ "defines": [],
+ "structs": {
+ "rlimit": [
+ "rlim_cur",
+ "rlim_max"
+ ],
+ "rusage": [
+ {
+ "ru_utime": [
+ "tv_sec",
+ "tv_usec"
+ ]
+ },
+ {
+ "ru_stime": [
+ "tv_sec",
+ "tv_usec"
+ ]
+ },
+ "ru_maxrss",
+ "ru_ixrss",
+ "ru_idrss",
+ "ru_isrss",
+ "ru_minflt",
+ "ru_majflt",
+ "ru_nswap",
+ "ru_inblock",
+ "ru_oublock",
+ "ru_msgsnd",
+ "ru_msgrcv",
+ "ru_nsignals",
+ "ru_nvcsw",
+ "ru_nivcsw"
+ ]
+ }
+ },
+ {
+ "file": "libc/netdb.h",
+ "defines": [
+ "AI_V4MAPPED",
+ "EAI_SERVICE",
+ "EAI_FAMILY",
+ "AI_ALL",
+ "AI_ADDRCONFIG",
+ "AI_NUMERICSERV",
+ "NI_NUMERICHOST",
+ "EAI_OVERFLOW",
+ "AI_NUMERICHOST",
+ "AI_CANONNAME",
+ "AI_PASSIVE",
+ "NI_NAMEREQD",
+ "EAI_NONAME",
+ "EAI_SOCKTYPE",
+ "EAI_BADFLAGS"
+ ],
+ "structs": {
+ "sockaddr": [
+ "sa_family",
+ "sa_data"
+ ],
+ "hostent": [
+ "h_name",
+ "h_aliases",
+ "h_addrtype",
+ "h_length",
+ "h_addr_list"
+ ],
+ "addrinfo": [
+ "ai_flags",
+ "ai_family",
+ "ai_socktype",
+ "ai_protocol",
+ "ai_addrlen",
+ "ai_addr",
+ "ai_canonname",
+ "ai_next"
+ ],
+ "in_addr": [
+ "s_addr"
+ ],
+ "linger": [
+ "l_onoff",
+ "l_linger"
+ ],
+ "protoent": [
+ "p_name",
+ "p_aliases",
+ "p_proto"
+ ],
+ "sockaddr_in": [
+ "sin_family",
+ "sin_port",
+ {
+ "sin_addr": [
+ "s_addr"
+ ]
+ },
+ "sin_zero"
+ ],
+ "iovec": [
+ "iov_base",
+ "iov_len"
+ ],
+ "cmsghdr": [
+ "cmsg_len",
+ "cmsg_level",
+ "cmsg_type"
+ ],
+ "sockaddr_in6": [
+ "sin6_family",
+ "sin6_port",
+ "sin6_flowinfo",
+ {
+ "sin6_addr": [
+ {
+ "__in6_union": [
+ "__s6_addr",
+ "__s6_addr16",
+ "__s6_addr32"
+ ]
+ }
+ ]
+ },
+ "sin6_scope_id"
+ ],
+ "msghdr": [
+ "msg_name",
+ "msg_namelen",
+ "msg_iov",
+ "msg_iovlen",
+ "msg_control",
+ "msg_controllen",
+ "msg_flags"
+ ],
+ "in6_addr": [
+ {
+ "__in6_union": [
+ "__s6_addr",
+ "__s6_addr16",
+ "__s6_addr32"
+ ]
+ }
+ ],
+ "netent": [
+ "n_name",
+ "n_aliases",
+ "n_addrtype",
+ "n_net"
+ ]
+ }
+ },
+ {
+ "file": "libc/netinet/in.h",
+ "defines": [
+ "IPPROTO_UDP",
+ "IPPROTO_TCP",
+ "INADDR_LOOPBACK"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/math.h",
+ "defines": [
+ "FP_ZERO",
+ "FP_NAN",
+ "FP_INFINITE",
+ "FP_NORMAL"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/bits/fcntl.h",
+ "defines": [
+ "O_CREAT",
+ "O_SYNC",
+ "F_GETFD",
+ "F_SETFL",
+ "O_NOFOLLOW",
+ "O_APPEND",
+ "F_SETOWN",
+ "O_TRUNC",
+ "F_GETOWN",
+ "F_SETFD",
+ "O_EXCL",
+ "F_GETFL"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/sys/socket.h",
+ "defines": [
+ "SOCK_DGRAM",
+ "SOCK_STREAM",
+ "AF_INET",
+ "AF_UNSPEC",
+ "AF_INET6"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/bits/ioctl.h",
+ "defines": [
+ "FIONREAD"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/unistd.h",
+ "defines": [
+ "_SC_XOPEN_LEGACY",
+ "_SC_XOPEN_VERSION",
+ "_SC_BC_DIM_MAX",
+ "_CS_POSIX_V6_LP64_OFF64_LIBS",
+ "_PC_REC_MIN_XFER_SIZE",
+ "_SC_V6_ILP32_OFFBIG",
+ "_SC_MEMLOCK",
+ "_SC_THREADS",
+ "_PC_SOCK_MAXBUF",
+ "_SC_THREAD_KEYS_MAX",
+ "_SC_2_PBS",
+ "_SC_TRACE_INHERIT",
+ "_SC_REGEXP",
+ "_CS_POSIX_V6_LP64_OFF64_CFLAGS",
+ "_SC_VERSION",
+ "_PC_CHOWN_RESTRICTED",
+ "_SC_MQ_PRIO_MAX",
+ "_SC_PAGE_SIZE",
+ "_SC_BARRIERS",
+ "_SC_2_LOCALEDEF",
+ "_SC_STREAM_MAX",
+ "_SC_TIMERS",
+ "_PC_PATH_MAX",
+ "_SC_SPORADIC_SERVER",
+ "_SC_NPROCESSORS_ONLN",
+ "_CS_POSIX_V6_LPBIG_OFFBIG_LIBS",
+ "_PC_MAX_INPUT",
+ "_SC_CLK_TCK",
+ "_SC_AIO_MAX",
+ "_SC_THREAD_PRIO_INHERIT",
+ "_PC_2_SYMLINKS",
+ "_SC_SPAWN",
+ "_CS_POSIX_V6_ILP32_OFF32_LDFLAGS",
+ "_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS",
+ "_SC_TRACE_SYS_MAX",
+ "_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS",
+ "_SC_AIO_PRIO_DELTA_MAX",
+ "_SC_MONOTONIC_CLOCK",
+ "_SC_XOPEN_ENH_I18N",
+ "_SC_SPIN_LOCKS",
+ "_SC_XOPEN_SHM",
+ "_PC_LINK_MAX",
+ "_SC_FSYNC",
+ "_SC_GETGR_R_SIZE_MAX",
+ "_SC_TRACE_NAME_MAX",
+ "_SC_BC_BASE_MAX",
+ "_SC_XOPEN_STREAMS",
+ "_SC_GETPW_R_SIZE_MAX",
+ "_SC_CPUTIME",
+ "_SC_XBS5_ILP32_OFFBIG",
+ "_SC_TRACE_EVENT_FILTER",
+ "_SC_OPEN_MAX",
+ "_SC_2_FORT_RUN",
+ "_SC_RE_DUP_MAX",
+ "_SC_THREAD_PRIO_PROTECT",
+ "_SC_2_PBS_CHECKPOINT",
+ "_SC_XBS5_LPBIG_OFFBIG",
+ "_SC_SHARED_MEMORY_OBJECTS",
+ "_PC_ALLOC_SIZE_MIN",
+ "_SC_READER_WRITER_LOCKS",
+ "_SC_MEMLOCK_RANGE",
+ "_SC_PRIORITY_SCHEDULING",
+ "_PC_VDISABLE",
+ "_SC_MESSAGE_PASSING",
+ "_SC_THREAD_ATTR_STACKADDR",
+ "_SC_THREAD_THREADS_MAX",
+ "_SC_LOGIN_NAME_MAX",
+ "_SC_2_C_BIND",
+ "_PC_NO_TRUNC",
+ "_SC_SHELL",
+ "_SC_V6_LP64_OFF64",
+ "_CS_GNU_LIBC_VERSION",
+ "_SC_SEM_VALUE_MAX",
+ "_SC_MQ_OPEN_MAX",
+ "_SC_HOST_NAME_MAX",
+ "_SC_THREAD_STACK_MIN",
+ "_SC_TIMEOUTS",
+ "_SC_CHILD_MAX",
+ "_SC_2_PBS_MESSAGE",
+ "_SC_2_C_DEV",
+ "_SC_TIMER_MAX",
+ "_SC_SYMLOOP_MAX",
+ "_PC_REC_XFER_ALIGN",
+ "_SC_REALTIME_SIGNALS",
+ "_PC_ASYNC_IO",
+ "_SC_MAPPED_FILES",
+ "_SC_NGROUPS_MAX",
+ "_SC_SEMAPHORES",
+ "_SC_TRACE_LOG",
+ "_CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS",
+ "_CS_POSIX_V6_LP64_OFF64_LDFLAGS",
+ "_SC_THREAD_DESTRUCTOR_ITERATIONS",
+ "_SC_TRACE_EVENT_NAME_MAX",
+ "_SC_BC_STRING_MAX",
+ "_SC_2_SW_DEV",
+ "_SC_ARG_MAX",
+ "_SC_THREAD_PRIORITY_SCHEDULING",
+ "_SC_THREAD_CPUTIME",
+ "_CS_POSIX_V6_ILP32_OFF32_LIBS",
+ "_SC_SYNCHRONIZED_IO",
+ "_CS_POSIX_V6_ILP32_OFF32_CFLAGS",
+ "_SC_MEMORY_PROTECTION",
+ "_PC_PRIO_IO",
+ "_SC_V6_LPBIG_OFFBIG",
+ "_SC_EXPR_NEST_MAX",
+ "_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS",
+ "_PC_REC_MAX_XFER_SIZE",
+ "_SC_DELAYTIMER_MAX",
+ "W_OK",
+ "R_OK",
+ "_SC_XOPEN_CRYPT",
+ "_SC_XBS5_LP64_OFF64",
+ "_SC_SIGQUEUE_MAX",
+ "_SC_TZNAME_MAX",
+ "_CS_PATH",
+ "_PC_MAX_CANON",
+ "_SC_THREAD_SAFE_FUNCTIONS",
+ "_PC_NAME_MAX",
+ "_SC_TRACE_USER_EVENT_MAX",
+ "_SC_RAW_SOCKETS",
+ "_SC_RTSIG_MAX",
+ "_SC_PRIORITIZED_IO",
+ "_SC_XOPEN_UNIX",
+ "_PC_REC_INCR_XFER_SIZE",
+ "_PC_FILESIZEBITS",
+ "_SC_XBS5_ILP32_OFF32",
+ "_CS_GNU_LIBPTHREAD_VERSION",
+ "_SC_2_PBS_LOCATE",
+ "_SC_V6_ILP32_OFF32",
+ "_PC_SYNC_IO",
+ "_SC_2_UPE",
+ "_SC_SEM_NSEMS_MAX",
+ "_SC_IOV_MAX",
+ "_SC_TRACE",
+ "_CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS",
+ "_SC_LINE_MAX",
+ "_CS_POSIX_V6_ILP32_OFFBIG_LIBS",
+ "_SC_2_FORT_DEV",
+ "_SC_ATEXIT_MAX",
+ "_SC_SAVED_IDS",
+ "_SC_2_PBS_TRACK",
+ "_SC_THREAD_PROCESS_SHARED",
+ "_SC_JOB_CONTROL",
+ "_SC_IPV6",
+ "_SC_ADVISORY_INFO",
+ "_SC_XOPEN_REALTIME_THREADS",
+ "_PC_SYMLINK_MAX",
+ "X_OK",
+ "_SC_COLL_WEIGHTS_MAX",
+ "_SC_CLOCK_SELECTION",
+ "_SC_XOPEN_REALTIME",
+ "_PC_PIPE_BUF",
+ "_SC_2_PBS_ACCOUNTING",
+ "_SC_THREAD_SPORADIC_SERVER",
+ "_SC_THREAD_ATTR_STACKSIZE",
+ "_SC_2_VERSION",
+ "_SC_TYPED_MEMORY_OBJECTS",
+ "_SC_ASYNCHRONOUS_IO",
+ "_SC_2_CHAR_TERM",
+ "_SC_AIO_LISTIO_MAX",
+ "_SC_BC_SCALE_MAX",
+ "_SC_TTY_NAME_MAX"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/bits/errno.h",
+ "defines": [
+ "ETXTBSY",
+ "ETOOMANYREFS",
+ "ENAMETOOLONG",
+ "ENOPKG",
+ "EL3HLT",
+ "EINPROGRESS",
+ "ENOTSOCK",
+ "ENOTSUP",
+ "EFBIG",
+ "ENOLINK",
+ "EL3RST",
+ "ENOTUNIQ",
+ "ELNRNG",
+ "ENOANO",
+ "ENOPROTOOPT",
+ "E2BIG",
+ "EHOSTDOWN",
+ "EBFONT",
+ "ENOTEMPTY",
+ "EBUSY",
+ "EADDRINUSE",
+ "ELIBACC",
+ "EDQUOT",
+ "ENOENT",
+ "ECOMM",
+ "EXFULL",
+ "ENOTDIR",
+ "ENETRESET",
+ "EAFNOSUPPORT",
+ "EINVAL",
+ "ENODEV",
+ "ENOCSI",
+ "EPROTONOSUPPORT",
+ "ETIME",
+ "ENOTTY",
+ "EAGAIN",
+ "EMSGSIZE",
+ "ELIBEXEC",
+ "EMLINK",
+ "ECANCELED",
+ "EDESTADDRREQ",
+ "EADDRNOTAVAIL",
+ "EPERM",
+ "EPROTOTYPE",
+ "ENOMEDIUM",
+ "ELOOP",
+ "EREMOTE",
+ "ELIBMAX",
+ "EMULTIHOP",
+ "ECONNABORTED",
+ "EFAULT",
+ "EBADMSG",
+ "EDOM",
+ "EILSEQ",
+ "EPFNOSUPPORT",
+ "ENONET",
+ "ECHRNG",
+ "ESRCH",
+ "EHOSTUNREACH",
+ "EL2HLT",
+ "EL2NSYNC",
+ "ENOMSG",
+ "EISDIR",
+ "EDEADLOCK",
+ "ECONNRESET",
+ "ESTRPIPE",
+ "ESHUTDOWN",
+ "EDEADLK",
+ "EBADRQC",
+ "EUNATCH",
+ "ECHILD",
+ "ETIMEDOUT",
+ "EALREADY",
+ "ENXIO",
+ "EMFILE",
+ "ENFILE",
+ "EREMCHG",
+ "ENOMEM",
+ "ENOSR",
+ "EOWNERDEAD",
+ "ELIBSCN",
+ "EPIPE",
+ "EBADSLT",
+ "ENOSTR",
+ "EIO",
+ "EWOULDBLOCK",
+ "EBADE",
+ "ENODATA",
+ "ESOCKTNOSUPPORT",
+ "ENOLCK",
+ "EPROTO",
+ "ESRMNT",
+ "EXDEV",
+ "ENOSPC",
+ "ELIBBAD",
+ "ERANGE",
+ "ESTALE",
+ "ENOTRECOVERABLE",
+ "ENOBUFS",
+ "EIDRM",
+ "EINTR",
+ "EADV",
+ "ENOSYS",
+ "EUSERS",
+ "EOPNOTSUPP",
+ "ENOTCONN",
+ "ENETUNREACH",
+ "ESPIPE",
+ "EROFS",
+ "ECONNREFUSED",
+ "ENETDOWN",
+ "ENOEXEC",
+ "EBADF",
+ "EDOTDOT",
+ "EBADFD",
+ "EBADR",
+ "EISCONN",
+ "ENOTBLK",
+ "EOVERFLOW"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/langinfo.h",
+ "defines": [
+ "ABDAY_7",
+ "ABDAY_6",
+ "ABDAY_5",
+ "ABDAY_4",
+ "ABDAY_3",
+ "ABDAY_2",
+ "ABDAY_1",
+ "ABMON_1",
+ "RADIXCHAR",
+ "ABMON_3",
+ "AM_STR",
+ "ALT_DIGITS",
+ "PM_STR",
+ "ABMON_9",
+ "YESEXPR",
+ "ABMON_2",
+ "ABMON_7",
+ "ABMON_6",
+ "ABMON_5",
+ "ABMON_4",
+ "ABMON_8",
+ "ERA",
+ "MON_2",
+ "MON_3",
+ "MON_1",
+ "MON_6",
+ "MON_7",
+ "MON_4",
+ "MON_5",
+ "MON_8",
+ "MON_9",
+ "NOEXPR",
+ "T_FMT_AMPM",
+ "MON_10",
+ "MON_11",
+ "MON_12",
+ "T_FMT",
+ "THOUSEP",
+ "ERA_T_FMT",
+ "ERA_D_T_FMT",
+ "D_FMT",
+ "DAY_2",
+ "DAY_3",
+ "DAY_1",
+ "DAY_6",
+ "DAY_7",
+ "DAY_4",
+ "DAY_5",
+ "ERA_D_FMT",
+ "CODESET",
+ "D_T_FMT",
+ "CRNCYSTR",
+ "ABMON_12",
+ "ABMON_11",
+ "ABMON_10"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/stdio.h",
+ "defines": [
+ "EOF",
+ "SEEK_END",
+ "SEEK_SET"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/arpa/tftp.h",
+ "defines": [
+ "EACCES",
+ "EEXIST"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "compat/sys/stat.h",
+ "defines": [
+ "S_IALLUGO",
+ "S_IWUGO",
+ "S_IRUGO",
+ "S_IRWXUGO",
+ "S_IXUGO"
+ ],
+ "structs": {}
+ },
+ {
+ "file": "libc/bits/mman.h",
+ "defines": [
+ "MAP_PRIVATE"
+ ],
+ "structs": {}
+ },
+
+ // ===========================================
+ // SDL
+ // ===========================================
+ {
+ "file": "SDL/SDL_rect.h",
+ "defines": [],
+ "structs": {
+ "SDL_Rect": [
+ "x",
+ "y",
+ "w",
+ "h"
+ ]
+ }
+ },
+ {
+ "file": "SDL/SDL_keyboard.h",
+ "defines": [],
+ "structs": {
+ "SDL_Keysym": [
+ "scancode",
+ "sym",
+ "mod",
+ "unicode"
+ ]
+ }
+ },
+ {
+ "file": "SDL/SDL_pixels.h",
+ "defines": [],
+ "structs": {
+ "SDL_Palette": [
+ "ncolors",
+ "colors",
+ "version",
+ "refcount"
+ ],
+ "SDL_PixelFormat": [
+ "format",
+ "palette",
+ "BitsPerPixel",
+ "BytesPerPixel",
+ "padding",
+ "Rmask",
+ "Gmask",
+ "Bmask",
+ "Amask",
+ "Rloss",
+ "Gloss",
+ "Bloss",
+ "Aloss",
+ "Rshift",
+ "Gshift",
+ "Bshift",
+ "Ashift",
+ "refcount",
+ "next"
+ ],
+ "SDL_Color": [
+ "r",
+ "g",
+ "b",
+ "unused"
+ ]
+ }
+ },
+ {
+ "file": "SDL/SDL_surface.h",
+ "defines": [],
+ "structs": {
+ "SDL_Surface": [
+ "flags",
+ "format",
+ "w",
+ "h",
+ "pitch",
+ "pixels",
+ "userdata",
+ "locked",
+ "lock_data",
+ "clip_rect",
+ "map",
+ "refcount"
+ ]
+ }
+ },
+ {
+ "file": "SDL/SDL_events.h",
+ "defines": [],
+ "structs": {
+ "SDL_KeyboardEvent": [
+ "type",
+ "windowID",
+ "state",
+ "repeat",
+ "padding2",
+ "padding3",
+ "keysym"
+ ],
+ "SDL_TextInputEvent": [
+ "type",
+ "windowID",
+ "text"
+ ],
+ "SDL_MouseMotionEvent": [
+ "type",
+ "windowID",
+ "state",
+ "padding1",
+ "padding2",
+ "padding3",
+ "x",
+ "y",
+ "xrel",
+ "yrel"
+ ],
+ "SDL_MouseButtonEvent": [
+ "type",
+ "windowID",
+ "button",
+ "state",
+ "padding1",
+ "padding2",
+ "x",
+ "y"
+ ],
+ "SDL_ResizeEvent": [
+ "type",
+ "w",
+ "h"
+ ]
+ }
+ },
+ {
+ "file": "SDL/SDL_audio.h",
+ "defines": [
+ "SDL_AUDIO_MASK_BITSIZE",
+ "SDL_AUDIO_MASK_DATATYPE",
+ "SDL_AUDIO_MASK_ENDIAN",
+ "SDL_AUDIO_MASK_SIGNED",
+ "AUDIO_U8",
+ "AUDIO_S8",
+ "AUDIO_U16LSB",
+ "AUDIO_S16LSB",
+ "AUDIO_U16MSB",
+ "AUDIO_S16MSB",
+ "AUDIO_U16",
+ "AUDIO_S16",
+ "AUDIO_S32LSB",
+ "AUDIO_S32MSB",
+ "AUDIO_S32",
+ "AUDIO_F32LSB",
+ "AUDIO_F32MSB",
+ "AUDIO_F32",
+ "AUDIO_U16SYS",
+ "AUDIO_S16SYS",
+ "AUDIO_S32SYS",
+ "AUDIO_F32SYS",
+ "SDL_AUDIO_ALLOW_FREQUENCY_CHANGE",
+ "SDL_AUDIO_ALLOW_FORMAT_CHANGE",
+ "SDL_AUDIO_ALLOW_CHANNELS_CHANGE",
+ "SDL_AUDIO_ALLOW_ANY_CHANGE",
+ "SDL_MIX_MAXVOLUME"
+ ],
+ "structs": {
+ "SDL_AudioCVT": [
+ "needed",
+ "src_format",
+ "dst_format",
+ "rate_incr",
+ "buf",
+ "len",
+ "len_cvt",
+ "len_mult",
+ "len_ratio",
+ "filters",
+ "filter_index"
+ ],
+ "SDL_AudioSpec": [
+ "freq",
+ "format",
+ "channels",
+ "silence",
+ "samples",
+ "padding",
+ "size",
+ "callback",
+ "userdata"
+ ]
+ }
+ },
+ {
+ "file": "SDL/SDL_version.h",
+ "defines": [
+ "SDL_MAJOR_VERSION",
+ "SDL_MINOR_VERSION",
+ "SDL_PATCHLEVEL",
+ "SDL_COMPILEDVERSION"
+ ],
+ "structs": {
+ "SDL_version": [
+ "major",
+ "minor",
+ "patch"
+ ]
+ }
+ }
+]
diff --git a/src/utility.js b/src/utility.js
index 7d122cef..b793106c 100644
--- a/src/utility.js
+++ b/src/utility.js
@@ -334,6 +334,17 @@ function jsonCompare(x, y) {
return JSON.stringify(x) == JSON.stringify(y);
}
+function sortedJsonCompare(x, y) {
+ if (x === null || typeof x !== 'object') return x === y;
+ for (var i in x) {
+ if (!sortedJsonCompare(x[i], y[i])) return false;
+ }
+ for (var i in y) {
+ if (!sortedJsonCompare(x[i], y[i])) return false;
+ }
+ return true;
+}
+
function stringifyWithFunctions(obj) {
if (typeof obj === 'function') return obj.toString();
if (obj === null || typeof obj !== 'object') return JSON.stringify(obj);