8149415: [AArch64] implement JVMCI CodeInstaller
authortwisti
Wed, 10 Feb 2016 11:23:17 -1000
changeset 36060 de5c192c2eac
parent 36059 5ae62468859f
child 36061 baa556050d22
8149415: [AArch64] implement JVMCI CodeInstaller Reviewed-by: aph, kvn
hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp
hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.cpp
hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java
--- a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp	Wed Feb 10 16:31:17 2016 +0000
+++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp	Wed Feb 10 11:23:17 2016 -1000
@@ -30,39 +30,151 @@
 #include "vmreg_aarch64.inline.hpp"
 
 jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) {
-  Unimplemented();
-  return 0;
+  if (inst->is_call() || inst->is_jump() || inst->is_blr()) {
+    return pc_offset + NativeCall::instruction_size;
+  } else if (inst->is_general_jump()) {
+    return pc_offset + NativeGeneralJump::instruction_size;
+  } else {
+    JVMCI_ERROR_0("unsupported type of instruction for call site");
+  }
 }
 
 void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
-  Unimplemented();
+  address pc = _instructions->start() + pc_offset;
+  Handle obj = HotSpotObjectConstantImpl::object(constant);
+  jobject value = JNIHandles::make_local(obj());
+  if (HotSpotObjectConstantImpl::compressed(constant)) {
+    int oop_index = _oop_recorder->find_index(value);
+    RelocationHolder rspec = oop_Relocation::spec(oop_index);
+    _instructions->relocate(pc, rspec, 1);
+    Unimplemented();
+  } else {
+    NativeMovConstReg* move = nativeMovConstReg_at(pc);
+    move->set_data((intptr_t) value);
+    int oop_index = _oop_recorder->find_index(value);
+    RelocationHolder rspec = oop_Relocation::spec(oop_index);
+    _instructions->relocate(pc, rspec);
+  }
 }
 
 void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) {
-  Unimplemented();
+  address pc = _instructions->start() + pc_offset;
+  if (HotSpotMetaspaceConstantImpl::compressed(constant)) {
+    narrowKlass narrowOop = record_narrow_metadata_reference(constant, CHECK);
+    TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop);
+    Unimplemented();
+  } else {
+    NativeMovConstReg* move = nativeMovConstReg_at(pc);
+    Metadata* reference = record_metadata_reference(constant, CHECK);
+    move->set_data((intptr_t) reference);
+    TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference));
+  }
 }
 
 void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
