8269592
: [JVMCI] Optimize c2v_iterateFrames
Reviewed-by: kvn, never, dlong
This commit is contained in:
parent
c0d4efff3c
commit
b1bb05bcf4
@ -62,6 +62,7 @@
|
||||
#include "runtime/stackFrameStream.inline.hpp"
|
||||
#include "runtime/timerTrace.hpp"
|
||||
#include "runtime/vframe_hp.hpp"
|
||||
#include "runtime/vframe.inline.hpp"
|
||||
|
||||
JVMCIKlassHandle::JVMCIKlassHandle(Thread* thread, Klass* klass) {
|
||||
_thread = thread;
|
||||
@ -1147,30 +1148,99 @@ C2V_VMENTRY_NULL(jobject, getSymbol, (JNIEnv* env, jobject, jlong symbol))
|
||||
return JVMCIENV->get_jobject(sym);
|
||||
C2V_END
|
||||
|
||||
bool matches(jobjectArray methods, Method* method, JVMCIEnv* JVMCIENV) {
|
||||
/*
|
||||
* Used by matches() to convert a ResolvedJavaMethod[] to an array of Method*.
|
||||
*/
|
||||
GrowableArray<Method*>* init_resolved_methods(jobjectArray methods, JVMCIEnv* JVMCIENV) {
|
||||
objArrayOop methods_oop = (objArrayOop) JNIHandles::resolve(methods);
|
||||
|
||||
GrowableArray<Method*>* resolved_methods = new GrowableArray<Method*>(methods_oop->length());
|
||||
for (int i = 0; i < methods_oop->length(); i++) {
|
||||
oop resolved = methods_oop->obj_at(i);
|
||||
if ((resolved->klass() == HotSpotJVMCI::HotSpotResolvedJavaMethodImpl::klass()) && HotSpotJVMCI::asMethod(JVMCIENV, resolved) == method) {
|
||||
Method* resolved_method = NULL;
|
||||
if (resolved->klass() == HotSpotJVMCI::HotSpotResolvedJavaMethodImpl::klass()) {
|
||||
resolved_method = HotSpotJVMCI::asMethod(JVMCIENV, resolved);
|
||||
}
|
||||
resolved_methods->append(resolved_method);
|
||||
}
|
||||
return resolved_methods;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used by c2v_iterateFrames to check if `method` matches one of the ResolvedJavaMethods in the `methods` array.
|
||||
* The ResolvedJavaMethod[] array is converted to a Method* array that is then cached in the resolved_methods_ref in/out parameter.
|
||||
* In case of a match, the matching ResolvedJavaMethod is returned in matched_jvmci_method_ref.
|
||||
*/
|
||||
bool matches(jobjectArray methods, Method* method, GrowableArray<Method*>** resolved_methods_ref, Handle* matched_jvmci_method_ref, Thread* THREAD, JVMCIEnv* JVMCIENV) {
|
||||
GrowableArray<Method*>* resolved_methods = *resolved_methods_ref;
|
||||
if (resolved_methods == NULL) {
|
||||
resolved_methods = init_resolved_methods(methods, JVMCIENV);
|
||||
*resolved_methods_ref = resolved_methods;
|
||||
}
|
||||
assert(method != NULL, "method should not be NULL");
|
||||
assert(resolved_methods->length() == ((objArrayOop) JNIHandles::resolve(methods))->length(), "arrays must have the same length");
|
||||
for (int i = 0; i < resolved_methods->length(); i++) {
|
||||
Method* m = resolved_methods->at(i);
|
||||
if (m == method) {
|
||||
*matched_jvmci_method_ref = Handle(THREAD, ((objArrayOop) JNIHandles::resolve(methods))->obj_at(i));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void call_interface(JavaValue* result, Klass* spec_klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
||||
/*
|
||||
* Resolves an interface call to a concrete method handle.
|
||||
*/
|
||||
methodHandle resolve_interface_call(Klass* spec_klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
||||
CallInfo callinfo;
|
||||
Handle receiver = args->receiver();
|
||||
Klass* recvrKlass = receiver.is_null() ? (Klass*)NULL : receiver->klass();
|
||||
LinkInfo link_info(spec_klass, name, signature);
|
||||
LinkResolver::resolve_interface_call(
|
||||
callinfo, receiver, recvrKlass, link_info, true, CHECK);
|
||||
callinfo, receiver, recvrKlass, link_info, true, CHECK_(methodHandle()));
|
||||
methodHandle method(THREAD, callinfo.selected_method());
|
||||
assert(method.not_null(), "should have thrown exception");
|
||||
return method;
|
||||
}
|
||||
|
||||
// Invoke the method
|
||||
JavaCalls::call(result, method, args, CHECK);
|
||||
/*
|
||||
* Used by c2v_iterateFrames to make a new vframeStream at the given compiled frame id (stack pointer) and vframe id.
|
||||
*/
|
||||
void resync_vframestream_to_compiled_frame(vframeStream& vfst, intptr_t* stack_pointer, int vframe_id, JavaThread* thread, TRAPS) {
|
||||
vfst = vframeStream(thread);
|
||||
while (vfst.frame_id() != stack_pointer && !vfst.at_end()) {
|
||||
vfst.next();
|
||||
}
|
||||
if (vfst.frame_id() != stack_pointer) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found after deopt")
|
||||
}
|
||||
if (vfst.is_interpreted_frame()) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected")
|
||||
}
|
||||
while (vfst.vframe_id() != vframe_id) {
|
||||
if (vfst.at_end()) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "vframe not found after deopt")
|
||||
}
|
||||
vfst.next();
|
||||
assert(!vfst.is_interpreted_frame(), "Wrong frame type");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Used by c2v_iterateFrames. Returns an array of any unallocated scope objects or NULL if none.
|
||||
*/
|
||||
GrowableArray<ScopeValue*>* get_unallocated_objects_or_null(GrowableArray<ScopeValue*>* scope_objects) {
|
||||
GrowableArray<ScopeValue*>* unallocated = NULL;
|
||||
for (int i = 0; i < scope_objects->length(); i++) {
|
||||
ObjectValue* sv = (ObjectValue*) scope_objects->at(i);
|
||||
if (sv->value().is_null()) {
|
||||
if (unallocated == NULL) {
|
||||
unallocated = new GrowableArray<ScopeValue*>(scope_objects->length());
|
||||
}
|
||||
unallocated->append(sv);
|
||||
}
|
||||
}
|
||||
return unallocated;
|
||||
}
|
||||
|
||||
C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, jobjectArray initial_methods, jobjectArray match_methods, jint initialSkip, jobject visitor_handle))
|
||||
@ -1183,90 +1253,100 @@ C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, job
|
||||
requireInHotSpot("iterateFrames", JVMCI_CHECK_NULL);
|
||||
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(CHECK_NULL);
|
||||
Handle frame_reference = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL);
|
||||
|
||||
StackFrameStream fst(thread, true /* update */, true /* process_frames */);
|
||||
vframeStream vfst(thread);
|
||||
jobjectArray methods = initial_methods;
|
||||
methodHandle visitor_method;
|
||||
GrowableArray<Method*>* resolved_methods = NULL;
|
||||
|
||||
int frame_number = 0;
|
||||
vframe* vf = vframe::new_vframe(fst, thread);
|
||||
|
||||
while (true) {
|
||||
// look for the given method
|
||||
while (!vfst.at_end()) { // frame loop
|
||||
bool realloc_called = false;
|
||||
while (true) {
|
||||
StackValueCollection* locals = NULL;
|
||||
if (vf->is_compiled_frame()) {
|
||||
// compiled method frame
|
||||
compiledVFrame* cvf = compiledVFrame::cast(vf);
|
||||
if (methods == NULL || matches(methods, cvf->method(), JVMCIENV)) {
|
||||
if (initialSkip > 0) {
|
||||
initialSkip--;
|
||||
} else {
|
||||
ScopeDesc* scope = cvf->scope();
|
||||
// native wrappers do not have a scope
|
||||
if (scope != NULL && scope->objects() != NULL) {
|
||||
GrowableArray<ScopeValue*>* objects;
|
||||
if (!realloc_called) {
|
||||
objects = scope->objects();
|
||||
} else {
|
||||
// some object might already have been re-allocated, only reallocate the non-allocated ones
|
||||
objects = new GrowableArray<ScopeValue*>(scope->objects()->length());
|
||||
for (int i = 0; i < scope->objects()->length(); i++) {
|
||||
ObjectValue* sv = (ObjectValue*) scope->objects()->at(i);
|
||||
if (sv->value().is_null()) {
|
||||
objects->append(sv);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), fst.register_map(), objects, CHECK_NULL);
|
||||
Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures, false);
|
||||
realloc_called = true;
|
||||
intptr_t* frame_id = vfst.frame_id();
|
||||
|
||||
GrowableArray<ScopeValue*>* local_values = scope->locals();
|
||||
assert(local_values != NULL, "NULL locals");
|
||||
typeArrayOop array_oop = oopFactory::new_boolArray(local_values->length(), CHECK_NULL);
|
||||
typeArrayHandle array(THREAD, array_oop);
|
||||
for (int i = 0; i < local_values->length(); i++) {
|
||||
ScopeValue* value = local_values->at(i);
|
||||
if (value->is_object()) {
|
||||
array->bool_at_put(i, true);
|
||||
}
|
||||
}
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_localIsVirtual(JVMCIENV, frame_reference(), array());
|
||||
// Previous compiledVFrame of this frame; use with at_scope() to reuse scope object pool.
|
||||
compiledVFrame* prev_cvf = NULL;
|
||||
|
||||
for (; !vfst.at_end() && vfst.frame_id() == frame_id; vfst.next()) { // vframe loop
|
||||
int frame_number = 0;
|
||||
Method *method = vfst.method();
|
||||
int bci = vfst.bci();
|
||||
|
||||
Handle matched_jvmci_method;
|
||||
if (methods == NULL || matches(methods, method, &resolved_methods, &matched_jvmci_method, THREAD, JVMCIENV)) {
|
||||
if (initialSkip > 0) {
|
||||
initialSkip--;
|
||||
continue;
|
||||
}
|
||||
javaVFrame* vf;
|
||||
if (prev_cvf != NULL && prev_cvf->frame_pointer()->id() == frame_id) {
|
||||
assert(prev_cvf->is_compiled_frame(), "expected compiled Java frame");
|
||||
vf = prev_cvf->at_scope(vfst.decode_offset(), vfst.vframe_id());
|
||||
} else {
|
||||
vf = vfst.asJavaVFrame();
|
||||
}
|
||||
|
||||
StackValueCollection* locals = NULL;
|
||||
typeArrayHandle localIsVirtual_h;
|
||||
if (vf->is_compiled_frame()) {
|
||||
// compiled method frame
|
||||
compiledVFrame* cvf = compiledVFrame::cast(vf);
|
||||
|
||||
ScopeDesc* scope = cvf->scope();
|
||||
// native wrappers do not have a scope
|
||||
if (scope != NULL && scope->objects() != NULL) {
|
||||
prev_cvf = cvf;
|
||||
|
||||
GrowableArray<ScopeValue*>* objects = NULL;
|
||||
if (!realloc_called) {
|
||||
objects = scope->objects();
|
||||
} else {
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_localIsVirtual(JVMCIENV, frame_reference(), NULL);
|
||||
// some object might already have been re-allocated, only reallocate the non-allocated ones
|
||||
objects = get_unallocated_objects_or_null(scope->objects());
|
||||
}
|
||||
|
||||
locals = cvf->locals();
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_bci(JVMCIENV, frame_reference(), cvf->bci());
|
||||
methodHandle mh(THREAD, cvf->method());
|
||||
JVMCIObject method = JVMCIENV->get_jvmci_method(mh, JVMCI_CHECK_NULL);
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_method(JVMCIENV, frame_reference(), JNIHandles::resolve(method.as_jobject()));
|
||||
}
|
||||
}
|
||||
} else if (vf->is_interpreted_frame()) {
|
||||
// interpreted method frame
|
||||
interpretedVFrame* ivf = interpretedVFrame::cast(vf);
|
||||
if (methods == NULL || matches(methods, ivf->method(), JVMCIENV)) {
|
||||
if (initialSkip > 0) {
|
||||
initialSkip--;
|
||||
} else {
|
||||
locals = ivf->locals();
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_bci(JVMCIENV, frame_reference(), ivf->bci());
|
||||
methodHandle mh(THREAD, ivf->method());
|
||||
JVMCIObject method = JVMCIENV->get_jvmci_method(mh, JVMCI_CHECK_NULL);
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_method(JVMCIENV, frame_reference(), JNIHandles::resolve(method.as_jobject()));
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_localIsVirtual(JVMCIENV, frame_reference(), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (objects != NULL) {
|
||||
RegisterMap reg_map(vf->register_map());
|
||||
bool realloc_failures = Deoptimization::realloc_objects(thread, vf->frame_pointer(), ®_map, objects, CHECK_NULL);
|
||||
Deoptimization::reassign_fields(vf->frame_pointer(), ®_map, objects, realloc_failures, false);
|
||||
realloc_called = true;
|
||||
}
|
||||
|
||||
GrowableArray<ScopeValue*>* local_values = scope->locals();
|
||||
for (int i = 0; i < local_values->length(); i++) {
|
||||
ScopeValue* value = local_values->at(i);
|
||||
if (value->is_object()) {
|
||||
if (localIsVirtual_h.is_null()) {
|
||||
typeArrayOop array_oop = oopFactory::new_boolArray(local_values->length(), CHECK_NULL);
|
||||
localIsVirtual_h = typeArrayHandle(THREAD, array_oop);
|
||||
}
|
||||
localIsVirtual_h->bool_at_put(i, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals = cvf->locals();
|
||||
frame_number = cvf->vframe_id();
|
||||
} else {
|
||||
// interpreted method frame
|
||||
interpretedVFrame* ivf = interpretedVFrame::cast(vf);
|
||||
|
||||
locals = ivf->locals();
|
||||
}
|
||||
assert(bci == vf->bci(), "wrong bci");
|
||||
assert(method == vf->method(), "wrong method");
|
||||
|
||||
Handle frame_reference = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL);
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_bci(JVMCIENV, frame_reference(), bci);
|
||||
if (matched_jvmci_method.is_null()) {
|
||||
methodHandle mh(THREAD, method);
|
||||
JVMCIObject jvmci_method = JVMCIENV->get_jvmci_method(mh, JVMCI_CHECK_NULL);
|
||||
matched_jvmci_method = Handle(THREAD, JNIHandles::resolve(jvmci_method.as_jobject()));
|
||||
}
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_method(JVMCIENV, frame_reference(), matched_jvmci_method());
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_localIsVirtual(JVMCIENV, frame_reference(), localIsVirtual_h());
|
||||
|
||||
// locals != NULL means that we found a matching frame and result is already partially initialized
|
||||
if (locals != NULL) {
|
||||
methods = match_methods;
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_compilerToVM(JVMCIENV, frame_reference(), JNIHandles::resolve(compilerToVM));
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_stackPointer(JVMCIENV, frame_reference(), (jlong) fst.current()->sp());
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_stackPointer(JVMCIENV, frame_reference(), (jlong) frame_id);
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::set_frameNumber(JVMCIENV, frame_reference(), frame_number);
|
||||
|
||||
// initialize the locals array
|
||||
@ -1283,51 +1363,30 @@ C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, job
|
||||
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCallArguments args(visitor);
|
||||
if (visitor_method.is_null()) {
|
||||
visitor_method = resolve_interface_call(HotSpotJVMCI::InspectedFrameVisitor::klass(), vmSymbols::visitFrame_name(), vmSymbols::visitFrame_signature(), &args, CHECK_NULL);
|
||||
}
|
||||
|
||||
args.push_oop(frame_reference);
|
||||
call_interface(&result, HotSpotJVMCI::InspectedFrameVisitor::klass(), vmSymbols::visitFrame_name(), vmSymbols::visitFrame_signature(), &args, CHECK_NULL);
|
||||
JavaCalls::call(&result, visitor_method, &args, CHECK_NULL);
|
||||
if (result.get_oop() != NULL) {
|
||||
return JNIHandles::make_local(thread, result.get_oop());
|
||||
}
|
||||
if (methods == initial_methods) {
|
||||
methods = match_methods;
|
||||
if (resolved_methods != NULL && JNIHandles::resolve(match_methods) != JNIHandles::resolve(initial_methods)) {
|
||||
resolved_methods = NULL;
|
||||
}
|
||||
}
|
||||
assert(initialSkip == 0, "There should be no match before initialSkip == 0");
|
||||
if (HotSpotJVMCI::HotSpotStackFrameReference::objectsMaterialized(JVMCIENV, frame_reference()) == JNI_TRUE) {
|
||||
// the frame has been deoptimized, we need to re-synchronize the frame and vframe
|
||||
prev_cvf = NULL;
|
||||
intptr_t* stack_pointer = (intptr_t*) HotSpotJVMCI::HotSpotStackFrameReference::stackPointer(JVMCIENV, frame_reference());
|
||||
fst = StackFrameStream(thread, true /* update */, true /* process_frames */);
|
||||
while (fst.current()->sp() != stack_pointer && !fst.is_done()) {
|
||||
fst.next();
|
||||
}
|
||||
if (fst.current()->sp() != stack_pointer) {
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "stack frame not found after deopt")
|
||||
}
|
||||
vf = vframe::new_vframe(fst, thread);
|
||||
if (!vf->is_compiled_frame()) {
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected")
|
||||
}
|
||||
for (int i = 0; i < frame_number; i++) {
|
||||
if (vf->is_top()) {
|
||||
THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "vframe not found after deopt")
|
||||
}
|
||||
vf = vf->sender();
|
||||
assert(vf->is_compiled_frame(), "Wrong frame type");
|
||||
}
|
||||
resync_vframestream_to_compiled_frame(vfst, stack_pointer, frame_number, thread, CHECK_NULL);
|
||||
}
|
||||
frame_reference = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL);
|
||||
HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(CHECK_NULL);
|
||||
}
|
||||
|
||||
if (vf->is_top()) {
|
||||
break;
|
||||
}
|
||||
frame_number++;
|
||||
vf = vf->sender();
|
||||
} // end of vframe loop
|
||||
|
||||
if (fst.is_done()) {
|
||||
break;
|
||||
}
|
||||
fst.next();
|
||||
vf = vframe::new_vframe(fst, thread);
|
||||
frame_number = 0;
|
||||
} // end of frame loop
|
||||
|
||||
// the end was reached without finding a matching method
|
||||
@ -1426,10 +1485,10 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_
|
||||
// look for the given stack frame
|
||||
StackFrameStream fst(thread, false /* update */, true /* process_frames */);
|
||||
intptr_t* stack_pointer = (intptr_t*) JVMCIENV->get_HotSpotStackFrameReference_stackPointer(hs_frame);
|
||||
while (fst.current()->sp() != stack_pointer && !fst.is_done()) {
|
||||
while (fst.current()->id() != stack_pointer && !fst.is_done()) {
|
||||
fst.next();
|
||||
}
|
||||
if (fst.current()->sp() != stack_pointer) {
|
||||
if (fst.current()->id() != stack_pointer) {
|
||||
JVMCI_THROW_MSG(IllegalStateException, "stack frame not found");
|
||||
}
|
||||
|
||||
@ -1443,10 +1502,10 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_
|
||||
Deoptimization::deoptimize(thread, *fst.current(), Deoptimization::Reason_none);
|
||||
// look for the frame again as it has been updated by deopt (pc, deopt state...)
|
||||
StackFrameStream fstAfterDeopt(thread, true /* update */, true /* process_frames */);
|
||||
while (fstAfterDeopt.current()->sp() != stack_pointer && !fstAfterDeopt.is_done()) {
|
||||
while (fstAfterDeopt.current()->id() != stack_pointer && !fstAfterDeopt.is_done()) {
|
||||
fstAfterDeopt.next();
|
||||
}
|
||||
if (fstAfterDeopt.current()->sp() != stack_pointer) {
|
||||
if (fstAfterDeopt.current()->id() != stack_pointer) {
|
||||
JVMCI_THROW_MSG(IllegalStateException, "stack frame not found after deopt");
|
||||
}
|
||||
|
||||
|
@ -574,31 +574,36 @@ void vframeStreamCommon::skip_prefixed_method_and_wrappers() {
|
||||
javaVFrame* vframeStreamCommon::asJavaVFrame() {
|
||||
javaVFrame* result = NULL;
|
||||
if (_mode == compiled_mode) {
|
||||
guarantee(_frame.is_compiled_frame(), "expected compiled Java frame");
|
||||
assert(_frame.is_compiled_frame() || _frame.is_native_frame(), "expected compiled Java frame");
|
||||
|
||||
// lazy update to register map
|
||||
bool update_map = true;
|
||||
RegisterMap map(_thread, update_map);
|
||||
frame f = _prev_frame.sender(&map);
|
||||
|
||||
guarantee(f.is_compiled_frame(), "expected compiled Java frame");
|
||||
assert(f.is_compiled_frame() || f.is_native_frame(), "expected compiled Java frame");
|
||||
|
||||
compiledVFrame* cvf = compiledVFrame::cast(vframe::new_vframe(&f, &map, _thread));
|
||||
|
||||
guarantee(cvf->cb() == cb(), "wrong code blob");
|
||||
assert(cvf->cb() == cb(), "wrong code blob");
|
||||
|
||||
// get the same scope as this stream
|
||||
cvf = cvf->at_scope(_decode_offset, _vframe_id);
|
||||
if (cvf->scope() == NULL) {
|
||||
// native nmethods have no scope
|
||||
assert(f.is_native_frame(), "expected native frame");
|
||||
} else {
|
||||
// get the same scope as this stream
|
||||
cvf = cvf->at_scope(_decode_offset, _vframe_id);
|
||||
|
||||
guarantee(cvf->scope()->decode_offset() == _decode_offset, "wrong scope");
|
||||
guarantee(cvf->scope()->sender_decode_offset() == _sender_decode_offset, "wrong scope");
|
||||
guarantee(cvf->vframe_id() == _vframe_id, "wrong vframe");
|
||||
assert(cvf->scope()->decode_offset() == _decode_offset, "wrong scope");
|
||||
assert(cvf->scope()->sender_decode_offset() == _sender_decode_offset, "wrong scope");
|
||||
}
|
||||
assert(cvf->vframe_id() == _vframe_id, "wrong vframe");
|
||||
|
||||
result = cvf;
|
||||
} else {
|
||||
result = javaVFrame::cast(vframe::new_vframe(&_frame, &_reg_map, _thread));
|
||||
}
|
||||
guarantee(result->method() == method(), "wrong method");
|
||||
assert(result->method() == method(), "wrong method");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -310,6 +310,8 @@ class vframeStreamCommon : StackObj {
|
||||
int bci() const { return _bci; }
|
||||
inline intptr_t* frame_id() const;
|
||||
address frame_pc() const { return _frame.pc(); }
|
||||
inline int vframe_id() const;
|
||||
inline int decode_offset() const;
|
||||
|
||||
CodeBlob* cb() const { return _frame.cb(); }
|
||||
CompiledMethod* nm() const {
|
||||
|
@ -36,6 +36,16 @@ inline vframeStreamCommon::vframeStreamCommon(JavaThread* thread, bool process_f
|
||||
|
||||
inline intptr_t* vframeStreamCommon::frame_id() const { return _frame.id(); }
|
||||
|
||||
inline int vframeStreamCommon::vframe_id() const {
|
||||
assert(_mode == compiled_mode, "unexpected mode: %d", _mode);
|
||||
return _vframe_id;
|
||||
}
|
||||
|
||||
inline int vframeStreamCommon::decode_offset() const {
|
||||
assert(_mode == compiled_mode, "unexpected mode: %d", _mode);
|
||||
return _decode_offset;
|
||||
}
|
||||
|
||||
inline bool vframeStreamCommon::is_interpreted_frame() const { return _frame.is_interpreted_frame(); }
|
||||
|
||||
inline bool vframeStreamCommon::is_entry_frame() const { return _frame.is_entry_frame(); }
|
||||
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8269592
|
||||
*
|
||||
* @requires vm.jvmci & vm.compMode == "Xmixed"
|
||||
* @requires vm.opt.final.EliminateAllocations == true
|
||||
*
|
||||
* @comment no "-Xcomp -XX:-TieredCompilation" combination allowed until JDK-8140018 is resolved
|
||||
* @requires vm.opt.TieredCompilation == null | vm.opt.TieredCompilation == true
|
||||
*
|
||||
* @library / /test/lib
|
||||
* @library ../common/patches
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||
* jdk.internal.vm.ci/jdk.vm.ci.hotspot
|
||||
* jdk.internal.vm.ci/jdk.vm.ci.code
|
||||
* jdk.internal.vm.ci/jdk.vm.ci.code.stack
|
||||
* jdk.internal.vm.ci/jdk.vm.ci.meta
|
||||
*
|
||||
* @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper sun.hotspot.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run main/othervm -Xbatch -Xbootclasspath/a:.
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
|
||||
* -XX:+DoEscapeAnalysis -XX:-UseCounterDecay
|
||||
* compiler.jvmci.compilerToVM.IterateFramesNative
|
||||
*/
|
||||
|
||||
package compiler.jvmci.compilerToVM;
|
||||
|
||||
import compiler.jvmci.common.CTVMUtilities;
|
||||
import compiler.testlibrary.CompilerUtils;
|
||||
import compiler.whitebox.CompilerWhiteBoxTest;
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.vm.ci.code.stack.InspectedFrame;
|
||||
import jdk.vm.ci.hotspot.CompilerToVMHelper;
|
||||
import jdk.vm.ci.hotspot.HotSpotStackFrameReference;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jtreg.SkippedException;
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class IterateFramesNative {
|
||||
private static final WhiteBox WB;
|
||||
private static final int COMPILE_THRESHOLD;
|
||||
private static final ResolvedJavaMethod NATIVE_METHOD_RESOLVED;
|
||||
private static final ResolvedJavaMethod NATIVE_CALLBACK_METHOD_RESOLVED;
|
||||
|
||||
static {
|
||||
Method nativeMethod;
|
||||
Method nativeCallbackMethod;
|
||||
WB = WhiteBox.getWhiteBox();
|
||||
try {
|
||||
nativeMethod = IterateFramesNative.class.getDeclaredMethod("callerNative",
|
||||
Runnable.class);
|
||||
nativeCallbackMethod = IterateFramesNative.class.getDeclaredMethod("testNativeFrameCallback",
|
||||
Helper.class, int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new Error("Can't get executable for test method", e);
|
||||
}
|
||||
NATIVE_METHOD_RESOLVED = CTVMUtilities.getResolvedMethod(nativeMethod);
|
||||
NATIVE_CALLBACK_METHOD_RESOLVED = CTVMUtilities.getResolvedMethod(nativeCallbackMethod);
|
||||
COMPILE_THRESHOLD = WB.getBooleanVMFlag("TieredCompilation")
|
||||
? CompilerWhiteBoxTest.THRESHOLD
|
||||
: CompilerWhiteBoxTest.THRESHOLD * 2;
|
||||
|
||||
loadNativeLibrary();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int levels[] = CompilerUtils.getAvailableCompilationLevels();
|
||||
// we need compilation level 4 to use EscapeAnalysis
|
||||
if (levels.length < 1 || levels[levels.length - 1] != 4) {
|
||||
throw new SkippedException("Test needs compilation level 4");
|
||||
}
|
||||
|
||||
new IterateFramesNative().test();
|
||||
}
|
||||
|
||||
private void test() {
|
||||
for (int i = 0; i < CompilerWhiteBoxTest.THRESHOLD + 1; i++) {
|
||||
testNativeFrame("someString", i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads native library(libIterateFramesNative.so)
|
||||
*/
|
||||
protected static void loadNativeLibrary() {
|
||||
System.loadLibrary("IterateFramesNative");
|
||||
}
|
||||
|
||||
private void testNativeFrame(String str, int iteration) {
|
||||
Helper innerHelper = new Helper("foo");
|
||||
callerNative(() -> testNativeFrameCallback(innerHelper, iteration));
|
||||
|
||||
Asserts.assertEQ(innerHelper.string, NATIVE_METHOD_RESOLVED.getName(),
|
||||
"Native frame not found?: " + NATIVE_METHOD_RESOLVED.getName());
|
||||
}
|
||||
|
||||
public static native void callerNative(Runnable runnable);
|
||||
|
||||
private void testNativeFrameCallback(Helper helper, int iteration) {
|
||||
AtomicInteger frameCounter = new AtomicInteger();
|
||||
ResolvedJavaMethod[] methods = new ResolvedJavaMethod[] {NATIVE_METHOD_RESOLVED, NATIVE_CALLBACK_METHOD_RESOLVED};
|
||||
CompilerToVMHelper.iterateFrames(
|
||||
methods,
|
||||
methods,
|
||||
0,
|
||||
f -> {
|
||||
HotSpotStackFrameReference frame = (HotSpotStackFrameReference) f;
|
||||
Asserts.assertNotNull(frame, "got null frame for native method");
|
||||
int index = frameCounter.getAndIncrement();
|
||||
if (index == 0) {
|
||||
Asserts.assertTrue(frame.isMethod(NATIVE_CALLBACK_METHOD_RESOLVED),
|
||||
"unexpected method: " + frame.getMethod().getName());
|
||||
} else if (index == 1) {
|
||||
Asserts.assertTrue(frame.isMethod(NATIVE_METHOD_RESOLVED),
|
||||
"unexpected method: " + frame.getMethod().getName());
|
||||
helper.string = frame.getMethod().getName();
|
||||
Asserts.assertFalse(frame.hasVirtualObjects(),
|
||||
"native frames do not have virtual objects");
|
||||
return frame; // stop
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private class Helper {
|
||||
public String string;
|
||||
|
||||
public Helper(String s) {
|
||||
this.string = s;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define CHECK_EXCEPTIONS if ((*env)->ExceptionCheck(env)) return
|
||||
|
||||
JNIEXPORT void JNICALL Java_compiler_jvmci_compilerToVM_IterateFramesNative_callerNative(JNIEnv *env, jobject obj, jobject runnable) {
|
||||
jclass cls = (*env)->GetObjectClass(env, runnable);
|
||||
jmethodID runMethodID = (*env)->GetMethodID(env, cls, "run", "()V");
|
||||
CHECK_EXCEPTIONS;
|
||||
(*env)->CallVoidMethod(env, runnable, runMethodID);
|
||||
CHECK_EXCEPTIONS;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user