RFR(S) 8212200 assert when shared java.lang.Object is redefined by JVMTI agent
Harold David Seigel
harold.seigel at oracle.com
Tue Oct 23 19:06:15 UTC 2018
Hi Ioi,
Should this code in SystemDictionary.cpp have an "#ifdef ASSERT" around it?
2108 if (UseSharedSpaces) {
2109 assert(JvmtiEnvBase::get_phase() <= JVMTI_PHASE_PRIMORDIAL,
2110 "All well known classes must be resolved in
JVMTI_PHASE_PRIMORDIAL or before");
2111 for (int i = FIRST_WKID; i < last; i++) {
2112 InstanceKlass* k = _well_known_klasses[i];
2113 assert(k->is_shared(), "must not be replaced by JVMTI class
file load hook");
2114 }
Thanks, Harold
On 10/23/2018 10:34 AM, Lois Foltan wrote:
> On 10/23/2018 12:09 AM, Ioi Lam wrote:
>
>>
>>
>> On 10/22/18 10:25 AM, Lois Foltan wrote:
>>> On 10/22/2018 1:49 AM, Ioi Lam wrote:
>>>
>>>> Hi David,
>>>>
>>>> Thanks for the review. Updated webrev:
>>>>
>>>> http://cr.openjdk.java.net/~iklam/jdk12/8212200-cds-jvmti-clfh-critical-classes.v04/
>>>>
>>>> http://cr.openjdk.java.net/~iklam/jdk12/8212200-cds-jvmti-clfh-critical-classes.v04.delta/
>>>>
>>>
>>> Hi Ioi,
>>>
>>> Looks good. A couple of comments:
>>>
>>> classfile/systemDictionary.cpp
>>> - line#1975 - My preference is to declare the variable sid outside
>>> the for statement and compare sid == 0 within the for loop conditional.
>> Do you mean this?
>>
>> bool SystemDictionary::is_well_known_klass(Symbol* class_name) {
>> int sid;
>> for (int i = 0; (sid = wk_init_info[i]) != 0; i++) {
>> Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid);
>> if (class_name == symbol) {
>> return true;
>> }
>> }
>> return false;
>> }
>>
> Yes, I think that's better.
>
>>> - line#1981 - can you use class_name->fast_compare(symbol) for the
>>> equality check?
>>>
>> The comments around fast_compare says it's for vtable sorting only.
> Right, David pointed that out to me as well. Comment retracted.
>
>>
>>> memory/heapShared.cpp
>>> - line#422 could be a ResourceMark rm(THREAD);
>>>
>> Fixed.
> Great, thanks!
> Lois
>
>>
>> Thanks
>> - Ioi
>>
>>> Thanks,
>>> Lois
>>>
>>>>
>>>> More comments below:
>>>>
>>>>
>>>>
>>>> On 10/21/18 6:57 PM, David Holmes wrote:
>>>>> Hi Ioi,
>>>>>
>>>>> Generally seems okay.
>>>>>
>>>>> On 22/10/2018 11:15 AM, Ioi Lam wrote:
>>>>>> Re-sending to the correct mailing lists. Please disregard the
>>>>>> other email.
>>>>>>
>>>>>> http://cr.openjdk.java.net/~iklam/jdk12/8212200-cds-jvmti-clfh-critical-classes.v03/
>>>>>>
>>>>>> https://bugs.openjdk.java.net/browse/JDK-8212200
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> CDS has various built-in assumptions that classes loaded by
>>>>>> SystemDictionary::resolve_well_known_classes must not be replaced
>>>>>> by JVMTI ClassFileLoadHook during run time, including
>>>>>>
>>>>>> - field offsets computed in JavaClasses::compute_offsets
>>>>>> - the layout of the strings objects in the shared strings table
>>>>>>
>>>>>> The "well-known" classes can be replaced by ClassFileLoadHook only
>>>>>> when JvmtiExport::early_class_hook_env() is true. Therefore, the
>>>>>> fix is to disable CDS under this condition.
>>>>>
>>>>> I'm a little unclear why we have to iterate JvmtiEnv list when
>>>>> this has to be checked during JVMTI_PHASE_PRIMORDIAL?
>>>>>
>>>> I think you are asking about this new function? I don't like the
>>>> name "early_class_hook_env()". Maybe I should change it to
>>>> "has_early_class_hook_env()"?
>>>>
>>>>
>>>> bool JvmtiExport::early_class_hook_env() {
>>>> JvmtiEnvIterator it;
>>>> for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
>>>> if (env->early_class_hook_env()) {
>>>> return true;
>>>> }
>>>> }
>>>> return false;
>>>> }
>>>>
>>>> This function matches condition in the existing code that would
>>>> call into ClassFileLoadHook:
>>>>
>>>> class JvmtiClassFileLoadHookPoster {
>>>> ...
>>>> void post_all_envs() {
>>>> JvmtiEnvIterator it;
>>>> for (JvmtiEnv* env = it.first(); env != NULL; env =
>>>> it.next(env)) {
>>>> ..
>>>> post_to_env(env, true);
>>>> }
>>>> }
>>>> ...
>>>> void post_to_env(JvmtiEnv* env, bool caching_needed) {
>>>> if (env->phase() == JVMTI_PHASE_PRIMORDIAL &&
>>>> !env->early_class_hook_env()) {
>>>> return;
>>>> }
>>>>
>>>>
>>>> post_all_envs() is called just before a class is about to be loaded
>>>> in the JVM. So if *any* env->early_class_hook_env() returns true,
>>>> there's a chance that it will replace a well-known class.So, as a
>>>> preventive measure, CDS will be disabled.
>>>>
>>>>
>>>>
>>>>>> I have added a few test cases to try to replace shared classes,
>>>>>> including well-known classes and other classes. See
>>>>>> comments in ReplaceCriticalClasses.java for details.
>>>>>>
>>>>>> As a clean up, I also renamed all use of "preloaded" in
>>>>>> the source code to "well-known". They refer to the same thing
>>>>>> in HotSpot, so there's no need to use 2 terms. Also, The word
>>>>>> "preloaded" is ambiguous -- it's unclear when "preloading" happens,
>>>>>> and could be confused with what CDS does during archive dump time.
>>>>>
>>>>> A few specific comments:
>>>>>
>>>>> src/hotspot/share/classfile/systemDictionary.cpp
>>>>>
>>>>> + bool SystemDictionary::is_well_known_klass(Symbol* class_name) {
>>>>> + for (int i = 0; ; i++) {
>>>>> + int sid = wk_init_info[i];
>>>>> + if (sid == 0) {
>>>>> + break;
>>>>> + }
>>>>>
>>>>> I take it a zero value is a guaranteed end-of-list sentinel?
>>>>>
>>>>
>>>> Yes. The array is defined just a few lines above:
>>>>
>>>> static const short wk_init_info[] = {
>>>> #define WK_KLASS_INIT_INFO(name, symbol) \
>>>> ((short)vmSymbols::VM_SYMBOL_ENUM_NAME(symbol)),
>>>>
>>>> WK_KLASSES_DO(WK_KLASS_INIT_INFO)
>>>> #undef WK_KLASS_INIT_INFO
>>>> 0
>>>> };
>>>>
>>>> Also,
>>>>
>>>> class vmSymbols: AllStatic {
>>>> enum SID {
>>>> NO_SID = 0,
>>>> ....
>>>>
>>>>
>>>>
>>>>> + for (int i=FIRST_WKID; i<last; i++) {
>>>>>
>>>>> Style nit: need spaces around = and <
>>>>>
>>>>
>>>> Fixed.
>>>>
>>>>> ---
>>>>>
>>>>> test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/ReplaceCriticalClasses.java
>>>>>
>>>>>
>>>>> New file should have current copyright year only.
>>>>>
>>>> Fixed.
>>>>
>>>>> 31 * @comment CDS should not be disabled -- these critical
>>>>> classes will be replaced because
>>>>> JvmtiExport::early_class_hook_env() is true.
>>>>>
>>>>> Comment seems contradictory: if we replace critical classes then
>>>>> CDS should be disabled right??
>>>>>
>>>> Fixed.
>>>>
>>>>> I expected to see tests that checked for:
>>>>>
>>>>> "CDS is disabled because early JVMTI ClassFileLoadHook is in use."
>>>>>
>>>>> in the output. ??
>>>>>
>>>> <rant>
>>>> It would have been easy if jtreg lets you check the output of @run
>>>> easily. Instead, your innocent suggestion has turned into 150+
>>>> lines of new code :-( Maybe "let's write all shell tests in Java"
>>>> isn't such a great idea after all.
>>>> </rant>
>>>>
>>>> Now the test checks that whether CDS is indeed disabled, whether
>>>> the affected class is loaded from the shared archive, etc.
>>>>
>>>> Thanks
>>>> - Ioi
>>>>
>>>>> Thanks,
>>>>> David
>>>>>
>>>>>
>>>>>>
>>>>>> > In early e-mails Jiangli wrote:
>>>>>> >
>>>>>> > We should consider including more classes from the default
>>>>>> classlist
>>>>>> > in the test. Archived classes loaded during both 'early' phase
>>>>>> and after
>>>>>> > should be tested.
>>>>>>
>>>>>> Done.
>>>>>>
>>>>>>
>>>>>> > For future optimizations, we might want to prevent loading
>>>>>> additional
>>>>>> > shared classes if any of the archived system classes is changed.
>>>>>>
>>>>>> What's the benefit of doing this? Today we already stop loading a
>>>>>> shared
>>>>>> class if its super class was not loaded from the archive.
>>>>>>
>>>>>>
>>>>>> Thanks
>>>>>> - Ioi
>>>>>>
>>>>
>>>
>>
>
More information about the hotspot-runtime-dev
mailing list