--- old/src/share/vm/opto/callGenerator.cpp 2017-06-20 21:25:42.645655495 +0200 +++ new/src/share/vm/opto/callGenerator.cpp 2017-06-20 21:25:38.661667115 +0200 @@ -888,6 +888,27 @@ } } +static void cast_argument(int arg_nb, ciType* t, GraphKit& kit) { + PhaseGVN& gvn = kit.gvn(); + Node* arg = kit.argument(arg_nb); + const Type* arg_type = arg->bottom_type(); + const Type* sig_type = TypeOopPtr::make_from_klass(t->as_klass()); + if (t->is_valuetype()) { + assert(!(arg_type->isa_valuetype() && t == kit.C->env()->___Value_klass()), "need to a pointer to the value type"); + if (arg_type->isa_valuetypeptr() && t != kit.C->env()->___Value_klass()) { + const Type* sig_type = TypeOopPtr::make_from_klass(t->as_klass()); + Node* cast = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type)); + Node* vt = ValueTypeNode::make(gvn, kit.merged_memory(), cast); + kit.set_argument(arg_nb, vt); + } + } else { + if (arg_type->isa_oopptr() && !arg_type->higher_equal(sig_type)) { + Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type)); + kit.set_argument(arg_nb, cast_obj); + } + } +} + CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* caller, ciMethod* callee, bool& input_not_const, bool delayed_forbidden) { GraphKit kit(jvms); PhaseGVN& gvn = kit.gvn(); @@ -953,25 +974,13 @@ const int receiver_skip = target->is_static() ? 0 : 1; // Cast receiver to its type. if (!target->is_static()) { - Node* arg = kit.argument(0); - const TypeOopPtr* arg_type = arg->bottom_type()->isa_oopptr(); - const Type* sig_type = TypeOopPtr::make_from_klass(signature->accessing_klass()); - if (arg_type != NULL && !arg_type->higher_equal(sig_type)) { - Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type)); - kit.set_argument(0, cast_obj); - } + cast_argument(0, signature->accessing_klass(), kit); } // Cast reference arguments to its type. for (int i = 0, j = 0; i < signature->count(); i++) { ciType* t = signature->type_at(i); if (t->is_klass()) { - Node* arg = kit.argument(receiver_skip + j); - const TypeOopPtr* arg_type = arg->bottom_type()->isa_oopptr(); - const Type* sig_type = TypeOopPtr::make_from_klass(t->as_klass()); - if (arg_type != NULL && !arg_type->higher_equal(sig_type)) { - Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type)); - kit.set_argument(receiver_skip + j, cast_obj); - } + cast_argument(receiver_skip + j, t, kit); } j += t->size(); // long and double take two slots } --- old/src/share/vm/opto/graphKit.cpp 2017-06-20 21:25:47.212642175 +0200 +++ new/src/share/vm/opto/graphKit.cpp 2017-06-20 21:25:42.710655305 +0200 @@ -2126,7 +2126,7 @@ int skip = Bytecodes::has_receiver(bc) ? 1 : 0; for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) { const Type *targ = tf->domain_sig()->field_at(j + TypeFunc::Parms); - if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) { + if (targ->isa_oopptr() && !targ->isa_valuetypeptr()) { bool maybe_null = true; ciKlass* better_type = NULL; if (method()->argument_profiled_type(bci(), i, better_type, maybe_null)) { --- old/src/share/vm/opto/type.cpp 2017-06-20 21:25:51.197630551 +0200 +++ new/src/share/vm/opto/type.cpp 2017-06-20 21:25:47.287641956 +0200 @@ -2023,7 +2023,7 @@ if (vt_fields_as_args) { for (int i = 0; i < sig->count(); i++) { ciType* type = sig->type_at(i); - if (type->basic_type() == T_VALUETYPE) { + if (type->basic_type() == T_VALUETYPE && type != ciEnv::current()->___Value_klass()) { assert(type->is_valuetype(), "inconsistent type"); ciValueKlass* vk = (ciValueKlass*)type; vt_extra += vk->value_arg_slots()-1; @@ -2081,8 +2081,7 @@ break; case T_VALUETYPE: { assert(type->is_valuetype(), "inconsistent type"); - assert(type != ciEnv::current()->___Value_klass(), "unsupported"); - if (vt_fields_as_args) { + if (vt_fields_as_args && type != ciEnv::current()->___Value_klass()) { ciValueKlass* vk = (ciValueKlass*)type; collect_value_fields(vk, field_array, pos); } else { --- old/test/compiler/valhalla/valuetypes/ValueTypeTestBench.java 2017-06-20 21:25:55.234618777 +0200 +++ new/test/compiler/valhalla/valuetypes/ValueTypeTestBench.java 2017-06-20 21:25:51.279630312 +0200 @@ -2146,7 +2146,7 @@ } @DontCompile - public void test76_verifier(boolean warmup) throws Exception { + public void test76_verifier(boolean warmup) { MyValue3 vt = test76(); test76_vt.verify(vt); } @@ -2365,6 +2365,67 @@ ); } + // When test85_helper1 is inlined in test85, the method handle + // linker that called it is passed a pointer to a copy of vt + // stored in memory. The method handle linker needs to load the + // fields from memory before it inlines test85_helper1. + static public int test85_helper1(MyValue1 vt) { + return vt.x; + } + + static MyValue1 test85_vt = MyValue1.createWithFieldsInline(rI, rL); + static public MyValue1 test85_helper2() { + return test85_vt; + } + + static final MethodHandle test85_mh; + + @Test + public int test85() throws Throwable { + return (int)test85_mh.invokeExact(); + } + + @DontCompile + public void test85_verifier(boolean warmup) throws Throwable { + int i = test85(); + Asserts.assertEQ(i, test85_vt.x); + } + + // Test method handle call with value type argument + public int test86_target(MyValue1 vt) { + return vt.x; + } + + static final MethodHandle test86_mh; + MyValue1 test86_vt = MyValue1.createWithFieldsInline(rI, rL); + + @Test + public int test86() throws Throwable { + return (int)test86_mh.invokeExact(this, test86_vt); + } + + @DontCompile + public void test86_verifier(boolean warmup) throws Throwable { + int i = test86(); + Asserts.assertEQ(i, test86_vt.x); + } + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + + MethodType test85_mt1 = MethodType.fromMethodDescriptorString("(Qcompiler/valhalla/valuetypes/MyValue1;)I", ValueTypeTestBench.class.getClassLoader()); + MethodType test85_mt2 = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue1;", ValueTypeTestBench.class.getClassLoader()); + MethodHandle test85_mh1 = lookup.findStatic(ValueTypeTestBench.class, "test85_helper1", test85_mt1); + MethodHandle test85_mh2 = lookup.findStatic(ValueTypeTestBench.class, "test85_helper2", test85_mt2); + test85_mh = MethodHandles.filterReturnValue(test85_mh2, test85_mh1); + + MethodType test86_mt = MethodType.fromMethodDescriptorString("(Qcompiler/valhalla/valuetypes/MyValue1;)I", ValueTypeTestBench.class.getClassLoader()); + test86_mh = lookup.findVirtual(ValueTypeTestBench.class, "test86_target", test86_mt); + } catch (NoSuchMethodException|IllegalAccessException e) { + throw new RuntimeException("method handle lookup fails"); + } + } // ========== Test infrastructure ========== private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();