StgMacros.h 21 KB
Newer Older
1
/* -----------------------------------------------------------------------------
2
 * $Id: StgMacros.h,v 1.15 1999/11/02 17:04:28 simonmar Exp $
3
4
 *
 * (c) The GHC Team, 1998-1999
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *
 * Macros used for writing STG-ish C code.
 *
 * ---------------------------------------------------------------------------*/

#ifndef STGMACROS_H
#define STGMACROS_H

/* -----------------------------------------------------------------------------
  The following macros create function headers.

  Each basic block is represented by a C function with no arguments.
  We therefore always begin with either

  extern F_ f(void)

  or
  
  static F_ f(void)

  The macros can be used either to define the function itself, or to provide
  prototypes (by following with a ';').
sof's avatar
sof committed
27
28
29
30
31
32
33
34
35
36
37
38

  Note: the various I*_ shorthands in the second block below are used to
  declare forward references to local symbols. These shorthands *have* to
  use the 'extern' type specifier and not 'static'. The reason for this is
  that 'static' declares a reference as being a static/local variable,
  and *not* as a forward reference to a static variable.

  This might seem obvious, but it had me stumped as to why my info tables
  were suddenly all filled with 0s.

    -- sof 1/99 

39
40
41
42
  --------------------------------------------------------------------------- */

#define STGFUN(f)       StgFunPtr f(void)
#define EXTFUN(f)	extern StgFunPtr f(void)
sof's avatar
sof committed
43
#define EXTFUN_RTS(f)	extern DLL_IMPORT_RTS StgFunPtr f(void)
44
45
46
47
#define FN_(f)		F_ f(void)
#define IFN_(f)		static F_ f(void)
#define IF_(f)		static F_ f(void)
#define EF_(f)		extern F_ f(void)
sof's avatar
sof committed
48
#define EDF_(f)		extern DLLIMPORT F_ f(void)
sof's avatar
sof committed
49

50
#define ED_		extern
sof's avatar
sof committed
51
#define EDD_		extern DLLIMPORT 
52
53
54
#define ED_RO_		extern const
#define ID_		extern
#define ID_RO_		extern const
55
56
57
#define EI_             extern INFO_TBL_CONST StgInfoTable
#define EDI_            extern DLLIMPORT INFO_TBL_CONST StgInfoTable
#define II_             extern INFO_TBL_CONST StgInfoTable
58
#define EC_		extern StgClosure
sof's avatar
sof committed
59
#define EDC_		extern DLLIMPORT StgClosure
60
#define IC_		extern StgClosure
61
62
63
#define ECP_(x)		extern const StgClosure *(x)[]
#define EDCP_(x)	extern DLLIMPORT StgClosure *(x)[]
#define ICP_(x)		extern const StgClosure *(x)[]
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

/* -----------------------------------------------------------------------------
   Stack Tagging.

   For a  block of non-pointer words on the stack, we precede the
   block with a small-integer tag giving the number of non-pointer
   words in the block.
   -------------------------------------------------------------------------- */

#ifndef DEBUG_EXTRA
#define ARGTAG_MAX 16		/* probably arbitrary */
#define ARG_TAG(n)  (n)
#define ARG_SIZE(n) stgCast(StgWord,n)

typedef enum {
    REALWORLD_TAG = 0,
    INT_TAG    = sizeofW(StgInt), 
    INT64_TAG  = sizeofW(StgInt64), 
    WORD_TAG   = sizeofW(StgWord), 
    ADDR_TAG   = sizeofW(StgAddr), 
    CHAR_TAG   = sizeofW(StgChar),
    FLOAT_TAG  = sizeofW(StgFloat), 
    DOUBLE_TAG = sizeofW(StgDouble), 
    STABLE_TAG = sizeofW(StgWord), 
} StackTag;

#else /* DEBUG_EXTRA */

typedef enum {
    ILLEGAL_TAG,
    REALWORLD_TAG,
    INT_TAG    ,
    INT64_TAG  ,
    WORD_TAG   ,
    ADDR_TAG   ,
    CHAR_TAG   ,
    FLOAT_TAG  ,
    DOUBLE_TAG ,
    STABLE_TAG ,
    ARGTAG_MAX = DOUBLE_TAG
} StackTag;

