RFR 8152271: MemberNameTable doesn't purge stale entries

Vladimir Ivanov vladimir.x.ivanov at oracle.com
Wed Jun 15 12:22:31 UTC 2016



On 6/15/16 3:03 PM, Coleen Phillimore wrote:
>
>
> On 6/15/16 7:06 AM, Vladimir Ivanov wrote:
>> Coleen,
>>
>> Latest version looks good. Thanks for adding clarifying comment in the
>> code.
>>
>>>>> Summary: Intern MemberNames in table instead of allocating new entries
>>>>>
>>>>> For degenerate case, we were leaking native code in the member name
>>>>> table.  Going with the suggested workaround, it was only a few more
>>>>> lines of code to intern MemberName and return the MemberName that was
>>>>> already in the table.
>>>>
>>>> I guess I'm very surprised that these were not already being "cached"
>>>> at some level (ie the Java level where all other reflection-like
>>>> objects get cached)! I'm not familiar with the mechanics or j.l.invoke
>>>> so was wondering where MemberName instances actually get created -
>>>> because I'd like to understand how you get two distinct MemberName
>>>> instances that compare equal in the first place?
>>>
>>> Hi David,
>>>
>>> The MemberNames were not being cached. There was a change to attempt to
>>> cache them in the jdk https://bugs.openjdk.java.net/browse/JDK-8013267
>>> but it was a much bigger change and we still need access to MemberName
>>> in the jvm because we have to replace the Method* in them with
>>> redefinition.
>>>
>>> MemberNames get created mostly when you create a MethodHandle. The
>>> MemberName is the jvm representation of the member of the class. It's
>>> not simply a Method* because it contains flags based on how it's
>>> resolved at linktime.
>>>
>>> In the test case provided,
>>>       MethodHandle mh = lookup.findSpecial(Leak.class, "callMe", mt,
>>> Leak.class);
>>>
>>> this looks up the same method and creates the same MemberName over and
>>> over.
>>
>> j.l.i.MemberName implements Cloneable and MN cloning is pervasively
>> used during DirectMethodHandle construction (see MN.resolve() and
>> other MN instance methods).
>
> So there'd still be a leak but just not a simple one.   Are there plans
> to not use cloning?  That should be a separate issue, though. The VM
> would now reuse MemberName with this change.

No, I'm not aware of any plans to get rid of MN cloning.

The following code takes care of cloned MN instance:

--- old/src/share/vm/prims/jvm.cpp	2016-06-09 17:19:13.896240434 -0400
+++ new/src/share/vm/prims/jvm.cpp	2016-06-09 17:19:13.454960882 -0400
@@ -695,7 +695,7 @@
        // This can safepoint and redefine method, so need both new_obj 
and method
        // in a handle, for two different reasons.  new_obj can move, 
method can be
        // deleted if nothing is using it on the stack.
-      m->method_holder()->add_member_name(new_obj());
+      m->method_holder()->add_member_name(new_obj(), false);
      }
    }

The cloned instance is usually adjusted (changes in MN.flags) right 
away, so it becomes non-equal to the original one. It allows to bypass 
repeated resolution.

When you talk about a leak, do you mean the situation when there's 
already a duplicate of adjusted MN registered ?

If it causes a leak, we can do a call into the JVM to intern adjusted MN 
instance, e.g:

jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java:

     private MemberName changeReferenceKind(byte refKind, byte oldKind) {
         assert(getReferenceKind() == oldKind);
         assert(MethodHandleNatives.refKindIsValid(refKind));
         flags += (((int)refKind - oldKind) << MN_REFERENCE_KIND_SHIFT);
	return MethodHandleNatives.intern(this); // returns interned MN instance
     }

Best regards,
Vladimir Ivanov

>
> Thanks,
> Coleen
>
>>
>> Best regards,
>> Vladimir Ivanov
>>
>>>>
>>>> Otherwise changes seem fine - though perhaps
>>>> MemberNameTable::add_member_name should assert the member_name is not
>>>> already present, just to confirm those intern==false cases are working
>>>> as intended.
>>>
>>> I want to keep add_member_name simple and not go through the list even
>>> under ASSERT.  It's okay if some member_name are already present, and
>>> for the case with JVM_Clone, we want an additional MemberName in the
>>> table (and that uses add_member_name()).
>>>
>>> Thanks for looking at the code.
>>> Coleen
>>>
>>>>
>>>> Thanks,
>>>> David
>>>> -----
>>>>
>>>>> This has been performance tested to show no regression and works
>>>>> really
>>>>> well for the degenerate test case, even though the real percentage of
>>>>> reused MemberName seems quite small.
>>>>>
>>>>> Tested with all runtime nightly tests, tests in
>>>>> jdk/test/java/lang/invoke.
>>>>>
>>>>> open webrev at http://cr.openjdk.java.net/~coleenp/8152271.01/webrev
>>>>> bug link https://bugs.openjdk.java.net/browse/JDK-8152271
>>>>>
>>>>> Thanks,
>>>>> Coleen
>>>
>


More information about the hotspot-dev mailing list