diff src/cpu/ppc/vm/interpreter_ppc.cpp @ 14445:67fa91961822

8029940: PPC64 (part 122): C2 compiler port Reviewed-by: kvn
author goetz
date Wed, 11 Dec 2013 00:06:11 +0100
parents ec28f9c041ff
children e5e8aa897002
line wrap: on
line diff
--- a/src/cpu/ppc/vm/interpreter_ppc.cpp	Tue Dec 10 14:29:43 2013 +0100
+++ b/src/cpu/ppc/vm/interpreter_ppc.cpp	Wed Dec 11 00:06:11 2013 +0100
@@ -396,18 +396,14 @@
   //
 
   Label done;
-  Label is_false;
-
   address entry = __ pc();
 
   switch (type) {
   case T_BOOLEAN:
-    __ cmpwi(CCR0, R3_RET, 0);
-    __ beq(CCR0, is_false);
-    __ li(R3_RET, 1);
-    __ b(done);
-    __ bind(is_false);
-    __ li(R3_RET, 0);
+    // convert !=0 to 1
+    __ neg(R0, R3_RET);
+    __ orr(R0, R3_RET, R0);
+    __ srwi(R3_RET, R0, 31);
     break;
   case T_BYTE:
      // sign extend 8 bits
@@ -478,7 +474,7 @@
 
   // Push a new C frame and save LR.
   __ save_LR_CR(R0);
-  __ push_frame_abi112_nonvolatiles(0, R11_scratch1);
+  __ push_frame_abi112(0, R11_scratch1);
 
   // This is not a leaf but we have a JavaFrameAnchor now and we will
   // check (create) exceptions afterward so this is ok.
@@ -491,8 +487,12 @@
   // Reset JavaFrameAnchor from call_VM_leaf above.
   __ reset_last_Java_frame();
 
+#ifdef CC_INTERP
   // Return to frame manager, it will handle the pending exception.
   __ blr();
+#else
+  Unimplemented();
+#endif
 
   return entry;
 }
@@ -503,16 +503,20 @@
   if(!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods)))
     return NULL;
 
-  Label Ldone, Lslow_path;
+  Label Lslow_path, Lacquire;
 
-  const Register Rthis = R3_ARG1,
+  const Register
+         Rclass_or_obj = R3_ARG1,
          Rconst_method = R4_ARG2,
          Rcodes        = Rconst_method,
          Rcpool_cache  = R5_ARG3,
          Rscratch      = R11_scratch1,
          Rjvmti_mode   = Rscratch,
          Roffset       = R12_scratch2,
-         Rflags        = R6_ARG4;
+         Rflags        = R6_ARG4,
+         Rbtable       = R7_ARG5;
+
+  static address branch_table[number_of_states];
 
   address entry = __ pc();
 
@@ -521,13 +525,9 @@
 
   // Also check for JVMTI mode
   // Check for null obj, take slow path if so.
-#ifdef CC_INTERP
-  __ ld(Rthis, Interpreter::stackElementSize, R17_tos);
-#else
-  Unimplemented()
-#endif
+  __ ld(Rclass_or_obj, Interpreter::stackElementSize, CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp));
   __ lwz(Rjvmti_mode, thread_(interp_only_mode));
-  __ cmpdi(CCR1, Rthis, 0);
+  __ cmpdi(CCR1, Rclass_or_obj, 0);
   __ cmpwi(CCR0, Rjvmti_mode, 0);
   __ crorc(/*CCR0 eq*/2, /*CCR1 eq*/4+2, /*CCR0 eq*/2);
   __ beq(CCR0, Lslow_path); // this==null or jvmti_mode!=0
@@ -560,58 +560,127 @@
   __ ld(Rflags, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcpool_cache);
   __ ld(Roffset, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f2_offset()), Rcpool_cache);
 
