bytecode rewrite and breakpoint

San Hong Li sherrylso at gmail.com
Tue Jan 13 11:56:46 UTC 2015


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> 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> 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> 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