/* putting this in a .h file generates many copies - but its only a 
 * debugging build.
 */
static StgWord stg_arg_size[] = {
    [REALWORLD_TAG] = 0,
    [INT_TAG   ] = sizeofW(StgInt), 
    [INT64_TAG ] = sizeofW(StgInt64), 
    [WORD_TAG  ] = sizeofW(StgWord), 
    [ADDR_TAG  ] = sizeofW(StgAddr), 
    [CHAR_TAG  ] = sizeofW(StgChar),
    [FLOAT_TAG ] = sizeofW(StgFloat), 
    [DOUBLE_TAG] = sizeofW(StgDouble),
    [STABLE_TAG] = sizeofW(StgWord)
};

#define ARG_SIZE(tag) stg_arg_size[stgCast(StgWord,tag)]

#endif /* DEBUG_EXTRA */

static inline int IS_ARG_TAG( StgWord p );
static inline int IS_ARG_TAG( StgWord p ) { return p <= ARGTAG_MAX; }

/* -----------------------------------------------------------------------------
   Argument checks.
   
sof's avatar
sof committed
131
   If (Sp + <n_args>) > Su { JMP_(stg_update_PAP); }
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
   
   Sp points to the topmost used word on the stack, and Su points to
   the most recently pushed update frame.

   Remember that <n_args> must include any tagging of unboxed values.

   ARGS_CHK_LOAD_NODE is for top-level functions, whose entry
   convention doesn't require that Node is loaded with a pointer to
   the closure.  Thus we must load node before calling stg_updatePAP if
   the argument check fails. 
   -------------------------------------------------------------------------- */

#define ARGS_CHK(n) 				\
        if ((P_)(Sp + (n)) > (P_)Su) {		\
		JMP_(stg_update_PAP);		\
	}

#define ARGS_CHK_LOAD_NODE(n,closure)		\
        if ((P_)(Sp + (n)) > (P_)Su) {		\
		R1.p = (P_)closure;             \
		JMP_(stg_update_PAP);		\
	}

/* -----------------------------------------------------------------------------
   Heap/Stack Checks.

   When failing a check, we save a return address on the stack and
   jump to a pre-compiled code fragment that saves the live registers
   and returns to the scheduler.

   The return address in most cases will be the beginning of the basic
   block in which the check resides, since we need to perform the check
   again on re-entry because someone else might have stolen the resource
   in the meantime.
   ------------------------------------------------------------------------- */

