aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc9
-rw-r--r--src/intertyper.js13
-rw-r--r--src/jsifier.js70
-rw-r--r--src/library.js8
-rw-r--r--src/library_gl.js3
-rw-r--r--src/modules.js8
-rw-r--r--src/parseTools.js52
-rw-r--r--src/preamble.js22
-rw-r--r--src/preamble_sharedlib.js1
-rw-r--r--src/settings.js4
-rw-r--r--src/utility.js8
-rw-r--r--tests/cases/gepoverflow.txt2
-rw-r--r--tests/cases/subnums.ll2
-rw-r--r--tests/gl_subdata.cpp141
-rwxr-xr-xtests/runner.py103
-rw-r--r--tools/shared.py4
16 files changed, 376 insertions, 74 deletions
diff --git a/emcc b/emcc
index 7e7efe6d..dc8bd630 100755
--- a/emcc
+++ b/emcc
@@ -335,7 +335,11 @@ Options that are modified or new in %s include:
builds - where you are compiling a large
program but only modified a small part of it -
to be much faster (at the cost of more disk
- IO for cache accesses).
+ IO for cache accesses). Note that you need
+ to enable --jcache for both loading and saving
+ of data, so you must enable it on a full build
+ for a later incremental build (where you also
+ enable it) to be sped up.
--clear-cache Manually clears the cache of compiled
emscripten system libraries (libc++,
@@ -772,7 +776,8 @@ try:
else:
print >> sys.stderr, 'emcc: %s: warning: Not valid LLVM bitcode' % arg
else:
- print >> sys.stderr, 'emcc: %s: warning: No such file or directory' % arg
+ print >> sys.stderr, 'emcc: %s: error: No such file or directory' % arg
+ exit(1)
elif arg.startswith('-L'):
lib_dirs.append(arg[2:])
newargs[i] = ''
diff --git a/src/intertyper.js b/src/intertyper.js
index 8e7bb418..7db1a2fe 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -73,13 +73,11 @@ function intertyper(data, sidePass, baseLineNums) {
if (!testType) {
var global = /([@%\w\d\.\" $-]+) = .*/.exec(line);
var globalIdent = toNiceIdent(global[1]);
- var testAlias = /[@%\w\d\.\" $-]+ = alias .*/.exec(line);
- var testString = /[@%\w\d\.\" $-]+ = [\w ]+ \[\d+ x i8] c".*/.exec(line);
+ var testAlias = /[@%\w\d\.\" $-]+ = (hidden )?alias .*/.exec(line);
Variables.globals[globalIdent] = {
name: globalIdent,
alias: !!testAlias,
- impl: VAR_EMULATED,
- isString : !!testString
+ impl: VAR_EMULATED
};
unparsedGlobals.lines.push(line);
} else {
@@ -459,6 +457,9 @@ function intertyper(data, sidePass, baseLineNums) {
};
ret.type = ret.value.type;
Types.needAnalysis[ret.type] = 0;
+ if (!NAMED_GLOBALS) {
+ Variables.globals[ret.ident].type = ret.type;
+ }
return [ret];
}
if (item.tokens[2].text == 'type') {
@@ -509,6 +510,10 @@ function intertyper(data, sidePass, baseLineNums) {
private_: private_,
lineNum: item.lineNum
};
+ if (!NAMED_GLOBALS) {
+ Variables.globals[ret.ident].type = ret.type;
+ Variables.globals[ret.ident].external = external;
+ }
Types.needAnalysis[ret.type] = 0;
if (ident == '@llvm.global_ctors') {
ret.ctors = [];
diff --git a/src/jsifier.js b/src/jsifier.js
index 595e057c..ce094e1e 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -217,7 +217,7 @@ function JSify(data, functionsOnly, givenFunctions) {
throw 'Invalid segment: ' + dump(segment);
}
assert(segment.type, 'Missing type for constant segment!');
- return indexizeFunctions(ret, segment.type);
+ return makeGlobalUse(indexizeFunctions(ret, segment.type));
};
return tokens.map(handleSegment)
}
@@ -226,7 +226,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (value.intertype in PARSABLE_LLVM_FUNCTIONS) {
return [finalizeLLVMFunctionCall(value)];
} else if (Runtime.isNumberType(type) || pointingLevels(type) >= 1) {
- return indexizeFunctions(parseNumerical(value.value), type);
+ return makeGlobalUse(indexizeFunctions(parseNumerical(value.value), type));
} else if (value.intertype === 'emptystruct') {
return makeEmptyStruct(type);
} else if (value.intertype === 'string') {
@@ -250,7 +250,7 @@ function JSify(data, functionsOnly, givenFunctions) {
processItem: function(item) {
function needsPostSet(value) {
return value[0] in UNDERSCORE_OPENPARENS || value.substr(0, 14) === 'CHECK_OVERFLOW'
- || value.substr(0, 13) === 'STRING_TABLE.';
+ || value.substr(0, 6) === 'GLOBAL';
}
item.intertype = 'GlobalVariableStub';
@@ -262,16 +262,17 @@ function JSify(data, functionsOnly, givenFunctions) {
'\n]);\n';
return ret;
} else {
+ var constant = null;
+ var allocator = (BUILD_AS_SHARED_LIB && !item.external) ? 'ALLOC_NORMAL' : 'ALLOC_STATIC';
+ var index = null;
if (item.external && BUILD_AS_SHARED_LIB) {
// External variables in shared libraries should not be declared as
// they would shadow similarly-named globals in the parent.
item.JS = '';
} else {
- if (!(item.ident in Variables.globals) || !Variables.globals[item.ident].isString) {
- item.JS = 'var ' + item.ident + ';';
- }
+ item.JS = makeGlobalDef(item.ident);
}
- var constant = null;
+
if (item.external) {
// Import external global variables from the library if available.
var shortident = item.ident.slice(1);
@@ -286,7 +287,7 @@ function JSify(data, functionsOnly, givenFunctions) {
padding = makeEmptyStruct(item.type);
}
var padded = val.concat(padding.slice(val.length));
- var js = item.ident + '=' + makePointer(JSON.stringify(padded), null, 'ALLOC_STATIC', item.type) + ';'
+ var js = item.ident + '=' + makePointer(JSON.stringify(padded), null, allocator, item.type, index) + ';'
if (LibraryManager.library[shortident + '__postset']) {
js += '\n' + LibraryManager.library[shortident + '__postset'];
}
@@ -297,6 +298,10 @@ function JSify(data, functionsOnly, givenFunctions) {
}
return ret;
} else {
+ if (!NAMED_GLOBALS && isIndexableGlobal(item.ident)) {
+ index = makeGlobalUse(item.ident); // index !== null indicates we are indexing this
+ allocator = 'ALLOC_NONE';
+ }
constant = parseConst(item.value, item.type, item.ident);
if (typeof constant === 'string' && constant[0] != '[') {
constant = [constant]; // A single item. We may need a postset for it.
@@ -307,7 +312,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (needsPostSet(value)) { // ident, or expression containing an ident
ret.push({
intertype: 'GlobalVariablePostSet',
- JS: makeSetValue(item.ident, i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
+ JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
});
constant[i] = '0';
}
@@ -316,21 +321,17 @@ function JSify(data, functionsOnly, givenFunctions) {
}
// NOTE: This is the only place that could potentially create static
// allocations in a shared library.
- constant = makePointer(constant, null, BUILD_AS_SHARED_LIB ? 'ALLOC_NORMAL' : 'ALLOC_STATIC', item.type);
-
+ constant = makePointer(constant, null, allocator, item.type, index);
var js;
- // Strings are held in STRING_TABLE, to not clutter up the main namespace (in some cases we have
- // many many strings, possibly exceeding the js engine limit on global vars).
- if (Variables.globals[item.ident].isString) {
- js = 'STRING_TABLE.' + item.ident + '=' + constant + ';';
- } else {
- js = item.ident + '=' + constant + ';';
- }
+ js = (index !== null ? '' : item.ident + '=') + constant + ';'; // \n Module.print("' + item.ident + ' :" + ' + makeGlobalUse(item.ident) + ');';
// Special case: class vtables. We make sure they are null-terminated, to allow easy runtime operations
if (item.ident.substr(0, 5) == '__ZTV') {
- js += '\n' + makePointer('[0]', null, BUILD_AS_SHARED_LIB ? 'ALLOC_NORMAL' : 'ALLOC_STATIC', ['void*']) + ';';
+ if (index !== null) {
+ index = getFastValue(index, '+', Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type)));
+ }
+ js += '\n' + makePointer('[0]', null, allocator, ['void*'], index) + ';';
}
if (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS)) {
js += '\nModule["' + item.ident + '"] = ' + item.ident + ';';
@@ -821,7 +822,7 @@ function JSify(data, functionsOnly, givenFunctions) {
break;
case VAR_EMULATED:
if (item.pointer.intertype == 'value') {
- return makeSetValue(item.ident, 0, value, item.valueType, 0, 0, item.align) + ';';
+ return makeSetValue(makeGlobalUse(item.ident), 0, value, item.valueType, 0, 0, item.align) + ';';
} else {
return makeSetValue(0, finalizeLLVMParameter(item.pointer), value, item.valueType, 0, 0, item.align) + ';';
}
@@ -1278,6 +1279,15 @@ function JSify(data, functionsOnly, givenFunctions) {
//
if (!mainPass) {
+ if (phase == 'pre' && !Variables.generatedGlobalBase) {
+ Variables.generatedGlobalBase = true;
+ if (Variables.nextIndexedOffset > 0) {
+ // Variables have been calculated, print out the base generation before we print them
+ print('var GLOBAL_BASE = STATICTOP;\n');
+ print('STATICTOP += ' + Variables.nextIndexedOffset + ';\n');
+ print('assert(STATICTOP < TOTAL_MEMORY);\n');
+ }
+ }
var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable).concat(itemsDict.GlobalVariablePostSet);
if (!DEBUG_MEMORY) print(generated.map(function(item) { return item.JS }).join('\n'));
return;
@@ -1286,7 +1296,23 @@ function JSify(data, functionsOnly, givenFunctions) {
// Print out global variables and postsets TODO: batching
if (phase == 'pre') {
legalizedI64s = false;
- JSify(analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true), true, Functions);
+
+ var globalsData = analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true);
+
+ if (!NAMED_GLOBALS) {
+ sortGlobals(globalsData.globalVariables).forEach(function(g) {
+ var ident = g.ident;
+ if (!isIndexableGlobal(ident)) return;
+ Variables.indexedGlobals[ident] = Variables.nextIndexedOffset;
+ Variables.nextIndexedOffset += Runtime.alignMemory(calcAllocatedSize(Variables.globals[ident].type));
+ if (ident.substr(0, 5) == '__ZTV') { // leave room for null-terminating the vtable
+ Variables.nextIndexedOffset += Runtime.getNativeTypeSize('i32');
+ }
+ });
+ }
+
+ JSify(globalsData, true, Functions);
+ globalsData = null;
data.unparsedGlobalss = null;
var generated = itemsDict.functionStub.concat(itemsDict.GlobalVariablePostSet);
@@ -1350,7 +1376,7 @@ function JSify(data, functionsOnly, givenFunctions) {
substrate.addItems(data.functionStubs, 'FunctionStub');
assert(data.functions.length == 0);
} else {
- substrate.addItems(values(data.globalVariables), 'GlobalVariable');
+ substrate.addItems(sortGlobals(data.globalVariables), 'GlobalVariable');
substrate.addItems(data.aliass, 'Alias');
substrate.addItems(data.functions, 'FunctionSplitter');
}
diff --git a/src/library.js b/src/library.js
index 12ac0ed0..5a8a9ae7 100644
--- a/src/library.js
+++ b/src/library.js
@@ -2461,6 +2461,7 @@ LibraryManager.library = {
for (var formatIndex = 0; formatIndex < format.length;) {
if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') {
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
+ argIndex += Runtime.getNativeFieldSize('void*');
{{{ makeSetValue('argPtr', 0, 'soFar', 'i32') }}};
formatIndex += 2;
continue;
@@ -3484,11 +3485,11 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/000095399/functions/printf.html
var result = __formatString(format, varargs);
var limit = (n === undefined) ? result.length
- : Math.min(result.length, n - 1);
+ : Math.min(result.length, Math.max(n - 1, 0));
for (var i = 0; i < limit; i++) {
{{{ makeSetValue('s', 'i', 'result[i]', 'i8') }}};
}
- {{{ makeSetValue('s', 'i', '0', 'i8') }}};
+ if (limit < n || (n === undefined)) {{{ makeSetValue('s', 'i', '0', 'i8') }}};
return result.length;
},
fprintf__deps: ['fwrite', '_formatString'],
@@ -3738,6 +3739,7 @@ LibraryManager.library = {
strtod_l: 'strtod', // no locale support yet
strtold: 'strtod', // XXX add real support for long double
strtold_l: 'strtold', // no locale support yet
+ strtof: 'strtod', // use stdtod to handle strtof
_parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'],
_parseInt: function(str, endptr, base, min, max, bits, unsign) {
@@ -5363,7 +5365,7 @@ LibraryManager.library = {
},
fmaxf: 'fmax',
fmin: function(x, y) {
- return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y);
+ return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y);
},
fminf: 'fmin',
fma: function(x, y, z) {
diff --git a/src/library_gl.js b/src/library_gl.js
index 4d83572e..b4098813 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -454,8 +454,7 @@ var LibraryGL = {
},
glBufferSubData: function(target, offset, size, data) {
- var floatArray = {{{ makeHEAPView('F32', 'data', 'data+size') }}};
- Module.ctx.bufferSubData(target, offset, floatArray);
+ Module.ctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size));
},
glIsBuffer: function(buffer) {
diff --git a/src/modules.js b/src/modules.js
index 9ef87691..fd0ec35e 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -174,7 +174,10 @@ var PreProcessor = {
};
var Variables = {
- globals: {}
+ globals: {},
+ indexedGlobals: {}, // for indexed globals, ident ==> index
+ // Used in calculation of indexed globals
+ nextIndexedOffset: 0
};
var Types = {
@@ -263,6 +266,7 @@ var Functions = {
var LibraryManager = {
library: null,
+ loaded: false,
load: function() {
assert(!this.library);
@@ -271,6 +275,8 @@ var LibraryManager = {
for (var i = 0; i < libraries.length; i++) {
eval(processMacros(preprocess(read(libraries[i]))));
}
+
+ this.loaded = true;
},
// Given an ident, see if it is an alias for something, and so forth, returning
diff --git a/src/parseTools.js b/src/parseTools.js
index c70b511a..7387bf31 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -356,6 +356,40 @@ function hasVarArgs(params) {
return false;
}
+var UNINDEXABLE_GLOBALS = set(
+ '_llvm_global_ctors' // special-cased
+);
+
+function noticePtr(ptr) {
+ if (!NAMED_GLOBALS && !LibraryManager.loaded) UNINDEXABLE_GLOBALS[ptr] = 1; // we cannot index globals referred to in the library, since they are used there by name
+}
+
+function isIndexableGlobal(ident) {
+ if (!(ident in Variables.globals)) return false;
+ if (ident in UNINDEXABLE_GLOBALS) return false;
+ var data = Variables.globals[ident];
+ return !data.alias && !data.external;
+}
+
+function makeGlobalDef(ident) {
+ if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '';
+ return 'var ' + ident + ';'; // TODO: add option for namespacing or offsetting to allow reducing the number of globals
+}
+
+function makeGlobalUse(ident) {
+ if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return '(' + getFastValue('GLOBAL_BASE', '+', Variables.indexedGlobals[ident]) + ')';
+ return ident; // TODO: add option for namespacing or offsetting to allow reducing the number of globals
+}
+
+function sortGlobals(globals) {
+ var ks = keys(globals);
+ ks.sort();
+ var inv = invertArray(ks);
+ return values(globals).sort(function(a, b) {
+ return inv[b.ident] - inv[a.ident];
+ });
+}
+
function finalizeParam(param) {
if (param.intertype in PARSABLE_LLVM_FUNCTIONS) {
return finalizeLLVMFunctionCall(param);
@@ -368,10 +402,9 @@ function finalizeParam(param) {
return parseI64Constant(param.ident);
}
var ret = toNiceIdent(param.ident);
- if (ret in Variables.globals && Variables.globals[ret].isString) {
- ret = "STRING_TABLE." + ret;
+ if (ret in Variables.globals) {
+ ret = makeGlobalUse(ret);
}
-
return ret;
}
}
@@ -907,6 +940,7 @@ function getHeapOffset(offset, type) {
// See makeSetValue
function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) {
+ noticePtr(ptr);
if (UNALIGNED_MEMORY) align = 1;
if (isStructType(type)) {
var typeData = Types.types[type];
@@ -987,6 +1021,7 @@ function indexizeFunctions(value, type) {
//! which means we should write to all slabs, ignore type differences if any on reads, etc.
//! @param noNeedFirst Whether to ignore the offset in the pointer itself.
function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) {
+ noticePtr(ptr);
if (UNALIGNED_MEMORY && !forcedAlign) align = 1;
sep = sep || ';';
if (isStructType(type)) {
@@ -1058,6 +1093,7 @@ var SEEK_OPTIMAL_ALIGN_MIN = 20;
var UNROLL_LOOP_MAX = 8;
function makeSetValues(ptr, pos, value, type, num, align) {
+ noticePtr(ptr);
function unroll(type, num, jump, value$) {
jump = jump || 1;
value$ = value$ || value;
@@ -1107,6 +1143,8 @@ function makeSetValues(ptr, pos, value, type, num, align) {
var TYPED_ARRAY_SET_MIN = Infinity; // .set() as memcpy seems to just slow us down
function makeCopyValues(dest, src, num, type, modifier, align, sep) {
+ noticePtr(dest);
+ noticePtr(src);
sep = sep || ';';
function unroll(type, num, jump) {
jump = jump || 1;
@@ -1260,7 +1298,7 @@ function makeGetPos(ptr) {
var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP');
-function makePointer(slab, pos, allocator, type) {
+function makePointer(slab, pos, allocator, type, ptr) {
assert(type, 'makePointer requires type info');
if (slab.substr(0, 4) === 'HEAP' || (USE_TYPED_ARRAYS == 1 && slab in IHEAP_FHEAP)) return pos;
var types = generateStructTypes(type);
@@ -1290,7 +1328,7 @@ function makePointer(slab, pos, allocator, type) {
types = de[0];
}
}
- return 'allocate(' + slab + ', ' + JSON.stringify(types) + (allocator ? ', ' + allocator : '') + ')';
+ return 'allocate(' + slab + ', ' + JSON.stringify(types) + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')';
}
function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
@@ -1472,8 +1510,8 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) {
}
} else if (param.intertype == 'value') {
ret = param.ident;
- if (ret in Variables.globals && Variables.globals[ret].isString) {
- ret = "STRING_TABLE." + ret;
+ if (ret in Variables.globals) {
+ ret = makeGlobalUse(ret);
}
if (param.type == 'i64' && USE_TYPED_ARRAYS == 2) {
ret = parseI64Constant(ret);
diff --git a/src/preamble.js b/src/preamble.js
index 1c66797b..9342bf2b 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -472,9 +472,11 @@ Module['getValue'] = getValue;
var ALLOC_NORMAL = 0; // Tries to use _malloc()
var ALLOC_STACK = 1; // Lives for the duration of the current function call
var ALLOC_STATIC = 2; // Cannot be freed
+var ALLOC_NONE = 3; // Do not allocate
Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
Module['ALLOC_STACK'] = ALLOC_STACK;
Module['ALLOC_STATIC'] = ALLOC_STATIC;
+Module['ALLOC_NONE'] = ALLOC_NONE;
// allocate(): This is for internal use. You can use it yourself as well, but the interface
// is a little tricky (see docs right below). The reason is that it is optimized
@@ -489,7 +491,7 @@ Module['ALLOC_STATIC'] = ALLOC_STATIC;
// is initial data - if @slab is a number, then this does not matter at all and is
// ignored.
// @allocator: How to allocate memory, see ALLOC_*
-function allocate(slab, types, allocator) {
+function allocate(slab, types, allocator, ptr) {
var zeroinit, size;
if (typeof slab === 'number') {
zeroinit = true;
@@ -501,7 +503,12 @@ function allocate(slab, types, allocator) {
var singleType = typeof types === 'string' ? types : null;
- var ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+ var ret;
+ if (allocator == ALLOC_NONE) {
+ ret = ptr;
+ } else {
+ ret = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
+ }
if (zeroinit) {
_memset(ret, 0, size);
@@ -544,6 +551,9 @@ function Pointer_stringify(ptr, /* optional */ length) {
var i = 0;
var t;
while (1) {
+#if ASSERTIONS
+ assert(i < TOTAL_MEMORY);
+#endif
t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}};
if (nullTerminated && t == 0) break;
ret += utf8.processCChar(t);
@@ -750,7 +760,11 @@ function exitRuntime() {
function String_len(ptr) {
var i = ptr;
- while ({{{ makeGetValue('i++', '0', 'i8') }}}) {}; // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds
+ while ({{{ makeGetValue('i++', '0', 'i8') }}}) { // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds
+#if ASSERTIONS
+ assert(i < TOTAL_MEMORY);
+#endif
+ }
return i - ptr - 1;
}
Module['String_len'] = String_len;
@@ -806,8 +820,6 @@ function writeArrayToMemory(array, buffer) {
}
Module['writeArrayToMemory'] = writeArrayToMemory;
-var STRING_TABLE = [];
-
{{{ unSign }}}
{{{ reSign }}}
diff --git a/src/preamble_sharedlib.js b/src/preamble_sharedlib.js
index af204e2f..2a071f6b 100644
--- a/src/preamble_sharedlib.js
+++ b/src/preamble_sharedlib.js
@@ -16,7 +16,6 @@ function callRuntimeCallbacks(callbacks) {
}
var __ATINIT__ = []; // functions called during startup
-var STRING_TABLE = [];
function initRuntime() {
callRuntimeCallbacks(__ATINIT__);
diff --git a/src/settings.js b/src/settings.js
index 5dc1e2eb..1d8805a8 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -194,6 +194,10 @@ var PGO = 0; // Profile-guided optimization.
// All CORRECT_* options default to 1 with PGO builds.
// See https://github.com/kripken/emscripten/wiki/Optimizing-Code for more info
+var NAMED_GLOBALS = 1; // If 1, we use global variables for globals. Otherwise
+ // they are referred to by a base plus an offset (called an indexed global),
+ // saving global variables but adding runtime overhead.
+
var PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage example.
var EXPORT_ALL = 0; // If true, we export all the symbols
diff --git a/src/utility.js b/src/utility.js
index f3ece90b..84b50ce9 100644
--- a/src/utility.js
+++ b/src/utility.js
@@ -282,6 +282,14 @@ function setIntersect(x, y) {
return ret;
}
+function invertArray(x) {
+ var ret = {};
+ for (var i = 0; i < x.length; i++) {
+ ret[x[i]] = i;
+ }
+ return ret;
+}
+
function copy(x) {
return JSON.parse(JSON.stringify(x));
}
diff --git a/tests/cases/gepoverflow.txt b/tests/cases/gepoverflow.txt
index bd3091fd..e01c78dd 100644
--- a/tests/cases/gepoverflow.txt
+++ b/tests/cases/gepoverflow.txt
@@ -1,2 +1,2 @@
-*5246498,5247068*
+*5246470,5247040*
*-514,56*
diff --git a/tests/cases/subnums.ll b/tests/cases/subnums.ll
index 981a1592..dc2af1c7 100644
--- a/tests/cases/subnums.ll
+++ b/tests/cases/subnums.ll
@@ -2,7 +2,7 @@
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
target triple = "i386-pc-linux-gnu"
-@.str = private unnamed_addr constant [15 x i8] c"hello, world! %d\0A\00", align 1 ; [#uses=1 type=[18 x i8]*]
+@.str = private unnamed_addr constant [18 x i8] c"hello, world! %d\0A\00", align 1 ; [#uses=1 type=[18 x i8]*]
; [#uses=0]
define i32 @main() {
diff --git a/tests/gl_subdata.cpp b/tests/gl_subdata.cpp
new file mode 100644
index 00000000..d159b2b2
--- /dev/null
+++ b/tests/gl_subdata.cpp
@@ -0,0 +1,141 @@
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+#include <cmath>
+#include <iostream>
+#include <vector>
+extern "C" {
+#include <GL/gl.h>
+#include <GL/glut.h>
+}
+static const char vertex_shader[] =
+ "#ifdef GL_ES\n"
+ "precision highp float;\n"
+ "#endif\n"
+ "attribute float indices;\n"
+ "uniform sampler2D nodeInfo;\n"
+ "varying vec4 color;"
+ "\n"
+ "void main(void)\n"
+ "{\n"
+ " float s = (indices + 0.5) / 512.; \n"
+ " vec4 v = texture2D(nodeInfo, vec2( s, 0.5));\n"
+ " gl_Position = vec4(v.x, v.y, 0.5, 1.);\n"
+ " gl_PointSize = v.z;\n"
+ " color = vec4(0.5 + v.w/2., 0.5 + 0.5 * v.w/2., 0.5, 1);\n"
+ "}\n";
+static const char fragment_shader[] =
+ "#ifdef GL_ES\n"
+ "precision highp float;\n"
+ "#endif\n"
+ "\n"
+ "varying vec4 color;\n"
+ "void main(void)\n"
+ "{\n"
+ " float dst = distance(vec2(0.5, 0.5), gl_PointCoord); \n"
+ " gl_FragColor = color;\n"
+ " if ( dst > 0.3) {"
+ " gl_FragColor = vec4(0., 0., 0.5, 0.2);\n"
+ "}\n"
+ "if ( dst > 0.5) discard;\n"
+ "}";
+struct NodeInfo { //structure that we want to transmit to our shaders
+ float x;
+ float y;
+ float s;
+ float c;
+};
+GLuint nodeTexture; //texture id used to bind
+GLuint nodeSamplerLocation; //shader sampler address
+GLuint indicesAttributeLocation; //shader attribute address
+GLuint indicesVBO; //Vertex Buffer Object Id;
+const int nbNodes = 512;
+NodeInfo data[nbNodes]; //our data that will be transmitted using float texture.
+double alpha = 0; //use to make a simple funny effect;
+static void updateFloatTexture() {
+ int count = 0;
+ for (float x=0; x < nbNodes; ++x ) {
+ data[count].x = 0.2*pow(cos(alpha), 3) + (sin(alpha)*3. + 3.5) * x/nbNodes * cos(alpha + x/nbNodes * 16. * M_PI);
+ data[count].y = 0.2*pow(sin(alpha), 3) + (sin(alpha)*3. + 3.5) * x/nbNodes * sin(alpha + x/nbNodes * 16. * M_PI);
+ data[count].s = (16. + 16. * cos(alpha + x/nbNodes * 32. * M_PI)) + 8.;// * fmod(x/nbNodes + alpha, 1.) + 5.;
+ data[count].c = 0.5 + 0.5 * sin(alpha + x/nbNodes * 32. * M_PI);
+ ++count;
+ }
+ glBindTexture(GL_TEXTURE_2D, nodeTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, nbNodes, 1, 0, GL_RGBA, GL_FLOAT, data);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glBindTexture(GL_TEXTURE_2D, NULL);
+ alpha -= 0.001;
+}
+static void glut_draw_callback(void) {
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glClearColor(1., 1., 1., 0.);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glActiveTexture(GL_TEXTURE0);
+ updateFloatTexture(); //we change the texture each time to create the effect (it is just for the test)
+ glBindTexture(GL_TEXTURE_2D, nodeTexture);
+ glUniform1i(nodeSamplerLocation, GL_TEXTURE0);
+ glEnableVertexAttribArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, indicesVBO);
+ glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL);
+ glDrawArrays(GL_POINTS, 0, nbNodes);
+ glutSwapBuffers();
+}
+GLuint createShader(const char source[], int type) {
+ char msg[512];
+ GLuint shader = glCreateShader(type);
+ glShaderSource(shader, 1, (const GLchar**)(&source), NULL);
+ glCompileShader(shader);
+ glGetShaderInfoLog(shader, sizeof msg, NULL, msg);
+ std::cout << "Shader info: " << msg << std::endl;
+ return shader;
+}
+static void gl_init(void) {
+ GLuint program = glCreateProgram();
+ glAttachShader(program, createShader(vertex_shader , GL_VERTEX_SHADER));
+ glAttachShader(program, createShader(fragment_shader, GL_FRAGMENT_SHADER));
+ glLinkProgram(program);
+ char msg[512];
+ glGetProgramInfoLog(program, sizeof msg, NULL, msg);
+ std::cout << "info: " << msg << std::endl;
+ glUseProgram(program);
+ std::vector<float> elements(nbNodes);
+ int count = 0;
+ for (float x=0; x < nbNodes; ++x ) {
+ elements[count] = count;
+ ++count;
+ }
+ /*Create one texture to store all the needed information */
+ glGenTextures(1, &nodeTexture);
+ /* Store the vertices in a vertex buffer object (VBO) */
+ glGenBuffers(1, &indicesVBO);
+ glBindBuffer(GL_ARRAY_BUFFER, indicesVBO);
+ float zeroes[nbNodes];
+ memset(zeroes, 0, sizeof(zeroes));
+ glBufferData(GL_ARRAY_BUFFER, elements.size() * sizeof(float), zeroes, GL_STATIC_DRAW);
+ for (int x = 0; x < nbNodes; x++) {
+ glBufferSubData(GL_ARRAY_BUFFER, x * sizeof(float), elements.size() * sizeof(float), &elements[x]);
+ }
+ /* Get the locations of the uniforms so we can access them */
+ nodeSamplerLocation = glGetUniformLocation(program, "nodeInfo");
+ glBindAttribLocation(program, 0, "indices");
+ //Enable glPoint size in shader, always enable in Open Gl ES 2.
+ glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+ glEnable(GL_POINT_SPRITE);
+}
+int main(int argc, char *argv[]) {
+ glutInit(&argc, argv);
+ glutInitWindowSize(640, 480);
+ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+ glutCreateWindow("Simple FLOAT Texture Test");
+ /* Set up glut callback functions */
+ glutDisplayFunc(glut_draw_callback );
+ gl_init();
+ glutMainLoop();
+ return 0;
+}
+
+
diff --git a/tests/runner.py b/tests/runner.py
index a4bc4944..cef14e95 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -279,10 +279,18 @@ process(sys.argv[1])
return ret
def build_native(self, filename):
- Popen([CLANG, '-O2', filename, '-o', filename+'.native'], stdout=PIPE).communicate()[0]
+ process = Popen([CLANG, '-O2', filename, '-o', filename+'.native'], stdout=PIPE);
+ output = process.communicate()
+ if process.returncode is not 0:
+ print >> sys.stderr, "Building native executable with command '%s' failed with a return code %d!" % (' '.join([CLANG, '-O2', filename, '-o', filename+'.native']), process.returncode)
+ print "Output: " + output[0]
def run_native(self, filename, args):
- Popen([filename+'.native'] + args, stdout=PIPE).communicate()[0]
+ process = Popen([filename+'.native'] + args, stdout=PIPE);
+ output = process.communicate()
+ if process.returncode is not 0:
+ print >> sys.stderr, "Running native executable with command '%s' failed with a return code %d!" % (' '.join([filename+'.native'] + args), process.returncode)
+ print "Output: " + output[0]
def assertIdentical(self, values, y):
if type(values) not in [list, tuple]: values = [values]
@@ -1368,6 +1376,7 @@ c5,de,15,8a
def test_floatvars(self):
src = '''
#include <stdio.h>
+ #include <math.h>
int main()
{
float x = 1.234, y = 3.5, q = 0.00000001;
@@ -1375,6 +1384,8 @@ c5,de,15,8a
int z = x < y;
printf("*%d,%d,%.1f,%d,%.4f,%.2f*\\n", z, int(y), y, (int)x, x, q);
+ printf("%.2f, %.2f, %.2f, %.2f\\n", fmin(0.5, 3.3), fmin(NAN, 3.3), fmax(0.5, 3.3), fmax(NAN, 3.3));
+
/*
// Rounding behavior
float fs[6] = { -2.75, -2.50, -2.25, 2.25, 2.50, 2.75 };
@@ -1386,7 +1397,7 @@ c5,de,15,8a
return 0;
}
'''
- self.do_run(src, '*1,10,10.5,1,1.2340,0.00*')
+ self.do_run(src, '*1,10,10.5,1,1.2340,0.00*\n0.50, 3.30, 3.30, 3.30\n')
def test_globaldoubles(self):
src = r'''
@@ -1642,7 +1653,15 @@ c5,de,15,8a
return 0;
}
'''
- self.do_run(src, '4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\n', ['wowie', 'too', '74'])
+ for named, expected in [(0, 100), (1, 0)]:
+ print named
+ Settings.NAMED_GLOBALS = named
+ self.do_run(src, '4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\n', ['wowie', 'too', '74'])
+ if self.emcc_args == []:
+ gen = open(self.in_dir('src.cpp.o.js')).read()
+ count = gen.count('GLOBAL_BASE')
+ assert count == expected
+ print ' counted'
def test_strcmp_uni(self):
src = '''
@@ -1932,7 +1951,7 @@ c5,de,15,8a
TEST(C4__);
TEST(C4_2);
TEST(C__z);
- return 1;
+ return 0;
}
'''
if Settings.QUANTUM_SIZE == 1:
@@ -1947,7 +1966,7 @@ c5,de,15,8a
int main() {
assert(1 == true); // pass
assert(1 == false); // fail
- return 1;
+ return 0;