Invoke <clinit> where necessary.
This lets us run Long.toString and friends for integral types, though
we'll need a libcore hack to avoid ThreadLocals for the time being.
Change-Id: I04bba5914f1b7d00e4917922e65b9c27302a59ff
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 211b87d..b8cd891 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1177,7 +1177,7 @@
bool ClassLinker::InitializeClass(Class* klass) {
CHECK(klass->GetStatus() == Class::kStatusResolved ||
- klass->GetStatus() == Class::kStatusError);
+ klass->GetStatus() == Class::kStatusError) << klass->GetStatus();
Thread* self = Thread::Current();
@@ -1270,9 +1270,7 @@
Method* clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
if (clinit != NULL) {
- // JValue unused;
- // TODO: dvmCallMethod(self, method, NULL, &unused);
- // UNIMPLEMENTED(FATAL);
+ clinit->Invoke(self, NULL, NULL, NULL);
}
{
diff --git a/src/compiler/RuntimeUtilities.cc b/src/compiler/RuntimeUtilities.cc
index 298cef1..8c94d62 100644
--- a/src/compiler/RuntimeUtilities.cc
+++ b/src/compiler/RuntimeUtilities.cc
@@ -73,7 +73,9 @@
{
uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
uint32_t size_in_bytes = size * table[1];
- UNIMPLEMENTED(WARNING) << "Need to check if array.length() <= size";
+ if (static_cast<int32_t>(size) > array->GetLength()) {
+ UNIMPLEMENTED(FATAL) << "need to throw AIOOBE and unwind";
+ }
memcpy((char*)array + art::Array::DataOffset().Int32Value(),
(char*)&table[4], size_in_bytes);
}
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index a1aadc8..b11dff6 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -296,35 +296,63 @@
CompileDirectMethod(NULL, "java.lang.String", "<clinit>", "()V");
CompileDirectMethod(NULL, "java.lang.String", "<init>", "(II[C)V");
CompileDirectMethod(NULL, "java.lang.String", "<init>", "([CII)V");
+ CompileVirtualMethod(NULL, "java.lang.String", "_getChars", "(II[CI)V");
CompileVirtualMethod(NULL, "java.lang.String", "charAt", "(I)C");
CompileVirtualMethod(NULL, "java.lang.String", "length", "()I");
- CompileVirtualMethod(NULL, "java.lang.String", "_getChars", "(II[CI)V");
+ CompileDirectMethod(NULL, "java.lang.AbstractStringBuilder", "<init>", "()V");
CompileDirectMethod(NULL, "java.lang.AbstractStringBuilder", "<init>", "(I)V");
- CompileVirtualMethod(NULL, "java.lang.AbstractStringBuilder", "append0", "(Ljava/lang/String;)V");
- CompileVirtualMethod(NULL, "java.lang.AbstractStringBuilder", "append0", "(C)V");
- CompileVirtualMethod(NULL, "java.lang.AbstractStringBuilder", "appendNull", "()V");
CompileDirectMethod(NULL, "java.lang.AbstractStringBuilder", "enlargeBuffer", "(I)V");
+ CompileVirtualMethod(NULL, "java.lang.AbstractStringBuilder", "append0", "(C)V");
+ CompileVirtualMethod(NULL, "java.lang.AbstractStringBuilder", "append0", "(Ljava/lang/String;)V");
+ CompileVirtualMethod(NULL, "java.lang.AbstractStringBuilder", "append0", "([CII)V");
+ CompileVirtualMethod(NULL, "java.lang.AbstractStringBuilder", "appendNull", "()V");
CompileVirtualMethod(NULL, "java.lang.AbstractStringBuilder", "toString", "()Ljava/lang/String;");
+ CompileDirectMethod(NULL, "java.lang.StringBuilder", "<init>", "()V");
CompileDirectMethod(NULL, "java.lang.StringBuilder", "<init>", "(I)V");
- CompileVirtualMethod(NULL, "java.lang.StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
CompileVirtualMethod(NULL, "java.lang.StringBuilder", "append", "(C)Ljava/lang/StringBuilder;");
+ CompileVirtualMethod(NULL, "java.lang.StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");
+ CompileVirtualMethod(NULL, "java.lang.StringBuilder", "append", "(J)Ljava/lang/StringBuilder;");
+ CompileVirtualMethod(NULL, "java.lang.StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
CompileVirtualMethod(NULL, "java.lang.StringBuilder", "toString", "()Ljava/lang/String;");
+ CompileDirectMethod(NULL, "java.lang.ThreadLocal", "<init>", "()V");
+ CompileVirtualMethod(NULL, "java.lang.ThreadLocal", "get", "()Ljava/lang/Object;");
+
+ CompileDirectMethod(NULL, "java.lang.Long", "toHexString", "(J)Ljava/lang/String;");
+ CompileDirectMethod(NULL, "java.lang.Long", "toString", "(J)Ljava/lang/String;");
CompileDirectMethod(NULL, "java.lang.Long", "toString", "(JI)Ljava/lang/String;");
+
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "<clinit>", "()V");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "appendInt", "(Ljava/lang/AbstractStringBuilder;I)V");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "appendLong", "(Ljava/lang/AbstractStringBuilder;J)V");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "convertInt", "(Ljava/lang/AbstractStringBuilder;I)Ljava/lang/String;");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "convertLong", "(Ljava/lang/AbstractStringBuilder;J)Ljava/lang/String;");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "intIntoCharArray", "([CII)I");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "intToHexString", "(IZI)Ljava/lang/String;");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "longToHexString", "(J)Ljava/lang/String;");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "longToString", "(J)Ljava/lang/String;");
CompileDirectMethod(NULL, "java.lang.IntegralToString", "longToString", "(JI)Ljava/lang/String;");
+ CompileDirectMethod(NULL, "java.lang.IntegralToString", "stringOf", "([C)Ljava/lang/String;");
CompileDirectMethod(NULL, "java.lang.System", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V");
- CompileDirectMethod(NULL, "java.lang.System", "log", "(CLjava/lang/String;Ljava/lang/Throwable;)V");
- CompileDirectMethod(NULL, "java.lang.System", "logI", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
- CompileDirectMethod(NULL, "java.lang.System", "logI", "(Ljava/lang/String;)V");
CompileDirectMethod(NULL, "java.lang.System", "currentTimeMillis", "()J");
+ CompileDirectMethod(NULL, "java.lang.System", "log", "(CLjava/lang/String;Ljava/lang/Throwable;)V");
+ CompileDirectMethod(NULL, "java.lang.System", "logI", "(Ljava/lang/String;)V");
+ CompileDirectMethod(NULL, "java.lang.System", "logI", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
+
+ CompileDirectMethod(NULL, "java.util.Arrays", "checkOffsetAndCount", "(III)V");
const ClassLoader* class_loader = LoadDex("SystemMethods");
+
+ CompileDirectMethod(class_loader, "SystemMethods", "<clinit>", "()V");
+
AssertStaticIntMethod(class_loader, "SystemMethods", "test0", "()I", 123);
AssertStaticIntMethod(class_loader, "SystemMethods", "test1", "()I", 123);
AssertStaticIntMethod(class_loader, "SystemMethods", "test2", "()I", 123);
+ AssertStaticIntMethod(class_loader, "SystemMethods", "test3", "()I", 123);
+ AssertStaticIntMethod(class_loader, "SystemMethods", "test4", "()I", 123);
}
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index bd1ccec..ef15e8e 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -196,28 +196,8 @@
JValue InvokeWithArgArray(ScopedJniThreadState& ts, Object* receiver,
Method* method, byte* args) {
- Thread* self = ts.Self();
-
- // Push a transition back into managed code onto the linked list in thread
- CHECK_EQ(Thread::kRunnable, self->GetState());
- NativeToManagedRecord record;
- self->PushNativeToManagedRecord(&record);
-
- // Call the invoke stub associated with the method
- // Pass everything as arguments
- const Method::InvokeStub* stub = method->GetInvokeStub();
JValue result;
-
- if (method->HasCode() && stub != NULL) {
- (*stub)(method, receiver, self, args, &result);
- } else {
- LOG(WARNING) << "Not invoking method with no associated code: "
- << PrettyMethod(method);
- result.j = 0;
- }
-
- // Pop transition
- self->PopNativeToManagedRecord(record);
+ method->Invoke(ts.Self(), receiver, args, &result);
return result;
}
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index ac9a7cd..a2f1a56 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -511,11 +511,11 @@
if (*cleared != NULL) {
Thread* self = Thread::Current();
DCHECK(self != NULL);
- // TODO: Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
- // DCHECK(meth != NULL);
- // JValue unused;
+ // TODO: Method* m = gDvm.methJavaLangRefReferenceQueueAdd;
+ // DCHECK(m != NULL);
// Object* reference = *cleared;
- // TODO: dvmCallMethod(self, meth, NULL, &unused, reference);
+ // args = {reference}
+ // TODO: m->Invoke(self, NULL, args, NULL);
UNIMPLEMENTED(FATAL);
*cleared = NULL;
}
diff --git a/src/object.cc b/src/object.cc
index f92f746..8b0c976 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -56,57 +56,48 @@
return Runtime::Current()->GetClassLinker()->ResolveType(GetTypeIdx(), this);
}
-uint32_t Field::Get32StaticFromCode(uint32_t field_idx, const Method* referrer) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return 0;
+Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Field* f = class_linker->ResolveField(field_idx, referrer);
+ if (f != NULL) {
+ Class* c = f->GetDeclaringClass();
+ // If the class is already initializing, we must be inside <clinit>, or
+ // we'd still be waiting for the lock.
+ if (c->GetStatus() == Class::kStatusInitializing || class_linker->EnsureInitialized(c)) {
+ return f;
+ }
}
+ UNIMPLEMENTED(FATAL) << "throw an error and unwind";
+ return NULL;
+}
+
+uint32_t Field::Get32StaticFromCode(uint32_t field_idx, const Method* referrer) {
+ Field* field = FindFieldFromCode(field_idx, referrer);
DCHECK(field->GetType()->PrimitiveSize() == sizeof(int32_t));
return field->Get32(NULL);
}
void Field::Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint32_t new_value) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return;
- }
+ Field* field = FindFieldFromCode(field_idx, referrer);
DCHECK(field->GetType()->PrimitiveSize() == sizeof(int32_t));
field->Set32(NULL, new_value);
}
uint64_t Field::Get64StaticFromCode(uint32_t field_idx, const Method* referrer) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return 0;
- }
+ Field* field = FindFieldFromCode(field_idx, referrer);
DCHECK(field->GetType()->PrimitiveSize() == sizeof(int64_t));
return field->Get64(NULL);
}
void Field::Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint64_t new_value) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return;
- }
+ Field* field = FindFieldFromCode(field_idx, referrer);
DCHECK(field->GetType()->PrimitiveSize() == sizeof(int64_t));
field->Set64(NULL, new_value);
}
Object* Field::GetObjStaticFromCode(uint32_t field_idx, const Method* referrer) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return 0;
- }
+ Field* field = FindFieldFromCode(field_idx, referrer);
DCHECK(!field->GetType()->IsPrimitive());
return field->GetObj(NULL);
}
void Field::SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Object* new_value) {
- Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
- if (field == NULL) {
- UNIMPLEMENTED(FATAL) << "throw an error";
- return;
- }
+ Field* field = FindFieldFromCode(field_idx, referrer);
DCHECK(!field->GetType()->IsPrimitive());
field->SetObj(NULL, new_value);
}
@@ -483,6 +474,28 @@
OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_), invoke_stub, false);
}
+void Method::Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const {
+ // Push a transition back into managed code onto the linked list in thread.
+ CHECK_EQ(Thread::kRunnable, self->GetState());
+ NativeToManagedRecord record;
+ self->PushNativeToManagedRecord(&record);
+
+ // Call the invoke stub associated with the method.
+ // Pass everything as arguments.
+ const Method::InvokeStub* stub = GetInvokeStub();
+ if (HasCode() && stub != NULL) {
+ (*stub)(this, receiver, self, args, result);
+ } else {
+ LOG(WARNING) << "Not invoking method with no associated code: " << PrettyMethod(this);
+ if (result != NULL) {
+ result->j = 0;
+ }
+ }
+
+ // Pop transition.
+ self->PopNativeToManagedRecord(record);
+}
+
void Class::SetStatus(Status new_status) {
CHECK(new_status > GetStatus() || new_status == kStatusError ||
Runtime::Current() == NULL); // no runtime implies we're not initialized
diff --git a/src/object.h b/src/object.h
index 9b3bf88..8504612 100644
--- a/src/object.h
+++ b/src/object.h
@@ -602,7 +602,7 @@
class Method : public AccessibleObject {
public:
// An function that invokes a method with an array of its arguments.
- typedef void InvokeStub(Method* method,
+ typedef void InvokeStub(const Method* method,
Object* obj,
Thread* thread,
byte* args,
@@ -833,6 +833,8 @@
// Size in bytes of the return value
size_t ReturnSize() const;
+ void Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const;
+
const ByteArray* GetCodeArray() const {
return GetFieldPtr<const ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, code_array_), false);
}