11cb0ef41Sopenharmony_ci# Copyright 2016 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci# found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci# Fork from commands.py and output.py in v8 test driver.
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciimport os
81cb0ef41Sopenharmony_ciimport signal
91cb0ef41Sopenharmony_ciimport subprocess
101cb0ef41Sopenharmony_ciimport sys
111cb0ef41Sopenharmony_cifrom threading import Event, Timer
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ciimport v8_fuzz_config
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ciPYTHON3 = sys.version_info >= (3, 0)
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci# List of default flags passed to each d8 run.
181cb0ef41Sopenharmony_ciDEFAULT_FLAGS = [
191cb0ef41Sopenharmony_ci    '--correctness-fuzzer-suppressions',
201cb0ef41Sopenharmony_ci    '--expose-gc',
211cb0ef41Sopenharmony_ci    '--fuzzing',
221cb0ef41Sopenharmony_ci    '--allow-natives-for-differential-fuzzing',
231cb0ef41Sopenharmony_ci    '--invoke-weak-callbacks',
241cb0ef41Sopenharmony_ci    '--omit-quit',
251cb0ef41Sopenharmony_ci    '--harmony',
261cb0ef41Sopenharmony_ci    '--wasm-staging',
271cb0ef41Sopenharmony_ci    '--no-wasm-async-compilation',
281cb0ef41Sopenharmony_ci    '--suppress-asm-messages',
291cb0ef41Sopenharmony_ci]
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciBASE_PATH = os.path.dirname(os.path.abspath(__file__))
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci# List of files passed to each d8 run before the testcase.
341cb0ef41Sopenharmony_ciDEFAULT_MOCK = os.path.join(BASE_PATH, 'v8_mock.js')
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci# Suppressions on JavaScript level for known issues.
371cb0ef41Sopenharmony_ciJS_SUPPRESSIONS = os.path.join(BASE_PATH, 'v8_suppressions.js')
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci# Config-specific mock files.
401cb0ef41Sopenharmony_ciARCH_MOCKS = os.path.join(BASE_PATH, 'v8_mock_archs.js')
411cb0ef41Sopenharmony_ciWEBASSEMBLY_MOCKS = os.path.join(BASE_PATH, 'v8_mock_webassembly.js')
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cidef _startup_files(options):
451cb0ef41Sopenharmony_ci  """Default files and optional config-specific mock files."""
461cb0ef41Sopenharmony_ci  files = [DEFAULT_MOCK]
471cb0ef41Sopenharmony_ci  if not options.skip_suppressions:
481cb0ef41Sopenharmony_ci    files.append(JS_SUPPRESSIONS)
491cb0ef41Sopenharmony_ci  if options.first.arch != options.second.arch:
501cb0ef41Sopenharmony_ci    files.append(ARCH_MOCKS)
511cb0ef41Sopenharmony_ci  # Mock out WebAssembly when comparing with jitless mode.
521cb0ef41Sopenharmony_ci  if '--jitless' in options.first.flags + options.second.flags:
531cb0ef41Sopenharmony_ci    files.append(WEBASSEMBLY_MOCKS)
541cb0ef41Sopenharmony_ci  return files
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ciclass BaseException(Exception):
581cb0ef41Sopenharmony_ci  """Used to abort the comparison workflow and print the given message."""
591cb0ef41Sopenharmony_ci  def __init__(self, message):
601cb0ef41Sopenharmony_ci    self.message = message
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ciclass PassException(BaseException):
641cb0ef41Sopenharmony_ci  """Represents an early abort making the overall run pass."""
651cb0ef41Sopenharmony_ci  pass
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ciclass FailException(BaseException):
691cb0ef41Sopenharmony_ci  """Represents an early abort making the overall run fail."""
701cb0ef41Sopenharmony_ci  pass
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ciclass Command(object):
741cb0ef41Sopenharmony_ci  """Represents a configuration for running V8 multiple times with certain
751cb0ef41Sopenharmony_ci  flags and files.
761cb0ef41Sopenharmony_ci  """
771cb0ef41Sopenharmony_ci  def __init__(self, options, label, executable, config_flags):
781cb0ef41Sopenharmony_ci    self.label = label
791cb0ef41Sopenharmony_ci    self.executable = executable
801cb0ef41Sopenharmony_ci    self.config_flags = config_flags
811cb0ef41Sopenharmony_ci    self.common_flags =  DEFAULT_FLAGS[:]
821cb0ef41Sopenharmony_ci    self.common_flags.extend(['--random-seed', str(options.random_seed)])
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci    self.files = _startup_files(options)
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  def run(self, testcase, timeout, verbose=False):
871cb0ef41Sopenharmony_ci    """Run the executable with a specific testcase."""
881cb0ef41Sopenharmony_ci    args = [self.executable] + self.flags + self.files + [testcase]
891cb0ef41Sopenharmony_ci    if verbose:
901cb0ef41Sopenharmony_ci      print('# Command line for %s comparison:' % self.label)
911cb0ef41Sopenharmony_ci      print(' '.join(args))
921cb0ef41Sopenharmony_ci    if self.executable.endswith('.py'):
931cb0ef41Sopenharmony_ci      # Wrap with python in tests.
941cb0ef41Sopenharmony_ci      args = [sys.executable] + args
951cb0ef41Sopenharmony_ci    return Execute(
961cb0ef41Sopenharmony_ci        args,
971cb0ef41Sopenharmony_ci        cwd=os.path.dirname(os.path.abspath(testcase)),
981cb0ef41Sopenharmony_ci        timeout=timeout,
991cb0ef41Sopenharmony_ci    )
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  @property
1021cb0ef41Sopenharmony_ci  def flags(self):
1031cb0ef41Sopenharmony_ci    return self.common_flags + self.config_flags
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ciclass Output(object):
1071cb0ef41Sopenharmony_ci  def __init__(self, exit_code, stdout, pid):
1081cb0ef41Sopenharmony_ci    self.exit_code = exit_code
1091cb0ef41Sopenharmony_ci    self.stdout = stdout
1101cb0ef41Sopenharmony_ci    self.pid = pid
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  def HasCrashed(self):
1131cb0ef41Sopenharmony_ci    return self.exit_code < 0
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_cidef Execute(args, cwd, timeout=None):
1171cb0ef41Sopenharmony_ci  popen_args = [c for c in args if c != ""]
1181cb0ef41Sopenharmony_ci  kwargs = {}
1191cb0ef41Sopenharmony_ci  if PYTHON3:
1201cb0ef41Sopenharmony_ci    kwargs['encoding'] = 'utf-8'
1211cb0ef41Sopenharmony_ci  try:
1221cb0ef41Sopenharmony_ci    process = subprocess.Popen(
1231cb0ef41Sopenharmony_ci      args=popen_args,
1241cb0ef41Sopenharmony_ci      stdout=subprocess.PIPE,
1251cb0ef41Sopenharmony_ci      stderr=subprocess.PIPE,
1261cb0ef41Sopenharmony_ci      cwd=cwd,
1271cb0ef41Sopenharmony_ci      **kwargs
1281cb0ef41Sopenharmony_ci    )
1291cb0ef41Sopenharmony_ci  except Exception as e:
1301cb0ef41Sopenharmony_ci    sys.stderr.write("Error executing: %s\n" % popen_args)
1311cb0ef41Sopenharmony_ci    raise e
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  timeout_event = Event()
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  def kill_process():
1361cb0ef41Sopenharmony_ci    timeout_event.set()
1371cb0ef41Sopenharmony_ci    try:
1381cb0ef41Sopenharmony_ci      process.kill()
1391cb0ef41Sopenharmony_ci    except OSError:
1401cb0ef41Sopenharmony_ci      sys.stderr.write('Error: Process %s already ended.\n' % process.pid)
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  timer = Timer(timeout, kill_process)
1431cb0ef41Sopenharmony_ci  timer.start()
1441cb0ef41Sopenharmony_ci  stdout, _ = process.communicate()
1451cb0ef41Sopenharmony_ci  timer.cancel()
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  if timeout_event.is_set():
1481cb0ef41Sopenharmony_ci    raise PassException('# V8 correctness - T-I-M-E-O-U-T')
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  return Output(
1511cb0ef41Sopenharmony_ci      process.returncode,
1521cb0ef41Sopenharmony_ci      stdout,
1531cb0ef41Sopenharmony_ci      process.pid,
1541cb0ef41Sopenharmony_ci  )
155