-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Source maps (Refs #1252, Reopens #1267) #1274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
86e672a
Commit the source-map library.
int3 747f74e
Implement basic source maps. Closes #1252.
int3 165befa
Add check for keep_llvm_debug + minor touchups.
int3 2f16717
Add test for source maps.
int3 2c0dcd9
Ensure line numbers are the same in HTML.
int3 af52a9a
Fix source map line numbering for inline scripts.
int3 be5d45f
Add test for HTML source map generation.
int3 7656f94
Lay the groundwork for optimized source maps.
int3 0c3cb93
Delete uglify code that was only needed for compression.
int3 0f73e28
Map source lines for assignment statements.
int3 54a59be
Move source mapping files into their own folder.
int3 050335f
Update the source-map library.
int3 d680f5e
Implement source maps for optimized builds.
int3 486413c
Make sure the line numbers sync up.
int3 cfe4eb5
Source maps should only be activated via the `--map` flag.
int3 5459b35
Fix line numbering for invoke instructions.
int3 99fa57e
Make test_debug actually fail when things go wrong.
int3 7212198
Make optimizer handle both strings and string-like type objects.
int3 4eef4be
Put uglify back the way it was.
int3 d50e7b4
Improvements to test_html_source_map.
int3 88feddf
Get test_source_map passing again.
int3 9382556
Test that source mapping works with EMCC_DEBUG=2.
int3 6103884
Ensure JS output remains the same when making source maps.
int3 3a84846
Centralize debug options in a -gX flag.
int3 2b54c4f
Fix up the source map JS output 'reftest'.
int3 7ff0dde
Merge remote-tracking branch 'upstream/incoming' into source-maps
int3 5eaa7ba
Ensure original test environment is restored.
int3 452b871
Optimize!
int3 6768d77
Clean up emcc flag parsing + help message.
int3 0c19e40
Get rid of stale comment.
int3 5664470
Move line numbers to the AST node itself.
int3 e3a37fc
Strict compare all the things!
int3 e08502d
We can just compare for strings here.
int3 5383aa8
Reuse nodes where possible.
int3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,7 +49,7 @@ emcc can be influenced by a few environment variables: | |
|
||
import os, sys, shutil, tempfile, subprocess, shlex, time, re, logging | ||
from subprocess import PIPE, STDOUT | ||
from tools import shared | ||
from tools import shared, jsrun | ||
from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename | ||
from tools.response_file import read_response_file | ||
|
||
|
@@ -203,10 +203,18 @@ Options that are modified or new in %s include: | |
-g2 Preserve function names | ||
-g3 Preserve variable names | ||
-g4 Preserve LLVM debug info (if -g was | ||
used when compiling the C/C++ sources) | ||
and show line number debug comments. | ||
This is the highest level of debuggability. | ||
(default in -O0) | ||
used when compiling the C/C++ sources), | ||
show line number debug comments, and | ||
generate source maps. This is the highest | ||
level of debuggability. Note that this | ||
may make -O1 and above significantly | ||
slower because JS optimization will be | ||
limited to 1 core. (default in -O0) | ||
|
||
-g2 Like -g1, but we generate source maps as well, | ||
and we preserve comments even with -O1 and above. | ||
Note that this may be considerably slower because | ||
JS optimization is limited to a single core. | ||
|
||
--typed-arrays <mode> 0: No typed arrays | ||
1: Parallel typed arrays | ||
|
@@ -731,6 +739,14 @@ try: | |
|
||
settings_changes = [] | ||
|
||
def validate_arg_level(level_string, max_level, err_msg): | ||
try: | ||
level = int(level_string) | ||
assert 0 <= level <= max_level | ||
except: | ||
raise Exception(err_msg) | ||
return level | ||
|
||
for i in range(len(newargs)): | ||
newargs[i] = newargs[i].strip() # On Windows Vista (and possibly others), excessive spaces in the command line leak into the items in this array, so trim e.g. 'foo.cpp ' -> 'foo.cpp' | ||
if newargs[i].startswith('-O'): | ||
|
@@ -739,11 +755,7 @@ try: | |
if requested_level == 's': | ||
requested_level = 2 | ||
settings_changes.append('INLINING_LIMIT=50') | ||
try: | ||
opt_level = int(requested_level) | ||
assert 0 <= opt_level <= 3 | ||
except: | ||
raise Exception('Invalid optimization level: ' + newargs[i]) | ||
opt_level = validate_arg_level(requested_level, 3, 'Invalid optimization level: ' + newargs[i]) | ||
newargs[i] = '' | ||
elif newargs[i].startswith('--llvm-opts'): | ||
check_bad_eq(newargs[i]) | ||
|
@@ -787,12 +799,8 @@ try: | |
newargs[i+1] = '' | ||
elif newargs[i].startswith('-g'): | ||
requested_level = newargs[i][2:] or '3' | ||
try: | ||
debug_level = int(requested_level) | ||
assert 0 <= debug_level <= 4 | ||
except: | ||
raise Exception('Invalid debug level: ' + newargs[i]) | ||
newargs[i] = '-g' # discard level for clang args | ||
debug_level = validate_arg_level(requested_level, 4, 'Invalid debug level: ' + newargs[i]) | ||
newargs[i] = '-g' # we'll need this to get LLVM debug info | ||
elif newargs[i] == '--bind': | ||
bind = True | ||
newargs[i] = '' | ||
|
@@ -884,6 +892,11 @@ try: | |
if opt_level == 0: debug_level = 4 | ||
if closure is None and opt_level == 3: closure = True | ||
|
||
# TODO: support source maps with js_transform | ||
if js_transform and debug_level >= 4: | ||
logging.warning('disabling source maps because a js transform is being done') | ||
debug_level = 3 | ||
|
||
if DEBUG: start_time = time.time() # done after parsing arguments, which might affect debug state | ||
|
||
if closure: | ||
|
@@ -1408,6 +1421,7 @@ try: | |
# Optimize, if asked to | ||
if not LEAVE_INPUTS_RAW: | ||
link_opts = [] if debug_level >= 4 else ['-strip-debug'] # remove LLVM debug if we are not asked for it | ||
|
||
if llvm_opts > 0: | ||
if not os.environ.get('EMCC_OPTIMIZE_NORMALLY'): | ||
shared.Building.llvm_opt(in_temp(target_basename + '.bc'), llvm_opts) | ||
|
@@ -1495,9 +1509,11 @@ try: | |
final += '.tr.js' | ||
posix = True if not shared.WINDOWS else False | ||
logging.debug('applying transform: %s' % js_transform) | ||
execute(shlex.split(js_transform, posix=posix) + [os.path.abspath(final)]) | ||
subprocess.check_call(shlex.split(js_transform, posix=posix) + [os.path.abspath(final)]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This ensures that we throw an error when the transform fails, allowing failures in post-build hooks to be recorded by the test runner. |
||
if DEBUG: save_intermediate('transformed') | ||
|
||
js_transform_tempfiles = [final] | ||
|
||
# It is useful to run several js optimizer passes together, to save on unneeded unparsing/reparsing | ||
js_optimizer_queue = [] | ||
def flush_js_optimizer_queue(): | ||
|
@@ -1507,15 +1523,17 @@ try: | |
if shared.Settings.ASM_JS: | ||
js_optimizer_queue = ['asm'] + js_optimizer_queue | ||
logging.debug('applying js optimization passes: %s', js_optimizer_queue) | ||
final = shared.Building.js_optimizer(final, js_optimizer_queue, jcache) | ||
final = shared.Building.js_optimizer(final, js_optimizer_queue, jcache, debug_level >= 4) | ||
js_transform_tempfiles.append(final) | ||
if DEBUG: save_intermediate('js_opts') | ||
else: | ||
for name in js_optimizer_queue: | ||
passes = [name] | ||
if shared.Settings.ASM_JS: | ||
passes = ['asm'] + passes | ||
logging.debug('applying js optimization pass: %s', passes) | ||
final = shared.Building.js_optimizer(final, passes, jcache) | ||
final = shared.Building.js_optimizer(final, passes, jcache, debug_level >= 4) | ||
js_transform_tempfiles.append(final) | ||
save_intermediate(name) | ||
js_optimizer_queue = [] | ||
|
||
|
@@ -1524,7 +1542,8 @@ try: | |
|
||
if DEBUG == '2': | ||
# Clean up the syntax a bit | ||
final = shared.Building.js_optimizer(final, [], jcache) | ||
final = shared.Building.js_optimizer(final, [], jcache, debug_level >= 4) | ||
js_transform_tempfiles.append(final) | ||
if DEBUG: save_intermediate('pretty') | ||
|
||
def get_eliminate(): | ||
|
@@ -1542,6 +1561,8 @@ try: | |
flush_js_optimizer_queue() | ||
|
||
logging.debug('running closure') | ||
# no need to add this to js_transform_tempfiles, because closure and | ||
# debug_level > 0 are never simultaneously true | ||
final = shared.Building.closure_compiler(final) | ||
if DEBUG: save_intermediate('closure') | ||
|
||
|
@@ -1589,19 +1610,33 @@ try: | |
src = re.sub('/\* memory initializer \*/ allocate\(([\d,\.concat\(\)\[\]\\n ]+)"i8", ALLOC_NONE, Runtime\.GLOBAL_BASE\)', repl, src, count=1) | ||
open(final + '.mem.js', 'w').write(src) | ||
final += '.mem.js' | ||
js_transform_tempfiles[-1] = final # simple text substitution preserves comment line number mappings | ||
if DEBUG: | ||
if os.path.exists(memfile): | ||
save_intermediate('meminit') | ||
logging.debug('wrote memory initialization to %s' % memfile) | ||
else: | ||
logging.debug('did not see memory initialization') | ||
|
||
def generate_source_map(map_file_base_name, offset=0): | ||
jsrun.run_js(shared.path_from_root('tools', 'source-maps', 'sourcemapper.js'), | ||
shared.NODE_JS, js_transform_tempfiles + | ||
['--sourceRoot', os.getcwd(), | ||
'--mapFileBaseName', map_file_base_name, | ||
'--offset', str(offset)]) | ||
|
||
# If we were asked to also generate HTML, do that | ||
if final_suffix == 'html': | ||
logging.debug('generating HTML') | ||
shell = open(shell_path).read() | ||
html = open(target, 'w') | ||
if not Compression.on: | ||
if debug_level >= 4: | ||
match = re.match('.*?<script[^>]*>{{{ SCRIPT_CODE }}}</script>', shell, | ||
re.DOTALL) | ||
if match is None: | ||
raise RuntimeError('Could not find script insertion point') | ||
generate_source_map(target, match.group().count('\n')) | ||
html.write(shell.replace('{{{ SCRIPT_CODE }}}', open(final).read())) | ||
else: | ||
# Compress the main code | ||
|
@@ -1672,6 +1707,8 @@ try: | |
from tools.split import split_javascript_file | ||
split_javascript_file(final, unsuffixed(target), split_js_file) | ||
else: | ||
if debug_level >= 4: generate_source_map(target) | ||
|
||
# copy final JS to output | ||
shutil.move(final, target) | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -695,7 +695,9 @@ function JSify(data, functionsOnly, givenFunctions) { | |
} | ||
} | ||
i++; | ||
return JS + (Debugging.on ? Debugging.getComment(line.lineNum) : ''); | ||
// invoke instructions span two lines, and the debug info is located | ||
// on the second line, hence the +1 | ||
return JS + (Debugging.on ? Debugging.getComment(line.lineNum + (line.intertype === 'invoke' ? 1 : 0)) : ''); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice hack ;) |
||
}) | ||
.join('\n') | ||
.split('\n') // some lines include line breaks | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emcc now defines -g0 to -g4. this should go in -g4 (highest level of debuggability)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, missed this out while doing the merge.