--- old/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp 2018-05-30 18:45:35.009706675 +0200 +++ new/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp 2018-05-30 18:45:34.365707433 +0200 @@ -1025,6 +1025,21 @@ // If this happens, control eventually transfers back to the compiled // caller, but with an uncorrected stack, causing delayed havoc. + Label value_arg_is_null; + bool has_null_check = false; + if (EnableValhalla) { + for (int i = 0; i < sig_extended.length(); i++) { + BasicType bt = sig_extended.at(i)._bt; + if (bt == T_VALUETYPEPTR) { + // Add null check for value type argument + int ld_off = (sig_extended.length() - i) * Interpreter::stackElementSize; + __ cmpptr(Address(rsp, ld_off), 0); + __ jcc(Assembler::equal, value_arg_is_null); + has_null_check = true; + } + } + } + // Pick up the return address __ movptr(rax, Address(rsp, 0)); @@ -1180,6 +1195,13 @@ // rax __ mov(rax, rbx); __ jmp(r11); + + if (has_null_check) { + __ bind(value_arg_is_null); + // TODO For now, we just call the interpreter if a value type argument is NULL + __ movptr(r11, Address(rbx, in_bytes(Method::interpreter_entry_offset()))); + __ jmp(r11); + } } // --------------------------------------------------------------- --- old/src/hotspot/share/opto/callGenerator.cpp 2018-05-30 18:45:36.121705368 +0200 +++ new/src/hotspot/share/opto/callGenerator.cpp 2018-05-30 18:45:35.581706003 +0200 @@ -179,6 +179,9 @@ } } kit.set_arguments_for_java_call(call); + if (kit.stopped()) { + return kit.transfer_exceptions_into_jvms(); + } kit.set_edges_for_java_call(call, false, _separate_io_proj); Node* ret = kit.set_results_for_java_call(call, _separate_io_proj); kit.push_node(method()->return_type()->basic_type(), ret); @@ -261,6 +264,9 @@ call->set_override_symbolic_info(true); } kit.set_arguments_for_java_call(call); + if (kit.stopped()) { + return kit.transfer_exceptions_into_jvms(); + } kit.set_edges_for_java_call(call); Node* ret = kit.set_results_for_java_call(call); kit.push_node(method()->return_type()->basic_type(), ret); --- old/src/hotspot/share/opto/graphKit.cpp 2018-05-30 18:45:36.701704686 +0200 +++ new/src/hotspot/share/opto/graphKit.cpp 2018-05-30 18:45:36.421705015 +0200 @@ -1780,34 +1780,34 @@ uint nargs = domain->cnt(); for (uint i = TypeFunc::Parms, idx = TypeFunc::Parms; i < nargs; i++) { Node* arg = argument(i-TypeFunc::Parms); - if (ValueTypePassFieldsAsArgs) { - if (arg->is_ValueType()) { - ValueTypeNode* vt = arg->as_ValueType(); - // TODO fix this with the calling convention changes - if (true /*!domain->field_at(i)->is_valuetypeptr()->is__Value()*/) { - // We don't pass value type arguments by reference but instead - // pass each field of the value type - idx += vt->pass_fields(call, idx, *this); - // 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(). - // For example, see CompiledMethod::preserve_callee_argument_oops(). - call->set_override_symbolic_info(true); - } else { - arg = arg->as_ValueType()->allocate(this)->get_oop(); - call->init_req(idx, arg); - idx++; - } + const Type* t = domain->field_at(i); + if (arg->is_ValueType()) { + assert(t->is_oopptr()->can_be_value_type(), "wrong argument type"); + ValueTypeNode* vt = arg->as_ValueType(); + if (ValueTypePassFieldsAsArgs) { + // We don't pass value type arguments by reference but instead + // pass each field of the value type + idx += vt->pass_fields(call, idx, *this); + // 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(). + // For example, see CompiledMethod::preserve_callee_argument_oops(). + call->set_override_symbolic_info(true); + continue; } else { - call->init_req(idx, arg); - idx++; - } - } else { - if (arg->is_ValueType()) { // Pass value type argument via oop to callee - arg = arg->as_ValueType()->allocate(this)->get_oop(); + arg = vt->allocate(this)->get_oop(); } - call->init_req(i, arg); + } else if (t->is_valuetypeptr()) { + // Constant null passed for a value type argument + assert(arg->bottom_type()->remove_speculative() == TypePtr::NULL_PTR, "Anything other than null?"); + ciMethod* declared_method = method()->get_method_at_bci(bci()); + int arg_size = declared_method->signature()->arg_size_for_bc(java_bc()); + inc_sp(arg_size); // restore arguments + uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none); + return; } + call->init_req(idx, arg); + idx++; } } --- old/src/hotspot/share/opto/parse1.cpp 2018-05-30 18:45:37.361703910 +0200 +++ new/src/hotspot/share/opto/parse1.cpp 2018-05-30 18:45:37.065704258 +0200 @@ -613,17 +613,7 @@ const Type* t = _gvn.type(parm); if (t->is_valuetypeptr()) { // Create ValueTypeNode from the oop and replace the parameter - Node* null_ctl = top(); - Node* not_null_obj = null_check_common(parm, T_VALUETYPE, false, &null_ctl, false); - if (null_ctl != top()) { - // TODO For now, we just deoptimize if value type is NULL - PreserveJVMState pjvms(this); - set_control(null_ctl); - replace_in_map(parm, null()); - uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none); - } - // Value type oop may point to the TLVB - Node* vt = ValueTypeNode::make_from_oop(this, not_null_obj, t->value_klass(), /* null_check */ false, /* buffer_check */ true); + Node* vt = ValueTypeNode::make_from_oop(this, parm, t->value_klass(), /* null_check */ false, /* buffer_check */ true); map()->replace_edge(parm, vt); } } --- old/src/hotspot/share/opto/type.cpp 2018-05-30 18:45:38.041703110 +0200 +++ new/src/hotspot/share/opto/type.cpp 2018-05-30 18:45:37.673703543 +0200 @@ -2035,12 +2035,7 @@ ciValueKlass* vk = (ciValueKlass*)recv; collect_value_fields(vk, field_array, pos); } else { - if (recv->is_valuetype()) { - // TODO For now, we just deoptimize if the value type receiver is null - field_array[pos++] = get_const_type(recv); - } else { - field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL); - } + field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL); } } else { field_array = fields(arg_cnt + vt_extra); @@ -2078,9 +2073,7 @@ collect_value_fields(vk, field_array, pos); } else { // Value types arguments cannot be NULL - // field_array[pos++] = get_const_type(type)->join_speculative(TypePtr::NOTNULL); - // TODO they can be NULL in LWorld - field_array[pos++] = get_const_type(type); + field_array[pos++] = get_const_type(type)->join_speculative(TypePtr::NOTNULL); } break; } --- old/src/hotspot/share/opto/valuetypenode.cpp 2018-05-30 18:45:38.645702400 +0200 +++ new/src/hotspot/share/opto/valuetypenode.cpp 2018-05-30 18:45:38.329702772 +0200 @@ -539,7 +539,7 @@ } // Create and initialize a ValueTypeNode by loading all field // values from a heap-allocated version and also save the oop. - ValueTypeNode* vt = new ValueTypeNode(TypeValueType::make(vk), oop); + ValueTypeNode* vt = new ValueTypeNode(TypeValueType::make(vk), oop); if (null_check && !vt->is_allocated(&gvn)) { // Add oop null check --- old/src/hotspot/share/runtime/sharedRuntime.cpp 2018-05-30 18:45:39.473701426 +0200 +++ new/src/hotspot/share/runtime/sharedRuntime.cpp 2018-05-30 18:45:39.077701891 +0200 @@ -2293,7 +2293,10 @@ // between a T_VALUETYPE and a T_OBJECT in the signature. return ValueTypePassFieldsAsArgs ? in : adapter_encoding(T_OBJECT, false); } + case T_VALUETYPEPTR: + return T_VALUETYPE; // TODO hack because we don't have enough bits to represent T_VALUETYPEPTR. + case T_OBJECT: case T_ARRAY: // In other words, we assume that any register good enough for @@ -2675,8 +2678,8 @@ } } for (SignatureStream ss(method->signature()); !ss.at_return_type(); ss.next()) { - if (ss.type() == T_VALUETYPE) { - Symbol* name = ss.as_symbol(CHECK_NULL); + Symbol* sym = ss.as_symbol_or_null(); + if (sym != NULL && method->method_holder()->is_declared_value_type(sym)) { if (!ValueTypePassFieldsAsArgs) { sig_extended.push(SigEntry(T_VALUETYPEPTR)); } else { --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java 2018-05-30 18:45:40.189700583 +0200 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestLWorld.java 2018-05-30 18:45:39.821701017 +0200 @@ -294,6 +294,7 @@ __NotFlattened MyValue1 nullField; @Test + @Warmup(10000) // Warmup to make sure 'callTest7WithNull' is compiled public long test7(MyValue1 vt) { long result = 0; try {