1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team, 1998-2004
5 * Canned Heap-Check and Stack-Check sequences.
7 * This file is written in a subset of C--, extended with various
8 * features specific to GHC. It is compiled by GHC directly. For the
9 * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
11 * ---------------------------------------------------------------------------*/
16 import pthread_mutex_unlock;
18 import EnterCriticalSection;
19 import LeaveCriticalSection;
21 /* Stack/Heap Check Failure
22 * ------------------------
24 * Both heap and stack check failures end up in the same place, so
25 * that we can share the code for the failure case when a proc needs
26 * both a stack check and a heap check (a common case).
28 * So when we get here, we have to tell the difference between a stack
29 * check failure and a heap check failure. The code for the checks
32 if (Sp - 16 < SpLim) goto c1Tf;
34 if (Hp > HpLim) goto c1Th;
39 c1Tf: jump stg_gc_enter_1 ();
41 * Note that Sp is not decremented by the check, whereas Hp is. The
42 * reasons for this seem to be largely historic, I can't think of a
43 * good reason not to decrement Sp at the check too. (--SDM)
45 * Note that HpLim may be set to zero arbitrarily by the timer signal
46 * or another processor to trigger a context switch via heap check
49 * The job of these fragments (stg_gc_enter_1 and friends) is to
50 * 1. Leave no slop in the heap, so Hp must be retreated if it was
51 * incremented by the check. No-slop is a requirement for LDV
52 * profiling, at least.
53 * 2. If a heap check failed, try to grab another heap block from
54 * the nursery and continue.
55 * 3. otherwise, return to the scheduler with StackOverflow,
56 * HeapOverflow, or ThreadYielding as appropriate.
58 * We can tell whether Hp was incremented, because HpAlloc is
59 * non-zero: HpAlloc is required to be zero at all times unless a
60 * heap-check just failed, which is why the stack-check failure case
61 * does not set HpAlloc (see code fragment above). So that covers (1).
62 * HpAlloc is zeroed in LOAD_THREAD_STATE().
64 * If Hp > HpLim, then either (a) we have reached the end of the
65 * current heap block, or (b) HpLim == 0 and we should yield. Hence
66 * check Hp > HpLim first, and then HpLim == 0 to decide whether to
67 * return ThreadYielding or try to grab another heap block from the
70 * If Hp <= HpLim, then this must be a StackOverflow. The scheduler
71 * will either increase the size of our stack, or raise an exception if
72 * the stack is already too big.
75 #define PRE_RETURN(why,what_next) \
76 StgTSO_what_next(CurrentTSO) = what_next::I16; \
77 StgRegTable_rRet(BaseReg) = why; \
80 /* Remember that the return address is *removed* when returning to a
81 * ThreadRunGHC thread.
85 DEBUG_ONLY(foreign "C" heapCheckFail()); \
87 Hp = Hp - HpAlloc/*in bytes*/; \
89 R1 = ThreadYielding; \
92 if (HpAlloc <= BLOCK_SIZE \
93 && bdescr_link(CurrentNursery) != NULL) { \
96 CurrentNursery = bdescr_link(CurrentNursery); \
98 if (Capability_context_switch(MyCapability()) != 0 :: CInt) { \
99 R1 = ThreadYielding; \
102 jump %ENTRY_CODE(Sp(0)); \
109 R1 = StackOverflow; \
112 PRE_RETURN(R1,ThreadRunGHC); \
113 jump stg_returnToSched;
116 PRE_RETURN(HeapOverflow, ThreadRunGHC) \
117 jump stg_returnToSched;
119 #define BLOCK_GENERIC \
120 PRE_RETURN(ThreadBlocked, ThreadRunGHC) \
121 jump stg_returnToSched;
123 #define YIELD_GENERIC \
124 PRE_RETURN(ThreadYielding, ThreadRunGHC) \
125 jump stg_returnToSched;
127 #define BLOCK_BUT_FIRST(c) \
128 PRE_RETURN(ThreadBlocked, ThreadRunGHC) \
130 jump stg_returnToSchedButFirst;
132 #define YIELD_TO_INTERPRETER \
133 PRE_RETURN(ThreadYielding, ThreadInterpret) \
134 jump stg_returnToSchedNotPaused;
136 /* -----------------------------------------------------------------------------
137 Heap checks in thunks/functions.
139 In these cases, node always points to the function closure. This gives
140 us an easy way to return to the function: just leave R1 on the top of
141 the stack, and have the scheduler enter it to return.
143 There are canned sequences for 'n' pointer values in registers.
144 -------------------------------------------------------------------------- */
146 INFO_TABLE_RET( stg_enter, RET_SMALL, P_ unused)
157 Sp(0) = stg_enter_info;
161 /* -----------------------------------------------------------------------------
162 Heap checks in Primitive case alternatives
164 A primitive case alternative is entered with a value either in
165 R1, FloatReg1 or D1 depending on the return convention. All the
166 cases are covered below.
167 -------------------------------------------------------------------------- */
169 /*-- No Registers live ------------------------------------------------------ */
176 /*-- void return ------------------------------------------------------------ */
178 INFO_TABLE_RET( stg_gc_void, RET_SMALL)
181 jump %ENTRY_CODE(Sp(0));
184 /*-- R1 is boxed/unpointed -------------------------------------------------- */
186 INFO_TABLE_RET( stg_gc_unpt_r1, RET_SMALL, P_ unused)
190 jump %ENTRY_CODE(Sp(0));
197 Sp(0) = stg_gc_unpt_r1_info;
201 /*-- R1 is unboxed -------------------------------------------------- */
203 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
204 INFO_TABLE_RET( stg_gc_unbx_r1, RET_SMALL, W_ unused )
208 jump %ENTRY_CODE(Sp(0));
215 Sp(0) = stg_gc_unbx_r1_info;
219 /*-- F1 contains a float ------------------------------------------------- */
221 INFO_TABLE_RET( stg_gc_f1, RET_SMALL, F_ unused )
225 jump %ENTRY_CODE(Sp(0));
231 F_[Sp + WDS(1)] = F1;
232 Sp(0) = stg_gc_f1_info;
236 /*-- D1 contains a double ------------------------------------------------- */
238 INFO_TABLE_RET( stg_gc_d1, RET_SMALL, D_ unused )
240 D1 = D_[Sp + WDS(1)];
241 Sp = Sp + WDS(1) + SIZEOF_StgDouble;
242 jump %ENTRY_CODE(Sp(0));
247 Sp = Sp - WDS(1) - SIZEOF_StgDouble;
248 D_[Sp + WDS(1)] = D1;
249 Sp(0) = stg_gc_d1_info;
254 /*-- L1 contains an int64 ------------------------------------------------- */
256 INFO_TABLE_RET( stg_gc_l1, RET_SMALL, L_ unused )
258 L1 = L_[Sp + WDS(1)];
259 Sp_adj(1) + SIZEOF_StgWord64;
260 jump %ENTRY_CODE(Sp(0));
265 Sp_adj(-1) - SIZEOF_StgWord64;
266 L_[Sp + WDS(1)] = L1;
267 Sp(0) = stg_gc_l1_info;
271 /*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */
273 INFO_TABLE_RET( stg_ut_1_0_unreg, RET_SMALL, P_ unused )
276 // one ptr is on the stack (Sp(0))
277 jump %ENTRY_CODE(Sp(1));
280 /* -----------------------------------------------------------------------------
281 Generic function entry heap check code.
283 At a function entry point, the arguments are as per the calling convention,
284 i.e. some in regs and some on the stack. There may or may not be
285 a pointer to the function closure in R1 - if there isn't, then the heap
286 check failure code in the function will arrange to load it.
288 The function's argument types are described in its info table, so we
289 can just jump to this bit of generic code to save away all the
290 registers and return to the scheduler.
292 This code arranges the stack like this:
296 +---------------------+
298 +---------------------+
300 +---------------------+
302 +---------------------+
304 The size is the number of words of arguments on the stack, and is cached
305 in the frame in order to simplify stack walking: otherwise the size of
306 this stack frame would have to be calculated by looking at f's info table.
308 -------------------------------------------------------------------------- */
316 info = %GET_FUN_INFO(UNTAG(R1));
319 type = TO_W_(StgFunInfoExtra_fun_type(info));
320 if (type == ARG_GEN) {
321 size = BITMAP_SIZE(StgFunInfoExtra_bitmap(info));
323 if (type == ARG_GEN_BIG) {
324 #ifdef TABLES_NEXT_TO_CODE
325 // bitmap field holds an offset
326 size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info)
327 + %GET_ENTRY(UNTAG(R1)) /* ### */ );
329 size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info) );
332 size = BITMAP_SIZE(W_[stg_arg_bitmaps + WDS(type)]);
337 // we don't have to save any registers away
341 Sp(0) = stg_gc_fun_info;
345 type = TO_W_(StgFunInfoExtra_fun_type(info));
347 if (type == ARG_GEN || type == ARG_GEN_BIG) {
348 // regs already saved by the heap check code
352 Sp(0) = stg_gc_fun_info;
353 // DEBUG_ONLY(foreign "C" debugBelch("stg_fun_gc_gen(ARG_GEN)"););
356 jump W_[stg_stack_save_entries + WDS(type)];
357 // jumps to stg_gc_noregs after saving stuff
359 #endif /* !NO_ARG_REGS */
362 /* -----------------------------------------------------------------------------
363 Generic Apply (return point)
365 The dual to stg_fun_gc_gen (above): this fragment returns to the
366 function, passing arguments in the stack and in registers
367 appropriately. The stack layout is given above.
368 -------------------------------------------------------------------------- */
370 INFO_TABLE_RET( stg_gc_fun, RET_FUN )
375 // Minor optimisation: there are no argument registers to load up,
376 // so we can just jump straight to the function's entry point.
377 jump %GET_ENTRY(UNTAG(R1));
382 info = %GET_FUN_INFO(UNTAG(R1));
383 type = TO_W_(StgFunInfoExtra_fun_type(info));
384 if (type == ARG_GEN || type == ARG_GEN_BIG) {
385 jump StgFunInfoExtra_slow_apply(info);
387 if (type == ARG_BCO) {
388 // cover this case just to be on the safe side
391 Sp(0) = stg_apply_interp_info;
392 jump stg_yield_to_interpreter;
394 jump W_[stg_ap_stack_entries + WDS(type)];
400 /* -----------------------------------------------------------------------------
401 Generic Heap Check Code.
403 Called with Liveness mask in R9, Return address in R10.
404 Stack must be consistent (containing all necessary info pointers
407 See StgMacros.h for a description of the RET_DYN stack frame.
409 We also define an stg_gen_yield here, because it's very similar.
410 -------------------------------------------------------------------------- */
412 // For simplicity, we assume that SIZEOF_DOUBLE == 2*SIZEOF_VOID_P
413 // on a 64-bit machine, we'll end up wasting a couple of words, but
414 // it's not a big deal.
416 #define RESTORE_EVERYTHING \
417 L1 = L_[Sp + WDS(19)]; \
418 D2 = D_[Sp + WDS(17)]; \
419 D1 = D_[Sp + WDS(15)]; \
420 F4 = F_[Sp + WDS(14)]; \
421 F3 = F_[Sp + WDS(13)]; \
422 F2 = F_[Sp + WDS(12)]; \
423 F1 = F_[Sp + WDS(11)]; \
434 #define RET_OFFSET (-19)
436 #define SAVE_EVERYTHING \
438 L_[Sp + WDS(19)] = L1; \
439 D_[Sp + WDS(17)] = D2; \
440 D_[Sp + WDS(15)] = D1; \
441 F_[Sp + WDS(14)] = F4; \
442 F_[Sp + WDS(13)] = F3; \
443 F_[Sp + WDS(12)] = F2; \
444 F_[Sp + WDS(11)] = F1; \
453 Sp(2) = R10; /* return address */ \
454 Sp(1) = R9; /* liveness mask */ \
455 Sp(0) = stg_gc_gen_info;
457 INFO_TABLE_RET( stg_gc_gen, RET_DYN )
458 /* bitmap in the above info table is unused, the real one is on the stack. */
461 jump Sp(RET_OFFSET); /* No %ENTRY_CODE( - this is an actual code ptr */
470 // A heap check at an unboxed tuple return point. The return address
471 // is on the stack, and we can find it by using the offsets given
472 // to us in the liveness mask.
475 R10 = %ENTRY_CODE(Sp(RET_DYN_NONPTRS(R9) + RET_DYN_PTRS(R9)));
481 * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
482 * because we've just failed doYouWantToGC(), not a standard heap
483 * check. GC_GENERIC would end up returning StackOverflow.
491 /* -----------------------------------------------------------------------------
493 -------------------------------------------------------------------------- */
506 /* -----------------------------------------------------------------------------
507 Yielding to the interpreter... top of stack says what to do next.
508 -------------------------------------------------------------------------- */
510 stg_yield_to_interpreter
512 YIELD_TO_INTERPRETER;
515 /* -----------------------------------------------------------------------------
517 -------------------------------------------------------------------------- */
534 Sp(0) = stg_enter_info;
538 /* -----------------------------------------------------------------------------
539 * takeMVar/putMVar-specific blocks
541 * Stack layout for a thread blocked in takeMVar:
545 * stg_block_takemvar_info
547 * Stack layout for a thread blocked in putMVar:
552 * stg_block_putmvar_info
554 * See PrimOps.hc for a description of the workings of take/putMVar.
556 * -------------------------------------------------------------------------- */
558 INFO_TABLE_RET( stg_block_takemvar, RET_SMALL, P_ unused )
565 // code fragment executed just before we return to the scheduler
566 stg_block_takemvar_finally
569 unlockClosure(R3, stg_MVAR_DIRTY_info);
571 SET_INFO(R3, stg_MVAR_DIRTY_info);
580 Sp(0) = stg_block_takemvar_info;
582 BLOCK_BUT_FIRST(stg_block_takemvar_finally);
585 INFO_TABLE_RET( stg_block_putmvar, RET_SMALL, P_ unused1, P_ unused2 )
593 // code fragment executed just before we return to the scheduler
594 stg_block_putmvar_finally
597 unlockClosure(R3, stg_MVAR_DIRTY_info);
599 SET_INFO(R3, stg_MVAR_DIRTY_info);
609 Sp(0) = stg_block_putmvar_info;
611 BLOCK_BUT_FIRST(stg_block_putmvar_finally);
614 // code fragment executed just before we return to the scheduler
615 stg_block_blackhole_finally
617 #if defined(THREADED_RTS)
618 // The last thing we do is release sched_lock, which is
619 // preventing other threads from accessing blackhole_queue and
620 // picking up this thread before we are finished with it.
621 RELEASE_LOCK(sched_mutex "ptr");
630 Sp(0) = stg_enter_info;
631 BLOCK_BUT_FIRST(stg_block_blackhole_finally);
634 INFO_TABLE_RET( stg_block_throwto, RET_SMALL, P_ unused, P_ unused )
639 jump stg_killThreadzh;
642 stg_block_throwto_finally
644 // unlock the throwto message, but only if it wasn't already
645 // unlocked. It may have been unlocked if we revoked the message
646 // due to an exception being raised during threadPaused().
647 if (StgHeader_info(StgTSO_block_info(CurrentTSO)) == stg_WHITEHOLE_info) {
648 unlockClosure(StgTSO_block_info(CurrentTSO), stg_MSG_THROWTO_info);
658 Sp(0) = stg_block_throwto_info;
659 BLOCK_BUT_FIRST(stg_block_throwto_finally);
662 #ifdef mingw32_HOST_OS
663 INFO_TABLE_RET( stg_block_async, RET_SMALL )
668 ares = StgTSO_block_info(CurrentTSO);
669 len = StgAsyncIOResult_len(ares);
670 errC = StgAsyncIOResult_errCode(ares);
671 StgTSO_block_info(CurrentTSO) = NULL;
672 foreign "C" free(ares "ptr");
675 jump %ENTRY_CODE(Sp(1));
681 Sp(0) = stg_block_async_info;
685 /* Used by threadDelay implementation; it would be desirable to get rid of
686 * this free()'ing void return continuation.
688 INFO_TABLE_RET( stg_block_async_void, RET_SMALL )
692 ares = StgTSO_block_info(CurrentTSO);
693 StgTSO_block_info(CurrentTSO) = NULL;
694 foreign "C" free(ares "ptr");
696 jump %ENTRY_CODE(Sp(0));
702 Sp(0) = stg_block_async_void_info;
708 /* -----------------------------------------------------------------------------
710 -------------------------------------------------------------------------- */
712 stg_block_stmwait_finally
714 foreign "C" stmWaitUnlock(MyCapability() "ptr", R3 "ptr");
720 BLOCK_BUT_FIRST(stg_block_stmwait_finally);