Skip to content
octomarat edited this page Aug 15, 2014 · 14 revisions

General info

Description of how breakpoints mechanism is implemented in GHCi. Useful when working with GHCi source code.

GHCi data structures

data BreakInfo 
   = BreakInfo
   { breakInfo_module :: Module
   , breakInfo_number :: {-# UNPACK #-} !Int
   , breakInfo_vars   :: [(Id,Word16)]
   , breakInfo_resty  :: Type
   }
 
data Resume
   = Resume {
       resumeStmt      :: String,       -- the original statement
       resumeThreadId  :: ThreadId,     -- thread running the computation
       resumeBreakMVar :: MVar (),
       resumeStatMVar  :: MVar Status,
       resumeBindings  :: ([TyThing], GlobalRdrEnv),
       resumeFinalIds  :: [Id],         -- [Id] to bind on completion
       resumeApStack   :: HValue,       -- The object from which we can get
                                        -- value of the free variables.
       resumeBreakInfo :: Maybe BreakInfo,
                                        -- the breakpoint we stopped at
                                        -- (Nothing <=> exception)
       resumeSpan      :: SrcSpan,      -- just a cache, otherwise it's a pain
                                        -- to fetch the ModDetails & ModBreaks
                                        -- to get this.
       resumeHistory   :: [History],
       resumeHistoryIx :: Int           -- 0 <==> at the top of the history
   }
data History
   = History {
        historyApStack   :: HValue,
        historyBreakInfo :: BreakInfo,
      

resumeApStack сontaints new_aps from code below.

Intepreter.c

size_words = BCO_BITMAP_SIZE(obj) + 2;
new_aps = (StgAP_STACK *) allocate(cap, AP_STACK_sizeW(size_words));
SET_HDR(new_aps,&stg_AP_STACK_info,CCS_SYSTEM); 
new_aps->size = size_words;
new_aps->fun = &stg_dummy_ret_closure; 

// fill in the payload of the AP_STACK 
new_aps->payload[0] = (StgClosure *)&stg_apply_interp_info;
new_aps->payload[1] = (StgClosure *)obj;

// copy the contents of the top stack frame into the AP_STACK
for (i = 2; i < size_words; i++)
{
    new_aps->payload[i] = (StgClosure *)Sp[i-2];
}

Description for StgClosure, StgThunkHeader and StgAP_STACK

Very good description of these things is given in GHC commentary for RTS in section Storage/HeapObjects.

Structures under consideration are actually defined in the file ghc/includes/rts/storage/Closures.h, comments there may be useful.

Some useful information about what Entry Code, Info Table and Closures are is given in description of STG machine in the section "Important concepts in the machine".

  1. StgClosure

Defined in ghc/includes/rts/Types.h as follows:

typedef struct StgClosure_   StgClosure;

So it it just a typedef. Actual definition is in ghc/includes/rts/storage/Closures.h:

typedef struct StgClosure_ {
    StgHeader   header;
    struct StgClosure_ *payload[FLEXIBLE_ARRAY];
} *StgClosurePtr; // StgClosure defined in rts/Types.h

This structure represents heap object. Heap objects are closures, if I've got the idea right. All heap objects have header and payload.

Main part of the header is pointer to InfoTable. InfoTable contains different information, for example, closure type and layout of payload (payload's structure, how objects located there). This info is used by Garbage Collector (GC) in particular. Another important thing stored in InfoTable is entry code. It is used to evaluate the closure.

Payload contains different information about closure depending on it's type. For example, payload of Function Closures stores free variables of the function.

  1. StgThunkHeader

As it was mentioned above, closures have headers. It seems like Thunks (closure type that represents an expression that is not obviously in head normal form, see Storage/HeapObjects for more info) has this kind of headers. Source code in ghc/includes/rts/storage/Closures.h:

/* -----------------------------------------------------------------------------
   The SMP header
   
   A thunk has a padding word to take the updated value.  This is so
   that the update doesn't overwrite the payload, so we can avoid
   needing to lock the thunk during entry and update.
   
   Note: this doesn't apply to THUNK_STATICs, which have no payload.

   Note: we leave this padding word in all ways, rather than just SMP,
   so that we don't have to recompile all our libraries for SMP.
   -------------------------------------------------------------------------- */

typedef struct {
    StgWord pad;
} StgSMPThunkHeader;

/* -----------------------------------------------------------------------------
   The full fixed-size closure header

   The size of the fixed header is the sum of the optional parts plus a single
   word for the entry code pointer.
   -------------------------------------------------------------------------- */

typedef struct {
    const StgInfoTable* info;
#ifdef PROFILING
    StgProfHeader         prof;
#endif
} StgHeader;

typedef struct {
    const StgInfoTable* info;
#ifdef PROFILING
    StgProfHeader         prof;
#endif
    StgSMPThunkHeader     smp;
} StgThunkHeader;

All this makes me think that it is usual header but with additional information for SMP ([info] (http://www.haskell.org/ghc/docs/6.6/html/users_guide/sec-using-smp.html)). So we may assume that it is just a header as it is described above.

  1. StgAP_STACK

Represents closure type for Stack Application. See corresponding section in Storage/HeapObjects. Source code in ghc/includes/rts/storage/Closures.h:

typedef struct {
    StgThunkHeader   header;
    StgWord     size;                    /* number of words in payload */
    StgClosure *fun;
    StgClosure *payload[FLEXIBLE_ARRAY]; /* contains a chunk of *stack* */
} StgAP_STACK;