Merge "Ignore frame-larger-than warning for auto generated code." into dalvik-dev
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 3e844fd..4efa27a 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -1658,6 +1658,13 @@
         oatFreeTemp(cUnit, r2);
         oatFreeTemp(cUnit, r3);
     } else if (bb->blockType == kExitBlock) {
+        /*
+         * In the exit path, r0/r1 are live - make sure they aren't
+         * allocated by the register utilities as temps.
+         */
+        oatLockTemp(cUnit, r0);
+        oatLockTemp(cUnit, r1);
+
         newLIR0(cUnit, kArmPseudoMethodExit);
         /* If we're compiling for the debugger, generate an update callout */
         if (cUnit->genDebugger) {
diff --git a/src/debugger.cc b/src/debugger.cc
index 8e0d5a9..5a1b1ad 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -1167,16 +1167,42 @@
   return BasicTagFromDescriptor(FieldHelper(FromFieldId(fieldId)).GetTypeDescriptor());
 }
 
-static JDWP::JdwpError GetFieldValueImpl(JDWP::ObjectId objectId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply, bool is_static) {
+static JDWP::JdwpError GetFieldValueImpl(JDWP::RefTypeId refTypeId, JDWP::ObjectId objectId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply, bool is_static) {
+  JDWP::JdwpError status;
+  Class* c = DecodeClass(refTypeId, status);
+  if (refTypeId != 0 && c == NULL) {
+    return status;
+  }
+
   Object* o = gRegistry->Get<Object*>(objectId);
   if ((!is_static && o == NULL) || o == kInvalidObject) {
     return JDWP::ERR_INVALID_OBJECT;
   }
   Field* f = FromFieldId(fieldId);
-  if (f->IsStatic() != is_static) {
+
+  Class* receiver_class = c;
+  if (receiver_class == NULL && o != NULL) {
+    receiver_class = o->GetClass();
+  }
+  // TODO: should we give up now if receiver_class is NULL?
+  if (receiver_class != NULL && !f->GetDeclaringClass()->IsAssignableFrom(receiver_class)) {
+    LOG(INFO) << "ERR_INVALID_FIELDID: " << PrettyField(f) << " " << PrettyClass(receiver_class);
     return JDWP::ERR_INVALID_FIELDID;
   }
 
+  // The RI only enforces the static/non-static mismatch in one direction.
+  // TODO: should we change the tests and check both?
+  if (is_static) {
+    if (!f->IsStatic()) {
+      return JDWP::ERR_INVALID_FIELDID;
+    }
+  } else {
+    if (f->IsStatic()) {
+      LOG(WARNING) << "Ignoring non-NULL receiver for ObjectReference.SetValues on static field " << PrettyField(f);
+      o = NULL;
+    }
+  }
+
   JDWP::JdwpTag tag = BasicTagFromDescriptor(FieldHelper(f).GetTypeDescriptor());
 
   if (IsPrimitiveTag(tag)) {
@@ -1201,11 +1227,11 @@
 }
 
 JDWP::JdwpError Dbg::GetFieldValue(JDWP::ObjectId objectId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply) {
-  return GetFieldValueImpl(objectId, fieldId, pReply, false);
+  return GetFieldValueImpl(0, objectId, fieldId, pReply, false);
 }
 
-JDWP::JdwpError Dbg::GetStaticFieldValue(JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply) {
-  return GetFieldValueImpl(0, fieldId, pReply, true);
+JDWP::JdwpError Dbg::GetStaticFieldValue(JDWP::RefTypeId refTypeId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply) {
+  return GetFieldValueImpl(refTypeId, 0, fieldId, pReply, true);
 }
 
 static JDWP::JdwpError SetFieldValueImpl(JDWP::ObjectId objectId, JDWP::FieldId fieldId, uint64_t value, int width, bool is_static) {
@@ -1214,8 +1240,18 @@
     return JDWP::ERR_INVALID_OBJECT;
   }
   Field* f = FromFieldId(fieldId);
-  if (f->IsStatic() != is_static) {
-    return JDWP::ERR_INVALID_FIELDID;
+
+  // The RI only enforces the static/non-static mismatch in one direction.
+  // TODO: should we change the tests and check both?
+  if (is_static) {
+    if (!f->IsStatic()) {
+      return JDWP::ERR_INVALID_FIELDID;
+    }
+  } else {
+    if (f->IsStatic()) {
+      LOG(WARNING) << "Ignoring non-NULL receiver for ObjectReference.SetValues on static field " << PrettyField(f);
+      o = NULL;
+    }
   }
 
   JDWP::JdwpTag tag = BasicTagFromDescriptor(FieldHelper(f).GetTypeDescriptor());
@@ -1339,10 +1375,12 @@
     return false;
   }
 
+  // TODO: if we're in Thread.sleep(long), we should return TS_SLEEPING,
+  // even if it's implemented using Object.wait(long).
   switch (thread->GetState()) {
   case Thread::kTerminated:   *pThreadStatus = JDWP::TS_ZOMBIE;   break;
   case Thread::kRunnable:     *pThreadStatus = JDWP::TS_RUNNING;  break;
-  case Thread::kTimedWaiting: *pThreadStatus = JDWP::TS_SLEEPING; break;
+  case Thread::kTimedWaiting: *pThreadStatus = JDWP::TS_WAIT;     break;
   case Thread::kBlocked:      *pThreadStatus = JDWP::TS_MONITOR;  break;
   case Thread::kWaiting:      *pThreadStatus = JDWP::TS_WAIT;     break;
   case Thread::kInitializing: *pThreadStatus = JDWP::TS_ZOMBIE;   break;
diff --git a/src/debugger.h b/src/debugger.h
index b88edbb..659843a 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -170,7 +170,7 @@
   static JDWP::JdwpTag GetStaticFieldBasicTag(JDWP::FieldId fieldId);
   static JDWP::JdwpError GetFieldValue(JDWP::ObjectId objectId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply);
   static JDWP::JdwpError SetFieldValue(JDWP::ObjectId objectId, JDWP::FieldId fieldId, uint64_t value, int width);
-  static JDWP::JdwpError GetStaticFieldValue(JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply);
+  static JDWP::JdwpError GetStaticFieldValue(JDWP::RefTypeId refTypeId, JDWP::FieldId fieldId, JDWP::ExpandBuf* pReply);
   static JDWP::JdwpError SetStaticFieldValue(JDWP::FieldId fieldId, uint64_t value, int width);
 
   static std::string StringToUtf8(JDWP::ObjectId strId);
diff --git a/src/heap_bitmap.cc b/src/heap_bitmap.cc
index fd75b7e..21db0e6 100644
--- a/src/heap_bitmap.cc
+++ b/src/heap_bitmap.cc
@@ -209,3 +209,103 @@
 }
 
 }  // namespace art
+
+// Support needed for in order traversal
+#include "object.h"
+#include "object_utils.h"
+
+namespace art {
+
+static void WalkFieldsInOrder(HeapBitmap* visited, HeapBitmap::Callback* callback, Object* obj,
+                              void* arg);
+
+// Walk instance fields of the given Class. Separate function to allow recursion on the super
+// class.
+static void WalkInstanceFields(HeapBitmap* visited, HeapBitmap::Callback* callback, Object* obj,
+                               Class* klass, void* arg) {
+  // Visit fields of parent classes first.
+  Class* super = klass->GetSuperClass();
+  if (super != NULL) {
+    WalkInstanceFields(visited, callback, obj, super, arg);
+  }
+  // Walk instance fields
+  ObjectArray<Field>* fields = klass->GetIFields();
+  if (fields != NULL) {
+    for (int32_t i = 0; i < fields->GetLength(); i++) {
+      Field* field = fields->Get(i);
+      FieldHelper fh(field);
+      if (!fh.GetType()->IsPrimitive()) {
+        Object* value = field->GetObj(obj);
+        if (value != NULL) {
+          WalkFieldsInOrder(visited, callback, value,  arg);
+        }
+      }
+    }
+  }
+}
+
+// For an unvisited object, visit it then all its children found via fields.
+static void WalkFieldsInOrder(HeapBitmap* visited, HeapBitmap::Callback* callback, Object* obj,
+                              void* arg) {
+  if (visited->Test(obj)) {
+    return;
+  }
+  // visit the object itself
+  (*callback)(obj, arg);
+  visited->Set(obj);
+  // Walk instance fields of all objects
+  Class* klass = obj->GetClass();
+  WalkInstanceFields(visited, callback, obj, klass, arg);
+  // Walk static fields of a Class
+  if (obj->IsClass()) {
+    ObjectArray<Field>* fields = klass->GetSFields();
+    if (fields != NULL) {
+      for (int32_t i = 0; i < fields->GetLength(); i++) {
+        Field* field = fields->Get(i);
+        FieldHelper fh(field);
+        if (!fh.GetType()->IsPrimitive()) {
+          Object* value = field->GetObj(NULL);
+          if (value != NULL) {
+            WalkFieldsInOrder(visited, callback, value, arg);
+          }
+        }
+      }
+    }
+  } else if (obj->IsObjectArray()) {
+    // Walk elements of an object array
+    ObjectArray<Object>* obj_array = obj->AsObjectArray<Object>();
+    int32_t length = obj_array->GetLength();
+    for (int32_t i = 0; i < length; i++) {
+      Object* value = obj_array->Get(i);
+      if (value != NULL) {
+        WalkFieldsInOrder(visited, callback, value, arg);
+      }
+    }
+  }
+}
+
+// Visits set bits with an in order traversal.  The callback is not permitted to change the bitmap
+// bits or max during the traversal.
+void HeapBitmap::InOrderWalk(HeapBitmap::Callback* callback, void* arg) {
+  UniquePtr<HeapBitmap> visited (Create("bitmap for in-order walk",
+                                        reinterpret_cast<byte*>(heap_begin_),
+                                        HB_INDEX_TO_OFFSET(bitmap_size_ / kWordSize)));
+  CHECK(bitmap_begin_ != NULL);
+  CHECK(callback != NULL);
+  uintptr_t end = HB_OFFSET_TO_INDEX(heap_end_ - heap_begin_);
+  for (uintptr_t i = 0; i <= end; ++i) {
+    word w = bitmap_begin_[i];
+    if (UNLIKELY(w != 0)) {
+      word high_bit = 1 << (kBitsPerWord - 1);
+      uintptr_t ptr_base = HB_INDEX_TO_OFFSET(i) + heap_begin_;
+      while (w != 0) {
+        const int shift = CLZ(w);
+        Object* obj = reinterpret_cast<Object*>(ptr_base + shift * kAlignment);
+        WalkFieldsInOrder(visited.get(), callback, obj, arg);
+        w &= ~(high_bit >> shift);
+      }
+    }
+  }
+}
+
+}  // namespace art
diff --git a/src/heap_bitmap.h b/src/heap_bitmap.h
index aa542db..70684b9 100644
--- a/src/heap_bitmap.h
+++ b/src/heap_bitmap.h
@@ -90,6 +90,8 @@
 
   void Walk(Callback* callback, void* arg);
 
+  void InOrderWalk(HeapBitmap::Callback* callback, void* arg);
+
   void ScanWalk(uintptr_t base, uintptr_t max, ScanCallback* thunk, void* arg);
 
   static void SweepWalk(const HeapBitmap& live,
diff --git a/src/image_writer.cc b/src/image_writer.cc
index ffe4ec3..91c4e3c 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -308,7 +308,7 @@
   // know where image_roots is going to end up
   image_end_ += RoundUp(sizeof(ImageHeader), 8); // 64-bit-alignment
 
-  heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this);  // TODO: add Space-limited Walk
+  heap_bitmap->InOrderWalk(CalculateNewObjectOffsetsCallback, this);  // TODO: add Space-limited Walk
   DCHECK_LT(image_end_, image_->Size());
 
   // Note that image_top_ is left at end of used space
diff --git a/src/jdwp/jdwp_event.cc b/src/jdwp/jdwp_event.cc
index b92884f..6476c3c 100644
--- a/src/jdwp/jdwp_event.cc
+++ b/src/jdwp/jdwp_event.cc
@@ -839,7 +839,7 @@
 
     if (match_count != 0) {
       VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << match_count << " total) "
-                 << "thread=" << (void*) basket.threadId << ")";
+                 << StringPrintf("thread=%#llx", basket.threadId) << ")";
 
       suspendPolicy = scanSuspendPolicy(matchList, match_count);
       VLOG(jdwp) << "  suspendPolicy=" << suspendPolicy;
@@ -932,8 +932,8 @@
     FindMatchingEvents(EK_EXCEPTION, &basket, matchList, &match_count);
     if (match_count != 0) {
       VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << match_count << " total)"
-                 << " thread=" << (void*) basket.threadId
-                 << " exceptId=" << (void*) exceptionId
+                 << StringPrintf(" thread=%#llx", basket.threadId)
+                 << StringPrintf(" exceptId=%#llx", exceptionId)
                  << " caught=" << basket.caught << ")"
                  << "  throw: " << *pThrowLoc;
       if (pCatchLoc->classId == 0) {
@@ -1012,7 +1012,7 @@
     FindMatchingEvents(EK_CLASS_PREPARE, &basket, matchList, &match_count);
     if (match_count != 0) {
       VLOG(jdwp) << "EVENT: " << matchList[0]->eventKind << "(" << match_count << " total) "
-                 << "thread=" << (void*) basket.threadId << ") " << signature;
+                 << StringPrintf("thread=%#llx", basket.threadId) << ") " << signature;
 
       suspendPolicy = scanSuspendPolicy(matchList, match_count);
       VLOG(jdwp) << "  suspendPolicy=" << suspendPolicy;
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index ef40817..fed1cf9 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -444,24 +444,6 @@
   return handleVM_AllClasses(state, buf, dataLen, pReply, true, true);
 }
 
-/*
- * Given a referenceTypeID, return a string with the JNI reference type
- * signature (e.g. "Ljava/lang/Error;").
- */
-static JdwpError handleRT_Signature(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
-  RefTypeId refTypeId = ReadRefTypeId(&buf);
-
-  VLOG(jdwp) << StringPrintf("  Req for signature of refTypeId=%#llx", refTypeId);
-  std::string signature;
-
-  JdwpError status = Dbg::GetSignature(refTypeId, signature);
-  if (status != ERR_NONE) {
-    return status;
-  }
-  expandBufAddUtf8String(pReply, signature);
-  return ERR_NONE;
-}
-
 static JdwpError handleRT_Modifiers(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   RefTypeId refTypeId = ReadRefTypeId(&buf);
   return Dbg::GetModifiers(refTypeId, pReply);
@@ -471,20 +453,16 @@
  * Get values from static fields in a reference type.
  */
 static JdwpError handleRT_GetValues(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
-  ReadRefTypeId(&buf); // We don't need this, but we need to skip over it in the request.
-  uint32_t numFields = Read4BE(&buf);
-
-  VLOG(jdwp) << "  RT_GetValues " << numFields << ":";
-
-  expandBufAdd4BE(pReply, numFields);
-  for (uint32_t i = 0; i < numFields; i++) {
+  RefTypeId refTypeId = ReadRefTypeId(&buf);
+  uint32_t field_count = Read4BE(&buf);
+  expandBufAdd4BE(pReply, field_count);
+  for (uint32_t i = 0; i < field_count; i++) {
     FieldId fieldId = ReadFieldId(&buf);
-    JdwpError status = Dbg::GetStaticFieldValue(fieldId, pReply);
+    JdwpError status = Dbg::GetStaticFieldValue(refTypeId, fieldId, pReply);
     if (status != ERR_NONE) {
       return status;
     }
   }
-
   return ERR_NONE;
 }
 
@@ -551,27 +529,31 @@
   return ERR_ABSENT_INFORMATION;
 }
 
-/*
- * Like RT_Signature but with the possibility of a "generic signature".
- */
-static JdwpError handleRT_SignatureWithGeneric(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
-  static const char genericSignature[1] = "";
-
+static JdwpError handleRT_Signature(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply, bool with_generic) {
   RefTypeId refTypeId = ReadRefTypeId(&buf);
 
   VLOG(jdwp) << StringPrintf("  Req for signature of refTypeId=%#llx", refTypeId);
   std::string signature;
-  if (Dbg::GetSignature(refTypeId, signature)) {
-    expandBufAddUtf8String(pReply, signature);
-  } else {
-    LOG(WARNING) << StringPrintf("No signature for refTypeId=%#llx", refTypeId);
-    expandBufAddUtf8String(pReply, "Lunknown;");
-  }
-  expandBufAddUtf8String(pReply, genericSignature);
 
+  JdwpError status = Dbg::GetSignature(refTypeId, signature);
+  if (status != ERR_NONE) {
+    return status;
+  }
+  expandBufAddUtf8String(pReply, signature);
+  if (with_generic) {
+    expandBufAddUtf8String(pReply, "");
+  }
   return ERR_NONE;
 }
 
+static JdwpError handleRT_Signature(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
+  return handleRT_Signature(state, buf, dataLen, pReply, false);
+}
+
+static JdwpError handleRT_SignatureWithGeneric(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
+  return handleRT_Signature(state, buf, dataLen, pReply, true);
+}
+
 /*
  * Return the instance of java.lang.ClassLoader that loaded the specified
  * reference type, or null if it was loaded by the system loader.
@@ -773,13 +755,13 @@
  */
 static JdwpError handleOR_GetValues(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   ObjectId objectId = ReadObjectId(&buf);
-  uint32_t numFields = Read4BE(&buf);
+  uint32_t field_count = Read4BE(&buf);
 
-  VLOG(jdwp) << StringPrintf("  Req for %d fields from objectId=%#llx", numFields, objectId);
+  VLOG(jdwp) << StringPrintf("  Req for %d fields from objectId=%#llx", field_count, objectId);
 
-  expandBufAdd4BE(pReply, numFields);
+  expandBufAdd4BE(pReply, field_count);
 
-  for (uint32_t i = 0; i < numFields; i++) {
+  for (uint32_t i = 0; i < field_count; i++) {
     FieldId fieldId = ReadFieldId(&buf);
     JdwpError status = Dbg::GetFieldValue(objectId, fieldId, pReply);
     if (status != ERR_NONE) {
@@ -795,11 +777,11 @@
  */
 static JdwpError handleOR_SetValues(JdwpState* state, const uint8_t* buf, int dataLen, ExpandBuf* pReply) {
   ObjectId objectId = ReadObjectId(&buf);
-  uint32_t numFields = Read4BE(&buf);
+  uint32_t field_count = Read4BE(&buf);
 
-  VLOG(jdwp) << StringPrintf("  Req to set %d fields in objectId=%#llx", numFields, objectId);
+  VLOG(jdwp) << StringPrintf("  Req to set %d fields in objectId=%#llx", field_count, objectId);
 
-  for (uint32_t i = 0; i < numFields; i++) {
+  for (uint32_t i = 0; i < field_count; i++) {
     FieldId fieldId = ReadFieldId(&buf);
 
     JDWP::JdwpTag fieldTag = Dbg::GetFieldBasicTag(fieldId);
diff --git a/src/thread.h b/src/thread.h
index cd39794..4aa77dd 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -73,7 +73,7 @@
     // These correspond to JDWP states (but needn't share the same values).
     kTerminated   = 0,        // TS_ZOMBIE
     kRunnable     = 1,        // TS_RUNNING
-    kTimedWaiting = 2,        // TS_SLEEPING in Object.wait()
+    kTimedWaiting = 2,        // TS_WAIT in Object.wait() with a timeout
     kBlocked      = 3,        // TS_MONITOR on a monitor
     kWaiting      = 4,        // TS_WAIT in Object.wait()
     // Non-JDWP states.