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);