diff --git a/docs/paper.pdf b/docs/paper.pdf index 755eaddc2..401162ace 100644 Binary files a/docs/paper.pdf and b/docs/paper.pdf differ diff --git a/docs/paper.tex b/docs/paper.tex index 5687788f8..4ad795b88 100644 --- a/docs/paper.tex +++ b/docs/paper.tex @@ -30,7 +30,7 @@ \begin{abstract} We present Emscripten, a compiler from LLVM (Low Level Virtual Machine) assembly to JavaScript. This opens up two avenues for running code written -in languages other than JavaScript on the web: (1) Compile code directly into LLVM assemby, and +in languages other than JavaScript on the web: (1) Compile code directly into LLVM assembly, and then compile that into JavaScript using Emscripten, or (2) Compile a language's entire runtime into LLVM and then JavaScript, as in the previous approach, and then use the compiled runtime to run code written in that language. For example, the @@ -477,7 +477,7 @@ reading from memory before a value was written (somewhat similarly to tools like Valgrind\footnote{\url{http://valgrind.org/}}). When such problems are detected, possible solutions are to ignore the issue (if it has no actual consqeuences), or alter the source code. -Note that it is somewhat wasteful to allocation 4 memory locations for +Note that it is somewhat wasteful to allocate 4 memory locations for a 32-bit integer, and use only one of them. It is possible to change that behavior with the QUANTUM\_SIZE parameter to Emscripten, however, the difficulty is that LLVM assembly has hardcoded values that depend on diff --git a/settings.py b/settings.py index 31f115c23..9773aa1ea 100644 --- a/settings.py +++ b/settings.py @@ -13,13 +13,11 @@ COMPILER_OPTS = ['-m32', '-g'] # Need to build as 32bit arch, for now - # various errors on 64bit compilation # WARNING: '-g' here will generate llvm bitcode that lli will crash on! -SPIDERMONKEY_ENGINE = [os.path.expanduser('~/Dev/tracemonkey/js/src/js'), '-m', '-j', '-p'] +SPIDERMONKEY_ENGINE = [os.path.expanduser('~/Dev/mozilla-central/js/src/js'), '-m', '-j', '-p'] V8_ENGINE = [os.path.expanduser('~/Dev/v8/d8')] -# XXX Warning: Compiling the 'cubescript' test in SpiderMonkey can lead to an extreme amount of memory being -# used, see Mozilla bug 593659. Possibly also some other tests as well. -#COMPILER_ENGINE=SPIDERMONKEY_ENGINE -COMPILER_ENGINE=V8_ENGINE +COMPILER_ENGINE=SPIDERMONKEY_ENGINE +#COMPILER_ENGINE=V8_ENGINE # XXX Warning: currently appears to be broken on v8 trunk, some arguments issue JS_ENGINE=V8_ENGINE diff --git a/src/library.js b/src/library.js index 031cf42da..e6fee62e2 100644 --- a/src/library.js +++ b/src/library.js @@ -1783,7 +1783,7 @@ LibraryManager.library = { return -1; } }, - getlogin: ['getlogin_r'], + getlogin__deps: ['getlogin_r'], getlogin: function() { // char *getlogin(void); // http://pubs.opengroup.org/onlinepubs/000095399/functions/getlogin.html diff --git a/src/modules.js b/src/modules.js index 04b777fe1..6b8d880a4 100644 --- a/src/modules.js +++ b/src/modules.js @@ -235,7 +235,7 @@ var LibraryManager = { load: function() { assert(!this.library); - for (suffix in set('', '_sdl', '_gl', '_browser')) { + for (var suffix in set('', '_sdl', '_gl', '_browser')) { eval(processMacros(preprocess(read('library' + suffix + '.js'), CONSTANTS))); } }, diff --git a/src/parseTools.js b/src/parseTools.js index 4a3867efb..2985ccb60 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -13,7 +13,7 @@ function processMacros(text) { // Simple #if/else/endif preprocessing for a file. Checks if the // ident checked is true in our global. Also replaces some constants. function preprocess(text, constants) { - for (constant in constants) { + for (var constant in constants) { text = text.replace(eval('/' + constant + '/g'), constants[constant]); } var lines = text.split('\n'); diff --git a/src/preamble.js b/src/preamble.js index 21e9021e4..99288244c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -301,6 +301,43 @@ function assert(condition, text) { } } +// Sets a value in memory in a dynamic way at run-time. Uses the +// type data. This is the same as makeSetValue, except that +// makeSetValue is done at compile-time and generates the needed +// code then, whereas this function picks the right code at +// run-time. + +function setValue(ptr, value, type) { + if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit + switch(type) { + case 'i1': {{{ makeSetValue('ptr', '0', 'value', 'i1') }}}; break; + case 'i8': {{{ makeSetValue('ptr', '0', 'value', 'i8') }}}; break; + case 'i16': {{{ makeSetValue('ptr', '0', 'value', 'i16') }}}; break; + case 'i32': {{{ makeSetValue('ptr', '0', 'value', 'i32') }}}; break; + case 'i64': {{{ makeSetValue('ptr', '0', 'value', 'i64') }}}; break; + case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float') }}}; break; + case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double') }}}; break; + default: abort('invalid type for setValue: ' + type); + } +} + +// Parallel to setValue. + +function getValue(ptr, type) { + if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit + switch(type) { + case 'i1': return {{{ makeGetValue('ptr', '0', 'i1') }}}; + case 'i8': return {{{ makeGetValue('ptr', '0', 'i8') }}}; + case 'i16': return {{{ makeGetValue('ptr', '0', 'i16') }}}; + case 'i32': return {{{ makeGetValue('ptr', '0', 'i32') }}}; + case 'i64': return {{{ makeGetValue('ptr', '0', 'i64') }}}; + case 'float': return {{{ makeGetValue('ptr', '0', 'float') }}}; + case 'double': return {{{ makeGetValue('ptr', '0', 'double') }}}; + default: abort('invalid type for setValue: ' + type); + } + return null; +} + // Allocates memory for some data and initializes it properly. var ALLOC_NORMAL = 0; // Tries to use _malloc() @@ -338,30 +375,8 @@ function allocate(slab, types, allocator) { assert(type, 'Must know what type to store in allocate!'); #endif - if (type === 'i1') { - {{{ makeSetValue(0, 'ret+i', 'curr', 'i1') }}} - i += {{{ getNativeFieldSize('i1', true) }}}; - } else if (type === 'i8') { - {{{ makeSetValue(0, 'ret+i', 'curr', 'i8') }}} - i += {{{ getNativeFieldSize('i8', true) }}}; - } else if (type === 'i16') { - {{{ makeSetValue(0, 'ret+i', 'curr', 'i16') }}} - i += {{{ getNativeFieldSize('i16', true) }}}; - } else if (type === 'i32' || type[type.length-1] === '*') { // hardcoded pointers as 32-bit - {{{ makeSetValue(0, 'ret+i', 'curr', 'i32') }}} - i += {{{ getNativeFieldSize('i32', true) }}}; - } else if (type === 'float') { - {{{ makeSetValue(0, 'ret+i', 'curr', 'float') }}} - i += {{{ getNativeFieldSize('float', true) }}}; - } else if (type === 'i64') { - {{{ makeSetValue(0, 'ret+i', 'curr', 'i64') }}} - i += {{{ getNativeFieldSize('i64', true) }}}; - } else if (type === 'double') { - {{{ makeSetValue(0, 'ret+i', 'curr', 'double') }}} - i += {{{ getNativeFieldSize('double', true) }}}; - } else { - abort('invalid type for allocate: ' + type); - } + setValue(ret+i, curr, type); + i += Runtime.getNativeFieldSize(type, true); } return ret; diff --git a/src/shell.js b/src/shell.js index c73cf6e4e..06cf4175d 100644 --- a/src/shell.js +++ b/src/shell.js @@ -13,9 +13,13 @@ if (!this['Module']) { this['Module'] = {}; } try { - Module.arguments = arguments; + Module.arguments = scriptArgs; } catch(e) { - Module.arguments = []; + try { + Module.arguments = arguments; + } catch(e) { + Module.arguments = []; + } } //*/ diff --git a/tests/runner.py b/tests/runner.py index 10cb35c84..e3f0e0e60 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -2895,7 +2895,7 @@ if 'benchmark' not in sys.argv: lambda: map(ord, open(path_from_root('tests', 'poppler', 'ref.ppm'), 'r').read()).__str__().replace(' ', ''), args='-scale-to 512 paper.pdf filename'.split(' '), post_build=post, - js_engines=[SPIDERMONKEY_ENGINE]) # V8 bug 1257 + js_engines=[V8_ENGINE]) # XXX Moz bug 675269 #, build_ll_hook=self.do_autodebug) def test_openjpeg(self): @@ -3141,12 +3141,14 @@ if 'benchmark' not in sys.argv: Child1(int val) : Parent(val*2) { value -= 1; printf("Child1:%d\\n", value); }; int getValSqr() { return value*value; } int getValSqr(int more) { return value*value*more; } + int getValTimes(int times=1) { return value*times; } }; - class Child2 : Parent { + class Child2 : public Parent { public: Child2() : Parent(9) { printf("Child2:%d\\n", value); }; int getValCube() { return value*value*value; } + static void printStatic() { printf("*static*\\n"); } private: void doSomethingSecret() { printf("security breached!\\n"); }; // we should not be able to do this }; @@ -3155,6 +3157,7 @@ if 'benchmark' not in sys.argv: basename = os.path.join(self.get_dir(), 'bindingtest') output = Popen([BINDINGS_GENERATOR, basename, header_filename], stdout=PIPE, stderr=STDOUT).communicate()[0] + #print output assert 'Traceback' not in output, 'Failure in binding generation: ' + output src = ''' @@ -3179,16 +3182,18 @@ if 'benchmark' not in sys.argv: c1.mulVal(2); print(c1.getVal()); print(c1.getValSqr()); - print(c1.getValSqr_2(3)); + print(c1.getValSqr(3)); + print(c1.getValTimes()); // default argument should be 1 + print(c1.getValTimes(2)); print('c1 v2'); - c1 = new Child1_2(8); + c1 = new Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2 print(c1.getVal()); c1.mulVal(2); print(c1.getVal()); print(c1.getValSqr()); - print(c1.getValSqr_2(3)); + print(c1.getValSqr(3)); print('c2') @@ -3217,6 +3222,8 @@ if 'benchmark' not in sys.argv: } catch(e) {} print(succeeded); + Child2.prototype.printStatic(); // static calls go through the prototype + print('*ok*'); ''' @@ -3236,6 +3243,8 @@ Child1:7 14 196 588 +14 +28 c1 v2 Parent:16 Child1:15 @@ -3252,6 +3261,7 @@ Child2:9 0 0 1 +*static* *ok* ''', post_build=post2) @@ -3668,7 +3678,8 @@ else: USE_CLOSURE_COMPILER = 1 if USE_CLOSURE_COMPILER: - SPIDERMONKEY_ENGINE = filter(lambda x: x != '-s', SPIDERMONKEY_ENGINE) # closure generates non-strict + index = SPIDERMONKEY_ENGINE.index("options('strict')") + SPIDERMONKEY_ENGINE = SPIDERMONKEY_ENGINE[:index-1] + SPIDERMONKEY_ENGINE[index+1:] # closure generates non-strict COMPILER = CLANG JS_ENGINE = SPIDERMONKEY_ENGINE diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py index 61d049425..2abc5bf3d 100755 --- a/tools/bindings_generator.py +++ b/tools/bindings_generator.py @@ -47,7 +47,7 @@ import CppHeaderParser basename = sys.argv[1] -processor = lambda line: line +processor = lambda text: text ignored = [] if '--' in sys.argv: @@ -62,54 +62,124 @@ if '--' in sys.argv: classes = {} struct_parents = {} +text = '' +for header in sys.argv[2:]: + text += '//// ' + header + '\n' + text += open(header, 'r').read() all_h_name = basename + '.all.h' all_h = open(all_h_name, 'w') -for header in sys.argv[2:]: - all_h.write('//// ' + header + '\n') - all_h.write(processor(open(header, 'r').read())) - +all_h.write(processor(text)) all_h.close() parsed = CppHeaderParser.CppHeader(all_h_name) -for cname, clazz in parsed.classes.iteritems(): - #print 'zz see', cname - if len(clazz['methods']['public']) > 0: # Do not notice stub classes - #print 'zz for real', cname, clazz, dir(clazz) - classes[cname] = clazz - for sname, struct in clazz._public_structs.iteritems(): - struct_parents[sname] = cname - #print 'zz seen struct %s in %s' % (sname, cname) +for classname, clazz in parsed.classes.iteritems(): + print 'zz see', classname + classes[classname] = clazz + for sname, struct in clazz._public_structs.iteritems(): + struct_parents[sname] = classname + #print 'zz seen struct %s in %s' % (sname, classname) + + # Various precalculations + for method in clazz['methods']['public'][:]: + constructor = method['name'] == classname + method['constructor'] = constructor # work around cppheaderparser issue + args = method['parameters'] + + default_param = len(args)+1 + for i in range(len(args)): + if args[i].get('default'): + default_param = i+1 + break + + method['num_args'] = set(range(default_param-1, len(args)+1)) + print 'zz ', classname, 'has num_args of', method['num_args'] + + if method['static']: + method['rtnType'] = method['rtnType'].replace('static', '') + +# Explore all functions we need to generate, including parent classes, handling of overloading, etc. + +for classname, clazz in parsed.classes.iteritems(): + clazz['final_methods'] = {} + + def explore(subclass): + # Do our functions first, and do not let later classes override + for method in subclass['methods']['public']: + if method['constructor']: + if clazz != subclass: continue # Subclasses cannot directly use their parent's constructors + if method['destructor']: continue # Nothing to do there + + if method['name'] not in clazz['final_methods']: + clazz['final_methods'][method['name']] = {} + for key in ['name', 'constructor', 'static', 'rtnType', 'destructor', 'pure_virtual']: + clazz['final_methods'][method['name']][key] = method[key] + clazz['final_methods'][method['name']]['num_args'] = method['num_args'].copy() + clazz['final_methods'][method['name']]['parameters'] = method['parameters'][:] + clazz['final_methods'][method['name']]['origin'] = subclass + else: + # Merge the new function in the best way we can. Shared arguments must match! + + curr = clazz['final_methods'][method['name']] + + if curr['origin'] is not subclass: continue # child class functions mask/hide parent functions of the same name in C++ + + if any([curr['parameters'][i]['type'] != method['parameters'][i]['type'] for i in range(min(len(curr['parameters']), len(method['parameters'])))]): + print 'Warning: Cannot mix in overloaded functions', method['name'], 'in class', classname, ', skipping' + continue + # TODO: Other compatibility checks, if any? + + if len(method['parameters']) > len(curr['parameters']): + curr['parameters'] = method['parameters'] + + curr['num_args'] = curr['num_args'].union(method['num_args']) + print 'zz ', classname, 'has an updated num_args of ', curr['num_args'] + + # Recurse + for parent in subclass['inherits']: + if parent['class'] not in classes: + print 'Warning: parent class', parent, 'not a known class. Ignoring.' + return + explore(classes[parent['class']]) + + explore(clazz) + + for method in clazz['final_methods'].itervalues(): + method['num_args'] = list(method['num_args']) + method['num_args'].sort() # Second pass - generate bindings # TODO: Bind virtual functions using dynamic binding in the C binding code funcs = {} # name -> # of copies in the original, and originalname in a copy +c_funcs = [] gen_c = open(basename + '.c', 'w') gen_js = open(basename + '.js', 'w') gen_c.write('extern "C" {\n') -def generate_class(generating_cname, cname, clazz): - inherited = generating_cname != cname +def generate_class(generating_classname, classname, clazz): # TODO: deprecate generating? + inherited = generating_classname != classname - for method in clazz['methods']['public']: + for method in clazz['final_methods'].itervalues(): mname = method['name'] - #print "zz generating: ", generating_cname, cname, mname - if cname + '::' + mname in ignored: continue + if classname + '::' + mname in ignored: continue args = method['parameters'] - constructor = mname == cname + constructor = method['constructor'] # we fixed this before destructor = method['destructor'] + static = method['static'] + + print "zz generating: ", generating_classname, classname, mname, constructor, method['rtnType'] if destructor: continue if constructor and inherited: continue - if method['pure_virtual']: continue skip = False for i in range(len(args)): - #print 'zz arggggggg', cname, 'x', mname, 'x', args[i]['name'], 'x', args[i]['type'], 'x' + #print 'zz arggggggg', classname, 'x', mname, 'x', args[i]['name'], 'x', args[i]['type'], 'x', dir(args[i]), 'y', args[i].get('default'), 'z', args[i].get('defaltValue'), args[i].keys() + if args[i]['name'].replace(' ', '') == '': args[i]['name'] = 'arg' + str(i+1) elif args[i]['name'] == '&': @@ -117,7 +187,7 @@ def generate_class(generating_cname, cname, clazz): args[i]['type'] += '&' if '>' in args[i]['name']: - print 'WARNING: odd ">" in %s, skipping' % cname + print 'WARNING: odd ">" in %s, skipping' % classname skip = True break #print 'c1', struct_parents.keys() @@ -129,14 +199,12 @@ def generate_class(generating_cname, cname, clazz): elif sname.replace('const ', '') in struct_parents: sname = sname.replace('const ', '') args[i]['type'] = 'const ' + struct_parents[sname] + '::' + sname + '&' - #print 'POST arggggggg', cname, 'x', mname, 'x', args[i]['name'], 'x', args[i]['type'] + #print 'POST arggggggg', classname, 'x', mname, 'x', args[i]['name'], 'x', args[i]['type'] if skip: continue - # C - - ret = ((cname + ' *') if constructor else method['rtnType']).replace('virtual ', '') - callprefix = 'new ' if constructor else 'self->' + ret = ((classname + ' *') if constructor else method['rtnType']).replace('virtual ', '') + callprefix = 'new ' if constructor else ('self->' if not static else (classname + '::')) actualmname = '' if mname == '__operator___assignment_': @@ -170,100 +238,145 @@ def generate_class(generating_cname, cname, clazz): callprefix = '*self - ' continue # TODO else: - actualmname = mname + actualmname = method.get('truename') or mname - typedargs = ', '.join( ([] if constructor else [cname + ' * self']) + map(lambda arg: arg['type'] + ' ' + arg['name'], args) ) - justargs = ', '.join(map(lambda arg: arg['name'], args)) - fullname = 'emscripten_bind_' + generating_cname + '__' + mname - generating_cname_suffixed = generating_cname + need_self = not constructor and not static + typedargs = ([] if not need_self else [classname + ' * self']) + map(lambda arg: arg['type'] + ' ' + arg['name'], args) + justargs = map(lambda arg: arg['name'], args) + fullname = 'emscripten_bind_' + generating_classname + '__' + mname + generating_classname_suffixed = generating_classname mname_suffixed = mname count = funcs.setdefault(fullname, 0) funcs[fullname] += 1 # handle overloading + dupe = False if count > 0: + dupe = True suffix = '_' + str(count+1) - funcs[fullname + suffix] = fullname # this should never change + funcs[fullname + suffix] = 0 fullname += suffix mname_suffixed += suffix if constructor: - generating_cname_suffixed += suffix + generating_classname_suffixed += suffix - gen_c.write(''' -%s %s(%s) { + argfixes = '\n'.join(map(lambda arg: ''' %s = (%s && %s.ptr) ? %s.ptr : %s;''' % (arg['name'], arg['name'], arg['name'], arg['name'], arg['name']), args)) + + for i in method['num_args']: + # C + + gen_c.write(''' +%s %s_p%d(%s) { %s%s%s(%s); } -''' % (ret, fullname, typedargs, 'return ' if ret.replace(' ', '') != 'void' else '', callprefix, actualmname, justargs)) +''' % (ret, fullname, i, ', '.join(typedargs[:i + (0 if not need_self else 1)]), 'return ' if ret.replace(' ', '') != 'void' else '', callprefix, actualmname, ', '.join(justargs[:i]))) + + c_funcs.append(fullname + '_p' + str(i)) # JS - - if constructor: - dupe = type(funcs[fullname]) is str - if not dupe: - gen_js.write(''' -function %s(%s) { - this.ptr = _%s(%s); -} -''' % (generating_cname_suffixed, justargs, fullname, justargs)) + calls = '' + print 'js loopin', method['num_args'], '|', len(args), args + for i in method['num_args']: + print ' ', i, type(i) + if i != method['num_args'][0]: + calls += ' else ' + if i != method['num_args'][-1]: + calls += ' if (' + justargs[i] + ' === undefined)' + calls += '\n ' + (' ' if len(method['num_args']) > 0 else '') + if constructor: + if not dupe: + calls += '''this.ptr = _%s_p%d(%s); +''' % (fullname, i, ', '.join(justargs[:i])) + else: + calls += '''this.ptr = _%s_p%d(%s); +''' % (fullname, i, ', '.join(justargs[:i])) else: - gen_js.write(''' + calls += '''%s_%s_p%d(%s); +''' % ('return ' if ret != 'void' else '', fullname, i, ', '.join((['this.ptr'] if need_self else []) + justargs[:i])) + + print 'Maekin:', classname, generating_classname, mname, mname_suffixed + if constructor: + if not dupe: + js_text = ''' function %s(%s) { - this.ptr = _%s(%s); +%s +%s +} +''' % (mname_suffixed, ', '.join(justargs), argfixes, calls) + else: + js_text = ''' +function %s(%s) { +%s +%s } %s.prototype = %s.prototype; -''' % (generating_cname_suffixed, justargs, fullname, justargs, generating_cname_suffixed, cname)) +''' % (mname_suffixed, ', '.join(justargs), argfixes, calls, mname_suffixed, classname) else: - gen_js.write(''' + js_text = ''' %s.prototype.%s = function(%s) { - %s_%s(this.ptr%s); +%s +%s } -''' % (generating_cname, mname_suffixed, justargs, 'return ' if ret != 'void' else '', fullname, (', ' if len(justargs) > 0 else '') + justargs)) +''' % (generating_classname, mname_suffixed, ', '.join(justargs), argfixes, calls) -for cname, clazz in classes.iteritems(): - if cname in ignored: continue + js_text = js_text.replace('\n\n', '\n').replace('\n\n', '\n') + gen_js.write(js_text) + +# Main loop + +for classname, clazz in classes.iteritems(): + if classname in ignored: continue # Nothing to generate for pure virtual classes def check_pure_virtual(clazz, progeny): - if any([check_pure_virtual(classes[parent['class']], [clazz] + progeny) for parent in clazz['inherits']]): return True + print 'Checking pure virtual for', clazz['name'], clazz['inherits'] + # If we do not recognize any of the parent classes, assume this is pure virtual - ignore it + if any([((not parent['class'] in classes) or check_pure_virtual(classes[parent['class']], [clazz] + progeny)) for parent in clazz['inherits']]): return True def dirtied(mname): + #print 'zz checking dirtiness for', mname, 'in', progeny for progen in progeny: - for method in clazz['methods']['public']: - if method['name'] == mname and not method['pure_virtual']: return True + for method in progen['methods']['public']: + if method['name'] == mname and not method['pure_virtual']: + #print 'zz dirty' + return True + #print 'zz not dirtied' return False for method in clazz['methods']['public']: - if method['pure_virtual'] and not dirtied(method['name']): return True + if method['pure_virtual'] and not dirtied(method['name']): + print 'zz ignoring pure virtual class', classname, 'due to', method['name'] + return True - if check_pure_virtual(clazz, []): continue + if check_pure_virtual(clazz, []): + continue # Add a constructor if none exist has_constructor = False for method in clazz['methods']['public']: mname = method['name'] - has_constructor = has_constructor or (cname == mname) + has_constructor = has_constructor or (classname == mname and not method['destructor']) + + print 'zz ', classname, 'has constructor?', has_constructor if not has_constructor: + print 'zz no constructor for', classname, 'so ignoring' + continue + clazz['methods']['public'] = [{ - 'name': cname, + 'name': classname, 'parameters': [], 'pure_virtual': False, 'destructor': False, }] + clazz['methods']['public'] - generate_class(cname, cname, clazz) - - # In addition, generate all methods of parent classes. We do not inherit in JS (how would we do multiple inheritance etc.?) - for parent in clazz['inherits']: - generate_class(cname, parent['class'], classes[parent['class']]) + generate_class(classname, classname, clazz) # TODO: Add a destructor # Finish up -funcs = funcs.keys() - gen_c.write(''' } @@ -275,9 +388,9 @@ struct EmscriptenEnsurer // Actually use the binding functions, so DFE will not eliminate them int sum = 0; void *seen = (void*)%s; -''' % funcs[0]) +''' % c_funcs[0]) -for func in funcs[1:]: +for func in c_funcs[1:]: gen_c.write(''' sum += (void*)%s == seen; ''' % func) diff --git a/tools/emmaken.py b/tools/emmaken.py index e6e33cb6e..8539d7b66 100755 --- a/tools/emmaken.py +++ b/tools/emmaken.py @@ -87,8 +87,8 @@ try: CC_ARG_SKIP = ['-O1', '-O2', '-O3'] CC_ADDITIONAL_ARGS = ['-m32', '-g', '-U__i386__', '-U__x86_64__', '-U__i386', '-U__x86_64', '-U__SSE__', '-U__SSE2__', '-UX87_DOUBLE_ROUNDING', '-UHAVE_GCC_ASM_FOR_X87'] ALLOWED_LINK_ARGS = ['-f', '-help', '-o', '-print-after', '-print-after-all', '-print-before', - '-print-before-all', '-time-passes', '-v', '-verify-dom-info', '-version' ] - DISALLOWED_LINK_ARGS = []#['rc'] + '-print-before-all', '-time-passes', '-v', '-verify-dom-info', '-version' ] + TWO_PART_DISALLOWED_LINK_ARGS = ['-L'] # Ignore thingsl like |-L .| EMMAKEN_CFLAGS = os.environ.get('EMMAKEN_CFLAGS') if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += EMMAKEN_CFLAGS.split(' ') @@ -125,7 +125,7 @@ try: if '--version' in opts: use_linker = False - if set(sys.argv[1]).issubset(set('cru')): # ar + if set(sys.argv[1]).issubset(set('cruqs')): # ar sys.argv = sys.argv[:1] + sys.argv[3:] + ['-o='+sys.argv[2]] assert use_linker, 'Linker should be used in this case' @@ -133,7 +133,10 @@ try: call = LLVM_LINK newargs = [] found_o = False - for arg in sys.argv[1:]: + i = 0 + while i < len(sys.argv)-1: + i += 1 + arg = sys.argv[i] if found_o: newargs.append('-o=%s' % arg) found_o = False @@ -145,12 +148,13 @@ try: prefix = arg.split('=')[0] if prefix in ALLOWED_LINK_ARGS: newargs.append(arg) + if arg in TWO_PART_DISALLOWED_LINK_ARGS: + i += 1 elif arg.endswith('.so'): continue # .so's do not exist yet, in many cases else: # not option, so just append - if arg not in DISALLOWED_LINK_ARGS: - newargs.append(arg) + newargs.append(arg) elif not header: call = CXX if use_cxx else CC newargs = [ arg for arg in sys.argv[1:] if arg not in CC_ARG_SKIP ] + CC_ADDITIONAL_ARGS @@ -170,6 +174,6 @@ try: os.execvp(call, [call] + newargs) except Exception, e: - print 'Error in emmaken.py. Is the config file ~/.emscripten set up properly?', e + print 'Error in emmaken.py. (Is the config file ~/.emscripten set up properly?) Error:', e raise diff --git a/tools/shared.py b/tools/shared.py index 9ccc21054..0ee9a0ac6 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -25,8 +25,8 @@ BINDINGS_GENERATOR = path_from_root('tools', 'bindings_generator.py') # Engine tweaks -if '-s' not in SPIDERMONKEY_ENGINE: - SPIDERMONKEY_ENGINE += ['-s'] # Strict mode in SpiderMonkey. With V8 we check that fallback to non-strict works too +if 'strict' not in str(SPIDERMONKEY_ENGINE): + SPIDERMONKEY_ENGINE += ['-e', "options('strict')"] # Strict mode in SpiderMonkey. With V8 we check that fallback to non-strict works too if 'gcparam' not in str(SPIDERMONKEY_ENGINE): SPIDERMONKEY_ENGINE += ['-e', "gcparam('maxBytes', 1024*1024*1024);"] # Our very large files need lots of gc heap