Merge "Restructure to reduce MIR references" into ics-mr1-plus-art
diff --git a/build/Android.common.mk b/build/Android.common.mk
index aeb4c79..bcac723 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -325,6 +325,7 @@
 	src/jdwp/jdwp.h \
 	src/jdwp/jdwp_constants.h \
 	src/mutex.h \
+	src/object.h \
 	src/thread.h \
 	src/verifier/method_verifier.h
 
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 98d5fe0..3280410 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1967,7 +1967,8 @@
     return;
   }
 
-  CHECK_EQ(klass->GetStatus(), Class::kStatusResolved) << PrettyClass(klass);
+  CHECK(klass->GetStatus() == Class::kStatusResolved ||
+        klass->GetStatus() == Class::kStatusRetryVerificationAtRuntime) << PrettyClass(klass);
   klass->SetStatus(Class::kStatusVerifying);
 
   // Verify super class
@@ -1980,7 +1981,7 @@
     if (!super->IsVerified() && !super->IsErroneous()) {
       Runtime::Current()->GetClassLinker()->VerifyClass(super);
     }
-    if (!super->IsVerified()) {
+    if (!super->IsCompileTimeVerified()) {
       error_msg = "Rejecting class ";
       error_msg += PrettyDescriptor(klass);
       error_msg += " that attempts to sub-class erroneous class ";
@@ -2005,16 +2006,22 @@
   const DexFile& dex_file = FindDexFile(klass->GetDexCache());
   Class::Status oat_file_class_status(Class::kStatusNotReady);
   bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
-  bool verified = preverified || verifier::MethodVerifier::VerifyClass(klass, error_msg);
-  if (verified) {
+  verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure;
+  if (!preverified) {
+    verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg);
+  }
+  if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
     if (!preverified && oat_file_class_status == Class::kStatusError) {
       LOG(FATAL) << "Verification failed hard on class " << PrettyDescriptor(klass)
                  << " at compile time, but succeeded at runtime! The verifier must be broken.";
     }
     DCHECK(!Thread::Current()->IsExceptionPending());
+    CHECK(verifier_failure == verifier::MethodVerifier::kNoFailure ||
+          Runtime::Current()->IsCompiler());
     // Make sure all classes referenced by catch blocks are resolved
     ResolveClassExceptionHandlerTypes(dex_file, klass);
-    klass->SetStatus(Class::kStatusVerified);
+    klass->SetStatus(verifier_failure == verifier::MethodVerifier::kNoFailure ?
+                     Class::kStatusVerified : Class::kStatusRetryVerificationAtRuntime);
     // Sanity check that a verified class has GC maps on all methods
     CheckMethodsHaveGcMaps(klass);
   } else {
@@ -2052,7 +2059,7 @@
   if (oat_file_class_status == Class::kStatusVerified || oat_file_class_status == Class::kStatusInitialized) {
     return true;
   }
-  if (oat_file_class_status == Class::kStatusResolved) {
+  if (oat_file_class_status == Class::kStatusRetryVerificationAtRuntime) {
     // Compile time verification failed with a soft error. Compile time verification can fail
     // because we have incomplete type information. Consider the following:
     // class ... {
@@ -2351,10 +2358,13 @@
       return false;
     }
 
-    if (klass->GetStatus() == Class::kStatusResolved) {
+    if (klass->GetStatus() == Class::kStatusResolved ||
+        klass->GetStatus() == Class::kStatusRetryVerificationAtRuntime) {
       VerifyClass(klass);
       if (klass->GetStatus() != Class::kStatusVerified) {
-        CHECK(self->IsExceptionPending());
+        if (klass->GetStatus() == Class::kStatusError) {
+          CHECK(self->IsExceptionPending());
+        }
         return false;
       }
     }
diff --git a/src/compiler.cc b/src/compiler.cc
index af06de1..dadfc40 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1155,8 +1155,8 @@
      * will be rejected by the verifier and later skipped during compilation in the compiler.
      */
     std::string error_msg;
-    if (!verifier::MethodVerifier::VerifyClass(context->GetDexFile(), context->GetDexCache(),
-        context->GetClassLoader(), class_def_index, error_msg)) {
+    if (verifier::MethodVerifier::VerifyClass(context->GetDexFile(), context->GetDexCache(),
+        context->GetClassLoader(), class_def_index, error_msg) == verifier::MethodVerifier::kHardFailure) {
       const DexFile::ClassDef& class_def = context->GetDexFile()->GetClassDef(class_def_index);
       LOG(ERROR) << "Verification failed on class "
                  << PrettyDescriptor(context->GetDexFile()->GetClassDescriptor(class_def))
@@ -1172,14 +1172,9 @@
     CHECK(Thread::Current()->IsExceptionPending());
     Thread::Current()->ClearException();
     art::Compiler::ClassReference ref(context->GetDexFile(), class_def_index);
-    if (!verifier::MethodVerifier::IsClassRejected(ref)) {
-      // If the erroneous class wasn't rejected by the verifier, it was a soft error. We want
-      // to try verification again at run-time, so move back into the resolved state.
-      klass->SetStatus(Class::kStatusResolved);
-    }
   }
 
-  CHECK(klass->IsVerified() || klass->IsResolved() || klass->IsErroneous()) << PrettyClass(klass);
+  CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous()) << PrettyClass(klass);
   CHECK(!Thread::Current()->IsExceptionPending()) << PrettyTypeOf(Thread::Current()->GetException());
 }
 
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 418bf3c..088cb45 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -449,7 +449,7 @@
 }
 
 static int dex2oat(int argc, char** argv) {
-  InitLogging();
+  InitLogging(argv);
 
   // Skip over argv[0].
   argv++;
diff --git a/src/heap.cc b/src/heap.cc
index eb4f3e8..5129a41 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -581,12 +581,14 @@
 void Heap::CollectGarbageInternal(bool concurrent, bool clear_soft_references) {
   lock_->AssertHeld();
 
+  TimingLogger timings("CollectGarbageInternal");
+  uint64_t t0 = NanoTime(), rootEnd = 0, dirtyBegin = 0, dirtyEnd = 0;
+
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   thread_list->SuspendAll();
+  timings.AddSplit("SuspendAll");
 
   size_t initial_size = num_bytes_allocated_;
-  TimingLogger timings("CollectGarbageInternal");
-  uint64_t t0 = NanoTime();
   Object* cleared_references = NULL;
   {
     MarkSweep mark_sweep(mark_stack_);
@@ -602,8 +604,10 @@
     DCHECK(mark_sweep.IsMarkStackEmpty());
 
     if (concurrent) {
+      timings.AddSplit("RootEnd");
       Unlock();
       thread_list->ResumeAll();
+      rootEnd = NanoTime();
     }
 
     // Recursively mark all bits set in the non-image mark bitmap
@@ -611,8 +615,10 @@
     timings.AddSplit("RecursiveMark");
 
     if (concurrent) {
+      dirtyBegin = NanoTime();
       Lock();
       thread_list->SuspendAll();
+      timings.AddSplit("ReSuspend");
 
       // Re-mark root set.
       mark_sweep.ReMarkRoots();
@@ -644,12 +650,14 @@
 
   GrowForUtilization();
   timings.AddSplit("GrowForUtilization");
-  uint64_t t1 = NanoTime();
   thread_list->ResumeAll();
+  dirtyEnd = NanoTime();
 
   EnqueueClearedReferences(&cleared_references);
   RequestHeapTrim();
+  timings.AddSplit("Finish");
 
+  uint64_t t1 = NanoTime();
   uint64_t duration_ns = t1 - t0;
   bool gc_was_particularly_slow = duration_ns > MsToNs(50); // TODO: crank this down for concurrent.
   if (VLOG_IS_ON(gc) || gc_was_particularly_slow) {
@@ -657,9 +665,20 @@
     size_t bytes_freed = initial_size - num_bytes_allocated_;
     // lose low nanoseconds in duration. TODO: make this part of PrettyDuration
     duration_ns = (duration_ns / 1000) * 1000;
-    LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << GetPercentFree() << "% free, "
-              << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory()) << ", "
-              << "paused " << PrettyDuration(duration_ns);
+    if (concurrent) {
+      uint64_t pauseRootsTime = (rootEnd - t0) / 1000 * 1000;
+      uint64_t pauseDirtyTime = (t1 - dirtyBegin) / 1000 * 1000;
+      LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << GetPercentFree() << "% free, "
+                << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory()) << ", "
+                << "paused " << PrettyDuration(pauseRootsTime) << "+" << PrettyDuration(pauseDirtyTime)
+                << ", total " << PrettyDuration(duration_ns);
+    } else {
+      uint64_t markSweepTime = (dirtyEnd - t0) / 1000 * 1000;
+      LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << GetPercentFree() << "% free, "
+                << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory()) << ", "
+                << "paused " << PrettyDuration(markSweepTime)
+                << ", total " << PrettyDuration(duration_ns);
+    }
   }
   Dbg::GcDidFinish();
   if (VLOG_IS_ON(heap)) {
diff --git a/src/logging.cc b/src/logging.cc
index 7d176a2..86c8bdf 100644
--- a/src/logging.cc
+++ b/src/logging.cc
@@ -24,14 +24,28 @@
 
 LogVerbosity gLogVerbosity;
 
-static bool gInitLoggingCalled = false;
 static LogSeverity gMinimumLogSeverity = INFO;
+static std::string* gCmdLine;
+static std::string* gProgramInvocationName;
+static std::string* gProgramInvocationShortName;
 
 static Mutex& GetLoggingLock() {
   static Mutex logging_lock("LogMessage lock");
   return logging_lock;
 }
 
+const char* GetCmdLine() {
+  return (gCmdLine != NULL) ? gCmdLine->c_str() : NULL;
+}
+
+const char* ProgramInvocationName() {
+  return (gProgramInvocationName != NULL) ? gProgramInvocationName->c_str() : "art";
+}
+
+const char* ProgramInvocationShortName() {
+  return (gProgramInvocationShortName != NULL) ? gProgramInvocationShortName->c_str() : "art";
+}
+
 // Configure logging based on ANDROID_LOG_TAGS environment variable.
 // We need to parse a string that looks like
 //
@@ -40,8 +54,19 @@
 // The tag (or '*' for the global level) comes first, followed by a colon
 // and a letter indicating the minimum priority level we're expected to log.
 // This can be used to reveal or conceal logs with specific tags.
-void InitLogging() {
-  gInitLoggingCalled = true;
+void InitLogging(char* argv[]) {
+  // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this,
+  // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are
+  // commonly used.
+  gCmdLine = new std::string(argv[0]);
+  for (size_t i = 1; argv[i] != NULL; ++i) {
+    gCmdLine->append(" ");
+    gCmdLine->append(argv[i]);
+  }
+  gProgramInvocationName = new std::string(argv[0]);
+  const char* last_slash = strrchr(argv[0], '/');
+  gProgramInvocationShortName = new std::string((last_slash != NULL) ? last_slash + 1 : argv[0]);
+
   const char* tags = getenv("ANDROID_LOG_TAGS");
   if (tags == NULL) {
     return;
diff --git a/src/logging.h b/src/logging.h
index 337f12e..f7b687b 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -265,7 +265,11 @@
 };
 
 extern LogVerbosity gLogVerbosity;
-extern void InitLogging();
+extern void InitLogging(char* argv[]);
+
+extern const char* GetCmdLine();
+extern const char* ProgramInvocationName();
+extern const char* ProgramInvocationShortName();
 
 }  // namespace art
 
diff --git a/src/logging_android.cc b/src/logging_android.cc
index 8ba61f1..7007d7a 100644
--- a/src/logging_android.cc
+++ b/src/logging_android.cc
@@ -36,11 +36,12 @@
 }
 
 void LogMessage::LogLine(const char* message) {
+  const char* tag = ProgramInvocationShortName();
   int priority = kLogSeverityToAndroidLogPriority[data_->severity];
   if (priority == ANDROID_LOG_FATAL) {
-    LOG_PRI(priority, "art", "%s:%d] %s", data_->file, data_->line_number, message);
+    LOG_PRI(priority, tag, "%s:%d] %s", data_->file, data_->line_number, message);
   } else {
-    LOG_PRI(priority, "art", "%s", message);
+    LOG_PRI(priority, tag, "%s", message);
   }
 }
 
diff --git a/src/logging_linux.cc b/src/logging_linux.cc
index 5bb8764..0d7fc0b 100644
--- a/src/logging_linux.cc
+++ b/src/logging_linux.cc
@@ -35,7 +35,8 @@
 
 void LogMessage::LogLine(const char* message) {
   char severity = "VDIWEFF"[data_->severity];
-  fprintf(stderr, "%c %5d %5d %s:%d] %s\n", severity, getpid(), ::art::GetTid(),
+  fprintf(stderr, "%s %c %5d %5d %s:%d] %s\n",
+          ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(),
           data_->file, data_->line_number, message);
 }
 
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 1348df1..8dd4e45 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -1133,7 +1133,7 @@
 };
 
 static int oatdump(int argc, char** argv) {
-  InitLogging();
+  InitLogging(argv);
 
   // Skip over argv[0].
   argv++;
diff --git a/src/oatexec.cc b/src/oatexec.cc
index e8e2050..49c0706 100644
--- a/src/oatexec.cc
+++ b/src/oatexec.cc
@@ -102,7 +102,7 @@
 // Parse arguments.  Most of it just gets passed through to the runtime.
 // The JNI spec defines a handful of standard arguments.
 static int oatexec(int argc, char** argv) {
-  InitLogging();
+  InitLogging(argv);
   setvbuf(stdout, NULL, _IONBF, 0);
 
   // Skip over argv[0].
diff --git a/src/object.cc b/src/object.cc
index 7e73e8d..6dda684 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1569,24 +1569,4 @@
   return trace;
 }
 
-static const char* kClassStatusNames[] = {
-  "Error",
-  "NotReady",
-  "Idx",
-  "Loaded",
-  "Resolved",
-  "Verifying",
-  "Verified",
-  "Initializing",
-  "Initialized"
-};
-std::ostream& operator<<(std::ostream& os, const Class::Status& rhs) {
-  if (rhs >= Class::kStatusError && rhs <= Class::kStatusInitialized) {
-    os << kClassStatusNames[rhs + 1];
-  } else {
-    os << "Class::Status[" << static_cast<int>(rhs) << "]";
-  }
-  return os;
-}
-
 }  // namespace art
diff --git a/src/object.h b/src/object.h
index 9ad02a8..b6455db 100644
--- a/src/object.h
+++ b/src/object.h
@@ -109,7 +109,7 @@
 #if defined(ART_USE_LLVM_COMPILER)
 namespace compiler_llvm {
   class InferredRegCategoryMap;
-}
+} // namespace compiler_llvm
 #endif
 
 static const uint32_t kAccPublic = 0x0001;  // class, field, method, ic
@@ -1136,7 +1136,8 @@
 // provides the static storage. However, this might change to an Array
 // to improve image sharing, so we use this type to avoid assumptions
 // on the current storage.
-class MANAGED StaticStorageBase : public Object {};
+class MANAGED StaticStorageBase : public Object {
+};
 
 // C++ mirror of java.lang.Class
 class MANAGED Class : public StaticStorageBase {
@@ -1165,6 +1166,14 @@
   // it kStatusResolved. Java allows circularities of the form where a super
   // class has a field that is of the type of the sub class. We need to be able
   // to fully resolve super classes while resolving types for fields.
+  //
+  // kStatusRetryVerificationAtRuntime: The verifier sets a class to
+  // this state if it encounters a soft failure at compile time. This
+  // often happens when there are unresolved classes in other dex
+  // files, and this status marks a class as needing to be verified
+  // again at runtime.
+  //
+  // TODO: Explain the other states
 
   enum Status {
     kStatusError = -1,
@@ -1173,9 +1182,10 @@
     kStatusLoaded = 2,  // DEX idx values resolved
     kStatusResolved = 3,  // part of linking
     kStatusVerifying = 4,  // in the process of being verified
-    kStatusVerified = 5,  // logically part of linking; done pre-init
-    kStatusInitializing = 6,  // class init in progress
-    kStatusInitialized = 7,  // ready to go
+    kStatusRetryVerificationAtRuntime = 5,  // compile time verification failed, retry at runtime
+    kStatusVerified = 6,  // logically part of linking; done pre-init
+    kStatusInitializing = 7,  // class init in progress
+    kStatusInitialized = 8,  // ready to go
   };
 
   Status GetStatus() const {
@@ -1205,6 +1215,11 @@
     return GetStatus() >= kStatusResolved;
   }
 
+  // Returns true if the class was compile-time verified.
+  bool IsCompileTimeVerified() const {
+    return GetStatus() >= kStatusRetryVerificationAtRuntime;
+  }
+
   // Returns true if the class has been verified.
   bool IsVerified() const {
     return GetStatus() >= kStatusVerified;
@@ -2547,8 +2562,7 @@
   }
 
  private:
-
-  enum ArrayIndex {
+  enum {
     // Points to the interface class.
     kInterface   = 0,
     // Method pointers into the vtable, allow fast map from interface
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index 95f183f..a4bdacc 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -233,6 +233,7 @@
                       signal_number == SIGFPE || signal_number == SIGSEGV);
 
   OS os_info;
+
   UContext thread_context(raw_context);
   Backtrace thread_backtrace;
 
@@ -243,6 +244,7 @@
                                       GetSignalCodeName(signal_number, info->si_code))
                       << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "") << "\n"
                       << "OS: " << Dumpable<OS>(os_info) << "\n"
+                      << "Cmdline: " << GetCmdLine() << "\n"
                       << "Registers:\n" << Dumpable<UContext>(thread_context) << "\n"
                       << "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace);
 
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index 33600ba..5c7a30f 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -36,21 +36,28 @@
 #include "thread_list.h"
 #include "utils.h"
 
-#if !defined(__APPLE__)
-#define HAVE_PROC_CMDLINE
-#endif
-
 namespace art {
 
-#if defined(HAVE_PROC_CMDLINE)
-static bool ReadCmdLine(std::string& result) {
-  if (!ReadFileToString("/proc/self/cmdline", &result)) {
-    return false;
+static void DumpCmdLine(std::ostream& os) {
+#if defined(__linux__)
+  // Show the original command line, and the current command line too if it's changed.
+  // On Android, /proc/self/cmdline will have been rewritten to something like "system_server".
+  std::string current_cmd_line;
+  if (ReadFileToString("/proc/self/cmdline", &current_cmd_line)) {
+    current_cmd_line.resize(current_cmd_line.size() - 1); // Lose the trailing '\0'.
+    std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' ');
+
+    os << "Cmdline: " << current_cmd_line;
+    const char* stashed_cmd_line = GetCmdLine();
+    if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line) {
+      os << "Original command line: " << stashed_cmd_line;
+    }
   }
-  std::replace(result.begin(), result.end(), '\0', ' ');
-  return true;
-}
+  os << "\n";
+#else
+  os << "Cmdline: " << GetCmdLine() << "\n";
 #endif
+}
 
 SignalCatcher::SignalCatcher(const std::string& stack_trace_file)
     : stack_trace_file_(stack_trace_file),
@@ -59,12 +66,6 @@
       thread_(NULL) {
   SetHaltFlag(false);
 
-#if defined(HAVE_PROC_CMDLINE)
-  // Stash the original command line for SIGQUIT reporting.
-  // By then, /proc/self/cmdline will have been rewritten to something like "system_server".
-  CHECK(ReadCmdLine(cmd_line_));
-#endif
-
   // Create a raw pthread; its start routine will attach to the runtime.
   CHECK_PTHREAD_CALL(pthread_create, (&pthread_, NULL, &Run, this), "signal catcher thread");
 
@@ -129,17 +130,7 @@
   os << "\n"
      << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n";
 
-#if defined(HAVE_PROC_CMDLINE)
-  std::string current_cmd_line;
-  if (ReadCmdLine(current_cmd_line) && current_cmd_line != cmd_line_) {
-    os << "Cmdline: " << current_cmd_line;
-  }
-  os << "\n";
-
-  if (current_cmd_line != cmd_line_) {
-    os << "Original command line: " << cmd_line_ << "\n";
-  }
-#endif
+  DumpCmdLine(os);
 
   os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n";
 
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index da61ceb..131b07c 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -52,7 +52,6 @@
   ConditionVariable cond_;
   pthread_t pthread_;
   Thread* thread_;
-  std::string cmd_line_;
 };
 
 }  // namespace art
diff --git a/src/thread.cc b/src/thread.cc
index d854c3b..e1764ef 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -250,6 +250,7 @@
   CHECK(runtime != NULL);
 
   thin_lock_id_ = runtime->GetThreadList()->AllocThreadId();
+  pthread_self_ = pthread_self();
 
   InitTid();
   InitStackHwm();
@@ -457,10 +458,6 @@
     priority = GetNativePriority();
   }
 
-  int policy;
-  sched_param sp;
-  CHECK_PTHREAD_CALL(pthread_getschedparam, (pthread_self(), &policy, &sp), __FUNCTION__);
-
   std::string scheduler_group_name(GetSchedulerGroupName(tid));
   if (scheduler_group_name.empty()) {
     scheduler_group_name = "default";
@@ -483,7 +480,6 @@
     }
     os << '"' << thread_name << '"'
        << " prio=" << priority
-       << " tid=?"
        << " (not attached)\n";
   }
 
