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 stg_enter_checkbh is just like stg_enter, except that we also call
163 checkBlockingQueues(). The point of this is that the GC can
164 replace an stg_marked_upd_frame with an stg_enter_checkbh if it
165 finds that the BLACKHOLE has already been updated by another
166 thread. It would be unsafe to use stg_enter, because there might
167 be an orphaned BLOCKING_QUEUE now.
168 -------------------------------------------------------------------------- */
170 INFO_TABLE_RET( stg_enter_checkbh, RET_SMALL, P_ unused)
174 foreign "C" checkBlockingQueues(MyCapability() "ptr",
179 /* -----------------------------------------------------------------------------
180 Heap checks in Primitive case alternatives
182 A primitive case alternative is entered with a value either in
183 R1, FloatReg1 or D1 depending on the return convention. All the
184 cases are covered below.
185 -------------------------------------------------------------------------- */
187 /*-- No Registers live ------------------------------------------------------ */
194 /*-- void return ------------------------------------------------------------ */
196 INFO_TABLE_RET( stg_gc_void, RET_SMALL)
199 jump %ENTRY_CODE(Sp(0));
202 /*-- R1 is boxed/unpointed -------------------------------------------------- */
204 INFO_TABLE_RET( stg_gc_unpt_r1, RET_SMALL, P_ unused)
208 jump %ENTRY_CODE(Sp(0));
215 Sp(0) = stg_gc_unpt_r1_info;
219 /*-- R1 is unboxed -------------------------------------------------- */
221 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
222 INFO_TABLE_RET( stg_gc_unbx_r1, RET_SMALL, W_ unused )
226 jump %ENTRY_CODE(Sp(0));
233 Sp(0) = stg_gc_unbx_r1_info;
237 /*-- F1 contains a float ------------------------------------------------- */
239 INFO_TABLE_RET( stg_gc_f1, RET_SMALL, F_ unused )
243 jump %ENTRY_CODE(Sp(0));
249 F_[Sp + WDS(1)] = F1;
250 Sp(0) = stg_gc_f1_info;
254 /*-- D1 contains a double ------------------------------------------------- */
256 INFO_TABLE_RET( stg_gc_d1, RET_SMALL, D_ unused )
258 D1 = D_[Sp + WDS(1)];
259 Sp = Sp + WDS(1) + SIZEOF_StgDouble;
260 jump %ENTRY_CODE(Sp(0));
265 Sp = Sp - WDS(1) - SIZEOF_StgDouble;
266 D_[Sp + WDS(1)] = D1;
267 Sp(0) = stg_gc_d1_info;
272 /*-- L1 contains an int64 ------------------------------------------------- */
274 INFO_TABLE_RET( stg_gc_l1, RET_SMALL, L_ unused )
276 L1 = L_[Sp + WDS(1)];
277 Sp_adj(1) + SIZEOF_StgWord64;
278 jump %ENTRY_CODE(Sp(0));
283 Sp_adj(-1) - SIZEOF_StgWord64;
284 L_[Sp + WDS(1)] = L1;
285 Sp(0) = stg_gc_l1_info;
289 /*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */
291 INFO_TABLE_RET( stg_ut_1_0_unreg, RET_SMALL, P_ unused )
294 // one ptr is on the stack (Sp(0))
295 jump %ENTRY_CODE(Sp(1));
298 /* -----------------------------------------------------------------------------
299 Generic function entry heap check code.
301 At a function entry point, the arguments are as per the calling convention,
302 i.e. some in regs and some on the stack. There may or may not be
303 a pointer to the function closure in R1 - if there isn't, then the heap
304 check failure code in the function will arrange to load it.
306 The function's argument types are described in its info table, so we
307 can just jump to this bit of generic code to save away all the
308 registers and return to the scheduler.
310 This code arranges the stack like this:
314 +---------------------+
316 +---------------------+
318 +---------------------+
320 +---------------------+
322 The size is the number of words of arguments on the stack, and is cached
323 in the frame in order to simplify stack walking: otherwise the size of
324 this stack frame would have to be calculated by looking at f's info table.
326 -------------------------------------------------------------------------- */
334 info = %GET_FUN_INFO(UNTAG(R1));
337 type = TO_W_(StgFunInfoExtra_fun_type(info));
338 if (type == ARG_GEN) {
339 size = BITMAP_SIZE(StgFunInfoExtra_bitmap(info));
341 if (type == ARG_GEN_BIG) {
342 #ifdef TABLES_NEXT_TO_CODE
343 // bitmap field holds an offset
344 size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info)
345 + %GET_ENTRY(UNTAG(R1)) /* ### */ );
347 size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info) );
350 size = BITMAP_SIZE(W_[stg_arg_bitmaps + WDS(type)]);
355 // we don't have to save any registers away
359 Sp(0) = stg_gc_fun_info;
363 type = TO_W_(StgFunInfoExtra_fun_type(info));
365 if (type == ARG_GEN || type == ARG_GEN_BIG) {
366 // regs already saved by the heap check code
370 Sp(0) = stg_gc_fun_info;
371 // DEBUG_ONLY(foreign "C" debugBelch("stg_fun_gc_gen(ARG_GEN)"););
374 jump W_[stg_stack_save_entries + WDS(type)];
375 // jumps to stg_gc_noregs after saving stuff
377 #endif /* !NO_ARG_REGS */
380 /* -----------------------------------------------------------------------------
381 Generic Apply (return point)
383 The dual to stg_fun_gc_gen (above): this fragment returns to the
384 function, passing arguments in the stack and in registers
385 appropriately. The stack layout is given above.
386 -------------------------------------------------------------------------- */
388 INFO_TABLE_RET( stg_gc_fun, RET_FUN )
393 // Minor optimisation: there are no argument registers to load up,
394 // so we can just jump straight to the function's entry point.
395 jump %GET_ENTRY(UNTAG(R1));
400 info = %GET_FUN_INFO(UNTAG(R1));
401 type = TO_W_(StgFunInfoExtra_fun_type(info));
402 if (type == ARG_GEN || type == ARG_GEN_BIG) {
403 jump StgFunInfoExtra_slow_apply(info);
405 if (type == ARG_BCO) {
406 // cover this case just to be on the safe side
409 Sp(0) = stg_apply_interp_info;
410 jump stg_yield_to_interpreter;
412 jump W_[stg_ap_stack_entries + WDS(type)];
418 /* -----------------------------------------------------------------------------
419 Generic Heap Check Code.
421 Called with Liveness mask in R9, Return address in R10.
422 Stack must be consistent (containing all necessary info pointers
425 See StgMacros.h for a description of the RET_DYN stack frame.
427 We also define an stg_gen_yield here, because it's very similar.
428 -------------------------------------------------------------------------- */
430 // For simplicity, we assume that SIZEOF_DOUBLE == 2*SIZEOF_VOID_P
431 // on a 64-bit machine, we'll end up wasting a couple of words, but
432 // it's not a big deal.
434 #define RESTORE_EVERYTHING \
435 L1 = L_[Sp + WDS(19)]; \
436 D2 = D_[Sp + WDS(17)]; \
437 D1 = D_[Sp + WDS(15)]; \
438 F4 = F_[Sp + WDS(14)]; \
439 F3 = F_[Sp + WDS(13)]; \
440 F2 = F_[Sp + WDS(12)]; \
441 F1 = F_[Sp + WDS(11)]; \
452 #define RET_OFFSET (-19)
454 #define SAVE_EVERYTHING \
456 L_[Sp + WDS(19)] = L1; \
457 D_[Sp + WDS(17)] = D2; \
458 D_[Sp + WDS(15)] = D1; \
459 F_[Sp + WDS(14)] = F4; \
460 F_[Sp + WDS(13)] = F3; \
461 F_[Sp + WDS(12)] = F2; \
462 F_[Sp + WDS(11)] = F1; \
471 Sp(2) = R10; /* return address */ \
472 Sp(1) = R9; /* liveness mask */ \
473 Sp(0) = stg_gc_gen_info;
475 INFO_TABLE_RET( stg_gc_gen, RET_DYN )
476 /* bitmap in the above info table is unused, the real one is on the stack. */
479 jump Sp(RET_OFFSET); /* No %ENTRY_CODE( - this is an actual code ptr */
484 // Hack; see Note [mvar-heap-check] in PrimOps.cmm
485 if (R10 == stg_putMVarzh || R10 == stg_takeMVarzh) {
486 unlockClosure(R1, stg_MVAR_DIRTY_info)
492 // A heap check at an unboxed tuple return point. The return address
493 // is on the stack, and we can find it by using the offsets given
494 // to us in the liveness mask.
497 R10 = %ENTRY_CODE(Sp(RET_DYN_NONPTRS(R9) + RET_DYN_PTRS(R9)));
503 * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
504 * because we've just failed doYouWantToGC(), not a standard heap
505 * check. GC_GENERIC would end up returning StackOverflow.
513 /* -----------------------------------------------------------------------------
515 -------------------------------------------------------------------------- */
528 /* -----------------------------------------------------------------------------
529 Yielding to the interpreter... top of stack says what to do next.
530 -------------------------------------------------------------------------- */
532 stg_yield_to_interpreter
534 YIELD_TO_INTERPRETER;
537 /* -----------------------------------------------------------------------------
539 -------------------------------------------------------------------------- */
556 Sp(0) = stg_enter_info;
560 /* -----------------------------------------------------------------------------
561 * takeMVar/putMVar-specific blocks
563 * Stack layout for a thread blocked in takeMVar:
567 * stg_block_takemvar_info
569 * Stack layout for a thread blocked in putMVar:
574 * stg_block_putmvar_info
576 * See PrimOps.hc for a description of the workings of take/putMVar.
578 * -------------------------------------------------------------------------- */
580 INFO_TABLE_RET( stg_block_takemvar, RET_SMALL, P_ unused )
587 // code fragment executed just before we return to the scheduler
588 stg_block_takemvar_finally
590 unlockClosure(R3, stg_MVAR_DIRTY_info);
598 Sp(0) = stg_block_takemvar_info;
600 BLOCK_BUT_FIRST(stg_block_takemvar_finally);
603 INFO_TABLE_RET( stg_block_putmvar, RET_SMALL, P_ unused1, P_ unused2 )
611 // code fragment executed just before we return to the scheduler
612 stg_block_putmvar_finally
614 unlockClosure(R3, stg_MVAR_DIRTY_info);
623 Sp(0) = stg_block_putmvar_info;
625 BLOCK_BUT_FIRST(stg_block_putmvar_finally);
632 Sp(0) = stg_enter_info;
636 INFO_TABLE_RET( stg_block_throwto, RET_SMALL, P_ unused, P_ unused )
641 jump stg_killThreadzh;
644 stg_block_throwto_finally
646 // unlock the throwto message, but only if it wasn't already
647 // unlocked. It may have been unlocked if we revoked the message
648 // due to an exception being raised during threadPaused().
649 if (StgHeader_info(StgTSO_block_info(CurrentTSO)) == stg_WHITEHOLE_info) {
650 unlockClosure(StgTSO_block_info(CurrentTSO), stg_MSG_THROWTO_info);
660 Sp(0) = stg_block_throwto_info;
661 BLOCK_BUT_FIRST(stg_block_throwto_finally);
664 #ifdef mingw32_HOST_OS
665 INFO_TABLE_RET( stg_block_async, RET_SMALL, W_ unused )
671 len = StgAsyncIOResult_len(ares);
672 errC = StgAsyncIOResult_errCode(ares);
673 foreign "C" free(ares "ptr");
677 jump %ENTRY_CODE(Sp(1));
683 Sp(0) = stg_block_async_info;
687 /* Used by threadDelay implementation; it would be desirable to get rid of
688 * this free()'ing void return continuation.
690 INFO_TABLE_RET( stg_block_async_void, RET_SMALL, W_ ares )
695 foreign "C" free(ares "ptr");
697 jump %ENTRY_CODE(Sp(0));
703 Sp(0) = stg_block_async_void_info;
709 /* -----------------------------------------------------------------------------
711 -------------------------------------------------------------------------- */
713 stg_block_stmwait_finally
715 foreign "C" stmWaitUnlock(MyCapability() "ptr", R3 "ptr");
721 BLOCK_BUT_FIRST(stg_block_stmwait_finally);