1# Copyright 2016 the V8 project authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5# Fork from commands.py and output.py in v8 test driver. 6 7import os 8import signal 9import subprocess 10import sys 11from threading import Event, Timer 12 13import v8_fuzz_config 14 15PYTHON3 = sys.version_info >= (3, 0) 16 17# List of default flags passed to each d8 run. 18DEFAULT_FLAGS = [ 19 '--correctness-fuzzer-suppressions', 20 '--expose-gc', 21 '--fuzzing', 22 '--allow-natives-for-differential-fuzzing', 23 '--invoke-weak-callbacks', 24 '--omit-quit', 25 '--harmony', 26 '--wasm-staging', 27 '--no-wasm-async-compilation', 28 '--suppress-asm-messages', 29] 30 31BASE_PATH = os.path.dirname(os.path.abspath(__file__)) 32 33# List of files passed to each d8 run before the testcase. 34DEFAULT_MOCK = os.path.join(BASE_PATH, 'v8_mock.js') 35 36# Suppressions on JavaScript level for known issues. 37JS_SUPPRESSIONS = os.path.join(BASE_PATH, 'v8_suppressions.js') 38 39# Config-specific mock files. 40ARCH_MOCKS = os.path.join(BASE_PATH, 'v8_mock_archs.js') 41WEBASSEMBLY_MOCKS = os.path.join(BASE_PATH, 'v8_mock_webassembly.js') 42 43 44def _startup_files(options): 45 """Default files and optional config-specific mock files.""" 46 files = [DEFAULT_MOCK] 47 if not options.skip_suppressions: 48 files.append(JS_SUPPRESSIONS) 49 if options.first.arch != options.second.arch: 50 files.append(ARCH_MOCKS) 51 # Mock out WebAssembly when comparing with jitless mode. 52 if '--jitless' in options.first.flags + options.second.flags: 53 files.append(WEBASSEMBLY_MOCKS) 54 return files 55 56 57class BaseException(Exception): 58 """Used to abort the comparison workflow and print the given message.""" 59 def __init__(self, message): 60 self.message = message 61 62 63class PassException(BaseException): 64 """Represents an early abort making the overall run pass.""" 65 pass 66 67 68class FailException(BaseException): 69 """Represents an early abort making the overall run fail.""" 70 pass 71 72 73class Command(object): 74 """Represents a configuration for running V8 multiple times with certain 75 flags and files. 76 """ 77 def __init__(self, options, label, executable, config_flags): 78 self.label = label 79 self.executable = executable 80 self.config_flags = config_flags 81 self.common_flags = DEFAULT_FLAGS[:] 82 self.common_flags.extend(['--random-seed', str(options.random_seed)]) 83 84 self.files = _startup_files(options) 85 86 def run(self, testcase, timeout, verbose=False): 87 """Run the executable with a specific testcase.""" 88 args = [self.executable] + self.flags + self.files + [testcase] 89 if verbose: 90 print('# Command line for %s comparison:' % self.label) 91 print(' '.join(args)) 92 if self.executable.endswith('.py'): 93 # Wrap with python in tests. 94 args = [sys.executable] + args 95 return Execute( 96 args, 97 cwd=os.path.dirname(os.path.abspath(testcase)), 98 timeout=timeout, 99 ) 100 101 @property 102 def flags(self): 103 return self.common_flags + self.config_flags 104 105 106class Output(object): 107 def __init__(self, exit_code, stdout, pid): 108 self.exit_code = exit_code 109 self.stdout = stdout 110 self.pid = pid 111 112 def HasCrashed(self): 113 return self.exit_code < 0 114 115 116def Execute(args, cwd, timeout=None): 117 popen_args = [c for c in args if c != ""] 118 kwargs = {} 119 if PYTHON3: 120 kwargs['encoding'] = 'utf-8' 121 try: 122 process = subprocess.Popen( 123 args=popen_args, 124 stdout=subprocess.PIPE, 125 stderr=subprocess.PIPE, 126 cwd=cwd, 127 **kwargs 128 ) 129 except Exception as e: 130 sys.stderr.write("Error executing: %s\n" % popen_args) 131 raise e 132 133 timeout_event = Event() 134 135 def kill_process(): 136 timeout_event.set() 137 try: 138 process.kill() 139 except OSError: 140 sys.stderr.write('Error: Process %s already ended.\n' % process.pid) 141 142 timer = Timer(timeout, kill_process) 143 timer.start() 144 stdout, _ = process.communicate() 145 timer.cancel() 146 147 if timeout_event.is_set(): 148 raise PassException('# V8 correctness - T-I-M-E-O-U-T') 149 150 return Output( 151 process.returncode, 152 stdout, 153 process.pid, 154 ) 155