aboutsummaryrefslogtreecommitdiff
path: root/emscripten.py
diff options
context:
space:
mode:
Diffstat (limited to 'emscripten.py')
-rwxr-xr-xemscripten.py109
1 files changed, 102 insertions, 7 deletions
diff --git a/emscripten.py b/emscripten.py
index 800ca8d7..7bf1bb03 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -25,6 +25,8 @@ WARNING: You should normally never use this! Use emcc instead.
from tools import shared
+DEBUG = os.environ.get('EMCC_DEBUG')
+
__rootpath__ = os.path.abspath(os.path.dirname(__file__))
def path_from_root(*pathelems):
"""Returns the absolute path for which the given path elements are
@@ -35,21 +37,114 @@ def path_from_root(*pathelems):
temp_files = shared.TempFiles()
+def scan(ll, settings):
+ # blockaddress(@main, %23)
+ blockaddrs = []
+ for blockaddr in re.findall('blockaddress\([^)]*\)', ll):
+ b = blockaddr.split('(')[1][:-1].split(', ')
+ blockaddrs.append(b)
+ if len(blockaddrs) > 0:
+ settings['NECESSARY_BLOCKADDRS'] = blockaddrs
+
def emscript(infile, settings, outfile, libraries=[]):
- """Runs the emscripten LLVM-to-JS compiler.
+ """Runs the emscripten LLVM-to-JS compiler. We parallelize as much as possible
Args:
infile: The path to the input LLVM assembly file.
- settings: JSON-formatted string of settings that overrides the values
+ settings: JSON-formatted settings that override the values
defined in src/settings.js.
outfile: The file where the output is written.
"""
- settings_file = temp_files.get('.txt').name # Save settings to a file to work around v8 issue 1579
+
+ compiler = path_from_root('src', 'compiler.js')
+
+ # Parallelization: We run 3 passes:
+ # 1 aka 'pre' : Process types and metadata and so forth, and generate the preamble.
+ # 2 aka 'funcs': Process functions. We can parallelize this, working on each function independently.
+ # 3 aka 'post' : Process globals, generate postamble and finishing touches.
+
+ # Pre-scan ll and alter settings as necessary
+ ll = open(infile).read()
+ scan(ll, settings)
+ ll = None # allow collection
+
+ # Split input into the relevant parts for each phase
+ pre = ''
+ funcs = [] # split up functions here, for parallelism later
+ meta = '' # needed by each function XXX
+ post = ''
+
+ in_func = False
+ ll_lines = open(infile).readlines()
+ for line in ll_lines:
+ if in_func:
+ funcs[-1] += line
+ if line.startswith('}'):
+ in_func = False
+ #pre += line # XXX pre needs function defs?
+ else:
+ if line.startswith('define '):
+ in_func = True
+ funcs.append(line)
+ #pre += line # XXX pre needs function defs?
+ elif line.find(' = type { ') > 0:
+ pre += line # type
+ elif line.startswith('!'):
+ meta += line # metadata
+ else:
+ post += line # global
+ pre += line # pre needs it to, so we know about globals in pre and funcs
+ ll_lines = None
+
+ #print '========= pre ================\n'
+ #print pre
+ #print '========== funcs ===============\n'
+ #for func in funcs:
+ # print '\n// ===\n\n', func
+ #print '========== post ==============\n'
+ #print post
+ #print '=========================\n'
+
+ # Save settings to a file to work around v8 issue 1579
+ settings_file = temp_files.get('.txt').name
s = open(settings_file, 'w')
- s.write(settings)
+ s.write(json.dumps(settings))
s.close()
- compiler = path_from_root('src', 'compiler.js')
- shared.run_js(compiler, shared.COMPILER_ENGINE, [settings_file, infile] + libraries, stdout=outfile, cwd=path_from_root('src'))
+
+ # Pass 1
+ if DEBUG: print >> sys.stderr, 'phase 1'
+ pre_file = temp_files.get('.ll').name
+ open(pre_file, 'w').write(pre)
+ out = shared.run_js(compiler, shared.COMPILER_ENGINE, [settings_file, pre_file, 'pre'] + libraries, stdout=subprocess.PIPE, cwd=path_from_root('src'))
+ js, forwarded_data = out.split('//FORWARDED_DATA:')
+ #print 'js', js
+ #print >> sys.stderr, 'FORWARDED_DATA 1:', forwarded_data, type(forwarded_data)
+ forwarded_file = temp_files.get('.json').name
+ open(forwarded_file, 'w').write(forwarded_data)
+
+ # Pass 2
+ if DEBUG: print >> sys.stderr, 'phase 2'
+ funcs_file = temp_files.get('.ll').name
+ open(funcs_file, 'w').write('\n'.join(funcs) + '\n' + meta)
+ #print 'pass 2c..'#, open(funcs_file).read()
+ out = shared.run_js(compiler, shared.COMPILER_ENGINE, [settings_file, funcs_file, 'funcs', forwarded_file] + libraries, stdout=subprocess.PIPE, cwd=path_from_root('src'))
+ funcs_js, forwarded_data = out.split('//FORWARDED_DATA:')
+ #print 'js', js
+ forwarded_file += '2'
+ #print >> sys.stderr, 'FORWARDED_DATA 2:', forwarded_data, type(forwarded_data), forwarded_file
+ open(forwarded_file, 'w').write(forwarded_data)
+ # XXX must coordinate function indexixing data when parallelizing
+ #print 'OUT\n', out
+ js += funcs_js
+
+ # Pass 3
+ if DEBUG: print >> sys.stderr, 'phase 3'
+ post_file = temp_files.get('.ll').name
+ open(post_file, 'w').write(post)
+ out = shared.run_js(compiler, shared.COMPILER_ENGINE, [settings_file, post_file, 'post', forwarded_file] + libraries, stdout=subprocess.PIPE, cwd=path_from_root('src'))
+ js += out
+
+ outfile.write(js)
outfile.close()
@@ -127,7 +222,7 @@ def main(args):
libraries = args.libraries[0].split(',') if len(args.libraries) > 0 else []
# Compile the assembly to Javascript.
- emscript(args.infile, json.dumps(settings), args.outfile, libraries)
+ emscript(args.infile, settings, args.outfile, libraries)
if __name__ == '__main__':
parser = optparse.OptionParser(