--- old/src/share/vm/runtime/safepoint.cpp 2017-05-29 18:07:48.281021370 +0200 +++ new/src/share/vm/runtime/safepoint.cpp 2017-05-29 18:07:48.203021454 +0200 @@ -39,6 +39,7 @@ #include "memory/universe.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" +#include "oops/valueKlass.hpp" #include "runtime/atomic.hpp" #include "runtime/compilationPolicy.hpp" #include "runtime/deoptimization.hpp" @@ -1029,16 +1030,33 @@ // return point does not mark the return value as an oop (if it is), so // it needs a handle here to be updated. if( nm->is_at_poll_return(real_return_addr) ) { + ResourceMark rm; // See if return type is an oop. - bool return_oop = nm->method()->is_returning_oop(); - Handle return_value; + Method* method = nm->method(); + bool return_oop = method->is_returning_oop(); + + GrowableArray return_values; + ValueKlass* vk = NULL; + if (!return_oop && method->is_returning_vt()) { + // We're at a safepoint at the return of a method that returns + // multiple values. We must make sure we preserve the oop values + // across the safepoint. + vk = ValueKlass::returned_value_type(map); + assert(vk == NULL || vk == method->returned_value_type(thread()) || + method->returned_value_type(thread()) == SystemDictionary::___Value_klass(), "Bad value klass"); + if (vk != NULL && !vk->save_oop_results(map, return_values)) { + return_oop = true; + vk = NULL; + } + } + if (return_oop) { // The oop result has been saved on the stack together with all // the other registers. In order to preserve it over GCs we need // to keep it in a handle. oop result = caller_fr.saved_oop_result(&map); assert(result == NULL || result->is_oop(), "must be oop"); - return_value = Handle(thread(), result); + return_values.push(Handle(thread(), result)); assert(Universe::heap()->is_in_or_null(result), "must be heap pointer"); } @@ -1047,7 +1065,10 @@ // restore oop result, if any if (return_oop) { - caller_fr.set_saved_oop_result(&map, return_value()); + assert(return_values.length() == 1, "only one return value"); + caller_fr.set_saved_oop_result(&map, return_values.pop()()); + } else if (vk != NULL) { + vk->restore_oop_results(map, return_values); } }