| Index: tools/foozzie/v8_foozzie.py | 
| diff --git a/tools/foozzie/v8_foozzie.py b/tools/foozzie/v8_foozzie.py | 
| index 8cfceb04203268b6030610a04fcea3e518521860..86194b9871ee6b477972a8a7bdf20156b60a474a 100755 | 
| --- a/tools/foozzie/v8_foozzie.py | 
| +++ b/tools/foozzie/v8_foozzie.py | 
| @@ -51,7 +51,7 @@ SUPPORTED_ARCHS = ['ia32', 'x64', 'arm', 'arm64'] | 
| FAILURE_HEADER_TEMPLATE = """# | 
| # V8 correctness failure | 
| # V8 correctness configs: %(configs)s | 
| -# V8 correctness sources: %(sources)s | 
| +# V8 correctness sources: %(source_key)s | 
| # V8 correctness suppression: %(suppression)s | 
| """ | 
|  | 
| @@ -69,6 +69,9 @@ FAILURE_TEMPLATE = FAILURE_HEADER_TEMPLATE + """# | 
| # Difference: | 
| %(difference)s | 
| # | 
| +# Source file: | 
| +%(source)s | 
| +# | 
| ### Start of configuration %(first_config_label)s: | 
| %(first_config_output)s | 
| ### End of configuration %(first_config_label)s | 
| @@ -79,6 +82,7 @@ FAILURE_TEMPLATE = FAILURE_HEADER_TEMPLATE + """# | 
| """ | 
|  | 
| FUZZ_TEST_RE = re.compile(r'.*fuzz(-\d+\.js)') | 
| +SOURCE_RE = re.compile(r'print\("v8-foozzie source: (.*)"\);') | 
|  | 
| def parse_args(): | 
| parser = argparse.ArgumentParser() | 
| @@ -117,14 +121,6 @@ def parse_args(): | 
| os.path.isfile(options.testcase)), ( | 
| 'Test case %s doesn\'t exist' % options.testcase) | 
|  | 
| -  # Deduce metadata file name from test case. This also removes | 
| -  # the prefix the test case might get during minimization. | 
| -  suffix = FUZZ_TEST_RE.match(os.path.basename(options.testcase)).group(1) | 
| -  options.meta_data_path = os.path.join( | 
| -      os.path.dirname(options.testcase), 'meta' + suffix) | 
| -  assert os.path.exists(options.meta_data_path), ( | 
| -      'Metadata %s doesn\'t exist' % options.meta_data_path) | 
| - | 
| # Use first d8 as default for second d8. | 
| options.second_d8 = options.second_d8 or options.first_d8 | 
|  | 
| @@ -147,27 +143,26 @@ def parse_args(): | 
| return options | 
|  | 
|  | 
| -def metadata_bailout(metadata, ignore_fun): | 
| -  """Print failure state and return if ignore_fun matches metadata.""" | 
| -  bug = (ignore_fun(metadata) or '').strip() | 
| +def get_meta_data(content): | 
| +  """Extracts original-source-file paths from test case content.""" | 
| +  sources = [] | 
| +  for line in content.splitlines(): | 
| +    match = SOURCE_RE.match(line) | 
| +    if match: | 
| +      sources.append(match.group(1)) | 
| +  return {'sources': sources} | 
| + | 
| + | 
| +def content_bailout(content, ignore_fun): | 
| +  """Print failure state and return if ignore_fun matches content.""" | 
| +  bug = (ignore_fun(content) or '').strip() | 
| if bug: | 
| print FAILURE_HEADER_TEMPLATE % dict( | 
| -        configs='', sources='', suppression=bug) | 
| +        configs='', source_key='', suppression=bug) | 
| return True | 
| return False | 
|  | 
|  | 
| -def test_pattern_bailout(testcase, ignore_fun): | 
| -  """Print failure state and return if ignore_fun matches testcase.""" | 
| -  with open(testcase) as f: | 
| -    bug = (ignore_fun(f.read()) or '').strip() | 
| -    if bug: | 
| -      print FAILURE_HEADER_TEMPLATE % dict( | 
| -          configs='', sources='', suppression=bug) | 
| -      return True | 
| -  return False | 
| - | 
| - | 
| def pass_bailout(output, step_number): | 
| """Print info and return if in timeout or crash pass states.""" | 
| if output.HasTimedOut(): | 
| @@ -186,7 +181,7 @@ def fail_bailout(output, ignore_by_output_fun): | 
| bug = (ignore_by_output_fun(output.stdout) or '').strip() | 
| if bug: | 
| print FAILURE_HEADER_TEMPLATE % dict( | 
| -        configs='', sources='', suppression=bug) | 
| +        configs='', source_key='', suppression=bug) | 
| return True | 
| return False | 
|  | 
| @@ -200,18 +195,15 @@ def main(): | 
| options.second_arch, options.second_config, | 
| ) | 
|  | 
| -  # Get metadata. | 
| -  # TODO(machenbach): We probably don't need the metadata file anymore | 
| -  # now that the metadata is printed in the test cases. | 
| -  with open(options.meta_data_path) as f: | 
| -    metadata = json.load(f) | 
| - | 
| -  if metadata_bailout(metadata, suppress.ignore_by_metadata): | 
| +  # Static bailout based on test case content or metadata. | 
| +  with open(options.testcase) as f: | 
| +    content = f.read() | 
| +  if content_bailout(get_meta_data(content), suppress.ignore_by_metadata): | 
| return RETURN_FAIL | 
| - | 
| -  if test_pattern_bailout(options.testcase, suppress.ignore_by_content): | 
| +  if content_bailout(content, suppress.ignore_by_content): | 
| return RETURN_FAIL | 
|  | 
| +  # Set up runtime arguments. | 
| common_flags = FLAGS + ['--random-seed', str(options.random_seed)] | 
| first_config_flags = common_flags + CONFIGS[options.first_config] | 
| second_config_flags = common_flags + CONFIGS[options.second_config] | 
| @@ -243,7 +235,7 @@ def main(): | 
| if fail_bailout(second_config_output, suppress.ignore_by_output2): | 
| return RETURN_FAIL | 
|  | 
| -  difference, source_key = suppress.diff( | 
| +  difference, source, source_key = suppress.diff( | 
| first_config_output.stdout, second_config_output.stdout) | 
| if difference: | 
| # The first three entries will be parsed by clusterfuzz. Format changes | 
| @@ -252,7 +244,7 @@ def main(): | 
| second_config_label = '%s,%s' % (options.second_arch, options.second_config) | 
| print FAILURE_TEMPLATE % dict( | 
| configs='%s:%s' % (first_config_label, second_config_label), | 
| -        sources=source_key, | 
| +        source_key=source_key, | 
| suppression='', # We can't tie bugs to differences. | 
| first_config_label=first_config_label, | 
| second_config_label=second_config_label, | 
| @@ -260,6 +252,7 @@ def main(): | 
| second_config_flags=' '.join(second_config_flags), | 
| first_config_output=first_config_output.stdout, | 
| second_config_output=second_config_output.stdout, | 
| +        source=source, | 
| difference=difference, | 
| ) | 
| return RETURN_FAIL | 
| @@ -279,11 +272,11 @@ if __name__ == "__main__": | 
| # Make sure clusterfuzz reports internal errors and wrong usage. | 
| # Use one label for all internal and usage errors. | 
| print FAILURE_HEADER_TEMPLATE % dict( | 
| -        configs='', sources='', suppression='wrong_usage') | 
| +        configs='', source_key='', suppression='wrong_usage') | 
| result = RETURN_FAIL | 
| except Exception as e: | 
| print FAILURE_HEADER_TEMPLATE % dict( | 
| -        configs='', sources='', suppression='internal_error') | 
| +        configs='', source_key='', suppression='internal_error') | 
| print '# Internal error: %s' % e | 
| traceback.print_exc(file=sys.stdout) | 
| result = RETURN_FAIL | 
|  |