--- old/src/hotspot/cpu/zero/methodHandles_zero.cpp 2018-06-04 16:06:45.772312645 +0200 +++ new/src/hotspot/cpu/zero/methodHandles_zero.cpp 2018-06-04 16:06:45.492313194 +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,13 @@ 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, hence AME. + if (vmtarget != NULL) { + invoke_target(vmtarget, THREAD); + } else { + throw_AME(recv->klass(), target, THREAD); + } return 0; } --- old/src/hotspot/cpu/zero/methodHandles_zero.hpp 2018-06-04 16:06:46.484311248 +0200 +++ new/src/hotspot/cpu/zero/methodHandles_zero.hpp 2018-06-04 16:06:46.201311803 +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); --- old/src/hotspot/share/interpreter/bytecodeInterpreter.cpp 2018-06-04 16:06:47.193309858 +0200 +++ new/src/hotspot/share/interpreter/bytecodeInterpreter.cpp 2018-06-04 16:06:46.913310407 +0200 @@ -2572,11 +2572,11 @@ istate->set_msg(call_method); // Special case of invokeinterface called for virtual method of - // java.lang.Object. See cpCacheOop.cpp for details. + // java.lang.Object. See cpCache.cpp for details. // This code isn't produced by javac, but could be produced by // another compliant java compiler. + 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(); @@ -2593,6 +2593,27 @@ // 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. + 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 @@ -2602,10 +2623,9 @@ #endif /* VM_JVMTI */ istate->set_bcp_advance(5); UPDATE_PC_AND_RETURN(0); // I'll be back... - } + } // this could definitely be cleaned up QQQ - Method* callee; Method *interface_method = cache->f2_as_interface_method(); InstanceKlass* iclass = interface_method->method_holder();