summaryrefslogtreecommitdiff
path: root/rts/AutoApply.h
blob: d0c5c3fe6ba325e7e1a9fde6860820978e5974c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
/* -----------------------------------------------------------------------------
 *
 * (c) The University of Glasgow 2002-2004
 *
 * Helper bits for the generic apply code (AutoApply.hc)
 *
 * -------------------------------------------------------------------------- */

#ifndef AUTOAPPLY_H
#define AUTOAPPLY_H

// Build a new PAP: function is in R1
// ret addr and m arguments taking up n words are on the stack.
// NB. x is a dummy argument attached to the 'for' label so that
// BUILD_PAP can be used multiple times in the same function.
#define BUILD_PAP(m,n,f,x)				\
    W_ pap;						\
    W_ size;						\
    W_ i;						\
    size = SIZEOF_StgPAP + WDS(n);			\
    HP_CHK_NP_ASSIGN_SP0(size,f);			\
    TICK_ALLOC_HEAP_NOCTR(BYTES_TO_WDS(size));		\
    TICK_ALLOC_PAP(n+1 /* +1 for the FUN */, 0);	\
    pap = Hp + WDS(1) - size;				\
    SET_HDR(pap, stg_PAP_info, CCCS);                   \
    StgPAP_arity(pap) = HALF_W_(arity - m);		\
    StgPAP_fun(pap)   = R1;				\
    StgPAP_n_args(pap) = HALF_W_(n);			\
    i = 0;						\
  for##x:						\
    if (i < n) {					\
	StgPAP_payload(pap,i) = Sp(1+i);		\
	i = i + 1;					\
	goto for##x;					\
    }							\
    R1 = pap;						\
    Sp_adj(1 + n);					\
    jump %ENTRY_CODE(Sp(0));

// Copy the old PAP, build a new one with the extra arg(s)
// ret addr and m arguments taking up n words are on the stack.
// NB. x is a dummy argument attached to the 'for' label so that
// BUILD_PAP can be used multiple times in the same function.
#define NEW_PAP(m,n,f,x)					\
     W_ pap;							\
     W_ new_pap;						\
     W_ size;							\
     W_ i;							\
     pap = R1;							\
     size = SIZEOF_StgPAP + WDS(TO_W_(StgPAP_n_args(pap))) + WDS(n);	\
     HP_CHK_NP_ASSIGN_SP0(size,f);				\
     TICK_ALLOC_HEAP_NOCTR(BYTES_TO_WDS(size));			\
     TICK_ALLOC_PAP(n+1 /* +1 for the FUN */, 0);		\
     new_pap = Hp + WDS(1) - size;				\
     SET_HDR(new_pap, stg_PAP_info, CCCS);                      \
     StgPAP_arity(new_pap) = HALF_W_(arity - m);		\
     W_ n_args;							\
     n_args = TO_W_(StgPAP_n_args(pap));			\
     StgPAP_n_args(new_pap) = HALF_W_(n_args + n);		\
     StgPAP_fun(new_pap) = StgPAP_fun(pap);			\
     i = 0;							\
   for1##x:							\
     if (i < n_args) {						\
         StgPAP_payload(new_pap,i) = StgPAP_payload(pap,i);	\
	 i = i + 1;						\
	 goto for1##x;						\
     }								\
     i = 0;							\
   for2##x:							\
     if (i < n) {						\
	 StgPAP_payload(new_pap,n_args+i) = Sp(1+i);		\
         i = i + 1;						\
         goto for2##x;						\
     }								\
     R1 = new_pap;						\
     Sp_adj(n+1);						\
     jump %ENTRY_CODE(Sp(0));

// Jump to target, saving CCCS and restoring it on return
#if defined(PROFILING)
#define jump_SAVE_CCCS(target)                  \
    Sp(-1) = CCCS;                              \
    Sp(-2) = stg_restore_cccs_info;             \
    Sp_adj(-2);                                 \
    jump (target)
#else
#define jump_SAVE_CCCS(target) jump (target)
#endif

#endif /* APPLY_H */