aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/intertyper.js3
-rw-r--r--src/jsifier.js34
-rw-r--r--src/modules.js6
-rw-r--r--src/parseTools.js6
-rw-r--r--src/preamble.js11
-rw-r--r--src/settings.js5
-rwxr-xr-xtests/runner.py10
7 files changed, 63 insertions, 12 deletions
diff --git a/src/intertyper.js b/src/intertyper.js
index 1ad51b96..dbd5f458 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -507,6 +507,9 @@ function intertyper(data, sidePass, baseLineNums) {
private_: private_,
lineNum: item.lineNum
};
+ if (NUM_NAMED_GLOBALS >= 0) {
+ Variables.globals[ret.ident].type = ret.type;
+ }
Types.needAnalysis[ret.type] = 0;
if (ident == '@llvm.global_ctors') {
ret.ctors = [];
diff --git a/src/jsifier.js b/src/jsifier.js
index c361278a..ac8037df 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -262,6 +262,20 @@ 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 (NUM_NAMED_GLOBALS >= 0) {
+ if (Variables.seenGlobals < NUM_NAMED_GLOBALS) {
+ Variables.seenGlobals++; // named
+ } else {
+ // indexed
+ Variables.indexedGlobals[item.ident] = Variables.nextIndexedOffset;
+ index = makeGlobalUse(item.ident);
+ Variables.nextIndexedOffset += Runtime.alignMemory(calcAllocatedSize(Variables.globals[item.ident].type));
+ allocator = 'ALLOC_NONE';
+ }
+ }
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.
@@ -269,7 +283,7 @@ function JSify(data, functionsOnly, givenFunctions) {
} else {
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);
@@ -284,7 +298,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'];
}
@@ -314,15 +328,14 @@ 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;
- js = makeGlobalUse(item.ident) + '=' + constant + ';';
+ js = (index !== null ? '' : item.ident + '=') + constant + ';';
// 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*']) + ';';
+ js += '\n' + makePointer('[0]', null, allocator, ['void*'], index) + ';';
}
if (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS)) {
js += '\nModule["' + item.ident + '"] = ' + item.ident + ';';
@@ -1270,6 +1283,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;
diff --git a/src/modules.js b/src/modules.js
index 9ef87691..4f7fc784 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -174,7 +174,11 @@ var PreProcessor = {
};
var Variables = {
- globals: {}
+ globals: {},
+ indexedGlobals: {}, // for indexed globals, ident ==> index
+ // Used in calculation of indexed globals
+ nextIndexedOffset: 0,
+ seenGlobals: 0,
};
var Types = {
diff --git a/src/parseTools.js b/src/parseTools.js
index 2591a94a..786d55c8 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -357,10 +357,12 @@ function hasVarArgs(params) {
}
function makeGlobalDef(ident) {
+ if (ident in Variables.indexedGlobals) return '';
return 'var ' + ident + ';'; // TODO: add option for namespacing or offsetting to allow reducing the number of globals
}
function makeGlobalUse(ident) {
+ if (ident in Variables.indexedGlobals) return getFastValue('GLOBAL_BASE', '+', Variables.indexedGlobals[ident]);
return ident; // TODO: add option for namespacing or offsetting to allow reducing the number of globals
}
@@ -1267,7 +1269,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);
@@ -1297,7 +1299,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) {
diff --git a/src/preamble.js b/src/preamble.js
index 14bf4d36..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);
diff --git a/src/settings.js b/src/settings.js
index 5dc1e2eb..4881e149 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -194,6 +194,11 @@ 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 NUM_NAMED_GLOBALS = -1; // If >= 0, the number of globals we allow to be named. Other globals
+ // are then referred to by a base plus an offset (called an indexed global),
+ // saving global variables but adding runtime overhead. If -1, then we
+ // allow all globals to be named.
+
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/tests/runner.py b/tests/runner.py
index deeb5689..1d85b3df 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -1645,7 +1645,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 [(-1, 0), (0, 100), (1, 98), (5, 88), (1000, 0)]:
+ print named
+ Settings.NUM_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 = '''