X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FHeapStackCheck.hc;h=f3882fe9ff7100f0418eb78174063639a45b3208;hb=d07a6e61ca1bcf8d71f2d01e45885f0a3233d1f0;hp=ff31c74651cdab4657a727b525e30ff63d2f7e86;hpb=456eca7317895df8193d83b986352b6238e3824d;p=ghc-hetmet.git diff --git a/ghc/rts/HeapStackCheck.hc b/ghc/rts/HeapStackCheck.hc index ff31c74..f3882fe 100644 --- a/ghc/rts/HeapStackCheck.hc +++ b/ghc/rts/HeapStackCheck.hc @@ -1,5 +1,5 @@ /* ----------------------------------------------------------------------------- - * $Id: HeapStackCheck.hc,v 1.4 1999/03/16 13:20:15 simonm Exp $ + * $Id: HeapStackCheck.hc,v 1.26 2002/03/02 17:43:44 sof Exp $ * * (c) The GHC Team, 1998-1999 * @@ -7,11 +7,11 @@ * * ---------------------------------------------------------------------------*/ +#include "Stg.h" #include "Rts.h" #include "Storage.h" /* for CurrentTSO */ #include "StgRun.h" /* for StgReturn and register saving */ #include "Schedule.h" /* for context_switch */ -#include "HeapStackCheck.h" /* Stack/Heap Check Failure * ------------------------ @@ -20,7 +20,7 @@ * * - If the context_switch flag is set, indicating that there are more * threads waiting to run, we yield to the scheduler - * (return ThreadYeilding). + * (return ThreadYielding). * * - If Hp > HpLim, we've had a heap check failure. This means we've * come to the end of the current heap block, so we try to chain @@ -47,10 +47,10 @@ * ThreadRunGHC thread. */ - #define GC_GENERIC \ if (Hp > HpLim) { \ - if (ExtendNursery(Hp,HpLim)) { \ + Hp -= HpAlloc; \ + if (HpAlloc <= BLOCK_SIZE_W && ExtendNursery(Hp,HpLim)) {\ if (context_switch) { \ R1.i = ThreadYielding; \ } else { \ @@ -64,12 +64,13 @@ R1.i = StackOverflow; \ } \ SaveThreadState(); \ - CurrentTSO->whatNext = ThreadRunGHC; \ + CurrentTSO->what_next = ThreadRunGHC; \ JMP_(StgReturn); #define GC_ENTER \ if (Hp > HpLim) { \ - if (ExtendNursery(Hp,HpLim)) { \ + Hp -= HpAlloc; \ + if (HpAlloc <= BLOCK_SIZE_W && ExtendNursery(Hp,HpLim)) {\ if (context_switch) { \ R1.i = ThreadYielding; \ } else { \ @@ -84,42 +85,42 @@ R1.i = StackOverflow; \ } \ SaveThreadState(); \ - CurrentTSO->whatNext = ThreadEnterGHC; \ + CurrentTSO->what_next = ThreadEnterGHC; \ JMP_(StgReturn); #define HP_GENERIC \ SaveThreadState(); \ - CurrentTSO->whatNext = ThreadRunGHC; \ + CurrentTSO->what_next = ThreadRunGHC; \ R1.i = HeapOverflow; \ JMP_(StgReturn); #define STK_GENERIC \ SaveThreadState(); \ - CurrentTSO->whatNext = ThreadRunGHC; \ + CurrentTSO->what_next = ThreadRunGHC; \ R1.i = StackOverflow; \ JMP_(StgReturn); #define YIELD_GENERIC \ SaveThreadState(); \ - CurrentTSO->whatNext = ThreadRunGHC; \ + CurrentTSO->what_next = ThreadRunGHC; \ R1.i = ThreadYielding; \ JMP_(StgReturn); -#define YIELD_TO_HUGS \ +#define YIELD_TO_INTERPRETER \ SaveThreadState(); \ - CurrentTSO->whatNext = ThreadEnterHugs; \ + CurrentTSO->what_next = ThreadEnterInterp; \ R1.i = ThreadYielding; \ JMP_(StgReturn); #define BLOCK_GENERIC \ SaveThreadState(); \ - CurrentTSO->whatNext = ThreadRunGHC; \ + CurrentTSO->what_next = ThreadRunGHC; \ R1.i = ThreadBlocked; \ JMP_(StgReturn); #define BLOCK_ENTER \ SaveThreadState(); \ - CurrentTSO->whatNext = ThreadEnterGHC;\ + CurrentTSO->what_next = ThreadEnterGHC;\ R1.i = ThreadBlocked; \ JMP_(StgReturn); @@ -150,7 +151,7 @@ EXTFUN(stg_gc_entertop) There are canned sequences for 'n' pointer values in registers. -------------------------------------------------------------------------- */ -EXTFUN(stg_gc_enter_1) +EXTFUN(__stg_gc_enter_1) { FB_ Sp -= 1; @@ -159,6 +160,18 @@ EXTFUN(stg_gc_enter_1) FE_ } +EXTFUN(stg_gc_enter_1_hponly) +{ + FB_ + Sp -= 1; + Sp[0] = R1.w; + R1.i = HeapOverflow; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + JMP_(StgReturn); + FE_ +} + /*- 2 Regs--------------------------------------------------------------------*/ EXTFUN(stg_gc_enter_2) @@ -264,6 +277,334 @@ EXTFUN(stg_gc_enter_8) FE_ } +#if defined(GRAN) +/* + ToDo: merge the block and yield macros, calling something like BLOCK(N) + at the end; +*/ + +/* + Should we actually ever do a yield in such a case?? -- HWL +*/ +EXTFUN(gran_yield_0) +{ + FB_ + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +EXTFUN(gran_yield_1) +{ + FB_ + Sp -= 1; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +/*- 2 Regs--------------------------------------------------------------------*/ + +EXTFUN(gran_yield_2) +{ + FB_ + Sp -= 2; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +/*- 3 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_yield_3) +{ + FB_ + Sp -= 3; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +/*- 4 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_yield_4) +{ + FB_ + Sp -= 4; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +/*- 5 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_yield_5) +{ + FB_ + Sp -= 5; + Sp[4] = R5.w; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +/*- 6 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_yield_6) +{ + FB_ + Sp -= 6; + Sp[5] = R6.w; + Sp[4] = R5.w; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +/*- 7 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_yield_7) +{ + FB_ + Sp -= 7; + Sp[6] = R7.w; + Sp[5] = R6.w; + Sp[4] = R5.w; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +/*- 8 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_yield_8) +{ + FB_ + Sp -= 8; + Sp[7] = R8.w; + Sp[6] = R7.w; + Sp[5] = R6.w; + Sp[4] = R5.w; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadYielding; + JMP_(StgReturn); + FE_ +} + +// the same routines but with a block rather than a yield + +EXTFUN(gran_block_1) +{ + FB_ + Sp -= 1; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +/*- 2 Regs--------------------------------------------------------------------*/ + +EXTFUN(gran_block_2) +{ + FB_ + Sp -= 2; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +/*- 3 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_block_3) +{ + FB_ + Sp -= 3; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +/*- 4 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_block_4) +{ + FB_ + Sp -= 4; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +/*- 5 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_block_5) +{ + FB_ + Sp -= 5; + Sp[4] = R5.w; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +/*- 6 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_block_6) +{ + FB_ + Sp -= 6; + Sp[5] = R6.w; + Sp[4] = R5.w; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +/*- 7 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_block_7) +{ + FB_ + Sp -= 7; + Sp[6] = R7.w; + Sp[5] = R6.w; + Sp[4] = R5.w; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +/*- 8 Regs -------------------------------------------------------------------*/ + +EXTFUN(gran_block_8) +{ + FB_ + Sp -= 8; + Sp[7] = R8.w; + Sp[6] = R7.w; + Sp[5] = R6.w; + Sp[4] = R5.w; + Sp[3] = R4.w; + Sp[2] = R3.w; + Sp[1] = R2.w; + Sp[0] = R1.w; + SaveThreadState(); + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +#endif + +#if 0 && defined(PAR) + +/* + Similar to stg_block_1 (called via StgMacro BLOCK_NP) but separates the + saving of the thread state from the actual jump via an StgReturn. + We need this separation because we call RTS routines in blocking entry codes + before jumping back into the RTS (see parallel/FetchMe.hc). +*/ + +EXTFUN(par_block_1_no_jump) +{ + FB_ + Sp -= 1; + Sp[0] = R1.w; + SaveThreadState(); + FE_ +} + +EXTFUN(par_jump) +{ + FB_ + CurrentTSO->what_next = ThreadEnterGHC; + R1.i = ThreadBlocked; + JMP_(StgReturn); + FE_ +} + +#endif + /* ----------------------------------------------------------------------------- For a case expression on a polymorphic or function-typed object, if the default branch (there can only be one branch) of the case fails @@ -293,22 +634,39 @@ EXTFUN(stg_gc_seq_1) cases are covered below. -------------------------------------------------------------------------- */ -/*-- No regsiters live, return address already on the stack: ---------------- */ +/*-- No registers live (probably a void return) ----------------------------- */ + +/* If we change the policy for thread startup to *not* remove the + * return address from the stack, we can get rid of this little + * function/info table... + */ +INFO_TABLE_SRT_BITMAP(stg_gc_noregs_info, stg_gc_noregs_ret, 0/*BITMAP*/, + 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, + RET_SMALL,, EF_, 0, 0); + +EXTFUN(stg_gc_noregs_ret) +{ + FB_ + JMP_(ENTRY_CODE(Sp[0])); + FE_ +} EXTFUN(stg_gc_noregs) { FB_ + Sp -= 1; + Sp[0] = (W_)&stg_gc_noregs_info; GC_GENERIC FE_ } /*-- R1 is boxed/unpointed -------------------------------------------------- */ -INFO_TABLE_SRT_BITMAP(stg_gc_unpt_r1_info, stg_gc_unpt_r1_entry, 0/*BITMAP*/, +INFO_TABLE_SRT_BITMAP(stg_gc_unpt_r1_info, stg_gc_unpt_r1_ret, 0/*BITMAP*/, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, - RET_SMALL, const, EF_, 0, 0); + RET_SMALL,, EF_, 0, 0); -EXTFUN(stg_gc_unpt_r1_entry) +EXTFUN(stg_gc_unpt_r1_ret) { FB_ R1.w = Sp[0]; @@ -327,14 +685,28 @@ EXTFUN(stg_gc_unpt_r1) FE_ } +/*-- Unboxed tuple return (unregisterised build only)------------------ */ + +INFO_TABLE_SRT_BITMAP(stg_ut_1_0_unreg_info, stg_ut_1_0_unreg_ret, 0/*BITMAP*/, + 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, + RET_SMALL,, EF_, 0, 0); + +EXTFUN(stg_ut_1_0_unreg_ret) +{ + FB_ + /* R1 is on the stack (*Sp) */ + JMP_(ENTRY_CODE(Sp[1])); + FE_ +} + /*-- R1 is unboxed -------------------------------------------------- */ -INFO_TABLE_SRT_BITMAP(stg_gc_unbx_r1_info, stg_gc_unbx_r1_entry, 1/*BITMAP*/, +INFO_TABLE_SRT_BITMAP(stg_gc_unbx_r1_info, stg_gc_unbx_r1_ret, 1/*BITMAP*/, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, - RET_SMALL, const, EF_, 0, 0); + RET_SMALL,, EF_, 0, 0); /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */ -EXTFUN(stg_gc_unbx_r1_entry) +EXTFUN(stg_gc_unbx_r1_ret) { FB_ R1.w = Sp[0]; @@ -355,11 +727,11 @@ EXTFUN(stg_gc_unbx_r1) /*-- F1 contains a float ------------------------------------------------- */ -INFO_TABLE_SRT_BITMAP(stg_gc_f1_info, stg_gc_f1_entry, 1/*BITMAP*/, +INFO_TABLE_SRT_BITMAP(stg_gc_f1_info, stg_gc_f1_ret, 1/*BITMAP*/, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, - RET_SMALL, const, EF_, 0, 0); + RET_SMALL,, EF_, 0, 0); -EXTFUN(stg_gc_f1_entry) +EXTFUN(stg_gc_f1_ret) { FB_ F1 = PK_FLT(Sp); @@ -388,11 +760,11 @@ EXTFUN(stg_gc_f1) # define DBL_BITMAP 3 #endif -INFO_TABLE_SRT_BITMAP(stg_gc_d1_info, stg_gc_d1_entry, DBL_BITMAP, +INFO_TABLE_SRT_BITMAP(stg_gc_d1_info, stg_gc_d1_ret, DBL_BITMAP, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, - RET_SMALL, const, EF_, 0, 0); + RET_SMALL,, EF_, 0, 0); -EXTFUN(stg_gc_d1_entry) +EXTFUN(stg_gc_d1_ret) { FB_ D1 = PK_DBL(Sp); @@ -411,6 +783,40 @@ EXTFUN(stg_gc_d1) FE_ } + +/*-- L1 contains an int64 ------------------------------------------------- */ + +/* we support int64s of either 1 or 2 words in size */ + +#if SIZEOF_VOID_P == 8 +# define LLI_BITMAP 1 +#else +# define LLI_BITMAP 3 +#endif + +INFO_TABLE_SRT_BITMAP(stg_gc_l1_info, stg_gc_l1_ret, LLI_BITMAP, + 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, + RET_SMALL,, EF_, 0, 0); + +EXTFUN(stg_gc_l1_ret) +{ + FB_ + L1 = PK_Int64(Sp); + Sp += sizeofW(StgWord64); + JMP_(ENTRY_CODE(Sp[0])); + FE_ +} + +EXTFUN(stg_gc_l1) +{ + FB_ + Sp -= 1 + sizeofW(StgWord64); + ASSIGN_Int64(Sp+1,L1); + Sp[0] = (W_)&stg_gc_l1_info; + GC_GENERIC + FE_ +} + /* ----------------------------------------------------------------------------- Heap checks for unboxed tuple case alternatives @@ -441,16 +847,16 @@ EXTFUN(stg_gc_d1) /*---- R1 contains a pointer: ------ */ -INFO_TABLE_SRT_BITMAP(stg_gc_ut_1_0_info, stg_gc_ut_1_0_entry, 1/*BITMAP*/, +INFO_TABLE_SRT_BITMAP(stg_gc_ut_1_0_info, stg_gc_ut_1_0_ret, 1/*BITMAP*/, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, - RET_SMALL, const, EF_, 0, 0); + RET_SMALL,, EF_, 0, 0); -EXTFUN(stg_gc_ut_1_0_entry) +EXTFUN(stg_gc_ut_1_0_ret) { FB_ R1.w = Sp[1]; Sp += 2; - JMP_(Sp[-2]); + JMP_(ENTRY_CODE(Sp[-2])); FE_ } @@ -467,16 +873,16 @@ EXTFUN(stg_gc_ut_1_0) /*---- R1 contains a non-pointer: ------ */ -INFO_TABLE_SRT_BITMAP(stg_gc_ut_0_1_info, stg_gc_ut_0_1_entry, 3/*BITMAP*/, +INFO_TABLE_SRT_BITMAP(stg_gc_ut_0_1_info, stg_gc_ut_0_1_ret, 3/*BITMAP*/, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, - RET_SMALL, const, EF_, 0, 0); + RET_SMALL,, EF_, 0, 0); -EXTFUN(stg_gc_ut_0_1_entry) +EXTFUN(stg_gc_ut_0_1_ret) { FB_ R1.w = Sp[1]; Sp += 2; - JMP_(Sp[-2]); + JMP_(ENTRY_CODE(Sp[-2])); FE_ } @@ -522,7 +928,7 @@ EXTFUN(stg_gc_ut_0_1) /*- 0 Regs -------------------------------------------------------------------*/ -EXTFUN(stg_chk_0) +EXTFUN(__stg_chk_0) { FB_ Sp -= 1; @@ -533,7 +939,7 @@ EXTFUN(stg_chk_0) /*- 1 Reg --------------------------------------------------------------------*/ -EXTFUN(stg_chk_1) +EXTFUN(__stg_chk_1) { FB_ Sp -= 2; @@ -764,7 +1170,7 @@ EXTFUN(stg_chk_8) INFO_TABLE_SRT_BITMAP(stg_gen_chk_info, stg_gen_chk_ret, 0, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, - RET_DYN, const, EF_, 0, 0); + RET_DYN,, EF_, 0, 0); /* bitmap in the above info table is unused, the real one is on the stack. */ @@ -773,7 +1179,7 @@ FN_(stg_gen_chk_ret) { FB_ RESTORE_EVERYTHING; - JMP_(Sp[RET_OFFSET]); + JMP_(Sp[RET_OFFSET]); /* NO ENTRY_CODE() - this is a direct ret address */ FE_ } @@ -798,6 +1204,10 @@ FN_(stg_gen_hp) FE_ } +/* ----------------------------------------------------------------------------- + Yields + -------------------------------------------------------------------------- */ + FN_(stg_gen_yield) { FB_ @@ -809,18 +1219,24 @@ FN_(stg_gen_yield) FN_(stg_yield_noregs) { FB_ - YIELD_GENERIC + Sp--; + Sp[0] = (W_)&stg_gc_noregs_info; + YIELD_GENERIC; FE_ } -FN_(stg_yield_to_Hugs) +FN_(stg_yield_to_interpreter) { FB_ /* No need to save everything - no live registers */ - YIELD_TO_HUGS + YIELD_TO_INTERPRETER FE_ } +/* ----------------------------------------------------------------------------- + Blocks + -------------------------------------------------------------------------- */ + FN_(stg_gen_block) { FB_ @@ -829,6 +1245,15 @@ FN_(stg_gen_block) FE_ } +FN_(stg_block_noregs) +{ + FB_ + Sp--; + Sp[0] = (W_)&stg_gc_noregs_info; + BLOCK_GENERIC; + FE_ +} + FN_(stg_block_1) { FB_ @@ -837,3 +1262,71 @@ FN_(stg_block_1) BLOCK_ENTER; FE_ } + +/* ----------------------------------------------------------------------------- + * takeMVar/putMVar-specific blocks + * + * Stack layout for a thread blocked in takeMVar: + * + * ret. addr + * ptr to MVar (R1) + * stg_block_takemvar_info + * + * Stack layout for a thread blocked in putMVar: + * + * ret. addr + * ptr to Value (R2) + * ptr to MVar (R1) + * stg_block_putmvar_info + * + * See PrimOps.hc for a description of the workings of take/putMVar. + * + * -------------------------------------------------------------------------- */ + +INFO_TABLE_SRT_BITMAP(stg_block_takemvar_info, stg_block_takemvar_ret, + 0/*BITMAP*/, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, + RET_SMALL,, IF_, 0, 0); + +IF_(stg_block_takemvar_ret) +{ + FB_ + R1.w = Sp[0]; + Sp++; + JMP_(takeMVarzh_fast); + FE_ +} + +FN_(stg_block_takemvar) +{ + FB_ + Sp -= 2; + Sp[1] = R1.w; + Sp[0] = (W_)&stg_block_takemvar_info; + BLOCK_GENERIC; + FE_ +} + +INFO_TABLE_SRT_BITMAP(stg_block_putmvar_info, stg_block_putmvar_ret, + 0/*BITMAP*/, 0/*SRT*/, 0/*SRT_OFF*/, 0/*SRT_LEN*/, + RET_SMALL,, IF_, 0, 0); + +IF_(stg_block_putmvar_ret) +{ + FB_ + R2.w = Sp[1]; + R1.w = Sp[0]; + Sp += 2; + JMP_(putMVarzh_fast); + FE_ +} + +FN_(stg_block_putmvar) +{ + FB_ + Sp -= 3; + Sp[2] = R2.w; + Sp[1] = R1.w; + Sp[0] = (W_)&stg_block_putmvar_info; + BLOCK_GENERIC; + FE_ +}