--- a/hotspot/src/share/vm/runtime/deoptimization.cpp Fri Dec 05 15:16:01 2014 +0100
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Tue Nov 25 17:33:59 2014 +0100
@@ -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,22 +208,19 @@
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
+ reassign_fields(&deoptee, &map, objects, realloc_failures);
}
- if (reallocated) {
- reassign_fields(&deoptee, &map, objects);
#ifndef PRODUCT
- if (TraceDeoptimization) {
- ttyLocker ttyl;
- tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread);
- print_objects(objects);
- }
+ if (TraceDeoptimization) {
+ ttyLocker ttyl;
+ tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread);
+ print_objects(objects, realloc_failures);
+ }
#endif
- }
if (save_oop_result) {
// Restore result.
deoptee.set_saved_oop_result(&map, return_value());
@@ -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();