-  // Get field type.
-  // (Rflags>>ConstantPoolCacheEntry::tos_state_shift)&((1<<ConstantPoolCacheEntry::tos_state_bits)-1)
+  // Following code is from templateTable::getfield_or_static
+  // Load pointer to branch table
+  __ load_const_optimized(Rbtable, (address)branch_table, Rscratch);
+
+  // Get volatile flag
+  __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // extract volatile bit
+  // note: sync is needed before volatile load on PPC64
+
+  // Check field type
   __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);
 
 #ifdef ASSERT
-    __ ld(R9_ARG7, 0, R1_SP);
-    __ ld(R10_ARG8, 0, R21_sender_SP);
-    __ cmpd(CCR0, R9_ARG7, R10_ARG8);
-    __ asm_assert_eq("backlink", 0x543);
+  Label LFlagInvalid;
+  __ cmpldi(CCR0, Rflags, number_of_states);
+  __ bge(CCR0, LFlagInvalid);
+
+  __ ld(R9_ARG7, 0, R1_SP);
+  __ ld(R10_ARG8, 0, R21_sender_SP);
+  __ cmpd(CCR0, R9_ARG7, R10_ARG8);
+  __ asm_assert_eq("backlink", 0x543);
 #endif // ASSERT
   __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
 
-  // Load the return value according to field type.
-  Label Litos, Lltos, Lbtos, Lctos, Lstos;
-  __ cmpdi(CCR1, Rflags, itos);
-  __ cmpdi(CCR0, Rflags, ltos);
-  __ beq(CCR1, Litos);
-  __ beq(CCR0, Lltos);
-  __ cmpdi(CCR1, Rflags, btos);
-  __ cmpdi(CCR0, Rflags, ctos);
-  __ beq(CCR1, Lbtos);
-  __ beq(CCR0, Lctos);
-  __ cmpdi(CCR1, Rflags, stos);
-  __ beq(CCR1, Lstos);
+  // Load from branch table and dispatch (volatile case: one instruction ahead)
+  __ sldi(Rflags, Rflags, LogBytesPerWord);
+  __ cmpwi(CCR6, Rscratch, 1); // volatile?
+  __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // volatile ? size of 1 instruction : 0
+  __ ldx(Rbtable, Rbtable, Rflags);
+
+  __ subf(Rbtable, Rscratch, Rbtable); // point to volatile/non-volatile entry point
+  __ mtctr(Rbtable);
+  __ bctr();
+
 #ifdef ASSERT
-  __ cmpdi(CCR0, Rflags, atos);
-  __ asm_assert_eq("what type is this?", 0x432);
+  __ bind(LFlagInvalid);
+  __ stop("got invalid flag", 0x6541);
+
+  bool all_uninitialized = true,
+       all_initialized   = true;
+  for (int i = 0; i<number_of_states; ++i) {
+    all_uninitialized = all_uninitialized && (branch_table[i] == NULL);
+    all_initialized   = all_initialized   && (branch_table[i] != NULL);
+  }
+  assert(all_uninitialized != all_initialized, "consistency"); // either or
+
+  __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+  if (branch_table[vtos] == 0) branch_table[vtos] = __ pc(); // non-volatile_entry point
+  if (branch_table[dtos] == 0) branch_table[dtos] = __ pc(); // non-volatile_entry point
+  if (branch_table[ftos] == 0) branch_table[ftos] = __ pc(); // non-volatile_entry point
+  __ stop("unexpected type", 0x6551);
 #endif
