--- old/src/hotspot/share/runtime/safepoint.cpp 2019-03-11 14:27:18.130354160 +0100 +++ new/src/hotspot/share/runtime/safepoint.cpp 2019-03-11 14:27:17.906354163 +0100 @@ -44,6 +44,7 @@ #include "memory/universe.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" @@ -1053,16 +1054,40 @@ // 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->may_return_oop(); + + GrowableArray return_values; + ValueKlass* vk = NULL; + + if (return_oop && ValueTypeReturnedAsFields) { + SignatureStream ss(method->signature()); + while (!ss.at_return_type()) { + ss.next(); + } + if (ss.type() == T_VALUETYPE) { + // Check if value type is returned as fields + vk = ValueKlass::returned_value_klass(map); + if (vk != NULL) { + // 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. + assert(vk == method->returned_value_type(thread()), "bad value klass"); + vk->save_oop_fields(map, return_values); + return_oop = false; + } + } + } + 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(oopDesc::is_oop_or_null(result), "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"); } @@ -1071,7 +1096,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); } }