Getting ciObject from oop/jobject
Nick Williams
nicholas+openjdk at nicholaswilliams.net
Thu Aug 1 19:25:17 PDT 2013
I do not have a full patch yet. A demo should be fine, but I'll include some relative code below in case it helps:
In javaClasses.cpp (all new):
oop java_lang_StackTraceFrame::create(Method* method, int version, int bci, TRAPS) {
// Allocate java.lang.StackTraceFrame instance
Klass* k = SystemDictionary::StackTraceFrame_klass();
assert(k != NULL, "must be loaded in 1.8+");
instanceKlassHandle ik (THREAD, k);
if (ik->should_be_initialized()) {
ik->initialize(CHECK_0);
}
Handle stFrame = ik->allocate_instance_handle(CHECK_0);
// Fill in declaringClass
ResourceMark rm(THREAD);
InstanceKlass* holder = InstanceKlass::cast(method->method_holder());
java_lang_StackTraceFrame::set_declaringClass(stFrame(), method->method_holder()->java_mirror());
// Fill in methodName
oop methodname = StringTable::intern(method->name(), CHECK_0);
java_lang_StackTraceFrame::set_methodName(stFrame(), methodname);
if (!version_matches(method, version)) {
// The method was redefined, accurate source information isn't available
java_lang_StackTraceFrame::set_fileName(stFrame(), NULL);
java_lang_StackTraceFrame::set_lineNumber(stFrame(), -1);
} else {
// Fill in source fileName and lineNumber.
Symbol* source = holder->source_file_name();
if (ShowHiddenFrames && source == NULL)
source = vmSymbols::unknown_class_name();
oop filename = StringTable::intern(source, CHECK_0);
java_lang_StackTraceFrame::set_fileName(stFrame(), filename);
int line_number = get_line_number(method, bci);
java_lang_StackTraceFrame::set_lineNumber(stFrame(), line_number);
}
return stFrame();
}
oop java_lang_StackTraceFrame::create(vframeStream* vfst, TRAPS) {
return create(vfst->method(), vfst->method()->constants()->version(), vfst->bci(), THREAD);
}
In library_call.cpp:
bool LibraryCallKit::inline_native_ReflectionOrStackTraceFrame_getCallerClassOrFrame(bool getFrame) {
#ifndef PRODUCT
if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) {
if (getFrame) {
tty->print_cr("Attempting to inline java.lang.StackTraceFrame#getCallerFrame()");
} else {
tty->print_cr("Attempting to inline getCallerClass() in sun.reflect.Reflection or java.lang.StackTraceFrame");
}
}
#endif
if (!jvms()->has_method()) {
#ifndef PRODUCT
if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) {
tty->print_cr(" Bailing out because intrinsic was inlined at top level");
}
#endif
return false;
}
// Walk back up the JVM state to find the caller at the required
// depth.
JVMState* caller_jvms = jvms();
// Cf. JVM_GetCallerClass
// NOTE: Start the loop at depth 1 because the current JVM state does
// not include the Reflection/StackTraceFrame.getCallerClass() frame.
for (int n = 1; caller_jvms != NULL; caller_jvms = caller_jvms->caller(), n++) {
ciMethod* m = caller_jvms->method();
switch (n) {
case 0:
fatal("current JVM state does not include the Reflection/StackTraceFrame.getCallerClass frame");
break;
case 1:
// Frame 0 and 1 must be caller sensitive (see JVM_GetCallerClass).
if (!m->caller_sensitive()) {
#ifndef PRODUCT
if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) {
tty->print_cr(" Bailing out: CallerSensitive annotation expected at frame %d", n);
}
#endif
return false; // bail-out; let JVM_GetCallerClass do the work
}
break;
default:
if (!m->is_ignored_by_security_stack_walk()) {
// We have reached the desired frame; return the caller.
if (getFrame) {
fatal("Got into getFrame anyway, which is weird, yo");
return false; // TODO fix this
// Acquire java.lang.StackTraceFrame and push as constant
//Method* method = (Method*)m->constant_encoding();
//oop stFrame = java_lang_StackTraceFrame::create(method, method->constants()->version(), caller_jvms->bci(), NULL);
// TODO fix this ciObject* stfObject = ciEnv::current()->get_object(stFrame);
// TODO fix this set_result(makecon(TypeInstPtr::make(stfObject)));
} else {
// Acquire method holder as java.lang.Class and push as constant.
ciInstanceKlass* caller_klass = m->holder();
ciInstance* caller_mirror = caller_klass->java_mirror();
set_result(makecon(TypeInstPtr::make(caller_mirror)));
}
#ifndef PRODUCT
if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) {
tty->print_cr(" Succeeded: caller = %d) %s.%s, JVMS depth = %d", n, caller_klass->name()->as_utf8(), caller_jvms->method()->name()->as_utf8(), jvms()->depth());
tty->print_cr(" JVM state at this point:");
for (int i = jvms()->depth(), n = 1; i >= 1; i--, n++) {
ciMethod* m = jvms()->of_depth(i)->method();
tty->print_cr(" %d) %s.%s", n, m->holder()->name()->as_utf8(), m->name()->as_utf8());
}
}
#endif
return true;
}
break;
}
}
#ifndef PRODUCT
if ((PrintIntrinsics || PrintInlining || PrintOptoInlining) && Verbose) {
tty->print_cr(" Bailing out because caller depth exceeded inlining depth = %d", jvms()->depth());
tty->print_cr(" JVM state at this point:");
for (int i = jvms()->depth(), n = 1; i >= 1; i--, n++) {
ciMethod* m = jvms()->of_depth(i)->method();
tty->print_cr(" %d) %s.%s", n, m->holder()->name()->as_utf8(), m->name()->as_utf8());
}
}
#endif
return false; // bail-out; let JVM_GetCallerClass do the work
}
On Aug 1, 2013, at 9:19 PM, Krystal Mok wrote:
> On Fri, Aug 2, 2013 at 10:15 AM, Nick Williams <nicholas+openjdk at nicholaswilliams.net> wrote:
>
> On Aug 1, 2013, at 9:07 PM, Krystal Mok wrote:
>
>> Hi Nick,
>>
>> All right, that explains everything. My take on this:
>>
>> In HotSpot VM, the compiler threads shouldn't manipulate the Java object graph; in other words, although the compilers have access to certain Java objects through the Compiler Interface, it should only be "reading", but not "writing" or creating new Java objects.
>>
>> In your case, calling java_lang_StackTraceFrame::create() from compiler code creates a new object, and that's probably not the right way.
>> You're trying to embed a pointer to a StackTraceFrame object in the generated code, as a constant. You don't have to do that. It might work if you embed the Method* (as a TypeMetadataPtr), and generate a runtime call to java_lang_StackTraceFrame::create() with that pointer, instead of calling it at compile time.
>
> Sounds good, but I'm not exactly sure how to do it. Do you mind assisting a bit? Remember that "ciMethod* m" is the executing method on the stack frame we're interested in. "Method* method" is the same thing, just in a different form. It sounds like I need to actually embed a runtime call to java_lang_StackTraceFrame::create()? I may be missing something. :-)
>
> Sure. I can give it a shot and see if it works.
> Do you have a full patch that I can use as a base, or would you just like to see a demo of doing a runtime call passing an embedded pointer constant?
>
> - Kris
>
> Nick
>
>>
>> HTH,
>> Kris
>>
>>
>> On Fri, Aug 2, 2013 at 9:28 AM, Nick Williams <nicholas+openjdk at nicholaswilliams.net> wrote:
>> Well let me explain what I'm trying to do, and maybe someone can point me in the right direction.
>>
>> On the core-libs-dev mailing list, I proposed a public API replacement for the sun.reflect.Reflection#getCallerClass(int) of old and the sun.reflect.Reflection#getCallerClass() of now. The new class, java.lang.StackTraceFrame, has the following four methods that are relevant to this discussion:
>>
>> @CallerSensitive
>> public native Class<?> getCallerClass();
>> public native Class<?> getCallerClass(int);
>> @CallerSensitive
>> public native StackTraceFrame getCallerFrame();
>> public native StackTraceFrame getCallerFrame(int);
>>
>> There is code in library_call.cpp that inlines Reflection.getCallerClass(), and I took advantage of that code to also inline StackTraceFrame.getCallerClass(). I also recreated (with changes necessary due to new way of doing things in library_call.cpp) the inline code for Reflection.getCallerClass(int) from the jdk7 source code. All of that works perfectly. Code is inlined as expected, and all is well.
>>
>> Now I want to inline getCallerFrame() and getCallerFrame(int) as well. If the Class<?> versions can be inlined, I see no reason that the StackTraceFrame versions can't be inlined, but that may be my first wrong assumption. If these methods aren't eligible for inlining for some reason, please let me know and I can move on.
>>
>> So the code that gets the Class<?> and sets it as an inline constant replacing the method call works like this (where m is a ciMethod*):
>>
>> // Acquire method holder as java.lang.Class and push as constant.
>> ciInstanceKlass* caller_klass = m->holder();
>> ciInstance* caller_mirror = caller_klass->java_mirror();
>> set_result(makecon(TypeInstPtr::make(caller_mirror)));
>>
>> In javaClasses.cpp, I already have a method that can create a StackTraceFrame from a Method* (not ciMethod*), method version (int), and bci (int):
>>
>> oop java_lang_StackTraceFrame::create(Method* method, int version, int bci, TRAPS);
>>
>> I tried calling that to create the StackTraceFrame, but it appears I can't actually set it to the result. First I tried this:
>>
>> // Acquire java.lang.StackTraceFrame and push as constant
>> Method* method = (Method*)m->constant_encoding();
>> oop stFrame = java_lang_StackTraceFrame::create(method, method->constants()->version(), caller_jvms->bci(), NULL);
>> set_result(makecon(TypeInstPtr::make(oop)));
>>
>> But this obviously didn't work because there is no TypeInstPtr::make() method that takes an oopDesc&. So I looked around trying to figure out how to convert an oop (or jobject, which I can get from an oop) to a ciObject. I discovered that ciObject actually holds a jobject internally, so I figured surely this is possible. I found a few methods that appear to do it. ciObjectFactory has a ciObject* get(oop) method, but I can't figure out how to get the ciObjectFactory. ciEnv has a ciObject* get_object(oop) method which I tried to use, only to discover that it was private:
>>
>> // Acquire java.lang.StackTraceFrame and push as constant
>> Method* method = (Method*)m->constant_encoding();
>> oop stFrame = java_lang_StackTraceFrame::create(method, method->constants()->version(), caller_jvms->bci(), NULL);
>> ciObject* stfObject = ciEnv::current()->get_object(stFrame);
>> set_result(makecon(TypeInstPtr::make(stfObject)));
>>
>> So that obviously doesn't work either. I'll admit, I'm a little out of my league here. I was pretty confident working in javaClasses.hpp/cpp and jvm.h/cpp, but this inlining/compiler stuff is pretty over my head. Hopefully one of the knowledgeable people on this list can help me out with this. I want my code to perform as well as possible and also be stable--more likely to get accepted that way. :-)
>>
>> Thanks,
>>
>> Nick
>>
>> On Aug 1, 2013, at 8:16 AM, Krystal Mok wrote:
>>
>>> Hi Nick,
>>>
>>> This topic is related to HotSpot Server Compiler instead of the Java core library, so I'm cc'ing this email to hotspot-compiler-dev and dropping core-libs-dev.
>>>
>>> As you already know, HotSpot compilers are shielded from VM runtime implementation details via the Compiler Interface (CI). That's why you shouldn't be getting raw oops in C2 code.
>>>
>>> Where are you getting the oopInstance from? If it can be found from some known "roots", e.g. "well-known classes", fields of "well-known classes", or the holder class of the method to be compiled, etc., then it's already available through CI.
>>>
>>> - Kris
>>>
>>>
>>> On Thu, Aug 1, 2013 at 3:17 AM, Nick Williams <nicholas+openjdk at nicholaswilliams.net> wrote:
>>> In native code (library_call.cpp), if I have an oop (which I can convert to a jobject if need be), how do I get a ciObject? I see that ciEnv has a ciObject* get_object(oop) method, but it's private. And ciObjectFactory has a ciObject* get(oop) method, but I can't figure out how to get the ciObjectFactory instance.
>>>
>>> I know that ciObject keeps a jobject internally, and I know that ciObject has a ciObject(oop) constructor, but it's protected (for good reason).
>>>
>>> If it helps, I'm trying to inline a method and need to set_result(makecon(TypeInstPtr::make(oopInstance))). I may be going down the wrong path.
>>>
>>> Thanks in advance for any help,
>>>
>>> Nick
>>>
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20130801/3d1adb3a/attachment-0001.html
More information about the hotspot-compiler-dev
mailing list