RFR(M): 8145221: Use trampolines for i2i and i2c entries in Methods that are stored in CDS archive

Ioi Lam ioi.lam at oracle.com
Mon Mar 21 16:40:46 UTC 2016



On 3/18/16 6:43 PM, Jiangli Zhou wrote:
> Hi Ioi,
>
>> On Mar 18, 2016, at 4:04 PM, Ioi Lam <ioi.lam at oracle.com 
>> <mailto:ioi.lam at oracle.com>> wrote:
>>
>>
>>
>> On 3/18/16 11:52 AM, Jiangli Zhou wrote:
>>>
>>>>>
>>>>> The changes look good overall. Following are my comments and 
>>>>> questions.
>>>>>
>>>>> - src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp
>>>>> - src/os_cpu/linux_aarch64/vm/thread_linux_aarch64.cpp
>>>>> - src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp
>>>>> - src/os_cpu/linux_x86/vm/thread_linux_x86.cpp
>>>>> - src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp
>>>>> - src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp
>>>>> - src/os_cpu/windows_x86/vm/thread_windows_x86.cpp
>>>>>   Please place the new CDS-only code under #if INCLUDE_CDS.
>>>>>
>>>>>  It would be a good idea to assert the address (current pc) is 
>>>>> within the generated trampoline entry buffer.
>>>> I am not sure what this means. Could you explain?
>>>
>>>
>>> We should assert that the address is in the generated trampoline 
>>> code, but not at a random place in the shared space. If the control 
>>> dumps to an arbitrary location, it might manifest itself into a bug 
>>> that’s hard to debug.
>>
>> I still don't understand where you want to put the assertion. Could 
>> you tell me which file/function you want to add the assert, and what 
>> should be put in the assert?
>
>
> For example, assert the pc() is in trampoline code if we get an 
> address in the shared space in the following code in 
> JavaThread::pd_get_top_frame().
>
>    69     if (UseSharedSpaces && MetaspaceShared::is_in_shared_space(addr.pc())) {
>    70       // In the middle of a trampoline call. Bail out for safety.
>    71       // This happens rarely so shouldn't affect profiling.
>    72       return false;
>    73     }
> Something like the following?
>
> assert(addr.pc() >= MetaspaceShared::cds_i2i_entry_code_buffers() &&
>            addr.pc() < MetaspaceShared::cds_i2i_entry_code_buffers() + 
> MetaspaceShared::cds_i2i_entry_code_buffer_size(),
>            “Unexpected");
>
The address range you listed is just part of the trampolines (for the 
"standard" method entries). More trampolines can be allocated here -- 
these are entries that are associated with specific method signatures.

3021 void CDSAdapterHandlerEntry::init() {
3022   assert(DumpSharedSpaces, "used during dump time only");
3023   _c2i_entry_trampoline = 
(address)MetaspaceShared::misc_code_space_alloc(SharedRuntime::trampoline_size());
3024   _adapter_trampoline = 
(AdapterHandlerEntry**)MetaspaceShared::misc_data_space_alloc(sizeof(AdapterHandlerEntry*));
3025 };

In addition, addr.pc() can also be one of the vtable patching methods.

So, instead of adding an assert, I think it's better to narrow the check 
to something like:

      if (UseSharedSpaces && 
MetaspaceShared::is_in_shared_misc_code_space(addr.pc())) {


[...snip...]

>>
>>>>> - src/share/vm/oops/method.hpp
>>>>>   In set_interpreter_entry(), when _i2i_entry and 
>>>>> _from_interpreted_entry are not the same as ‘entry’ for shared method?
>>>>
>>>> The purpose of the check is to avoid writing the same value into 
>>>> the shared Method (which would cause the pages to be 
>>>> copied-on-write, even if the value does not change).
>>>>
>>>> 475   void set_interpreter_entry(address entry) {
>>>> 476     if (_i2i_entry != entry) {
>>>> 477       _i2i_entry = entry;
>>>> 478     }
>>>> 479     if (_from_interpreted_entry != entry) {
>>>> 480       _from_interpreted_entry = entry;
>>>> 481     }
>>>> 482   }
>>>
>>> I see set_interpreter_entry() is called from Method initializing 
>>> code and link_method(). For a shared method, we should change the if 
>>> check to be an assert. Would there be any case where the entry is 
>>> not the same as the one in the shared method?
>>
>> I am actually not sure if for shared methods the i2i_entry and 
>> from_interpreter_entry would be set to any other values. E.g., in the 
>> future, someone may add a new tracing facility that requires 
>> modifying these 2 fields.
>>
>> I'd rather play safe so we don't overwrite into the shared Method 
>> most of the time, but if it does happen it will continue to work.
>
> This part of the code is more critical. So, we should have a tighter 
> control of it. If someone is setting the the entry to a different 
> valve than the one in the Method, we need to know what is the new 
> entry and understand why. The assertion would force us to exam each 
> new case like the one you described in the above. Is that reasonable?
>
Sounds good. I think we should add the assert so we will catch such new 
cases in non-product builds. But for safety, in product builds, we 
should set the values as requested. We don't want assumptions made by 
this optimization to affect functional correctness.

475   void set_interpreter_entry(address entry) {
         if (is_shared()) {
           assert(_i2i_entry != entry && _from_interpreted_entry != 
entry, "must be");
         }
476     if (_i2i_entry != entry) {
477       _i2i_entry = entry;
478     }
479     if (_from_interpreted_entry != entry) {
480       _from_interpreted_entry = entry;
481     }
482   }




More information about the hotspot-runtime-dev mailing list