ART: Refactor intrinsics slow-paths

Refactor slow paths so that there is a default implementation for
common cases (only arm64 with vixl is special). Write a generic
intrinsic slow-path that can be reused for the specific architectures.
Move helper functions into CodeGenerator so that they are accessible.

Change-Id: Ibd788dce432601c6a9f7e6f13eab31f28dcb8550
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index cc8ddb6..938c78e 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -21,6 +21,7 @@
 #include "code_generator_arm.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "intrinsics.h"
+#include "intrinsics_utils.h"
 #include "mirror/array-inl.h"
 #include "mirror/string.h"
 #include "thread.h"
@@ -38,99 +39,7 @@
   return codegen_->GetGraph()->GetArena();
 }
 
-#define __ codegen->GetAssembler()->
-
-static void MoveFromReturnRegister(Location trg, Primitive::Type type, CodeGeneratorARM* codegen) {
-  if (!trg.IsValid()) {
-    DCHECK(type == Primitive::kPrimVoid);
-    return;
-  }
-
-  DCHECK_NE(type, Primitive::kPrimVoid);
-
-  if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
-    if (type == Primitive::kPrimLong) {
-      Register trg_reg_lo = trg.AsRegisterPairLow<Register>();
-      Register trg_reg_hi = trg.AsRegisterPairHigh<Register>();
-      Register res_reg_lo = R0;
-      Register res_reg_hi = R1;
-      if (trg_reg_lo != res_reg_hi) {
-        if (trg_reg_lo != res_reg_lo) {
-          __ mov(trg_reg_lo, ShifterOperand(res_reg_lo));
-          __ mov(trg_reg_hi, ShifterOperand(res_reg_hi));
-        } else {
-          DCHECK_EQ(trg_reg_lo + 1, trg_reg_hi);
-        }
-      } else {
-        __ mov(trg_reg_hi, ShifterOperand(res_reg_hi));
-        __ mov(trg_reg_lo, ShifterOperand(res_reg_lo));
-      }
-    } else {
-      Register trg_reg = trg.AsRegister<Register>();
-      Register res_reg = R0;
-      if (trg_reg != res_reg) {
-        __ mov(trg_reg, ShifterOperand(res_reg));
-      }
-    }
-  } else {
-    UNIMPLEMENTED(FATAL) << "Floating-point return.";
-  }
-}
-
-static void MoveArguments(HInvoke* invoke, CodeGeneratorARM* codegen) {
-  InvokeDexCallingConventionVisitorARM calling_convention_visitor;
-  IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
-}
-
-// Slow-path for fallback (calling the managed code to handle the intrinsic) in an intrinsified
-// call. This will copy the arguments into the positions for a regular call.
-//
-// Note: The actual parameters are required to be in the locations given by the invoke's location
-//       summary. If an intrinsic modifies those locations before a slowpath call, they must be
-//       restored!
-class IntrinsicSlowPathARM : public SlowPathCodeARM {
- public:
-  explicit IntrinsicSlowPathARM(HInvoke* invoke) : invoke_(invoke) { }
-
-  void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
-    CodeGeneratorARM* codegen = down_cast<CodeGeneratorARM*>(codegen_in);
-    __ Bind(GetEntryLabel());
-
-    SaveLiveRegisters(codegen, invoke_->GetLocations());
-
-    MoveArguments(invoke_, codegen);
-
-    if (invoke_->IsInvokeStaticOrDirect()) {
-      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
-                                          Location::RegisterLocation(kArtMethodRegister));
-    } else {
-      codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(),
-                                   Location::RegisterLocation(kArtMethodRegister));
-    }
-    codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
-
-    // Copy the result back to the expected output.
-    Location out = invoke_->GetLocations()->Out();
-    if (out.IsValid()) {
-      DCHECK(out.IsRegister());  // TODO: Replace this when we support output in memory.
-      DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
-      MoveFromReturnRegister(out, invoke_->GetType(), codegen);
-    }
-
-    RestoreLiveRegisters(codegen, invoke_->GetLocations());
-    __ b(GetExitLabel());
-  }
-
-  const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathARM"; }
-
- private:
-  // The instruction where this slow path is happening.
-  HInvoke* const invoke_;
-
-  DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathARM);
-};
-
-#undef __
+using IntrinsicSlowPathARM = IntrinsicSlowPath<InvokeDexCallingConventionVisitorARM>;
 
 bool IntrinsicLocationsBuilderARM::TryDispatch(HInvoke* invoke) {
   Dispatch(invoke);
@@ -1094,7 +1003,7 @@
   // TODO: For simplicity, the index parameter is requested in a register, so different from Quick
   //       we will not optimize the code for constants (which would save a register).
 
-  SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
+  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
   codegen_->AddSlowPath(slow_path);
 
   __ ldr(temp, Address(obj, count_offset.Int32Value()));          // temp = str.length.
@@ -1130,7 +1039,7 @@
 
   Register argument = locations->InAt(1).AsRegister<Register>();
   __ cmp(argument, ShifterOperand(0));
-  SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
+  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
   codegen_->AddSlowPath(slow_path);
   __ b(slow_path->GetEntryLabel(), EQ);
 
@@ -1248,7 +1157,7 @@
 
   // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
   // or directly dispatch if we have a constant.
-  SlowPathCodeARM* slow_path = nullptr;
+  SlowPathCode* slow_path = nullptr;
   if (invoke->InputAt(1)->IsIntConstant()) {
     if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) >
         std::numeric_limits<uint16_t>::max()) {
@@ -1341,7 +1250,7 @@
 
   Register byte_array = locations->InAt(0).AsRegister<Register>();
   __ cmp(byte_array, ShifterOperand(0));
-  SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
+  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
   codegen_->AddSlowPath(slow_path);
   __ b(slow_path->GetEntryLabel(), EQ);
 
@@ -1387,7 +1296,7 @@
 
   Register string_to_copy = locations->InAt(0).AsRegister<Register>();
   __ cmp(string_to_copy, ShifterOperand(0));
-  SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
+  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
   codegen_->AddSlowPath(slow_path);
   __ b(slow_path->GetEntryLabel(), EQ);