diff options
Diffstat (limited to 'rts/Updates.cmm')
-rw-r--r-- | rts/Updates.cmm | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/rts/Updates.cmm b/rts/Updates.cmm new file mode 100644 index 0000000000..1d2fc5fe0f --- /dev/null +++ b/rts/Updates.cmm @@ -0,0 +1,153 @@ +/* ----------------------------------------------------------------------------- + * + * (c) The GHC Team, 1998-2004 + * + * Code to perform updates. + * + * This file is written in a subset of C--, extended with various + * features specific to GHC. It is compiled by GHC directly. For the + * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y. + * + * ---------------------------------------------------------------------------*/ + +#include "Cmm.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 +*/ + +/* The update fragment has been tuned so as to generate good + code with gcc, which accounts for some of the strangeness in the + way it is written. + + In particular, the JMP_(ret) bit is passed down and pinned on the + end of each branch (there end up being two major branches in the + 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 + +/* + Make sure this table is big enough to handle the maximum vectored + return size! + */ + +#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_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 */ + ) +{ + Sp_adj(1); + jump %ENTRY_CODE(Sp(0)); +} |