backedge checks
Andrew Haley
aph at redhat.com
Wed Feb 18 09:24:50 PST 2009
> Hi folks,
>
> In bytecodeInterpreter.c is this wonderful macro
>
> #define DO_BACKEDGE_CHECKS(skip, branch_pc)\
> if ((skip) <= 0) {\
> if (UseCompiler && UseLoopCounter) {\
> bool do_OSR = UseOnStackReplacement;\
> BACKEDGE_COUNT->increment();\
> if (do_OSR) do_OSR = BACKEDGE_COUNT->reached_InvocationLimit();\
> if (do_OSR) {\
> nmethod* osr_nmethod;\
> OSR_REQUEST(osr_nmethod, branch_pc);\
> if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() !=InvalidOSREntryBci) { \
> intptr_t* buf;\
> CALL_VM(buf=SharedRuntime::OSR_migration_begin(THREAD), handle_exception); \
> istate->set_msg(do_osr);\
> istate->set_osr_buf((address)buf);\
> istate->set_osr_entry(osr_nmethod->osr_entry());\
> return;\
> }\
> } else {\
> INCR_INVOCATION_COUNT;\
> SAFEPOINT;\
> }\
> } /* UseCompiler ... */\
> INCR_INVOCATION_COUNT;\
> SAFEPOINT;\
> }
>
>
> This macro is invoked in every branch (although the body is only
> executed on backwards branches).
>
> Firstly, is it just me, or does it do INCR_INVOCATION_COUNT; SAFEPOINT
> twice on every backwards branch. Surely a mistake?
It looks like that to me.
> Secondly, can someone tell me under what circumstances in zero
> UseCompiler would ever be true (and no, it doesn't resolve to a
> constant.
This stuff is AFAIK used to decide when to compile a method with Shark.
> Thirdly, it should be possible to avoid the SAFEPOINT checks. SAFEPOINT
> does...
>
> #define SAFEPOINT \
> if ( SafepointSynchronize::is_synchronizing()) { \
> { \
> /* zap freed handles rather than GC'ing them */ \
> HandleMarkCleaner __hmc(THREAD); \
> } \
> CALL_VM(SafepointSynchronize::block(THREAD), handle_exception); \
> }
>
>
> However, there is an upcall notice_safepoints() which safepoint.cpp
> calls whenever it is setting is_synchronizing(). This upcall is there to
> notify the interpreter that it needs to run to a GC safepoint. A
> corresponding call ignore_safepoints() is called when the interpreter
> can safely ignore safepoints. So there should be no need for the
> interpreter to continually check for safepoints.
>
> notice_safepoints() and ignore_safepoints() in the template interpreter
> do indeed do something sensible. However, in the bytecode Interpreter
> the implementation is just {}
>
> The way it would work is...
>
> When compiling gcc bytecodeInterpreter.cpp uses a dispatch table rather
> than a switch statement. Currently this is defined as
>
> const static void* const opclabels_data[256] = {
> /* 0x00 */ &&opc_nop,
> &&opc_aconst_null,&&opc_iconst_m1,&&opc_iconst_0,
> ...
> };
> register uintptr_t *dispatch_table = (uintptr_t*)&opclabels_data[0];
>
> We would change this to
>
> const static void* opclabels_data[256] = {
> /* 0x00 */ &&opc_nop,
> &&opc_aconst_null,&&opc_iconst_m1,&&opc_iconst_0,
> ...
> };
>
> IE. I have just removed the 'const' because we are going to change this
> dynamically
> We would then define two sets of handlers for branch instructions
>
> struct branch_dispatch {
> int bytecode; /* The bytecode */
> void *handler; /* The handler for it */
> };
> typedef struct branch_dispatch branch_dispatch;
>
> branch_dispatch safe_branch_dispatch_table[] = {
> { Bytecodes::_ifle,safe_ifle_handler },
> { Bytecodes::_ifgt,safe_ifgt_handler },
> ...
> };
>
> branch_dispatch unsafe_branch_dispatch_table[] = {
> { Bytecodes::_ifle,unsafe_ifle_handler },
> { Bytecodes::_ifgt,unsafe_ifgt_handler },
> ...
> }
>
> notice_safepoints() and ignore_safepoints() then become
>
> void update_table(branch_dispatch *p, branch_dispatch *pend)
> {
> do { opclabels_data[p->bytecode] = p->handler; } while (p++ < pend);
> }
>
> notice_safepoints()
> {
> update_table(safe_branch_dispatch_table,
> safe_branch_dispatch_table +
> sizeof(safe_branch_dispatch_table)/sizeof(branch_dispatch));
> }
>
> ignore_safepoint()
> {
> update_table(unsafe_branch_dispatch_table,
> unsafe_branch_dispatch_table +
> sizeof(unsafe_branch_dispatch_table)/sizeof(branch_dispatch));
> }
Hmm, this doesn't look like it's thread safe to me. It would make more
sense to have a pointer to the branch dispatch table that's updated
atomically.
> Finally, can someone enlighten me as to the purpose of
> INCR_INVOCATION_COUNT, if we can get rid of that we could get rid of all
> backedge checks.
Surely the compile broker uses that count.
Andrew.
More information about the zero-dev
mailing list