src/cpu/x86/vm/c1_LIRAssembler_x86.cpp

Print this page
rev 2893 : 7121756: Improve C1 inlining policy by using profiling at call sites
Summary: profile based recompilation of methods with C1 with more inlining.
Reviewed-by:

@@ -2849,10 +2849,23 @@
   RelocationHolder rh = virtual_call_Relocation::spec(pc());
   __ movoop(IC_Klass, (jobject)Universe::non_oop_word());
   assert(!os::is_MP() ||
          (__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0,
          "must be aligned");
+
+  if (op->info()->is_profiled_call()) {
+    // The static call stub is not used for standard ic calls (a
+    // transition stub is allocated instead for calls to the
+    // interpreter). We emit the static call stub for profiled call
+    // sites anyway because the runtime locates the profile call stub
+    // by first looking up the static call stub and then walking over
+    // it to the profile call stub.
+    emit_static_call_stub();
+    // Emit the profile call stub right behind the static call stub
+    emit_profile_call_stub(op->info()->method(), op->info()->stack()->bci(), SharedRuntime::get_resolve_profile_call_stub());
+  }
+
   __ call(AddressLiteral(op->addr(), rh));
   add_call_info(code_offset(), op->info());
 }
 
 

@@ -2887,10 +2900,60 @@
 
   assert(__ offset() - start <= call_stub_size, "stub too big");
   __ end_a_stub();
 }
 
+void LIR_Assembler::emit_profile_call_stub(ciMethod* method, int bci, address dest) {
+  ciMethodData* md = method->method_data();
+  if (md == NULL) {
+    bailout("out of memory building methodDataOop");
+    return;
+  }
+  address call_pc = __ pc();
+  address stub = __ start_a_stub(profile_call_stub_size);
+  if (stub == NULL) {
+    bailout("profile call stub overflow");
+    return;
+  }
+
+  int start = __ offset();
+  address off_addr = __ pc();
+  
+  // The runtime needs the starting address of the profile call stub
+  // (to make the call site jump to the stub) and the location of the
+  // first jump in the stub (to make it branch to the callee). The
+  // starting address is found by first looking up the static call
+  // stub and then finding the profile call stub right behind
+  // it. Finding the jump is tricky because the code emitted before it
+  // depends on runtime conditions. Here, we first emit an integer (0)
+  // that we change to contain the offset of the jump within the stub
+  // when the jump is emitted and the offset is known. Locating the
+  // jump can then be done from the runtime by reading this offset and
+  // adding it to the address of the start of the stub.
+  __ a_long(0);
+  
+  ciProfileData* data = md->bci_to_data(bci);
+  assert(data->is_CounterData(), "need CounterData for calls");
+
+  Register tmp = NOT_LP64(rdi) LP64_ONLY(r12);
+
+  __ movoop(tmp, md->constant_encoding());
+  Address counter_addr(tmp, md->byte_offset_of_slot(data, CounterData::count_offset()));
+  __ addl(counter_addr, DataLayout::counter_increment);
+  __ cmpl(counter_addr, C1ProfileCompileThreshold);
+  Label L;
+  __ jcc(Assembler::greater, L);
+
+  *(jint*)off_addr = __ offset() - start;
+  __ jump(RuntimeAddress(__ pc()));
+  
+  __ bind(L);
+  __ jump(RuntimeAddress(dest));
+
+  assert(__ offset() - start <= profile_call_stub_size, "stub too big");
+  __ end_a_stub();
+}
 
 void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) {
   assert(exceptionOop->as_register() == rax, "must match");
   assert(exceptionPC->as_register() == rdx, "must match");