Merge remote-tracking branch 'upstream/master'
This commit is contained in:
Коммит
a6e44cf635
Двоичные данные
docs/paper.pdf
Двоичные данные
docs/paper.pdf
Двоичный файл не отображается.
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = [];
|
||||
}
|
||||
}
|
||||
//*/
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче