summaryrefslogtreecommitdiffstats
path: root/runtime/entrypoints/jni
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2013-08-05 10:56:33 -0700
committerIan Rogers <irogers@google.com>2013-08-07 22:17:00 -0700
commit848871b4d8481229c32e0d048a9856e5a9a17ef9 (patch)
tree4be4602e3becc899f76a29a87618801458fe04b9 /runtime/entrypoints/jni
parent423fb4d70f2ac36bf9f630146b4150771a8e7e76 (diff)
downloadart-848871b4d8481229c32e0d048a9856e5a9a17ef9.zip
art-848871b4d8481229c32e0d048a9856e5a9a17ef9.tar.gz
art-848871b4d8481229c32e0d048a9856e5a9a17ef9.tar.bz2
Entry point clean up.
Create set of entry points needed for image methods to avoid fix-up at load time: - interpreter - bridge to interpreter, bridge to compiled code - jni - dlsym lookup - quick - resolution and bridge to interpreter - portable - resolution and bridge to interpreter Fix JNI work around to use JNI work around argument rewriting code that'd been accidentally disabled. Remove abstact method error stub, use interpreter bridge instead. Consolidate trampoline (previously stub) generation in generic helper. Simplify trampolines to jump directly into assembly code, keeps stack crawlable. Dex: replace use of int with ThreadOffset for values that are thread offsets. Tidy entry point routines between interpreter, jni, quick and portable. Change-Id: I52a7c2bbb1b7e0ff8a3c3100b774212309d0828e
Diffstat (limited to 'runtime/entrypoints/jni')
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.cc87
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.h37
2 files changed, 119 insertions, 5 deletions
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 98f7b12..88b4936 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -15,23 +15,26 @@
*/
#include "base/logging.h"
-#include "mirror/abstract_method.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "mirror/abstract_method-inl.h"
+#include "mirror/object-inl.h"
+#include "object_utils.h"
#include "scoped_thread_state_change.h"
#include "thread.h"
namespace art {
// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
-extern "C" void* artFindNativeMethod(Thread* self) {
+extern "C" void* artFindNativeMethod() {
+ Thread* self = Thread::Current();
Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native.
- DCHECK(Thread::Current() == self);
ScopedObjectAccess soa(self);
mirror::AbstractMethod* method = self->GetCurrentMethod(NULL);
DCHECK(method != NULL);
- // Lookup symbol address for method, on failure we'll return NULL with an
- // exception set, otherwise we return the address of the method we found.
+ // Lookup symbol address for method, on failure we'll return NULL with an exception set,
+ // otherwise we return the address of the method we found.
void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
if (native_code == NULL) {
DCHECK(self->IsExceptionPending());
@@ -43,4 +46,78 @@ extern "C" void* artFindNativeMethod(Thread* self) {
}
}
+static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
+ intptr_t value = *arg_ptr;
+ mirror::Object** value_as_jni_rep = reinterpret_cast<mirror::Object**>(value);
+ mirror::Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
+ CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep))
+ << value_as_work_around_rep;
+ *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
+}
+
+extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(Thread::Current() == self);
+ // TODO: this code is specific to ARM
+ // On entry the stack pointed by sp is:
+ // | arg3 | <- Calling JNI method's frame (and extra bit for out args)
+ // | LR |
+ // | R3 | arg2
+ // | R2 | arg1
+ // | R1 | jclass/jobject
+ // | R0 | JNIEnv
+ // | unused |
+ // | unused |
+ // | unused | <- sp
+ mirror::AbstractMethod* jni_method = self->GetCurrentMethod(NULL);
+ DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method);
+ intptr_t* arg_ptr = sp + 4; // pointer to r1 on stack
+ // Fix up this/jclass argument
+ WorkAroundJniBugsForJobject(arg_ptr);
+ arg_ptr++;
+ // Fix up jobject arguments
+ MethodHelper mh(jni_method);
+ int reg_num = 2; // Current register being processed, -1 for stack arguments.
+ for (uint32_t i = 1; i < mh.GetShortyLength(); i++) {
+ char shorty_char = mh.GetShorty()[i];
+ if (shorty_char == 'L') {
+ WorkAroundJniBugsForJobject(arg_ptr);
+ }
+ if (shorty_char == 'J' || shorty_char == 'D') {
+ if (reg_num == 2) {
+ arg_ptr = sp + 8; // skip to out arguments
+ reg_num = -1;
+ } else if (reg_num == 3) {
+ arg_ptr = sp + 10; // skip to out arguments plus 2 slots as long must be aligned
+ reg_num = -1;
+ } else {
+ DCHECK_EQ(reg_num, -1);
+ if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) {
+ arg_ptr += 3; // unaligned, pad and move through stack arguments
+ } else {
+ arg_ptr += 2; // aligned, move through stack arguments
+ }
+ }
+ } else {
+ if (reg_num == 2) {
+ arg_ptr++; // move through register arguments
+ reg_num++;
+ } else if (reg_num == 3) {
+ arg_ptr = sp + 8; // skip to outgoing stack arguments
+ reg_num = -1;
+ } else {
+ DCHECK_EQ(reg_num, -1);
+ arg_ptr++; // move through stack arguments
+ }
+ }
+ }
+ // Load expected destination, see Method::RegisterNative
+ const void* code = reinterpret_cast<const void*>(jni_method->GetNativeGcMap());
+ if (UNLIKELY(code == NULL)) {
+ code = GetJniDlsymLookupStub();
+ jni_method->RegisterNative(self, code);
+ }
+ return code;
+}
+
} // namespace art
diff --git a/runtime/entrypoints/jni/jni_entrypoints.h b/runtime/entrypoints/jni/jni_entrypoints.h
new file mode 100644
index 0000000..0a53447
--- /dev/null
+++ b/runtime/entrypoints/jni/jni_entrypoints.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ENTRYPOINTS_JNI_JNI_ENTRYPOINTS_H_
+#define ART_RUNTIME_ENTRYPOINTS_JNI_JNI_ENTRYPOINTS_H_
+
+#include "base/macros.h"
+#include "offsets.h"
+
+#define JNI_ENTRYPOINT_OFFSET(x) \
+ ThreadOffset(static_cast<uintptr_t>(OFFSETOF_MEMBER(Thread, jni_entrypoints_)) + \
+ static_cast<uintptr_t>(OFFSETOF_MEMBER(JniEntryPoints, x)))
+
+namespace art {
+
+// Pointers to functions that are called by JNI trampolines via thread-local storage.
+struct PACKED(4) JniEntryPoints {
+ // Called when the JNI method isn't registered.
+ void* (*pDlsymLookup)(JNIEnv* env, jobject);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_ENTRYPOINTS_JNI_JNI_ENTRYPOINTS_H_