Getting ciObject from oop/jobject

Krystal Mok rednaxelafx at gmail.com
Fri Aug 2 05:11:17 PDT 2013


On Fri, Aug 2, 2013 at 8:04 PM, Nick Williams <
nicholas+openjdk at nicholaswilliams.net> wrote:

> *whoosh* :-( most of that went over my head...
>
> I did implement it first. Code is implemented in JVM_GetCallerClass (which
> just required minor tweaks) and JVM_GetCallerFrame (which is all-new). So I
> have a working program. I suppose I could submit a patch without
> inlining JVM_GetCallerFrame, but performance is pretty different. 0-1 ms
> for 1,000,000 calls of JVM_GetCallerClass, ~1300ms for 1,000,000 calls
> of JVM_GetCallerFrame. Now, I understand that hotspot can't always inline
> something, and so 0-1 ms for 1,000,000 calls is an unrealistic expectation
> for everything (with inlining disabled, JVM_GetCallerClass is more like
> ~200ms for 1,000,000 calls). But there's still a difference to be made.
>
> At least you've got something running already. Good for you :-)


> You said that among the 12 basic types that hotspot expects is object.
> This is why the existing code below can bind the Class as the result,
> right? Well StackTraceFrame is an object. It's an oop at first, but we
> already know there's a way to convert it (ciObject*
> ciObjectFactory::get(oop)). Surely there must be a way to do the same with
> it that we're doing with the Class, since metadata won't work?
>

The existing code doesn't make a runtime call when
Reflection.getCallerClass() is inlined. The place where I had trouble with
is that I was trying to pass a Method* as an argument to a runtime call,
but only the 12 basic types mentioned could be used for arguments or return
value. So I can't pass that Method* to my runtime code, and I was stuck.
There might be another way around, gotta think a little bit more. I still
believe there's a way to pass something to runtime code that would fetch
your StackTraceFrame back out...

- Kris


>
> N
>
> On Aug 2, 2013, at 1:21 AM, Krystal Mok wrote:
>
> Oops, I tried to put together a demo, but it seems like my earlier
> suggestion doesn't work.
>
> Here's the demo (that doesn't work):
> https://gist.github.com/rednaxelafx/6137819
>
> The patch is against tip version of hsx/hotspot-comp/hotspot.
> Applying this patch gives you a VM that builds, but when it tries to
> compile and inline our special intrinsic method, it crashes
> in SharedRuntime::java_calling_convention().
>
> The reason is that HotSpot's Java calling convention only expects the 12
> basic types: boolean / byte / char / short / int / float / long / double /
> address / object / array / void.
> But "metadata" is not one of them. Before the PermGen removal project, it
> used to be that metadata were "oops" too, so this kind of code would have
> worked. Now "metadata" is distinct from "object", so...I'm not sure how to
> proceed with this right now.
>
> Sorry about it. Let's see if someone else would come up with a viable
> solution.
>
> (Actually, you don't have to generate inline code to make an intrinsic
> work. Just as there's a fallback in the VM for Reflection.getCallerClass(),
> which is JVM_GetCallerClass(). You could just implement your feature
> without making it an inline intrinsic first. That way you can at least get
> a running program and move on.)
>
> - Kris
>
>
> On Fri, Aug 2, 2013 at 10:19 AM, Krystal Mok <rednaxelafx at gmail.com>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/20130802/ae776f6e/attachment.html 


More information about the hotspot-compiler-dev mailing list