Fix the invocation interface.
Previously, we just cast the Runtime* to a JavaVM*, which blew up as soon as
the caller tried to use their supposed JavaVM*.
This also implements NewObjectArray. Running aexecd on the host, this gets us
as far as not having an x86 CreateInvokeStub...
Change-Id: Iba5f148797d053fba1c69af99b20508ea6aff5cb
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 9a0563b..5cc9ff6 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -98,7 +98,7 @@
offset += 4;
break;
case 'L': {
- // TODO: local reference
+ // TODO: DecodeReference
Object* obj = reinterpret_cast<Object*>(va_arg(ap, jobject));
*reinterpret_cast<Object**>(&arg_array[offset]) = obj;
offset += sizeof(Object*);
@@ -136,7 +136,8 @@
offset += 4;
break;
case 'L': {
- Object* obj = reinterpret_cast<Object*>(args[i - 1].l); // TODO: local reference
+ // TODO: DecodeReference
+ Object* obj = reinterpret_cast<Object*>(args[i - 1].l);
*reinterpret_cast<Object**>(&arg_array[offset]) = obj;
offset += sizeof(Object*);
break;
@@ -156,7 +157,8 @@
JValue InvokeWithArgArray(Thread* self, Object* obj, jmethodID method_id,
byte* args) {
- Method* method = reinterpret_cast<Method*>(method_id); // TODO
+ // TODO: DecodeReference
+ Method* method = reinterpret_cast<Method*>(method_id);
// Call the invoke stub associated with the method
// Pass everything as arguments
const Method::InvokeStub* stub = method->GetInvokeStub();
@@ -221,7 +223,7 @@
std::string descriptor(NormalizeJniClassDescriptor(name));
// TODO: need to get the appropriate ClassLoader.
Class* c = class_linker->FindClass(descriptor, NULL);
- // TODO: local reference.
+ // TODO: AddLocalReference.
return reinterpret_cast<jclass>(c);
}
@@ -321,7 +323,7 @@
void DeleteLocalRef(JNIEnv* env, jobject obj) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
+ UNIMPLEMENTED(WARNING);
}
jboolean IsSameObject(JNIEnv* env, jobject obj1, jobject obj2) {
@@ -900,7 +902,7 @@
jmethodID GetStaticMethodID(JNIEnv* env,
jclass clazz, const char* name, const char* sig) {
ScopedJniThreadState ts(env);
- // TODO: retrieve handle value for class
+ // TODO: DecodeReference
Class* klass = reinterpret_cast<Class*>(clazz);
// TODO: check that klass is initialized
Method* method = klass->FindDirectMethod(name, sig);
@@ -923,7 +925,7 @@
va_list ap;
va_start(ap, methodID);
JValue result = InvokeWithVarArgs(ts.Self(), NULL, methodID, ap);
- jobject obj = reinterpret_cast<jobject>(result.l); // TODO: local reference
+ jobject obj = reinterpret_cast<jobject>(result.l); // TODO: AddLocalReference
return obj;
}
@@ -931,7 +933,7 @@
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
JValue result = InvokeWithVarArgs(ts.Self(), NULL, methodID, args);
- jobject obj = reinterpret_cast<jobject>(result.l); // TODO: local reference
+ jobject obj = reinterpret_cast<jobject>(result.l); // TODO: AddLocalReference
return obj;
}
@@ -939,7 +941,7 @@
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
JValue result = InvokeWithJValues(ts.Self(), NULL, methodID, args);
- jobject obj = reinterpret_cast<jobject>(result.l); // TODO: local reference
+ jobject obj = reinterpret_cast<jobject>(result.l); // TODO: AddLocalReference
return obj;
}
@@ -1282,13 +1284,6 @@
return 0;
}
-jobjectArray NewObjectArray(JNIEnv* env,
- jsize len, jclass clazz, jobject init) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
jobject GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
ScopedJniThreadState ts(env);
UNIMPLEMENTED(FATAL);
@@ -1305,48 +1300,73 @@
JniT NewPrimitiveArray(ScopedJniThreadState& ts, jsize length) {
CHECK_GE(length, 0); // TODO: ReportJniError
ArtT* result = ArtT::Alloc(length);
- // TODO: local reference
+ // TODO: AddLocalReference
return reinterpret_cast<JniT>(result);
}
-jbooleanArray NewBooleanArray(JNIEnv* env, jsize len) {
+jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jbooleanArray, BooleanArray>(ts, len);
+ return NewPrimitiveArray<jbooleanArray, BooleanArray>(ts, length);
}
-jbyteArray NewByteArray(JNIEnv* env, jsize len) {
+jbyteArray NewByteArray(JNIEnv* env, jsize length) {
ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jbyteArray, ByteArray>(ts, len);
+ return NewPrimitiveArray<jbyteArray, ByteArray>(ts, length);
}
-jcharArray NewCharArray(JNIEnv* env, jsize len) {
+jcharArray NewCharArray(JNIEnv* env, jsize length) {
ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jcharArray, CharArray>(ts, len);
+ return NewPrimitiveArray<jcharArray, CharArray>(ts, length);
}
-jdoubleArray NewDoubleArray(JNIEnv* env, jsize len) {
+jdoubleArray NewDoubleArray(JNIEnv* env, jsize length) {
ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jdoubleArray, DoubleArray>(ts, len);
+ return NewPrimitiveArray<jdoubleArray, DoubleArray>(ts, length);
}
-jfloatArray NewFloatArray(JNIEnv* env, jsize len) {
+jfloatArray NewFloatArray(JNIEnv* env, jsize length) {
ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jfloatArray, FloatArray>(ts, len);
+ return NewPrimitiveArray<jfloatArray, FloatArray>(ts, length);
}
-jintArray NewIntArray(JNIEnv* env, jsize len) {
+jintArray NewIntArray(JNIEnv* env, jsize length) {
ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jintArray, IntArray>(ts, len);
+ return NewPrimitiveArray<jintArray, IntArray>(ts, length);
}
-jlongArray NewLongArray(JNIEnv* env, jsize len) {
+jlongArray NewLongArray(JNIEnv* env, jsize length) {
ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jlongArray, LongArray>(ts, len);
+ return NewPrimitiveArray<jlongArray, LongArray>(ts, length);
}
-jshortArray NewShortArray(JNIEnv* env, jsize len) {
+jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_jclass, jobject initial_element) {
ScopedJniThreadState ts(env);
- return NewPrimitiveArray<jshortArray, ShortArray>(ts, len);
+ CHECK_GE(length, 0); // TODO: ReportJniError
+
+ // Compute the array class corresponding to the given element class.
+ // TODO: DecodeReference
+ Class* element_class = reinterpret_cast<Class*>(element_jclass);
+ std::string descriptor;
+ descriptor += "[";
+ descriptor += element_class->GetDescriptor().ToString();
+
+ // Find the class.
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ // TODO: need to get the appropriate ClassLoader.
+ Class* array_class = class_linker->FindClass(descriptor, NULL);
+ if (array_class == NULL) {
+ return NULL;
+ }
+
+ ObjectArray<Object>* result = ObjectArray<Object>::Alloc(array_class, length);
+ CHECK(initial_element == NULL); // TODO: support initial_element
+ // TODO: AddLocalReference.
+ return reinterpret_cast<jobjectArray>(result);
+}
+
+jshortArray NewShortArray(JNIEnv* env, jsize length) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jshortArray, ShortArray>(ts, length);
}
jboolean* GetBooleanArrayElements(JNIEnv* env,
@@ -1572,8 +1592,13 @@
jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ Runtime* runtime = Runtime::Current();
+ if (runtime != NULL) {
+ *vm = runtime->GetJavaVM();
+ } else {
+ *vm = NULL;
+ }
+ return (*vm != NULL) ? JNI_OK : JNI_ERR;
}
void GetStringRegion(JNIEnv* env,
@@ -1902,9 +1927,10 @@
JNIEnv* CreateJNIEnv() {
Thread* self = Thread::Current();
CHECK(self != NULL);
- JNIEnvExt* result = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
+ JNIEnvExt* result = new JNIEnvExt;
result->fns = &gNativeInterface;
result->self = self;
+ result->critical = false;
result->MonitorEnterHelper = &MonitorEnterHelper;
result->MonitorExitHelper = &MonitorExitHelper;
return reinterpret_cast<JNIEnv*>(result);
@@ -1924,24 +1950,23 @@
option->extraInfo));
}
bool ignore_unrecognized = args->ignoreUnrecognized;
- scoped_ptr<Runtime> runtime(Runtime::Create(options, ignore_unrecognized));
+ Runtime* runtime = Runtime::Create(options, ignore_unrecognized);
if (runtime == NULL) {
return JNI_ERR;
} else {
*p_env = reinterpret_cast<JNIEnv*>(Thread::Current()->GetJniEnv());
- *p_vm = reinterpret_cast<JavaVM*>(runtime.release());
+ *p_vm = runtime->GetJavaVM();
return JNI_OK;
}
}
-extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen,
- jsize* nVMs) {
+extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize, jsize* vm_count) {
Runtime* runtime = Runtime::Current();
if (runtime == NULL) {
- *nVMs = 0;
+ *vm_count = 0;
} else {
- *nVMs = 1;
- vmBuf[0] = reinterpret_cast<JavaVM*>(runtime);
+ *vm_count = 1;
+ vms[0] = runtime->GetJavaVM();
}
return JNI_OK;
}
@@ -1951,23 +1976,23 @@
return JNI_ERR;
}
-jint JniInvokeInterface::DestroyJavaVM(JavaVM* vm) {
+jint DestroyJavaVM(JavaVM* vm) {
if (vm == NULL) {
return JNI_ERR;
} else {
- Runtime* runtime = reinterpret_cast<Runtime*>(vm);
- delete runtime;
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ delete raw_vm->runtime;
+ raw_vm->runtime = NULL;
return JNI_OK;
}
}
-jint JniInvokeInterface::AttachCurrentThread(JavaVM* vm,
- JNIEnv** p_env,
- void* thr_args) {
+jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
if (vm == NULL || p_env == NULL) {
return JNI_ERR;
}
- Runtime* runtime = reinterpret_cast<Runtime*>(vm);
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ Runtime* runtime = raw_vm->runtime;
const char* name = NULL;
if (thr_args != NULL) {
// TODO: check version
@@ -1982,17 +2007,18 @@
}
}
-jint JniInvokeInterface::DetachCurrentThread(JavaVM* vm) {
+jint DetachCurrentThread(JavaVM* vm) {
if (vm == NULL) {
return JNI_ERR;
} else {
- Runtime* runtime = reinterpret_cast<Runtime*>(vm);
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ Runtime* runtime = raw_vm->runtime;
runtime->DetachCurrentThread();
return JNI_OK;
}
}
-jint JniInvokeInterface::GetEnv(JavaVM* vm, void** env, jint version) {
+jint GetEnv(JavaVM* vm, void** env, jint version) {
if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
return JNI_EVERSION;
}
@@ -2008,13 +2034,12 @@
return JNI_OK;
}
-jint JniInvokeInterface::AttachCurrentThreadAsDaemon(JavaVM* vm,
- JNIEnv** p_env,
- void* thr_args) {
+jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
if (vm == NULL || p_env == NULL) {
return JNI_ERR;
}
- Runtime* runtime = reinterpret_cast<Runtime*>(vm);
+ JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
+ Runtime* runtime = raw_vm->runtime;
const char* name = NULL;
if (thr_args != NULL) {
// TODO: check version
@@ -2029,7 +2054,7 @@
}
}
-struct JNIInvokeInterface JniInvokeInterface::invoke_interface_ = {
+struct JNIInvokeInterface gInvokeInterface = {
NULL, // reserved0
NULL, // reserved1
NULL, // reserved2
@@ -2040,4 +2065,11 @@
AttachCurrentThreadAsDaemon
};
+JavaVM* CreateJavaVM(Runtime* runtime) {
+ JavaVMExt* result = new JavaVMExt;
+ result->fns = &gInvokeInterface;
+ result->runtime = runtime;
+ return reinterpret_cast<JavaVM*>(result);
+}
+
} // namespace art
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 39ce2cd..3ff12d8 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -10,12 +10,22 @@
namespace art {
+class Runtime;
class Thread;
+JavaVM* CreateJavaVM(Runtime* runtime);
JNIEnv* CreateJNIEnv();
+struct JavaVMExt {
+ // Must be first to correspond with JNIEnv.
+ const struct JNIInvokeInterface* fns;
+
+ Runtime* runtime;
+};
+
struct JNIEnvExt {
- const struct JNINativeInterface* fns; // Must be first.
+ // Must be first to correspond with JavaVM.
+ const struct JNINativeInterface* fns;
Thread* self;
@@ -28,23 +38,6 @@
void (*MonitorExitHelper)(JNIEnv*, jobject);
};
-class JniInvokeInterface {
- public:
- static struct JNIInvokeInterface* GetInterface() {
- return &invoke_interface_;
- }
- private:
- static jint DestroyJavaVM(JavaVM* vm);
- static jint AttachCurrentThread(JavaVM* vm, JNIEnv** penv, void* thr_args);
- static jint DetachCurrentThread(JavaVM* vm);
- static jint GetEnv(JavaVM* vm, void** penv, int version);
- static jint AttachCurrentThreadAsDaemon(JavaVM* vm,
- JNIEnv** penv,
- void* thr_args);
- static struct JNIInvokeInterface invoke_interface_;
- DISALLOW_IMPLICIT_CONSTRUCTORS(JniInvokeInterface);
-};
-
} // namespace art
#endif // ART_SRC_JNI_INTERNAL_H_
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index ce640e2..df9844f 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -60,6 +60,10 @@
TEST_F(JniInternalTest, NewPrimitiveArray) {
// TODO: death tests for negative array sizes.
+ // TODO: check returned array size.
+
+ // TODO: check returned array class.
+
CHECK(env_->NewBooleanArray(0) != NULL);
CHECK(env_->NewByteArray(0) != NULL);
CHECK(env_->NewCharArray(0) != NULL);
@@ -79,6 +83,22 @@
CHECK(env_->NewShortArray(1) != NULL);
}
+TEST_F(JniInternalTest, NewObjectArray) {
+ // TODO: death tests for negative array sizes.
+
+ // TODO: check returned array size.
+
+ // TODO: check returned array class.
+
+ // TODO: check non-NULL initial elements.
+
+ jclass c = env_->FindClass("[Ljava.lang.String;");
+
+ CHECK(env_->NewObjectArray(0, c, NULL) != NULL);
+
+ CHECK(env_->NewObjectArray(1, c, NULL) != NULL);
+}
+
bool EnsureInvokeStub(Method* method);
byte* AllocateCode(void* code, size_t length) {
diff --git a/src/main.cc b/src/main.cc
index b0eb659..091cda0 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -93,7 +93,7 @@
return true;
}
-static bool InvokeMain(JavaVM* vm, JNIEnv* env, int argc, char** argv) {
+static bool InvokeMain(JNIEnv* env, int argc, char** argv) {
// We want to call main() with a String array with our arguments in
// it. Create an array and populate it. Note argv[0] is not
// included.
@@ -197,7 +197,7 @@
DCHECK_LE(curr_opt, option_count);
JavaVMInitArgs init_args;
- init_args.version = JNI_VERSION_1_4;
+ init_args.version = JNI_VERSION_1_6;
init_args.options = options.get();
init_args.nOptions = curr_opt;
init_args.ignoreUnrecognized = JNI_FALSE;
@@ -212,18 +212,17 @@
return EXIT_FAILURE;
}
- bool success = InvokeMain(vm, env, argc - arg_idx, &argv[arg_idx]);
+ bool success = InvokeMain(env, argc - arg_idx, &argv[arg_idx]);
- if (vm != NULL && vm->DetachCurrentThread() != JNI_OK) {
+ if (vm->DetachCurrentThread() != JNI_OK) {
fprintf(stderr, "Warning: unable to detach main thread\n");
success = false;
}
- if (vm != NULL && vm->DestroyJavaVM() != 0) {
+ if (vm->DestroyJavaVM() != 0) {
fprintf(stderr, "Warning: VM did not shut down cleanly\n");
success = false;
}
- int retval = success ? EXIT_SUCCESS : EXIT_FAILURE;
- return retval;
+ return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/src/runtime.cc b/src/runtime.cc
index c9a2794..05a89b2 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -146,6 +146,7 @@
Thread* current_thread = Thread::Attach();
thread_list_->Register(current_thread);
class_linker_ = ClassLinker::Create(boot_class_path);
+ java_vm_.reset(CreateJavaVM(this));
return true;
}
diff --git a/src/runtime.h b/src/runtime.h
index f04aefe..56a8970 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -9,6 +9,7 @@
#include "jni.h"
#include "globals.h"
#include "macros.h"
+#include "scoped_ptr.h"
#include "stringpiece.h"
namespace art {
@@ -53,6 +54,10 @@
return class_linker_;
}
+ JavaVM* GetJavaVM() {
+ return java_vm_.get();
+ }
+
void SetVfprintfHook(void* hook);
void SetExitHook(void* hook);
@@ -71,6 +76,8 @@
ClassLinker* class_linker_;
+ scoped_ptr<JavaVM> java_vm_;
+
// A pointer to the active runtime or NULL.
static Runtime* instance_;
diff --git a/tools/art b/tools/art
index ab252eb..8033c51 100755
--- a/tools/art
+++ b/tools/art
@@ -18,9 +18,11 @@
ANDROID_DATA=/tmp/android-data \
ANDROID_ROOT=$ANDROID_BUILD_TOP/out/host/linux-x86 \
LD_LIBRARY_PATH=$ANDROID_BUILD_TOP/out/host/linux-x86/lib \
-$ANDROID_BUILD_TOP/out/host/linux-x86/bin/aexecd \
+$ANDROID_BUILD_TOP/out/host/linux-x86/bin/aexec \
-Xbootclasspath\
:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/core-hostdex.jar\
+:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/core-junit-hostdex.jar\
+:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/core-tests-hostdex.jar\
:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/bouncycastle-hostdex.jar\
:$ANDROID_BUILD_TOP/out/host/linux-x86/framework/apache-xml-hostdex.jar \
$*