--- old/src/share/vm/ci/ciValueKlass.cpp 2016-12-13 16:55:41.059291779 +0100 +++ new/src/share/vm/ci/ciValueKlass.cpp 2016-12-13 16:55:40.998291897 +0100 @@ -133,18 +133,17 @@ ) } -// When passing field's fields as arguments, count the number of extra -// argument slots that are needed -int ciValueKlass::extra_value_args() { - // -1 because we count the number of extra args - int vt_extra = nof_nonstatic_fields() - 1; +// When passing a value type's fields as arguments, count the number +// of argument slots that are needed +int ciValueKlass::value_arg_slots() { + int slots = nof_nonstatic_fields(); for (int j = 0; j < nof_nonstatic_fields(); j++) { ciField* f = nonstatic_field_at(j); BasicType bt = f->type()->basic_type(); assert(bt != T_VALUETYPE, "embedded"); if (bt == T_LONG || bt == T_DOUBLE) { - vt_extra++; + slots++; } } - return vt_extra; + return slots; } --- old/src/share/vm/ci/ciValueKlass.hpp 2016-12-13 16:55:41.400291121 +0100 +++ new/src/share/vm/ci/ciValueKlass.hpp 2016-12-13 16:55:41.338291240 +0100 @@ -66,7 +66,7 @@ ciType* field_type_by_index(int index); int first_field_offset() const; - int extra_value_args(); + int value_arg_slots(); }; #endif // SHARE_VM_CI_CIVALUEKLASS_HPP --- old/src/share/vm/opto/callGenerator.cpp 2016-12-13 16:55:41.720290503 +0100 +++ new/src/share/vm/opto/callGenerator.cpp 2016-12-13 16:55:41.657290625 +0100 @@ -372,11 +372,7 @@ return; } - // FIXME: late inlining of methods that take value type arguments is - // broken: arguments at the call are set up so fields of value type - // arguments are passed but code here expects a single argument per - // value type (a ValueTypeNode) instead. - const TypeTuple *r = call->tf()->domain_sig(); + const TypeTuple *r = call->tf()->domain_cc(); for (int i1 = 0; i1 < method()->arg_size(); i1++) { if (call->in(TypeFunc::Parms + i1)->is_top() && r->field_at(TypeFunc::Parms + i1) != Type::HALF) { assert(Compile::current()->inlining_incrementally(), "shouldn't happen during parsing"); @@ -404,26 +400,48 @@ map->init_req(i1, call->in(i1)); } + PhaseGVN& gvn = *C->initial_gvn(); // Make sure the state is a MergeMem for parsing. if (!map->in(TypeFunc::Memory)->is_MergeMem()) { Node* mem = MergeMemNode::make(map->in(TypeFunc::Memory)); - C->initial_gvn()->set_type_bottom(mem); + gvn.set_type_bottom(mem); map->set_req(TypeFunc::Memory, mem); } - uint nargs = method()->arg_size(); // blow away old call arguments Node* top = C->top(); - for (uint i1 = 0; i1 < nargs; i1++) { - map->set_req(TypeFunc::Parms + i1, top); + for (uint i1 = TypeFunc::Parms; i1 < call->_tf->domain_cc()->cnt(); i1++) { + map->set_req(i1, top); } jvms->set_map(map); // Make enough space in the expression stack to transfer // the incoming arguments and return value. map->ensure_stack(jvms, jvms->method()->max_stack()); + const TypeTuple *domain_sig = call->_tf->domain_sig(); + uint nargs = method()->arg_size(); + assert(domain_sig->cnt() - TypeFunc::Parms == nargs, "inconsistent signature"); + + uint j = TypeFunc::Parms; for (uint i1 = 0; i1 < nargs; i1++) { - map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1)); + const Type* t = domain_sig->field_at(TypeFunc::Parms + i1); + if (!ValueTypePassFieldsAsArgs) { + Node* arg = call->in(TypeFunc::Parms + i1); + if (t->isa_valuetypeptr()) { + arg = ValueTypeNode::make(gvn, map->memory(), arg); + } + map->set_argument(jvms, i1, arg); + } else { + if (t->isa_valuetypeptr()) { + ciValueKlass* vk = t->is_valuetypeptr()->value_type()->value_klass(); + Node* vt = C->create_vt_node(call, vk, vk, 0, j); + map->set_argument(jvms, i1, gvn.transform(vt)); + j += vk->value_arg_slots(); + } else { + map->set_argument(jvms, i1, call->in(j)); + j++; + } + } } C->print_inlining_assert_ready(); @@ -466,6 +484,10 @@ C->env()->notice_inlined_method(_inline_cg->method()); C->set_inlining_progress(true); + if (result->is_ValueType()) { + result = result->as_ValueType()->store_to_memory(&kit); + } + kit.replace_call(call, result, true); } --- old/src/share/vm/opto/compile.hpp 2016-12-13 16:55:42.059289849 +0100 +++ new/src/share/vm/opto/compile.hpp 2016-12-13 16:55:41.996289970 +0100 @@ -1320,6 +1320,8 @@ CloneMap& clone_map(); void set_clone_map(Dict* d); + + Node* create_vt_node(Node* n, ciValueKlass* vk, ciValueKlass* base_vk, int base_offset, int base_input); }; #endif // SHARE_VM_OPTO_COMPILE_HPP --- old/src/share/vm/opto/parse1.cpp 2016-12-13 16:55:42.379289231 +0100 +++ new/src/share/vm/opto/parse1.cpp 2016-12-13 16:55:42.318289348 +0100 @@ -790,16 +790,16 @@ // Helper function to create a ValueTypeNode from its fields passed as // arguments. Fields are passed in order of increasing offsets. -static Node* create_vt_node(StartNode* start, ciValueKlass* vk, ciValueKlass* base_vk, int base_offset, int base_input, Compile* C) { +Node* Compile::create_vt_node(Node* n, ciValueKlass* vk, ciValueKlass* base_vk, int base_offset, int base_input) { assert(base_offset >= 0, "offset in value type always positive"); - PhaseGVN& gvn = *C->initial_gvn(); + PhaseGVN& gvn = *initial_gvn(); ValueTypeNode* vt = ValueTypeNode::make(gvn, vk); for (uint i = 0; i < vt->field_count(); i++) { ciType* field_type = vt->get_field_type(i); int offset = base_offset + vt->get_field_offset(i) - (base_offset > 0 ? vk->first_field_offset() : 0); if (field_type->is_valuetype()) { ciValueKlass* embedded_vk = field_type->as_value_klass(); - Node* embedded_vt = create_vt_node(start, embedded_vk, base_vk, offset, base_input, C); + Node* embedded_vt = create_vt_node(n, embedded_vk, base_vk, offset, base_input); vt->set_field_value(i, embedded_vt); } else { int j = 0; int extra = 0; @@ -815,10 +815,16 @@ } } assert(j != base_vk->nof_nonstatic_fields(), "must find"); - Node* parm = gvn.transform(new ParmNode(start, base_input + j + extra)); + Node* parm = NULL; + if (n->is_Start()) { + parm = gvn.transform(new ParmNode(n->as_Start(), base_input + j + extra)); + } else { + assert(n->is_Call(), "nothing else here"); + parm = n->in(base_input + j + extra); + } vt->set_field_value(i, parm); // Record all these guys for later GVN. - C->record_for_igvn(parm); + record_for_igvn(parm); } } return gvn.transform(vt); @@ -862,17 +868,9 @@ const Type* t = tf->domain_sig()->field_at(i); if (t->isa_valuetypeptr()) { ciValueKlass* vk = t->is_valuetypeptr()->value_type()->value_klass(); - Node* vt = create_vt_node(start, vk, vk, 0, j, C); + Node* vt = create_vt_node(start, vk, vk, 0, j); map->init_req(i, gvn.transform(vt)); - int extra = 0; - for (int k = 0; k < vk->nof_nonstatic_fields(); k++) { - ciField* f = vk->nonstatic_field_at(k); - BasicType bt = f->type()->basic_type(); - if (bt == T_LONG || bt == T_DOUBLE) { - extra++; - } - } - j += extra + vk->nof_nonstatic_fields(); + j += vk->value_arg_slots(); } else { Node* parm = gvn.transform(new ParmNode(start, j)); map->init_req(i, parm); --- old/src/share/vm/opto/type.cpp 2016-12-13 16:55:42.710288592 +0100 +++ new/src/share/vm/opto/type.cpp 2016-12-13 16:55:42.646288715 +0100 @@ -1835,7 +1835,7 @@ if (type->basic_type() == T_VALUETYPE) { assert(type->is_valuetype(), "inconsistent type"); ciValueKlass* vk = (ciValueKlass*)type; - vt_extra += vk->extra_value_args(); + vt_extra += vk->value_arg_slots()-1; } } assert(((int)arg_cnt) + vt_extra >= 0, "negative number of actual arguments?"); @@ -1847,7 +1847,7 @@ arg_cnt++; if (vt_fields_as_args && recv->is_valuetype()) { ciValueKlass* vk = (ciValueKlass*)recv; - vt_extra += vk->extra_value_args(); + vt_extra += vk->value_arg_slots()-1; } field_array = fields(arg_cnt + vt_extra); // Use get_const_type here because it respects UseUniqueSubclasses: --- old/test/compiler/valhalla/valuetypes/ValueTypeTestBench.java 2016-12-13 16:55:43.062287912 +0100 +++ new/test/compiler/valhalla/valuetypes/ValueTypeTestBench.java 2016-12-13 16:55:43.002288028 +0100 @@ -30,6 +30,7 @@ * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main ClassFileInstaller jdk.test.lib.Platform * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+ValueTypePassFieldsAsArgs * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs @@ -813,9 +814,8 @@ } } - public static void main(String[] args) throws Throwable { - if (args.length == 0) { - ArrayList all_args = new ArrayList(List.of( + private static void execute_vm(String... extra_args) throws Throwable { + ArrayList all_args = new ArrayList(List.of( "-noverify", "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI", "-XX:-TieredCompilation", "-XX:-BackgroundCompilation", @@ -824,24 +824,31 @@ "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*" )); - // Run tests in own process and verify output - all_args.add("-XX:+UnlockExperimentalVMOptions"); + all_args.addAll(List.of(extra_args)); + // Run tests in own process and verify output + all_args.add(ValueTypeTestBench.class.getName()); + all_args.add("run"); + OutputAnalyzer oa = ProcessTools.executeTestJvm(all_args.toArray(new String[0])); + // If ideal graph printing is enabled/supported, verify output + String output = oa.getOutput(); + oa.shouldHaveExitValue(0); + if (output.contains("PrintIdeal enabled")) { + parseOutput(output); + } else { + System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?"); + } + } + + public static void main(String[] args) throws Throwable { + if (args.length == 0) { + String field_as_args; if ((Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs")) { - all_args.add("-XX:+ValueTypePassFieldsAsArgs"); - } else { - all_args.add("-XX:-ValueTypePassFieldsAsArgs"); - } - all_args.add(ValueTypeTestBench.class.getName()); - all_args.add("run"); - OutputAnalyzer oa = ProcessTools.executeTestJvm(all_args.toArray(new String[0])); - // If ideal graph printing is enabled/supported, verify output - String output = oa.getOutput(); - oa.shouldHaveExitValue(0); - if (output.contains("PrintIdeal enabled")) { - parseOutput(output); + field_as_args = "-XX:+ValueTypePassFieldsAsArgs"; } else { - System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?"); + field_as_args = "-XX:-ValueTypePassFieldsAsArgs"; } + execute_vm("-XX:+UnlockExperimentalVMOptions", field_as_args); + execute_vm("-XX:+AlwaysIncrementalInline", "-XX:+UnlockExperimentalVMOptions", field_as_args); } else { if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { System.out.println("PrintIdeal enabled");