diff -r eeb7ae9b81c3 src/share/vm/prims/jvmti.xml --- a/src/share/vm/prims/jvmti.xml Mon Apr 27 19:51:00 2015 -0700 +++ b/src/share/vm/prims/jvmti.xml Tue Apr 28 02:57:04 2015 -0700 @@ -6210,6 +6210,266 @@ + + + + These functions are used to retrieve or set the value of an operand stack slot. + The slot is identified by the depth of the frame containing its + value and the slot's number within that frame. + + + + Get Operand Stack Value - Object + + This function can be used to retrieve the value of an operand + stack slot whose type is Object or a subclass of Object. + + jvmdi + + + + + + + + The thread of the frame containing the slot's value. + + + + + + The depth of the frame containing the slot's value. + + + + + + The slot's number. + + + + + + On return, points to the slot's value. + + + + + + Invalid slot. + + + The slot's type is not + Object or a subclass of Object. + + + Not a visible frame + + + + + + Get Operand Stack Value - Int + + This function can be used to retrieve the value of an operand + stack slot whose type is int, + short, char, byte, or + boolean. + + jvmdi + + + + + + + + The thread of the frame containing the slot's value. + + + + + + The depth of the frame containing the slot's value. + + + + + + The slot's number. + + + + + + On return, points to the slot's value. + + + + + + Invalid slot. + + + The slot's type is not + int, short, + char, byte, or + boolean. + + + Not a visible frame + + + + + + Get Operand Stack Value - Long + + This function can be used to retrieve the value of an operand + stack slot whose type is long. + + jvmdi + + + + + + + + The thread of the frame containing the slot's value. + + + + + + The depth of the frame containing the slot's value. + + + + + + The slot's number. + + + + + + On return, points to the slot's value. + + + + + + Invalid slot. + + + The variable type is not long. + + + Not a visible frame + + + + + + Get Operand Stack Value - Float + + This function can be used to retrieve the value of an operand + stack slot whose type is float. + + jvmdi + + + + + + + + The thread of the frame containing the slot's value. + + + + + + The depth of the frame containing the slot's value. + + + + + + The slot's number. + + + + + + On return, points to the slot's value. + + + + + + Invalid slot. + + + The variable type is not float. + + + Not a visible frame + + + + + + Get Operand Stack Value - Double + + This function can be used to retrieve the value of an operand + stack slot whose type is double. + + jvmdi + + + + + + + + The thread of the frame containing the slot's value. + + + + + + The depth of the frame containing the slot's value. + + + + + + The slot's number. + + + + + + On return, points to the slot's value. + + + + + + Invalid slot. + + + The variable type is not double. + + + Not a visible frame + + + + + diff -r eeb7ae9b81c3 src/share/vm/prims/jvmtiEnv.cpp --- a/src/share/vm/prims/jvmtiEnv.cpp Mon Apr 27 19:51:00 2015 -0700 +++ b/src/share/vm/prims/jvmtiEnv.cpp Tue Apr 28 02:57:04 2015 -0700 @@ -1998,6 +1998,106 @@ // + // Operand Stack functions + // + +// Threads_lock NOT held, java_thread not protected by lock +// java_thread - pre-checked +// java_thread - unchecked +// depth - pre-checked as non-negative +// value_ptr - pre-checked for NULL +jvmtiError +JvmtiEnv::GetOperandObject(JavaThread* java_thread, jint depth, jint slot, jobject* value_ptr) { + JavaThread* current_thread = JavaThread::current(); + // rm object is created to clean up the javaVFrame created in + // doit_prologue(), but after doit() is finished with it. + ResourceMark rm(current_thread); + + VM_GetOperand op(java_thread, current_thread, depth, slot); + VMThread::execute(&op); + jvmtiError err = op.result(); + if (err != JVMTI_ERROR_NONE) { + return err; + } else { + *value_ptr = op.value().l; + return JVMTI_ERROR_NONE; + } +} /* end GetOperandObject */ + + +// Threads_lock NOT held, java_thread not protected by lock +// java_thread - pre-checked +// java_thread - unchecked +// depth - pre-checked as non-negative +// value_ptr - pre-checked for NULL +jvmtiError +JvmtiEnv::GetOperandInt(JavaThread* java_thread, jint depth, jint slot, jint* value_ptr) { + // rm object is created to clean up the javaVFrame created in + // doit_prologue(), but after doit() is finished with it. + ResourceMark rm; + + VM_GetOperand op(java_thread, depth, slot, T_INT); + VMThread::execute(&op); + *value_ptr = op.value().i; + return op.result(); +} /* end GetOperandInt */ + + +// Threads_lock NOT held, java_thread not protected by lock +// java_thread - pre-checked +// java_thread - unchecked +// depth - pre-checked as non-negative +// value_ptr - pre-checked for NULL +jvmtiError +JvmtiEnv::GetOperandLong(JavaThread* java_thread, jint depth, jint slot, jlong* value_ptr) { + // rm object is created to clean up the javaVFrame created in + // doit_prologue(), but after doit() is finished with it. + ResourceMark rm; + + VM_GetOperand op(java_thread, depth, slot, T_LONG); + VMThread::execute(&op); + *value_ptr = op.value().j; + return op.result(); +} /* end GetOperandLong */ + + +// Threads_lock NOT held, java_thread not protected by lock +// java_thread - pre-checked +// java_thread - unchecked +// depth - pre-checked as non-negative +// value_ptr - pre-checked for NULL +jvmtiError +JvmtiEnv::GetOperandFloat(JavaThread* java_thread, jint depth, jint slot, jfloat* value_ptr) { + // rm object is created to clean up the javaVFrame created in + // doit_prologue(), but after doit() is finished with it. + ResourceMark rm; + + VM_GetOperand op(java_thread, depth, slot, T_FLOAT); + VMThread::execute(&op); + *value_ptr = op.value().f; + return op.result(); +} /* end GetOperandFloat */ + + +// Threads_lock NOT held, java_thread not protected by lock +// java_thread - pre-checked +// java_thread - unchecked +// depth - pre-checked as non-negative +// value_ptr - pre-checked for NULL +jvmtiError +JvmtiEnv::GetOperandDouble(JavaThread* java_thread, jint depth, jint slot, jdouble* value_ptr) { + // rm object is created to clean up the javaVFrame created in + // doit_prologue(), but after doit() is finished with it. + ResourceMark rm; + + VM_GetOperand op(java_thread, depth, slot, T_DOUBLE); + VMThread::execute(&op); + *value_ptr = op.value().d; + return op.result(); +} /* end GetOperandDouble */ + + + // // Breakpoint functions // diff -r eeb7ae9b81c3 src/share/vm/prims/jvmtiImpl.cpp --- a/src/share/vm/prims/jvmtiImpl.cpp Mon Apr 27 19:51:00 2015 -0700 +++ b/src/share/vm/prims/jvmtiImpl.cpp Tue Apr 28 02:57:04 2015 -0700 @@ -824,6 +824,147 @@ JavaThread* thread, JavaThread* caller_thread, jint depth) : VM_GetOrSetLocal(thread, caller_thread, depth, 0) {} + +/////////////////////////////////////////////////////////////// +// +// class VM_GetOperand +// + +// Constructor for non-object getter +VM_GetOperand::VM_GetOperand(JavaThread* thread, jint depth, int index, BasicType type) + : _thread(thread) + , _calling_thread(NULL) + , _depth(depth) + , _index(index) + , _type(type) + , _jvf(NULL) + , _result(JVMTI_ERROR_NONE) +{ +} + +// Constructor for object getter +VM_GetOperand::VM_GetOperand(JavaThread* thread, JavaThread* calling_thread, jint depth, int index) + : _thread(thread) + , _calling_thread(calling_thread) + , _depth(depth) + , _index(index) + , _type(T_OBJECT) + , _jvf(NULL) + , _result(JVMTI_ERROR_NONE) +{ +} + +vframe *VM_GetOperand::get_vframe() { + if (!_thread->has_last_Java_frame()) { + return NULL; + } + RegisterMap reg_map(_thread); + vframe *vf = _thread->last_java_vframe(®_map); + int d = 0; + while ((vf != NULL) && (d < _depth)) { + vf = vf->java_sender(); + d++; + } + return vf; +} + +javaVFrame *VM_GetOperand::get_java_vframe() { + vframe* vf = get_vframe(); + if (vf == NULL) { + _result = JVMTI_ERROR_NO_MORE_FRAMES; + return NULL; + } + javaVFrame *jvf = (javaVFrame*)vf; + + if (!vf->is_java_frame()) { + _result = JVMTI_ERROR_OPAQUE_FRAME; + return NULL; + } + return jvf; +} + +// Checks error conditions: +// JVMTI_ERROR_INVALID_SLOT +// Returns: 'true' - everything is Ok, 'false' - error code +bool VM_GetOperand::check_slot_type(javaVFrame* jvf) { + // index checking + StackValueCollection *expressions = _jvf->expressions(); + jint size = expressions->size(); + size -= (_type == T_LONG || _type == T_DOUBLE) ? 1 : 0; + + if (_index < 0 || _index >= size) { + _result = JVMTI_ERROR_INVALID_SLOT; + return false; + } + + // FIXME insert proper type-checking code here + + return true; +} + +bool VM_GetOperand::doit_prologue() { + _jvf = get_java_vframe(); + NULL_CHECK(_jvf, false); + + if (_jvf->method()->is_native()) { + if (getting_receiver() && !_jvf->method()->is_static()) { + return true; + } else { + _result = JVMTI_ERROR_OPAQUE_FRAME; + return false; + } + } + + if (!check_slot_type(_jvf)) { + return false; + } + return true; +} + +void VM_GetOperand::doit() { + // get + if (_jvf->method()->is_native() && _jvf->is_compiled_frame()) { + assert(getting_receiver(), "Can only get here when getting receiver"); + oop receiver = _jvf->fr().get_native_receiver(); + _value.l = JNIHandles::make_local(_calling_thread, receiver); + } else { + StackValueCollection *expressions = _jvf->expressions(); + + if (expressions->at(_index)->type() == T_CONFLICT) { + memset(&_value, 0, sizeof(_value)); + _value.l = NULL; + return; + } + + switch (_type) { + case T_INT: _value.i = expressions->int_at (_index); break; + case T_LONG: _value.j = expressions->long_at (_index); break; + case T_FLOAT: _value.f = expressions->float_at (_index); break; + case T_DOUBLE: _value.d = expressions->double_at(_index); break; + case T_OBJECT: { + // Wrap the oop to be returned in a local JNI handle since + // oops_do() no longer applies after doit() is finished. + intptr_t temp = expressions->at(_index)->get_int(); + intptr_t *addr = &temp; + _value.l = JNIHandles::make_local(_calling_thread, *(oop *)addr); + break; + } + default: ShouldNotReachHere(); + } + } +} + + +bool VM_GetOperand::allow_nested_vm_operations() const { + return true; // May need to deoptimize +} + + +VM_GetOperandReceiver::VM_GetOperandReceiver( + JavaThread* thread, JavaThread* caller_thread, jint depth) + : VM_GetOperand(thread, caller_thread, depth, 0) {} + + ///////////////////////////////////////////////////////////////////////////////////////// // diff -r eeb7ae9b81c3 src/share/vm/prims/jvmtiImpl.hpp --- a/src/share/vm/prims/jvmtiImpl.hpp Mon Apr 27 19:51:00 2015 -0700 +++ b/src/share/vm/prims/jvmtiImpl.hpp Tue Apr 28 02:57:04 2015 -0700 @@ -417,6 +417,57 @@ /////////////////////////////////////////////////////////////// +// This is a copy of VM_GetOrSetLocal modified to access operands +// instead of local variables. +// +class VM_GetOperand : public VM_Operation { + protected: + JavaThread* _thread; + JavaThread* _calling_thread; + jint _depth; + jint _index; + BasicType _type; + jvalue _value; + javaVFrame* _jvf; + + // It is possible to get the receiver out of a non-static native wrapper + // frame. Use VM_GetReceiver to do this. + virtual bool getting_receiver() const { return false; } + + jvmtiError _result; + + vframe* get_vframe(); + javaVFrame* get_java_vframe(); + bool check_slot_type(javaVFrame* vf); + +public: + // Constructor for non-object getter + VM_GetOperand(JavaThread* thread, jint depth, jint index, BasicType type); + + // Constructor for object getter + VM_GetOperand(JavaThread* thread, JavaThread* calling_thread, jint depth, int index); + + VMOp_Type type() const { return VMOp_GetOperand; } + jvalue value() { return _value; } + jvmtiError result() { return _result; } + + bool doit_prologue(); + void doit(); + bool allow_nested_vm_operations() const; + const char* name() const { return "get operands"; } +}; + +class VM_GetOperandReceiver : public VM_GetOperand { + protected: + virtual bool getting_receiver() const { return true; } + + public: + VM_GetOperandReceiver(JavaThread* thread, JavaThread* calling_thread, jint depth); + const char* name() const { return "get operand receiver"; } +}; + + +/////////////////////////////////////////////////////////////// // // class JvmtiSuspendControl // diff -r eeb7ae9b81c3 src/share/vm/runtime/vm_operations.hpp --- a/src/share/vm/runtime/vm_operations.hpp Mon Apr 27 19:51:00 2015 -0700 +++ b/src/share/vm/runtime/vm_operations.hpp Tue Apr 28 02:57:04 2015 -0700 @@ -88,6 +88,7 @@ template(GetFrameLocation) \ template(ChangeBreakpoints) \ template(GetOrSetLocal) \ + template(GetOperand) \ template(GetCurrentLocation) \ template(EnterInterpOnlyMode) \ template(ChangeSingleStep) \