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");