X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FUpdates.cmm;h=789bdd5e53f77bee4e861d7ba7536bb8d89f585c;hb=fff1f6194c3c39de53cd645bda9865fb131b1c68;hp=1d2fc5fe0fb4c1a747d86d92ae0fc61f05437d41;hpb=0065d5ab628975892cea1ec7303f968c3338cbe1;p=ghc-hetmet.git diff --git a/rts/Updates.cmm b/rts/Updates.cmm index 1d2fc5f..789bdd5 100644 --- a/rts/Updates.cmm +++ b/rts/Updates.cmm @@ -10,28 +10,17 @@ * * ---------------------------------------------------------------------------*/ + #include "Cmm.h" +#include "rts/prof/LDV.h" + #include "Updates.h" -#include "StgLdvProf.h" - -/* - The update frame return address must be *polymorphic*, that means - we have to cope with both vectored and non-vectored returns. This - is done by putting the return vector right before the info table, and - having a standard direct return address after the info table (pointed - to by the return address itself, as usual). - - Each entry in the vector table points to a specialised entry code fragment - that knows how to return after doing the update. It would be possible to - use a single generic piece of code that simply entered the return value - to return, but it's quicker this way. The direct return code of course - just does another direct return when it's finished. -*/ -/* on entry to the update code - (1) R1 points to the closure being returned - (2) Sp points to the update frame -*/ +#if defined(PROFILING) +#define UPD_FRAME_PARAMS W_ unused1, W_ unused2, P_ unused3 +#else +#define UPD_FRAME_PARAMS P_ unused1 +#endif /* The update fragment has been tuned so as to generate good code with gcc, which accounts for some of the strangeness in the @@ -42,112 +31,69 @@ code), since we don't mind duplicating this jump. */ -#define UPD_FRAME_ENTRY_TEMPLATE(label,ind_info,ret) \ - label \ - { \ - W_ updatee; \ - \ - updatee = StgUpdateFrame_updatee(Sp); \ - \ - /* remove the update frame from the stack */ \ - Sp = Sp + SIZEOF_StgUpdateFrame; \ - \ - /* ToDo: it might be a PAP, so we should check... */ \ - TICK_UPD_CON_IN_NEW(sizeW_fromITBL(%GET_STD_INFO(updatee))); \ - \ - UPD_SPEC_IND(updatee, ind_info, R1, jump (ret)); \ - } - -UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_0_ret,stg_IND_0_info,%RET_VEC(Sp(0),0)) -UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_1_ret,stg_IND_1_info,%RET_VEC(Sp(0),1)) -UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_2_ret,stg_IND_2_info,%RET_VEC(Sp(0),2)) -UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_3_ret,stg_IND_3_info,%RET_VEC(Sp(0),3)) -UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_4_ret,stg_IND_4_info,%RET_VEC(Sp(0),4)) -UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_5_ret,stg_IND_5_info,%RET_VEC(Sp(0),5)) -UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_6_ret,stg_IND_6_info,%RET_VEC(Sp(0),6)) -UPD_FRAME_ENTRY_TEMPLATE(stg_upd_frame_7_ret,stg_IND_7_info,%RET_VEC(Sp(0),7)) - -#if MAX_VECTORED_RTN > 8 -#error MAX_VECTORED_RTN has changed: please modify stg_upd_frame too. -#endif +/* on entry to the update code + (1) R1 points to the closure being returned + (2) Sp points to the update frame +*/ -/* - Make sure this table is big enough to handle the maximum vectored - return size! - */ +INFO_TABLE_RET( stg_upd_frame, UPDATE_FRAME, UPD_FRAME_PARAMS) +{ + W_ updatee; + + updatee = StgUpdateFrame_updatee(Sp); + + /* remove the update frame from the stack */ + Sp = Sp + SIZEOF_StgUpdateFrame; + + /* ToDo: it might be a PAP, so we should check... */ + TICK_UPD_CON_IN_NEW(sizeW_fromITBL(%GET_STD_INFO(updatee))); + + updateWithIndirection(updatee, + R1, + jump %ENTRY_CODE(Sp(0))); +} -#if defined(PROFILING) -#define UPD_FRAME_BITMAP 3 -#define UPD_FRAME_WORDS 3 -#else -#define UPD_FRAME_BITMAP 0 -#define UPD_FRAME_WORDS 1 -#endif -/* this bitmap indicates that the first word of an update frame is a - * non-pointer - this is the update frame link. (for profiling, - * there's a cost-centre-stack in there too). - */ - -INFO_TABLE_RET( stg_upd_frame, - UPD_FRAME_WORDS, UPD_FRAME_BITMAP, UPDATE_FRAME, - stg_upd_frame_0_ret, - stg_upd_frame_1_ret, - stg_upd_frame_2_ret, - stg_upd_frame_3_ret, - stg_upd_frame_4_ret, - stg_upd_frame_5_ret, - stg_upd_frame_6_ret, - stg_upd_frame_7_ret - ) -UPD_FRAME_ENTRY_TEMPLATE(,stg_IND_direct_info,%ENTRY_CODE(Sp(0))) - - -INFO_TABLE_RET( stg_marked_upd_frame, - UPD_FRAME_WORDS, UPD_FRAME_BITMAP, UPDATE_FRAME, - stg_upd_frame_0_ret, - stg_upd_frame_1_ret, - stg_upd_frame_2_ret, - stg_upd_frame_3_ret, - stg_upd_frame_4_ret, - stg_upd_frame_5_ret, - stg_upd_frame_6_ret, - stg_upd_frame_7_ret - ) -UPD_FRAME_ENTRY_TEMPLATE(,stg_IND_direct_info,%ENTRY_CODE(Sp(0))) - -/*----------------------------------------------------------------------------- - Seq frames - - We don't have a primitive seq# operator: it is just a 'case' - expression whose scrutinee has either a polymorphic or function type - (constructor types can be handled by normal 'case' expressions). - - To handle a polymorphic/function typed seq, we push a SEQ frame on - the stack. This is a polymorphic activation record that just pops - itself and returns (in a non-vectored way) when entered. The - purpose of the SEQ frame is to avoid having to make a polymorphic return - point for each polymorphic case expression. - - Another way of looking at it: the SEQ frame turns a vectored return - into a direct one. - -------------------------------------------------------------------------- */ - -#if MAX_VECTORED_RTN > 8 -#error MAX_VECTORED_RTN has changed: please modify stg_seq_frame too. -#endif +INFO_TABLE_RET( stg_marked_upd_frame, UPDATE_FRAME, UPD_FRAME_PARAMS) +{ + W_ updatee, v, i, tso, link; + + // we know the closure is a BLACKHOLE + updatee = StgUpdateFrame_updatee(Sp); + v = StgInd_indirectee(updatee); + + // remove the update frame from the stack + Sp = Sp + SIZEOF_StgUpdateFrame; + + if (GETTAG(v) != 0) { + // updated by someone else: discard our value and use the + // other one to increase sharing, but check the blocking + // queues to see if any threads were waiting on this BLACKHOLE. + R1 = v; + foreign "C" checkBlockingQueues(MyCapability() "ptr", + CurrentTSO "ptr") [R1]; + jump %ENTRY_CODE(Sp(0)); + } + + // common case: it is still our BLACKHOLE + if (v == CurrentTSO) { + updateWithIndirection(updatee, + R1, + jump %ENTRY_CODE(Sp(0))); + } + + // The other cases are all handled by the generic code + foreign "C" updateThunk (MyCapability() "ptr", CurrentTSO "ptr", + updatee "ptr", R1 "ptr") [R1]; + + jump %ENTRY_CODE(Sp(0)); +} -INFO_TABLE_RET( stg_seq_frame, 0/* words */, 0/* bitmap */, RET_SMALL, - RET_LBL(stg_seq_frame), /* 0 */ - RET_LBL(stg_seq_frame), /* 1 */ - RET_LBL(stg_seq_frame), /* 2 */ - RET_LBL(stg_seq_frame), /* 3 */ - RET_LBL(stg_seq_frame), /* 4 */ - RET_LBL(stg_seq_frame), /* 5 */ - RET_LBL(stg_seq_frame), /* 6 */ - RET_LBL(stg_seq_frame) /* 7 */ - ) +// Special update frame code for CAFs and eager-blackholed thunks: it +// knows how to update blackholes, but is distinct from +// stg_marked_upd_frame so that lazy blackholing won't treat it as the +// high watermark. +INFO_TABLE_RET (stg_bh_upd_frame, UPDATE_FRAME, UPD_FRAME_PARAMS) { - Sp_adj(1); - jump %ENTRY_CODE(Sp(0)); + jump RET_LBL(stg_marked_upd_frame); }