提交 18a8f53d 编写于 作者: V vkempik

8130309: Need to bailout cleanly if creation of stubs fails when codecache is out of space

Summary: Check for failed expansion of stub section in code buffer and bailout.
Reviewed-by: kvn, thartmann
上级 4ebeac0e
...@@ -94,7 +94,7 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { ...@@ -94,7 +94,7 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
const int IC_pos_in_java_to_interp_stub = 8; const int IC_pos_in_java_to_interp_stub = 8;
#define __ _masm. #define __ _masm.
void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
#ifdef COMPILER2 #ifdef COMPILER2
// Get the mark within main instrs section which is set to the address of the call. // Get the mark within main instrs section which is set to the address of the call.
address call_addr = cbuf.insts_mark(); address call_addr = cbuf.insts_mark();
...@@ -106,8 +106,7 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { ...@@ -106,8 +106,7 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
// Start the stub. // Start the stub.
address stub = __ start_a_stub(CompiledStaticCall::to_interp_stub_size()); address stub = __ start_a_stub(CompiledStaticCall::to_interp_stub_size());
if (stub == NULL) { if (stub == NULL) {
Compile::current()->env()->record_out_of_memory_failure(); return NULL; // CodeCache is full
return;
} }
// For java_to_interp stubs we use R11_scratch1 as scratch register // For java_to_interp stubs we use R11_scratch1 as scratch register
...@@ -149,6 +148,7 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { ...@@ -149,6 +148,7 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
// End the stub. // End the stub.
__ end_a_stub(); __ end_a_stub();
return stub;
#else #else
ShouldNotReachHere(); ShouldNotReachHere();
#endif #endif
......
...@@ -1171,7 +1171,7 @@ void CallStubImpl::emit_trampoline_stub(MacroAssembler &_masm, int destination_t ...@@ -1171,7 +1171,7 @@ void CallStubImpl::emit_trampoline_stub(MacroAssembler &_masm, int destination_t
// Start the stub. // Start the stub.
address stub = __ start_a_stub(Compile::MAX_stubs_size/2); address stub = __ start_a_stub(Compile::MAX_stubs_size/2);
if (stub == NULL) { if (stub == NULL) {
Compile::current()->env()->record_out_of_memory_failure(); ciEnv::current()->record_failure("CodeCache is full");
return; return;
} }
...@@ -1249,7 +1249,7 @@ EmitCallOffsets emit_call_with_trampoline_stub(MacroAssembler &_masm, address en ...@@ -1249,7 +1249,7 @@ EmitCallOffsets emit_call_with_trampoline_stub(MacroAssembler &_masm, address en
// Emit the trampoline stub which will be related to the branch-and-link below. // Emit the trampoline stub which will be related to the branch-and-link below.
CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, offsets.insts_call_instruction_offset); CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, offsets.insts_call_instruction_offset);
if (Compile::current()->env()->failing()) { return offsets; } // Code cache may be full. if (ciEnv::current()->failing()) { return offsets; } // Code cache may be full.
__ relocate(rtype); __ relocate(rtype);
} }
...@@ -3488,7 +3488,7 @@ encode %{ ...@@ -3488,7 +3488,7 @@ encode %{
// Emit the trampoline stub which will be related to the branch-and-link below. // Emit the trampoline stub which will be related to the branch-and-link below.
CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset);
if (Compile::current()->env()->failing()) { return; } // Code cache may be full. if (ciEnv::current()->failing()) { return; } // Code cache may be full.
__ relocate(_optimized_virtual ? __ relocate(_optimized_virtual ?
relocInfo::opt_virtual_call_type : relocInfo::static_call_type); relocInfo::opt_virtual_call_type : relocInfo::static_call_type);
} }
...@@ -3501,7 +3501,11 @@ encode %{ ...@@ -3501,7 +3501,11 @@ encode %{
__ bl(__ pc()); // Emits a relocation. __ bl(__ pc()); // Emits a relocation.
// The stub for call to interpreter. // The stub for call to interpreter.
CompiledStaticCall::emit_to_interp_stub(cbuf); address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
if (stub == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return;
}
} }
%} %}
...@@ -3546,7 +3550,11 @@ encode %{ ...@@ -3546,7 +3550,11 @@ encode %{
assert(_method, "execute next statement conditionally"); assert(_method, "execute next statement conditionally");
// The stub for call to interpreter. // The stub for call to interpreter.
CompiledStaticCall::emit_to_interp_stub(cbuf); address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
if (stub == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return;
}
// Restore original sp. // Restore original sp.
__ ld(R11_scratch1, 0, R1_SP); // Load caller sp. __ ld(R11_scratch1, 0, R1_SP); // Load caller sp.
......
...@@ -431,6 +431,9 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { ...@@ -431,6 +431,9 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
__ mov(length()->as_register(), O4); __ mov(length()->as_register(), O4);
ce->emit_static_call_stub(); ce->emit_static_call_stub();
if (ce->compilation()->bailed_out()) {
return; // CodeCache is full
}
__ call(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type); __ call(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type);
__ delayed()->nop(); __ delayed()->nop();
......
...@@ -53,7 +53,7 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { ...@@ -53,7 +53,7 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#define __ _masm. #define __ _masm.
void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
#ifdef COMPILER2 #ifdef COMPILER2
// Stub is fixed up when the corresponding call is converted from calling // Stub is fixed up when the corresponding call is converted from calling
// compiled code to calling interpreted code. // compiled code to calling interpreted code.
...@@ -64,9 +64,10 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { ...@@ -64,9 +64,10 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
address base = address base = __ start_a_stub(to_interp_stub_size());
__ start_a_stub(to_interp_stub_size()*2); if (base == NULL) {
if (base == NULL) return; // CodeBuffer::expand failed. return NULL; // CodeBuffer::expand failed.
}
// Static stub relocation stores the instruction address of the call. // Static stub relocation stores the instruction address of the call.
__ relocate(static_stub_Relocation::spec(mark)); __ relocate(static_stub_Relocation::spec(mark));
...@@ -81,6 +82,7 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { ...@@ -81,6 +82,7 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
// Update current stubs pointer and restore code_end. // Update current stubs pointer and restore code_end.
__ end_a_stub(); __ end_a_stub();
return base;
#else #else
ShouldNotReachHere(); ShouldNotReachHere();
#endif #endif
......
...@@ -1775,9 +1775,11 @@ int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { ...@@ -1775,9 +1775,11 @@ int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) {
AddressLiteral exception_blob(OptoRuntime::exception_blob()->entry_point()); AddressLiteral exception_blob(OptoRuntime::exception_blob()->entry_point());
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
address base = address base = __ start_a_stub(size_exception_handler());
__ start_a_stub(size_exception_handler()); if (base == NULL) {
if (base == NULL) return 0; // CodeBuffer::expand failed ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset(); int offset = __ offset();
...@@ -1798,9 +1800,11 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { ...@@ -1798,9 +1800,11 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) {
AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack()); AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack());
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
address base = address base = __ start_a_stub(size_deopt_handler());
__ start_a_stub(size_deopt_handler()); if (base == NULL) {
if (base == NULL) return 0; // CodeBuffer::expand failed ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset(); int offset = __ offset();
__ save_frame(0); __ save_frame(0);
...@@ -2601,7 +2605,12 @@ encode %{ ...@@ -2601,7 +2605,12 @@ encode %{
emit_call_reloc(cbuf, $meth$$method, relocInfo::static_call_type); emit_call_reloc(cbuf, $meth$$method, relocInfo::static_call_type);
} }
if (_method) { // Emit stub for static call. if (_method) { // Emit stub for static call.
CompiledStaticCall::emit_to_interp_stub(cbuf); address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
// Stub does not fit into scratch buffer if TraceJumps is enabled
if (stub == NULL && !(TraceJumps && Compile::current()->in_scratch_emit_size())) {
ciEnv::current()->record_failure("CodeCache is full");
return;
}
} }
%} %}
......
...@@ -502,6 +502,9 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { ...@@ -502,6 +502,9 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) {
ce->align_call(lir_static_call); ce->align_call(lir_static_call);
ce->emit_static_call_stub(); ce->emit_static_call_stub();
if (ce->compilation()->bailed_out()) {
return; // CodeCache is full
}
AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(), AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(),
relocInfo::static_call_type); relocInfo::static_call_type);
__ call(resolve); __ call(resolve);
......
...@@ -50,7 +50,7 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { ...@@ -50,7 +50,7 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#define __ _masm. #define __ _masm.
void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
// Stub is fixed up when the corresponding call is converted from // Stub is fixed up when the corresponding call is converted from
// calling compiled code to calling interpreted code. // calling compiled code to calling interpreted code.
// movq rbx, 0 // movq rbx, 0
...@@ -62,9 +62,10 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { ...@@ -62,9 +62,10 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
// That's why we must use the macroassembler to generate a stub. // That's why we must use the macroassembler to generate a stub.
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
address base = address base = __ start_a_stub(to_interp_stub_size());
__ start_a_stub(to_interp_stub_size()*2); if (base == NULL) {
if (base == NULL) return; // CodeBuffer::expand failed. return NULL; // CodeBuffer::expand failed.
}
// Static stub relocation stores the instruction address of the call. // Static stub relocation stores the instruction address of the call.
__ relocate(static_stub_Relocation::spec(mark), Assembler::imm_operand); __ relocate(static_stub_Relocation::spec(mark), Assembler::imm_operand);
// Static stub relocation also tags the Method* in the code-stream. // Static stub relocation also tags the Method* in the code-stream.
...@@ -74,6 +75,7 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { ...@@ -74,6 +75,7 @@ void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
// Update current stubs pointer and restore insts_end. // Update current stubs pointer and restore insts_end.
__ end_a_stub(); __ end_a_stub();
return base;
} }
#undef __ #undef __
......
...@@ -550,7 +550,10 @@ int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { ...@@ -550,7 +550,10 @@ int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) {
// That's why we must use the macroassembler to generate a handler. // That's why we must use the macroassembler to generate a handler.
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
address base = __ start_a_stub(size_exception_handler()); address base = __ start_a_stub(size_exception_handler());
if (base == NULL) return 0; // CodeBuffer::expand failed if (base == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset(); int offset = __ offset();
__ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); __ jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point()));
assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); assert(__ offset() - offset <= (int) size_exception_handler(), "overflow");
...@@ -565,7 +568,10 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { ...@@ -565,7 +568,10 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) {
// That's why we must use the macroassembler to generate a handler. // That's why we must use the macroassembler to generate a handler.
MacroAssembler _masm(&cbuf); MacroAssembler _masm(&cbuf);
address base = __ start_a_stub(size_deopt_handler()); address base = __ start_a_stub(size_deopt_handler());
if (base == NULL) return 0; // CodeBuffer::expand failed if (base == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return 0; // CodeBuffer::expand failed
}
int offset = __ offset(); int offset = __ offset();
#ifdef _LP64 #ifdef _LP64
......
...@@ -1870,7 +1870,11 @@ encode %{ ...@@ -1870,7 +1870,11 @@ encode %{
static_call_Relocation::spec(), RELOC_IMM32 ); static_call_Relocation::spec(), RELOC_IMM32 );
} }
if (_method) { // Emit stub for static call. if (_method) { // Emit stub for static call.
CompiledStaticCall::emit_to_interp_stub(cbuf); address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
if (stub == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return;
}
} }
%} %}
......
...@@ -2125,7 +2125,11 @@ encode %{ ...@@ -2125,7 +2125,11 @@ encode %{
} }
if (_method) { if (_method) {
// Emit stub for static call. // Emit stub for static call.
CompiledStaticCall::emit_to_interp_stub(cbuf); address stub = CompiledStaticCall::emit_to_interp_stub(cbuf);
if (stub == NULL) {
ciEnv::current()->record_failure("CodeCache is full");
return;
}
} }
%} %}
......
...@@ -60,8 +60,9 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) { ...@@ -60,8 +60,9 @@ bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
ShouldNotReachHere(); // Only needed for COMPILER2. ShouldNotReachHere(); // Only needed for COMPILER2.
return NULL;
} }
int CompiledStaticCall::to_interp_stub_size() { int CompiledStaticCall::to_interp_stub_size() {
......
...@@ -464,6 +464,7 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) { ...@@ -464,6 +464,7 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) {
// emit the static call stub stuff out of line // emit the static call stub stuff out of line
emit_static_call_stub(); emit_static_call_stub();
CHECK_BAILOUT();
switch (op->code()) { switch (op->code()) {
case lir_static_call: case lir_static_call:
......
...@@ -320,7 +320,7 @@ class CompiledStaticCall: public NativeCall { ...@@ -320,7 +320,7 @@ class CompiledStaticCall: public NativeCall {
friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site); friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site);
// Code // Code
static void emit_to_interp_stub(CodeBuffer &cbuf); static address emit_to_interp_stub(CodeBuffer &cbuf);
static int to_interp_stub_size(); static int to_interp_stub_size();
static int reloc_to_interp_stub(); static int reloc_to_interp_stub();
......
...@@ -608,6 +608,10 @@ uint Compile::scratch_emit_size(const Node* n) { ...@@ -608,6 +608,10 @@ uint Compile::scratch_emit_size(const Node* n) {
n->as_MachBranch()->label_set(&fakeL, 0); n->as_MachBranch()->label_set(&fakeL, 0);
} }
n->emit(buf, this->regalloc()); n->emit(buf, this->regalloc());
// Emitting into the scratch buffer should not fail
assert (!failing(), err_msg_res("Must not have pending failure. Reason is: %s", failure_reason()));
if (is_branch) // Restore label. if (is_branch) // Restore label.
n->as_MachBranch()->label_set(saveL, save_bnum); n->as_MachBranch()->label_set(saveL, save_bnum);
......
...@@ -1502,6 +1502,13 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { ...@@ -1502,6 +1502,13 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
n->emit(*cb, _regalloc); n->emit(*cb, _regalloc);
current_offset = cb->insts_size(); current_offset = cb->insts_size();
// Above we only verified that there is enough space in the instruction section.
// However, the instruction may emit stubs that cause code buffer expansion.
// Bail out here if expansion failed due to a lack of code cache space.
if (failing()) {
return;
}
#ifdef ASSERT #ifdef ASSERT
if (n->size(_regalloc) < (current_offset-instr_offset)) { if (n->size(_regalloc) < (current_offset-instr_offset)) {
n->dump(); n->dump();
...@@ -1630,11 +1637,14 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { ...@@ -1630,11 +1637,14 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
if (_method) { if (_method) {
// Emit the exception handler code. // Emit the exception handler code.
_code_offsets.set_value(CodeOffsets::Exceptions, HandlerImpl::emit_exception_handler(*cb)); _code_offsets.set_value(CodeOffsets::Exceptions, HandlerImpl::emit_exception_handler(*cb));
if (failing()) {
return; // CodeBuffer::expand failed
}
// Emit the deopt handler code. // Emit the deopt handler code.
_code_offsets.set_value(CodeOffsets::Deopt, HandlerImpl::emit_deopt_handler(*cb)); _code_offsets.set_value(CodeOffsets::Deopt, HandlerImpl::emit_deopt_handler(*cb));
// Emit the MethodHandle deopt handler code (if required). // Emit the MethodHandle deopt handler code (if required).
if (has_method_handle_invokes()) { if (has_method_handle_invokes() && !failing()) {
// We can use the same code as for the normal deopt handler, we // We can use the same code as for the normal deopt handler, we
// just need a different entry point address. // just need a different entry point address.
_code_offsets.set_value(CodeOffsets::DeoptMH, HandlerImpl::emit_deopt_handler(*cb)); _code_offsets.set_value(CodeOffsets::DeoptMH, HandlerImpl::emit_deopt_handler(*cb));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册