Merge "ART: Factor out StackTraceElement creation"
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 1252905..ba18f8d 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1291,60 +1291,111 @@
 
 void Monitor::DescribeWait(std::ostream& os, const Thread* thread) {
   // Determine the wait message and object we're waiting or blocked upon.
-  mirror::Object* pretty_object = nullptr;
+  mirror::Object* pretty_object;
+  uint32_t lock_owner;
+  ThreadState state = FetchState(thread, &pretty_object, &lock_owner);
+
   const char* wait_message = nullptr;
-  uint32_t lock_owner = ThreadList::kInvalidThreadId;
-  ThreadState state = thread->GetState();
-  if (state == kWaiting || state == kTimedWaiting || state == kSleeping) {
-    wait_message = (state == kSleeping) ? "  - sleeping on " : "  - waiting on ";
-    Thread* self = Thread::Current();
-    MutexLock mu(self, *thread->GetWaitMutex());
-    Monitor* monitor = thread->GetWaitMonitor();
-    if (monitor != nullptr) {
-      pretty_object = monitor->GetObject();
-    }
-  } else if (state == kBlocked || state == kWaitingForLockInflation) {
-    wait_message = (state == kBlocked) ? "  - waiting to lock "
-                                       : "  - waiting for lock inflation of ";
-    pretty_object = thread->GetMonitorEnterObject();
-    if (pretty_object != nullptr) {
-      if (kUseReadBarrier && Thread::Current()->GetIsGcMarking()) {
-        // We may call Thread::Dump() in the middle of the CC thread flip and this thread's stack
-        // may have not been flipped yet and "pretty_object" may be a from-space (stale) ref, in
-        // which case the GetLockOwnerThreadId() call below will crash. So explicitly mark/forward
-        // it here.
-        pretty_object = ReadBarrier::Mark(pretty_object);
-      }
-      lock_owner = pretty_object->GetLockOwnerThreadId();
-    }
+  switch (state) {
+    case kWaiting:
+    case kTimedWaiting:
+      wait_message = "  - waiting on ";
+      break;
+
+    case kSleeping:
+      wait_message = "  - sleeping on ";
+      break;
+
+    case kBlocked:
+      wait_message = "  - waiting to lock ";
+      break;
+
+    case kWaitingForLockInflation:
+      wait_message = "  - waiting for lock inflation of ";
+      break;
+
+    default:
+      break;
   }
 
-  if (wait_message != nullptr) {
-    if (pretty_object == nullptr) {
-      os << wait_message << "an unknown object";
+  if (wait_message == nullptr) {
+    return;
+  }
+
+  if (pretty_object == nullptr) {
+    os << wait_message << "an unknown object";
+  } else {
+    if ((pretty_object->GetLockWord(true).GetState() == LockWord::kThinLocked) &&
+        Locks::mutator_lock_->IsExclusiveHeld(Thread::Current())) {
+      // Getting the identity hashcode here would result in lock inflation and suspension of the
+      // current thread, which isn't safe if this is the only runnable thread.
+      os << wait_message << StringPrintf("<@addr=0x%" PRIxPTR "> (a %s)",
+                                         reinterpret_cast<intptr_t>(pretty_object),
+                                         pretty_object->PrettyTypeOf().c_str());
     } else {
-      if ((pretty_object->GetLockWord(true).GetState() == LockWord::kThinLocked) &&
-          Locks::mutator_lock_->IsExclusiveHeld(Thread::Current())) {
-        // Getting the identity hashcode here would result in lock inflation and suspension of the
-        // current thread, which isn't safe if this is the only runnable thread.
-        os << wait_message << StringPrintf("<@addr=0x%" PRIxPTR "> (a %s)",
-                                           reinterpret_cast<intptr_t>(pretty_object),
-                                           pretty_object->PrettyTypeOf().c_str());
-      } else {
-        // - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
-        // Call PrettyTypeOf before IdentityHashCode since IdentityHashCode can cause thread
-        // suspension and move pretty_object.
-        const std::string pretty_type(pretty_object->PrettyTypeOf());
-        os << wait_message << StringPrintf("<0x%08x> (a %s)", pretty_object->IdentityHashCode(),
-                                           pretty_type.c_str());
+      // - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
+      // Call PrettyTypeOf before IdentityHashCode since IdentityHashCode can cause thread
+      // suspension and move pretty_object.
+      const std::string pretty_type(pretty_object->PrettyTypeOf());
+      os << wait_message << StringPrintf("<0x%08x> (a %s)", pretty_object->IdentityHashCode(),
+                                         pretty_type.c_str());
+    }
+  }
+  // - waiting to lock <0x613f83d8> (a java.lang.Object) held by thread 5
+  if (lock_owner != ThreadList::kInvalidThreadId) {
+    os << " held by thread " << lock_owner;
+  }
+  os << "\n";
+}
+
+ThreadState Monitor::FetchState(const Thread* thread,
+                                /* out */ mirror::Object** monitor_object,
+                                /* out */ uint32_t* lock_owner_tid) {
+  DCHECK(monitor_object != nullptr);
+  DCHECK(lock_owner_tid != nullptr);
+
+  *monitor_object = nullptr;
+  *lock_owner_tid = ThreadList::kInvalidThreadId;
+
+  ThreadState state = thread->GetState();
+
+  switch (state) {
+    case kWaiting:
+    case kTimedWaiting:
+    case kSleeping:
+    {
+      Thread* self = Thread::Current();
+      MutexLock mu(self, *thread->GetWaitMutex());
+      Monitor* monitor = thread->GetWaitMonitor();
+      if (monitor != nullptr) {
+        *monitor_object = monitor->GetObject();
       }
     }
-    // - waiting to lock <0x613f83d8> (a java.lang.Object) held by thread 5
-    if (lock_owner != ThreadList::kInvalidThreadId) {
-      os << " held by thread " << lock_owner;
+    break;
+
+    case kBlocked:
+    case kWaitingForLockInflation:
+    {
+      mirror::Object* lock_object = thread->GetMonitorEnterObject();
+      if (lock_object != nullptr) {
+        if (kUseReadBarrier && Thread::Current()->GetIsGcMarking()) {
+          // We may call Thread::Dump() in the middle of the CC thread flip and this thread's stack
+          // may have not been flipped yet and "pretty_object" may be a from-space (stale) ref, in
+          // which case the GetLockOwnerThreadId() call below will crash. So explicitly mark/forward
+          // it here.
+          lock_object = ReadBarrier::Mark(lock_object);
+        }
+        *monitor_object = lock_object;
+        *lock_owner_tid = lock_object->GetLockOwnerThreadId();
+      }
     }
-    os << "\n";
+    break;
+
+    default:
+      break;
   }
+
+  return state;
 }
 
 mirror::Object* Monitor::GetContendedMonitor(Thread* thread) {
diff --git a/runtime/monitor.h b/runtime/monitor.h
index b4c0e6f..30f47d8 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -97,6 +97,11 @@
   static void DescribeWait(std::ostream& os, const Thread* thread)
       REQUIRES(!Locks::thread_suspend_count_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
+  static ThreadState FetchState(const Thread* thread,
+                                /* out */ mirror::Object** monitor_object,
+                                /* out */ uint32_t* lock_owner_tid)
+      REQUIRES(!Locks::thread_suspend_count_lock_)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Used to implement JDWP's ThreadReference.CurrentContendedMonitor.
   static mirror::Object* GetContendedMonitor(Thread* thread)
diff --git a/tools/jfuzz/README.md b/tools/jfuzz/README.md
index bee2396..1991c97 100644
--- a/tools/jfuzz/README.md
+++ b/tools/jfuzz/README.md
@@ -51,6 +51,7 @@
                           [--jfuzz_arg=ARG]
                           [--true_divergence]
                           [--dexer=DEXER]
+                          [--debug_info]
 
 where
 
@@ -67,6 +68,7 @@
     --jfuzz_arg       : argument for jfuzz
     --true_divergence : don't bisect timeout divergences
     --dexer=DEXER     : use either dx, d8, or jack to obtain dex files
+    --debug_info      : include debugging info
 
 How to start JFuzz nightly testing
 ==================================
@@ -88,6 +90,7 @@
                           [--num_inputs=NUM_INPUTS]
                           [--device=DEVICE]
                           [--dexer=DEXER]
+                          [--debug_info]
 
 where
 
@@ -95,6 +98,7 @@
     --num_inputs  : number of JFuzz programs to generate
     --device      : target device serial number (passed to adb -s)
     --dexer=DEXER : use either dx, d8, or jack to obtain dex files
+    --debug_info      : include debugging info
 
 Background
 ==========
diff --git a/tools/jfuzz/run_dex_fuzz_test.py b/tools/jfuzz/run_dex_fuzz_test.py
index fdff9c0..a25ef3f 100755
--- a/tools/jfuzz/run_dex_fuzz_test.py
+++ b/tools/jfuzz/run_dex_fuzz_test.py
@@ -41,7 +41,7 @@
 class DexFuzzTester(object):
   """Tester that feeds JFuzz programs into DexFuzz testing."""
 
-  def  __init__(self, num_tests, num_inputs, device, dexer):
+  def  __init__(self, num_tests, num_inputs, device, dexer, debug_info):
     """Constructor for the tester.
 
     Args:
@@ -49,6 +49,7 @@
       num_inputs: int, number of JFuzz programs to generate
       device: string, target device serial number (or None)
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
     """
     self._num_tests = num_tests
     self._num_inputs = num_inputs
@@ -59,6 +60,7 @@
     self._inputs_dir = None
     self._dexfuzz_env = None
     self._dexer = dexer
+    self._debug_info = debug_info
 
   def __enter__(self):
     """On entry, enters new temp directory after saving current directory.
@@ -110,7 +112,8 @@
       FatalError: error when compilation fails
     """
     if self._dexer == 'dx' or self._dexer == 'd8':
-      if RunCommand(['javac', 'Test.java'],
+      dbg = '-g' if self._debug_info else '-g:none'
+      if RunCommand(['javac', dbg, 'Test.java'],
                     out=None, err='jerr.txt', timeout=30) != RetCode.SUCCESS:
         print('Unexpected error while running javac')
         raise FatalError('Unexpected error while running javac')
@@ -183,12 +186,17 @@
                       help='number of tests to run (default: 1000)')
   parser.add_argument('--num_inputs', default=10, type=int,
                       help='number of JFuzz program to generate (default: 10)')
+  parser.add_argument('--device', help='target device serial number')
   parser.add_argument('--dexer', default='dx', type=str,
                       help='defines dexer as dx, d8, or jack (default: dx)')
-  parser.add_argument('--device', help='target device serial number')
+  parser.add_argument('--debug_info', default=False, action='store_true',
+                      help='include debugging info')
   args = parser.parse_args()
   # Run the DexFuzz tester.
-  with DexFuzzTester(args.num_tests, args.num_inputs, args.device, args.dexer) as fuzzer:
+  with DexFuzzTester(args.num_tests,
+                     args.num_inputs,
+                     args.device,
+                     args.dexer, args.debug_info) as fuzzer:
     fuzzer.Run()
 
 if __name__ == '__main__':
diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py
index b889940..2b56767 100755
--- a/tools/jfuzz/run_jfuzz_test.py
+++ b/tools/jfuzz/run_jfuzz_test.py
@@ -43,11 +43,12 @@
 BISECTABLE_RET_CODES = (RetCode.SUCCESS, RetCode.ERROR, RetCode.TIMEOUT)
 
 
-def GetExecutionModeRunner(dexer, device, mode):
+def GetExecutionModeRunner(dexer, debug_info, device, mode):
   """Returns a runner for the given execution mode.
 
   Args:
     dexer: string, defines dexer
+    debug_info: boolean, if True include debugging info
     device: string, target device serial number (or None)
     mode: string, execution mode
   Returns:
@@ -56,15 +57,15 @@
     FatalError: error for unknown execution mode
   """
   if mode == 'ri':
-    return TestRunnerRIOnHost()
+    return TestRunnerRIOnHost(debug_info)
   if mode == 'hint':
-    return TestRunnerArtIntOnHost(dexer)
+    return TestRunnerArtIntOnHost(dexer, debug_info)
   if mode == 'hopt':
-    return TestRunnerArtOptOnHost(dexer)
+    return TestRunnerArtOptOnHost(dexer, debug_info)
   if mode == 'tint':
-    return TestRunnerArtIntOnTarget(dexer, device)
+    return TestRunnerArtIntOnTarget(dexer, debug_info, device)
   if mode == 'topt':
-    return TestRunnerArtOptOnTarget(dexer, device)
+    return TestRunnerArtOptOnTarget(dexer, debug_info, device)
   raise FatalError('Unknown execution mode')
 
 
@@ -117,19 +118,22 @@
 class TestRunnerWithHostCompilation(TestRunner):
   """Abstract test runner that supports compilation on host."""
 
-  def  __init__(self, dexer):
+  def  __init__(self, dexer, debug_info):
     """Constructor for the runner with host compilation.
 
     Args:
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
     """
+    self._dexer = dexer
+    self._debug_info = debug_info
     self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
                        'Test.java']
-    self._dexer = dexer
 
   def CompileOnHost(self):
     if self._dexer == 'dx' or self._dexer == 'd8':
-      if RunCommand(['javac', 'Test.java'],
+      dbg = '-g' if self._debug_info else '-g:none'
+      if RunCommand(['javac', dbg, 'Test.java'],
                     out=None, err=None, timeout=30) == RetCode.SUCCESS:
         dx = 'dx' if self._dexer == 'dx' else 'd8-compat-dx'
         retc = RunCommand([dx, '--dex', '--output=classes.dex'] + glob('*.class'),
@@ -147,6 +151,14 @@
 class TestRunnerRIOnHost(TestRunner):
   """Concrete test runner of the reference implementation on host."""
 
+  def  __init__(self, debug_info):
+    """Constructor for the runner with host compilation.
+
+    Args:
+      debug_info: boolean, if True include debugging info
+    """
+    self._debug_info = debug_info
+
   @property
   def description(self):
     return 'RI on host'
@@ -156,7 +168,8 @@
     return 'RI'
 
   def CompileAndRunTest(self):
-    if RunCommand(['javac', 'Test.java'],
+    dbg = '-g' if self._debug_info else '-g:none'
+    if RunCommand(['javac', dbg, 'Test.java'],
                   out=None, err=None, timeout=30) == RetCode.SUCCESS:
       retc = RunCommand(['java', 'Test'], self.output_file, err=None)
     else:
@@ -170,14 +183,15 @@
 class TestRunnerArtOnHost(TestRunnerWithHostCompilation):
   """Abstract test runner of Art on host."""
 
-  def  __init__(self, dexer, extra_args=None):
+  def  __init__(self, dexer, debug_info, extra_args=None):
     """Constructor for the Art on host tester.
 
     Args:
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
       extra_args: list of strings, extra arguments for dalvikvm
     """
-    super().__init__(dexer)
+    super().__init__(dexer, debug_info)
     self._art_cmd = ['/bin/bash', 'art', '-cp', 'classes.dex']
     if extra_args is not None:
       self._art_cmd += extra_args
@@ -194,13 +208,14 @@
 class TestRunnerArtIntOnHost(TestRunnerArtOnHost):
   """Concrete test runner of interpreter mode Art on host."""
 
-  def  __init__(self, dexer):
+  def  __init__(self, dexer, debug_info):
     """Constructor for the Art on host tester (interpreter).
 
     Args:
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
    """
-    super().__init__(dexer, ['-Xint'])
+    super().__init__(dexer, debug_info, ['-Xint'])
 
   @property
   def description(self):
@@ -217,13 +232,14 @@
 class TestRunnerArtOptOnHost(TestRunnerArtOnHost):
   """Concrete test runner of optimizing compiler mode Art on host."""
 
-  def  __init__(self, dexer):
+  def  __init__(self, dexer, debug_info):
     """Constructor for the Art on host tester (optimizing).
 
     Args:
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
    """
-    super().__init__(dexer, None)
+    super().__init__(dexer, debug_info, None)
 
   @property
   def description(self):
@@ -242,15 +258,16 @@
 class TestRunnerArtOnTarget(TestRunnerWithHostCompilation):
   """Abstract test runner of Art on target."""
 
-  def  __init__(self, dexer, device, extra_args=None):
+  def  __init__(self, dexer, debug_info, device, extra_args=None):
     """Constructor for the Art on target tester.
 
     Args:
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
       device: string, target device serial number (or None)
       extra_args: list of strings, extra arguments for dalvikvm
     """
-    super().__init__(dexer)
+    super().__init__(dexer, debug_info)
     self._test_env = DeviceTestEnv('jfuzz_', specific_device=device)
     self._dalvik_cmd = ['dalvikvm']
     if extra_args is not None:
@@ -284,14 +301,15 @@
 class TestRunnerArtIntOnTarget(TestRunnerArtOnTarget):
   """Concrete test runner of interpreter mode Art on target."""
 
-  def  __init__(self, dexer, device):
+  def  __init__(self, dexer, debug_info, device):
     """Constructor for the Art on target tester (interpreter).
 
     Args:
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
       device: string, target device serial number (or None)
     """
-    super().__init__(dexer, device, ['-Xint'])
+    super().__init__(dexer, debug_info, device, ['-Xint'])
 
   @property
   def description(self):
@@ -308,14 +326,15 @@
 class TestRunnerArtOptOnTarget(TestRunnerArtOnTarget):
   """Concrete test runner of optimizing compiler mode Art on target."""
 
-  def  __init__(self, dexer, device):
+  def  __init__(self, dexer, debug_info, device):
     """Constructor for the Art on target tester (optimizing).
 
     Args:
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
       device: string, target device serial number (or None)
     """
-    super().__init__(dexer, device, None)
+    super().__init__(dexer, debug_info, device, None)
 
   @property
   def description(self):
@@ -345,7 +364,7 @@
   """Tester that runs JFuzz many times and report divergences."""
 
   def  __init__(self, num_tests, device, mode1, mode2, jfuzz_args,
-                report_script, true_divergence_only, dexer):
+                report_script, true_divergence_only, dexer, debug_info):
     """Constructor for the tester.
 
     Args:
@@ -357,15 +376,17 @@
       report_script: string, path to script called for each divergence
       true_divergence_only: boolean, if True don't bisect timeout divergences
       dexer: string, defines dexer
+      debug_info: boolean, if True include debugging info
     """
     self._num_tests = num_tests
     self._device = device
-    self._runner1 = GetExecutionModeRunner(dexer, device, mode1)
-    self._runner2 = GetExecutionModeRunner(dexer, device, mode2)
+    self._runner1 = GetExecutionModeRunner(dexer, debug_info, device, mode1)
+    self._runner2 = GetExecutionModeRunner(dexer, debug_info, device, mode2)
     self._jfuzz_args = jfuzz_args
     self._report_script = report_script
     self._true_divergence_only = true_divergence_only
     self._dexer = dexer
+    self._debug_info = debug_info
     self._save_dir = None
     self._results_dir = None
     self._jfuzz_dir = None
@@ -409,6 +430,7 @@
     print('Exec-mode1:', self._runner1.description)
     print('Exec-mode2:', self._runner2.description)
     print('Dexer     :', self._dexer)
+    print('Debug-info:', self._debug_info)
     print()
     self.ShowStats()
     for self._test in range(1, self._num_tests + 1):
@@ -529,6 +551,7 @@
       wrapped_args = ['--jfuzz_arg={0}'.format(opt) for opt in jfuzz_args]
       repro_cmd_str = (os.path.basename(__file__) +
                        ' --num_tests=1 --dexer=' + self._dexer +
+                       (' --debug_info' if self._debug_info else '') +
                        ' '.join(wrapped_args))
       comment = 'jfuzz {0}\nReproduce test:\n{1}\nReproduce divergence:\n{2}\n'.format(
           jfuzz_ver, jfuzz_cmd_str, repro_cmd_str)
@@ -610,14 +633,20 @@
                       help='do not bisect timeout divergences')
   parser.add_argument('--dexer', default='dx', type=str,
                       help='defines dexer as dx, d8, or jack (default: dx)')
+  parser.add_argument('--debug_info', default=False, action='store_true',
+                      help='include debugging info')
   args = parser.parse_args()
   if args.mode1 == args.mode2:
     raise FatalError('Identical execution modes given')
   # Run the JFuzz tester.
   with JFuzzTester(args.num_tests,
-                   args.device, args.mode1, args.mode2,
-                   args.jfuzz_args, args.report_script,
-                   args.true_divergence, args.dexer) as fuzzer:
+                   args.device,
+                   args.mode1, args.mode2,
+                   args.jfuzz_args,
+                   args.report_script,
+                   args.true_divergence,
+                   args.dexer,
+                   args.debug_info) as fuzzer:
     fuzzer.Run()
 
 if __name__ == '__main__':