aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormax99x <max99x@gmail.com>2011-07-30 04:02:27 +0300
committermax99x <max99x@gmail.com>2011-07-30 04:02:27 +0300
commita6e44cf635adb9a46f86f655075f3817c741f76e (patch)
treef108ae5e8f664740244bf4839fcbf9855f9a737a
parentefacab6cd2ee666207ece72478c261dbaf476322 (diff)
parentda3cce725967ce04bdf62d73faf2d947f8063d0a (diff)
Merge remote-tracking branch 'upstream/master'
-rw-r--r--docs/paper.pdfbin220464 -> 220318 bytes
-rw-r--r--docs/paper.tex4
-rw-r--r--settings.py8
-rw-r--r--src/library.js2
-rw-r--r--src/modules.js2
-rw-r--r--src/parseTools.js2
-rw-r--r--src/preamble.js63
-rw-r--r--src/shell.js8
-rw-r--r--tests/runner.py23
-rwxr-xr-xtools/bindings_generator.py243
-rwxr-xr-xtools/emmaken.py18
-rw-r--r--tools/shared.py4
12 files changed, 261 insertions, 116 deletions
diff --git a/docs/paper.pdf b/docs/paper.pdf
index 755eaddc..401162ac 100644
--- a/docs/paper.pdf
+++ b/docs/paper.pdf
Binary files differ
diff --git a/docs/paper.tex b/docs/paper.tex
index 5687788f..4ad795b8 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 31f115c2..9773aa1e 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 031cf42d..e6fee62e 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 04b777fe..6b8d880a 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 4a3867ef..2985ccb6 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 21e9021e..99288244 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 c73cf6e4..06cf4175 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 10cb35c8..e3f0e0e6 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 61d04942..2abc5bf3 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
+
+ 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(%s) {
+ 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
+ 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:
+ 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:
- dupe = type(funcs[fullname]) is str
if not dupe:
- gen_js.write('''
+ js_text = '''
function %s(%s) {
- this.ptr = _%s(%s);
+%s
+%s
}
-''' % (generating_cname_suffixed, justargs, fullname, justargs))
+''' % (mname_suffixed, ', '.join(justargs), argfixes, calls)
else:
- gen_js.write('''
+ js_text = '''
function %s(%s) {
- this.ptr = _%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)
+
+ js_text = js_text.replace('\n\n', '\n').replace('\n\n', '\n')
+ gen_js.write(js_text)
+
+# Main loop
-for cname, clazz in classes.iteritems():
- if cname in ignored: continue
+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 e6e33cb6..8539d7b6 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 9ccc2105..0ee9a0ac 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