riscv64: add invoke-interface support in invokeExact.

Test: art/test/testrunner/testrunner.py --target --64
Change-Id: I3cd534326cbde4d9c10714138dbde3f3867ac9bf
diff --git a/compiler/optimizing/intrinsics_riscv64.cc b/compiler/optimizing/intrinsics_riscv64.cc
index 9379c8d..3914e49 100644
--- a/compiler/optimizing/intrinsics_riscv64.cc
+++ b/compiler/optimizing/intrinsics_riscv64.cc
@@ -19,6 +19,7 @@
 #include "code_generator_riscv64.h"
 #include "intrinsic_objects.h"
 #include "intrinsics_utils.h"
+#include "mirror/class.h"
 #include "optimizing/locations.h"
 #include "well_known_classes.h"
 
@@ -5852,12 +5853,58 @@
     __ Sh3Add(temp, temp, receiver_class);
     __ Loadd(method, temp, vtable_offset);
     __ J(&execute_target_method);
-    __ Bind(&non_virtual_dispatch);
-  }
 
-  // Checks above are jumping to `execute_target_method` is they succeed. If none match, try to
-  // handle in the slow path.
-  __ J(slow_path->GetEntryLabel());
+    __ Bind(&non_virtual_dispatch);
+    __ Li(temp, mirror::MethodHandle::Kind::kInvokeInterface);
+    __ Bne(method_handle_kind, temp, slow_path->GetEntryLabel());
+
+    // Skip virtual dispatch if `method` is private.
+    // Re-use method_handle_kind to store access flags.
+    XRegister access_flags = locations->GetTemp(2).AsRegister<XRegister>();
+    __ Loadwu(access_flags, method, ArtMethod::AccessFlagsOffset().Int32Value());
+    __ Andi(temp, access_flags, kAccPrivate);
+    __ Bnez(temp, &execute_target_method);
+
+    // The register T0 is required to be used for the hidden argument in
+    // art_quick_imt_conflict_trampoline. So prevent the assembler from using it.
+    ScratchRegisterScope srs(assembler);
+    srs.ExcludeXRegister(T0);
+
+    // Set the hidden argument.
+    __ Mv(T0, method);
+
+    Riscv64Label get_imt_index_from_method_index;
+    Riscv64Label do_imt_dispatch;
+
+    // Get IMT index.
+    // Not doing default conflict check as IMT index is set for all method which have
+    // kAccAbstract bit.
+    __ Andi(temp, access_flags, kAccAbstract);
+    __ Beqz(temp, &get_imt_index_from_method_index);
+
+    // imt_index is uint16_t
+    __ Loadhu(temp, method, ArtMethod::ImtIndexOffset().Int32Value());
+    __ J(&do_imt_dispatch);
+
+    // Default method, do method->GetMethodIndex() & (ImTable::kSizeTruncToPowerOfTwo - 1);
+    __ Bind(&get_imt_index_from_method_index);
+    __ Loadhu(temp, method, ArtMethod::MethodIndexOffset().Int32Value());
+    __ Andi(temp, temp, ImTable::kSizeTruncToPowerOfTwo - 1);
+
+    __ Bind(&do_imt_dispatch);
+    // Re-using `method` to store receiver class and ImTableEntry.
+    __ Loadd(method, receiver, mirror::Object::ClassOffset().Int32Value());
+    codegen_->MaybeUnpoisonHeapReference(method);
+
+    __ Loadd(method, method, mirror::Class::ImtPtrOffset(PointerSize::k64).Int32Value());
+    __ Sh3Add(temp, temp, method);
+    __ Loadd(method, temp, 0);
+
+    __ J(&execute_target_method);
+  } else {
+    // Not invoke-static and the first argument is not a reference type.
+    __ J(slow_path->GetEntryLabel());
+  }
 
   __ Bind(&execute_target_method);
   Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kRiscv64PointerSize);