Request for review: JDK-8004728 Hotspot support for parameter reflection
Eric McCorkle
eric.mccorkle at oracle.com
Tue Jan 8 11:00:52 PST 2013
Thanks to all for their reviews. There is an updated version here:
http://oklahoma.us.oracle.com/~cphillim/webrev/JDK-8004728/
On 01/07/13 14:42, Coleen Phillimore wrote:
>
>
> John, Thank you for your thorough review of this. I have a couple of
> comments below.
>
> On 01/05/2013 06:41 PM, John Rose wrote:
>> On Jan 4, 2013, at 6:14 PM, Eric McCorkle wrote:
>>
>>> Please review the following change set, which implements support for
>>> method parameter reflection in hotspot. The open webrev can be found
>>> here:
>>>
>>> http://cr.openjdk.java.net/~acorn/8004728/webrev
>> Here are some more comments.
>>
>> The method java_lang_reflect_Parameter::index uses modifiers_offset,
>> which isn't correct. I don't see any other errors like that. It
>> would be best to test such things with asserts or even unit tests,
>> although code this simple can usually be verified by inspection.
>>
>> I notice that the Parameter class is marked "Opt", which is good. In
>> order to avoid surprise JVM crashes during testing, it should be the
>> case that the changed JVM will work correctly with old versions of the
>> JDK which lack Parameter.class, even with arbitrary inputs. I think
>> Murphy's Law will bite if the JVM happens to load any class file that
>> contains the new attribute. I suggest providing for this more
>> explicitly:
>>
>> + } else if (method_attribute_name ==
>> vmSymbols::tag_method_parameters()) {
>> + method_parameters_length = cfs->get_u1_fast();
>> + method_parameters_data = cfs->get_u1_buffer();
>> + cfs->skip_u2_fast(method_parameters_length);
>> + cfs->skip_u4_fast(method_parameters_length;
>> ++ if (!SystemDictionary::Parameter_klass_loaded())
>> ++ method_parameters_length = 0; // ignore this attribute if it
>> cannot be reflected
>>
>> I think that's the only point necessary for such a check. (This path
>> could be tested by manually removing Parameter.class from an rt.jar
>> and running unit tests, or by injecting a typo into the name of the
>> class in vmsymbols.hpp.) In general, version numbers, etc., will keep
>> such bugs away, but it is better to be safe than sorry.
>>
>> In jvm.cpp and reflection.cpp there is some ambivalence about the
>> method pointer argument for a Parameter factory method. Since the
>> term "executable" is foreign to the JVM, and we just use the term
>> "method" everywhere, I suggest using the word "executable" (confusing
>> in the context of the JVM, and non-existent in reflection.cpp) only
>> for the field in the Parameter itself (in javaClasses.hpp etc.). Use
>> the word "method" elsewhere. The distinction between the JNI method
>> argument and the JVM handle is often conveyed by a simple conventional
>> prefix or suffix. Same general comment for the distinction between a
>> reflective object and an internal metadata pointer. For example:
>> +JVM_ENTRY(jobjectArray, JVM_GetMethodParameters(JNIEnv *env,
>> jobject method_jh))
>> +{
>> + JVMWrapper("JVM_GetMethodParameters");
>> + // method is a handle to a java.lang.reflect.Method object
>> + Handle reflected_method(THREAD,
>> JNIHandles::resolve_non_null(method_jh));
>> + Method* method_oop = jvm_get_method_common(method, CHECK_NULL);
>> + methodHandle method(THREAD, method_oop);
>>
>> Please avoid leading underscores in local variable names, so change _r
>> to result_oop and _m to method_oop, or some such. There are
>> pre-existing examples of this pattern in jvm.cpp, for example in
>> JVM_DoPrivileged and JVM_FindClassFromClass. We use leading
>> underscores only in limited ways, because of portability concerns.
>
> I agree, except method_oop isn't an oop, so method_pointer or golly,
> even m would be a better name.
>> The subroutine jvm_get_method_common no longer needs to take a TRAPS
>> argument, since the permgen removal. You can clean that up since you
>> are in the same file, if you want. (There will be lots of little nits
>> like this, after permgen removal. They can be adjusted on the fly, as
>> we touch code.) Removing the "TRAPS" will make it possible to
>> simplify your new code, since you won't need a CHECK_NULL and the
>> extra method_oop temporary.
>
>
> If Eric takes out the "TRAPS" parameter to get_method_common, he also
> needs to change these lines since TRAPS gives you THREAD. I still
> think it's a nice thing to do.
>
> KlassHandle kh(THREAD, k);
> Method* m = InstanceKlass::cast(kh())->method_with_idnum(slot);
> to
> Method* m = InstanceKlass::cast(k)->method_with_idnum(slot);
>>
>> The changes in constMethod.cpp look correct, but it's hard to tell.
>> The code which manages the "inlined tables" is delicate and very
>> sensitive to initialization ordering. You might try fault injection
>> to ensure that the asserts will catch bugs. By that I mean moving the
>> insertion around a bit in 'set_inlined_tables_length' and ensuring
>> that you get an error diagnostic each time the code is out of place.
>> Add asserts as needed.
>>
>> (Side note: I have some qualms about constMethod which are not due to
>> your changes, but your changes expose a scaling problem in the coding
>> pattern used. It appears to me that, given N inline tables, there are
>> N(N+1)/2 code paths that need to be written correctly, and that a bug
>> on any of those paths may stay latent until the exact pattern of
>> inline-table bits shows up in practice. One symptom of this is the
>> increasing levels of indentation in the logic (which could be
>> clarified slightly by else-if chaining, BTW). Not sure what to do
>> about this. I don't think there's a quick incremental fix. If we go
>> after metadata footprint, I think all such metadata (if not frequently
>> accessed) should be stored via compressed streams
>> (CompressedWriteStream etc.), and that will provide a suitable moment
>> to address this problem, but it's not in scope for this fix.)
>
> I was also wondering if there was a better way to inline these optional
> tables in constMethod because I want to add the method annotations to
> each method (remove from Annotations* type).
>
> Thanks,
> coleen
>> About whitespace: I was reviewing using the raw patch file, and saw a
>> number of apparent oddities involving whitespace. They don't affect
>> correctness, but it would be good to tidy them, to control excess
>> noise in our code base. For example:
>>
>> template(java_lang_reflect_Field,
>> "java/lang/reflect/Field") \
>> + template(java_lang_reflect_Parameter,
>> "java/lang/reflect/Parameter") \ <== extra indent here
>>
>> - compressed_line_number_size,
>> + compressed_line_number_size, <== changed indent
>> here, with no apparent value add
>>
>> checked_exceptions_len,
>> + method_parameters_len, <== one space extend,
>> probably a diff+tab artifact
>> generic_signature_index,
>>
>> + if(has_method_parameters()) { <== missing recommended space after
>> 'if'
>>
>> + return has_generic_signature() ? (last_u2_element() - 1) :
>> + last_u2_element(); <== tiny indent, should be horizontally
>> aligned with previous expression, as with similar code nearby
>>
>>
>> It's hard to tell for sure, since there are tabs in the diff, which a
>> pre-push "jcheck" will reject.
>>
>> Although we (or our text editors) sometimes re-indent code we touch,
>> it is often better to follow the ambient indentation, if the change
>> would not improve readability or consistency. If you were re-aligning
>> parameter declarations, that's a reasonable improvement; I'm not sure
>> that's what you did because of the tabs. In some places you broke a
>> parameter list onto multiple lines, which is fine.
>>
>> I updated the public style guide to clarify some of these points:
>> https://wikis.oracle.com/display/HotSpotInternals/StyleGuide
>>
>> Thanks for making these changes. I think they will be taken up
>> quickly by language implementors.
>>
>> — John
>>
>
More information about the hotspot-dev
mailing list