--- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -675,7 +675,7 @@
case handle_exception_nofpu_id:
case handle_exception_id:
// At this point all registers MAY be live.
- oop_map = save_live_registers(sasm, 1 /*thread*/, id == handle_exception_nofpu_id);
+ oop_map = save_live_registers(sasm, 1 /*thread*/, id != handle_exception_nofpu_id);
break;
case handle_exception_from_callee_id: {
// At this point all registers except exception oop (RAX) and
@@ -748,7 +748,7 @@
case handle_exception_nofpu_id:
case handle_exception_id:
// Restore the registers that were saved at the beginning.
- restore_live_registers(sasm, id == handle_exception_nofpu_id);
+ restore_live_registers(sasm, id != handle_exception_nofpu_id);
break;
case handle_exception_from_callee_id:
// WIN64_ONLY: No need to add frame::arg_reg_save_area_bytes to SP
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -385,6 +385,18 @@
int handler_bci;
int current_bci = bci(thread);
+ if (thread->frames_to_pop_failed_realloc() > 0) {
+ // Allocation of scalar replaced object used in this frame
+ // failed. Unconditionally pop the frame.
+ thread->dec_frames_to_pop_failed_realloc();
+ thread->set_vm_result(h_exception());
+ // If the method is synchronized we already unlocked the monitor
+ // during deoptimization so the interpreter needs to skip it when
+ // the frame is popped.
+ thread->set_do_not_unlock_if_synchronized(true);
+ return Interpreter::remove_activation_entry();
+ }
+
// Need to do this check first since when _do_not_unlock_if_synchronized
// is set, we don't want to trigger any classloading which may make calls
// into java, or surprisingly find a matching exception handler for bci 0
--- a/hotspot/src/share/vm/memory/universe.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/memory/universe.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -120,6 +120,7 @@
oop Universe::_out_of_memory_error_class_metaspace = NULL;
oop Universe::_out_of_memory_error_array_size = NULL;
oop Universe::_out_of_memory_error_gc_overhead_limit = NULL;
+oop Universe::_out_of_memory_error_realloc_objects = NULL;
objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL;
volatile jint Universe::_preallocated_out_of_memory_error_avail_count = 0;
bool Universe::_verify_in_progress = false;
@@ -191,6 +192,7 @@
f->do_oop((oop*)&_out_of_memory_error_class_metaspace);
f->do_oop((oop*)&_out_of_memory_error_array_size);
f->do_oop((oop*)&_out_of_memory_error_gc_overhead_limit);
+ f->do_oop((oop*)&_out_of_memory_error_realloc_objects);
f->do_oop((oop*)&_preallocated_out_of_memory_error_array);
f->do_oop((oop*)&_null_ptr_exception_instance);
f->do_oop((oop*)&_arithmetic_exception_instance);
@@ -575,7 +577,8 @@
(throwable() != Universe::_out_of_memory_error_metaspace) &&
(throwable() != Universe::_out_of_memory_error_class_metaspace) &&
(throwable() != Universe::_out_of_memory_error_array_size) &&
- (throwable() != Universe::_out_of_memory_error_gc_overhead_limit));
+ (throwable() != Universe::_out_of_memory_error_gc_overhead_limit) &&
+ (throwable() != Universe::_out_of_memory_error_realloc_objects));
}
@@ -1039,6 +1042,7 @@
Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_gc_overhead_limit =
k_h->allocate_instance(CHECK_false);
+ Universe::_out_of_memory_error_realloc_objects = k_h->allocate_instance(CHECK_false);
// Setup preallocated NullPointerException
// (this is currently used for a cheap & dirty solution in compiler exception handling)
@@ -1078,6 +1082,9 @@
msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false);
java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg());
+ msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK_false);
+ java_lang_Throwable::set_message(Universe::_out_of_memory_error_realloc_objects, msg());
+
msg = java_lang_String::create_from_str("/ by zero", CHECK_false);
java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg());
--- a/hotspot/src/share/vm/memory/universe.hpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/memory/universe.hpp Thu Dec 11 16:22:47 2014 -0800
@@ -157,6 +157,7 @@
static oop _out_of_memory_error_class_metaspace;
static oop _out_of_memory_error_array_size;
static oop _out_of_memory_error_gc_overhead_limit;
+ static oop _out_of_memory_error_realloc_objects;
static Array<int>* _the_empty_int_array; // Canonicalized int array
static Array<u2>* _the_empty_short_array; // Canonicalized short array
@@ -328,6 +329,7 @@
static oop out_of_memory_error_class_metaspace() { return gen_out_of_memory_error(_out_of_memory_error_class_metaspace); }
static oop out_of_memory_error_array_size() { return gen_out_of_memory_error(_out_of_memory_error_array_size); }
static oop out_of_memory_error_gc_overhead_limit() { return gen_out_of_memory_error(_out_of_memory_error_gc_overhead_limit); }
+ static oop out_of_memory_error_realloc_objects() { return gen_out_of_memory_error(_out_of_memory_error_realloc_objects); }
// Accessors needed for fast allocation
static Klass** boolArrayKlassObj_addr() { return &_boolArrayKlassObj; }
--- a/hotspot/src/share/vm/opto/castnode.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/opto/castnode.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -104,7 +104,8 @@
// Try to improve the type of the CastII if we recognize a CmpI/If
// pattern.
if (_carry_dependency) {
- if (in(0) != NULL && (in(0)->is_IfFalse() || in(0)->is_IfTrue())) {
+ if (in(0) != NULL && in(0)->in(0) != NULL && in(0)->in(0)->is_If()) {
+ assert(in(0)->is_IfFalse() || in(0)->is_IfTrue(), "should be If proj");
Node* proj = in(0);
if (proj->in(0)->in(1)->is_Bool()) {
Node* b = proj->in(0)->in(1);
--- a/hotspot/src/share/vm/opto/ifnode.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/opto/ifnode.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -820,6 +820,11 @@
static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff);
+struct RangeCheck {
+ Node* ctl;
+ jint off;
+};
+
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node. Strip out
// control copies
@@ -861,83 +866,141 @@
jint offset1;
int flip1 = is_range_check(range1, index1, offset1);
if( flip1 ) {
- Node *first_prev_dom = NULL;
-
// Try to remove extra range checks. All 'up_one_dom' gives up at merges
// so all checks we inspect post-dominate the top-most check we find.
// If we are going to fail the current check and we reach the top check
// then we are guaranteed to fail, so just start interpreting there.
- // We 'expand' the top 2 range checks to include all post-dominating
+ // We 'expand' the top 3 range checks to include all post-dominating
// checks.
- // The top 2 range checks seen
- Node *prev_chk1 = NULL;
- Node *prev_chk2 = NULL;
+ // The top 3 range checks seen
+ const int NRC =3;
+ RangeCheck prev_checks[NRC];
+ int nb_checks = 0;
+
// Low and high offsets seen so far
jint off_lo = offset1;
jint off_hi = offset1;
- // Scan for the top 2 checks and collect range of offsets
- for( int dist = 0; dist < 999; dist++ ) { // Range-Check scan limit
- if( dom->Opcode() == Op_If && // Not same opcode?
- prev_dom->in(0) == dom ) { // One path of test does dominate?
- if( dom == this ) return NULL; // dead loop
+ bool found_immediate_dominator = false;
+
+ // Scan for the top checks and collect range of offsets
+ for (int dist = 0; dist < 999; dist++) { // Range-Check scan limit
+ if (dom->Opcode() == Op_If && // Not same opcode?
+ prev_dom->in(0) == dom) { // One path of test does dominate?
+ if (dom == this) return NULL; // dead loop
// See if this is a range check
Node *index2, *range2;
jint offset2;
int flip2 = dom->as_If()->is_range_check(range2, index2, offset2);
// See if this is a _matching_ range check, checking against
// the same array bounds.
- if( flip2 == flip1 && range2 == range1 && index2 == index1 &&
- dom->outcnt() == 2 ) {
+ if (flip2 == flip1 && range2 == range1 && index2 == index1 &&
+ dom->outcnt() == 2) {
+ if (nb_checks == 0 && dom->in(1) == in(1)) {
+ // Found an immediately dominating test at the same offset.
+ // This kind of back-to-back test can be eliminated locally,
+ // and there is no need to search further for dominating tests.
+ assert(offset2 == offset1, "Same test but different offsets");
+ found_immediate_dominator = true;
+ break;
+ }
// Gather expanded bounds
off_lo = MIN2(off_lo,offset2);
off_hi = MAX2(off_hi,offset2);
- // Record top 2 range checks
- prev_chk2 = prev_chk1;
- prev_chk1 = prev_dom;
- // If we match the test exactly, then the top test covers
- // both our lower and upper bounds.
- if( dom->in(1) == in(1) )
- prev_chk2 = prev_chk1;
+ // Record top NRC range checks
+ prev_checks[nb_checks%NRC].ctl = prev_dom;
+ prev_checks[nb_checks%NRC].off = offset2;
+ nb_checks++;
}
}
prev_dom = dom;
- dom = up_one_dom( dom );
- if( !dom ) break;
+ dom = up_one_dom(dom);
+ if (!dom) break;
}
-
- // Attempt to widen the dominating range check to cover some later
- // ones. Since range checks "fail" by uncommon-trapping to the
- // interpreter, widening a check can make us speculative enter the
- // interpreter. If we see range-check deopt's, do not widen!
- if (!phase->C->allow_range_check_smearing()) return NULL;
+ if (!found_immediate_dominator) {
+ // Attempt to widen the dominating range check to cover some later
+ // ones. Since range checks "fail" by uncommon-trapping to the
+ // interpreter, widening a check can make us speculatively enter
+ // the interpreter. If we see range-check deopt's, do not widen!
+ if (!phase->C->allow_range_check_smearing()) return NULL;
- // Constant indices only need to check the upper bound.
- // Non-constance indices must check both low and high.
- if( index1 ) {
- // Didn't find 2 prior covering checks, so cannot remove anything.
- if( !prev_chk2 ) return NULL;
- // 'Widen' the offsets of the 1st and 2nd covering check
- adjust_check( prev_chk1, range1, index1, flip1, off_lo, igvn );
- // Do not call adjust_check twice on the same projection
- // as the first call may have transformed the BoolNode to a ConI
- if( prev_chk1 != prev_chk2 ) {
- adjust_check( prev_chk2, range1, index1, flip1, off_hi, igvn );
+ // Didn't find prior covering check, so cannot remove anything.
+ if (nb_checks == 0) {
+ return NULL;
}
- // Test is now covered by prior checks, dominate it out
- prev_dom = prev_chk2;
- } else {
- // Didn't find prior covering check, so cannot remove anything.
- if( !prev_chk1 ) return NULL;
- // 'Widen' the offset of the 1st and only covering check
- adjust_check( prev_chk1, range1, index1, flip1, off_hi, igvn );
- // Test is now covered by prior checks, dominate it out
- prev_dom = prev_chk1;
+ // Constant indices only need to check the upper bound.
+ // Non-constant indices must check both low and high.
+ int chk0 = (nb_checks - 1) % NRC;
+ if (index1) {
+ if (nb_checks == 1) {
+ return NULL;
+ } else {
+ // If the top range check's constant is the min or max of
+ // all constants we widen the next one to cover the whole
+ // range of constants.
+ RangeCheck rc0 = prev_checks[chk0];
+ int chk1 = (nb_checks - 2) % NRC;
+ RangeCheck rc1 = prev_checks[chk1];
+ if (rc0.off == off_lo) {
+ adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn);
+ prev_dom = rc1.ctl;
+ } else if (rc0.off == off_hi) {
+ adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn);
+ prev_dom = rc1.ctl;
+ } else {
+ // If the top test's constant is not the min or max of all
+ // constants, we need 3 range checks. We must leave the
+ // top test unchanged because widening it would allow the
+ // accesses it protects to successfully read/write out of
+ // bounds.
+ if (nb_checks == 2) {
+ return NULL;
+ }
+ int chk2 = (nb_checks - 3) % NRC;
+ RangeCheck rc2 = prev_checks[chk2];
+ // The top range check a+i covers interval: -a <= i < length-a
+ // The second range check b+i covers interval: -b <= i < length-b
+ if (rc1.off <= rc0.off) {
+ // if b <= a, we change the second range check to:
+ // -min_of_all_constants <= i < length-min_of_all_constants
+ // Together top and second range checks now cover:
+ // -min_of_all_constants <= i < length-a
+ // which is more restrictive than -b <= i < length-b:
+ // -b <= -min_of_all_constants <= i < length-a <= length-b
+ // The third check is then changed to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // so 2nd and 3rd checks restrict allowed values of i to:
+ // -min_of_all_constants <= i < length-max_of_all_constants
+ adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn);
+ adjust_check(rc2.ctl, range1, index1, flip1, off_hi, igvn);
+ } else {
+ // if b > a, we change the second range check to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // Together top and second range checks now cover:
+ // -a <= i < length-max_of_all_constants
+ // which is more restrictive than -b <= i < length-b:
+ // -b < -a <= i < length-max_of_all_constants <= length-b
+ // The third check is then changed to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // so 2nd and 3rd checks restrict allowed values of i to:
+ // -min_of_all_constants <= i < length-max_of_all_constants
+ adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn);
+ adjust_check(rc2.ctl, range1, index1, flip1, off_lo, igvn);
+ }
+ prev_dom = rc2.ctl;
+ }
+ }
+ } else {
+ RangeCheck rc0 = prev_checks[chk0];
+ // 'Widen' the offset of the 1st and only covering check
+ adjust_check(rc0.ctl, range1, index1, flip1, off_hi, igvn);
+ // Test is now covered by prior checks, dominate it out
+ prev_dom = rc0.ctl;
+ }
}
-
} else { // Scan for an equivalent test
Node *cmp;
@@ -1019,7 +1082,7 @@
// for lower and upper bounds.
ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj();
if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate))
- prev_dom = idom;
+ prev_dom = idom;
// Now walk the current IfNode's projections.
// Loop ends when 'this' has no more uses.
--- a/hotspot/src/share/vm/opto/loopopts.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/opto/loopopts.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -241,8 +241,13 @@
ProjNode* dp_proj = dp->as_Proj();
ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj();
if (exclude_loop_predicate &&
- unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate))
+ (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) ||
+ unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check))) {
+ // If this is a range check (IfNode::is_range_check), do not
+ // reorder because Compile::allow_range_check_smearing might have
+ // changed the check.
return; // Let IGVN transformation change control dependence.
+ }
IdealLoopTree *old_loop = get_loop(dp);
@@ -898,23 +903,23 @@
int n_op = n->Opcode();
// Check for an IF being dominated by another IF same test
- if( n_op == Op_If ) {
+ if (n_op == Op_If) {
Node *bol = n->in(1);
uint max = bol->outcnt();
// Check for same test used more than once?
- if( n_op == Op_If && max > 1 && bol->is_Bool() ) {
+ if (max > 1 && bol->is_Bool()) {
// Search up IDOMs to see if this IF is dominated.
Node *cutoff = get_ctrl(bol);
// Now search up IDOMs till cutoff, looking for a dominating test
Node *prevdom = n;
Node *dom = idom(prevdom);
- while( dom != cutoff ) {
- if( dom->req() > 1 && dom->in(1) == bol && prevdom->in(0) == dom ) {
+ while (dom != cutoff) {
+ if (dom->req() > 1 && dom->in(1) == bol && prevdom->in(0) == dom) {
// Replace the dominated test with an obvious true or false.
// Place it on the IGVN worklist for later cleanup.
C->set_major_progress();
- dominated_by( prevdom, n, false, true );
+ dominated_by(prevdom, n, false, true);
#ifndef PRODUCT
if( VerifyLoopOptimizations ) verify();
#endif
--- a/hotspot/src/share/vm/opto/macro.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/opto/macro.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -971,7 +971,11 @@
}
bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
- if (!EliminateAllocations || !alloc->_is_non_escaping) {
+ // Don't do scalar replacement if the frame can be popped by JVMTI:
+ // if reallocation fails during deoptimization we'll pop all
+ // interpreter frames for this compiled frame and that won't play
+ // nice with JVMTI popframe.
+ if (!EliminateAllocations || JvmtiExport::can_pop_frame() || !alloc->_is_non_escaping) {
return false;
}
Node* klass = alloc->in(AllocateNode::KlassNode);
--- a/hotspot/src/share/vm/prims/whitebox.hpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/prims/whitebox.hpp Thu Dec 11 16:22:47 2014 -0800
@@ -74,7 +74,7 @@
static JavaThread* create_sweeper_thread(TRAPS);
static int get_blob_type(const CodeBlob* code);
static CodeHeap* get_code_heap(int blob_type);
- static CodeBlob* allocate_code_blob(int blob_type, int size);
+ static CodeBlob* allocate_code_blob(int size, int blob_type);
static int array_bytes_to_length(size_t bytes);
static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread,
JNINativeMethod* method_array, int method_count);
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -176,6 +176,8 @@
assert(vf->is_compiled_frame(), "Wrong frame type");
chunk->push(compiledVFrame::cast(vf));
+ bool realloc_failures = false;
+
#ifdef COMPILER2
// Reallocate the non-escaping objects and restore their fields. Then
// relock objects if synchronization on them was eliminated.
@@ -206,19 +208,16 @@
tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, (void *)result, thread);
}
}
- bool reallocated = false;
if (objects != NULL) {
JRT_BLOCK
- reallocated = realloc_objects(thread, &deoptee, objects, THREAD);
+ realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD);
JRT_END
- }
- if (reallocated) {
- reassign_fields(&deoptee, &map, objects);
+ reassign_fields(&deoptee, &map, objects, realloc_failures);
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread);
- print_objects(objects);
+ print_objects(objects, realloc_failures);
}
#endif
}
@@ -236,7 +235,7 @@
assert (cvf->scope() != NULL,"expect only compiled java frames");
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
if (monitors->is_nonempty()) {
- relock_objects(monitors, thread);
+ relock_objects(monitors, thread, realloc_failures);
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
@@ -247,7 +246,12 @@
first = false;
tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread);
}
- tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner());
+ if (mi->owner_is_scalar_replaced()) {
+ Klass* k = java_lang_Class::as_Klass(mi->owner_klass());
+ tty->print_cr(" failed reallocation for klass %s", k->external_name());
+ } else {
+ tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner());
+ }
}
}
}
@@ -262,9 +266,14 @@
// out the java state residing in the vframeArray will be missed.
No_Safepoint_Verifier no_safepoint;
- vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk);
+ vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures);
+#ifdef COMPILER2
+ if (realloc_failures) {
+ pop_frames_failed_reallocs(thread, array);
+ }
+#endif
- assert(thread->vframe_array_head() == NULL, "Pending deopt!");;
+ assert(thread->vframe_array_head() == NULL, "Pending deopt!");
thread->set_vframe_array_head(array);
// Now that the vframeArray has been created if we have any deferred local writes
@@ -718,6 +727,8 @@
int exception_line = thread->exception_line();
thread->clear_pending_exception();
+ bool failures = false;
+
for (int i = 0; i < objects->length(); i++) {
assert(objects->at(i)->is_object(), "invalid debug information");
ObjectValue* sv = (ObjectValue*) objects->at(i);
@@ -727,27 +738,34 @@
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k());
- obj = ik->allocate_instance(CHECK_(false));
+ obj = ik->allocate_instance(THREAD);
} else if (k->oop_is_typeArray()) {
TypeArrayKlass* ak = TypeArrayKlass::cast(k());
assert(sv->field_size() % type2size[ak->element_type()] == 0, "non-integral array length");
int len = sv->field_size() / type2size[ak->element_type()];
- obj = ak->allocate(len, CHECK_(false));
+ obj = ak->allocate(len, THREAD);
} else if (k->oop_is_objArray()) {
ObjArrayKlass* ak = ObjArrayKlass::cast(k());
- obj = ak->allocate(sv->field_size(), CHECK_(false));
+ obj = ak->allocate(sv->field_size(), THREAD);
}
- assert(obj != NULL, "allocation failed");
+ if (obj == NULL) {
+ failures = true;
+ }
+
assert(sv->value().is_null(), "redundant reallocation");
+ assert(obj != NULL || HAS_PENDING_EXCEPTION, "allocation should succeed or we should get an exception");
+ CLEAR_PENDING_EXCEPTION;
sv->set_value(obj);
}
- if (pending_exception.not_null()) {
+ if (failures) {
+ THROW_OOP_(Universe::out_of_memory_error_realloc_objects(), failures);
+ } else if (pending_exception.not_null()) {
thread->set_pending_exception(pending_exception(), exception_file, exception_line);
}
- return true;
+ return failures;
}
// This assumes that the fields are stored in ObjectValue in the same order
@@ -885,12 +903,15 @@
// restore fields of all eliminated objects and arrays
-void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects) {
+void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures) {
for (int i = 0; i < objects->length(); i++) {
ObjectValue* sv = (ObjectValue*) objects->at(i);
KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()));
Handle obj = sv->value();
- assert(obj.not_null(), "reallocation was missed");
+ assert(obj.not_null() || realloc_failures, "reallocation was missed");
+ if (obj.is_null()) {
+ continue;
+ }
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k());
@@ -907,34 +928,36 @@
// relock objects for which synchronization was eliminated
-void Deoptimization::relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread) {
+void Deoptimization::relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread, bool realloc_failures) {
for (int i = 0; i < monitors->length(); i++) {
MonitorInfo* mon_info = monitors->at(i);
if (mon_info->eliminated()) {
- assert(mon_info->owner() != NULL, "reallocation was missed");
- Handle obj = Handle(mon_info->owner());
- markOop mark = obj->mark();
- if (UseBiasedLocking && mark->has_bias_pattern()) {
- // New allocated objects may have the mark set to anonymously biased.
- // Also the deoptimized method may called methods with synchronization
- // where the thread-local object is bias locked to the current thread.
- assert(mark->is_biased_anonymously() ||
- mark->biased_locker() == thread, "should be locked to current thread");
- // Reset mark word to unbiased prototype.
- markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
- obj->set_mark(unbiased_prototype);
+ assert(!mon_info->owner_is_scalar_replaced() || realloc_failures, "reallocation was missed");
+ if (!mon_info->owner_is_scalar_replaced()) {
+ Handle obj = Handle(mon_info->owner());
+ markOop mark = obj->mark();
+ if (UseBiasedLocking && mark->has_bias_pattern()) {
+ // New allocated objects may have the mark set to anonymously biased.
+ // Also the deoptimized method may called methods with synchronization
+ // where the thread-local object is bias locked to the current thread.
+ assert(mark->is_biased_anonymously() ||
+ mark->biased_locker() == thread, "should be locked to current thread");
+ // Reset mark word to unbiased prototype.
+ markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
+ obj->set_mark(unbiased_prototype);
+ }
+ BasicLock* lock = mon_info->lock();
+ ObjectSynchronizer::slow_enter(obj, lock, thread);
+ assert(mon_info->owner()->is_locked(), "object must be locked now");
}
- BasicLock* lock = mon_info->lock();
- ObjectSynchronizer::slow_enter(obj, lock, thread);
}
- assert(mon_info->owner()->is_locked(), "object must be locked now");
}
}
#ifndef PRODUCT
// print information about reallocated objects
-void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects) {
+void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects, bool realloc_failures) {
fieldDescriptor fd;
for (int i = 0; i < objects->length(); i++) {
@@ -944,10 +967,15 @@
tty->print(" object <" INTPTR_FORMAT "> of type ", (void *)sv->value()());
k->print_value();
- tty->print(" allocated (%d bytes)", obj->size() * HeapWordSize);
+ assert(obj.not_null() || realloc_failures, "reallocation was missed");
+ if (obj.is_null()) {
+ tty->print(" allocation failed");
+ } else {
+ tty->print(" allocated (%d bytes)", obj->size() * HeapWordSize);
+ }
tty->cr();
- if (Verbose) {
+ if (Verbose && !obj.is_null()) {
k->oop_print_on(obj(), tty);
}
}
@@ -955,7 +983,7 @@
#endif
#endif // COMPILER2
-vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk) {
+vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures) {
Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp());
#ifndef PRODUCT
@@ -998,7 +1026,7 @@
// Since the Java thread being deoptimized will eventually adjust it's own stack,
// the vframeArray containing the unpacking information is allocated in the C heap.
// For Compiler1, the caller of the deoptimized frame is saved for use by unpack_frames().
- vframeArray* array = vframeArray::allocate(thread, frame_size, chunk, reg_map, sender, caller, fr);
+ vframeArray* array = vframeArray::allocate(thread, frame_size, chunk, reg_map, sender, caller, fr, realloc_failures);
// Compare the vframeArray to the collected vframes
assert(array->structural_compare(thread, chunk), "just checking");
@@ -1013,6 +1041,33 @@
return array;
}
+#ifdef COMPILER2
+void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array) {
+ // Reallocation of some scalar replaced objects failed. Record
+ // that we need to pop all the interpreter frames for the
+ // deoptimized compiled frame.
+ assert(thread->frames_to_pop_failed_realloc() == 0, "missed frames to pop?");
+ thread->set_frames_to_pop_failed_realloc(array->frames());
+ // Unlock all monitors here otherwise the interpreter will see a
+ // mix of locked and unlocked monitors (because of failed
+ // reallocations of synchronized objects) and be confused.
+ for (int i = 0; i < array->frames(); i++) {
+ MonitorChunk* monitors = array->element(i)->monitors();
+ if (monitors != NULL) {
+ for (int j = 0; j < monitors->number_of_monitors(); j++) {
+ BasicObjectLock* src = monitors->at(j);
+ if (src->obj() != NULL) {
+ ObjectSynchronizer::fast_exit(src->obj(), src->lock(), thread);
+ }
+ }
+ array->element(i)->free_monitors(thread);
+#ifdef ASSERT
+ array->element(i)->set_removed_monitors();
+#endif
+ }
+ }
+}
+#endif
static void collect_monitors(compiledVFrame* cvf, GrowableArray<Handle>* objects_to_revoke) {
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
--- a/hotspot/src/share/vm/runtime/deoptimization.hpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Thu Dec 11 16:22:47 2014 -0800
@@ -125,13 +125,14 @@
static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS);
static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type);
static void reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj);
- static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects);
- static void relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread);
- NOT_PRODUCT(static void print_objects(GrowableArray<ScopeValue*>* objects);)
+ static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures);
+ static void relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread, bool realloc_failures);
+ static void pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array);
+ NOT_PRODUCT(static void print_objects(GrowableArray<ScopeValue*>* objects, bool realloc_failures);)
#endif // COMPILER2
public:
- static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk);
+ static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures);
// Interface used for unpacking deoptimized frames
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -456,6 +456,7 @@
address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) {
assert(frame::verify_return_pc(return_address), err_msg("must be a return address: " INTPTR_FORMAT, return_address));
+ assert(thread->frames_to_pop_failed_realloc() == 0 || Interpreter::contains(return_address), "missed frames to pop?");
// Reset method handle flag.
thread->set_is_method_handle_return(false);
--- a/hotspot/src/share/vm/runtime/thread.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -1448,6 +1448,7 @@
_popframe_condition = popframe_inactive;
_popframe_preserved_args = NULL;
_popframe_preserved_args_size = 0;
+ _frames_to_pop_failed_realloc = 0;
pd_initialize();
}
--- a/hotspot/src/share/vm/runtime/thread.hpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/runtime/thread.hpp Thu Dec 11 16:22:47 2014 -0800
@@ -908,6 +908,12 @@
// This is set to popframe_pending to signal that top Java frame should be popped immediately
int _popframe_condition;
+ // If reallocation of scalar replaced objects fails, we throw OOM
+ // and during exception propagation, pop the top
+ // _frames_to_pop_failed_realloc frames, the ones that reference
+ // failed reallocations.
+ int _frames_to_pop_failed_realloc;
+
#ifndef PRODUCT
int _jmp_ring_index;
struct {
@@ -1567,6 +1573,10 @@
void clr_pop_frame_in_process(void) { _popframe_condition &= ~popframe_processing_bit; }
#endif
+ int frames_to_pop_failed_realloc() const { return _frames_to_pop_failed_realloc; }
+ void set_frames_to_pop_failed_realloc(int nb) { _frames_to_pop_failed_realloc = nb; }
+ void dec_frames_to_pop_failed_realloc() { _frames_to_pop_failed_realloc--; }
+
private:
// Saved incoming arguments to popped frame.
// Used only when popped interpreted frame returns to deoptimized frame.
--- a/hotspot/src/share/vm/runtime/vframeArray.cpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/runtime/vframeArray.cpp Thu Dec 11 16:22:47 2014 -0800
@@ -57,7 +57,7 @@
}
}
-void vframeArrayElement::fill_in(compiledVFrame* vf) {
+void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) {
// Copy the information from the compiled vframe to the
// interpreter frame we will be creating to replace vf
@@ -65,6 +65,9 @@
_method = vf->method();
_bci = vf->raw_bci();
_reexecute = vf->should_reexecute();
+#ifdef ASSERT
+ _removed_monitors = false;
+#endif
int index;
@@ -82,11 +85,15 @@
// Migrate the BasicLocks from the stack to the monitor chunk
for (index = 0; index < list->length(); index++) {
MonitorInfo* monitor = list->at(index);
- assert(!monitor->owner_is_scalar_replaced(), "object should be reallocated already");
- assert(monitor->owner() == NULL || (!monitor->owner()->is_unlocked() && !monitor->owner()->has_bias_pattern()), "object must be null or locked, and unbiased");
+ assert(!monitor->owner_is_scalar_replaced() || realloc_failures, "object should be reallocated already");
BasicObjectLock* dest = _monitors->at(index);
- dest->set_obj(monitor->owner());
- monitor->lock()->move_to(monitor->owner(), dest->lock());
+ if (monitor->owner_is_scalar_replaced()) {
+ dest->set_obj(NULL);
+ } else {
+ assert(monitor->owner() == NULL || (!monitor->owner()->is_unlocked() && !monitor->owner()->has_bias_pattern()), "object must be null or locked, and unbiased");
+ dest->set_obj(monitor->owner());
+ monitor->lock()->move_to(monitor->owner(), dest->lock());
+ }
}
}
@@ -111,7 +118,7 @@
StackValue* value = locs->at(index);
switch(value->type()) {
case T_OBJECT:
- assert(!value->obj_is_scalar_replaced(), "object should be reallocated already");
+ assert(!value->obj_is_scalar_replaced() || realloc_failures, "object should be reallocated already");
// preserve object type
_locals->add( new StackValue(cast_from_oop<intptr_t>((value->get_obj()())), T_OBJECT ));
break;
@@ -136,7 +143,7 @@
StackValue* value = exprs->at(index);
switch(value->type()) {
case T_OBJECT:
- assert(!value->obj_is_scalar_replaced(), "object should be reallocated already");
+ assert(!value->obj_is_scalar_replaced() || realloc_failures, "object should be reallocated already");
// preserve object type
_expressions->add( new StackValue(cast_from_oop<intptr_t>((value->get_obj()())), T_OBJECT ));
break;
@@ -287,7 +294,7 @@
_frame.patch_pc(thread, pc);
- assert (!method()->is_synchronized() || locks > 0, "synchronized methods must have monitors");
+ assert (!method()->is_synchronized() || locks > 0 || _removed_monitors, "synchronized methods must have monitors");
BasicObjectLock* top = iframe()->interpreter_frame_monitor_begin();
for (int index = 0; index < locks; index++) {
@@ -439,7 +446,8 @@
vframeArray* vframeArray::allocate(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk,
- RegisterMap *reg_map, frame sender, frame caller, frame self) {
+ RegisterMap *reg_map, frame sender, frame caller, frame self,
+ bool realloc_failures) {
// Allocate the vframeArray
vframeArray * result = (vframeArray*) AllocateHeap(sizeof(vframeArray) + // fixed part
@@ -451,19 +459,20 @@
result->_caller = caller;
result->_original = self;
result->set_unroll_block(NULL); // initialize it
- result->fill_in(thread, frame_size, chunk, reg_map);
+ result->fill_in(thread, frame_size, chunk, reg_map, realloc_failures);
return result;
}
void vframeArray::fill_in(JavaThread* thread,
int frame_size,
GrowableArray<compiledVFrame*>* chunk,
- const RegisterMap *reg_map) {
+ const RegisterMap *reg_map,
+ bool realloc_failures) {
// Set owner first, it is used when adding monitor chunks
_frame_size = frame_size;
for(int i = 0; i < chunk->length(); i++) {
- element(i)->fill_in(chunk->at(i));
+ element(i)->fill_in(chunk->at(i), realloc_failures);
}
// Copy registers for callee-saved registers
--- a/hotspot/src/share/vm/runtime/vframeArray.hpp Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/src/share/vm/runtime/vframeArray.hpp Thu Dec 11 16:22:47 2014 -0800
@@ -58,6 +58,9 @@
MonitorChunk* _monitors; // active monitors for this vframe
StackValueCollection* _locals;
StackValueCollection* _expressions;
+#ifdef ASSERT
+ bool _removed_monitors;
+#endif
public:
@@ -78,7 +81,7 @@
StackValueCollection* expressions(void) const { return _expressions; }
- void fill_in(compiledVFrame* vf);
+ void fill_in(compiledVFrame* vf, bool realloc_failures);
// Formerly part of deoptimizedVFrame
@@ -99,6 +102,12 @@
bool is_bottom_frame,
int exec_mode);
+#ifdef ASSERT
+ void set_removed_monitors() {
+ _removed_monitors = true;
+ }
+#endif
+
#ifndef PRODUCT
void print(outputStream* st);
#endif /* PRODUCT */
@@ -160,13 +169,14 @@
int frames() const { return _frames; }
static vframeArray* allocate(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk,
- RegisterMap* reg_map, frame sender, frame caller, frame self);
+ RegisterMap* reg_map, frame sender, frame caller, frame self,
+ bool realloc_failures);
vframeArrayElement* element(int index) { assert(is_within_bounds(index), "Bad index"); return &_elements[index]; }
// Allocates a new vframe in the array and fills the array with vframe information in chunk
- void fill_in(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, const RegisterMap *reg_map);
+ void fill_in(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, const RegisterMap *reg_map, bool realloc_failures);
// Returns the owner of this vframeArray
JavaThread* owner_thread() const { return _owner_thread; }
--- a/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Thu Dec 11 16:22:47 2014 -0800
@@ -61,6 +61,7 @@
String[] vmOpts = new String[] {
"-Xbootclasspath/p:" + testClasses,
"-Xcomp",
+ "-XX:+IgnoreUnrecognizedVMOptions",
"-XX:-VerifyDependencies",
"-XX:CompileOnly=TestMonomorphicObjectCall::callFinalize",
"-XX:CompileOnly=Object::finalizeObject",
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/exceptions/SumTest.java Thu Dec 11 16:22:47 2014 -0800
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8066900
+ * @summary FP registers are not properly restored by C1 when handling exceptions
+ * @run main/othervm -Xbatch SumTest
+ *
+ */
+public class SumTest {
+ private static class Sum {
+
+ double[] sums;
+
+ /**
+ * Construct empty Sum
+ */
+ public Sum() {
+ sums = new double[0];
+ }
+
+ /**
+ * Return the sum of all numbers added to this Sum
+ *
+ * @return the sum
+ */
+ final public double getSum() {
+ double sum = 0;
+ for (final double s : sums) {
+ sum += s;
+ }
+
+ return sum;
+ }
+
+ /**
+ * Add a new number to this Sum
+ *
+ * @param a number to be added.
+ */
+ final public void add(double a) {
+ try {
+ sums[sums.length] = -1; // Cause IndexOutOfBoundsException
+ } catch (final IndexOutOfBoundsException e) {
+ final double[] oldSums = sums;
+ sums = new double[oldSums.length + 1]; // Extend sums
+ System.arraycopy(oldSums, 0, sums, 0, oldSums.length);
+ sums[oldSums.length] = a; // Append a
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ final Sum sum = new Sum();
+ for (int i = 1; i <= 10000; ++i) {
+ sum.add(1);
+ double ii = sum.getSum();
+ if (i != ii) {
+ throw new Exception("Failure: computed = " + ii + ", expected = " + i);
+ }
+ }
+ }
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java Thu Dec 11 16:22:47 2014 -0800
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8066103
+ * @summary C2's range check smearing allows out of bound array accesses
+ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox /testlibrary/com/oracle/java/testlibrary
+ * @build TestRangeCheckSmearing
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform
+ * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearing
+ *
+ */
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.NMethod;
+import com.oracle.java.testlibrary.Platform;
+
+public class TestRangeCheckSmearing {
+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface Args { int[] value(); }
+
+ // first range check is i + max of all constants
+ @Args({0, 8})
+ static int m1(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+9];
+ if (allaccesses) {
+ res += array[i+8];
+ res += array[i+7];
+ res += array[i+6];
+ res += array[i+5];
+ res += array[i+4];
+ res += array[i+3];
+ res += array[i+2];
+ res += array[i+1];
+ }
+ return res;
+ }
+
+ // first range check is i + min of all constants
+ @Args({0, -9})
+ static int m2(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+1];
+ if (allaccesses) {
+ res += array[i+2];
+ res += array[i+3];
+ res += array[i+4];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ // first range check is not i + min/max of all constants
+ @Args({0, 8})
+ static int m3(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ if (allaccesses) {
+ res += array[i+2];
+ res += array[i+1];
+ res += array[i+4];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, -9})
+ static int m4(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ if (allaccesses) {
+ res += array[i+4];
+ res += array[i+1];
+ res += array[i+2];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, -3})
+ static int m5(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+2];
+ if (allaccesses) {
+ res += array[i+1];
+ res += array[i+4];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, 6})
+ static int m6(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+4];
+ if (allaccesses) {
+ res += array[i+2];
+ res += array[i+1];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, 6})
+ static int m7(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+2];
+ res += array[i+4];
+ if (allaccesses) {
+ res += array[i+1];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, -3})
+ static int m8(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+4];
+ res += array[i+2];
+ if (allaccesses) {
+ res += array[i+1];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({6, 15})
+ static int m9(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ if (allaccesses) {
+ res += array[i-2];
+ res += array[i-1];
+ res += array[i-4];
+ res += array[i-5];
+ res += array[i-6];
+ }
+ return res;
+ }
+
+ @Args({3, 12})
+ static int m10(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ if (allaccesses) {
+ res += array[i-2];
+ res += array[i-1];
+ res += array[i-3];
+ res += array[i+4];
+ res += array[i+5];
+ res += array[i+6];
+ }
+ return res;
+ }
+
+ @Args({3, -3})
+ static int m11(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i-2];
+ if (allaccesses) {
+ res += array[i+5];
+ res += array[i+6];
+ }
+ return res;
+ }
+
+ @Args({3, 6})
+ static int m12(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+6];
+ if (allaccesses) {
+ res += array[i-2];
+ res += array[i-3];
+ }
+ return res;
+ }
+
+ // check that identical range check is replaced by dominating one
+ // only when correct
+ @Args({0})
+ static int m13(int[] array, int i, boolean ignore) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+3];
+ return res;
+ }
+
+ @Args({2, 0})
+ static int m14(int[] array, int i, boolean ignore) {
+ int res = 0;
+
+ res += array[i];
+ res += array[i-2];
+ res += array[i]; // If range check below were to be removed first this cannot be considered identical to first range check
+ res += array[i-1]; // range check removed so i-1 array access depends on previous check
+
+ return res;
+ }
+
+ static int[] m15_dummy = new int[10];
+ @Args({2, 0})
+ static int m15(int[] array, int i, boolean ignore) {
+ int res = 0;
+ res += array[i];
+
+ // When the loop is optimized out we don't want the
+ // array[i-1] access which is dependent on array[i]'s
+ // range check to become dependent on the identical range
+ // check above.
+
+ int[] array2 = m15_dummy;
+ int j = 0;
+ for (; j < 10; j++);
+ if (j == 10) {
+ array2 = array;
+ }
+
+ res += array2[i-2];
+ res += array2[i];
+ res += array2[i-1]; // range check removed so i-1 array access depends on previous check
+
+ return res;
+ }
+
+ @Args({2, 0})
+ static int m16(int[] array, int i, boolean ignore) {
+ int res = 0;
+
+ res += array[i];
+ res += array[i-1];
+ res += array[i-1];
+ res += array[i-2];
+
+ return res;
+ }
+
+ @Args({2, 0})
+ static int m17(int[] array, int i, boolean ignore) {
+ int res = 0;
+
+ res += array[i];
+ res += array[i-2];
+ res += array[i-2];
+ res += array[i+2];
+ res += array[i+2];
+ res += array[i-1];
+ res += array[i-1];
+
+ return res;
+ }
+
+ static public void main(String[] args) {
+ if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {
+ throw new AssertionError("Background compilation enabled");
+ }
+ new TestRangeCheckSmearing().doTests();
+ }
+ boolean success = true;
+ boolean exception = false;
+ final int[] array = new int[10];
+ final HashMap<String,Method> tests = new HashMap<>();
+ {
+ final Class<?> TEST_PARAM_TYPES[] = { int[].class, int.class, boolean.class };
+ for (Method m : this.getClass().getDeclaredMethods()) {
+ if (m.getName().matches("m[0-9]+")) {
+ assert(Modifier.isStatic(m.getModifiers())) : m;
+ assert(m.getReturnType() == int.class) : m;
+ assert(Arrays.equals(m.getParameterTypes(), TEST_PARAM_TYPES)) : m;
+ tests.put(m.getName(), m);
+ }
+ }
+ }
+
+ void invokeTest(Method m, int[] array, int index, boolean z) {
+ try {
+ m.invoke(null, array, index, z);
+ } catch (ReflectiveOperationException roe) {
+ Throwable ex = roe.getCause();
+ if (ex instanceof ArrayIndexOutOfBoundsException)
+ throw (ArrayIndexOutOfBoundsException) ex;
+ throw new AssertionError(roe);
+ }
+ }
+
+ void doTest(String name) {
+ Method m = tests.get(name);
+ tests.remove(name);
+ int[] args = m.getAnnotation(Args.class).value();
+ int index0 = args[0], index1;
+ boolean exceptionRequired = true;
+ if (args.length == 2) {
+ index1 = args[1];
+ } else {
+ // no negative test for this one
+ assert(args.length == 1);
+ assert(name.equals("m13"));
+ exceptionRequired = false;
+ index1 = index0;
+ }
+ // Get the method compiled.
+ if (!WHITE_BOX.isMethodCompiled(m)) {
+ // If not, try to compile it with C2
+ if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
+ // C2 compiler not available, try to compile with C1
+ WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
+ }
+ }
+ if (!WHITE_BOX.isMethodCompiled(m)) {
+ throw new RuntimeException(m + " not compiled");
+ }
+
+ // valid access
+ invokeTest(m, array, index0, true);
+
+ if (!WHITE_BOX.isMethodCompiled(m)) {
+ throw new RuntimeException(m + " deoptimized on valid array access");
+ }
+
+ exception = false;
+ boolean test_success = true;
+ try {
+ invokeTest(m, array, index1, false);
+ } catch(ArrayIndexOutOfBoundsException aioob) {
+ exception = true;
+ System.out.println("ArrayIndexOutOfBoundsException thrown in "+name);
+ }
+ if (!exception) {
+ System.out.println("ArrayIndexOutOfBoundsException was not thrown in "+name);
+ }
+
+ if (Platform.isServer()) {
+ if (exceptionRequired == WHITE_BOX.isMethodCompiled(m)) {
+ System.out.println((exceptionRequired?"Didn't deoptimized":"deoptimized") + " in "+name);
+ test_success = false;
+ }
+ }
+
+ if (exception != exceptionRequired) {
+ System.out.println((exceptionRequired?"exception required but not thrown":"not exception required but thrown") + " in "+name);
+ test_success = false;
+ }
+
+ if (!test_success) {
+ success = false;
+ System.out.println("TEST FAILED: "+name);
+ }
+
+ }
+ void doTests() {
+ doTest("m1");
+ doTest("m2");
+ doTest("m3");
+ doTest("m4");
+ doTest("m5");
+ doTest("m6");
+ doTest("m7");
+ doTest("m8");
+ doTest("m9");
+ doTest("m10");
+ doTest("m11");
+ doTest("m12");
+ doTest("m13");
+ doTest("m14");
+ doTest("m15");
+ doTest("m16");
+ doTest("m17");
+ if (!success) {
+ throw new RuntimeException("Some tests failed");
+ }
+ assert(tests.isEmpty()) : tests;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearingLoopOpts.java Thu Dec 11 16:22:47 2014 -0800
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8048170
+ * @summary Following range check smearing, range check cannot be replaced by dominating identical test.
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearingLoopOpts
+ *
+ */
+public class TestRangeCheckSmearingLoopOpts {
+
+ static int dummy;
+
+ static int m1(int[] array, int i) {
+ for (;;) {
+ for (;;) {
+ if (array[i] < 0) { // range check (i+0) dominates equivalent check below
+ break;
+ }
+ i++;
+ }
+
+ // A control flow that stops IfNode::up_one_dom()
+ if ((i % 2)== 0) {
+ if ((array[i] % 2) == 0) {
+ dummy = i;
+ }
+ }
+
+ // IfNode::Ideal will rewrite some range checks if Compile::allow_range_check_smearing
+ if (array[i-1] == 9) { // range check (i-1) unchanged
+ int res = array[i-3]; // range check (i-3) unchanged
+ res += array[i]; // range check (i+0) unchanged
+ res += array[i-2]; // removed redundant range check
+ // the previous access might be hoisted by
+ // PhaseIdealLoop::split_if_with_blocks_post because
+ // it appears to have the same guard, but it also
+ // depends on the previous guards
+ return res;
+ }
+ i++;
+ }
+ }
+
+ static public void main(String[] args) {
+ int[] array = { 0, 1, 2, -3, 4, 5, -2, 7, 8, 9, -1 };
+ for (int i = 0; i < 20000; i++) {
+ m1(array, 0);
+ }
+ array[0] = -1;
+ try {
+ m1(array, 0);
+ } catch(ArrayIndexOutOfBoundsException aioobe) {}
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/uncommontrap/TestDeoptOOM.java Thu Dec 11 16:22:47 2014 -0800
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6898462
+ * @summary failed reallocations of scalar replaced objects during deoptimization causes crash
+ * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=exclude,TestDeoptOOM::main -XX:CompileCommand=exclude,TestDeoptOOM::m9_1 -Xmx128M TestDeoptOOM
+ *
+ */
+
+public class TestDeoptOOM {
+
+ long f1;
+ long f2;
+ long f3;
+ long f4;
+ long f5;
+
+ static class LinkedList {
+ LinkedList l;
+ long[] array;
+ LinkedList(LinkedList l, int size) {
+ array = new long[size];
+ this.l = l;
+ }
+ }
+
+ static LinkedList ll;
+
+ static void consume_all_memory() {
+ int size = 128 * 1024 * 1024;
+ while(size > 0) {
+ try {
+ while(true) {
+ ll = new LinkedList(ll, size);
+ }
+ } catch(OutOfMemoryError oom) {
+ }
+ size = size / 2;
+ }
+ }
+
+ static void free_memory() {
+ ll = null;
+ }
+
+ static TestDeoptOOM m1(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m1");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m2_1(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m2_1");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m2(boolean deopt) {
+ try {
+ return m2_1(deopt);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m2");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m3_3(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m3_3");
+ }
+ return null;
+ }
+
+ static boolean m3_2(boolean deopt) {
+ try {
+ return m3_3(deopt) != null;
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m3_2");
+ }
+ return false;
+ }
+
+ static TestDeoptOOM m3_1(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (m3_2(deopt)) {
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m3_1");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m3(boolean deopt) {
+ try {
+ return m3_1(deopt);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m3");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m4(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ tdoom.f1 = 1l;
+ tdoom.f2 = 2l;
+ tdoom.f3 = 3l;
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m4");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m5(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ synchronized(tdoom) {
+ if (deopt) {
+ return tdoom;
+ }
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m5");
+ }
+ return null;
+ }
+
+ synchronized TestDeoptOOM m6_1(boolean deopt) {
+ if (deopt) {
+ return this;
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m6(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ return tdoom.m6_1(deopt);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m6");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m7_1(boolean deopt, Object lock) {
+ try {
+ synchronized(lock) {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ return tdoom;
+ }
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m7_1");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m7(boolean deopt, Object lock) {
+ try {
+ return m7_1(deopt, lock);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m7");
+ }
+ return null;
+ }
+
+ static class A {
+ long f1;
+ long f2;
+ long f3;
+ long f4;
+ long f5;
+ }
+
+ static class B {
+ long f1;
+ long f2;
+ long f3;
+ long f4;
+ long f5;
+
+ A a;
+ }
+
+ static B m8(boolean deopt) {
+ try {
+ A a = new A();
+ B b = new B();
+ b.a = a;
+ if (deopt) {
+ return b;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m8");
+ }
+ return null;
+ }
+
+ static void m9_1(int i) {
+ if (i > 90000) {
+ consume_all_memory();
+ }
+ }
+
+ static TestDeoptOOM m9() {
+ try {
+ for (int i = 0; i < 100000; i++) {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ m9_1(i);
+ if (i > 90000) {
+ return tdoom;
+ }
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m1");
+ }
+ return null;
+ }
+
+ public static void main(String[] args) {
+ for (int i = 0; i < 20000; i++) {
+ m1(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m1(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main " + oom.getMessage());
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m2(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m2(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m3(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m3(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m4(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m4(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m5(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m5(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m6(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m6(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ final Object lock = new Object();
+
+ for (int i = 0; i < 20000; i++) {
+ m7(false, lock);
+ }
+
+ consume_all_memory();
+
+ try {
+ m7(true, lock);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ Thread thread = new Thread() {
+ public void run() {
+ System.out.println("Acquiring lock");
+ synchronized(lock) {
+ System.out.println("Lock acquired");
+ }
+ System.out.println("Lock released");
+ }
+ };
+ thread.start();
+ try {
+ thread.join();
+ } catch(InterruptedException ie) {
+ }
+
+ for (int i = 0; i < 20000; i++) {
+ m8(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m8(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ try {
+ m9();
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/uncommontrap/TraceDeoptimizationNoRealloc.java Thu Dec 11 16:22:47 2014 -0800
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8067144
+ * @summary -XX:+TraceDeoptimization tries to print realloc'ed objects even when there are none
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceDeoptimization TraceDeoptimizationNoRealloc
+ *
+ */
+
+public class TraceDeoptimizationNoRealloc {
+
+ static void m(boolean some_condition) {
+ if (some_condition) {
+ return;
+ }
+ }
+
+
+ static public void main(String[] args) {
+ for (int i = 0; i < 20000; i++) {
+ m(false);
+ }
+ m(true);
+ }
+}
--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu Dec 11 20:39:25 2014 +0100
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu Dec 11 16:22:47 2014 -0800
@@ -153,6 +153,14 @@
public native int getMethodEntryBci(Executable method);
public native Object[] getNMethod(Executable method, boolean isOsr);
public native long allocateCodeBlob(int size, int type);
+ public long allocateCodeBlob(long size, int type) {
+ int intSize = (int) size;
+ if ((long) intSize != size || size < 0) {
+ throw new IllegalArgumentException(
+ "size argument has illegal value " + size);
+ }
+ return allocateCodeBlob( intSize, type);
+ }
public native void freeCodeBlob(long addr);
public void forceNMethodSweep() {
try {