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 * On discovering that a stack or heap check has failed, we do the following:
26 * - If HpLim==0, indicating that we should context-switch, we yield
27 * to the scheduler (return ThreadYielding).
29 * Note that we must leave no slop in the heap (this is a requirement
30 * for LDV profiling, at least), so if we just had a heap-check
31 * failure, then we must retract Hp by HpAlloc. How do we know
32 * whether there was a heap-check failure? HpLim might be zero, and
33 * yet we got here as a result of a stack-check failure. Hence, we
34 * require that HpAlloc is only non-zero if there was a heap-check
35 * failure, otherwise it is zero, so we can always safely subtract
38 * Hence, HpAlloc is zeroed in LOAD_THREAD_STATE().
40 * - If the context_switch flag is set (the backup plan if setting HpLim
41 * to 0 didn't trigger a context switch), we yield to the scheduler
42 * (return ThreadYielding).
44 * - If Hp > HpLim, we've had a heap check failure. This means we've
45 * come to the end of the current heap block, so we try to chain
46 * another block on with ExtendNursery().
48 * - If this succeeds, we carry on without returning to the
51 * - If it fails, we return to the scheduler claiming HeapOverflow
52 * so that a garbage collection can be performed.
54 * - If Hp <= HpLim, it must have been a stack check that failed. In
55 * which case, we return to the scheduler claiming StackOverflow, the
56 * scheduler will either increase the size of our stack, or raise
57 * an exception if the stack is already too big.
59 * The effect of checking for context switch only in the heap/stack check
60 * failure code is that we'll switch threads after the current thread has
61 * reached the end of its heap block. If a thread isn't allocating
62 * at all, it won't yield. Hopefully this won't be a problem in practice.
65 #define PRE_RETURN(why,what_next) \
66 StgTSO_what_next(CurrentTSO) = what_next::I16; \
67 StgRegTable_rRet(BaseReg) = why; \
70 /* Remember that the return address is *removed* when returning to a
71 * ThreadRunGHC thread.
75 DEBUG_ONLY(foreign "C" heapCheckFail()); \
77 Hp = Hp - HpAlloc/*in bytes*/; \
79 R1 = ThreadYielding; \
82 if (HpAlloc <= BLOCK_SIZE \
83 && bdescr_link(CurrentNursery) != NULL) { \
86 CurrentNursery = bdescr_link(CurrentNursery); \
88 if (Capability_context_switch(MyCapability()) != 0 :: CInt) { \
89 R1 = ThreadYielding; \
92 jump %ENTRY_CODE(Sp(0)); \
102 PRE_RETURN(R1,ThreadRunGHC); \
103 jump stg_returnToSched;
106 PRE_RETURN(HeapOverflow, ThreadRunGHC) \
107 jump stg_returnToSched;
109 #define BLOCK_GENERIC \
110 PRE_RETURN(ThreadBlocked, ThreadRunGHC) \
111 jump stg_returnToSched;
113 #define YIELD_GENERIC \
114 PRE_RETURN(ThreadYielding, ThreadRunGHC) \
115 jump stg_returnToSched;
117 #define BLOCK_BUT_FIRST(c) \
118 PRE_RETURN(ThreadBlocked, ThreadRunGHC) \
120 jump stg_returnToSchedButFirst;
122 #define YIELD_TO_INTERPRETER \
123 PRE_RETURN(ThreadYielding, ThreadInterpret) \
124 jump stg_returnToSchedNotPaused;
126 /* -----------------------------------------------------------------------------
127 Heap checks in thunks/functions.
129 In these cases, node always points to the function closure. This gives
130 us an easy way to return to the function: just leave R1 on the top of
131 the stack, and have the scheduler enter it to return.
133 There are canned sequences for 'n' pointer values in registers.
134 -------------------------------------------------------------------------- */
136 INFO_TABLE_RET( stg_enter, RET_SMALL, P_ unused)
147 Sp(0) = stg_enter_info;
151 /* -----------------------------------------------------------------------------
152 Heap checks in Primitive case alternatives
154 A primitive case alternative is entered with a value either in
155 R1, FloatReg1 or D1 depending on the return convention. All the
156 cases are covered below.
157 -------------------------------------------------------------------------- */
159 /*-- No Registers live ------------------------------------------------------ */
166 /*-- void return ------------------------------------------------------------ */
168 INFO_TABLE_RET( stg_gc_void, RET_SMALL)
171 jump %ENTRY_CODE(Sp(0));
174 /*-- R1 is boxed/unpointed -------------------------------------------------- */
176 INFO_TABLE_RET( stg_gc_unpt_r1, RET_SMALL, P_ unused)
180 jump %ENTRY_CODE(Sp(0));
187 Sp(0) = stg_gc_unpt_r1_info;
191 /*-- R1 is unboxed -------------------------------------------------- */
193 /* the 1 is a bitmap - i.e. 1 non-pointer word on the stack. */
194 INFO_TABLE_RET( stg_gc_unbx_r1, RET_SMALL, W_ unused )
198 jump %ENTRY_CODE(Sp(0));
205 Sp(0) = stg_gc_unbx_r1_info;
209 /*-- F1 contains a float ------------------------------------------------- */
211 INFO_TABLE_RET( stg_gc_f1, RET_SMALL, F_ unused )
215 jump %ENTRY_CODE(Sp(0));
221 F_[Sp + WDS(1)] = F1;
222 Sp(0) = stg_gc_f1_info;
226 /*-- D1 contains a double ------------------------------------------------- */
228 INFO_TABLE_RET( stg_gc_d1, RET_SMALL, D_ unused )
230 D1 = D_[Sp + WDS(1)];
231 Sp = Sp + WDS(1) + SIZEOF_StgDouble;
232 jump %ENTRY_CODE(Sp(0));
237 Sp = Sp - WDS(1) - SIZEOF_StgDouble;
238 D_[Sp + WDS(1)] = D1;
239 Sp(0) = stg_gc_d1_info;
244 /*-- L1 contains an int64 ------------------------------------------------- */
246 INFO_TABLE_RET( stg_gc_l1, RET_SMALL, L_ unused )
248 L1 = L_[Sp + WDS(1)];
249 Sp_adj(1) + SIZEOF_StgWord64;
250 jump %ENTRY_CODE(Sp(0));
255 Sp_adj(-1) - SIZEOF_StgWord64;
256 L_[Sp + WDS(1)] = L1;
257 Sp(0) = stg_gc_l1_info;
261 /*-- Unboxed tuple return, one pointer (unregisterised build only) ---------- */
263 INFO_TABLE_RET( stg_ut_1_0_unreg, RET_SMALL, P_ unused )
266 // one ptr is on the stack (Sp(0))
267 jump %ENTRY_CODE(Sp(1));
270 /* -----------------------------------------------------------------------------
271 Generic function entry heap check code.
273 At a function entry point, the arguments are as per the calling convention,
274 i.e. some in regs and some on the stack. There may or may not be
275 a pointer to the function closure in R1 - if there isn't, then the heap
276 check failure code in the function will arrange to load it.
278 The function's argument types are described in its info table, so we
279 can just jump to this bit of generic code to save away all the
280 registers and return to the scheduler.
282 This code arranges the stack like this:
286 +---------------------+
288 +---------------------+
290 +---------------------+
292 +---------------------+
294 The size is the number of words of arguments on the stack, and is cached
295 in the frame in order to simplify stack walking: otherwise the size of
296 this stack frame would have to be calculated by looking at f's info table.
298 -------------------------------------------------------------------------- */
306 info = %GET_FUN_INFO(UNTAG(R1));
309 type = TO_W_(StgFunInfoExtra_fun_type(info));
310 if (type == ARG_GEN) {
311 size = BITMAP_SIZE(StgFunInfoExtra_bitmap(info));
313 if (type == ARG_GEN_BIG) {
314 #ifdef TABLES_NEXT_TO_CODE
315 // bitmap field holds an offset
316 size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info)
317 + %GET_ENTRY(UNTAG(R1)) /* ### */ );
319 size = StgLargeBitmap_size( StgFunInfoExtra_bitmap(info) );
322 size = BITMAP_SIZE(W_[stg_arg_bitmaps + WDS(type)]);
327 // we don't have to save any registers away
331 Sp(0) = stg_gc_fun_info;
335 type = TO_W_(StgFunInfoExtra_fun_type(info));
337 if (type == ARG_GEN || type == ARG_GEN_BIG) {
338 // regs already saved by the heap check code
342 Sp(0) = stg_gc_fun_info;
343 // DEBUG_ONLY(foreign "C" debugBelch("stg_fun_gc_gen(ARG_GEN)"););
346 jump W_[stg_stack_save_entries + WDS(type)];
347 // jumps to stg_gc_noregs after saving stuff
349 #endif /* !NO_ARG_REGS */
352 /* -----------------------------------------------------------------------------
353 Generic Apply (return point)
355 The dual to stg_fun_gc_gen (above): this fragment returns to the
356 function, passing arguments in the stack and in registers
357 appropriately. The stack layout is given above.
358 -------------------------------------------------------------------------- */
360 INFO_TABLE_RET( stg_gc_fun, RET_FUN )
365 // Minor optimisation: there are no argument registers to load up,
366 // so we can just jump straight to the function's entry point.
367 jump %GET_ENTRY(UNTAG(R1));
372 info = %GET_FUN_INFO(UNTAG(R1));
373 type = TO_W_(StgFunInfoExtra_fun_type(info));
374 if (type == ARG_GEN || type == ARG_GEN_BIG) {
375 jump StgFunInfoExtra_slow_apply(info);
377 if (type == ARG_BCO) {
378 // cover this case just to be on the safe side
381 Sp(0) = stg_apply_interp_info;
382 jump stg_yield_to_interpreter;
384 jump W_[stg_ap_stack_entries + WDS(type)];
390 /* -----------------------------------------------------------------------------
391 Generic Heap Check Code.
393 Called with Liveness mask in R9, Return address in R10.
394 Stack must be consistent (containing all necessary info pointers
397 See StgMacros.h for a description of the RET_DYN stack frame.
399 We also define an stg_gen_yield here, because it's very similar.
400 -------------------------------------------------------------------------- */
402 // For simplicity, we assume that SIZEOF_DOUBLE == 2*SIZEOF_VOID_P
403 // on a 64-bit machine, we'll end up wasting a couple of words, but
404 // it's not a big deal.
406 #define RESTORE_EVERYTHING \
407 L1 = L_[Sp + WDS(19)]; \
408 D2 = D_[Sp + WDS(17)]; \
409 D1 = D_[Sp + WDS(15)]; \
410 F4 = F_[Sp + WDS(14)]; \
411 F3 = F_[Sp + WDS(13)]; \
412 F2 = F_[Sp + WDS(12)]; \
413 F1 = F_[Sp + WDS(11)]; \
424 #define RET_OFFSET (-19)
426 #define SAVE_EVERYTHING \
428 L_[Sp + WDS(19)] = L1; \
429 D_[Sp + WDS(17)] = D2; \
430 D_[Sp + WDS(15)] = D1; \
431 F_[Sp + WDS(14)] = F4; \
432 F_[Sp + WDS(13)] = F3; \
433 F_[Sp + WDS(12)] = F2; \
434 F_[Sp + WDS(11)] = F1; \
443 Sp(2) = R10; /* return address */ \
444 Sp(1) = R9; /* liveness mask */ \
445 Sp(0) = stg_gc_gen_info;
447 INFO_TABLE_RET( stg_gc_gen, RET_DYN )
448 /* bitmap in the above info table is unused, the real one is on the stack. */
451 jump Sp(RET_OFFSET); /* No %ENTRY_CODE( - this is an actual code ptr */
460 // A heap check at an unboxed tuple return point. The return address
461 // is on the stack, and we can find it by using the offsets given
462 // to us in the liveness mask.
465 R10 = %ENTRY_CODE(Sp(RET_DYN_NONPTRS(R9) + RET_DYN_PTRS(R9)));
471 * stg_gen_hp is used by MAYBE_GC, where we can't use GC_GENERIC
472 * because we've just failed doYouWantToGC(), not a standard heap
473 * check. GC_GENERIC would end up returning StackOverflow.
481 /* -----------------------------------------------------------------------------
483 -------------------------------------------------------------------------- */
496 /* -----------------------------------------------------------------------------
497 Yielding to the interpreter... top of stack says what to do next.
498 -------------------------------------------------------------------------- */
500 stg_yield_to_interpreter
502 YIELD_TO_INTERPRETER;
505 /* -----------------------------------------------------------------------------
507 -------------------------------------------------------------------------- */
524 Sp(0) = stg_enter_info;
528 /* -----------------------------------------------------------------------------
529 * takeMVar/putMVar-specific blocks
531 * Stack layout for a thread blocked in takeMVar:
535 * stg_block_takemvar_info
537 * Stack layout for a thread blocked in putMVar:
542 * stg_block_putmvar_info
544 * See PrimOps.hc for a description of the workings of take/putMVar.
546 * -------------------------------------------------------------------------- */
548 INFO_TABLE_RET( stg_block_takemvar, RET_SMALL, P_ unused )
555 // code fragment executed just before we return to the scheduler
556 stg_block_takemvar_finally
559 unlockClosure(R3, stg_MVAR_DIRTY_info);
561 SET_INFO(R3, stg_MVAR_DIRTY_info);
570 Sp(0) = stg_block_takemvar_info;
572 BLOCK_BUT_FIRST(stg_block_takemvar_finally);
575 INFO_TABLE_RET( stg_block_putmvar, RET_SMALL, P_ unused1, P_ unused2 )
583 // code fragment executed just before we return to the scheduler
584 stg_block_putmvar_finally
587 unlockClosure(R3, stg_MVAR_DIRTY_info);
589 SET_INFO(R3, stg_MVAR_DIRTY_info);
599 Sp(0) = stg_block_putmvar_info;
601 BLOCK_BUT_FIRST(stg_block_putmvar_finally);
604 // code fragment executed just before we return to the scheduler
605 stg_block_blackhole_finally
607 #if defined(THREADED_RTS)
608 // The last thing we do is release sched_lock, which is
609 // preventing other threads from accessing blackhole_queue and
610 // picking up this thread before we are finished with it.
611 RELEASE_LOCK(sched_mutex "ptr");
620 Sp(0) = stg_enter_info;
621 BLOCK_BUT_FIRST(stg_block_blackhole_finally);
624 INFO_TABLE_RET( stg_block_throwto, RET_SMALL, P_ unused, P_ unused )
629 jump stg_killThreadzh;
632 stg_block_throwto_finally
635 foreign "C" throwToReleaseTarget (R3 "ptr");
645 Sp(0) = stg_block_throwto_info;
646 BLOCK_BUT_FIRST(stg_block_throwto_finally);
649 #ifdef mingw32_HOST_OS
650 INFO_TABLE_RET( stg_block_async, RET_SMALL )
655 ares = StgTSO_block_info(CurrentTSO);
656 len = StgAsyncIOResult_len(ares);
657 errC = StgAsyncIOResult_errCode(ares);
658 StgTSO_block_info(CurrentTSO) = NULL;
659 foreign "C" free(ares "ptr");
662 jump %ENTRY_CODE(Sp(1));
668 Sp(0) = stg_block_async_info;
672 /* Used by threadDelay implementation; it would be desirable to get rid of
673 * this free()'ing void return continuation.
675 INFO_TABLE_RET( stg_block_async_void, RET_SMALL )
679 ares = StgTSO_block_info(CurrentTSO);
680 StgTSO_block_info(CurrentTSO) = NULL;
681 foreign "C" free(ares "ptr");
683 jump %ENTRY_CODE(Sp(0));
689 Sp(0) = stg_block_async_void_info;
695 /* -----------------------------------------------------------------------------
697 -------------------------------------------------------------------------- */
699 stg_block_stmwait_finally
701 foreign "C" stmWaitUnlock(MyCapability() "ptr", R3 "ptr");
707 BLOCK_BUT_FIRST(stg_block_stmwait_finally);