@@ -494,12 +490,18 @@
        << " obj=" << reinterpret_cast<void*>(thread->peer_)
        << " self=" << reinterpret_cast<const void*>(thread) << "\n";
   }
+
   os << "  | sysTid=" << tid
      << " nice=" << getpriority(PRIO_PROCESS, tid)
-     << " sched=" << policy << "/" << sp.sched_priority
-     << " cgrp=" << scheduler_group_name << "\n";
-
-  // TODO: fix this; it's never worked in art! << " handle=" << pthread_self() << "\n";
+     << " cgrp=" << scheduler_group_name;
+  if (thread != NULL) {
+    int policy;
+    sched_param sp;
+    CHECK_PTHREAD_CALL(pthread_getschedparam, (thread->pthread_self_, &policy, &sp), __FUNCTION__);
+    os << " sched=" << policy << "/" << sp.sched_priority
+       << " handle=" << reinterpret_cast<void*>(thread->pthread_self_);
+  }
+  os << "\n";
 
   // Grab the scheduler stats for this thread.
   std::string scheduler_stats;
diff --git a/src/thread.h b/src/thread.h
index 7d885c0..6a2b27e 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -643,6 +643,9 @@
   // A cached copy of the java.lang.Thread's name.
   std::string* name_;
 
+  // A cached pthread_t for the pthread underlying this Thread*.
+  pthread_t pthread_self_;
+
   uint32_t held_mutexes_[kMaxMutexRank + 1];
 
  public:
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 3d0e0be..0dc06f8 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -86,8 +86,8 @@
   }
 
   dirent de;
