Merge "Fix various JNI compiler bugs/unimplementeds." into dalvik-dev
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);
}
diff --git a/test/SystemMethods/SystemMethods.java b/test/SystemMethods/SystemMethods.java
index f14df18..3d76548 100644
--- a/test/SystemMethods/SystemMethods.java
+++ b/test/SystemMethods/SystemMethods.java
@@ -24,7 +24,6 @@
String[] digits = new String[] {
"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f",
};
- System.logI("hello world");
long t = System.currentTimeMillis();
for (int i = 7; i >= 0; --i) {
int b = ((int) (t >> (i * 8))) & 0xff;
@@ -34,31 +33,63 @@
return 123;
}
+ private static String[] STRING_DIGITS = new String[] {
+ "0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f",
+ };
+
public static int test2() {
- System.logI("creating char[]...");
char[] cs = new char[20];
- System.logI("...created char[]");
- String[] digits = new String[] {
- "0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f",
- };
long t = System.currentTimeMillis();
- System.logI("creating StringBuilder...");
StringBuilder sb = new StringBuilder(20);
- System.logI("...created StringBuilder");
for (int i = 7; i >= 0; --i) {
int b = ((int) (t >> (i * 8))) & 0xff;
- // TODO: StringBuilder.append(C) works, but StringBuilder.append(Ljava/lang/String;) doesn't.
- System.logI("calling append...");
- sb.append(digits[(b >> 4) & 0xf].charAt(0));
- System.logI("...called append");
- System.logI("calling append...");
- sb.append(digits[b & 0xf].charAt(0));
- System.logI("...called append");
+ sb.append(STRING_DIGITS[(b >> 4) & 0xf]);
+ sb.append(STRING_DIGITS[b & 0xf]);
}
- System.logI("calling toString...");
String result = sb.toString();
- System.logI("...called toString");
System.logI(result);
return 123;
}
+
+ private static char[] DIGITS = new char[] {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z'
+ };
+
+ public static int test3() {
+ long t = System.currentTimeMillis();
+
+ long v = t;
+ // int i = (int) v;
+ // if (v >= 0 && i == v) {
+ // return intToHexString(i, false, 0);
+ // }
+
+ int bufLen = 16; // Max number of hex digits in a long
+ char[] buf = new char[bufLen];
+ int cursor = bufLen;
+
+ do {
+ buf[--cursor] = DIGITS[((int) v) & 0xF];
+ } while ((v >>>= 4) != 0);
+
+ String s = new String(buf, cursor, bufLen - cursor);
+ System.logI(s);
+
+ System.logI(IntegralToString.longToHexString(t));
+ System.logI(Long.toHexString(t));
+ System.logI(Long.toString(t));
+ return 123;
+ }
+
+ private static int i = 4;
+ private static long j = 0x0123456789abcdefL;
+
+ public static int test4() {
+ String s = "int=" + i + " long=" + j;
+ System.logI(s);
+ return 123;
+ }
}