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/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index a4d1837..967b191 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -834,8 +834,6 @@
 
   static bool IsInstructionForExceptionHandling(uintptr_t pc);
 
-  virtual void Bind(Label* label) = 0;
-
   virtual void CompareAndBranchIfZero(Register r, Label* label) = 0;
   virtual void CompareAndBranchIfNonZero(Register r, Label* label) = 0;
 
@@ -985,6 +983,10 @@
     }
   }
 
+  void Jump(Label* label) OVERRIDE {
+    b(label);
+  }
+
  protected:
   // Returns whether or not the given register is used for passing parameters.
   static int RegisterCompare(const Register* reg1, const Register* reg2) {
diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h
index 8e85fe9..7b25b8f 100644
--- a/compiler/utils/arm64/assembler_arm64.h
+++ b/compiler/utils/arm64/assembler_arm64.h
@@ -193,6 +193,13 @@
   // Unpoison a heap reference contained in `reg` if heap poisoning is enabled.
   void MaybeUnpoisonHeapReference(vixl::Register reg);
 
+  void Bind(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
+    UNIMPLEMENTED(FATAL) << "Do not use Bind for ARM64";
+  }
+  void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE {
+    UNIMPLEMENTED(FATAL) << "Do not use Jump for ARM64";
+  }
+
  private:
   static vixl::Register reg_x(int code) {
     CHECK(code < kNumberOfXRegisters) << code;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 64d76b8..1088cb1 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -23,6 +23,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "arm/constants_arm.h"
+#include "label.h"
 #include "managed_register.h"
 #include "memory_region.h"
 #include "mips/constants_mips.h"
@@ -35,106 +36,6 @@
 
 class Assembler;
 class AssemblerBuffer;
-class AssemblerFixup;
-
-namespace arm {
-  class ArmAssembler;
-  class Arm32Assembler;
-  class Thumb2Assembler;
-}
-namespace arm64 {
-  class Arm64Assembler;
-}
-namespace mips {
-  class MipsAssembler;
-}
-namespace mips64 {
-  class Mips64Assembler;
-}
-namespace x86 {
-  class X86Assembler;
-  class NearLabel;
-}
-namespace x86_64 {
-  class X86_64Assembler;
-  class NearLabel;
-}
-
-class ExternalLabel {
- public:
-  ExternalLabel(const char* name_in, uintptr_t address_in)
-      : name_(name_in), address_(address_in) {
-    DCHECK(name_in != nullptr);
-  }
-
-  const char* name() const { return name_; }
-  uintptr_t address() const {
-    return address_;
-  }
-
- private:
-  const char* name_;
-  const uintptr_t address_;
-};
-
-class Label {
- public:
-  Label() : position_(0) {}
-
-  ~Label() {
-    // Assert if label is being destroyed with unresolved branches pending.
-    CHECK(!IsLinked());
-  }
-
-  // Returns the position for bound and linked labels. Cannot be used
-  // for unused labels.
-  int Position() const {
-    CHECK(!IsUnused());
-    return IsBound() ? -position_ - sizeof(void*) : position_ - sizeof(void*);
-  }
-
-  int LinkPosition() const {
-    CHECK(IsLinked());
-    return position_ - sizeof(void*);
-  }
-
-  bool IsBound() const { return position_ < 0; }
-  bool IsUnused() const { return position_ == 0; }
-  bool IsLinked() const { return position_ > 0; }
-
- private:
-  int position_;
-
-  void Reinitialize() {
-    position_ = 0;
-  }
-
-  void BindTo(int position) {
-    CHECK(!IsBound());
-    position_ = -position - sizeof(void*);
-    CHECK(IsBound());
-  }
-
-  void LinkTo(int position) {
-    CHECK(!IsBound());
-    position_ = position + sizeof(void*);
-    CHECK(IsLinked());
-  }
-
-  friend class arm::ArmAssembler;
-  friend class arm::Arm32Assembler;
-  friend class arm::Thumb2Assembler;
-  friend class arm64::Arm64Assembler;
-  friend class mips::MipsAssembler;
-  friend class mips64::Mips64Assembler;
-  friend class x86::X86Assembler;
-  friend class x86::NearLabel;
-  friend class x86_64::X86_64Assembler;
-  friend class x86_64::NearLabel;
-
-  DISALLOW_COPY_AND_ASSIGN(Label);
-};
-
 
 // Assembler fixups are positions in generated code that require processing
 // after the code has been copied to executable memory. This includes building
@@ -534,6 +435,9 @@
   // and branch to a ExceptionSlowPath if it is.
   virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) = 0;
 
+  virtual void Bind(Label* label) = 0;
+  virtual void Jump(Label* label) = 0;
+
   virtual ~Assembler() {}
 
   /**
diff --git a/compiler/utils/label.h b/compiler/utils/label.h
new file mode 100644
index 0000000..ff4a1a4
--- /dev/null
+++ b/compiler/utils/label.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_UTILS_LABEL_H_
+#define ART_COMPILER_UTILS_LABEL_H_
+
+#include "base/logging.h"
+#include "base/macros.h"
+
+namespace art {
+
+class Assembler;
+class AssemblerBuffer;
+class AssemblerFixup;
+
+namespace arm {
+  class ArmAssembler;
+  class Arm32Assembler;
+  class Thumb2Assembler;
+}
+namespace arm64 {
+  class Arm64Assembler;
+}
+namespace mips {
+  class MipsAssembler;
+}
+namespace mips64 {
+  class Mips64Assembler;
+}
+namespace x86 {
+  class X86Assembler;
+  class NearLabel;
+}
+namespace x86_64 {
+  class X86_64Assembler;
+  class NearLabel;
+}
+
+class ExternalLabel {
+ public:
+  ExternalLabel(const char* name_in, uintptr_t address_in)
+      : name_(name_in), address_(address_in) {
+    DCHECK(name_in != nullptr);
+  }
+
+  const char* name() const { return name_; }
+  uintptr_t address() const {
+    return address_;
+  }
+
+ private:
+  const char* name_;
+  const uintptr_t address_;
+};
+
+class Label {
+ public:
+  Label() : position_(0) {}
+
+  ~Label() {
+    // Assert if label is being destroyed with unresolved branches pending.
+    CHECK(!IsLinked());
+  }
+
+  // Returns the position for bound and linked labels. Cannot be used
+  // for unused labels.
+  int Position() const {
+    CHECK(!IsUnused());
+    return IsBound() ? -position_ - sizeof(void*) : position_ - sizeof(void*);
+  }
+
+  int LinkPosition() const {
+    CHECK(IsLinked());
+    return position_ - sizeof(void*);
+  }
+
+  bool IsBound() const { return position_ < 0; }
+  bool IsUnused() const { return position_ == 0; }
+  bool IsLinked() const { return position_ > 0; }
+
+ private:
+  int position_;
+
+  void Reinitialize() {
+    position_ = 0;
+  }
+
+  void BindTo(int position) {
+    CHECK(!IsBound());
+    position_ = -position - sizeof(void*);
+    CHECK(IsBound());
+  }
+
+  void LinkTo(int position) {
+    CHECK(!IsBound());
+    position_ = position + sizeof(void*);
+    CHECK(IsLinked());
+  }
+
+  friend class arm::ArmAssembler;
+  friend class arm::Arm32Assembler;
+  friend class arm::Thumb2Assembler;
+  friend class arm64::Arm64Assembler;
+  friend class mips::MipsAssembler;
+  friend class mips64::Mips64Assembler;
+  friend class x86::X86Assembler;
+  friend class x86::NearLabel;
+  friend class x86_64::X86_64Assembler;
+  friend class x86_64::NearLabel;
+
+  DISALLOW_COPY_AND_ASSIGN(Label);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_LABEL_H_
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index 6c8b162..378a59c 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -150,6 +150,13 @@
   void EmitJump(Label* label, bool link);
   void Bind(Label* label, bool is_jump);
 
+  void Bind(Label* label) OVERRIDE {
+    Bind(label, false);
+  }
+  void Jump(Label* label) OVERRIDE {
+    EmitJump(label, false);
+  }
+
   //
   // Overridden common assembler high-level functionality
   //
diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h
index a120abb..c170313 100644
--- a/compiler/utils/mips64/assembler_mips64.h
+++ b/compiler/utils/mips64/assembler_mips64.h
@@ -240,7 +240,10 @@
   void Addiu32(GpuRegister rt, GpuRegister rs, int32_t value, GpuRegister rtmp = AT);
   void Daddiu64(GpuRegister rt, GpuRegister rs, int64_t value, GpuRegister rtmp = AT);  // MIPS64
 
-  void Bind(Label* label);  // R6
+  void Bind(Label* label) OVERRIDE;  // R6
+  void Jump(Label* label) OVERRIDE {
+    B(label);
+  }
   void B(Label* label);  // R6
   void Jalr(Label* label, GpuRegister indirect_reg = RA);  // R6
   // TODO: implement common for R6 and non-R6 interface for conditional branches?
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index af78663..93ecdf5 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -600,7 +600,10 @@
   //
   int PreferredLoopAlignment() { return 16; }
   void Align(int alignment, int offset);
-  void Bind(Label* label);
+  void Bind(Label* label) OVERRIDE;
+  void Jump(Label* label) OVERRIDE {
+    jmp(label);
+  }
   void Bind(NearLabel* label);
 
   //
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index c8875e8..255f551 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -680,7 +680,10 @@
   //
   int PreferredLoopAlignment() { return 16; }
   void Align(int alignment, int offset);
-  void Bind(Label* label);
+  void Bind(Label* label) OVERRIDE;
+  void Jump(Label* label) OVERRIDE {
+    jmp(label);
+  }
   void Bind(NearLabel* label);
 
   //