OpenJDK / jdk / jdk
changeset 50736:f703d45c5687
8203188: Add JEP-181 support to the Zero interpreter
Reviewed-by: dholmes, chrisphi
author | sgehwolf |
---|---|
date | Tue, 05 Jun 2018 11:55:39 +0200 |
parents | 2f2af62dfac7 |
children | ada9735476b2 |
files | src/hotspot/cpu/zero/methodHandles_zero.cpp src/hotspot/cpu/zero/methodHandles_zero.hpp src/hotspot/share/interpreter/bytecodeInterpreter.cpp |
diffstat | 3 files changed, 67 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/src/hotspot/cpu/zero/methodHandles_zero.cpp Sat Jun 23 01:32:41 2018 -0400 +++ b/src/hotspot/cpu/zero/methodHandles_zero.cpp Tue Jun 05 11:55:39 2018 +0200 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "interpreter/cppInterpreterGenerator.hpp" #include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/method.inline.hpp" @@ -65,6 +66,37 @@ } +void MethodHandles::throw_AME(Klass* rcvr, Method* interface_method, TRAPS) { + + JavaThread *thread = (JavaThread *) THREAD; + // Set up the frame anchor if it isn't already + bool has_last_Java_frame = thread->has_last_Java_frame(); + if (!has_last_Java_frame) { + intptr_t *sp = thread->zero_stack()->sp(); + ZeroFrame *frame = thread->top_zero_frame(); + while (frame) { + if (frame->is_interpreter_frame()) { + interpreterState istate = + frame->as_interpreter_frame()->interpreter_state(); + if (istate->self_link() == istate) + break; + } + + sp = ((intptr_t *) frame) + 1; + frame = frame->next(); + } + + assert(frame != NULL, "must be"); + thread->set_last_Java_frame(frame, sp); + } + InterpreterRuntime::throw_AbstractMethodErrorVerbose(thread, rcvr, interface_method); + // Reset the frame anchor if necessary + if (!has_last_Java_frame) { + thread->reset_last_Java_frame(); + } + +} + int MethodHandles::method_handle_entry_invokeBasic(Method* method, intptr_t UNUSED, TRAPS) { JavaThread *thread = (JavaThread *) THREAD; @@ -124,8 +156,15 @@ itableMethodEntry* im = ki->first_method_entry(recv->klass()); Method* vmtarget = im[vmindex].method(); - - invoke_target(vmtarget, THREAD); + // Check that the vmtarget entry is non-null. A null entry means + // that the method no longer exists (got deleted) or is private. + // Private class methods can never be an implementation of an + // interface method. In those cases, throw AME. + if (vmtarget != NULL) { + invoke_target(vmtarget, THREAD); + } else { + throw_AME(recv->klass(), target, THREAD); + } return 0; }
--- a/src/hotspot/cpu/zero/methodHandles_zero.hpp Sat Jun 23 01:32:41 2018 -0400 +++ b/src/hotspot/cpu/zero/methodHandles_zero.hpp Tue Jun 05 11:55:39 2018 +0200 @@ -32,6 +32,7 @@ private: static oop popFromStack(TRAPS); static void invoke_target(Method* method, TRAPS); + static void throw_AME(Klass* rcvr, Method* interface_method, TRAPS); static int method_handle_entry_invokeBasic(Method* method, intptr_t UNUSED, TRAPS); static int method_handle_entry_linkToStaticOrSpecial(Method* method, intptr_t UNUSED, TRAPS); static int method_handle_entry_linkToVirtual(Method* method, intptr_t UNUSED, TRAPS);
--- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp Sat Jun 23 01:32:41 2018 -0400 +++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp Tue Jun 05 11:55:39 2018 +0200 @@ -2524,11 +2524,9 @@ istate->set_msg(call_method); // Special case of invokeinterface called for virtual method of - // java.lang.Object. See cpCacheOop.cpp for details. - // This code isn't produced by javac, but could be produced by - // another compliant java compiler. + // java.lang.Object. See cpCache.cpp for details. + Method* callee = NULL; if (cache->is_forced_virtual()) { - Method* callee; CHECK_NULL(STACK_OBJECT(-(cache->parameter_size()))); if (cache->is_vfinal()) { callee = cache->f2_as_vfinal_method(); @@ -2545,6 +2543,29 @@ // Profile 'special case of invokeinterface' virtual call. BI_PROFILE_UPDATE_VIRTUALCALL(rcvrKlass); } + } else if (cache->is_vfinal()) { + // private interface method invocations + // + // Ensure receiver class actually implements + // the resolved interface class. The link resolver + // does this, but only for the first time this + // interface is being called. + int parms = cache->parameter_size(); + oop rcvr = STACK_OBJECT(-parms); + CHECK_NULL(rcvr); + Klass* recv_klass = rcvr->klass(); + Klass* resolved_klass = cache->f1_as_klass(); + if (!recv_klass->is_subtype_of(resolved_klass)) { + ResourceMark rm(THREAD); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Class %s does not implement the requested interface %s", + recv_klass->external_name(), + resolved_klass->external_name()); + VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), buf, note_no_trap); + } + callee = cache->f2_as_vfinal_method(); + } + if (callee != NULL) { istate->set_callee(callee); istate->set_callee_entry_point(callee->from_interpreted_entry()); #ifdef VM_JVMTI @@ -2557,7 +2578,6 @@ } // this could definitely be cleaned up QQQ - Method* callee; Method *interface_method = cache->f2_as_interface_method(); InstanceKlass* iclass = interface_method->method_holder();