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