Static and direct resolution stub.
Ensure that invoke static and direct go through a stub that causes
resolution and initialization.
Change-Id: I872900560322817d8f4378b04ac410d9ea0b3b17
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 039a749..2bcd7d9 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -309,6 +309,85 @@
thread->DeliverException();
}
+void* UnresolvedDirectMethodTrampolineFromCode(int32_t method_idx, void* sp, Thread* thread,
+ bool is_static) {
+ // TODO: this code is specific to ARM
+ // On entry the stack pointed by sp is:
+ // | argN | |
+ // | ... | |
+ // | arg4 | |
+ // | arg3 spill | | Caller's frame
+ // | arg2 spill | |
+ // | arg1 spill | |
+ // | Method* | ---
+ // | LR |
+ // | R3 | arg3
+ // | R2 | arg2
+ // | R1 | arg1
+ // | R0 | <- sp
+ uintptr_t* regs = reinterpret_cast<uintptr_t*>(sp);
+ Method** caller_sp = reinterpret_cast<Method**>(®s[5]);
+ // Record the last top of the managed stack
+ thread->SetTopOfStack(caller_sp, regs[4]);
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ // Start new JNI local reference state
+ JNIEnvExt* env = thread->GetJniEnv();
+ uint32_t saved_local_ref_cookie = env->local_ref_cookie;
+ env->local_ref_cookie = env->locals.GetSegmentState();
+ // Discover shorty (avoid GCs)
+ const char* shorty = linker->MethodShorty(method_idx, *caller_sp);
+ size_t shorty_len = strlen(shorty);
+ size_t args_in_regs = shorty_len < 3 ? shorty_len : 3;
+ // Handlerize references in registers
+ int cur_arg = 1; // skip method_idx in R0, first arg is in R1
+ if (!is_static) {
+ Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+ cur_arg++;
+ AddLocalReference<jobject>(env, obj);
+ }
+ for(size_t i = 0; i < args_in_regs; i++) {
+ char c = shorty[i + 1]; // offset to skip return value
+ if (c == 'L') {
+ Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+ AddLocalReference<jobject>(env, obj);
+ }
+ cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
+ }
+ // Handlerize references in out going arguments
+ for(size_t i = 3; i < shorty_len; i++) {
+ char c = shorty[i + 1]; // offset to skip return value
+ if (c == 'L') {
+ Object* obj = reinterpret_cast<Object*>(regs[i + 3]); // skip R0, LR and Method* of caller
+ AddLocalReference<jobject>(env, obj);
+ }
+ cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
+ }
+ // Resolve method filling in dex cache
+ Method* called = linker->ResolveMethod(method_idx, *caller_sp, true);
+ if (!thread->IsExceptionPending()) {
+ // We got this far, ensure that the declaring class is initialized
+ linker->EnsureInitialized(called->GetDeclaringClass(), true);
+ }
+ // Restore JNI env state
+ env->locals.SetSegmentState(env->local_ref_cookie);
+ env->local_ref_cookie = saved_local_ref_cookie;
+
+ void* code;
+ if (thread->IsExceptionPending()) {
+ // Something went wrong, go into deliver exception with the pending exception in r0
+ code = reinterpret_cast<void*>(art_deliver_exception_from_code);
+ regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
+ thread->ClearException();
+ } else {
+ // Expect class to at least be initializing
+ CHECK(called->GetDeclaringClass()->IsInitializing());
+ // Set up entry into main method
+ regs[0] = reinterpret_cast<uintptr_t>(called);
+ code = const_cast<void*>(called->GetCode());
+ }
+ return code;
+}
+
// TODO: placeholder. Helper function to type
Class* InitializeTypeFromCode(uint32_t type_idx, Method* method) {
/*