Fixes for Generic JNI
This fixes some linking issues and native code retrieval errors.
All host tests are functional with this change.
Make ArtMethod::GetFrameSizeInBytes() templated to bypass the
embedded sanity check. Necessary for fix-up decision.
Add ArtMethod metadata fix-up code to ClassLinker::LinkCode.
Necessitates new parameters to access the shorty and compute
the frame size.
Fix handling the JNI dlsym lookup stub in the generic JNI code.
Change-Id: I4173b0fbb1ba5b1bcbee1bb340cfdd08a54767e5
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b709da3..e59640c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1735,7 +1735,7 @@
}
static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class,
- uint32_t method_index)
+ const DexFile& dex_file, uint32_t dex_method_index, uint32_t method_index)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Method shouldn't have already been linked.
DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
@@ -1790,6 +1790,38 @@
if (method->IsNative()) {
// Unregistering restores the dlsym lookup stub.
method->UnregisterNative(Thread::Current());
+
+ if (enter_interpreter) {
+ // We have a native method here without code. Then it should have either the GenericJni
+ // trampoline as entrypoint (non-static), or the Resolution trampoline (static).
+ DCHECK(method->GetEntryPointFromQuickCompiledCode() ==
+ GetQuickResolutionTrampoline(runtime->GetClassLinker())
+ ||
+ method->GetEntryPointFromQuickCompiledCode() == GetQuickGenericJniTrampoline());
+
+ DCHECK_EQ(method->GetFrameSizeInBytes<false>(), 0U);
+
+ // Fix up method metadata if necessary.
+ if (method->GetFrameSizeInBytes<false>() == 0) {
+ uint32_t s_len;
+ const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(dex_method_index), &s_len);
+ uint32_t refs = 1; // Native method always has "this" or class.
+ for (uint32_t i = 1; i < s_len; ++i) {
+ if (shorty[i] == 'L') {
+ refs++;
+ }
+ }
+ size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSize(refs);
+
+ // Get the generic spill masks and base frame size.
+ mirror::ArtMethod* callee_save_method =
+ Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
+
+ method->SetFrameSizeInBytes(callee_save_method->GetFrameSizeInBytes() + sirt_size);
+ method->SetCoreSpillMask(callee_save_method->GetCoreSpillMask());
+ method->SetFpSpillMask(callee_save_method->GetFpSpillMask());
+ }
+ }
}
// Allow instrumentation its chance to hijack code.
@@ -1902,7 +1934,7 @@
}
klass->SetDirectMethod(i, method.get());
if (oat_class.get() != NULL) {
- LinkCode(method, oat_class.get(), class_def_method_index);
+ LinkCode(method, oat_class.get(), dex_file, it.GetMemberIndex(), class_def_method_index);
}
method->SetMethodIndex(class_def_method_index);
class_def_method_index++;
@@ -1916,7 +1948,7 @@
klass->SetVirtualMethod(i, method.get());
DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
if (oat_class.get() != NULL) {
- LinkCode(method, oat_class.get(), class_def_method_index);
+ LinkCode(method, oat_class.get(), dex_file, it.GetMemberIndex(), class_def_method_index);
}
class_def_method_index++;
}