bytecode rewrite and breakpoint

Coleen Phillimore coleen.phillimore at oracle.com
Tue Jan 13 21:21:25 UTC 2015


Okay, yes, I see now.  We dispatch on the aload_0 bytecode as if it were 
in the stream.  Very tricky.

Coleen

On 1/13/15, 6:56 AM, San Hong Li wrote:
> HI Coleen,
> yes, your understanding is exactly what I meant.  But I would like to 
> explain why that code is necessary.
> (actually I get the answer from the implementation of 
> TemplateTable::_*breakpoint )*
> Suppose we have following bytecode stream, the _bp has been set at 
> this moment:
>
> bcp ---->  |  _bp                        |  ----- original (aload_0)
>                 |    _fast_igetfield      |
>
> The bcp (r13)  currently points to _bp, so the interpreter will 
> execute TemplateTable::_*breakpoint *  at this time.
>
> In TemplateTable::_*breakpoint *:
>
>
> void TemplateTable::_breakpoint() {
>   // Note: We get here even if we are single stepping..
>   // jbug inists on setting breakpoints at every bytecode
>   // even if we are in single step mode.
>
>   transition(vtos, vtos);
>
>   // get the unpatched byte code
>   __ get_method(c_rarg1);
>   __ call_VM(noreg,
>              CAST_FROM_FN_PTR(address,
> InterpreterRuntime::get_original_bytecode_at),
>              c_rarg1, r13);
>   __ mov(rbx, rax);
>
>   // post the breakpoint event
>   __ get_method(c_rarg1);
>   __ call_VM(noreg,
>              CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint),
>              c_rarg1, r13);
>
>   // complete the execution of original bytecode
>   __ dispatch_only_normal(vtos);
> }
>
> The key point here is:   the next original bytecode (aload_0)  was 
> loaded into rbx by    __ mov(rbx, rax) but without r13' advance, so 
> that after the interpreter resumed from breakpoint (e.g: the user 
> typed 'cont' command in jdb for continuous)
>
> The next bytecode aload_0 (loaded in rbx) will get executed, the 
> bytecode stream is still:
>
> bcp ---->  |  _bp                        |  ----- original (aload_0)
>                 |    _fast_igetfield      |
> although we are now executing aload_0 .
>
> In  execution of  aload_0, the patch_bytecode will be called for 
>  (aload_0+_fast_igetfield ) which will be patched as _fast_iaccess_0.
>
> Then back in TemplateTable::patch_bytecode:
> Tthe interpreter will see _bp   is at _bcp(0), but NOT aload_0 ---- as 
> the r13  is not advanced**
>
> Thanks!
> San Hong
>
> On Tue, Jan 13, 2015 at 2:23 AM, Coleen Phillimore 
> <coleen.phillimore at oracle.com <mailto:coleen.phillimore at oracle.com>> 
> wrote:
>
>
>     Hi,
>
>     This is an interesting question actually.
>
>     On 1/12/15, 7:33 AM, San Hong Li wrote:
>>     Hi Coleen:
>>     Thanks for your attention and reply. I would like to clarify my
>>     question again:
>>     Given that we have the following bytecde stream:
>>     |bp|
>>     -------------------------------------------------
>>     | x | x    | aload_0  | x | x  | x  |
>>     -------------------------------------------------
>>     and we suppose that the breakpoint gets inserted  at  the
>>     position of "aload_0 ",   the steam would be updated as follows:
>>
>>     -------------------------------------------------
>>     | x | x    | bp(202)| x | x  | x  |
>>     -------------------------------------------------
>>              (original: aload_0  )
>>
>>     The key point here is : bp and aload_0 have the same bcp index -
>>      I just deduced this from the implementation of
>>     TemplateTable::_*breakpoint.*
>>     *
>>     *
>>     *
>>     *
>>     Based on this layout,  when  the *TemplateTable::patch_bytecode
>>     *was called for **aload_0
>>     The interpreter will see that the bp will be at bcp(0)   (*NOT
>>     aload_0 *at this time)
>
>     If we are executing the code TemplateTable::patch_bytecode, then
>     the bytecode stream had an aload_0 in it *not* _bp, so I'm not
>     sure why we'd all of a sudden find a _bp in the bytecode stream at
>     this point.  The JVMTI set_breakpoint code seems to only set
>     breakpoints at safepoints, and while there's a safepoint at each
>     bytecode, there is not one after we've started executing the
>     bytecode in the template interpreter.  It appears that a different
>     thread cannot change the bytecode to _bp after the _aload_0 is
>     read from the stream.
>
>     So I don't see how we need this code.  It's been there forever. 
>     Maybe the breakpoint code used to work differently in the past
>     which made this code necessary. But a word of warning, this is
>     just my reading of this today, I could be surprised by some other
>     reason that this code is needed.
>
>     Did I understand your question this time?  It's a good one that I
>     don't know the answer to.
>
>     Thanks,
>     Coleen
>
>
>>
>>     This explained that why the HotSpot must have the  below block in
>>     *TemplateTable::patch_bytecode *
>>     to handle the case when the  at bcp(0) is bp.
>>     *(Actually this was the intention of my original question)*
>>
>>       if (JvmtiExport::can_post_breakpoint()) {
>>         Label L_fast_patch;
>>         // if a breakpoint is present we can't rewrite the stream
>>     directly
>>         __ movzbl(temp_reg, at_bcp(0));
>>         __ cmpl(temp_reg, Bytecodes::_breakpoint);
>>         __ jcc(Assembler::notEqual, L_fast_patch);
>>         __ get_method(temp_reg);
>>         // Let breakpoint table handling rewrite to quicker bytecode
>>         __ call_VM(noreg, CAST_FROM_FN_PTR(address,
>>     InterpreterRuntime::set_original_bytecode_at), temp_reg, r13,
>>     bc_reg);
>>     #ifndef ASSERT
>>         __ jmpb(L_patch_done);
>>     #else
>>         __ jmp(L_patch_done);
>>     #endif
>>         __ bind(L_fast_patch);
>>       }
>>
>>     Hopefully I  explain my question and answer clearly  :-)
>>
>>     On Fri, Jan 9, 2015 at 11:35 AM, San Hong Li <sherrylso at gmail.com
>>     <mailto:sherrylso at gmail.com>> wrote:
>>
>>         Hmmm, finally I got the answer for this question.
>>         The  at_bcp(0) would be the Bytecodes::_breakpoint if the
>>         patch_code happened after the  break point is set.
>>         The following example shows this:
>>
>>            33:  getstatic       #8; //Field
>>         java/lang/System.in:Ljava/io/InputStream;
>>            36:  invokevirtual   #9; //Method java/io/InputStream.read:()I
>>            39:  pop
>>            40:  aload_0  <---------------------- set break point here.
>>            41:  getfield        #2; //Field myInt:I
>>            44:  istore  6
>>            46:  iload   6
>>
>>         If we  set the breakpoint at 40 , when the  patch_code  in
>>         aload  happened later, the interpreter will see the
>>         Bytecodes::_breakpoint  at bcp(0).
>>
>>         hmmm, actually i just missed the info present
>>         in TemplateTable::_breakpoint - the breakpoint  used the same
>>         index with the original bytecode.
>>
>>         Anyway, thanks every one.
>>
>>         On Tue, Jan 6, 2015 at 10:18 PM, San Hong Li
>>         <sherrylso at gmail.com <mailto:sherrylso at gmail.com>> wrote:
>>
>>             Hi All:
>>
>>             For the bytecode patch path, the  interpreter does have
>>             some special handling for breakpoint bytecode, that is,
>>              if a breakpoint is present at_bcp(0),   the bytecode
>>             patching will be skipped and  handled by breakpoint table
>>             later.
>>
>>             The related implementation is in
>>              TemplateTable::patch_bytecode:
>>
>>               if (JvmtiExport::can_post_breakpoint()) {
>>                 Label L_fast_patch;
>>                 // if a breakpoint is present we can't rewrite the
>>             stream directly
>>                 __ movzbl(temp_reg, at_bcp(0));
>>                 __ cmpl(temp_reg, Bytecodes::_breakpoint);
>>                 __ jcc(Assembler::notEqual, L_fast_patch);
>>                 __ get_method(temp_reg);
>>                 // Let breakpoint table handling rewrite to quicker
>>             bytecode
>>                 __ call_VM(noreg, CAST_FROM_FN_PTR(address,
>>             InterpreterRuntime::set_original_bytecode_at), temp_reg,
>>             r13, bc_reg);
>>             #ifndef ASSERT
>>                 __ jmpb(L_patch_done);
>>             #else
>>                 __ jmp(L_patch_done);
>>             #endif
>>                 __ bind(L_fast_patch);
>>               }
>>
>>             My understanding is the breakpoint can only be set in
>>             safepoint,
>>             when the interpreter thread resumes from safepoint,
>>             because it will retrieve the next bytecode for executing
>>             again,the breakpoint bytecode which is set in safepoint
>>             before will get chance to be executed. I can not imagine
>>             when the bcp(0) could be changed as breakpoint in above code?
>>             So I am curious whether the above code is already dead?
>>             If not,  anyone can help to me to clarify that  how the
>>             bytecode which is currently executed by interpreter could
>>             be replaced with breakpoint? which case could trigger
>>              the "InterpreterRuntime::set_original_bytecode_at" to be
>>             called?
>>
>>             Appreciated for your help in advance.
>>
>>
>>
>
>



More information about the hotspot-runtime-dev mailing list