Merge "Get rid of some C artifacts as noted in the initial review." into dalvik-dev
diff --git a/src/assembler_arm.cc b/src/assembler_arm.cc
index c13db39..2022ee9 100644
--- a/src/assembler_arm.cc
+++ b/src/assembler_arm.cc
@@ -1499,6 +1499,13 @@
base.AsCoreRegister(), offs.Int32Value());
}
+void Assembler::LoadRawPtr(ManagedRegister dest, ManagedRegister base,
+ Offset offs) {
+ CHECK(dest.IsCoreRegister() && dest.IsCoreRegister());
+ LoadFromOffset(kLoadWord, dest.AsCoreRegister(),
+ base.AsCoreRegister(), offs.Int32Value());
+}
+
void Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
ManagedRegister scratch) {
CHECK(scratch.IsCoreRegister());
diff --git a/src/assembler_arm.h b/src/assembler_arm.h
index 99ff9fe..bad3023 100644
--- a/src/assembler_arm.h
+++ b/src/assembler_arm.h
@@ -431,6 +431,7 @@
void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch);
void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs);
+ void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs);
void StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
ManagedRegister scratch);
diff --git a/src/assembler_x86.cc b/src/assembler_x86.cc
index b6183a9..693f1b4 100644
--- a/src/assembler_x86.cc
+++ b/src/assembler_x86.cc
@@ -1487,6 +1487,12 @@
movl(dest.AsCpuRegister(), Address(base.AsCpuRegister(), offs));
}
+void Assembler::LoadRawPtr(ManagedRegister dest, ManagedRegister base,
+ Offset offs) {
+ CHECK(dest.IsCpuRegister() && dest.IsCpuRegister());
+ movl(dest.AsCpuRegister(), Address(base.AsCpuRegister(), offs));
+}
+
void Assembler::LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset offs) {
CHECK(dest.IsCpuRegister());
fs()->movl(dest.AsCpuRegister(), Address::Absolute(offs));
diff --git a/src/assembler_x86.h b/src/assembler_x86.h
index 2c7f2d2..afccc4d 100644
--- a/src/assembler_x86.h
+++ b/src/assembler_x86.h
@@ -125,6 +125,10 @@
Init(base, disp);
}
+ Address(Register base, Offset disp) {
+ Init(base, disp.Int32Value());
+ }
+
Address(Register base, FrameOffset disp) {
CHECK_EQ(base, ESP);
Init(ESP, disp.Int32Value());
@@ -442,6 +446,8 @@
void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs);
+ void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs);
+
void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset offs);
void CopyRawPtrFromThread(FrameOffset fr_offs, ThreadOffset thr_offs,
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index dd7d5e5..f3d13c8 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -25,6 +25,9 @@
JniCallingConvention jni_conv(native_method);
ManagedRuntimeCallingConvention mr_conv(native_method);
const bool is_static = native_method->IsStatic();
+ static Offset functions(OFFSETOF_MEMBER(JNIEnvExt, fns));
+ static Offset monitor_enter(OFFSETOF_MEMBER(JNINativeInterface, MonitorEnter));
+ static Offset monitor_exit(OFFSETOF_MEMBER(JNINativeInterface, MonitorExit));
// 1. Build the frame
const size_t frame_size(jni_conv.FrameSize());
@@ -136,9 +139,10 @@
FrameOffset out_off = jni_conv.CurrentParamStackOffset();
jni_asm->StoreRawPtr(out_off, jni_env_register);
}
- // Call JNIEnvExt::MonitorEnterHelper(JNIEnv*, object)
- static Offset monitor_enter(OFFSETOF_MEMBER(JNIEnvExt, MonitorEnterHelper));
- jni_asm->Call(jni_env_register, monitor_enter,
+ // Call JNIEnv->MonitorEnter(object)
+ ManagedRegister jni_fns_register = jni_conv.InterproceduralScratchRegister();
+ jni_asm->LoadRawPtr(jni_fns_register, jni_env_register, functions);
+ jni_asm->Call(jni_fns_register, monitor_enter,
jni_conv.InterproceduralScratchRegister());
jni_asm->FillFromSpillArea(spill_regs, out_arg_size);
jni_asm->ExceptionPoll(jni_conv.InterproceduralScratchRegister());
@@ -238,9 +242,10 @@
FrameOffset out_off = jni_conv.CurrentParamStackOffset();
jni_asm->StoreRawPtr(out_off, jni_env_register);
}
- // Call JNIEnvExt::MonitorExitHelper(JNIEnv*, object)
- static Offset monitor_exit(OFFSETOF_MEMBER(JNIEnvExt, MonitorExitHelper));
- jni_asm->Call(jni_env_register, monitor_exit,
+ // Call JNIEnv->MonitorExit(object)
+ ManagedRegister jni_fns_register = jni_conv.InterproceduralScratchRegister();
+ jni_asm->LoadRawPtr(jni_fns_register, jni_env_register, functions);
+ jni_asm->Call(jni_fns_register, monitor_exit,
jni_conv.InterproceduralScratchRegister());
// Reload return value
jni_asm->Load(jni_conv.ReturnRegister(), return_save_location,
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index eda3e9b..d6cfcb9 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -89,7 +89,7 @@
size_t num_bytes = method->NumArgArrayBytes();
scoped_array<byte> arg_array(new byte[num_bytes]);
const StringPiece& shorty = method->GetShorty();
- for (int i = 1, offset = 0; i < shorty.size() - 1; ++i) {
+ for (int i = 1, offset = 0; i < shorty.size(); ++i) {
switch (shorty[i]) {
case 'Z':
case 'B':
@@ -127,7 +127,7 @@
size_t num_bytes = method->NumArgArrayBytes();
scoped_array<byte> arg_array(new byte[num_bytes]);
const StringPiece& shorty = method->GetShorty();
- for (int i = 1, offset = 0; i < shorty.size() - 1; ++i) {
+ for (int i = 1, offset = 0; i < shorty.size(); ++i) {
switch (shorty[i]) {
case 'Z':
case 'B':
@@ -284,8 +284,23 @@
jthrowable ExceptionOccurred(JNIEnv* env) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ Object* exception = ts.Self()->GetException();
+ if (exception == NULL) {
+ return NULL;
+ } else {
+ // TODO: if adding a local reference failing causes the VM to abort
+ // then the following check will never occur.
+ jthrowable localException = AddLocalReference<jthrowable>(ts, exception);
+ if (localException == NULL) {
+ // We were unable to add a new local reference, and threw a new
+ // exception. We can't return "exception", because it's not a
+ // local reference. So we have to return NULL, indicating that
+ // there was no exception, even though it's pretty much raining
+ // exceptions in here.
+ LOG(WARNING) << "JNI WARNING: addLocal/exception combo";
+ }
+ return localException;
+ }
}
void ExceptionDescribe(JNIEnv* env) {
@@ -381,10 +396,19 @@
return NULL;
}
-jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) {
+jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass clazz) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
+ CHECK_NE(static_cast<jclass>(NULL), clazz);
+ if (jobj == NULL) {
+ // 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);
+ return Object::InstanceOf(obj, klass) ? JNI_TRUE : JNI_FALSE;
+ }
}
jmethodID GetMethodID(JNIEnv* env,
@@ -401,17 +425,31 @@
// private methods and constructors.
method = klass->FindDeclaredDirectMethod(name, sig);
}
- if (method == NULL || method->IsStatic()) {
- LG << "NoSuchMethodError"; // TODO: throw NoSuchMethodError
+ if (method == NULL) {
+ Thread* self = Thread::Current();
+ std::string class_name = klass->GetDescriptor().ToString();
+ // TODO: pretty print method names through a single routine
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "no method \"%s.%s%s\"",
+ class_name.c_str(), name, sig);
return NULL;
- }
- // TODO: create a JNI weak global reference for method
- bool success = EnsureInvokeStub(method);
- if (!success) {
- // TODO: throw OutOfMemoryException
+ } else if (method->IsStatic()) {
+ Thread* self = Thread::Current();
+ std::string class_name = klass->GetDescriptor().ToString();
+ // TODO: pretty print method names through a single routine
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "method \"%s.%s%s\" is static",
+ class_name.c_str(), name, sig);
return NULL;
+ } else {
+ // TODO: create a JNI weak global reference for method
+ bool success = EnsureInvokeStub(method);
+ if (!success) {
+ // TODO: throw OutOfMemoryException
+ return NULL;
+ }
+ return reinterpret_cast<jmethodID>(method);
}
- return reinterpret_cast<jmethodID>(method);
}
jobject CallObjectMethod(JNIEnv* env, jobject obj, jmethodID methodID, ...) {
@@ -933,17 +971,33 @@
// TODO: initialize the class
}
Method* method = klass->FindDirectMethod(name, sig);
- if (method == NULL || !method->IsStatic()) {
- LG << "NoSuchMethodError"; // TODO: throw NoSuchMethodError
+ if (method == NULL) {
+ Thread* self = Thread::Current();
+ std::string class_name = klass->GetDescriptor().ToString();
+ // TODO: pretty print method names through a single routine
+ // TODO: may want to FindVirtualMethod to give more informative error
+ // message here
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "no method \"%s.%s%s\"",
+ class_name.c_str(), name, sig);
return NULL;
- }
- // TODO: create a JNI weak global reference for method
- bool success = EnsureInvokeStub(method);
- if (!success) {
- // TODO: throw OutOfMemoryException
+ } else if (!method->IsStatic()) {
+ Thread* self = Thread::Current();
+ std::string class_name = klass->GetDescriptor().ToString();
+ // TODO: pretty print method names through a single routine
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "method \"%s.%s%s\" is not static",
+ class_name.c_str(), name, sig);
return NULL;
+ } else {
+ // TODO: create a JNI weak global reference for method
+ bool success = EnsureInvokeStub(method);
+ if (!success) {
+ // TODO: throw OutOfMemoryException
+ return NULL;
+ }
+ return reinterpret_cast<jmethodID>(method);
}
- return reinterpret_cast<jmethodID>(method);
}
jobject CallStaticObjectMethod(JNIEnv* env,
@@ -1597,8 +1651,35 @@
jint RegisterNatives(JNIEnv* env,
jclass clazz, const JNINativeMethod* methods, jint nMethods) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ // TODO: retrieve handle value for class
+ Class* klass = reinterpret_cast<Class*>(clazz);
+ for(int i = 0; i < nMethods; i++) {
+ const char* name = methods[i].name;
+ const char* sig = methods[i].signature;
+ Method* method = klass->FindDirectMethod(name, sig);
+ if (method == NULL) {
+ method = klass->FindVirtualMethod(name, sig);
+ }
+ if (method == NULL) {
+ Thread* self = Thread::Current();
+ std::string class_name = klass->GetDescriptor().ToString();
+ // TODO: pretty print method names through a single routine
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "no method \"%s.%s%s\"",
+ class_name.c_str(), name, sig);
+ return JNI_ERR;
+ } else if (!method->IsNative()) {
+ Thread* self = Thread::Current();
+ std::string class_name = klass->GetDescriptor().ToString();
+ // TODO: pretty print method names through a single routine
+ self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
+ "method \"%s.%s%s\" is not native",
+ class_name.c_str(), name, sig);
+ return JNI_ERR;
+ }
+ method->RegisterNative(methods[i].fnPtr);
+ }
+ return JNI_OK;
}
jint UnregisterNatives(JNIEnv* env, jclass clazz) {
@@ -1943,26 +2024,15 @@
GetObjectRefType,
};
-void MonitorEnterHelper(JNIEnv* env, jobject obj) {
- CHECK_EQ(Thread::Current()->GetJniEnv(), env);
- MonitorEnter(env, obj); // Ignore the result.
-}
+static const size_t kMonitorTableInitialSize = 32; // Arbitrary.
+static const size_t kMonitorTableMaxSize = 4096; // Arbitrary sanity check.
-void MonitorExitHelper(JNIEnv* env, jobject obj) {
- CHECK_EQ(Thread::Current()->GetJniEnv(), env);
- MonitorExit(env, obj); // Ignore the result.
-}
-
-JNIEnv* CreateJNIEnv() {
- Thread* self = Thread::Current();
- CHECK(self != NULL);
- JNIEnvExt* result = new JNIEnvExt;
- result->fns = &gNativeInterface;
- result->self = self;
- result->critical = false;
- result->MonitorEnterHelper = &MonitorEnterHelper;
- result->MonitorExitHelper = &MonitorExitHelper;
- return reinterpret_cast<JNIEnv*>(result);
+JNIEnvExt::JNIEnvExt(Thread* self, bool check_jni)
+ : fns(&gNativeInterface),
+ self(self),
+ check_jni(check_jni),
+ critical(false),
+ monitor_table("monitor table", kMonitorTableInitialSize, kMonitorTableMaxSize) {
}
// JNI Invocation interface.
@@ -2094,11 +2164,14 @@
AttachCurrentThreadAsDaemon
};
-JavaVM* CreateJavaVM(Runtime* runtime) {
- JavaVMExt* result = new JavaVMExt;
- result->fns = &gInvokeInterface;
- result->runtime = runtime;
- return reinterpret_cast<JavaVM*>(result);
+static const size_t kPinTableInitialSize = 16;
+static const size_t kPinTableMaxSize = 1024;
+
+JavaVMExt::JavaVMExt(Runtime* runtime, bool check_jni)
+ : fns(&gInvokeInterface),
+ runtime(runtime),
+ check_jni(check_jni),
+ pin_table("pin table", kPinTableInitialSize, kPinTableMaxSize) {
}
} // namespace art
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 3ff12d8..9cf8d57 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -7,35 +7,42 @@
#include "assembler.h"
#include "macros.h"
+#include "reference_table.h"
namespace art {
class Runtime;
class Thread;
-JavaVM* CreateJavaVM(Runtime* runtime);
-JNIEnv* CreateJNIEnv();
-
struct JavaVMExt {
+ JavaVMExt(Runtime* runtime, bool check_jni);
+
// Must be first to correspond with JNIEnv.
const struct JNIInvokeInterface* fns;
Runtime* runtime;
+
+ bool check_jni;
+
+ // Used to hold references to pinned primitive arrays.
+ ReferenceTable pin_table;
};
struct JNIEnvExt {
+ JNIEnvExt(Thread* self, bool check_jni);
+
// Must be first to correspond with JavaVM.
const struct JNINativeInterface* fns;
Thread* self;
+ bool check_jni;
+
// Are we in a "critical" JNI call?
bool critical;
- // Used to help call synchronized native methods.
- // TODO: make jni_compiler.cc do the indirection itself.
- void (*MonitorEnterHelper)(JNIEnv*, jobject);
- void (*MonitorExitHelper)(JNIEnv*, jobject);
+ // Entered JNI monitors, for bulk exit on thread detach.
+ ReferenceTable monitor_table;
};
} // namespace art
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 569dfda..04b3225 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -57,6 +57,117 @@
EXPECT_CLASS_NOT_FOUND("K");
}
+TEST_F(JniInternalTest, GetMethodID) {
+ jclass jlobject = env_->FindClass("java/lang/Object");
+ jclass jlstring = env_->FindClass("java/lang/String");
+ jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
+
+ // Sanity check that no exceptions are pending
+ EXPECT_FALSE(env_->ExceptionCheck());
+
+ // Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
+ // a pending exception
+ jmethodID method = env_->GetMethodID(jlobject, "foo", "()V");
+ EXPECT_EQ(static_cast<jmethodID>(NULL), method);
+ EXPECT_TRUE(env_->ExceptionCheck());
+ jthrowable exception = env_->ExceptionOccurred();
+ EXPECT_NE(static_cast<jthrowable>(NULL), exception);
+ EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
+ env_->ExceptionClear();
+
+ // Check that java.lang.Object.equals() does exist
+#if defined(__arm__)
+ method = env_->GetMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
+ EXPECT_NE(static_cast<jmethodID>(NULL), method);
+ EXPECT_FALSE(env_->ExceptionCheck());
+#endif
+
+ // Check that GetMethodID for java.lang.String.valueOf(int) fails as the
+ // method is static
+ method = env_->GetMethodID(jlstring, "valueOf", "(I)Ljava/lang/String;");
+ EXPECT_EQ(static_cast<jmethodID>(NULL), method);
+ EXPECT_TRUE(env_->ExceptionCheck());
+ exception = env_->ExceptionOccurred();
+ EXPECT_NE(static_cast<jthrowable>(NULL), exception);
+ EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
+ env_->ExceptionClear();
+}
+
+TEST_F(JniInternalTest, GetStaticMethodID) {
+ jclass jlobject = env_->FindClass("java/lang/Object");
+ jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
+
+ // Sanity check that no exceptions are pending
+ EXPECT_FALSE(env_->ExceptionCheck());
+
+ // Check that java.lang.Object.foo() doesn't exist and NoSuchMethodError is
+ // a pending exception
+ jmethodID method = env_->GetStaticMethodID(jlobject, "foo", "()V");
+ EXPECT_EQ(static_cast<jmethodID>(NULL), method);
+ EXPECT_TRUE(env_->ExceptionCheck());
+ jthrowable exception = env_->ExceptionOccurred();
+ EXPECT_NE(static_cast<jthrowable>(NULL), exception);
+ EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
+ env_->ExceptionClear();
+
+ // Check that GetStaticMethodID for java.lang.Object.equals(Object) fails as
+ // the method is not static
+ method = env_->GetStaticMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
+ EXPECT_EQ(static_cast<jmethodID>(NULL), method);
+ EXPECT_TRUE(env_->ExceptionCheck());
+ exception = env_->ExceptionOccurred();
+ EXPECT_NE(static_cast<jthrowable>(NULL), exception);
+ EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
+ env_->ExceptionClear();
+
+ // Check that java.lang.String.valueOf(int) does exist
+#if defined(__arm__)
+ jclass jlstring = env_->FindClass("java/lang/String");
+ method = env_->GetStaticMethodID(jlstring, "valueOf",
+ "(I)Ljava/lang/String;");
+ EXPECT_NE(static_cast<jmethodID>(NULL), method);
+ EXPECT_FALSE(env_->ExceptionCheck());
+#endif
+}
+
+TEST_F(JniInternalTest, RegisterNatives) {
+ jclass jlobject = env_->FindClass("java/lang/Object");
+ jclass jlnsme = env_->FindClass("java/lang/NoSuchMethodError");
+
+ // Sanity check that no exceptions are pending
+ EXPECT_FALSE(env_->ExceptionCheck());
+
+ // Check that registering to a non-existent java.lang.Object.foo() causes a
+ // NoSuchMethodError
+ {
+ JNINativeMethod methods[] = {{"foo", "()V", NULL}};
+ env_->RegisterNatives(jlobject, methods, 1);
+ }
+ EXPECT_TRUE(env_->ExceptionCheck());
+ jthrowable exception = env_->ExceptionOccurred();
+ EXPECT_NE(static_cast<jthrowable>(NULL), exception);
+ EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
+ env_->ExceptionClear();
+
+ // Check that registering non-native methods causes a NoSuchMethodError
+ {
+ JNINativeMethod methods[] = {{"equals", "(Ljava/lang/Object;)Z", NULL}};
+ env_->RegisterNatives(jlobject, methods, 1);
+ }
+ EXPECT_TRUE(env_->ExceptionCheck());
+ exception = env_->ExceptionOccurred();
+ EXPECT_NE(static_cast<jthrowable>(NULL), exception);
+ EXPECT_TRUE(env_->IsInstanceOf(exception, jlnsme));
+ env_->ExceptionClear();
+
+ // Check that registering native methods is successful
+ {
+ JNINativeMethod methods[] = {{"hashCode", "()I", NULL}};
+ env_->RegisterNatives(jlobject, methods, 1);
+ }
+ EXPECT_FALSE(env_->ExceptionCheck());
+}
+
TEST_F(JniInternalTest, NewPrimitiveArray) {
// TODO: death tests for negative array sizes.
diff --git a/src/runtime.cc b/src/runtime.cc
index 2ad3589..2476837 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -180,6 +180,13 @@
scoped_ptr<ParsedOptions> parsed(new ParsedOptions());
const char* boot_class_path = getenv("BOOTCLASSPATH");
parsed->boot_image_ = NULL;
+#ifdef NDEBUG
+ // CheckJNI is off by default for regular builds...
+ parsed->check_jni_ = false;
+#else
+ // ...but on by default in debug builds.
+ parsed->check_jni_ = true;
+#endif
parsed->heap_initial_size_ = Heap::kInitialSize;
parsed->heap_maximum_size_ = Heap::kMaximumSize;
parsed->hook_vfprintf_ = vfprintf;
@@ -194,6 +201,8 @@
parsed->boot_class_path_ = *reinterpret_cast<const std::vector<DexFile*>*>(options[i].second);
} else if (option.starts_with("-Xbootimage:")) {
parsed->boot_image_ = option.substr(strlen("-Xbootimage:")).data();
+ } else if (option.starts_with("-Xcheck:jni")) {
+ parsed->check_jni_ = true;
} else if (option.starts_with("-Xms")) {
parsed->heap_initial_size_ = ParseMemoryOption(option.substr(strlen("-Xms")).data(), 1024);
} else if (option.starts_with("-Xmx")) {
@@ -262,23 +271,24 @@
Heap::Init(parsed_options->heap_initial_size_,
parsed_options->heap_maximum_size_);
+ java_vm_.reset(reinterpret_cast<JavaVM*>(new JavaVMExt(this, parsed_options->check_jni_)));
+
Thread::Init();
- Thread* current_thread = Thread::Attach();
+ Thread* current_thread = Thread::Attach(this);
thread_list_->Register(current_thread);
class_linker_ = ClassLinker::Create(parsed_options->boot_class_path_);
- java_vm_.reset(CreateJavaVM(this));
return true;
}
bool Runtime::AttachCurrentThread(const char* name, JNIEnv** penv) {
- return Thread::Attach() != NULL;
+ return Thread::Attach(instance_) != NULL;
}
bool Runtime::AttachCurrentThreadAsDaemon(const char* name, JNIEnv** penv) {
// TODO: do something different for daemon threads.
- return Thread::Attach() != NULL;
+ return Thread::Attach(instance_) != NULL;
}
bool Runtime::DetachCurrentThread() {
diff --git a/src/runtime.h b/src/runtime.h
index da46ee6..828e677 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -33,6 +33,7 @@
std::vector<DexFile*> boot_class_path_;
const char* boot_image_;
+ bool check_jni_;
size_t heap_initial_size_;
size_t heap_maximum_size_;
jint (*hook_vfprintf_)(FILE* stream, const char* format, va_list ap);
@@ -76,7 +77,7 @@
return class_linker_;
}
- JavaVM* GetJavaVM() {
+ JavaVM* GetJavaVM() const {
return java_vm_.get();
}
diff --git a/src/thread.cc b/src/thread.cc
index 609ae41..baa659c 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -85,7 +85,7 @@
return new_thread;
}
-Thread* Thread::Attach() {
+Thread* Thread::Attach(const Runtime* runtime) {
Thread* thread = new Thread;
thread->InitCpu();
thread->stack_limit_ = reinterpret_cast<byte*>(-1); // TODO: getrlimit
@@ -103,7 +103,10 @@
PLOG(FATAL) << "pthread_setspecific failed";
}
- thread->jni_env_ = CreateJNIEnv();
+ JavaVMExt* vm = reinterpret_cast<JavaVMExt*>(runtime->GetJavaVM());
+ CHECK(vm != NULL);
+ bool check_jni = vm->check_jni;
+ thread->jni_env_ = reinterpret_cast<JNIEnv*>(new JNIEnvExt(thread, check_jni));
return thread;
}
diff --git a/src/thread.h b/src/thread.h
index 8bde370..de5893e 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -118,7 +118,7 @@
static Thread* Create(size_t stack_size);
// Creates a new thread from the calling thread.
- static Thread* Attach();
+ static Thread* Attach(const Runtime* runtime);
static Thread* Current() {
void* thread = pthread_getspecific(Thread::pthread_key_self_);