Implement Object.clone.

Also add a conditional to Thread to keep tests running.

Change-Id: I02145973af0fca823acb689e04912c2020d9c650
diff --git a/src/object.cc b/src/object.cc
index 63c9237..91c4b3d 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -21,15 +21,42 @@
 
 namespace art {
 
-bool Object::IsString() const {
-  // TODO use "klass_ == String::GetJavaLangString()" instead?
-  return GetClass() == GetClass()->GetDescriptor()->GetClass();
+Object* Object::Clone() {
+  Class* c = GetClass();
+  DCHECK(!c->IsClassClass());
+
+  // Object::SizeOf gets the right size even if we're an array.
+  // Using c->AllocObject() here would be wrong.
+  size_t num_bytes = SizeOf();
+  Object* copy = Heap::AllocObject(c, num_bytes);
+  if (copy == NULL) {
+    return NULL;
+  }
+
+  // Copy instance data.  We assume memcpy copies by words.
+  // TODO: expose and use move32.
+  byte* src_bytes = reinterpret_cast<byte*>(this);
+  byte* dst_bytes = reinterpret_cast<byte*>(copy);
+  size_t offset = sizeof(Object);
+  memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset);
+
+  // TODO: Mark the clone as finalizable if appropriate.
+//  if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
+//    dvmSetFinalizable(copy);
+//  }
+
+  return copy;
 }
 
 uint32_t Object::GetLockOwner() {
   return Monitor::GetLockOwner(monitor_);
 }
 
+bool Object::IsString() const {
+  // TODO use "klass_ == String::GetJavaLangString()" instead?
+  return GetClass() == GetClass()->GetDescriptor()->GetClass();
+}
+
 void Object::MonitorEnter(Thread* thread) {
   Monitor::MonitorEnter(thread, this);
 }
diff --git a/src/object.h b/src/object.h
index a04fcbb..2adee04 100644
--- a/src/object.h
+++ b/src/object.h
@@ -211,10 +211,7 @@
 
   size_t SizeOf() const;
 
-  Object* Clone() {
-    UNIMPLEMENTED(FATAL);
-    return NULL;
-  }
+  Object* Clone();
 
   static MemberOffset MonitorOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Object, monitor_);
diff --git a/src/object_test.cc b/src/object_test.cc
index 9b6897d..7f6ad4c 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -53,6 +53,14 @@
                                       String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;")));
 }
 
+TEST_F(ObjectTest, Clone) {
+  ObjectArray<Object>* a1 = class_linker_->AllocObjectArray<Object>(256);
+  size_t s1 = a1->SizeOf();
+  Object* clone = a1->Clone();
+  EXPECT_EQ(s1, clone->SizeOf());
+  EXPECT_TRUE(clone->GetClass() == a1->GetClass());
+}
+
 TEST_F(ObjectTest, AllocObjectArray) {
   ObjectArray<Object>* oa = class_linker_->AllocObjectArray<Object>(2);
   EXPECT_EQ(2, oa->GetLength());
diff --git a/src/thread.cc b/src/thread.cc
index 68020d1..9525a1c 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -921,9 +921,12 @@
     }
 
     // this.group.removeThread(this);
-    Method* m = group->GetClass()->FindVirtualMethodForVirtualOrInterface(gThreadGroup_removeThread);
-    Object* args = peer_;
-    m->Invoke(this, group, reinterpret_cast<byte*>(&args), NULL);
+    // group can be null if we're in the compiler or a test.
+    if (group != NULL) {
+      Method* m = group->GetClass()->FindVirtualMethodForVirtualOrInterface(gThreadGroup_removeThread);
+      Object* args = peer_;
+      m->Invoke(this, group, reinterpret_cast<byte*>(&args), NULL);
+    }
 
     // this.vmData = 0;
     SetVmData(peer_, NULL);