This commit is contained in:
Roland Westrelin 2014-07-09 02:50:46 -07:00
commit a03d25366a
11 changed files with 53 additions and 16 deletions

View file

@ -1997,7 +1997,13 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
if (!UseInlineCaches && is_loaded && code == Bytecodes::_invokevirtual
&& !target->can_be_statically_bound()) {
// Find a vtable index if one is available
vtable_index = target->resolve_vtable_index(calling_klass, callee_holder);
// For arrays, callee_holder is Object. Resolving the call with
// Object would allow an illegal call to finalize() on an
// array. We use holder instead: illegal calls to finalize() won't
// be compiled as vtable calls (IC call resolution will catch the
// illegal call) and the few legal calls on array types won't be
// either.
vtable_index = target->resolve_vtable_index(calling_klass, holder);
}
#endif

View file

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "code/vtableStubs.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/disassembler.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
@ -62,6 +63,7 @@ void* VtableStub::operator new(size_t size, int code_size) throw() {
// If changing the name, update the other file accordingly.
BufferBlob* blob = BufferBlob::create("vtable chunks", bytes);
if (blob == NULL) {
CompileBroker::handle_full_code_cache();
return NULL;
}
_chunk = blob->content_begin();

View file

@ -1093,6 +1093,7 @@ IRT_END
address SignatureHandlerLibrary::set_handler_blob() {
BufferBlob* handler_blob = BufferBlob::create("native signature handlers", blob_size);
if (handler_blob == NULL) {
CompileBroker::handle_full_code_cache();
return NULL;
}
address handler = handler_blob->code_begin();

View file

@ -871,8 +871,11 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
Node* receiver_node = kit.argument(0);
const TypeOopPtr* receiver_type = gvn.type(receiver_node)->isa_oopptr();
// call_does_dispatch and vtable_index are out-parameters. They might be changed.
target = C->optimize_virtual_call(caller, jvms->bci(), klass, target, receiver_type,
is_virtual,
// optimize_virtual_call() takes 2 different holder
// arguments for a corner case that doesn't apply here (see
// Parse::do_call())
target = C->optimize_virtual_call(caller, jvms->bci(), klass, klass,
target, receiver_type, is_virtual,
call_does_dispatch, vtable_index); // out-parameters
// We lack profiling at this call but type speculation may
// provide us with a type

View file

@ -29,6 +29,7 @@
#include "classfile/systemDictionary.hpp"
#include "code/exceptionHandlerTable.hpp"
#include "code/nmethod.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/disassembler.hpp"
#include "compiler/oopMap.hpp"
@ -555,6 +556,7 @@ void Compile::init_scratch_buffer_blob(int const_size) {
if (scratch_buffer_blob() == NULL) {
// Let CompilerBroker disable further compilations.
record_failure("Not enough space for scratch buffer in CodeCache");
CompileBroker::handle_full_code_cache();
return;
}
}

View file

@ -852,8 +852,8 @@ class Compile : public Phase {
// Helper functions to identify inlining potential at call-site
ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod* callee, const TypeOopPtr* receiver_type,
bool is_virtual,
ciKlass* holder, ciMethod* callee,
const TypeOopPtr* receiver_type, bool is_virtual,
bool &call_does_dispatch, int &vtable_index);
ciMethod* optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod* callee, const TypeOopPtr* receiver_type);

View file

@ -468,8 +468,14 @@ void Parse::do_call() {
Node* receiver_node = stack(sp() - nargs);
const TypeOopPtr* receiver_type = _gvn.type(receiver_node)->isa_oopptr();
// call_does_dispatch and vtable_index are out-parameters. They might be changed.
callee = C->optimize_virtual_call(method(), bci(), klass, orig_callee, receiver_type,
is_virtual,
// For arrays, klass below is Object. When vtable calls are used,
// resolving the call with Object would allow an illegal call to
// finalize() on an array. We use holder instead: illegal calls to
// finalize() won't be compiled as vtable calls (IC call
// resolution will catch the illegal call) and the few legal calls
// on array types won't be either.
callee = C->optimize_virtual_call(method(), bci(), klass, holder, orig_callee,
receiver_type, is_virtual,
call_does_dispatch, vtable_index); // out-parameters
speculative_receiver_type = receiver_type != NULL ? receiver_type->speculative_type() : NULL;
}
@ -940,8 +946,8 @@ void Parse::count_compiled_calls(bool at_method_entry, bool is_inline) {
ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod* callee, const TypeOopPtr* receiver_type,
bool is_virtual,
ciKlass* holder, ciMethod* callee,
const TypeOopPtr* receiver_type, bool is_virtual,
bool& call_does_dispatch, int& vtable_index) {
// Set default values for out-parameters.
call_does_dispatch = true;
@ -956,7 +962,7 @@ ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKl
call_does_dispatch = false;
} else if (!UseInlineCaches && is_virtual && callee->is_loaded()) {
// We can make a vtable call at this site
vtable_index = callee->resolve_vtable_index(caller->holder(), klass);
vtable_index = callee->resolve_vtable_index(caller->holder(), holder);
}
return callee;
}
@ -979,8 +985,10 @@ ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass*
ciInstanceKlass* actual_receiver = klass;
if (receiver_type != NULL) {
// Array methods are all inherited from Object, and are monomorphic.
// finalize() call on array is not allowed.
if (receiver_type->isa_aryptr() &&
callee->holder() == env()->Object_klass()) {
callee->holder() == env()->Object_klass() &&
callee->name() != ciSymbol::finalize_method_name()) {
return callee;
}

View file

@ -1163,6 +1163,7 @@ CodeBuffer* Compile::init_buffer(uint* blk_starts) {
// Have we run out of code space?
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
C->record_failure("CodeCache is full");
CompileBroker::handle_full_code_cache();
return NULL;
}
// Configure the code buffer.
@ -1487,6 +1488,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
cb->insts()->maybe_expand_to_ensure_remaining(MAX_inst_size);
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
C->record_failure("CodeCache is full");
CompileBroker::handle_full_code_cache();
return;
}
@ -1643,6 +1645,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) {
// One last check for failed CodeBuffer::expand:
if ((cb->blob() == NULL) || (!CompileBroker::should_compile_new_jobs())) {
C->record_failure("CodeCache is full");
CompileBroker::handle_full_code_cache();
return;
}

View file

@ -557,8 +557,9 @@ class Parse : public GraphKit {
float dynamic_branch_prediction(float &cnt);
float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci);
bool seems_never_taken(float prob);
bool seems_stable_comparison(BoolTest::mask btest, Node* c);
bool seems_never_taken(float prob) const;
bool path_is_suitable_for_uncommon_trap(float prob) const;
bool seems_stable_comparison() const;
void do_ifnull(BoolTest::mask btest, Node* c);
void do_if(BoolTest::mask btest, Node* c);

View file

@ -886,7 +886,7 @@ float Parse::branch_prediction(float& cnt,
// some branches (e.g., _213_javac.Assembler.eliminate) validly produce
// very small but nonzero probabilities, which if confused with zero
// counts would keep the program recompiling indefinitely.
bool Parse::seems_never_taken(float prob) {
bool Parse::seems_never_taken(float prob) const {
return prob < PROB_MIN;
}
@ -898,7 +898,7 @@ bool Parse::seems_never_taken(float prob) {
// already acting in a stable fashion. If the comparison
// seems stable, we will put an expensive uncommon trap
// on the untaken path.
bool Parse::seems_stable_comparison(BoolTest::mask btest, Node* cmp) {
bool Parse::seems_stable_comparison() const {
if (C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if)) {
return false;
}
@ -1127,6 +1127,14 @@ void Parse::do_if(BoolTest::mask btest, Node* c) {
}
}
bool Parse::path_is_suitable_for_uncommon_trap(float prob) const {
// Don't want to speculate on uncommon traps when running with -Xcomp
if (!UseInterpreter) {
return false;
}
return (seems_never_taken(prob) && seems_stable_comparison());
}
//----------------------------adjust_map_after_if------------------------------
// Adjust the JVM state to reflect the result of taking this path.
// Basically, it means inspecting the CmpNode controlling this
@ -1140,7 +1148,7 @@ void Parse::adjust_map_after_if(BoolTest::mask btest, Node* c, float prob,
bool is_fallthrough = (path == successor_for_bci(iter().next_bci()));
if (seems_never_taken(prob) && seems_stable_comparison(btest, c)) {
if (path_is_suitable_for_uncommon_trap(prob)) {
repush_if_args();
uncommon_trap(Deoptimization::Reason_unstable_if,
Deoptimization::Action_reinterpret,

View file

@ -34,6 +34,9 @@ void AbstractICache::initialize() {
ResourceMark rm;
BufferBlob* b = BufferBlob::create("flush_icache_stub", ICache::stub_size);
if (b == NULL) {
vm_exit_out_of_memory(ICache::stub_size, OOM_MALLOC_ERROR, "CodeCache: no space for flush_icache_stub");
}
CodeBuffer c(b);
ICacheStubGenerator g(&c);