--- old/src/hotspot/share/opto/callGenerator.cpp 2019-03-14 14:00:02.819847601 +0100 +++ new/src/hotspot/share/opto/callGenerator.cpp 2019-03-14 14:00:02.643846926 +0100 @@ -1136,7 +1136,7 @@ if (!method()->is_static()) { // We need an explicit receiver null_check before checking its type in predicate. // We share a map with the caller, so his JVMS gets adjusted. - Node* receiver = kit.null_check_receiver_before_call(method()); + kit.null_check_receiver_before_call(method()); if (kit.stopped()) { return kit.transfer_exceptions_into_jvms(); } --- old/src/hotspot/share/opto/graphKit.cpp 2019-03-14 14:00:03.251849259 +0100 +++ new/src/hotspot/share/opto/graphKit.cpp 2019-03-14 14:00:03.095848660 +0100 @@ -1798,10 +1798,6 @@ // We don't pass value type arguments by reference but instead // pass each field of the value type ValueTypeNode* vt = arg->isa_ValueType(); - if (vt == NULL) { - // TODO why is that?? Shouldn't we always see a valuetype node here? - vt = ValueTypeNode::make_from_oop(this, arg, t->value_klass()); - } vt->pass_fields(this, call, sig_cc, idx); // If a value type argument is passed as fields, attach the Method* to the call site // to be able to access the extended signature later via attached_method_before_pc(). --- old/src/hotspot/share/opto/graphKit.hpp 2019-03-14 14:00:03.727851085 +0100 +++ new/src/hotspot/share/opto/graphKit.hpp 2019-03-14 14:00:03.563850455 +0100 @@ -37,6 +37,7 @@ #include "opto/phaseX.hpp" #include "opto/subnode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/deoptimization.hpp" class BarrierSetC2; @@ -678,7 +679,7 @@ // Do a null check on the receiver as it would happen before the call to // callee (with all arguments still on the stack). - Node* null_check_receiver_before_call(ciMethod* callee) { + Node* null_check_receiver_before_call(ciMethod* callee, bool replace_value = true) { assert(!callee->is_static(), "must be a virtual method"); if (argument(0)->is_ValueType()) { return argument(0); @@ -690,6 +691,16 @@ inc_sp(nargs); Node* n = null_check_receiver(); dec_sp(nargs); + // Scalarize value type receiver + const Type* recv_type = gvn().type(n); + if (recv_type->is_valuetypeptr() && recv_type->value_klass()->is_scalarizable()) { + assert(!recv_type->maybe_null(), "should never be null"); + ValueTypeNode* vt = ValueTypeNode::make_from_oop(this, n, recv_type->value_klass()); + if (replace_value) { + replace_in_map(n, vt); + } + n = vt; + } return n; } --- old/src/hotspot/share/opto/library_call.cpp 2019-03-14 14:00:04.259853126 +0100 +++ new/src/hotspot/share/opto/library_call.cpp 2019-03-14 14:00:04.071852404 +0100 @@ -2651,7 +2651,7 @@ p = gvn().transform(new CastP2XNode(NULL, p)); p = ConvX2UL(p); } - if (field != NULL && field->is_flattenable()&& !field->is_flattened()) { + if (field != NULL && field->is_flattenable() && !field->is_flattened()) { // Load a non-flattened but flattenable value type from memory if (value_type->value_klass()->is_scalarizable()) { p = ValueTypeNode::make_from_oop(this, p, value_type->value_klass()); --- old/src/hotspot/share/opto/parse.hpp 2019-03-14 14:00:04.795855181 +0100 +++ new/src/hotspot/share/opto/parse.hpp 2019-03-14 14:00:04.627854537 +0100 @@ -529,7 +529,7 @@ bool static_field_ok_in_clinit(ciField *field, ciMethod *method); // common code for actually performing the load or store - void do_get_xxx(Node* obj, ciField* field, bool is_field); + void do_get_xxx(Node* obj, ciField* field); void do_put_xxx(Node* obj, ciField* field, bool is_field); // implementation of object creation bytecodes --- old/src/hotspot/share/opto/parse1.cpp 2019-03-14 14:00:05.179856655 +0100 +++ new/src/hotspot/share/opto/parse1.cpp 2019-03-14 14:00:05.031856087 +0100 @@ -1198,7 +1198,7 @@ // If this is an inlined method, we may have to do a receiver null check. if (_caller->has_method() && is_normal_parse() && !method()->is_static()) { GraphKit kit(_caller); - kit.null_check_receiver_before_call(method()); + kit.null_check_receiver_before_call(method(), false); _caller = kit.transfer_exceptions_into_jvms(); if (kit.stopped()) { _exits.add_exception_states_from(_caller); --- old/src/hotspot/share/opto/parse3.cpp 2019-03-14 14:00:05.583858204 +0100 +++ new/src/hotspot/share/opto/parse3.cpp 2019-03-14 14:00:05.431857621 +0100 @@ -134,7 +134,7 @@ if (is_get) { (void) pop(); // pop receiver before getting - do_get_xxx(obj, field, is_field); + do_get_xxx(obj, field); } else { do_put_xxx(obj, field, is_field); if (stopped()) { @@ -146,14 +146,14 @@ const TypeInstPtr* tip = TypeInstPtr::make(field_holder->java_mirror()); obj = _gvn.makecon(tip); if (is_get) { - do_get_xxx(obj, field, is_field); + do_get_xxx(obj, field); } else { do_put_xxx(obj, field, is_field); } } } -void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) { +void Parse::do_get_xxx(Node* obj, ciField* field) { BasicType bt = field->layout_type(); // Does this field have a constant value? If so, just push the value. @@ -211,6 +211,7 @@ ciObject* val = mirror->field_value(field).as_object(); if (!val->is_null_object()) { type = type->join_speculative(TypePtr::NOTNULL); + flattenable = true; // Null-free, treat as flattenable } } }