-  Unimplemented();
+  address pc = _instructions->start() + pc_offset;
+  NativeInstruction* inst = nativeInstruction_at(pc);
+  if (inst->is_adr_aligned()) {
+    address dest = _constants->start() + data_offset;
+    _instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS));
+    TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset);
+  } else {
+    JVMCI_ERROR("unknown load or move instruction at " PTR_FORMAT, p2i(pc));
+  }
 }
 
 void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) {
-  Unimplemented();
+  address pc = (address) inst;
+  if (inst->is_call()) {
+    NativeCall* call = nativeCall_at(pc);
+    call->set_destination((address) foreign_call_destination);
+    _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec());
+  } else if (inst->is_jump()) {
+    NativeJump* jump = nativeJump_at(pc);
+    jump->set_jump_destination((address) foreign_call_destination);
+    _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec());
+  } else if (inst->is_general_jump()) {
+    NativeGeneralJump* jump = nativeGeneralJump_at(pc);
+    jump->set_jump_destination((address) foreign_call_destination);
+    _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec());
+  } else {
+    JVMCI_ERROR("unknown call or jump instruction at " PTR_FORMAT, p2i(pc));
+  }
+  TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
 }
 
 void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) {
-  Unimplemented();
+#ifdef ASSERT
+  Method* method = NULL;
+  // we need to check, this might also be an unresolved method
+  if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) {
+    method = getMethodFromHotSpotMethod(hotspot_method());
+  }
+#endif
+  switch (_next_call_type) {
+    case INLINE_INVOKE:
+      break;
+    case INVOKEVIRTUAL:
+    case INVOKEINTERFACE: {
+      assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface");
+      NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
+      call->set_destination(SharedRuntime::get_resolve_virtual_call_stub());
+      _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc));
+      break;
+    }
+    case INVOKESTATIC: {
+      assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic");
+      NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
+      call->set_destination(SharedRuntime::get_resolve_static_call_stub());
+      _instructions->relocate(call->instruction_address(), relocInfo::static_call_type);
+      break;
+    }
+    case INVOKESPECIAL: {
+      assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial");
+      NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
+      call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub());
+      _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type);
+      break;
+    }
+    default:
+      JVMCI_ERROR("invalid _next_call_type value");
+      break;
+  }
 }
 
 void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) {
-  Unimplemented();
+  switch (mark) {
+    case POLL_NEAR:
+      JVMCI_ERROR("unimplemented");
+      break;
+    case POLL_FAR:
+      _instructions->relocate(pc, relocInfo::poll_type);
+      break;
+    case POLL_RETURN_NEAR:
+      JVMCI_ERROR("unimplemented");
+      break;
+    case POLL_RETURN_FAR:
+      _instructions->relocate(pc, relocInfo::poll_return_type);
+      break;
+    default:
+      JVMCI_ERROR("invalid mark value");
+      break;
+  }
 }
 
 // convert JVMCI register indices (as used in oop maps) to HotSpot registers
 VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) {
-  return NULL;
+  if (jvmci_reg < RegisterImpl::number_of_registers) {
+    return as_Register(jvmci_reg)->as_VMReg();
+  } else {
+    jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers;
+    if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) {
+      return as_FloatRegister(floatRegisterNumber)->as_VMReg();
+    }
+    JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg);
+  }
 }
 
 bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
-  return false;
+  return !hotspotRegister->is_FloatRegister();
 }
--- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.cpp	Wed Feb 10 16:31:17 2016 +0000
+++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.cpp	Wed Feb 10 11:23:17 2016 -1000
@@ -136,7 +136,7 @@
     MacroAssembler::pd_patch_instruction(instruction_address(), (address)x);
     ICache::invalidate_range(instruction_address(), instruction_size);
   }
-};
+}
 
 void NativeMovConstReg::print() {
   tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT,
@@ -208,6 +208,32 @@
 
 //-------------------------------------------------------------------
 
+address NativeGeneralJump::jump_destination() const {
+  NativeMovConstReg* move = nativeMovConstReg_at(instruction_address());
+  address dest = (address) move->data();
+
+  // We use jump to self as the unresolved address which the inline
+  // cache code (and relocs) know about
+
+  // return -1 if jump to self
+  dest = (dest == (address) this) ? (address) -1 : dest;
+  return dest;
+}
+
+void NativeGeneralJump::set_jump_destination(address dest) {
+  NativeMovConstReg* move = nativeMovConstReg_at(instruction_address());
+
+  // We use jump to self as the unresolved address which the inline
+  // cache code (and relocs) know about
+  if (dest == (address) -1) {
+    dest = instruction_address();
+  }
+
+  move->set_data((uintptr_t) dest);
+};
+
+//-------------------------------------------------------------------
+
 bool NativeInstruction::is_safepoint_poll() {
   // a safepoint_poll is implemented in two steps as either
   //
@@ -249,6 +275,22 @@
           Instruction_aarch64::extract(insn, 4, 0) == 0b11111);
 }
 