#define STK_CHK(headroom,ret,r,layout,tag_assts)		\
	if (Sp - headroom < SpLim) {				\
sof's avatar
sof committed
170
	    EXTFUN_RTS(stg_chk_##layout);		 	\
171
172
173
174
175
176
177
	    tag_assts						\
	    (r) = (P_)ret;					\
	    JMP_(stg_chk_##layout);				\
	}
       
#define HP_CHK(headroom,ret,r,layout,tag_assts)			\
	if ((Hp += headroom) > HpLim) {				\
sof's avatar
sof committed
178
	    EXTFUN_RTS(stg_chk_##layout);		 	\
179
	    tag_assts						\
180
	    (r) = (P_)ret;                                     	\
181
	    JMP_(stg_chk_##layout);			   	\
182
	}
183
184
185

#define HP_STK_CHK(stk_headroom,hp_headroom,ret,r,layout,tag_assts) \
	if (Sp - stk_headroom < SpLim || (Hp += hp_headroom) > HpLim) {	\
sof's avatar
sof committed
186
	    EXTFUN_RTS(stg_chk_##layout);		 	\
187
	    tag_assts						\
188
	    (r) = (P_)ret;	                               	\
189
	    JMP_(stg_chk_##layout);			   	\
190
	}
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208

/* -----------------------------------------------------------------------------
   A Heap Check in a case alternative are much simpler: everything is
   on the stack and covered by a liveness mask already, and there is
   even a return address with an SRT info table there as well.  

   Just push R1 and return to the scheduler saying 'EnterGHC'

   {STK,HP,HP_STK}_CHK_NP are the various checking macros for
   bog-standard case alternatives, thunks, and non-top-level
   functions.  In all these cases, node points to a closure that we
   can just enter to restart the heap check (the NP stands for 'node points').

   HpLim points to the LAST WORD of valid allocation space.
   -------------------------------------------------------------------------- */

#define STK_CHK_NP(headroom,ptrs,tag_assts)			\
	if ((Sp - (headroom)) < SpLim) {			\
sof's avatar
sof committed
209
	    EXTFUN_RTS(stg_gc_enter_##ptrs);			\
210
211
212
213
214
215
            tag_assts						\
	    JMP_(stg_gc_enter_##ptrs);				\
	}

#define HP_CHK_NP(headroom,ptrs,tag_assts)			\
	if ((Hp += (headroom)) > HpLim) {			\
sof's avatar
sof committed
216
	    EXTFUN_RTS(stg_gc_enter_##ptrs);			\
217
218
            tag_assts						\
	    JMP_(stg_gc_enter_##ptrs);				\
219
	}
220
221
222

#define HP_CHK_SEQ_NP(headroom,ptrs,tag_assts)			\
	if ((Hp += (headroom)) > HpLim) {			\
sof's avatar
sof committed
223
	    EXTFUN_RTS(stg_gc_seq_##ptrs);			\
224
225
            tag_assts						\
	    JMP_(stg_gc_seq_##ptrs);				\
226
	}
227
228
229

#define HP_STK_CHK_NP(stk_headroom, hp_headroom, ptrs, tag_assts) \
	if ((Sp - (stk_headroom)) < SpLim || (Hp += (hp_headroom)) > HpLim) { \
sof's avatar
sof committed
230
	    EXTFUN_RTS(stg_gc_enter_##ptrs);		 	\
231
232
            tag_assts						\
	    JMP_(stg_gc_enter_##ptrs);			   	\
233
234
	}

235
236
237
238
239

/* Heap checks for branches of a primitive case / unboxed tuple return */

#define GEN_HP_CHK_ALT(headroom,lbl,tag_assts)			\
	if ((Hp += (headroom)) > HpLim) {			\
sof's avatar
sof committed
240
	    EXTFUN_RTS(lbl);					\
241
242
            tag_assts						\
	    JMP_(lbl);						\
243
	}
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318

#define HP_CHK_NOREGS(headroom,tag_assts) \
    GEN_HP_CHK_ALT(headroom,stg_gc_noregs,tag_assts);
#define HP_CHK_UNPT_R1(headroom,tag_assts)  \
    GEN_HP_CHK_ALT(headroom,stg_gc_unpt_r1,tag_assts);
#define HP_CHK_UNBX_R1(headroom,tag_assts)  \
    GEN_HP_CHK_ALT(headroom,stg_gc_unbx_r1,tag_assts);
#define HP_CHK_F1(headroom,tag_assts)       \
    GEN_HP_CHK_ALT(headroom,stg_gc_f1,tag_assts);
#define HP_CHK_D1(headroom,tag_assts)       \
    GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);

#define HP_CHK_L1(headroom,tag_assts)       \
    GEN_HP_CHK_ALT(headroom,stg_gc_d1,tag_assts);

#define HP_CHK_UT_ALT(headroom, ptrs, nptrs, r, ret, tag_assts) \
    GEN_HP_CHK_ALT(headroom, stg_gc_ut_##ptrs##_##nptrs, \
		     tag_assts r = (P_)ret;)

/* -----------------------------------------------------------------------------
   Generic Heap checks.

   These are slow, but have the advantage of being usable in a variety
   of situations.  

   The one restriction is that any relevant SRTs must already be pointed
   to from the stack.  The return address doesn't need to have an info
   table attached: hence it can be any old code pointer.

   The liveness mask is a logical 'XOR' of NO_PTRS and zero or more
   Rn_PTR constants defined below.  All registers will be saved, but
   the garbage collector needs to know which ones contain pointers.

   Good places to use a generic heap check: 

        - case alternatives (the return address with an SRT is already
	  on the stack).

	- primitives (no SRT required).

   The stack layout is like this:

          DblReg1-2
	  FltReg1-4
	  R1-8
	  return address
	  liveness mask
	  stg_gen_chk_info

   so the liveness mask depends on the size of an StgDouble (FltRegs
   and R<n> are guaranteed to be 1 word in size).

   -------------------------------------------------------------------------- */

/* VERY MAGIC CONSTANTS! 
 * must agree with code in HeapStackCheck.c, stg_gen_chk
 */

#if SIZEOF_DOUBLE > SIZEOF_VOID_P
#define ALL_NON_PTRS   0xffff
#else /* SIZEOF_DOUBLE == SIZEOF_VOID_P */
#define ALL_NON_PTRS   0x3fff
#endif

#define LIVENESS_MASK(ptr_regs)  (ALL_NON_PTRS ^ (ptr_regs))

#define NO_PTRS   0
#define R1_PTR	  1<<0
#define R2_PTR	  1<<1
#define R3_PTR	  1<<2
#define R4_PTR	  1<<3
#define R5_PTR	  1<<4
#define R6_PTR	  1<<5
#define R7_PTR	  1<<6
#define R8_PTR	  1<<7
319

320
321
322
323
324
325
326
#define HP_CHK_GEN(headroom,liveness,reentry,tag_assts)	\
   if ((Hp += (headroom)) > HpLim ) {			\
	EF_(stg_gen_chk);				\
        tag_assts					\
	R9.w = (W_)LIVENESS_MASK(liveness);		\
        R10.w = (W_)reentry;				\
        JMP_(stg_gen_chk);				\
327
328
329
330
331
   }

#define HP_CHK_GEN_TICKY(headroom,liveness,reentry,tag_assts)	\
   HP_CHK_GEN(headroom,liveness,reentry,tag_assts);		\
   TICK_ALLOC_HEAP_NOCTR(headroom)
332
333
334
335
336
337
338
339

#define STK_CHK_GEN(headroom,liveness,reentry,tag_assts)	\
   if ((Sp - (headroom)) < SpLim) {				\
	EF_(stg_gen_chk);					\
        tag_assts						\
	R9.w = (W_)LIVENESS_MASK(liveness);			\
        R10.w = (W_)reentry;					\
        JMP_(stg_gen_chk);					\
340
   }
341
342
343
344
345
346
347

#define MAYBE_GC(liveness,reentry)		\
   if (doYouWantToGC()) {			\
	EF_(stg_gen_hp);			\
	R9.w = (W_)LIVENESS_MASK(liveness);	\
        R10.w = (W_)reentry;			\
        JMP_(stg_gen_hp);			\
348
349
350
351
352
353
354
355
356
   }

/* -----------------------------------------------------------------------------
   Voluntary Yields/Blocks

   We only have a generic version of this at the moment - if it turns
   out to be slowing us down we can make specialised ones.
   -------------------------------------------------------------------------- */

sof's avatar
sof committed
357
358
359
EF_(stg_gen_yield);
EF_(stg_gen_block);

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
#define YIELD(liveness,reentry)			\
  {						\
   R9.w  = (W_)LIVENESS_MASK(liveness);		\
   R10.w = (W_)reentry;				\
   JMP_(stg_gen_yield);				\
  }

#define BLOCK(liveness,reentry)			\
  {						\
   R9.w  = (W_)LIVENESS_MASK(liveness);		\
   R10.w = (W_)reentry;				\
   JMP_(stg_gen_block);				\
  }

#define BLOCK_NP(ptrs)				\
  {						\
sof's avatar
sof committed
376
    EF_(stg_block_##ptrs);			\
377
378
379
380
381
382
383
384
385
386
    JMP_(stg_block_##ptrs);			\
  }

/* -----------------------------------------------------------------------------
   CCall_GC needs to push a dummy stack frame containing the contents
   of volatile registers and variables.  

   We use a RET_DYN frame the same as for a dynamic heap check.
   ------------------------------------------------------------------------- */

sof's avatar
sof committed
387
#if COMPILING_RTS
388
EI_(stg_gen_chk_info);
sof's avatar
sof committed
389
390
391
#else
EDI_(stg_gen_chk_info);
#endif
392
393
394
395
396
397
398
399
400
401
402
403
404
/* -----------------------------------------------------------------------------
   Vectored Returns

   RETVEC(p,t) where 'p' is a pointer to the info table for a
   vectored return address, returns the address of the return code for
   tag 't'.

   Return vectors are placed in *reverse order* immediately before the info
   table for the return address.  Hence the formula for computing the
   actual return address is (addr - sizeof(InfoTable) - tag - 1).
   The extra subtraction of one word is because tags start at zero.
   -------------------------------------------------------------------------- */

405
#ifdef TABLES_NEXT_TO_CODE
406
#define RET_VEC(p,t) (*((P_)(p) - sizeofW(StgInfoTable) - t - 1))
407
408
#else
#define RET_VEC(p,t) (((StgInfoTable *)p)->vector[t])
409
410
411
412
413
414
415
416
417
#endif

/* -----------------------------------------------------------------------------
   Misc
   -------------------------------------------------------------------------- */

/* set the tag register (if we have one) */
#define SET_TAG(t)  /* nothing */

418
#ifdef EAGER_BLACKHOLING
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
#  ifdef SMP
#    define UPD_BH_UPDATABLE(info)		\
        TICK_UPD_BH_UPDATABLE();		\
        LOCK_THUNK(info);			\
        SET_INFO(R1.cl,&BLACKHOLE_info)
#    define UPD_BH_SINGLE_ENTRY(info)		\
        TICK_UPD_BH_SINGLE_ENTRY();		\
        LOCK_THUNK(info);			\
        SET_INFO(R1.cl,&BLACKHOLE_info)
#  else
#    define UPD_BH_UPDATABLE(info)		\
        TICK_UPD_BH_UPDATABLE();		\
        SET_INFO(R1.cl,&BLACKHOLE_info)
#    define UPD_BH_SINGLE_ENTRY(info)		\
        TICK_UPD_BH_SINGLE_ENTRY();		\
        SET_INFO(R1.cl,&SE_BLACKHOLE_info)
#  endif
436
437
438
439
#else /* !EAGER_BLACKHOLING */
#  define UPD_BH_UPDATABLE(thunk)    /* nothing */
#  define UPD_BH_SINGLE_ENTRY(thunk) /* nothing */
#endif /* EAGER_BLACKHOLING */
440

441
442
443
#define UPD_FRAME_UPDATEE(p)  (((StgUpdateFrame *)(p))->updatee)
#define UPDATE_SU_FROM_UPD_FRAME(p) (Su=((StgUpdateFrame *)(p))->link)

444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
/* -----------------------------------------------------------------------------
   Moving Floats and Doubles

   ASSIGN_FLT is for assigning a float to memory (usually the
              stack/heap).  The memory address is guaranteed to be
	      StgWord aligned (currently == sizeof(long)).

   PK_FLT     is for pulling a float out of memory.  The memory is
              guaranteed to be StgWord aligned.
   -------------------------------------------------------------------------- */

static inline void	  ASSIGN_FLT (W_ [], StgFloat);
static inline StgFloat    PK_FLT     (W_ []);

#if ALIGNMENT_FLOAT <= ALIGNMENT_LONG

static inline void     ASSIGN_FLT(W_ p_dest[], StgFloat src) { *(StgFloat *)p_dest = src; }
static inline StgFloat PK_FLT    (W_ p_src[])                { return *(StgFloat *)p_src; }

#else  /* ALIGNMENT_FLOAT > ALIGNMENT_UNSIGNED_INT */

static inline void ASSIGN_FLT(W_ p_dest[], StgFloat src)
{
    float_thing y;
    y.f = src;
    *p_dest = y.fu;
}

static inline StgFloat PK_FLT(W_ p_src[])
{
    float_thing y;
    y.fu = *p_src;
    return(y.f);
}

#endif /* ALIGNMENT_FLOAT > ALIGNMENT_LONG */

#if ALIGNMENT_DOUBLE <= ALIGNMENT_LONG

static inline void	  ASSIGN_DBL (W_ [], StgDouble);
static inline StgDouble   PK_DBL     (W_ []);

static inline void      ASSIGN_DBL(W_ p_dest[], StgDouble src) { *(StgDouble *)p_dest = src; }
static inline StgDouble PK_DBL    (W_ p_src[])                 { return *(StgDouble *)p_src; }

#else	/* ALIGNMENT_DOUBLE > ALIGNMENT_LONG */

/* Sparc uses two floating point registers to hold a double.  We can
 * write ASSIGN_DBL and PK_DBL by directly accessing the registers
 * independently - unfortunately this code isn't writable in C, we
 * have to use inline assembler.
 */
#if sparc_TARGET_ARCH

498
499
#define ASSIGN_DBL(dst0,src) \
    { StgPtr dst = (StgPtr)(dst0); \
500
      __asm__("st %2,%0\n\tst %R2,%1" : "=m" (((P_)(dst))[0]), \
501
502
	"=m" (((P_)(dst))[1]) : "f" (src)); \
    }
503

504
505
506
#define PK_DBL(src0) \
    ( { StgPtr src = (StgPtr)(src0); \
        register double d; \
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
      __asm__("ld %1,%0\n\tld %2,%R0" : "=f" (d) : \
	"m" (((P_)(src))[0]), "m" (((P_)(src))[1])); d; \
    } )

#else /* ! sparc_TARGET_ARCH */

static inline void	  ASSIGN_DBL (W_ [], StgDouble);
static inline StgDouble   PK_DBL     (W_ []);

typedef struct
  { StgWord dhi;
    StgWord dlo;
  } unpacked_double;

typedef union
  { StgDouble d;
    unpacked_double du;
  } double_thing;

static inline void ASSIGN_DBL(W_ p_dest[], StgDouble src)
{
    double_thing y;
    y.d = src;
    p_dest[0] = y.du.dhi;
    p_dest[1] = y.du.dlo;
}

/* GCC also works with this version, but it generates
   the same code as the previous one, and is not ANSI

#define ASSIGN_DBL( p_dest, src ) \
	*p_dest = ((double_thing) src).du.dhi; \
	*(p_dest+1) = ((double_thing) src).du.dlo \
*/

static inline StgDouble PK_DBL(W_ p_src[])
{
    double_thing y;
    y.du.dhi = p_src[0];
    y.du.dlo = p_src[1];
    return(y.d);
}

#endif /* ! sparc_TARGET_ARCH */

#endif /* ALIGNMENT_DOUBLE > ALIGNMENT_UNSIGNED_INT */

#ifdef SUPPORT_LONG_LONGS

typedef struct
  { StgWord dhi;
    StgWord dlo;
  } unpacked_double_word;

typedef union
  { StgInt64 i;
    unpacked_double_word iu;
  } int64_thing;

typedef union
sof's avatar
sof committed
567
  { StgWord64 w;
568
569
570
    unpacked_double_word wu;
  } word64_thing;

sof's avatar
sof committed
571
static inline void ASSIGN_Word64(W_ p_dest[], StgWord64 src)
572
573
574
575
576
577
578
{
    word64_thing y;
    y.w = src;
    p_dest[0] = y.wu.dhi;
    p_dest[1] = y.wu.dlo;
}

sof's avatar
sof committed
579
static inline StgWord64 PK_Word64(W_ p_src[])
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
{
    word64_thing y;
    y.wu.dhi = p_src[0];
    y.wu.dlo = p_src[1];
    return(y.w);
}

static inline void ASSIGN_Int64(W_ p_dest[], StgInt64 src)
{
    int64_thing y;
    y.i = src;
    p_dest[0] = y.iu.dhi;
    p_dest[1] = y.iu.dlo;
}

static inline StgInt64 PK_Int64(W_ p_src[])
{
    int64_thing y;
    y.iu.dhi = p_src[0];
    y.iu.dlo = p_src[1];
    return(y.i);
}
#endif

/* -----------------------------------------------------------------------------
   Catch frames
   -------------------------------------------------------------------------- */

sof's avatar
sof committed
608
extern DLL_IMPORT_DATA const StgPolyInfoTable catch_frame_info;
609
610
611
612
613
614
615
616

/* -----------------------------------------------------------------------------
   Seq frames

   A seq frame is very like an update frame, except that it doesn't do
   an update...
   -------------------------------------------------------------------------- */

sof's avatar
sof committed
617
extern DLL_IMPORT_DATA const StgPolyInfoTable seq_frame_info;
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655

#define PUSH_SEQ_FRAME(sp)					\
	{							\
		StgSeqFrame *__frame;				\
		TICK_SEQF_PUSHED();  				\
		__frame = (StgSeqFrame *)(sp); 			\
		SET_HDR_(__frame,&seq_frame_info,CCCS);        	\
		__frame->link = Su;				\
		Su = (StgUpdateFrame *)__frame;			\
	}

/* -----------------------------------------------------------------------------
   Split markers
   -------------------------------------------------------------------------- */

#if defined(USE_SPLIT_MARKERS)
#define __STG_SPLIT_MARKER(n) FN_(__stg_split_marker##n) { }
#else
#define __STG_SPLIT_MARKER(n) /* nothing */
#endif

/* -----------------------------------------------------------------------------
   Closure and Info Macros with casting.

   We don't want to mess around with casts in the generated C code, so
   we use these casting versions of the closure/info tables macros.
   -------------------------------------------------------------------------- */

#define SET_HDR_(c,info,ccs) \
   SET_HDR((StgClosure *)(c),(StgInfoTable *)(info),ccs)

/* -----------------------------------------------------------------------------
   Saving context for exit from the STG world, and loading up context
   on entry to STG code.

   We save all the STG registers (that is, the ones that are mapped to
   machine registers) in their places in the TSO.  

656
657
658
659
660
   The stack registers go into the current stack object, and the
   current nursery is updated from the heap pointer.

   These functions assume that BaseReg is loaded appropriately (if
   we have one).
661
662
   -------------------------------------------------------------------------- */

663
664
#ifndef NO_REGS

665
666
667
668
669
670
671
672
673
674
static __inline__ void
SaveThreadState(void)
{
  /* Don't need to save REG_Base, it won't have changed. */

  CurrentTSO->sp       = Sp;
  CurrentTSO->su       = Su;
  CurrentTSO->splim    = SpLim;
  CloseNursery(Hp);

675
676
677
678
679
680
#ifdef REG_CurrentTSO
  SAVE_CurrentTSO = CurrentTSO;
#endif
#ifdef REG_CurrentNursery
  SAVE_CurrentNursery = CurrentNursery;
#endif
681
682
683
684
685
686
687
688
689
690
691
692
693
#if defined(PROFILING)
  CurrentTSO->prof.CCCS = CCCS;
#endif
}

static __inline__ void 
LoadThreadState (void)
{
  Sp    = CurrentTSO->sp;
  Su    = CurrentTSO->su;
  SpLim = CurrentTSO->splim;
  OpenNursery(Hp,HpLim);

694
695
696
697
698
699
#ifdef REG_CurrentTSO
  CurrentTSO = SAVE_CurrentTSO;
#endif
#ifdef REG_CurrentNursery
  CurrentNursery = SAVE_CurrentNursery;
#endif
700
701
702
703
704
# if defined(PROFILING)
  CCCS = CurrentTSO->prof.CCCS;
# endif
}

705
706
#endif /* NO_REGS */

707
708
709
710
711
712
713
/* 
 * Suspending/resuming threads for doing external C-calls (_ccall_GC).
 * These functions are defined in rts/Schedule.c.
 */
StgInt        suspendThread ( StgRegTable *cap );
StgRegTable * resumeThread  ( StgInt );

714
715
#endif /* STGMACROS_H */