diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index dd183f36ea2..375cb402892 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -1487,23 +1487,32 @@ JRT_ENTRY(void, InterpreterRuntime::member_name_arg_or_null(JavaThread* current, Method* method, address bcp)) Bytecodes::Code code = Bytecodes::code_at(method, bcp); if (code != Bytecodes::_invokestatic) { + current->set_vm_result_oop(nullptr); return; } + ConstantPool* cpool = method->constants(); int cp_index = Bytes::get_native_u2(bcp + 1); Symbol* cname = cpool->klass_name_at(cpool->klass_ref_index_at(cp_index, code)); Symbol* mname = cpool->name_ref_at(cp_index, code); - if (MethodHandles::has_member_arg(cname, mname)) { - oop member_name_oop = cast_to_oop(member_name); - if (java_lang_invoke_DirectMethodHandle::is_instance(member_name_oop)) { - // FIXME: remove after j.l.i.InvokerBytecodeGenerator code shape is updated. - member_name_oop = java_lang_invoke_DirectMethodHandle::member(member_name_oop); - } - current->set_vm_result_oop(member_name_oop); - } else { + if (!MethodHandles::has_member_arg(cname, mname)) { current->set_vm_result_oop(nullptr); + return; } + + oop member_name_oop = cast_to_oop(member_name); + + guarantee(member_name_oop != nullptr, "member_name_oop should not be nullptr"); + guarantee(oopDesc::is_oop(member_name_oop), "member_name_oop should be an oop"); + guarantee(java_lang_invoke_MemberName::is_instance(member_name_oop) || + java_lang_invoke_DirectMethodHandle::is_instance(member_name_oop), + "member_name_oop is not MemberName or DMH"); + + if (java_lang_invoke_DirectMethodHandle::is_instance(member_name_oop)) { + member_name_oop = java_lang_invoke_DirectMethodHandle::member(member_name_oop); + } + current->set_vm_result_oop(member_name_oop); JRT_END #endif // INCLUDE_JVMTI diff --git a/test/hotspot/jtreg/compiler/jsr292/InvokerSignatureMismatch.java b/test/hotspot/jtreg/compiler/jsr292/InvokerSignatureMismatch.java index 188051025ad..6e684ea104c 100644 --- a/test/hotspot/jtreg/compiler/jsr292/InvokerSignatureMismatch.java +++ b/test/hotspot/jtreg/compiler/jsr292/InvokerSignatureMismatch.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package compiler.jsr292; import java.lang.invoke.MethodHandle; @@ -39,7 +62,7 @@ public class InvokerSignatureMismatch { static void mainLink(int i) throws Throwable { Object name = MethodHandleHelper.internalMemberName(INT_MH); - MethodHandleHelper.linkToStatic((float) i, name); + MethodHandleHelper.linkToStatic(name, (float) i); } static void mainInvoke(int i) throws Throwable { diff --git a/test/hotspot/jtreg/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java b/test/hotspot/jtreg/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java index a422e52986c..64eb58c5a2d 100644 --- a/test/hotspot/jtreg/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java +++ b/test/hotspot/jtreg/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ public class MethodHandleHelper { } @ForceInline - public static void linkToStatic(float arg, Object name) throws Throwable { + public static void linkToStatic(Object name, float arg) throws Throwable { MethodHandle.linkToStatic(arg, name); } diff --git a/test/hotspot/jtreg/runtime/interpreter/PopFrameMethodNameInvariantTest.java b/test/hotspot/jtreg/runtime/interpreter/PopFrameMethodNameInvariantTest.java new file mode 100644 index 00000000000..bd02227c464 --- /dev/null +++ b/test/hotspot/jtreg/runtime/interpreter/PopFrameMethodNameInvariantTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package runtime.interpreter; + +import com.sun.jdi.Bootstrap; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.connect.LaunchingConnector; +import com.sun.jdi.connect.VMStartException; +import com.sun.jdi.event.BreakpointEvent; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.request.ClassPrepareRequest; +import com.sun.jdi.request.EventRequestManager; +import jdk.test.lib.Utils; + +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleHelper; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.nio.file.Path; +import java.util.Map; + +/* + * @test + * @bug 8380080 + * @summary MemberName in local0 must be preserved when PopFrame re-executes direct MethodHandles.linkToStatic + * @requires vm.jvmti + * @requires vm.flavor != "zero" + * @library ../../compiler/jsr292/patches /test/lib + * @modules java.base/jdk.internal.vm.annotation + * jdk.jdi + * @build java.base/java.lang.invoke.MethodHandleHelper + * @run driver runtime.interpreter.PopFrameMethodNameInvariantTest + */ + +public class PopFrameMethodNameInvariantTest { + public static class Target { + static void body(float x) {} + public static void main(String[] args) throws Throwable { + MethodHandle target = MethodHandles.lookup().findStatic( + Target.class, + "body", + MethodType.methodType(void.class, float.class)); + Object name = MethodHandleHelper.internalMemberName(target); + MethodHandleHelper.linkToStatic(name, (float)1.0); + } + } + + public static void main(String[] args) throws Exception { + VirtualMachine vm = getVm(); + EventRequestManager eventRequestManager = vm.eventRequestManager(); + ClassPrepareRequest classPrepareRequest = eventRequestManager.createClassPrepareRequest(); + classPrepareRequest.addClassFilter(Target.class.getName()); + classPrepareRequest.enable(); + outerLoop: + while (true) { + EventSet eventSet = vm.eventQueue().remove(); + for (Event event : eventSet) { + if (event instanceof ClassPrepareEvent prepareEvent) { + eventRequestManager.createBreakpointRequest( + prepareEvent.referenceType() + .methodsByName("body") + .get(0) + .location() + ).enable(); + } + if (event instanceof BreakpointEvent breakpointEvent) { + breakpointEvent.request().disable(); + breakpointEvent.thread().popFrames(breakpointEvent.thread().frame(0)); + eventSet.resume(); + break outerLoop; + } + } + eventSet.resume(); + } + int exitCode = vm.process().waitFor(); + if (exitCode != 0) { + throw new RuntimeException("Debugee exited with code " + exitCode); + } + } + + private static VirtualMachine getVm() throws IOException, IllegalConnectorArgumentsException, VMStartException { + LaunchingConnector connector = Bootstrap.virtualMachineManager().defaultConnector(); + Map argumentMap = connector.defaultArguments(); + argumentMap.get("main").setValue(Target.class.getName()); + String options = String.join(" ", Utils.getTestJavaOpts()); + String patchPath = System.getProperty("test.patch.path"); + if (patchPath != null) { + options += " --patch-module=java.base=\"" + Path.of(patchPath, "java.base") + "\""; + } + argumentMap.get("options").setValue((options + " -Xint").trim()); + return connector.launch(argumentMap); + } +}