-  // fallthru: __ bind(Latos);
-  __ load_heap_oop(R3_RET, (RegisterOrConstant)Roffset, Rthis);
+
+  if (branch_table[itos] == 0) { // generate only once
+    __ align(32, 28, 28); // align load
+    __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+    branch_table[itos] = __ pc(); // non-volatile_entry point
+    __ lwax(R3_RET, Rclass_or_obj, Roffset);
+    __ beq(CCR6, Lacquire);
+    __ blr();
+  }
+
+  if (branch_table[ltos] == 0) { // generate only once
+    __ align(32, 28, 28); // align load
+    __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+    branch_table[ltos] = __ pc(); // non-volatile_entry point
+    __ ldx(R3_RET, Rclass_or_obj, Roffset);
+    __ beq(CCR6, Lacquire);
+    __ blr();
+  }
+
+  if (branch_table[btos] == 0) { // generate only once
+    __ align(32, 28, 28); // align load
+    __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+    branch_table[btos] = __ pc(); // non-volatile_entry point
+    __ lbzx(R3_RET, Rclass_or_obj, Roffset);
+    __ extsb(R3_RET, R3_RET);
+    __ beq(CCR6, Lacquire);
+    __ blr();
+  }
+
+  if (branch_table[ctos] == 0) { // generate only once
+    __ align(32, 28, 28); // align load
+    __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+    branch_table[ctos] = __ pc(); // non-volatile_entry point
+    __ lhzx(R3_RET, Rclass_or_obj, Roffset);
+    __ beq(CCR6, Lacquire);
+    __ blr();
+  }
+
+  if (branch_table[stos] == 0) { // generate only once
+    __ align(32, 28, 28); // align load
+    __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+    branch_table[stos] = __ pc(); // non-volatile_entry point
+    __ lhax(R3_RET, Rclass_or_obj, Roffset);
+    __ beq(CCR6, Lacquire);
+    __ blr();
+  }
+
+  if (branch_table[atos] == 0) { // generate only once
+    __ align(32, 28, 28); // align load
+    __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+    branch_table[atos] = __ pc(); // non-volatile_entry point
+    __ load_heap_oop(R3_RET, (RegisterOrConstant)Roffset, Rclass_or_obj);
+    __ verify_oop(R3_RET);
+    //__ dcbt(R3_RET); // prefetch
+    __ beq(CCR6, Lacquire);
+    __ blr();
+  }
+
+  __ align(32, 12);
+  __ bind(Lacquire);
+  __ twi_0(R3_RET);
+  __ isync(); // acquire
   __ blr();
 
-  __ bind(Litos);
-  __ lwax(R3_RET, Rthis, Roffset);
-  __ blr();
-
-  __ bind(Lltos);
-  __ ldx(R3_RET, Rthis, Roffset);
-  __ blr();
-
-  __ bind(Lbtos);
-  __ lbzx(R3_RET, Rthis, Roffset);
-  __ extsb(R3_RET, R3_RET);
-  __ blr();
-
-  __ bind(Lctos);
-  __ lhzx(R3_RET, Rthis, Roffset);
-  __ blr();
-
-  __ bind(Lstos);
-  __ lhax(R3_RET, Rthis, Roffset);
-  __ blr();
+#ifdef ASSERT
+  for (int i = 0; i<number_of_states; ++i) {
+    assert(branch_table[i], "accessor_entry initialization");
+    //tty->print_cr("accessor_entry: branch_table[%d] = 0x%llx (opcode 0x%llx)", i, branch_table[i], *((unsigned int*)branch_table[i]));
+  }
+#endif
 
   __ bind(Lslow_path);
   assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now");
@@ -670,18 +739,14 @@
     // continue and the thread will safepoint at the next bytecode dispatch.
 
     // If the receiver is null then it is OK to jump to the slow path.
-#ifdef CC_INTERP
-     __ ld(R3_RET, Interpreter::stackElementSize, R17_tos); // get receiver
-#else
-     Unimplemented();
-#endif
+    __ ld(R3_RET, Interpreter::stackElementSize, CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp)); // get receiver
 
     // Check if receiver == NULL and go the slow path.
     __ cmpdi(CCR0, R3_RET, 0);
     __ beq(CCR0, slow_path);
 
     // Load the value of the referent field.
-    __ load_heap_oop_not_null(R3_RET, referent_offset, R3_RET);
+    __ load_heap_oop(R3_RET, referent_offset, R3_RET);
 
     // Generate the G1 pre-barrier code to log the value of
     // the referent field in an SATB buffer. Note with