diff options
35 files changed, 1078 insertions, 215 deletions
@@ -99,5 +99,7 @@ a license to everyone to use it as detailed in LICENSE.) * Tobias Vrinssen <tobias@vrinssen.de> * Patrick R. Martin <patrick.martin.r@gmail.com> * Richard Quirk <richard.quirk@gmail.com> +* Marcos Scriven <marcos@scriven.org> +* Antoine Lambert <antoine.lambert33@gmail.com> * Daniel Aquino <mr.danielaquino@gmail.com> @@ -129,18 +129,18 @@ Most normal gcc/g++ options will work, for example: Options that are modified or new in %s include: -O0 No optimizations (default) -O1 Simple optimizations, including asm.js, LLVM -O1 - optimizations, and no runtime assertions + optimizations, relooping, and no runtime assertions or C++ exception catching (to re-enable C++ exception catching, use - -s DISABLE_EXCEPTION_CATCHING=0 ). - (For details on the affects of different - opt levels, see apply_opt_level() in - tools/shared.py and also src/settings.js.) - -O2 As -O1, plus the relooper (loop recreation), - LLVM -O3 optimizations, and + -s DISABLE_EXCEPTION_CATCHING=0 ), and enables -s ALIASING_FUNCTION_POINTERS=1 + (For details on the affects of different + opt levels, see apply_opt_level() in + tools/shared.py and also src/settings.js.) + -O2 As -O1, plus various js-level optimizations and + LLVM -O3 optimizations -O3 As -O2, plus dangerous optimizations that may break the generated code! This adds @@ -258,6 +258,9 @@ Options that are modified or new in %s include: try adjusting JAVA_HEAP_SIZE in the environment (for example, to 4096m for 4GB). + Note: Closure is only run if js opts are being + done (-O2 or above, or --js-opts 1). + --js-transform <cmd> <cmd> will be called on the generated code before it is optimized. This lets you modify the JavaScript, for example adding some code @@ -933,7 +936,7 @@ try: if default_cxx_std: newargs = newargs + [default_cxx_std] - if js_opts is None: js_opts = opt_level >= 1 + if js_opts is None: js_opts = opt_level >= 2 if llvm_opts is None: llvm_opts = LLVM_OPT_LEVEL[opt_level] if llvm_lto is None and opt_level >= 3: llvm_lto = 3 if opt_level == 0: debug_level = 4 @@ -1105,6 +1108,16 @@ try: shared.Settings.CORRECT_OVERFLOWS = 1 assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' + heap = 4096 + while heap < shared.Settings.TOTAL_MEMORY: + if heap <= 16*1024*1024: + heap *= 2 + else: + heap += 16*1024*1024 + if heap != shared.Settings.TOTAL_MEMORY: + logging.warning('increasing TOTAL_MEMORY to %d to be more reasonable for asm.js' % heap) + shared.Settings.TOTAL_MEMORY = heap + if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2: debug_level = 4 # must keep debug info to do line-by-line operations @@ -1218,7 +1231,7 @@ try: file_suffix = filename_type_suffix(input_file) if file_suffix.endswith(SOURCE_SUFFIXES): temp_file = temp_files[i] - logging.debug('optimizing %s with -O%d' % (input_file, llvm_opts)) + logging.debug('optimizing %s with -O%s' % (input_file, llvm_opts)) shared.Building.llvm_opt(temp_file, llvm_opts) # If we were just asked to generate bitcode, stop there diff --git a/emscripten.py b/emscripten.py index 2e90fa48..b7f85e6f 100755 --- a/emscripten.py +++ b/emscripten.py @@ -49,15 +49,8 @@ if STDERR_FILE: logging.info('logging stderr in js compiler phase into %s' % STDERR_FILE) STDERR_FILE = open(STDERR_FILE, 'w') -def process_funcs((i, funcs, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine, temp_files, DEBUG)): +def process_funcs((i, funcs_file, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine, DEBUG)): try: - funcs_file = temp_files.get('.func_%d.ll' % i).name - f = open(funcs_file, 'w') - f.write(funcs) - funcs = None - f.write('\n') - f.write(meta) - f.close() #print >> sys.stderr, 'running', str([settings_file, funcs_file, 'funcs', forwarded_file] + libraries).replace("'/", "'") # can use this in src/compiler_funcs.html arguments, # # just copy temp dir to under this one out = jsrun.run_js( @@ -100,42 +93,42 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, ll = open(infile).read() scan(ll, settings) total_ll_size = len(ll) - ll = None # allow collection if DEBUG: logging.debug(' emscript: scan took %s seconds' % (time.time() - t)) # Split input into the relevant parts for each phase + + if DEBUG: t = time.time() + pre = [] funcs = [] # split up functions here, for parallelism later - meta = [] # needed by each function XXX - if DEBUG: t = time.time() - in_func = False - ll_lines = open(infile).readlines() - curr_func = None - for line in ll_lines: - if in_func: - curr_func.append(line) - if line.startswith('}'): - in_func = False - funcs.append((curr_func[0], ''.join(curr_func))) # use the entire line as the identifier - # pre needs to know about all implemented functions, even for non-pre func - pre.append(curr_func[0]) - pre.append(line) - curr_func = None - else: - if line.startswith(';'): continue - if line.startswith('define '): - in_func = True - curr_func = [line] - elif line.find(' = type { ') > 0: - pre.append(line) # type - elif line.startswith('!'): - if line.startswith('!llvm.module'): continue # we can ignore that - meta.append(line) # metadata - else: - pre.append(line) # pre needs it so we know about globals in pre and funcs. So emit globals there - ll_lines = None - meta = ''.join(meta) + meta_start = ll.find('\n!') + if meta_start > 0: + meta = ll[meta_start:] + else: + meta = '' + meta_start = -1 + + start = ll.find('\n') if ll[0] == ';' else 0 # ignore first line, which contains ; ModuleID = '/dir name' + + func_start = start + last = func_start + while 1: + last = func_start + func_start = ll.find('\ndefine ', func_start) + if func_start > last: + pre.append(ll[last:min(func_start+1, meta_start)] + '\n') + if func_start < 0: + pre.append(ll[last:meta_start] + '\n') + break + header = ll[func_start+1:ll.find('\n', func_start+1)+1] + end = ll.find('\n}', func_start) + last = end+3 + funcs.append((header, ll[func_start+1:last])) + pre.append(header + '}\n') + func_start = last + ll = None + if DEBUG and len(meta) > 1024*1024: logging.debug('emscript warning: large amounts of metadata, will slow things down') if DEBUG: logging.debug(' emscript: split took %s seconds' % (time.time() - t)) @@ -195,6 +188,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, jcache.set(shortkey, keys, out) pre, forwarded_data = out.split('//FORWARDED_DATA:') forwarded_file = temp_files.get('.json').name + pre_input = None open(forwarded_file, 'w').write(forwarded_data) if DEBUG: logging.debug(' emscript: phase 1 took %s seconds' % (time.time() - t)) @@ -254,11 +248,20 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, if DEBUG: logging.debug(' emscript: phase 2 working on %d chunks %s (intended chunk size: %.2f MB, meta: %.2f MB, forwarded: %.2f MB, total: %.2f MB)' % (len(chunks), ('using %d cores' % cores) if len(chunks) > 1 else '', chunk_size/(1024*1024.), len(meta)/(1024*1024.), len(forwarded_data)/(1024*1024.), total_ll_size/(1024*1024.))) - commands = [ - (i, chunk, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine,# + ['--prof'], - temp_files, DEBUG) - for i, chunk in enumerate(chunks) - ] + commands = [] + for i in range(len(chunks)): + funcs_file = temp_files.get('.func_%d.ll' % i).name + f = open(funcs_file, 'w') + f.write(chunks[i]) + if not jcache: + chunks[i] = None # leave chunks array alive (need its length later) + f.write('\n') + f.write(meta) + f.close() + commands.append( + (i, funcs_file, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine,# + ['--prof'], + DEBUG) + ) if len(chunks) > 1: pool = multiprocessing.Pool(processes=cores) @@ -346,7 +349,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, else: curr = i i += settings['FUNCTION_POINTER_ALIGNMENT'] - #logging.debug('function indexing', indexed, curr, sig) + #logging.debug('function indexing ' + str([indexed, curr, sig])) forwarded_json['Functions']['indexedFunctions'][indexed] = curr # make sure not to modify this python object later - we use it in indexize def split_32(x): diff --git a/src/analyzer.js b/src/analyzer.js index 17ad26ad..95fbccc7 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -188,7 +188,7 @@ function analyzer(data, sidePass) { if (USE_TYPED_ARRAYS == 2) { function getLegalVars(base, bits, allowLegal) { bits = bits || 32; // things like pointers are all i32, but show up as 0 bits from getBits - if (allowLegal && bits <= 32) return [{ ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits }]; + if (allowLegal && bits <= 32) return [{ intertype: 'value', ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits, type: 'i' + bits }]; if (isNumber(base)) return getLegalLiterals(base, bits); if (base[0] == '{') { warnOnce('seeing source of illegal data ' + base + ', likely an inline struct - assuming zeroinit'); @@ -198,7 +198,7 @@ function analyzer(data, sidePass) { var i = 0; if (base == 'zeroinitializer' || base == 'undef') base = 0; while (bits > 0) { - ret[i] = { ident: base ? base + '$' + i : '0', bits: Math.min(32, bits) }; + ret[i] = { intertype: 'value', ident: base ? base + '$' + i : '0', bits: Math.min(32, bits), type: 'i' + Math.min(32, bits) }; bits -= 32; i++; } @@ -209,7 +209,7 @@ function analyzer(data, sidePass) { var ret = new Array(Math.ceil(bits/32)); var i = 0; while (bits > 0) { - ret[i] = { ident: (parsed[i]|0).toString(), bits: Math.min(32, bits) }; // resign all values + ret[i] = { intertype: 'value', ident: (parsed[i]|0).toString(), bits: Math.min(32, bits), type: 'i' + Math.min(32, bits) }; // resign all values bits -= 32; i++; } @@ -225,7 +225,8 @@ function analyzer(data, sidePass) { return getLegalLiterals(value.ident, bits); } else if (value.intertype == 'structvalue') { return getLegalStructuralParts(value).map(function(part) { - return { ident: part.ident, bits: part.type.substr(1) }; + part.bits = part.type.substr(1); // can be some nested IR, like LLVM calls + return part; }); } else { return getLegalVars(value.ident, bits); @@ -550,11 +551,7 @@ function analyzer(data, sidePass) { return { intertype: 'phiparam', label: param.label, - value: { - intertype: 'value', - ident: values[k++][j].ident, - type: 'i' + element.bits, - } + value: values[k++][j] }; }) }); @@ -802,27 +799,65 @@ function analyzer(data, sidePass) { var whole = shifts >= 0 ? Math.floor(shifts/32) : Math.ceil(shifts/32); var fraction = Math.abs(shifts % 32); if (signed) { - var signedFill = '(' + makeSignOp(sourceElements[sourceElements.length-1].ident, 'i' + sourceElements[sourceElements.length-1].bits, 're', 1, 1) + ' < 0 ? -1 : 0)'; - var signedKeepAlive = { intertype: 'value', ident: sourceElements[sourceElements.length-1].ident, type: 'i32' }; - } - for (var j = 0; j < targetElements.length; j++) { - var result = { - intertype: 'value', - ident: (j + whole >= 0 && j + whole < sourceElements.length) ? sourceElements[j + whole].ident : (signed ? signedFill : '0'), - params: [(signed && j + whole > sourceElements.length) ? signedKeepAlive : null], + var signedFill = { + intertype: 'mathop', + op: 'select', + variant: 's', type: 'i32', + params: [{ + intertype: 'mathop', + op: 'icmp', + variant: 'slt', + type: 'i32', + params: [ + { intertype: 'value', ident: sourceElements[sourceElements.length-1].ident, type: 'i' + Math.min(sourceBits, 32) }, + { intertype: 'value', ident: '0', type: 'i32' } + ] + }, + { intertype: 'value', ident: '-1', type: 'i32' }, + { intertype: 'value', ident: '0', type: 'i32' }, + ] }; - if (j == 0 && sourceBits < 32) { - // zext sign correction - result.ident = makeSignOp(result.ident, 'i' + sourceBits, isUnsignedOp(value.op) ? 'un' : 're', 1, 1); - } - if (fraction != 0) { - var other = { + } + for (var j = 0; j < targetElements.length; j++) { + var inBounds = j + whole >= 0 && j + whole < sourceElements.length; + var result; + if (inBounds || !signed) { + result = { intertype: 'value', - ident: (j + sign + whole >= 0 && j + sign + whole < sourceElements.length) ? sourceElements[j + sign + whole].ident : (signed ? signedFill : '0'), - params: [(signed && j + sign + whole > sourceElements.length) ? signedKeepAlive : null], - type: 'i32', + ident: inBounds ? sourceElements[j + whole].ident : '0', + type: 'i' + Math.min(sourceBits, 32), }; + if (j == 0 && sourceBits < 32) { + // zext sign correction + var result2 = { + intertype: 'mathop', + op: isUnsignedOp(value.op) ? 'zext' : 'sext', + params: [result, { + intertype: 'type', + ident: 'i32', + type: 'i' + sourceBits + }], + type: 'i32' + }; + result = result2; + } + } else { + // out of bounds and signed + result = copy(signedFill); + } + if (fraction != 0) { + var other; + var otherInBounds = j + sign + whole >= 0 && j + sign + whole < sourceElements.length; + if (otherInBounds || !signed) { + other = { + intertype: 'value', + ident: otherInBounds ? sourceElements[j + sign + whole].ident : '0', + type: 'i32', + }; + } else { + other = copy(signedFill); + } other = { intertype: 'mathop', op: shiftOp, @@ -872,10 +907,17 @@ function analyzer(data, sidePass) { } if (targetBits <= 32) { // We are generating a normal legal type here - legalValue = { - intertype: 'value', - ident: targetElements[0].ident + (targetBits < 32 ? '&' + (Math.pow(2, targetBits)-1) : ''), - type: 'rawJS' + legalValue = { intertype: 'value', ident: targetElements[0].ident, type: 'i32' }; + if (targetBits < 32) { + legalValue = { + intertype: 'mathop', + op: 'and', + type: 'i32', + params: [ + legalValue, + { intertype: 'value', ident: (Math.pow(2, targetBits)-1).toString(), type: 'i32' } + ] + } }; legalValue.assignTo = item.assignTo; toAdd.push(legalValue); @@ -1117,7 +1159,7 @@ function analyzer(data, sidePass) { rawLinesIndex: i }; if (variable.origin === 'alloca') { - variable.allocatedNum = item.allocatedNum; + variable.allocatedNum = item.ident; } if (variable.origin === 'call') { variable.type = getReturnType(variable.type); @@ -1608,9 +1650,9 @@ function analyzer(data, sidePass) { var lines = func.labels[0].lines; for (var i = 0; i < lines.length; i++) { var item = lines[i]; - if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum)) break; + if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.ident)) break; item.allocatedSize = func.variables[item.assignTo].impl === VAR_EMULATED ? - calcAllocatedSize(item.allocatedType)*item.allocatedNum: 0; + calcAllocatedSize(item.allocatedType)*item.ident: 0; if (USE_TYPED_ARRAYS === 2) { // We need to keep the stack aligned item.allocatedSize = Runtime.forceAlign(item.allocatedSize, Runtime.STACK_ALIGN); @@ -1619,7 +1661,7 @@ function analyzer(data, sidePass) { var index = 0; for (var i = 0; i < lines.length; i++) { var item = lines[i]; - if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum)) break; + if (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.ident)) break; item.allocatedIndex = index; index += item.allocatedSize; delete item.allocatedSize; @@ -1647,7 +1689,7 @@ function analyzer(data, sidePass) { for (var i = 0; i < lines.length; i++) { var item = lines[i]; - if (!finishedInitial && (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.allocatedNum))) { + if (!finishedInitial && (!item.assignTo || item.intertype != 'alloca' || !isNumber(item.ident))) { finishedInitial = true; } if (item.intertype == 'alloca' && finishedInitial) { diff --git a/src/compiler.js b/src/compiler.js index 90060837..d490f454 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -185,7 +185,6 @@ if (SAFE_HEAP) USE_BSS = 0; // must initialize heap for safe heap assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS == 2, must have normal QUANTUM_SIZE of 4'); if (ASM_JS) { assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap'); - assert((TOTAL_MEMORY&(TOTAL_MEMORY-1)) == 0, 'asm.js heap must be power of 2'); } assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have named globals'); @@ -207,7 +206,12 @@ 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)); +try { + var temp = JSON.parse(read(STRUCT_INFO)); +} catch(e) { + printErr('cannot load struct info at ' + STRUCT_INFO + ' : ' + e + ', trying in current dir'); + temp = JSON.parse(read('struct_info.compiled.json')); +} C_STRUCTS = temp.structs; C_DEFINES = temp.defines; @@ -312,3 +316,6 @@ if (ll_file) { } } +//var M = keys(tokenCacheMisses).map(function(m) { return [m, misses[m]] }).sort(function(a, b) { return a[1] - b[1] }); +//printErr(dump(M.slice(M.length-10))); + diff --git a/src/intertyper.js b/src/intertyper.js index 09bdaa33..781c8187 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -5,14 +5,16 @@ var fastPaths = 0, slowPaths = 0; +var tokenCache = {}; +['=', 'i32', 'label', ';', '4', '0', '1', '2', '255', 'align', 'i8*', 'i8', 'i16', 'getelementptr', 'inbounds', 'unnamed_addr', 'x', 'load', 'preds', 'br', 'i32*', 'i1', 'store', '<label>', 'constant', 'c', 'private', 'null', 'internal', 'to', 'bitcast', 'define', 'nounwind', 'nocapture', '%this', 'call', '...'].forEach(function(text) { tokenCache[text] = { text: text } }); + +//var tokenCacheMisses = {}; + // Line tokenizer -function tokenizer(item, inner) { - //assert(item.lineNum != 40000); - //if (item.lineNum) print(item.lineNum); +function tokenize(text, lineNum) { var tokens = []; var quotes = 0; var lastToken = null; - var CHUNKSIZE = 64; // How much forward to peek forward. Too much means too many string segments copied // Note: '{' is not an encloser, as its use in functions is split over many lines var enclosers = { '[': 0, @@ -26,22 +28,33 @@ function tokenizer(item, inner) { function makeToken(text) { if (text.length == 0) return; // merge certain tokens - if (lastToken && ( (lastToken.text == '%' && text[0] == '"') || /^\**$/.test(text) ) ) { + if (lastToken && /^\**$/.test(text)) { lastToken.text += text; return; } + var cached = tokenCache[text]; + if (cached) { + //assert(cached.text === text); + tokens.push(cached); + lastToken = cached; + return; + } + //tokenCacheMisses[text] = (misses[text] || 0) + 1; + var token = { text: text }; if (text[0] in enclosers) { - token.item = tokenizer({ - lineText: text.substr(1, text.length-2) - }, true); + token.item = tokenize(text.substr(1, text.length-2)); token.type = text[0]; } // merge certain tokens if (lastToken && isType(lastToken.text) && isFunctionDef(token)) { + if (lastToken.text in tokenCache) { + // create a copy of the cached value + lastToken = tokens[tokens.length-1] = { text: lastToken.text }; + } lastToken.text += ' ' + text; } else if (lastToken && text[0] == '}') { // }, }*, etc. var openBrace = tokens.length-1; @@ -63,7 +76,7 @@ function tokenizer(item, inner) { } } // Split using meaningful characters - var lineText = item.lineText + ' '; + var lineText = text + ' '; var re = /[\[\]\(\)<>, "]/g; var segments = lineText.split(re); segments.pop(); @@ -141,15 +154,11 @@ function tokenizer(item, inner) { var newItem = { tokens: tokens, indent: lineText.search(/[^ ]/), - lineNum: item.lineNum + lineNum: lineNum || 0 }; return newItem; } -function tokenize(text) { - return tokenizer({ lineText: text }, true); -} - // Handy sets var ENCLOSER_STARTERS = set('[', '(', '<'); @@ -251,7 +260,7 @@ function intertyper(lines, sidePass, baseLineNums) { if (mainPass && /^}.*/.test(line)) { inFunction = false; if (mainPass) { - var func = funcHeaderHandler(tokenizer({ lineText: currFunctionLines[0], lineNum: currFunctionLineNum }, true)); + var func = funcHeaderHandler(tokenize(currFunctionLines[0], currFunctionLineNum)); if (SKIP_STACK_IN_SMALL && /emscripten_autodebug/.exec(func.ident)) { warnOnce('Disabling SKIP_STACK_IN_SMALL because we are apparently processing autodebugger data'); @@ -766,15 +775,13 @@ function intertyper(lines, sidePass, baseLineNums) { return item; } // 'alloca' - var allocaPossibleVars = ['allocatedNum']; function allocaHandler(item) { item.intertype = 'alloca'; item.allocatedType = item.tokens[1].text; if (item.tokens.length > 3 && Runtime.isNumberType(item.tokens[3].text)) { - item.allocatedNum = toNiceIdent(item.tokens[4].text); - item.possibleVars = allocaPossibleVars; + item.ident = toNiceIdent(item.tokens[4].text); } else { - item.allocatedNum = 1; + item.ident = 1; } item.type = addPointing(item.tokens[1].text); // type of pointer we will get Types.needAnalysis[item.type] = 0; @@ -1099,7 +1106,7 @@ function intertyper(lines, sidePass, baseLineNums) { if (ret) { if (COMPILER_ASSERTIONS) { //printErr(['\n', dump(ret), '\n', dump(triager(tokenizer(line)))]); - var normal = triager(tokenizer(line)); + var normal = triager(tokenize(line)); delete normal.tokens; delete normal.indent; assert(sortedJsonCompare(normal, ret), 'fast path: ' + dump(normal) + '\n vs \n' + dump(ret)); @@ -1124,7 +1131,7 @@ function intertyper(lines, sidePass, baseLineNums) { //var time = Date.now(); - var t = tokenizer(line); + var t = tokenize(line.lineText, line.lineNum); item = triager(t); /* diff --git a/src/jsifier.js b/src/jsifier.js index 0e5f8ef3..f638ea08 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -234,8 +234,8 @@ function JSify(data, functionsOnly, givenFunctions) { function globalVariableHandler(item) { function needsPostSet(value) { if (typeof value !== 'string') return false; - return value[0] in UNDERSCORE_OPENPARENS || value.substr(0, 14) === 'CHECK_OVERFLOW' - || value.substr(0, 6) === 'GLOBAL'; + // (' is ok, as it is something we can indexize later into a concrete int: ('{{ FI_ ... + return /^([(_][^']|CHECK_OVERFLOW|GLOBAL).*/.test(value); } item.intertype = 'GlobalVariableStub'; @@ -308,6 +308,8 @@ function JSify(data, functionsOnly, givenFunctions) { JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors }); constant[i] = '0'; + } else { + if (typeof value === 'string') constant[i] = deParenCarefully(value); } }); @@ -405,6 +407,9 @@ function JSify(data, functionsOnly, givenFunctions) { var snippet = LibraryManager.library[ident]; var redirectedIdent = null; var deps = LibraryManager.library[ident + '__deps'] || []; + deps.forEach(function(dep) { + if (typeof snippet === 'string' && !(dep in LibraryManager.library)) warn('missing library dependency ' + dep + ', make sure you are compiling with the right options (see #ifdefs in src/library*.js)'); + }); var isFunction = false; if (typeof snippet === 'string') { @@ -536,7 +541,6 @@ function JSify(data, functionsOnly, givenFunctions) { case 'unreachable': line.JS = unreachableHandler(line); break; 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; @@ -1361,7 +1365,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (item.allocatedSize === 0) return ''; // This will not actually be shown - it's nativized return asmCoercion(getFastValue('sp', '+', item.allocatedIndex.toString()), 'i32'); } else { - return RuntimeGenerator.stackAlloc(getFastValue(calcAllocatedSize(item.allocatedType), '*', item.allocatedNum)); + retu |