Revert "Revert "ART: Compiler support for invoke-polymorphic.""

This reverts commit 0fb5af1c8287b1ec85c55c306a1c43820c38a337.

This takes us back to the original change and attempts to fix the
issues encountered:

- Adds transition record push/pop around artInvokePolymorphic.
- Changes X86/X64 relocations for MacSDK.
- Implements MIPS entrypoint for art_quick_invoke_polymorphic.
- Corrects size of returned reference in art_quick_invoke_polymorphic
  on ARM.

Bug: 30550796,33191393
Test: art/test/run-test 953
Test: m test-art-run-test

Change-Id: Ib6b93e00b37b9d4ab743a3470ab3d77fe857cda8
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index a3e5b55..8f7f746 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -27,10 +27,12 @@
 #include "imtable-inl.h"
 #include "interpreter/interpreter.h"
 #include "linear_alloc.h"
+#include "method_handles.h"
 #include "method_reference.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "mirror/method.h"
+#include "mirror/method_handle_impl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "oat_quick_method_header.h"
@@ -39,6 +41,7 @@
 #include "scoped_thread_state_change-inl.h"
 #include "stack.h"
 #include "debugger.h"
+#include "well_known_classes.h"
 
 namespace art {
 
@@ -2391,4 +2394,121 @@
                                 reinterpret_cast<uintptr_t>(method));
 }
 
+// Returns shorty type so the caller can determine how to put |result|
+// into expected registers. The shorty type is static so the compiler
+// could call different flavors of this code path depending on the
+// shorty type though this would require different entry points for
+// each type.
+extern "C" uintptr_t artInvokePolymorphic(
+    JValue* result,
+    mirror::Object* raw_method_handle,
+    Thread* self,
+    ArtMethod** sp)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  ScopedQuickEntrypointChecks sqec(self);
+  DCHECK_EQ(*sp, Runtime::Current()->GetCalleeSaveMethod(Runtime::kSaveRefsAndArgs));
+
+  // Start new JNI local reference state
+  JNIEnvExt* env = self->GetJniEnv();
+  ScopedObjectAccessUnchecked soa(env);
+  ScopedJniEnvLocalRefState env_state(env);
+  const char* old_cause = self->StartAssertNoThreadSuspension("Making stack arguments safe.");
+
+  // From the instruction, get the |callsite_shorty| and expose arguments on the stack to the GC.
+  ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
+  uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
+  const DexFile::CodeItem* code = caller_method->GetCodeItem();
+  const Instruction* inst = Instruction::At(&code->insns_[dex_pc]);
+  DCHECK(inst->Opcode() == Instruction::INVOKE_POLYMORPHIC ||
+         inst->Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE);
+  const DexFile* dex_file = caller_method->GetDexFile();
+  const uint32_t proto_idx = inst->VRegH();
+  const char* shorty = dex_file->GetShorty(proto_idx);
+  const size_t shorty_length = strlen(shorty);
+  static const bool kMethodIsStatic = false;  // invoke() and invokeExact() are not static.
+  RememberForGcArgumentVisitor gc_visitor(sp, kMethodIsStatic, shorty, shorty_length, &soa);
+  gc_visitor.Visit();
+
+  // Wrap raw_method_handle in a Handle for safety.
+  StackHandleScope<5> hs(self);
+  Handle<mirror::MethodHandleImpl> method_handle(
+      hs.NewHandle(ObjPtr<mirror::MethodHandleImpl>::DownCast(MakeObjPtr(raw_method_handle))));
+  raw_method_handle = nullptr;
+  self->EndAssertNoThreadSuspension(old_cause);
+
+  // Resolve method - it's either MethodHandle.invoke() or MethodHandle.invokeExact().
+  ClassLinker* linker = Runtime::Current()->GetClassLinker();
+  ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::kForceICCECheck>(self,
+                                                                                   inst->VRegB(),
+                                                                                   caller_method,
+                                                                                   kVirtual);
+  DCHECK((resolved_method ==
+          jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact)) ||
+         (resolved_method ==
+          jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invoke)));
+  if (UNLIKELY(method_handle.IsNull())) {
+    ThrowNullPointerExceptionForMethodAccess(resolved_method, InvokeType::kVirtual);
+    return static_cast<uintptr_t>('V');
+  }
+
+  Handle<mirror::Class> caller_class(hs.NewHandle(caller_method->GetDeclaringClass()));
+  Handle<mirror::MethodType> method_type(hs.NewHandle(linker->ResolveMethodType(
+      *dex_file, proto_idx,
+      hs.NewHandle<mirror::DexCache>(caller_class->GetDexCache()),
+      hs.NewHandle<mirror::ClassLoader>(caller_class->GetClassLoader()))));
+  // This implies we couldn't resolve one or more types in this method handle.
+  if (UNLIKELY(method_type.IsNull())) {
+    CHECK(self->IsExceptionPending());
+    return static_cast<uintptr_t>('V');
+  }
+
+  DCHECK_EQ(ArtMethod::NumArgRegisters(shorty) + 1u, (uint32_t)inst->VRegA());
+  DCHECK_EQ(resolved_method->IsStatic(), kMethodIsStatic);
+
+  // Fix references before constructing the shadow frame.
+  gc_visitor.FixupReferences();
+
+  // Construct shadow frame placing arguments consecutively from |first_arg|.
+  const bool is_range = (inst->Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE);
+  const size_t num_vregs = is_range ? inst->VRegA_4rcc() : inst->VRegA_45cc();
+  const size_t first_arg = 0;
+  ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
+      CREATE_SHADOW_FRAME(num_vregs, /* link */ nullptr, resolved_method, dex_pc);
+  ShadowFrame* shadow_frame = shadow_frame_unique_ptr.get();
+  ScopedStackedShadowFramePusher
+      frame_pusher(self, shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction);
+  BuildQuickShadowFrameVisitor shadow_frame_builder(sp,
+                                                    kMethodIsStatic,
+                                                    shorty,
+                                                    strlen(shorty),
+                                                    shadow_frame,
+                                                    first_arg);
+  shadow_frame_builder.VisitArguments();
+
+  // Push a transition back into managed code onto the linked list in thread.
+  ManagedStack fragment;
+  self->PushManagedStackFragment(&fragment);
+
+  // Call DoInvokePolymorphic with |is_range| = true, as shadow frame has argument registers in
+  // consecutive order.
+  uint32_t unused_args[Instruction::kMaxVarArgRegs] = {};
+  uint32_t first_callee_arg = first_arg + 1;
+  const bool do_assignability_check = false;
+  if (!DoInvokePolymorphic<true /* is_range */, do_assignability_check>(self,
+                                                                        resolved_method,
+                                                                        *shadow_frame,
+                                                                        method_handle,
+                                                                        method_type,
+                                                                        unused_args,
+                                                                        first_callee_arg,
+                                                                        result)) {
+    DCHECK(self->IsExceptionPending());
+  }
+
+  // Pop transition record.
+  self->PopManagedStackFragment(fragment);
+
+  return static_cast<uintptr_t>(shorty[0]);
+}
+
 }  // namespace art