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/stackFrameStream.inline.hpp"
|
||||||
#include "runtime/timerTrace.hpp"
|
#include "runtime/timerTrace.hpp"
|
||||||
#include "runtime/vframe_hp.hpp"
|
#include "runtime/vframe_hp.hpp"
|
||||||
|
#include "runtime/vframe.inline.hpp"
|
||||||
|
|
||||||
JVMCIKlassHandle::JVMCIKlassHandle(Thread* thread, Klass* klass) {
|
JVMCIKlassHandle::JVMCIKlassHandle(Thread* thread, Klass* klass) {
|
||||||
_thread = thread;
|
_thread = thread;
|
||||||
@ -1147,30 +1148,99 @@ C2V_VMENTRY_NULL(jobject, getSymbol, (JNIEnv* env, jobject, jlong symbol))
|
|||||||
return JVMCIENV->get_jobject(sym);
|
return JVMCIENV->get_jobject(sym);
|
||||||
C2V_END
|
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);
|
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++) {
|
for (int i = 0; i < methods_oop->length(); i++) {
|
||||||
oop resolved = methods_oop->obj_at(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 true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
CallInfo callinfo;
|
||||||
Handle receiver = args->receiver();
|
Handle receiver = args->receiver();
|
||||||
Klass* recvrKlass = receiver.is_null() ? (Klass*)NULL : receiver->klass();
|
Klass* recvrKlass = receiver.is_null() ? (Klass*)NULL : receiver->klass();
|
||||||
LinkInfo link_info(spec_klass, name, signature);
|
LinkInfo link_info(spec_klass, name, signature);
|
||||||
LinkResolver::resolve_interface_call(
|
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());
|
methodHandle method(THREAD, callinfo.selected_method());
|
||||||
assert(method.not_null(), "should have thrown exception");
|
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))
|
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);
|
requireInHotSpot("iterateFrames", JVMCI_CHECK_NULL);
|
||||||
|
|
||||||
HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(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;
|
jobjectArray methods = initial_methods;
|
||||||
|
methodHandle visitor_method;
|
||||||
|
GrowableArray<Method*>* resolved_methods = NULL;
|
||||||
|
|
||||||
int frame_number = 0;
|
while (!vfst.at_end()) { // frame loop
|
||||||
vframe* vf = vframe::new_vframe(fst, thread);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// look for the given method
|
|
||||||
bool realloc_called = false;
|
bool realloc_called = false;
|
||||||
while (true) {
|
intptr_t* frame_id = vfst.frame_id();
|
||||||
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;
|
|
||||||
|
|
||||||
GrowableArray<ScopeValue*>* local_values = scope->locals();
|
// Previous compiledVFrame of this frame; use with at_scope() to reuse scope object pool.
|
||||||
assert(local_values != NULL, "NULL locals");
|
compiledVFrame* prev_cvf = NULL;
|
||||||
typeArrayOop array_oop = oopFactory::new_boolArray(local_values->length(), CHECK_NULL);
|
|
||||||
typeArrayHandle array(THREAD, array_oop);
|
for (; !vfst.at_end() && vfst.frame_id() == frame_id; vfst.next()) { // vframe loop
|
||||||
for (int i = 0; i < local_values->length(); i++) {
|
int frame_number = 0;
|
||||||
ScopeValue* value = local_values->at(i);
|
Method *method = vfst.method();
|
||||||
if (value->is_object()) {
|
int bci = vfst.bci();
|
||||||
array->bool_at_put(i, true);
|
|
||||||
}
|
Handle matched_jvmci_method;
|
||||||
}
|
if (methods == NULL || matches(methods, method, &resolved_methods, &matched_jvmci_method, THREAD, JVMCIENV)) {
|
||||||
HotSpotJVMCI::HotSpotStackFrameReference::set_localIsVirtual(JVMCIENV, frame_reference(), array());
|
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 {
|
} 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();
|
if (objects != NULL) {
|
||||||
HotSpotJVMCI::HotSpotStackFrameReference::set_bci(JVMCIENV, frame_reference(), cvf->bci());
|
RegisterMap reg_map(vf->register_map());
|
||||||
methodHandle mh(THREAD, cvf->method());
|
bool realloc_failures = Deoptimization::realloc_objects(thread, vf->frame_pointer(), ®_map, objects, CHECK_NULL);
|
||||||
JVMCIObject method = JVMCIENV->get_jvmci_method(mh, JVMCI_CHECK_NULL);
|
Deoptimization::reassign_fields(vf->frame_pointer(), ®_map, objects, realloc_failures, false);
|
||||||
HotSpotJVMCI::HotSpotStackFrameReference::set_method(JVMCIENV, frame_reference(), JNIHandles::resolve(method.as_jobject()));
|
realloc_called = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (vf->is_interpreted_frame()) {
|
GrowableArray<ScopeValue*>* local_values = scope->locals();
|
||||||
// interpreted method frame
|
for (int i = 0; i < local_values->length(); i++) {
|
||||||
interpretedVFrame* ivf = interpretedVFrame::cast(vf);
|
ScopeValue* value = local_values->at(i);
|
||||||
if (methods == NULL || matches(methods, ivf->method(), JVMCIENV)) {
|
if (value->is_object()) {
|
||||||
if (initialSkip > 0) {
|
if (localIsVirtual_h.is_null()) {
|
||||||
initialSkip--;
|
typeArrayOop array_oop = oopFactory::new_boolArray(local_values->length(), CHECK_NULL);
|
||||||
} else {
|
localIsVirtual_h = typeArrayHandle(THREAD, array_oop);
|
||||||
locals = ivf->locals();
|
}
|
||||||
HotSpotJVMCI::HotSpotStackFrameReference::set_bci(JVMCIENV, frame_reference(), ivf->bci());
|
localIsVirtual_h->bool_at_put(i, true);
|
||||||
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);
|
|
||||||
}
|
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_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);
|
HotSpotJVMCI::HotSpotStackFrameReference::set_frameNumber(JVMCIENV, frame_reference(), frame_number);
|
||||||
|
|
||||||
// initialize the locals array
|
// initialize the locals array
|
||||||
@ -1283,51 +1363,30 @@ C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, job
|
|||||||
|
|
||||||
JavaValue result(T_OBJECT);
|
JavaValue result(T_OBJECT);
|
||||||
JavaCallArguments args(visitor);
|
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);
|
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) {
|
if (result.get_oop() != NULL) {
|
||||||
return JNIHandles::make_local(thread, result.get_oop());
|
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");
|
assert(initialSkip == 0, "There should be no match before initialSkip == 0");
|
||||||
if (HotSpotJVMCI::HotSpotStackFrameReference::objectsMaterialized(JVMCIENV, frame_reference()) == JNI_TRUE) {
|
if (HotSpotJVMCI::HotSpotStackFrameReference::objectsMaterialized(JVMCIENV, frame_reference()) == JNI_TRUE) {
|
||||||
// the frame has been deoptimized, we need to re-synchronize the frame and vframe
|
// 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());
|
intptr_t* stack_pointer = (intptr_t*) HotSpotJVMCI::HotSpotStackFrameReference::stackPointer(JVMCIENV, frame_reference());
|
||||||
fst = StackFrameStream(thread, true /* update */, true /* process_frames */);
|
resync_vframestream_to_compiled_frame(vfst, stack_pointer, frame_number, thread, CHECK_NULL);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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
|
} // end of vframe loop
|
||||||
|
|
||||||
if (fst.is_done()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fst.next();
|
|
||||||
vf = vframe::new_vframe(fst, thread);
|
|
||||||
frame_number = 0;
|
|
||||||
} // end of frame loop
|
} // end of frame loop
|
||||||
|
|
||||||
// the end was reached without finding a matching method
|
// 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
|
// look for the given stack frame
|
||||||
StackFrameStream fst(thread, false /* update */, true /* process_frames */);
|
StackFrameStream fst(thread, false /* update */, true /* process_frames */);
|
||||||
intptr_t* stack_pointer = (intptr_t*) JVMCIENV->get_HotSpotStackFrameReference_stackPointer(hs_frame);
|
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();
|
fst.next();
|
||||||
}
|
}
|
||||||
if (fst.current()->sp() != stack_pointer) {
|
if (fst.current()->id() != stack_pointer) {
|
||||||
JVMCI_THROW_MSG(IllegalStateException, "stack frame not found");
|
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);
|
Deoptimization::deoptimize(thread, *fst.current(), Deoptimization::Reason_none);
|
||||||
// look for the frame again as it has been updated by deopt (pc, deopt state...)
|
// look for the frame again as it has been updated by deopt (pc, deopt state...)
|
||||||
StackFrameStream fstAfterDeopt(thread, true /* update */, true /* process_frames */);
|
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();
|
fstAfterDeopt.next();
|
||||||
}
|
}
|
||||||
if (fstAfterDeopt.current()->sp() != stack_pointer) {
|
if (fstAfterDeopt.current()->id() != stack_pointer) {
|
||||||
JVMCI_THROW_MSG(IllegalStateException, "stack frame not found after deopt");
|
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* vframeStreamCommon::asJavaVFrame() {
|
||||||
javaVFrame* result = NULL;
|
javaVFrame* result = NULL;
|
||||||
if (_mode == compiled_mode) {
|
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
|
// lazy update to register map
|
||||||
bool update_map = true;
|
bool update_map = true;
|
||||||
RegisterMap map(_thread, update_map);
|
RegisterMap map(_thread, update_map);
|
||||||
frame f = _prev_frame.sender(&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));
|
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
|
if (cvf->scope() == NULL) {
|
||||||
cvf = cvf->at_scope(_decode_offset, _vframe_id);
|
// 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");
|
assert(cvf->scope()->decode_offset() == _decode_offset, "wrong scope");
|
||||||
guarantee(cvf->scope()->sender_decode_offset() == _sender_decode_offset, "wrong scope");
|
assert(cvf->scope()->sender_decode_offset() == _sender_decode_offset, "wrong scope");
|
||||||
guarantee(cvf->vframe_id() == _vframe_id, "wrong vframe");
|
}
|
||||||
|
assert(cvf->vframe_id() == _vframe_id, "wrong vframe");
|
||||||
|
|
||||||
result = cvf;
|
result = cvf;
|
||||||
} else {
|
} else {
|
||||||
result = javaVFrame::cast(vframe::new_vframe(&_frame, &_reg_map, _thread));
|
result = javaVFrame::cast(vframe::new_vframe(&_frame, &_reg_map, _thread));
|
||||||
}
|
}
|
||||||
guarantee(result->method() == method(), "wrong method");
|
assert(result->method() == method(), "wrong method");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +310,8 @@ class vframeStreamCommon : StackObj {
|
|||||||
int bci() const { return _bci; }
|
int bci() const { return _bci; }
|
||||||
inline intptr_t* frame_id() const;
|
inline intptr_t* frame_id() const;
|
||||||
address frame_pc() const { return _frame.pc(); }
|
address frame_pc() const { return _frame.pc(); }
|
||||||
|
inline int vframe_id() const;
|
||||||
|
inline int decode_offset() const;
|
||||||
|
|
||||||
CodeBlob* cb() const { return _frame.cb(); }
|
CodeBlob* cb() const { return _frame.cb(); }
|
||||||
CompiledMethod* nm() const {
|
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 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_interpreted_frame() const { return _frame.is_interpreted_frame(); }
|
||||||
|
|
||||||
inline bool vframeStreamCommon::is_entry_frame() const { return _frame.is_entry_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