Getting ciObject from oop/jobject

Nick Williams nicholas+openjdk at nicholaswilliams.net
Fri Aug 2 05:04:01 PDT 2013


*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.

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?

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/31bf582e/attachment-0001.html 


More information about the hotspot-compiler-dev mailing list