< prev index next >
src/share/vm/runtime/deoptimization.cpp
Print this page
@@ -211,41 +211,63 @@
// It is not guaranteed that we can get such information here only
// by analyzing bytecode in deoptimized frames. This is why this flag
// is set during method compilation (see Compile::Process_OopMap_Node()).
// If the previous frame was popped or if we are dispatching an exception,
// we don't have an oop result.
- bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution() && (exec_mode == Unpack_deopt);
- Handle return_value;
+ ScopeDesc* scope = chunk->at(0)->scope();
+ bool save_oop_result = scope->return_oop() && !thread->popframe_forcing_deopt_reexecution() && (exec_mode == Unpack_deopt);
+ // In case of the return of multiple values, we must take care
+ // of all oop return values.
+ GrowableArray<Handle> return_oops;
+ ValueKlass* vk = NULL;
+ if (save_oop_result) {
+ if (scope->return_vt()) {
+ vk = ValueKlass::returned_value_type(map);
+ if (vk != NULL) {
+ bool success = vk->save_oop_results(map, return_oops);
+ assert(success, "found klass ptr being returned: saving oops can't fail");
+ save_oop_result = false;
+ } else {
+ vk = NULL;
+ }
+ }
+ }
if (save_oop_result) {
// Reallocation may trigger GC. If deoptimization happened on return from
// call which returns oop we need to save it since it is not in oopmap.
oop result = deoptee.saved_oop_result(&map);
assert(result == NULL || result->is_oop(), "must be oop");
- return_value = Handle(thread, result);
+ return_oops.push(Handle(thread, result));
assert(Universe::heap()->is_in_or_null(result), "must be heap pointer");
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, p2i(result), p2i(thread));
}
}
- if (objects != NULL) {
+ if (objects != NULL || vk != NULL) {
bool skip_internal = (cm != NULL) && !cm->is_compiled_by_jvmci();
JRT_BLOCK
- realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD);
+ if (vk != NULL) {
+ realloc_failures = realloc_value_type_result(vk, map, return_oops, THREAD);
+ }
+ if (objects != NULL) {
+ realloc_failures = realloc_failures || realloc_objects(thread, &deoptee, objects, THREAD);
reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal, THREAD);
+ }
JRT_END
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, p2i(thread));
print_objects(objects, realloc_failures);
}
#endif
}
- if (save_oop_result) {
+ if (save_oop_result || vk != NULL) {
// Restore result.
- deoptee.set_saved_oop_result(&map, return_value());
+ assert(return_oops.length() == 1, "no value type");
+ deoptee.set_saved_oop_result(&map, return_oops.pop()());
}
#ifndef INCLUDE_JVMCI
}
if (EliminateLocks) {
#endif // INCLUDE_JVMCI
@@ -850,10 +872,30 @@
}
return failures;
}
+// We're deoptimizing at the return of a call, value type fields are
+// in registers. When we go back to the interpreter, it will expect a
+// reference to a value type instance. Allocate and initialize it from
+// the register values here.
+bool Deoptimization::realloc_value_type_result(ValueKlass* vk, const RegisterMap& map, GrowableArray<Handle>& return_oops, TRAPS) {
+ VMRegPair* regs;
+ int nb_fields;
+ const GrowableArray<SigEntry>& sig_vk = vk->return_convention(regs, nb_fields);
+ regs++;
+ nb_fields--;
+ oop new_vt = vk->realloc_result(sig_vk, map, regs, return_oops, nb_fields, THREAD);
+ if (new_vt == NULL) {
+ CLEAR_PENDING_EXCEPTION;
+ THROW_OOP_(Universe::out_of_memory_error_realloc_objects(), true);
+ }
+ return_oops.clear();
+ return_oops.push(Handle(THREAD, new_vt));
+ return false;
+}
+
// restore elements of an eliminated type array
void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) {
int index = 0;
intptr_t val;
< prev index next >