allow limited the amount of named globals

This commit is contained in:
Alon Zakai 2012-11-24 17:36:40 +01:00
Родитель 915d48e596
Коммит a27c01ed25
7 изменённых файлов: 63 добавлений и 12 удалений

Просмотреть файл

@ -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 = [];

Просмотреть файл

@ -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;

Просмотреть файл

@ -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 = {

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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);

Просмотреть файл

@ -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

Просмотреть файл

@ -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 = '''