+bool NativeInstruction::is_general_jump() {
+  if (is_movz()) {
+    NativeInstruction* inst1 = nativeInstruction_at(addr_at(instruction_size * 1));
+    if (inst1->is_movk()) {
+      NativeInstruction* inst2 = nativeInstruction_at(addr_at(instruction_size * 2));
+      if (inst2->is_movk()) {
+        NativeInstruction* inst3 = nativeInstruction_at(addr_at(instruction_size * 3));
+        if (inst3->is_blr()) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
 bool NativeInstruction::is_movz() {
   return Instruction_aarch64::extract(int_at(0), 30, 23) == 0b10100101;
 }
--- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp	Wed Feb 10 16:31:17 2016 +0000
+++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp	Wed Feb 10 11:23:17 2016 -1000
@@ -54,11 +54,22 @@
   friend class Relocation;
   friend bool is_NativeCallTrampolineStub_at(address);
  public:
-  enum { instruction_size = 4 };
+  enum {
+    instruction_size = 4
+  };
+
+  juint encoding() const {
+    return uint_at(0);
+  }
+
+  bool is_blr()                      const { return (encoding() & 0xfffffc1f) == 0xd63f0000; }
+  bool is_adr_aligned()              const { return (encoding() & 0xff000000) == 0x10000000; } // adr Xn, <label>, where label is aligned to 4 bytes (address of instruction).
+
   inline bool is_nop();
   inline bool is_illegal();
   inline bool is_return();
   bool is_jump();
+  bool is_general_jump();
   inline bool is_jump_or_nop();
   inline bool is_cond_jump();
   bool is_safepoint_poll();
@@ -341,11 +352,15 @@
 // An interface for accessing/manipulating native leal instruction of form:
 //        leal reg, [reg + offset]
 
-class NativeLoadAddress: public NativeMovRegMem {
-  static const bool has_rex = true;
-  static const int rex_size = 1;
+class NativeLoadAddress: public NativeInstruction {
+  enum AArch64_specific_constants {
+    instruction_size            =    4,
+    instruction_offset          =    0,
+    data_offset                 =    0,
+    next_instruction_offset     =    4
+  };
+
  public:
-
   void verify();
   void print ();
 
@@ -398,6 +413,10 @@
     data_offset                 =    0,
     next_instruction_offset     =    4 * 4
   };
+
+  address jump_destination() const;
+  void set_jump_destination(address dest);
+
   static void insert_unconditional(address code_pos, address entry);
   static void replace_mt_safe(address instr_addr, address code_buffer);
   static void verify();
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java	Wed Feb 10 16:31:17 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java	Wed Feb 10 11:23:17 2016 -1000
@@ -70,56 +70,64 @@
     public static final Register r28 = new Register(28, 28, "r28", CPU);
     public static final Register r29 = new Register(29, 29, "r29", CPU);
     public static final Register r30 = new Register(30, 30, "r30", CPU);
+
+    /*
+     * r31 is not a general purpose register, but represents either the stackpointer or the
+     * zero/discard register depending on the instruction. So we represent those two uses as two
+     * different registers. The register numbers are kept in sync with register_aarch64.hpp and have
+     * to be sequential, hence we also need a general r31 register here, which is never used.
+     */
     public static final Register r31 = new Register(31, 31, "r31", CPU);
+    public static final Register zr = new Register(32, 31, "zr", CPU);
+    public static final Register sp = new Register(33, 31, "sp", CPU);
 
     public static final Register lr = r30;
-    public static final Register zr = r31;
-    public static final Register sp = r31;
 
     // @formatter:off
     public static final Register[] cpuRegisters = {
         r0,  r1,  r2,  r3,  r4,  r5,  r6,  r7,
         r8,  r9,  r10, r11, r12, r13, r14, r15,
         r16, r17, r18, r19, r20, r21, r22, r23,
-        r24, r25, r26, r27, r28, r29, r30, r31
+        r24, r25, r26, r27, r28, r29, r30, r31,
+        zr,  sp
     };
     // @formatter:on
 
     public static final RegisterCategory SIMD = new RegisterCategory("SIMD");
 
     // Simd registers
-    public static final Register v0 = new Register(32, 0, "v0", SIMD);
-    public static final Register v1 = new Register(33, 1, "v1", SIMD);
-    public static final Register v2 = new Register(34, 2, "v2", SIMD);
-    public static final Register v3 = new Register(35, 3, "v3", SIMD);
-    public static final Register v4 = new Register(36, 4, "v4", SIMD);
-    public static final Register v5 = new Register(37, 5, "v5", SIMD);
-    public static final Register v6 = new Register(38, 6, "v6", SIMD);
-    public static final Register v7 = new Register(39, 7, "v7", SIMD);
-    public static final Register v8 = new Register(40, 8, "v8", SIMD);
-    public static final Register v9 = new Register(41, 9, "v9", SIMD);
-    public static final Register v10 = new Register(42, 10, "v10", SIMD);
-    public static final Register v11 = new Register(43, 11, "v11", SIMD);
-    public static final Register v12 = new Register(44, 12, "v12", SIMD);
-    public static final Register v13 = new Register(45, 13, "v13", SIMD);
-    public static final Register v14 = new Register(46, 14, "v14", SIMD);
-    public static final Register v15 = new Register(47, 15, "v15", SIMD);
-    public static final Register v16 = new Register(48, 16, "v16", SIMD);
-    public static final Register v17 = new Register(49, 17, "v17", SIMD);
-    public static final Register v18 = new Register(50, 18, "v18", SIMD);
-    public static final Register v19 = new Register(51, 19, "v19", SIMD);
-    public static final Register v20 = new Register(52, 20, "v20", SIMD);
-    public static final Register v21 = new Register(53, 21, "v21", SIMD);
-    public static final Register v22 = new Register(54, 22, "v22", SIMD);
-    public static final Register v23 = new Register(55, 23, "v23", SIMD);
-    public static final Register v24 = new Register(56, 24, "v24", SIMD);
-    public static final Register v25 = new Register(57, 25, "v25", SIMD);
-    public static final Register v26 = new Register(58, 26, "v26", SIMD);
-    public static final Register v27 = new Register(59, 27, "v27", SIMD);
-    public static final Register v28 = new Register(60, 28, "v28", SIMD);
-    public static final Register v29 = new Register(61, 29, "v29", SIMD);
-    public static final Register v30 = new Register(62, 30, "v30", SIMD);
-    public static final Register v31 = new Register(63, 31, "v31", SIMD);
+    public static final Register v0 = new Register(34, 0, "v0", SIMD);
+    public static final Register v1 = new Register(35, 1, "v1", SIMD);
+    public static final Register v2 = new Register(36, 2, "v2", SIMD);
+    public static final Register v3 = new Register(37, 3, "v3", SIMD);
+    public static final Register v4 = new Register(38, 4, "v4", SIMD);
+    public static final Register v5 = new Register(39, 5, "v5", SIMD);
+    public static final Register v6 = new Register(40, 6, "v6", SIMD);
+    public static final Register v7 = new Register(41, 7, "v7", SIMD);
+    public static final Register v8 = new Register(42, 8, "v8", SIMD);
+    public static final Register v9 = new Register(43, 9, "v9", SIMD);
+    public static final Register v10 = new Register(44, 10, "v10", SIMD);
+    public static final Register v11 = new Register(45, 11, "v11", SIMD);
+    public static final Register v12 = new Register(46, 12, "v12", SIMD);
+    public static final Register v13 = new Register(47, 13, "v13", SIMD);
+    public static final Register v14 = new Register(48, 14, "v14", SIMD);
+    public static final Register v15 = new Register(49, 15, "v15", SIMD);
+    public static final Register v16 = new Register(50, 16, "v16", SIMD);
+    public static final Register v17 = new Register(51, 17, "v17", SIMD);
+    public static final Register v18 = new Register(52, 18, "v18", SIMD);
+    public static final Register v19 = new Register(53, 19, "v19", SIMD);
+    public static final Register v20 = new Register(54, 20, "v20", SIMD);
+    public static final Register v21 = new Register(55, 21, "v21", SIMD);
+    public static final Register v22 = new Register(56, 22, "v22", SIMD);
+    public static final Register v23 = new Register(57, 23, "v23", SIMD);
+    public static final Register v24 = new Register(58, 24, "v24", SIMD);
+    public static final Register v25 = new Register(59, 25, "v25", SIMD);
+    public static final Register v26 = new Register(60, 26, "v26", SIMD);
+    public static final Register v27 = new Register(61, 27, "v27", SIMD);
+    public static final Register v28 = new Register(62, 28, "v28", SIMD);
+    public static final Register v29 = new Register(63, 29, "v29", SIMD);
+    public static final Register v30 = new Register(64, 30, "v30", SIMD);
+    public static final Register v31 = new Register(65, 31, "v31", SIMD);
 
     // @formatter:off
     public static final Register[] simdRegisters = {
@@ -136,6 +144,7 @@
         r8,  r9,  r10, r11, r12, r13, r14, r15,
         r16, r17, r18, r19, r20, r21, r22, r23,
         r24, r25, r26, r27, r28, r29, r30, r31,
+        zr,  sp,
 
         v0,  v1,  v2,  v3,  v4,  v5,  v6,  v7,
         v8,  v9,  v10, v11, v12, v13, v14, v15,
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java	Wed Feb 10 16:31:17 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java	Wed Feb 10 11:23:17 2016 -1000
@@ -31,6 +31,7 @@
 import static jdk.vm.ci.aarch64.AArch64.r28;
 import static jdk.vm.ci.aarch64.AArch64.r29;
 import static jdk.vm.ci.aarch64.AArch64.r3;
+import static jdk.vm.ci.aarch64.AArch64.r31;
 import static jdk.vm.ci.aarch64.AArch64.r4;
 import static jdk.vm.ci.aarch64.AArch64.r5;
 import static jdk.vm.ci.aarch64.AArch64.r6;
@@ -45,11 +46,13 @@
 import static jdk.vm.ci.aarch64.AArch64.v5;
 import static jdk.vm.ci.aarch64.AArch64.v6;
 import static jdk.vm.ci.aarch64.AArch64.v7;
+import static jdk.vm.ci.aarch64.AArch64.zr;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import jdk.vm.ci.aarch64.AArch64;
@@ -130,16 +133,20 @@
     public static final Register threadRegister = r28;
     public static final Register fp = r29;
 
+    private static final Register[] reservedRegisters = {threadRegister, fp, lr, r31, zr, sp};
+
     private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
         Register[] allRegisters = arch.getAvailableValueRegisters();
-        Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 5 : 4)];
+        Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
+        List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
 
         int idx = 0;
         for (Register reg : allRegisters) {
-            if (reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(sp)) {
-                // skip thread register, frame pointer, link register and stack pointer
+            if (reservedRegistersList.contains(reg)) {
+                // skip reserved registers
                 continue;
             }
+            assert !(reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(r31) || reg.equals(zr) || reg.equals(sp));
             if (reserveForHeapBase && reg.equals(heapBaseRegister)) {
                 // skip heap base register
                 continue;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Wed Feb 10 16:31:17 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Wed Feb 10 11:23:17 2016 -1000
@@ -45,6 +45,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import jdk.vm.ci.code.Architecture;
@@ -119,14 +120,17 @@
      */
     private final boolean needsNativeStackHomeSpace;
 
+    private static final Register[] reservedRegisters = {rsp, r15};
+
     private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
         Register[] allRegisters = arch.getAvailableValueRegisters();
-        Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 3 : 2)];
+        Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
+        List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
 
         int idx = 0;
         for (Register reg : allRegisters) {
-            if (reg.equals(rsp) || reg.equals(r15)) {
-                // skip stack pointer and thread register
+            if (reservedRegistersList.contains(reg)) {
+                // skip reserved registers
                 continue;
             }
             if (reserveForHeapBase && reg.equals(r12)) {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Wed Feb 10 16:31:17 2016 +0000
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Wed Feb 10 11:23:17 2016 -1000
@@ -68,6 +68,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.CallingConvention;
@@ -140,14 +141,17 @@
                     i0, i1, i2, i3, i4, i5, i6, i7};
     // @formatter:on
 
+    private static final Register[] reservedRegisters = {sp, g0, g2};
+
     private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
         Register[] allRegisters = arch.getAvailableValueRegisters();
-        Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 4 : 3)];
+        Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
+        List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
 
         int idx = 0;
         for (Register reg : allRegisters) {
-            if (reg.equals(sp) || reg.equals(g2) || reg.equals(g0)) {
-                // skip g0, stack pointer and thread register
+            if (reservedRegistersList.contains(reg)) {
+                // skip reserved registers
                 continue;
             }
             if (reserveForHeapBase && reg.equals(g6)) {