Switch to indirect references rather than direct pointers.
This also required a bit of fiddling to break cyclic dependencies,
now "jni_internal.h" needs Mutex from "thread.h".
Change-Id: I1d6fb2d801c190f72255f5e447a0a8a65cc3e673
diff --git a/src/indirect_reference_table.cc b/src/indirect_reference_table.cc
index 20f39b6..b30ce53 100644
--- a/src/indirect_reference_table.cc
+++ b/src/indirect_reference_table.cc
@@ -269,7 +269,7 @@
segmentState.parts.topIndex = topIndex;
} else {
segmentState.parts.topIndex = topIndex-1;
- LOG(INFO) << "+++ ate last entry " << topIndex-1;
+ //LOG(INFO) << "+++ ate last entry " << topIndex-1;
}
} else {
/*
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 94e67a4..599b0fe 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -151,10 +151,6 @@
// TODO: automate some of these checks!
- if (verbose_jni) {
- LOG(INFO) << "[calling dlopen(\"" << path << "\")...]";
- }
-
// This can execute slowly for a large library on a busy system, so we
// want to switch from RUNNING to VMWAIT while it executes. This allows
// the GC to ignore us.
@@ -165,7 +161,7 @@
self->SetState(old_state);
if (verbose_jni) {
- LOG(INFO) << "[dlopen(\"" << path << "\") returned " << handle << "]";
+ LOG(INFO) << "[Call to dlopen(\"" << path << "\") returned " << handle << "]";
}
if (handle == NULL) {
@@ -235,7 +231,8 @@
result = false;
} else {
if (verbose_jni) {
- LOG(INFO) << "[Returned from JNI_OnLoad in \"" << path << "\"]";
+ LOG(INFO) << "[Returned " << (result ? "successfully" : "failure")
+ << " from JNI_OnLoad in \"" << path << "\"]";
}
}
}
@@ -258,7 +255,8 @@
// that are using a JNIEnv on the wrong thread.
class ScopedJniThreadState {
public:
- explicit ScopedJniThreadState(JNIEnv* env) {
+ explicit ScopedJniThreadState(JNIEnv* env)
+ : env_(reinterpret_cast<JNIEnvExt*>(env)) {
self_ = ThreadForEnv(env);
self_->SetState(Thread::kRunnable);
}
@@ -267,6 +265,10 @@
self_->SetState(Thread::kNative);
}
+ JNIEnvExt* Env() {
+ return env_;
+ }
+
Thread* Self() {
return self_;
}
@@ -285,14 +287,114 @@
return self;
}
+ JNIEnvExt* env_;
Thread* self_;
DISALLOW_COPY_AND_ASSIGN(ScopedJniThreadState);
};
+/*
+ * Add a local reference for an object to the current stack frame. When
+ * the native function returns, the reference will be discarded.
+ *
+ * We need to allow the same reference to be added multiple times.
+ *
+ * This will be called on otherwise unreferenced objects. We cannot do
+ * GC allocations here, and it's best if we don't grab a mutex.
+ *
+ * Returns the local reference (currently just the same pointer that was
+ * passed in), or NULL on failure.
+ */
template<typename T>
T AddLocalReference(ScopedJniThreadState& ts, Object* obj) {
- UNIMPLEMENTED(WARNING);
- return reinterpret_cast<T>(obj);
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ IndirectReferenceTable& locals = ts.Env()->locals;
+
+ uint32_t cookie = IRT_FIRST_SEGMENT; // TODO
+ IndirectRef ref = locals.Add(cookie, obj);
+ if (ref == NULL) {
+ // TODO: just change Add's DCHECK to CHECK and lose this?
+ locals.Dump();
+ LOG(FATAL) << "Failed adding to JNI local reference table "
+ << "(has " << locals.Capacity() << " entries)";
+ // TODO: dvmDumpThread(dvmThreadSelf(), false);
+ }
+
+#if 0 // TODO: fix this to understand PushLocalFrame, so we can turn it on.
+ if (ts.Env()->check_jni) {
+ size_t entry_count = locals.Capacity();
+ if (entry_count > 16) {
+ std::string class_name(PrettyDescriptor(obj->GetClass()->GetDescriptor()));
+ LOG(WARNING) << "Warning: more than 16 JNI local references: "
+ << entry_count << " (most recent was a " << class_name << ")";
+ locals.Dump();
+ // TODO: dvmDumpThread(dvmThreadSelf(), false);
+ // dvmAbort();
+ }
+ }
+#endif
+
+ if (false /*gDvmJni.workAroundAppJniBugs*/) { // TODO
+ // Hand out direct pointers to support broken old apps.
+ return reinterpret_cast<T>(obj);
+ }
+
+ return reinterpret_cast<T>(ref);
+}
+
+template<typename T>
+T Decode(ScopedJniThreadState& ts, jobject obj) {
+ if (obj == NULL) {
+ return NULL;
+ }
+
+ IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
+ IndirectRefKind kind = GetIndirectRefKind(ref);
+ Object* result;
+ switch (kind) {
+ case kLocal:
+ {
+ IndirectReferenceTable& locals = ts.Env()->locals;
+ result = locals.Get(ref);
+ break;
+ }
+ case kGlobal:
+ {
+ JavaVMExt* vm = Runtime::Current()->GetJavaVM();
+ IndirectReferenceTable& globals = vm->globals;
+ MutexLock mu(&vm->globals_lock);
+ result = globals.Get(ref);
+ break;
+ }
+ case kWeakGlobal:
+ {
+ JavaVMExt* vm = Runtime::Current()->GetJavaVM();
+ IndirectReferenceTable& weak_globals = vm->weak_globals;
+ MutexLock mu(&vm->weak_globals_lock);
+ result = weak_globals.Get(ref);
+ if (result == kClearedJniWeakGlobal) {
+ // This is a special case where it's okay to return NULL.
+ return NULL;
+ }
+ break;
+ }
+ case kInvalid:
+ default:
+ if (false /*gDvmJni.workAroundAppJniBugs*/) { // TODO
+ // Assume an invalid local reference is actually a direct pointer.
+ return reinterpret_cast<T>(obj);
+ }
+ LOG(FATAL) << "Invalid indirect reference " << obj;
+ return reinterpret_cast<T>(kInvalidIndirectRefObject);
+ }
+
+ if (result == NULL) {
+ LOG(FATAL) << "JNI ERROR (app bug): use of deleted " << kind << ": "
+ << obj;
+ }
+ return reinterpret_cast<T>(result);
}
void CreateInvokeStub(Assembler* assembler, Method* method);
@@ -318,7 +420,7 @@
return true;
}
-byte* CreateArgArray(Method* method, va_list ap) {
+byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, va_list ap) {
size_t num_bytes = method->NumArgArrayBytes();
scoped_array<byte> arg_array(new byte[num_bytes]);
const StringPiece& shorty = method->GetShorty();
@@ -337,8 +439,7 @@
offset += 4;
break;
case 'L': {
- // TODO: DecodeReference
- Object* obj = reinterpret_cast<Object*>(va_arg(ap, jobject));
+ Object* obj = Decode<Object*>(ts, va_arg(ap, jobject));
*reinterpret_cast<Object**>(&arg_array[offset]) = obj;
offset += sizeof(Object*);
break;
@@ -356,7 +457,7 @@
return arg_array.release();
}
-byte* CreateArgArray(Method* method, jvalue* args) {
+byte* CreateArgArray(ScopedJniThreadState& ts, Method* method, jvalue* args) {
size_t num_bytes = method->NumArgArrayBytes();
scoped_array<byte> arg_array(new byte[num_bytes]);
const StringPiece& shorty = method->GetShorty();
@@ -375,8 +476,7 @@
offset += 4;
break;
case 'L': {
- // TODO: DecodeReference
- Object* obj = reinterpret_cast<Object*>(args[i - 1].l);
+ Object* obj = Decode<Object*>(ts, args[i - 1].l);
*reinterpret_cast<Object**>(&arg_array[offset]) = obj;
offset += sizeof(Object*);
break;
@@ -394,8 +494,8 @@
return arg_array.release();
}
-JValue InvokeWithArgArray(Thread* self, Object* obj, jmethodID method_id,
- byte* args) {
+JValue InvokeWithArgArray(ScopedJniThreadState& ts,
+ Object* obj, jmethodID method_id, byte* args) {
// TODO: DecodeReference
Method* method = reinterpret_cast<Method*>(method_id);
// Call the invoke stub associated with the method
@@ -403,22 +503,22 @@
const Method::InvokeStub* stub = method->GetInvokeStub();
CHECK(stub != NULL);
JValue result;
- (*stub)(method, obj, self, args, &result);
+ (*stub)(method, obj, ts.Self(), args, &result);
return result;
}
-JValue InvokeWithJValues(Thread* self, Object* obj, jmethodID method_id,
- jvalue* args) {
+JValue InvokeWithJValues(ScopedJniThreadState& ts,
+ Object* obj, jmethodID method_id, jvalue* args) {
Method* method = reinterpret_cast<Method*>(method_id);
- scoped_array<byte> arg_array(CreateArgArray(method, args));
- return InvokeWithArgArray(self, obj, method_id, arg_array.get());
+ scoped_array<byte> arg_array(CreateArgArray(ts, method, args));
+ return InvokeWithArgArray(ts, obj, method_id, arg_array.get());
}
-JValue InvokeWithVarArgs(Thread* self, Object* obj, jmethodID method_id,
- va_list args) {
+JValue InvokeWithVarArgs(ScopedJniThreadState& ts,
+ Object* obj, jmethodID method_id, va_list args) {
Method* method = reinterpret_cast<Method*>(method_id);
- scoped_array<byte> arg_array(CreateArgArray(method, args));
- return InvokeWithArgArray(self, obj, method_id, arg_array.get());
+ scoped_array<byte> arg_array(CreateArgArray(ts, method, args));
+ return InvokeWithArgArray(ts, obj, method_id, arg_array.get());
}
jint GetVersion(JNIEnv* env) {
@@ -559,7 +659,7 @@
jobject PopLocalFrame(JNIEnv* env, jobject res) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(WARNING) << "ignoring PopLocalFrame";
+ UNIMPLEMENTED(WARNING) << "ignoring PopLocalFrame " << res;
return res;
}
@@ -576,7 +676,23 @@
void DeleteLocalRef(JNIEnv* env, jobject obj) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(WARNING);
+
+ if (obj == NULL) {
+ return;
+ }
+
+ IndirectReferenceTable& locals = ts.Env()->locals;
+
+ uint32_t cookie = IRT_FIRST_SEGMENT; // TODO
+ if (!locals.Remove(cookie, obj)) {
+ // Attempting to delete a local reference that is not in the
+ // topmost local reference frame is a no-op. DeleteLocalRef returns
+ // void and doesn't throw any exceptions, but we should probably
+ // complain about it so the user will notice that things aren't
+ // going quite the way they expect.
+ LOG(WARNING) << "JNI WARNING: DeleteLocalRef(" << obj << ") "
+ << "failed to find entry";
+ }
}
jboolean IsSameObject(JNIEnv* env, jobject obj1, jobject obj2) {
@@ -636,10 +752,8 @@
// NB. JNI is different from regular Java instanceof in this respect
return JNI_TRUE;
} else {
- // TODO: retrieve handle value for object
- Object* obj = reinterpret_cast<Object*>(jobj);
- // TODO: retrieve handle value for class
- Class* klass = reinterpret_cast<Class*>(clazz);
+ Object* obj = Decode<Object*>(ts, jobj);
+ Class* klass = Decode<Class*>(ts, clazz);
return Object::InstanceOf(obj, klass) ? JNI_TRUE : JNI_FALSE;
}
}
@@ -647,8 +761,7 @@
jmethodID GetMethodID(JNIEnv* env,
jclass clazz, const char* name, const char* sig) {
ScopedJniThreadState ts(env);
- // TODO: retrieve handle value for class
- Class* klass = reinterpret_cast<Class*>(clazz);
+ Class* klass = Decode<Class*>(ts, clazz);
if (!klass->IsInitialized()) {
// TODO: initialize the class
}
@@ -1198,8 +1311,7 @@
jmethodID GetStaticMethodID(JNIEnv* env,
jclass clazz, const char* name, const char* sig) {
ScopedJniThreadState ts(env);
- // TODO: DecodeReference
- Class* klass = reinterpret_cast<Class*>(clazz);
+ Class* klass = Decode<Class*>(ts, clazz);
if (!klass->IsInitialized()) {
// TODO: initialize the class
}
@@ -1238,21 +1350,21 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- JValue result = InvokeWithVarArgs(ts.Self(), NULL, methodID, ap);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
return AddLocalReference<jobject>(ts, result.l);
}
jobject CallStaticObjectMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- JValue result = InvokeWithVarArgs(ts.Self(), NULL, methodID, args);
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, args);
return AddLocalReference<jobject>(ts, result.l);
}
jobject CallStaticObjectMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- JValue result = InvokeWithJValues(ts.Self(), NULL, methodID, args);
+ JValue result = InvokeWithJValues(ts, NULL, methodID, args);
return AddLocalReference<jobject>(ts, result.l);
}
@@ -1261,171 +1373,171 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, ap).z;
+ return InvokeWithVarArgs(ts, NULL, methodID, ap).z;
}
jboolean CallStaticBooleanMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, args).z;
+ return InvokeWithVarArgs(ts, NULL, methodID, args).z;
}
jboolean CallStaticBooleanMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts.Self(), NULL, methodID, args).z;
+ return InvokeWithJValues(ts, NULL, methodID, args).z;
}
jbyte CallStaticByteMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, ap).b;
+ return InvokeWithVarArgs(ts, NULL, methodID, ap).b;
}
jbyte CallStaticByteMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, args).b;
+ return InvokeWithVarArgs(ts, NULL, methodID, args).b;
}
jbyte CallStaticByteMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts.Self(), NULL, methodID, args).b;
+ return InvokeWithJValues(ts, NULL, methodID, args).b;
}
jchar CallStaticCharMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, ap).c;
+ return InvokeWithVarArgs(ts, NULL, methodID, ap).c;
}
jchar CallStaticCharMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, args).c;
+ return InvokeWithVarArgs(ts, NULL, methodID, args).c;
}
jchar CallStaticCharMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts.Self(), NULL, methodID, args).c;
+ return InvokeWithJValues(ts, NULL, methodID, args).c;
}
jshort CallStaticShortMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, ap).s;
+ return InvokeWithVarArgs(ts, NULL, methodID, ap).s;
}
jshort CallStaticShortMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, args).s;
+ return InvokeWithVarArgs(ts, NULL, methodID, args).s;
}
jshort CallStaticShortMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts.Self(), NULL, methodID, args).s;
+ return InvokeWithJValues(ts, NULL, methodID, args).s;
}
jint CallStaticIntMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, ap).i;
+ return InvokeWithVarArgs(ts, NULL, methodID, ap).i;
}
jint CallStaticIntMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, args).i;
+ return InvokeWithVarArgs(ts, NULL, methodID, args).i;
}
jint CallStaticIntMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts.Self(), NULL, methodID, args).i;
+ return InvokeWithJValues(ts, NULL, methodID, args).i;
}
jlong CallStaticLongMethod(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, ap).j;
+ return InvokeWithVarArgs(ts, NULL, methodID, ap).j;
}
jlong CallStaticLongMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, args).j;
+ return InvokeWithVarArgs(ts, NULL, methodID, args).j;
}
jlong CallStaticLongMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts.Self(), NULL, methodID, args).j;
+ return InvokeWithJValues(ts, NULL, methodID, args).j;
}
jfloat CallStaticFloatMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, ap).f;
+ return InvokeWithVarArgs(ts, NULL, methodID, ap).f;
}
jfloat CallStaticFloatMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, args).f;
+ return InvokeWithVarArgs(ts, NULL, methodID, args).f;
}
jfloat CallStaticFloatMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts.Self(), NULL, methodID, args).f;
+ return InvokeWithJValues(ts, NULL, methodID, args).f;
}
jdouble CallStaticDoubleMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, ap).d;
+ return InvokeWithVarArgs(ts, NULL, methodID, ap).d;
}
jdouble CallStaticDoubleMethodV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- return InvokeWithVarArgs(ts.Self(), NULL, methodID, args).d;
+ return InvokeWithVarArgs(ts, NULL, methodID, args).d;
}
jdouble CallStaticDoubleMethodA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- return InvokeWithJValues(ts.Self(), NULL, methodID, args).d;
+ return InvokeWithJValues(ts, NULL, methodID, args).d;
}
void CallStaticVoidMethod(JNIEnv* env, jclass cls, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- InvokeWithVarArgs(ts.Self(), NULL, methodID, ap);
+ InvokeWithVarArgs(ts, NULL, methodID, ap);
}
void CallStaticVoidMethodV(JNIEnv* env,
jclass cls, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- InvokeWithVarArgs(ts.Self(), NULL, methodID, args);
+ InvokeWithVarArgs(ts, NULL, methodID, args);
}
void CallStaticVoidMethodA(JNIEnv* env,
jclass cls, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- InvokeWithJValues(ts.Self(), NULL, methodID, args);
+ InvokeWithJValues(ts, NULL, methodID, args);
}
jfieldID GetStaticFieldID(JNIEnv* env,
@@ -1608,9 +1720,8 @@
void SetObjectArrayElement(JNIEnv* env,
jobjectArray java_array, jsize index, jobject java_value) {
ScopedJniThreadState ts(env);
- // TODO: DecodeReference
- ObjectArray<Object>* array = reinterpret_cast<ObjectArray<Object>*>(java_array);
- Object* value = reinterpret_cast<Object*>(java_value);
+ ObjectArray<Object>* array = Decode<ObjectArray<Object>*>(ts, java_array);
+ Object* value = Decode<Object*>(ts, java_value);
array->Set(index, value);
}
@@ -1661,8 +1772,7 @@
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);
+ Class* element_class = Decode<Class*>(ts, element_jclass);
std::string descriptor;
descriptor += "[";
descriptor += element_class->GetDescriptor().ToString();
@@ -1884,8 +1994,7 @@
jint RegisterNatives(JNIEnv* env,
jclass clazz, const JNINativeMethod* methods, jint nMethods) {
ScopedJniThreadState ts(env);
- // TODO: retrieve handle value for class
- Class* klass = reinterpret_cast<Class*>(clazz);
+ Class* klass = Decode<Class*>(ts, clazz);
for(int i = 0; i < nMethods; i++) {
const char* name = methods[i].name;
const char* sig = methods[i].signature;
@@ -2421,7 +2530,9 @@
check_jni(check_jni),
verbose_jni(verbose_jni),
pin_table("pin table", kPinTableInitialSize, kPinTableMaxSize),
+ globals_lock("JNI global reference table"),
globals(kGlobalsInitial, kGlobalsMax, kGlobal),
+ weak_globals_lock("JNI weak global reference table"),
weak_globals(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal) {
}
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 5d89dd8..74366d3 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -9,6 +9,7 @@
#include "indirect_reference_table.h"
#include "macros.h"
#include "reference_table.h"
+#include "thread.h"
#include <map>
#include <string>
@@ -17,7 +18,6 @@
class Runtime;
class SharedLibrary;
-class Thread;
struct JavaVMExt {
JavaVMExt(Runtime* runtime, bool check_jni, bool verbose_jni);
@@ -53,9 +53,11 @@
ReferenceTable pin_table;
// JNI global references.
+ Mutex globals_lock;
IndirectReferenceTable globals;
// JNI weak global references.
+ Mutex weak_globals_lock;
IndirectReferenceTable weak_globals;
std::map<std::string, SharedLibrary*> libraries;
diff --git a/src/runtime.cc b/src/runtime.cc
index 43427df..335396d 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -9,6 +9,7 @@
#include "class_linker.h"
#include "heap.h"
+#include "jni_internal.h"
#include "scoped_ptr.h"
#include "thread.h"
@@ -17,10 +18,11 @@
Runtime* Runtime::instance_ = NULL;
Runtime::~Runtime() {
- // TODO: use a smart pointer instead.
+ // TODO: use smart pointers instead. (we'll need the pimpl idiom.)
delete class_linker_;
Heap::Destroy();
delete thread_list_;
+ delete java_vm_;
// TODO: acquire a static mutex on Runtime to avoid racing.
CHECK(instance_ == NULL || instance_ == this);
instance_ = NULL;
@@ -336,7 +338,7 @@
}
bool verbose_jni = options->verbose_.find("jni") != options->verbose_.end();
- java_vm_.reset(new JavaVMExt(this, options->check_jni_, verbose_jni));
+ java_vm_ = new JavaVMExt(this, options->check_jni_, verbose_jni);
if (!Thread::Init()) {
return false;
diff --git a/src/runtime.h b/src/runtime.h
index e9d373d..9879023 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -3,12 +3,15 @@
#ifndef ART_SRC_RUNTIME_H_
#define ART_SRC_RUNTIME_H_
+#include <stdio.h>
+
#include <string>
#include <utility>
#include <vector>
+#include <jni.h>
+
#include "globals.h"
-#include "jni_internal.h"
#include "macros.h"
#include "scoped_ptr.h"
#include "stringpiece.h"
@@ -19,6 +22,7 @@
class ClassLinker;
class DexFile;
class Heap;
+class JavaVMExt;
class String;
class ThreadList;
@@ -84,7 +88,7 @@
}
JavaVMExt* GetJavaVM() const {
- return java_vm_.get();
+ return java_vm_;
}
private:
@@ -102,7 +106,7 @@
ClassLinker* class_linker_;
- scoped_ptr<JavaVMExt> java_vm_;
+ JavaVMExt* java_vm_;
// Hooks supported by JNI_CreateJavaVM
jint (*vfprintf_)(FILE* stream, const char* format, va_list ap);
diff --git a/src/thread.cc b/src/thread.cc
index 1001b29..eb7a4f7 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -9,6 +9,7 @@
#include <list>
#include "class_linker.h"
+#include "jni_internal.h"
#include "object.h"
#include "runtime.h"
#include "utils.h"
diff --git a/src/thread.h b/src/thread.h
index 4264a1a..71fbd48c 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -7,7 +7,6 @@
#include <list>
#include "globals.h"
-#include "jni_internal.h"
#include "logging.h"
#include "macros.h"
#include "mem_map.h"