-  dirent* result;
-  while (!readdir_r(d, &de, &result) && result != NULL) {
+  dirent* e;
+  while (!readdir_r(d, &de, &e) && e != NULL) {
     char* end;
     pid_t tid = strtol(de.d_name, &end, 10);
     if (!*end && !Contains(tid)) {
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index c68d6f3..78bc2e9 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -172,23 +172,23 @@
   }
 }
 
-bool MethodVerifier::VerifyClass(const Class* klass, std::string& error) {
+MethodVerifier::FailureKind MethodVerifier::VerifyClass(const Class* klass, std::string& error) {
   if (klass->IsVerified()) {
-    return true;
+    return kNoFailure;
   }
   Class* super = klass->GetSuperClass();
   if (super == NULL && StringPiece(ClassHelper(klass).GetDescriptor()) != "Ljava/lang/Object;") {
     error = "Verifier rejected class ";
     error += PrettyDescriptor(klass);
     error += " that has no super class";
-    return false;
+    return kHardFailure;
   }
   if (super != NULL && super->IsFinal()) {
     error = "Verifier rejected class ";
     error += PrettyDescriptor(klass);
     error += " that attempts to sub-class final class ";
     error += PrettyDescriptor(super);
-    return false;
+    return kHardFailure;
   }
   ClassHelper kh(klass);
   const DexFile& dex_file = kh.GetDexFile();
@@ -198,24 +198,25 @@
     error += PrettyDescriptor(klass);
     error += " that isn't present in dex file ";
     error += dex_file.GetLocation();
-    return false;
+    return kHardFailure;
   }
   return VerifyClass(&dex_file, kh.GetDexCache(), klass->GetClassLoader(), class_def_idx, error);
 }
 
-bool MethodVerifier::VerifyClass(const DexFile* dex_file, DexCache* dex_cache,
+MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, DexCache* dex_cache,
     const ClassLoader* class_loader, uint32_t class_def_idx, std::string& error) {
   const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx);
   const byte* class_data = dex_file->GetClassData(class_def);
   if (class_data == NULL) {
     // empty class, probably a marker interface
-    return true;
+    return kNoFailure;
   }
   ClassDataItemIterator it(*dex_file, class_data);
   while (it.HasNextStaticField() || it.HasNextInstanceField()) {
     it.Next();
   }
   size_t error_count = 0;
+  bool hard_fail = false;
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   while (it.HasNextDirectMethod()) {
     uint32_t method_idx = it.GetMemberIndex();
@@ -225,15 +226,19 @@
       // We couldn't resolve the method, but continue regardless.
       Thread::Current()->ClearException();
     }
-    if (!VerifyMethod(method_idx, dex_file, dex_cache, class_loader, class_def_idx,
-        it.GetMethodCodeItem(), method, it.GetMemberAccessFlags())) {
-      if (error_count > 0) {
-        error += "\n";
+    MethodVerifier::FailureKind result = VerifyMethod(method_idx, dex_file, dex_cache, class_loader,
+        class_def_idx, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags());
+    if (result != kNoFailure) {
+      if (result == kHardFailure) {
+        hard_fail = true;
+        if (error_count > 0) {
+          error += "\n";
+        }
+        error = "Verifier rejected class ";
+        error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+        error += " due to bad method ";
+        error += PrettyMethod(method_idx, *dex_file);
       }
-      error = "Verifier rejected class ";
-      error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
-      error += " due to bad method ";
-      error += PrettyMethod(method_idx, *dex_file);
       ++error_count;
     }
     it.Next();
@@ -246,35 +251,43 @@
       // We couldn't resolve the method, but continue regardless.
       Thread::Current()->ClearException();
     }
-    if (!VerifyMethod(method_idx, dex_file, dex_cache, class_loader, class_def_idx,
-        it.GetMethodCodeItem(), method, it.GetMemberAccessFlags())) {
-      if (error_count > 0) {
-        error += "\n";
+    MethodVerifier::FailureKind result = VerifyMethod(method_idx, dex_file, dex_cache, class_loader,
+        class_def_idx, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags());
+    if (result != kNoFailure) {
+      if (result == kHardFailure) {
+        hard_fail = true;
+        if (error_count > 0) {
+          error += "\n";
+        }
+        error = "Verifier rejected class ";
+        error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+        error += " due to bad method ";
+        error += PrettyMethod(method_idx, *dex_file);
       }
-      error = "Verifier rejected class ";
-      error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
-      error += " due to bad method ";
-      error += PrettyMethod(method_idx, *dex_file);
       ++error_count;
     }
     it.Next();
   }
-  return error_count == 0;
+  if (error_count == 0) {
+    return kNoFailure;
+  } else {
+    return hard_fail ? kHardFailure : kSoftFailure;
+  }
 }
 
-bool MethodVerifier::VerifyMethod(uint32_t method_idx, const DexFile* dex_file, DexCache* dex_cache,
-    const ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item,
-    Method* method, uint32_t method_access_flags) {
+MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, const DexFile* dex_file,
+    DexCache* dex_cache, const ClassLoader* class_loader, uint32_t class_def_idx,
+    const DexFile::CodeItem* code_item, Method* method, uint32_t method_access_flags) {
   MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item, method_idx,
                           method, method_access_flags);
-  bool success = verifier.Verify();
-  if (success) {
+  if (verifier.Verify()) {
     // Verification completed, however failures may be pending that didn't cause the verification
     // to hard fail.
     CHECK(!verifier.have_pending_hard_failure_);
     if (verifier.failures_.size() != 0) {
       verifier.DumpFailures(LOG(INFO) << "Soft verification failures in "
                                       << PrettyMethod(method_idx, *dex_file) << "\n");
+      return kSoftFailure;
     }
   } else {
     // Bad method data.
@@ -286,8 +299,9 @@
       std::cout << "\n" << verifier.info_messages_.str();
       verifier.Dump(std::cout);
     }
+    return kHardFailure;
   }
-  return success;
+  return kNoFailure;
 }
 
 void MethodVerifier::VerifyMethodAndDump(Method* method) {
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index 639d736..2e4b33f 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -161,9 +161,15 @@
   typedef greenland::InferredRegCategoryMap InferredRegCategoryMap;
 #endif
  public:
-  /* Verify a class. Returns "true" on success. */
-  static bool VerifyClass(const Class* klass, std::string& error);
-  static bool VerifyClass(const DexFile* dex_file, DexCache* dex_cache,
+  enum FailureKind {
+    kNoFailure,
+    kSoftFailure,
+    kHardFailure,
+  };
+
+  /* Verify a class. Returns "kNoFailure" on success. */
+  static FailureKind VerifyClass(const Class* klass, std::string& error);
+  static FailureKind VerifyClass(const DexFile* dex_file, DexCache* dex_cache,
       const ClassLoader* class_loader, uint32_t class_def_idx, std::string& error);
 
   uint8_t EncodePcToReferenceMapData() const;
@@ -227,7 +233,7 @@
    *  (3) Iterate through the method, checking type safety and looking
    *      for code flow problems.
    */
-  static bool VerifyMethod(uint32_t method_idx, const DexFile* dex_file, DexCache* dex_cache,
+  static FailureKind VerifyMethod(uint32_t method_idx, const DexFile* dex_file, DexCache* dex_cache,
       const ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item,
       Method* method, uint32_t method_access_flags);
   static void VerifyMethodAndDump(Method* method);
diff --git a/src/verifier/method_verifier_test.cc b/src/verifier/method_verifier_test.cc
index f35d8a1..5c23e9f 100644
--- a/src/verifier/method_verifier_test.cc
+++ b/src/verifier/method_verifier_test.cc
@@ -33,7 +33,7 @@
 
     // Verify the class
     std::string error_msg;
-    ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg)) << error_msg;
+    ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg) == MethodVerifier::kNoFailure) << error_msg;
   }
 
   void VerifyDexFile(const DexFile* dex) {
@@ -56,7 +56,7 @@
   SirtRef<ClassLoader> class_loader(LoadDex("IntMath"));
   Class* klass = class_linker_->FindClass("LIntMath;", class_loader.get());
   std::string error_msg;
-  ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg)) << error_msg;
+  ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg) == MethodVerifier::kNoFailure) << error_msg;
 }
 
 }  // namespace verifier
diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py
index ba2b4d1..23d6d3e 100755
--- a/tools/generate-operator-out.py
+++ b/tools/generate-operator-out.py
@@ -45,6 +45,7 @@
 
 def Confused(filename, line_number, line):
   sys.stderr.write('%s:%d: confused by:\n%s\n' % (filename, line_number, line))
+  raise Exception("giving up!")
   sys.exit(1)
 
 
@@ -83,7 +84,7 @@
         continue
 
       # Is this the start or end of an enclosing class or struct?
-      m = re.compile(r'^(?:class|struct) (\S+) \{').search(raw_line)
+      m = re.compile(r'^(?:class|struct)(?: MANAGED)? (\S+).* \{').search(raw_line)
       if m:
         enclosing_classes.append(m.group(1))
         continue
@@ -102,8 +103,13 @@
       in_enum = False
       continue
 
-    # Whitespace?
-    line = raw_line.strip()
+    # Strip // comments.
+    line = re.sub(r'//.*', '', raw_line)
+
+    # Strip whitespace.
+    line = line.strip()
+
+    # Skip blank lines.
     if len(line) == 0:
       continue