diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/bindings_generator.py | 113 | ||||
-rw-r--r-- | tools/eliminator/eliminator-test-output.js | 11 | ||||
-rw-r--r-- | tools/eliminator/eliminator-test.js | 13 | ||||
-rw-r--r-- | tools/eliminator/eliminator.coffee | 3 | ||||
-rw-r--r-- | tools/js-optimizer.js | 57 | ||||
-rw-r--r-- | tools/test-js-optimizer-output.js | 73 | ||||
-rw-r--r-- | tools/test-js-optimizer.js | 66 |
7 files changed, 253 insertions, 83 deletions
diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py index bdb3e755..17df1231 100755 --- a/tools/bindings_generator.py +++ b/tools/bindings_generator.py @@ -95,24 +95,38 @@ all_h.write(text) all_h.close() parsed = CppHeaderParser.CppHeader(all_h_name) -for classname, clazz in parsed.classes.iteritems(): - print 'zz see', classname +print 'zz dir: ', parsed.__dict__.keys() +for classname, clazz in parsed.classes.items() + parsed.structs.items(): + print 'zz see', classname, clazz, type(clazz) classes[classname] = clazz - clazz['methods'] = clazz['methods']['public'] # CppHeaderParser doesn't have 'public' etc. in structs. so equalize to that + if type(clazz['methods']) == dict: + clazz['saved_methods'] = clazz['methods'] + clazz['methods'] = clazz['methods']['public'] # CppHeaderParser doesn't have 'public' etc. in structs. so equalize to that if '::' in classname: assert classname.count('::') == 1 parents[classname.split('::')[1]] = classname.split('::')[0] - for sname, struct in clazz._public_structs.iteritems(): - parents[sname] = classname - classes[classname + '::' + sname] = struct - struct['name'] = sname # Missing in CppHeaderParser - print 'zz seen struct %s in %s' % (sname, classname) - + if hasattr(clazz, '_public_structs'): # This is a class + for sname, struct in clazz._public_structs.iteritems(): + parents[sname] = classname + classes[classname + '::' + sname] = struct + struct['name'] = sname # Missing in CppHeaderParser + print 'zz seen struct %s in %s' % (sname, classname) + + if 'fields' in clazz: # This is a struct + print 'zz add properties!' + clazz['properties'] = { 'public': clazz['fields'] } + clazz['name'] = classname + clazz['inherits'] = [] print 'zz parents: ', parents -for classname, clazz in classes.iteritems(): +def check_has_constructor(clazz): + for method in clazz['methods']: + if method['constructor'] and not method['destructor']: return True + return False + +for classname, clazz in parsed.classes.items() + parsed.structs.items(): # Various precalculations print 'zz precalc', classname for method in clazz['methods'][:]: @@ -157,7 +171,7 @@ for classname, clazz in classes.iteritems(): print 'zz subsubsub ', classname, method['name'], method['parameters'][0] method['name'] = 'op_sub' if len(method['parameters'][0]) == 0: - method['operator'] = ' return -*self; // %d' % len(method['parameters'][0]) + method['operator'] = ' static %s ret; ret = -*self; return ret;' % method['returns'] else: method['operator'] = ' return *self -= arg0; // %d : %s' % (len(method['parameters'][0]), method['parameters'][0][0]['name']) elif 'imul' in method['name']: @@ -180,8 +194,8 @@ for classname, clazz in classes.iteritems(): method['name'] = 'op_comp' method['operator'] = ' return arg0 == arg1;' if len(method['parameters'][0]) == 2 else ' return *self == arg0;' else: - print 'zz unknown operator:', method['name'] - 1/0. + print 'zz unknown operator:', method['name'], ', ignoring' + method['ignore'] = True # Fill in some missing stuff method['returns_text'] = method['returns_text'].replace('&', '').replace('*', '') @@ -237,21 +251,31 @@ for classname, clazz in classes.iteritems(): }]], }) - # Add destroyer - if not clazz.get('abstract'): - clazz['methods'].append({ - 'destroyer': True, - 'name': '__destroy__', - 'constructor': False, - 'destructor': False, - 'static': False, - 'returns': 'void', - 'returns_text': 'void', - 'returns_reference': False, - 'returns_pointer': False, - 'pure_virtual': False, - 'parameters': [[]], - }) + print 'zz is effectively abstract?', clazz['name'], classname, '0' + if 'saved_methods' in clazz and not check_has_constructor(clazz): + print 'zz is effectively abstract?', clazz['name'], '1' + # Having a private constructor and no public constructor means you are, in effect, abstract + for private_method in clazz['saved_methods']['private']: + print 'zz is effectively abstract?', clazz['name'], '2' + if private_method['constructor']: + print 'zz is effectively abstract?', clazz['name'], '3' + clazz['effectively_abstract'] = True + + # Add destroyer + if not clazz.get('abstract') and not clazz.get('effectively_abstract'): + clazz['methods'].append({ + 'destroyer': True, + 'name': '__destroy__', + 'constructor': False, + 'destructor': False, + 'static': False, + 'returns': 'void', + 'returns_text': 'void', + 'returns_reference': False, + 'returns_pointer': False, + 'pure_virtual': False, + 'parameters': [[]], + }) clazz['methods'] = filter(lambda method: not method.get('ignore'), clazz['methods']) @@ -277,7 +301,7 @@ def copy_args(args): ret.append(copiedarg) return ret -for classname, clazz in parsed.classes.iteritems(): +for classname, clazz in parsed.classes.items() + parsed.structs.items(): clazz['final_methods'] = {} def explore(subclass, template_name=None, template_value=None): @@ -286,10 +310,16 @@ for classname, clazz in parsed.classes.iteritems(): print classname, 'exploring', subclass['name'], '::', method['name'] if method['constructor']: - if clazz != subclass: continue # Subclasses cannot directly use their parent's constructors - if method['destructor']: continue # Nothing to do there + if clazz != subclass: + print "zz Subclasses cannot directly use their parent's constructors" + continue + if method['destructor']: + print 'zz Nothing to do there' + continue - if method.get('operator') and subclass is not clazz: continue # Do not use parent class operators. Cast to that class if you need those operators (castObject) + if method.get('operator') and subclass is not clazz: + print 'zz Do not use parent class operators. Cast to that class if you need those operators (castObject)' + continue if method['name'] not in clazz['final_methods']: copied = clazz['final_methods'][method['name']] = {} @@ -485,6 +515,7 @@ def generate_wrapping_code(classname): # %(classname)s.prototype['fields'] = Runtime.generateStructInfo(null, '%(classname)s'); - consider adding this def generate_class(generating_classname, classname, clazz): # TODO: deprecate generating? + print 'zz generating:', generating_classname, classname generating_classname_head = generating_classname.split('::')[-1] classname_head = classname.split('::')[-1] @@ -498,6 +529,7 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge gen_js.write('''Module['%s'] = %s; ''' % (generating_classname_head, generating_classname_head)) + print 'zz methods: ', clazz['final_methods'].keys() for method in clazz['final_methods'].itervalues(): mname = method['name'] if classname_head + '::' + mname in ignored: @@ -509,7 +541,7 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge destructor = method['destructor'] static = method['static'] - #print 'zz generating %s::%s. gets %s and returns %s' % (generating_classname, method['name'], str([arg['type'] for arg in method['parameters']]), method['returns_text']) + print 'zz generating %s::%s' % (generating_classname, method['name']) if destructor: continue if constructor and inherited: continue @@ -644,7 +676,7 @@ def generate_class(generating_classname, classname, clazz): # TODO: deprecate ge print 'zz making return', classname, method['name'], method['returns'], return_value if method['returns'] in classes: # Generate a wrapper - calls += 'return wrapPointer(%s, %s);' % (return_value, method['returns'].split('::')[-1]) + calls += 'return wrapPointer(%s, Module.%s);' % (return_value, method['returns'].split('::')[-1]) else: # Normal return calls += ('return ' if ret != 'void' else '') + return_value + ';' @@ -686,7 +718,7 @@ Module['%s'] = %s; # Main loop -for classname, clazz in classes.iteritems(): +for classname, clazz in parsed.classes.items() + parsed.structs.items(): if any([name in ignored for name in classname.split('::')]): print 'zz ignoring', classname continue @@ -727,18 +759,17 @@ for classname, clazz in classes.iteritems(): print 'zz ignoring pure virtual class', classname, 'due to', method['name'] return True - clazz['abstract'] = check_pure_virtual(clazz, []) + clazz['abstract'] = check_pure_virtual(clazz, []) or clazz.get('effectively_abstract') + print 'zz', classname, 'is abstract?', clazz['abstract'] #if check_pure_virtual(clazz, []): # continue # Add a constructor if none exist - has_constructor = False - for method in clazz['methods']: - has_constructor = has_constructor or (method['constructor'] and not method['destructor']) - + has_constructor = check_has_constructor(clazz) + print 'zz', classname, 'has constructor?', has_constructor - + if not has_constructor: if not clazz['abstract']: print 'zz no constructor for', classname, 'and not abstract, so ignoring' diff --git a/tools/eliminator/eliminator-test-output.js b/tools/eliminator/eliminator-test-output.js index d914a5da..aac21e87 100644 --- a/tools/eliminator/eliminator-test-output.js +++ b/tools/eliminator/eliminator-test-output.js @@ -117,4 +117,13 @@ function f3($s, $tree, $k) { } HEAP32[($s + 2908 + ($storemerge_in << 2) | 0) >> 2] = $0; } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["f", "g", "h", "py", "r", "t", "f2", "f3"] +function llvm3_1() { + while (check()) { + if ($curri_01 % $zj_0 == 0) { + break; + } + var $j_0 = $aj_0 + 1; + run($j_0 / 2); + } +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["f", "g", "h", "py", "r", "t", "f2", "f3", "llvm3_1"] diff --git a/tools/eliminator/eliminator-test.js b/tools/eliminator/eliminator-test.js index 35bed0bb..55f74d67 100644 --- a/tools/eliminator/eliminator-test.js +++ b/tools/eliminator/eliminator-test.js @@ -130,5 +130,14 @@ function f3($s, $tree, $k) { } HEAP32[($s + 2908 + ($storemerge_in << 2) | 0) >> 2] = $0; } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["f", "g", "h", "py", "r", "t", "f2", "f3"] - +function llvm3_1() { + while (check()) { + var $inc = $aj_0 + 1; + if ($curri_01 % $zj_0 == 0) { + break; + } + var $j_0 = $inc; + run($j_0 / 2); + } +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["f", "g", "h", "py", "r", "t", "f2", "f3", "llvm3_1"] diff --git a/tools/eliminator/eliminator.coffee b/tools/eliminator/eliminator.coffee index b78a5a7e..ba91aa89 100644 --- a/tools/eliminator/eliminator.coffee +++ b/tools/eliminator/eliminator.coffee @@ -49,9 +49,6 @@ NODES_WITHOUT_SIDE_EFFECTS = # Nodes which may break control flow. Moving a variable beyond them may have # side effects. CONTROL_FLOW_NODES = - return: true - break: true - continue: true new: true throw: true call: true diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index d84c664a..a0595b88 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -239,7 +239,7 @@ function emptyNode() { // Dump the AST. Useful for debugging. For example, // node tools/js-optimizer.js ABSOLUTE_PATH_TO_FILE dumpAst function dumpAst(ast) { - printErr(JSON.stringify(ast)); + printErr(JSON.stringify(ast, null, ' ')); } function dumpSrc(ast) { @@ -801,18 +801,24 @@ function vacuum(ast) { if (node[0] == 'block' && (!node[1] || (typeof node[1] != 'object') || node[1].length == 0 || (node[1].length == 1 && isEmpty(node[1])))) return true; return false; } - function simplifyList(node, i) { + function simplifyList(node, si) { var changed = false; - var pre = node[i].length; - node[i] = node[i].filter(function(node) { return !isEmpty(node) }); - if (node[i].length < pre) changed = true; - // Also, seek blocks with single items we can simplify - node[i] = node[i].map(function(subNode) { - if (subNode[0] == 'block' && typeof subNode[1] == 'object' && subNode[1].length == 1 && subNode[1][0][0] == 'if') { - return subNode[1][0]; + // Merge block items into this list, thus removing unneeded |{ .. }|'s + var statements = node[si]; + var i = 0; + while (i < statements.length) { + var subNode = statements[i]; + if (subNode[0] == 'block') { + statements.splice.apply(statements, [i, 1].concat(subNode[1] || [])); + changed = true; + } else { + i++; } - return subNode; - }); + } + // Remove empty items + var pre = node[si].length; + node[si] = node[si].filter(function(node) { return !isEmpty(node) }); + if (node[si].length < pre) changed = true; if (changed) { return node; } @@ -1002,6 +1008,35 @@ function hoistMultiples(ast) { }); vacuum(ast); + + // Afterpass: Reduce + // if (..) { .. break|continue } else { .. } + // to + // if (..) { .. break|continue } .. + traverseGenerated(ast, function(container, type) { + var statements = getStatements(container); + if (!statements) return; + for (var i = 0; i < statements.length; i++) { + var node = statements[i]; + if (node[0] == 'if' && node[2][0] == 'block' && node[3] && node[3][0] == 'block') { + var stat1 = node[2][1], stat2 = node[3][1]; + // If break|continue in the latter and not the former, reverse them + if (!(stat1[stat1.length-1][0] in LOOP_FLOW) && (stat2[stat2.length-1][0] in LOOP_FLOW)) { + var temp = node[3]; + node[3] = node[2]; + node[2] = temp; + node[1] = ['unary-prefix', '!', node[1]]; + simplifyNotComps(node[1]); // bake the ! into the expression + stat1 = node[2][1]; + stat2 = node[3][1]; + } + if (stat1[stat1.length-1][0] in LOOP_FLOW) { + statements.splice.apply(statements, [i+1, 0].concat(stat2)); + node[3] = null; + } + } + } + }); } // Simplifies loops diff --git a/tools/test-js-optimizer-output.js b/tools/test-js-optimizer-output.js index 17c06a95..ca76cae1 100644 --- a/tools/test-js-optimizer-output.js +++ b/tools/test-js-optimizer-output.js @@ -68,9 +68,7 @@ function loopy() { something(); } while (0); next(); - { - something(); - } + something(); } function ignoreLoopy() { b$for_cond$4 : while (1) { @@ -141,12 +139,11 @@ function hoisting() { } pause(7); while (1) { - if ($i < $N) { - somethingElse(); - } else { + if ($i >= $N) { __label__ = 3; break; } + somethingElse(); if ($i < $N) { somethingElse(); } @@ -166,15 +163,43 @@ function hoisting() { } __label__ = 39; break; - } else { - __label__ = 38; } + __label__ = 38; } while (0); if (__label__ == 38) { var $79 = $_pr6; } pause(9); var $cmp70 = ($call69 | 0) != 0; + pause(10); + while (check()) { + if ($i < $N) { + callOther(); + break; + } + somethingElse(); + if ($i1 < $N) { + callOther(); + continue; + } + somethingElse(); + if ($i2 >= $N) { + somethingElse(); + break; + } + callOther(); + if ($i3 >= $N) { + somethingElse(); + continue; + } + callOther(); + if ($i4 < $N) { + callOther(); + break; + } + somethingElse(); + continue; + } } function innerShouldAlsoBeHoisted() { function hoisting() { @@ -208,9 +233,7 @@ function sleep() { } function demangle($cmp) { do { - if ($cmp) { - __label__ = 3; - } else { + if (!$cmp) { if (something()) { __label__ = 3; break; @@ -218,6 +241,7 @@ function demangle($cmp) { more(); break; } + __label__ = 3; } while (0); if (__label__ == 3) { final(); @@ -259,25 +283,21 @@ function moreLabels() { } if ($cmp1) { break; - } else { - inc(); } + inc(); } pause(999); $while_body$$while_end$31 : do { if ($cmp3) { var $6 = $5; - { - while (1) { - var $6; - $iter = $6 + 3; - if (FHEAP[$iter + 1] < $pct_addr) { - var $6 = $iter; - } else { - var $_lcssa = $iter; - break $while_body$$while_end$31; - } + while (1) { + var $6; + $iter = $6 + 3; + if (FHEAP[$iter + 1] >= $pct_addr) { + var $_lcssa = $iter; + break $while_body$$while_end$31; } + var $6 = $iter; } } else { var $_lcssa = $5; @@ -286,4 +306,9 @@ function moreLabels() { var $_lcssa; cheez(); } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits", "maths", "hoisting", "demangle", "lua", "moreLabels"] +function notComps() { + if (HEAP32[$incdec_ptr71_i + 8 >> 2] != 0) { + shoo(); + } +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits", "maths", "hoisting", "demangle", "lua", "moreLabels", "notComps"] diff --git a/tools/test-js-optimizer.js b/tools/test-js-optimizer.js index 95985bc8..18c9ac75 100644 --- a/tools/test-js-optimizer.js +++ b/tools/test-js-optimizer.js @@ -226,6 +226,65 @@ function hoisting() { $if_then72$$if_end73$126 : do { if (__label__ == 40) {} else if (__label__ == 41) {} } while (0); + pause(10); + while(check()) { + if ($i < $N) { + __label__ = 2; + } else { + __label__ = 3; + } + if (__label__ == 2) { + callOther(); + break; + } else if (__label__ == 3) { + somethingElse(); + } + if ($i1 < $N) { + __label__ = 2; + } else { + __label__ = 3; + } + if (__label__ == 2) { + callOther(); + continue; + } else if (__label__ == 3) { + somethingElse(); + } + if ($i2 < $N) { + __label__ = 2; + } else { + __label__ = 3; + } + if (__label__ == 2) { + callOther(); + } else if (__label__ == 3) { + somethingElse(); + break; + } + if ($i3 < $N) { + __label__ = 2; + } else { + __label__ = 3; + } + if (__label__ == 2) { + callOther(); + } else if (__label__ == 3) { + somethingElse(); + continue; + } + if ($i4 < $N) { + __label__ = 2; + } else { + __label__ = 3; + } + if (__label__ == 2) { + callOther(); + break; + } else if (__label__ == 3) { + somethingElse(); + continue; + } + } } function innerShouldAlsoBeHoisted() { function hoisting() { @@ -358,4 +417,9 @@ function moreLabels() { var $_lcssa; cheez(); } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits", "maths", "hoisting", "demangle", "lua", "moreLabels"] +function notComps() { + if (!(HEAP32[$incdec_ptr71_i + 8 >> 2] == 0)) { + shoo(); + } +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["abc", "xyz", "xyz2", "expr", "loopy", "bits", "maths", "hoisting", "demangle", "lua", "moreLabels", "notComps"] |