Merge "Move MemUsage into run-test." into dalvik-dev
diff --git a/build/Android.common.mk b/build/Android.common.mk
index e6185ba..5d9fc4b 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -423,20 +423,17 @@
 	XandY
 
 # subdirectories of test/ which are used with test-art-target-oat
-# Declare the simplest tests (Main, HelloWorld, and Fibonacci) first, the rest are alphabetical
+# Declare the simplest tests (Main, HelloWorld) first, the rest are alphabetical
 TEST_OAT_DIRECTORIES := \
 	Main \
 	HelloWorld \
-	Fibonacci \
 	\
 	ExceptionTest \
 	GrowthLimit \
-	ConcurrentGC \
 	IntMath \
 	Invoke \
 	ParallelGC \
 	ReferenceMap \
-	ReflectionTest \
 	StackWalk \
 	ThreadStress
 
diff --git a/src/debugger.cc b/src/debugger.cc
index b2c486e..958fd38 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -669,6 +669,50 @@
   return JDWP::ERR_NONE;
 }
 
+JDWP::JdwpError Dbg::GetOwnedMonitors(JDWP::ObjectId thread_id, std::vector<JDWP::ObjectId>& monitors)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ScopedObjectAccessUnchecked soa(Thread::Current());
+  MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
+  Thread* thread;
+  JDWP::JdwpError error = DecodeThread(soa, thread_id, thread);
+  if (error != JDWP::ERR_NONE) {
+    return error;
+  }
+  if (!IsSuspendedForDebugger(soa, thread)) {
+    return JDWP::ERR_THREAD_NOT_SUSPENDED;
+  }
+
+  struct OwnedMonitorVisitor : public StackVisitor {
+    OwnedMonitorVisitor(const ManagedStack* stack,
+                        const std::deque<InstrumentationStackFrame>* instrumentation_stack)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+        : StackVisitor(stack, instrumentation_stack, NULL) {}
+
+    // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
+    // annotalysis.
+    bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
+      if (!GetMethod()->IsRuntimeMethod()) {
+        Monitor::VisitLocks(this, AppendOwnedMonitors, this);
+      }
+      return true;
+    }
+
+    static void AppendOwnedMonitors(Object* owned_monitor, void* context) {
+      reinterpret_cast<OwnedMonitorVisitor*>(context)->monitors.push_back(owned_monitor);
+    }
+
+    std::vector<Object*> monitors;
+  };
+  OwnedMonitorVisitor visitor(thread->GetManagedStack(), thread->GetInstrumentationStack());
+  visitor.WalkStack();
+
+  for (size_t i = 0; i < visitor.monitors.size(); ++i) {
+    monitors.push_back(gRegistry->Add(visitor.monitors[i]));
+  }
+
+  return JDWP::ERR_NONE;
+}
+
 JDWP::JdwpError Dbg::GetReflectedType(JDWP::RefTypeId class_id, JDWP::ExpandBuf* pReply) {
   JDWP::JdwpError status;
   Class* c = DecodeClass(class_id, status);
diff --git a/src/debugger.h b/src/debugger.h
index fac828a..c58fd4f 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -153,6 +153,8 @@
 
   static JDWP::JdwpError GetMonitorInfo(JDWP::ObjectId object_id, JDWP::ExpandBuf* reply)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static JDWP::JdwpError GetOwnedMonitors(JDWP::ObjectId thread_id, std::vector<JDWP::ObjectId>& monitors)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static JDWP::JdwpError GetArrayLength(JDWP::ObjectId array_id, int& length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 97e6304..f205c95 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -48,7 +48,7 @@
 /*
  * Helper function: read a "location" from an input buffer.
  */
-static void JdwpReadLocation(const uint8_t** pBuf, JdwpLocation* pLoc) {
+static void ReadLocation(const uint8_t** pBuf, JdwpLocation* pLoc) {
   memset(pLoc, 0, sizeof(*pLoc));     /* allows memcmp() later */
   pLoc->type_tag = ReadTypeTag(pBuf);
   pLoc->class_id = ReadObjectId(pBuf);
@@ -59,7 +59,7 @@
 /*
  * Helper function: read a variable-width value from the input buffer.
  */
-static uint64_t JdwpReadValue(const uint8_t** pBuf, size_t width) {
+static uint64_t ReadValue(const uint8_t** pBuf, size_t width) {
   uint64_t value = -1;
   switch (width) {
   case 1:     value = Read1(pBuf); break;
@@ -74,7 +74,7 @@
 /*
  * Helper function: write a variable-width value into the output input buffer.
  */
-static void JdwpWriteValue(ExpandBuf* pReply, int width, uint64_t value) {
+static void WriteValue(ExpandBuf* pReply, int width, uint64_t value) {
   switch (width) {
   case 1:     expandBufAdd1(pReply, value); break;
   case 2:     expandBufAdd2BE(pReply, value); break;
@@ -84,6 +84,17 @@
   }
 }
 
+static JdwpError WriteTaggedObject(ExpandBuf* reply, ObjectId object_id)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  uint8_t tag;
+  JdwpError rc = Dbg::GetObjectTag(object_id, tag);
+  if (rc == ERR_NONE) {
+    expandBufAdd1(reply, tag);
+    expandBufAddObjectId(reply, object_id);
+  }
+  return rc;
+}
+
 /*
  * Common code for *_InvokeMethod requests.
  *
@@ -109,7 +120,7 @@
   for (uint32_t i = 0; i < arg_count; ++i) {
     argTypes[i] = ReadTag(&buf);
     size_t width = Dbg::GetTagWidth(argTypes[i]);
-    argValues[i] = JdwpReadValue(&buf, width);
+    argValues[i] = ReadValue(&buf, width);
     VLOG(jdwp) << "          " << argTypes[i] << StringPrintf("(%zd): %#llx", width, argValues[i]);
   }
 
@@ -137,7 +148,7 @@
     size_t width = Dbg::GetTagWidth(resultTag);
     expandBufAdd1(pReply, resultTag);
     if (width != 0) {
-      JdwpWriteValue(pReply, width, resultValue);
+      WriteValue(pReply, width, resultValue);
     }
     expandBufAdd1(pReply, JT_OBJECT);
     expandBufAddObjectId(pReply, exceptObjId);
@@ -325,21 +336,6 @@
   return ERR_NONE;
 }
 
-/*
- * Tell the debugger what we are capable of.
- */
-static JdwpError VM_Capabilities(JdwpState*, const uint8_t*, int, ExpandBuf* pReply)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  expandBufAdd1(pReply, false);   // canWatchFieldModification
-  expandBufAdd1(pReply, false);   // canWatchFieldAccess
-  expandBufAdd1(pReply, false);   // canGetBytecodes
-  expandBufAdd1(pReply, true);    // canGetSyntheticAttribute
-  expandBufAdd1(pReply, false);   // canGetOwnedMonitorInfo
-  expandBufAdd1(pReply, false);   // canGetCurrentContendedMonitor
-  expandBufAdd1(pReply, true);    // canGetMonitorInfo
-  return ERR_NONE;
-}
-
 static JdwpError VM_ClassPaths(JdwpState*, const uint8_t*, int, ExpandBuf* pReply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   expandBufAddUtf8String(pReply, "/");
@@ -371,36 +367,42 @@
   return ERR_NONE;
 }
 
-/*
- * Tell the debugger what we are capable of.
- */
-static JdwpError VM_CapabilitiesNew(JdwpState*, const uint8_t*, int, ExpandBuf* pReply)
+static JdwpError VM_Capabilities(JdwpState*, const uint8_t*, int, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  expandBufAdd1(pReply, false);   // canWatchFieldModification
-  expandBufAdd1(pReply, false);   // canWatchFieldAccess
-  expandBufAdd1(pReply, false);   // canGetBytecodes
-  expandBufAdd1(pReply, true);    // canGetSyntheticAttribute
-  expandBufAdd1(pReply, false);   // canGetOwnedMonitorInfo
-  expandBufAdd1(pReply, false);   // canGetCurrentContendedMonitor
-  expandBufAdd1(pReply, true);    // canGetMonitorInfo
-  expandBufAdd1(pReply, false);   // canRedefineClasses
-  expandBufAdd1(pReply, false);   // canAddMethod
-  expandBufAdd1(pReply, false);   // canUnrestrictedlyRedefineClasses
-  expandBufAdd1(pReply, false);   // canPopFrames
-  expandBufAdd1(pReply, false);   // canUseInstanceFilters
-  expandBufAdd1(pReply, false);   // canGetSourceDebugExtension
-  expandBufAdd1(pReply, false);   // canRequestVMDeathEvent
-  expandBufAdd1(pReply, false);   // canSetDefaultStratum
-  expandBufAdd1(pReply, false);   // 1.6: canGetInstanceInfo
-  expandBufAdd1(pReply, false);   // 1.6: canRequestMonitorEvents
-  expandBufAdd1(pReply, false);   // 1.6: canGetMonitorFrameInfo
-  expandBufAdd1(pReply, false);   // 1.6: canUseSourceNameFilters
-  expandBufAdd1(pReply, false);   // 1.6: canGetConstantPool
-  expandBufAdd1(pReply, false);   // 1.6: canForceEarlyReturn
+  expandBufAdd1(reply, false);   // canWatchFieldModification
+  expandBufAdd1(reply, false);   // canWatchFieldAccess
+  expandBufAdd1(reply, false);   // canGetBytecodes
+  expandBufAdd1(reply, true);    // canGetSyntheticAttribute
+  expandBufAdd1(reply, true);    // canGetOwnedMonitorInfo
+  expandBufAdd1(reply, false);   // canGetCurrentContendedMonitor
+  expandBufAdd1(reply, true);    // canGetMonitorInfo
+  return ERR_NONE;
+}
 
-  /* fill in reserved22 through reserved32; note count started at 1 */
-  for (int i = 22; i <= 32; i++) {
-    expandBufAdd1(pReply, false);   /* reservedN */
+static JdwpError VM_CapabilitiesNew(JdwpState*, const uint8_t*, int, ExpandBuf* reply)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+
+  // The first few capabilities are the same as those reported by the older call.
+  VM_Capabilities(NULL, NULL, 0, reply);
+
+  expandBufAdd1(reply, false);   // canRedefineClasses
+  expandBufAdd1(reply, false);   // canAddMethod
+  expandBufAdd1(reply, false);   // canUnrestrictedlyRedefineClasses
+  expandBufAdd1(reply, false);   // canPopFrames
+  expandBufAdd1(reply, false);   // canUseInstanceFilters
+  expandBufAdd1(reply, false);   // canGetSourceDebugExtension
+  expandBufAdd1(reply, false);   // canRequestVMDeathEvent
+  expandBufAdd1(reply, false);   // canSetDefaultStratum
+  expandBufAdd1(reply, false);   // 1.6: canGetInstanceInfo
+  expandBufAdd1(reply, false);   // 1.6: canRequestMonitorEvents
+  expandBufAdd1(reply, false);   // 1.6: canGetMonitorFrameInfo
+  expandBufAdd1(reply, false);   // 1.6: canUseSourceNameFilters
+  expandBufAdd1(reply, false);   // 1.6: canGetConstantPool
+  expandBufAdd1(reply, false);   // 1.6: canForceEarlyReturn
+
+  // Fill in reserved22 through reserved32; note count started at 1.
+  for (size_t i = 22; i <= 32; ++i) {
+    expandBufAdd1(reply, false);
   }
   return ERR_NONE;
 }
@@ -652,7 +654,7 @@
     FieldId fieldId = ReadFieldId(&buf);
     JDWP::JdwpTag fieldTag = Dbg::GetStaticFieldBasicTag(fieldId);
     size_t width = Dbg::GetTagWidth(fieldTag);
-    uint64_t value = JdwpReadValue(&buf, width);
+    uint64_t value = ReadValue(&buf, width);
 
     VLOG(jdwp) << "    --> field=" << fieldId << " tag=" << fieldTag << " -> " << value;
     JdwpError status = Dbg::SetStaticFieldValue(fieldId, value, width);
@@ -825,7 +827,7 @@
 
     JDWP::JdwpTag fieldTag = Dbg::GetFieldBasicTag(fieldId);
     size_t width = Dbg::GetTagWidth(fieldTag);
-    uint64_t value = JdwpReadValue(&buf, width);
+    uint64_t value = ReadValue(&buf, width);
 
     VLOG(jdwp) << "    --> fieldId=" << fieldId << " tag=" << fieldTag << "(" << width << ") value=" << value;
     JdwpError status = Dbg::SetFieldValue(object_id, fieldId, value, width);
@@ -1048,15 +1050,35 @@
   ObjectId thread_id = ReadObjectId(&buf);
 
   size_t frame_count;
-  JdwpError error = Dbg::GetThreadFrameCount(thread_id, frame_count);
-  if (error != ERR_NONE) {
-    return error;
+  JdwpError rc = Dbg::GetThreadFrameCount(thread_id, frame_count);
+  if (rc != ERR_NONE) {
+    return rc;
   }
   expandBufAdd4BE(pReply, static_cast<uint32_t>(frame_count));
 
   return ERR_NONE;
 }
 
+static JdwpError TR_OwnedMonitors(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  ObjectId thread_id = ReadObjectId(&buf);
+
+  std::vector<ObjectId> monitors;
+  JdwpError rc = Dbg::GetOwnedMonitors(thread_id, monitors);
+  if (rc != ERR_NONE) {
+    return rc;
+  }
+
+  expandBufAdd4BE(reply, monitors.size());
+  for (size_t i = 0; i < monitors.size(); ++i) {
+    rc = WriteTaggedObject(reply, monitors[i]);
+    if (rc != ERR_NONE) {
+      return rc;
+    }
+  }
+  return ERR_NONE;
+}
+
 /*
  * Get the monitor that the thread is waiting on.
  */
@@ -1278,7 +1300,7 @@
     case MK_LOCATION_ONLY:  /* restrict certain events based on loc */
       {
         JdwpLocation loc;
-        JdwpReadLocation(&buf, &loc);
+        ReadLocation(&buf, &loc);
         VLOG(jdwp) << "    LocationOnly: " << loc;
         mod.locationOnly.loc = loc;
       }
@@ -1423,7 +1445,7 @@
     uint32_t slot = Read4BE(&buf);
     JDWP::JdwpTag sigByte = ReadTag(&buf);
     size_t width = Dbg::GetTagWidth(sigByte);
-    uint64_t value = JdwpReadValue(&buf, width);
+    uint64_t value = ReadValue(&buf, width);
 
     VLOG(jdwp) << "    --> slot " << slot << " " << sigByte << " " << value;
     Dbg::SetLocalValue(thread_id, frame_id, slot, sigByte, value, width);
@@ -1432,32 +1454,21 @@
   return ERR_NONE;
 }
 
-/*
- * Returns the value of "this" for the specified frame.
- */
-static JdwpError SF_ThisObject(JdwpState*, const uint8_t* buf, int, ExpandBuf* pReply)
+static JdwpError SF_ThisObject(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ObjectId thread_id = ReadObjectId(&buf);
   FrameId frame_id = ReadFrameId(&buf);
 
-  ObjectId id;
-  JdwpError rc = Dbg::GetThisObject(thread_id, frame_id, &id);
+  ObjectId object_id;
+  JdwpError rc = Dbg::GetThisObject(thread_id, frame_id, &object_id);
   if (rc != ERR_NONE) {
     return rc;
   }
 
-  uint8_t tag;
-  rc = Dbg::GetObjectTag(id, tag);
-  if (rc != ERR_NONE) {
-    return rc;
-  }
+  VLOG(jdwp) << StringPrintf("  Req for 'this' in thread_id=%#llx frame=%lld --> %#llx",
+                             thread_id, frame_id, object_id);
 
-  VLOG(jdwp) << StringPrintf("  Req for 'this' in thread_id=%#llx frame=%lld --> %#llx '%c'",
-                             thread_id, frame_id, id, static_cast<char>(tag));
-  expandBufAdd1(pReply, tag);
-  expandBufAddObjectId(pReply, id);
-
-  return ERR_NONE;
+  return WriteTaggedObject(reply, object_id);
 }
 
 /*
@@ -1609,7 +1620,7 @@
   { 11,   5,  TR_ThreadGroup,             "ThreadReference.ThreadGroup" },
   { 11,   6,  TR_Frames,                  "ThreadReference.Frames" },
   { 11,   7,  TR_FrameCount,              "ThreadReference.FrameCount" },
-  { 11,   8,  NULL,                       "ThreadReference.OwnedMonitors" },
+  { 11,   8,  TR_OwnedMonitors,           "ThreadReference.OwnedMonitors" },
   { 11,   9,  TR_CurrentContendedMonitor, "ThreadReference.CurrentContendedMonitor" },
   { 11,   10, NULL,                       "ThreadReference.Stop" },
   { 11,   11, NULL,                       "ThreadReference.Interrupt" },
diff --git a/src/monitor.cc b/src/monitor.cc
index df09522..80618e1 100644
--- a/src/monitor.cc
+++ b/src/monitor.cc
@@ -863,12 +863,7 @@
   os << "\n";
 }
 
-static void DumpLockedObject(std::ostream& os, Object* o)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  os << "  - locked <" << o << "> (a " << PrettyTypeOf(o) << ")\n";
-}
-
-void Monitor::DescribeLocks(std::ostream& os, StackVisitor* stack_visitor) {
+void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(Object*, void*), void* callback_context) {
   AbstractMethod* m = stack_visitor->GetMethod();
   CHECK(m != NULL);
 
@@ -877,7 +872,7 @@
   if (m->IsNative()) {
     if (m->IsSynchronized()) {
       Object* jni_this = stack_visitor->GetCurrentSirt()->GetReference(0);
-      DumpLockedObject(os, jni_this);
+      callback(jni_this, callback_context);
     }
     return;
   }
@@ -891,7 +886,7 @@
   // <clinit> is another special case. The runtime holds the class lock while calling <clinit>.
   MethodHelper mh(m);
   if (mh.IsClassInitializer()) {
-    DumpLockedObject(os, m->GetDeclaringClass());
+    callback(m->GetDeclaringClass(), callback_context);
     // Fall through because there might be synchronization in the user code too.
   }
 
@@ -910,11 +905,6 @@
     return;
   }
 
-  // Verification is an iterative process, so it can visit the same monitor-enter instruction
-  // repeatedly with increasingly accurate type information. We don't want duplicates.
-  // TODO: is this fixed if we share the other std::vector-returning verifier code?
-  STLSortAndRemoveDuplicates(&monitor_enter_dex_pcs);
-
   for (size_t i = 0; i < monitor_enter_dex_pcs.size(); ++i) {
     // The verifier works in terms of the dex pcs of the monitor-enter instructions.
     // We want the registers used by those instructions (so we can read the values out of them).
@@ -930,7 +920,7 @@
     uint16_t monitor_register = ((monitor_enter_instruction >> 8) & 0xff);
     Object* o = reinterpret_cast<Object*>(stack_visitor->GetVReg(m, monitor_register,
                                                                  kReferenceVReg));
-    DumpLockedObject(os, o);
+    callback(o, callback_context);
   }
 }
 
diff --git a/src/monitor.h b/src/monitor.h
index b546289..66db42e 100644
--- a/src/monitor.h
+++ b/src/monitor.h
@@ -87,7 +87,10 @@
   static void DescribeWait(std::ostream& os, const Thread* thread)
       LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  static void DescribeLocks(std::ostream& os, StackVisitor* stack_visitor)
+
+  // Calls 'callback' once for each lock held in the single stack frame represented by
+  // the current state of 'stack_visitor'.
+  static void VisitLocks(StackVisitor* stack_visitor, void (*callback)(Object*, void*), void* callback_context)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Object* GetObject();
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index a555c3d..81cbdd5 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -244,7 +244,6 @@
 }
 
 uintptr_t GetDeoptimizationEntryPoint() {
-  UNIMPLEMENTED(FATAL);
   return reinterpret_cast<uintptr_t>(art_deoptimize);
 }
 
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 1d24606..379fcce 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -374,15 +374,20 @@
 TWO_ARG_DOWNCALL art_initialize_type_from_code, artInitializeTypeFromCode, RETURN_IF_EAX_NOT_ZERO
 TWO_ARG_DOWNCALL art_initialize_type_and_verify_access_from_code, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_EAX_NOT_ZERO
 
+    /*
+     * On entry, eax and ecx must be preserved, edx is dex PC
+     */
 DEFINE_FUNCTION art_update_debugger
-    mov  %eax, %ebx               // stash away eax so that it's saved as if it were an argument
+    mov %eax, %ebx                // stash away eax so that it's saved as if it were an argument
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
+    subl LITERAL(4), %esp         // alignment padding
     pushl %esp                    // pass arg2 (sp)
     pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
     pushl %edx                    // pass arg0 (dex pc)
     call SYMBOL(artUpdateDebuggerFromCode) // artUpdateDebuggerFromCode(int32_t, Thread*, Method**)
+    addl LITERAL(16), %esp        // pop arguments
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
-    mov  %ebx, %eax               // restore original eax
+    mov %ebx, %eax                // restore original eax
     ret
 
 DEFINE_FUNCTION art_get_and_clear_exception
@@ -745,13 +750,68 @@
     addl LITERAL(44), %esp        // pop arguments
     RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
+    /*
+     * Routine that intercepts method calls and returns.
+     */
 DEFINE_FUNCTION art_instrumentation_entry_from_code
-    ret
+    xchgl %eax, (%esp)            // place LR in eax, save eax
+    pushl %ecx                    // save ecx
+    pushl %edx                    // save edx
+    pushl %ebx                    // save ebx
+    lea   16(%esp), %edx          // remember bottom of caller's frame
+    pushl %eax                    // pass LR
+    pushl %edx                    // pass SP
+    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    pushl 24(%esp)                // pass Method*
+    call  SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Thread*, SP, LR)
+    addl  LITERAL(16), %esp       // pop arguments
+    popl  %ebx                    // restore ebx
+    popl  %edx                    // restore edx
+    movl  (%esp), %ecx            // restore ecx (without popping)
+    movl  %eax, (%esp)            // place method's code pointer on stack
+    movl  4(%esp), %eax           // restore eax (without popping)
+    movl  LITERAL(SYMBOL(art_instrumentation_exit_from_code)), 4(%esp)
+                                  // place instrumentation exit as return pc
+    ret                           // call method (and pop)
 DEFINE_FUNCTION art_instrumentation_exit_from_code
-    ret
+    mov   %esp, %ecx              // remember bottom of caller's frame
+    pushl %edx                    // save return value
+    pushl %eax                    // save other half of return value
+    pushl %ecx                    // pass SP
+    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current
+    call  SYMBOL(artInstrumentationMethodExitFromCode)  // (Thread*, SP)
+    mov   %eax, %ecx              // move returned link register
+    // TODO: Set link register for deopt
+    addl  LITERAL(8), %esp        // pop arguments
+    popl  %eax                    // restore return value
+    popl  %edx                    // restore other half of return value
+    jmp   *%ecx                   // return
 
+    /*
+     * The thread's enter interpreter flag is set and so we should transition to the interpreter
+     * rather than allow execution to continue in the frame below. There may be live results in
+     * registers depending on how complete the operation is when we safepoint - for example, a
+     * set operation may have completed while a get operation needs writing back into the vregs.
+     */
 DEFINE_FUNCTION art_deoptimize
-    ret
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    pushl %esp                    // pass SP
+    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    pushl %edx                    // push half of return value
+    pushl %eax                    // push other half of return value
+    call SYMBOL(artDeoptimize)    // artDeoptimize(return value, Thread*, SP)
+                                  // Returns caller method's frame size.
+    addl LITERAL(16), %esp        // pop arguments
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    testl %eax, %eax              // Was the caller an upcall?
+    jz    1f                      // Return if caller was upcall.
+    lea   (%esp, %eax), %edx      // edx == bottom of caller's frame.
+    mov   %edx, %esp              // Remove frame.
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+    call SYMBOL(artEnterInterpreterFromDeoptimize) // Enter interpreter, callee-save ends stack fragment.
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+1:
+    ret                           // Return to caller.
 
     /*
      * String's indexOf.
diff --git a/src/thread.cc b/src/thread.cc
index 5acc611..f7c568f 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -85,7 +85,6 @@
 }
 
 void Thread::SetDebuggerUpdatesEnabled(bool enabled) {
-  LOG(INFO) << "Turning debugger updates " << (enabled ? "on" : "off") << " for " << *this;
 #if !defined(ART_USE_LLVM_COMPILER)
   ChangeDebuggerEntryPoint(&entrypoints_, enabled);
 #else
@@ -887,13 +886,20 @@
         Monitor::DescribeWait(os, thread);
       }
       if (can_allocate) {
-        Monitor::DescribeLocks(os, this);
+        Monitor::VisitLocks(this, DumpLockedObject, &os);
       }
     }
 
     ++frame_count;
     return true;
   }
+
+  static void DumpLockedObject(Object* o, void* context)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    std::ostream& os = *reinterpret_cast<std::ostream*>(context);
+    os << "  - locked <" << o << "> (a " << PrettyTypeOf(o) << ")\n";
+  }
+
   std::ostream& os;
   const Thread* thread;
   bool can_allocate;
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 6611d3c..7afa6d4 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -434,7 +434,7 @@
     case VERIFY_ERROR_ACCESS_METHOD:
     case VERIFY_ERROR_INSTANTIATION:
     case VERIFY_ERROR_CLASS_CHANGE:
-      if (Runtime::Current()->IsCompiler()) {
+      if (Runtime::Current()->IsCompiler() || !can_load_classes_) {
         // If we're optimistically running verification at compile time, turn NO_xxx, ACCESS_xxx,
         // class change and instantiation errors into soft verification errors so that we re-verify
         // at runtime. We may fail to find or to agree on access because of not yet available class
@@ -1049,7 +1049,6 @@
   verifier::MethodVerifier::SetInferredRegCategoryMap(ref, *table);
 #endif
 
-
   return true;
 }
 
@@ -1340,19 +1339,12 @@
 }
 
 bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) {
-#ifdef VERIFIER_STATS
-  if (CurrentInsnFlags().IsVisited()) {
-    gDvm.verifierStats.instrsReexamined++;
-  } else {
-    gDvm.verifierStats.instrsExamined++;
-  }
-#endif
-
   // If we're doing FindLocksAtDexPc, check whether we're at the dex pc we care about.
   // We want the state _before_ the instruction, for the case where the dex pc we're
   // interested in is itself a monitor-enter instruction (which is a likely place
   // for a thread to be suspended).
   if (monitor_enter_dex_pcs_ != NULL && work_insn_idx_ == interesting_dex_pc_) {
+    monitor_enter_dex_pcs_->clear(); // The new work line is more accurate than the previous one.
     for (size_t i = 0; i < work_line_->GetMonitorEnterCount(); ++i) {
       monitor_enter_dex_pcs_->push_back(work_line_->GetMonitorEnterDexPc(i));
     }
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index a02cc25..7779efe 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -224,6 +224,10 @@
   static bool IsClassRejected(Compiler::ClassReference ref)
       LOCKS_EXCLUDED(rejected_classes_lock_);
 
+  bool CanLoadClasses() const {
+    return can_load_classes_;
+  }
+
  private:
   explicit MethodVerifier(const DexFile* dex_file, DexCache* dex_cache,
       ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item,
diff --git a/src/verifier/register_line.cc b/src/verifier/register_line.cc
index afd2eff..74f83da 100644
--- a/src/verifier/register_line.cc
+++ b/src/verifier/register_line.cc
@@ -42,7 +42,8 @@
   } else if (new_type.IsConflict()) {  // should only be set during a merge
     verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
     return false;
-  } else if (!Runtime::Current()->IsCompiler() && new_type.IsUnresolvedTypes()) {
+  } else if (verifier_->CanLoadClasses() && !Runtime::Current()->IsCompiler() &&
+      new_type.IsUnresolvedTypes()) {
     // Unresolvable classes at runtime are bad and marked as a rewrite error.
     verifier_->Fail(VERIFY_ERROR_NO_CLASS) << "Set register to unresolved class '"
                                            << new_type << "' at runtime";
diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt
new file mode 100644
index 0000000..9417174
--- /dev/null
+++ b/test/100-reflect2/expected.txt
@@ -0,0 +1,77 @@
+true
+8
+x
+3.141592653589793
+3.14
+32
+81985529216486895
+16
+false
+7
+y
+2.7
+2.7
+31
+63
+15
+true
+6
+z
+1.3
+1.3
+30
+62
+14
+java.lang.IllegalArgumentException: invalid primitive conversion from int to short
+	at java.lang.reflect.Field.set(Native Method)
+	at Main.testFieldReflection(Main.java:121)
+	at Main.main(Main.java:269)
+true (class java.lang.Boolean)
+6 (class java.lang.Byte)
+z (class java.lang.Character)
+1.3 (class java.lang.Double)
+1.3 (class java.lang.Float)
+30 (class java.lang.Integer)
+62 (class java.lang.Long)
+14 (class java.lang.Short)
+[public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), private java.lang.String(java.lang.String,char), private java.lang.String(java.lang.String,int), private java.lang.String(java.lang.String,java.lang.String), private java.lang.String(java.lang.String,java.lang.String,java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)]
+[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID]
+[void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), static void java.lang.String.<clinit>(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)]
+[]
+[interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence]
+0
+17
+false
+true
+true
+false
+[int]
+4444
+null (null)
+[int]
+[int, int]
+1111 2222
+null (null)
+[int, int]
+1111 2222
+3333 (class java.lang.Integer)
+[class [I]
+10 (class java.lang.Integer)
+[class [Ljava.lang.String;]
+hello (class java.lang.String)
+[boolean, byte, char, double, float, int, long, short]
+true 0 1 2.0 3.0 4 5 6
+null (null)
+[boolean, byte, char, double, class java.lang.String, float, int, long, short]
+true 0 1 2.0  hello world 3.0 4 5 6
+null (null)
+[]
+java.lang.reflect.InvocationTargetException
+	at java.lang.reflect.Method.invoke(Native Method)
+	at Main.testMethodReflection(Main.java:210)
+	at Main.main(Main.java:270)
+Caused by: java.lang.ArithmeticException: surprise!
+	at Main.thrower(Main.java:218)
+	... 3 more
+ (class java.lang.String)
+yz (class java.lang.String)
diff --git a/test/100-reflect2/info.txt b/test/100-reflect2/info.txt
new file mode 100644
index 0000000..1910b6e
--- /dev/null
+++ b/test/100-reflect2/info.txt
@@ -0,0 +1 @@
+Another set of reflection tests.
\ No newline at end of file
diff --git a/test/ReflectionTest/ReflectionTest.java b/test/100-reflect2/src/Main.java
similarity index 65%
rename from test/ReflectionTest/ReflectionTest.java
rename to test/100-reflect2/src/Main.java
index a9dc6e7..0404591 100644
--- a/test/ReflectionTest/ReflectionTest.java
+++ b/test/100-reflect2/src/Main.java
@@ -17,7 +17,7 @@
 import java.lang.reflect.*;
 import java.util.*;
 
-class ReflectionTest {
+class Main {
   private static boolean z = true;
   private static byte b = 8;
   private static char c = 'x';
@@ -30,114 +30,114 @@
   public static void testFieldReflection() throws Exception {
     Field f;
 
-    f = ReflectionTest.class.getDeclaredField("z");
+    f = Main.class.getDeclaredField("z");
     System.out.println(f.getBoolean(null));
-    f = ReflectionTest.class.getDeclaredField("b");
+    f = Main.class.getDeclaredField("b");
     System.out.println(f.getByte(null));
-    f = ReflectionTest.class.getDeclaredField("c");
+    f = Main.class.getDeclaredField("c");
     System.out.println(f.getChar(null));
-    f = ReflectionTest.class.getDeclaredField("d");
+    f = Main.class.getDeclaredField("d");
     System.out.println(f.getDouble(null));
-    f = ReflectionTest.class.getDeclaredField("f");
+    f = Main.class.getDeclaredField("f");
     System.out.println(f.getFloat(null));
-    f = ReflectionTest.class.getDeclaredField("i");
+    f = Main.class.getDeclaredField("i");
     System.out.println(f.getInt(null));
-    f = ReflectionTest.class.getDeclaredField("j");
+    f = Main.class.getDeclaredField("j");
     System.out.println(f.getLong(null));
-    f = ReflectionTest.class.getDeclaredField("s");
+    f = Main.class.getDeclaredField("s");
     System.out.println(f.getShort(null));
 
-    f = ReflectionTest.class.getDeclaredField("z");
+    f = Main.class.getDeclaredField("z");
     f.setBoolean(null, false);
-    f = ReflectionTest.class.getDeclaredField("b");
+    f = Main.class.getDeclaredField("b");
     f.setByte(null, (byte) 7);
-    f = ReflectionTest.class.getDeclaredField("c");
+    f = Main.class.getDeclaredField("c");
     f.setChar(null, 'y');
-    f = ReflectionTest.class.getDeclaredField("d");
+    f = Main.class.getDeclaredField("d");
     f.setDouble(null, 2.7);
-    f = ReflectionTest.class.getDeclaredField("f");
+    f = Main.class.getDeclaredField("f");
     f.setFloat(null, 2.7f);
-    f = ReflectionTest.class.getDeclaredField("i");
+    f = Main.class.getDeclaredField("i");
     f.setInt(null, 31);
-    f = ReflectionTest.class.getDeclaredField("j");
+    f = Main.class.getDeclaredField("j");
     f.setLong(null, 63);
-    f = ReflectionTest.class.getDeclaredField("s");
+    f = Main.class.getDeclaredField("s");
     f.setShort(null, (short) 15);
 
-    f = ReflectionTest.class.getDeclaredField("z");
+    f = Main.class.getDeclaredField("z");
     System.out.println(f.getBoolean(null));
-    f = ReflectionTest.class.getDeclaredField("b");
+    f = Main.class.getDeclaredField("b");
     System.out.println(f.getByte(null));
-    f = ReflectionTest.class.getDeclaredField("c");
+    f = Main.class.getDeclaredField("c");
     System.out.println(f.getChar(null));
-    f = ReflectionTest.class.getDeclaredField("d");
+    f = Main.class.getDeclaredField("d");
     System.out.println(f.getDouble(null));
-    f = ReflectionTest.class.getDeclaredField("f");
+    f = Main.class.getDeclaredField("f");
     System.out.println(f.getFloat(null));
-    f = ReflectionTest.class.getDeclaredField("i");
+    f = Main.class.getDeclaredField("i");
     System.out.println(f.getInt(null));
-    f = ReflectionTest.class.getDeclaredField("j");
+    f = Main.class.getDeclaredField("j");
     System.out.println(f.getLong(null));
-    f = ReflectionTest.class.getDeclaredField("s");
+    f = Main.class.getDeclaredField("s");
     System.out.println(f.getShort(null));
 
-    f = ReflectionTest.class.getDeclaredField("z");
+    f = Main.class.getDeclaredField("z");
     f.set(null, Boolean.valueOf(true));
-    f = ReflectionTest.class.getDeclaredField("b");
+    f = Main.class.getDeclaredField("b");
     f.set(null, Byte.valueOf((byte) 6));
-    f = ReflectionTest.class.getDeclaredField("c");
+    f = Main.class.getDeclaredField("c");
     f.set(null, Character.valueOf('z'));
-    f = ReflectionTest.class.getDeclaredField("d");
+    f = Main.class.getDeclaredField("d");
     f.set(null, Double.valueOf(1.3));
-    f = ReflectionTest.class.getDeclaredField("f");
+    f = Main.class.getDeclaredField("f");
     f.set(null, Float.valueOf(1.3f));
-    f = ReflectionTest.class.getDeclaredField("i");
+    f = Main.class.getDeclaredField("i");
     f.set(null, Integer.valueOf(30));
-    f = ReflectionTest.class.getDeclaredField("j");
+    f = Main.class.getDeclaredField("j");
     f.set(null, Long.valueOf(62));
     f.set(null, Integer.valueOf(62));
-    f = ReflectionTest.class.getDeclaredField("s");
+    f = Main.class.getDeclaredField("s");
     f.set(null, Short.valueOf((short) 14));
 
-    f = ReflectionTest.class.getDeclaredField("z");
+    f = Main.class.getDeclaredField("z");
     System.out.println(f.getBoolean(null));
-    f = ReflectionTest.class.getDeclaredField("b");
+    f = Main.class.getDeclaredField("b");
     System.out.println(f.getByte(null));
-    f = ReflectionTest.class.getDeclaredField("c");
+    f = Main.class.getDeclaredField("c");
     System.out.println(f.getChar(null));
-    f = ReflectionTest.class.getDeclaredField("d");
+    f = Main.class.getDeclaredField("d");
     System.out.println(f.getDouble(null));
-    f = ReflectionTest.class.getDeclaredField("f");
+    f = Main.class.getDeclaredField("f");
     System.out.println(f.getFloat(null));
-    f = ReflectionTest.class.getDeclaredField("i");
+    f = Main.class.getDeclaredField("i");
     System.out.println(f.getInt(null));
-    f = ReflectionTest.class.getDeclaredField("j");
+    f = Main.class.getDeclaredField("j");
     System.out.println(f.getLong(null));
-    f = ReflectionTest.class.getDeclaredField("s");
+    f = Main.class.getDeclaredField("s");
     System.out.println(f.getShort(null));
 
     try {
-      f = ReflectionTest.class.getDeclaredField("s");
+      f = Main.class.getDeclaredField("s");
       f.set(null, Integer.valueOf(14));
     } catch (IllegalArgumentException expected) {
       expected.printStackTrace();
     }
 
-    f = ReflectionTest.class.getDeclaredField("z");
+    f = Main.class.getDeclaredField("z");
     show(f.get(null));
-    f = ReflectionTest.class.getDeclaredField("b");
+    f = Main.class.getDeclaredField("b");
     show(f.get(null));
-    f = ReflectionTest.class.getDeclaredField("c");
+    f = Main.class.getDeclaredField("c");
     show(f.get(null));
-    f = ReflectionTest.class.getDeclaredField("d");
+    f = Main.class.getDeclaredField("d");
     show(f.get(null));
-    f = ReflectionTest.class.getDeclaredField("f");
+    f = Main.class.getDeclaredField("f");
     show(f.get(null));
-    f = ReflectionTest.class.getDeclaredField("i");
+    f = Main.class.getDeclaredField("i");
     show(f.get(null));
-    f = ReflectionTest.class.getDeclaredField("j");
+    f = Main.class.getDeclaredField("j");
     show(f.get(null));
-    f = ReflectionTest.class.getDeclaredField("s");
+    f = Main.class.getDeclaredField("s");
     show(f.get(null));
 
     /*
@@ -161,10 +161,10 @@
     System.out.println(Arrays.toString(String.class.getDeclaredFields()));
     System.out.println(Arrays.toString(String.class.getDeclaredMethods()));
 
-    System.out.println(Arrays.toString(ReflectionTest.class.getInterfaces()));
+    System.out.println(Arrays.toString(Main.class.getInterfaces()));
     System.out.println(Arrays.toString(String.class.getInterfaces()));
 
-    System.out.println(ReflectionTest.class.getModifiers());
+    System.out.println(Main.class.getModifiers());
     System.out.println(String.class.getModifiers());
 
     System.out.println(String.class.isAssignableFrom(Object.class));
@@ -175,37 +175,37 @@
 
     Method m;
 
-    m = ReflectionTest.class.getDeclaredMethod("IV", int.class);
+    m = Main.class.getDeclaredMethod("IV", int.class);
     System.out.println(Arrays.toString(m.getParameterTypes()));
     show(m.invoke(null, 4444));
     System.out.println(Arrays.toString(m.getParameterTypes()));
 
-    m = ReflectionTest.class.getDeclaredMethod("IIV", int.class, int.class);
+    m = Main.class.getDeclaredMethod("IIV", int.class, int.class);
     System.out.println(Arrays.toString(m.getParameterTypes()));
     show(m.invoke(null, 1111, 2222));
 
-    m = ReflectionTest.class.getDeclaredMethod("III", int.class, int.class);
+    m = Main.class.getDeclaredMethod("III", int.class, int.class);
     System.out.println(Arrays.toString(m.getParameterTypes()));
     show(m.invoke(null, 1111, 2222));
 
-    m = ReflectionTest.class.getDeclaredMethod("sumArray", int[].class);
+    m = Main.class.getDeclaredMethod("sumArray", int[].class);
     System.out.println(Arrays.toString(m.getParameterTypes()));
     show(m.invoke(null, new int[] { 1, 2, 3, 4 }));
 
-    m = ReflectionTest.class.getDeclaredMethod("concat", String[].class);
+    m = Main.class.getDeclaredMethod("concat", String[].class);
     System.out.println(Arrays.toString(m.getParameterTypes()));
     show(m.invoke(null, (Object) new String[] { "h", "e", "l", "l", "o" }));
 
-    m = ReflectionTest.class.getDeclaredMethod("ZBCDFIJSV", boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class);
+    m = Main.class.getDeclaredMethod("ZBCDFIJSV", boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class);
     System.out.println(Arrays.toString(m.getParameterTypes()));
     show(m.invoke(null, true, (byte) 0, '1', 2, 3, 4, 5, (short) 6));
 
-    m = ReflectionTest.class.getDeclaredMethod("ZBCDLFIJSV", boolean.class, byte.class, char.class, double.class, String.class, float.class, int.class, long.class, short.class);
+    m = Main.class.getDeclaredMethod("ZBCDLFIJSV", boolean.class, byte.class, char.class, double.class, String.class, float.class, int.class, long.class, short.class);
     System.out.println(Arrays.toString(m.getParameterTypes()));
     show(m.invoke(null, true, (byte) 0, '1', 2, "hello world", 3, 4, 5, (short) 6));
 
     try {
-      m = ReflectionTest.class.getDeclaredMethod("thrower");
+      m = Main.class.getDeclaredMethod("thrower");
       System.out.println(Arrays.toString(m.getParameterTypes()));
       show(m.invoke(null));
       System.out.println("************* should have thrown!");
diff --git a/test/101-fibonacci/expected.txt b/test/101-fibonacci/expected.txt
new file mode 100644
index 0000000..dcc3617
--- /dev/null
+++ b/test/101-fibonacci/expected.txt
@@ -0,0 +1,2 @@
+fibonacci(10)=55
+fibonacci(11)=89
diff --git a/test/101-fibonacci/info.txt b/test/101-fibonacci/info.txt
new file mode 100644
index 0000000..991511c
--- /dev/null
+++ b/test/101-fibonacci/info.txt
@@ -0,0 +1 @@
+Computes fibonacci.
diff --git a/test/Fibonacci/Fibonacci.java b/test/101-fibonacci/src/Main.java
similarity index 98%
rename from test/Fibonacci/Fibonacci.java
rename to test/101-fibonacci/src/Main.java
index a5c4e4b..3773e1b 100644
--- a/test/Fibonacci/Fibonacci.java
+++ b/test/101-fibonacci/src/Main.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-class Fibonacci {
+class Main {
 
 /*
     // Iterative version
diff --git a/test/102-concurrent-gc/expected.txt b/test/102-concurrent-gc/expected.txt
new file mode 100644
index 0000000..f75da10
--- /dev/null
+++ b/test/102-concurrent-gc/expected.txt
@@ -0,0 +1 @@
+Test complete
diff --git a/test/102-concurrent-gc/info.txt b/test/102-concurrent-gc/info.txt
new file mode 100644
index 0000000..b423127
--- /dev/null
+++ b/test/102-concurrent-gc/info.txt
@@ -0,0 +1,2 @@
+Test that attempts to hide objects from a concurrently running GC. The
+concurrent GC should locate the "hidden" objects through a write-barrier.
diff --git a/test/ConcurrentGC/ConcurrentGC.java b/test/102-concurrent-gc/src/Main.java
similarity index 94%
rename from test/ConcurrentGC/ConcurrentGC.java
rename to test/102-concurrent-gc/src/Main.java
index 1a0fec8..1a9e88e 100644
--- a/test/ConcurrentGC/ConcurrentGC.java
+++ b/test/102-concurrent-gc/src/Main.java
@@ -14,13 +14,9 @@
  * limitations under the License.
  */
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
 import java.util.Random;
 
-public class ConcurrentGC {
+public class Main {
     private static final int buckets = 16 * 1024;
     private static final int bufferSize = 1024;
 
@@ -66,5 +62,6 @@
             }
         } catch (OutOfMemoryError e) {
         }
+        System.out.println("Test complete");
     }
 }