aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/hipe/hipe_x86_gc.h
blob: e92e6ea7188e902c2c0a5fdf2dde9540717b7c3f (plain) (blame)
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
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
131
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
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2004-2016. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * %CopyrightEnd%
 */
/*
 * Stack walking helpers for native stack GC procedures.
 */
#ifndef HIPE_X86_GC_H
#define HIPE_X86_GC_H

#include "hipe_x86_asm.h"	/* for NR_ARG_REGS */

/* uncomment to simulate & test what the initial PowerPC port will do */
/* #define SKIP_YOUNGEST_FRAME */

struct nstack_walk_state {
#ifdef SKIP_YOUNGEST_FRAME
    const struct hipe_sdesc *sdesc0;	/* .sdesc0 must be a pointer rvalue */
#else
    struct hipe_sdesc sdesc0[1];	/* .sdesc0 must be a pointer rvalue */
#endif
};

static inline int nstack_walk_init_check(const Process *p)
{
#ifdef SKIP_YOUNGEST_FRAME
    if (!p->hipe.nsp || p->hipe.nsp == p->hipe.nstend)
	return 0;
#endif
    return 1;
}

static inline Eterm *nstack_walk_nsp_begin(const Process *p)
{
#ifdef SKIP_YOUNGEST_FRAME
    unsigned int nstkarity = p->hipe.narity - NR_ARG_REGS;
    if ((int)nstkarity < 0)
	nstkarity = 0;
    return p->hipe.nsp + 1 + nstkarity;
#else
    return p->hipe.nsp;
#endif
}

static inline const struct hipe_sdesc*
nstack_walk_init_sdesc(const Process *p, struct nstack_walk_state *state)
{
#ifdef SKIP_YOUNGEST_FRAME
    const struct hipe_sdesc *sdesc = hipe_find_sdesc(p->hipe.nsp[0]);
    state->sdesc0 = sdesc;
    return sdesc;
#else
    state->sdesc0[0].fsize = 0;
    state->sdesc0[0].has_exnra = 0;
    state->sdesc0[0].stk_nargs = (p->hipe.narity < NR_ARG_REGS ? 0 :
                                  p->hipe.narity - NR_ARG_REGS);
    state->sdesc0[0].livebits[0] = 0;
    state->sdesc0[0].m_aix = 0;
    state->sdesc0[0].f_aix = atom_val(am_undefined);
    state->sdesc0[0].a     = 0;
    /* XXX: this appears to prevent a gcc-4.1.1 bug on x86 */
    __asm__ __volatile__("" : : "m"(*state) : "memory");
    return &state->sdesc0[0];
#endif
}

static inline const struct hipe_sdesc*
nstack_walk_init_sdesc_ignore_trap(const Process *p,
				   struct nstack_walk_state *state)
{
#ifdef SKIP_YOUNGEST_FRAME
    unsigned long ra = p->hipe.nsp[0];
    const struct hipe_sdesc *sdesc;
    if (ra == (unsigned long)nbif_stack_trap_ra)
	ra = (unsigned long)p->hipe.ngra;
    sdesc = hipe_find_sdesc(ra);
    state->sdesc0 = sdesc;
    return sdesc;
#else
    return nstack_walk_init_sdesc(p, state);
#endif
}

static inline void nstack_walk_update_trap(Process *p, const struct hipe_sdesc *sdesc0)
{
#ifdef SKIP_YOUNGEST_FRAME
    Eterm *nsp = p->hipe.nsp;
    p->hipe.nsp = nstack_walk_nsp_begin(p);
    hipe_update_stack_trap(p, sdesc0);
    p->hipe.nsp = nsp;
#else
    hipe_update_stack_trap(p, sdesc0);
#endif
}

static inline Eterm *nstack_walk_nsp_end(const Process *p)
{
    return p->hipe.nstend;
}

static inline void nstack_walk_kill_trap(Process *p, Eterm *nsp_end)
{
    /* remove gray/white boundary trap */
    for (;;) {
	--nsp_end;
	if (nsp_end[0] == (unsigned long)nbif_stack_trap_ra) {
	    nsp_end[0] = (unsigned long)p->hipe.ngra;
	    break;
	}
    }
}

static inline int nstack_walk_gray_passed_black(const Eterm *gray, const Eterm *black)
{
    return gray > black;
}

static inline int nstack_walk_nsp_reached_end(const Eterm *nsp, const Eterm *nsp_end)
{
    return nsp >= nsp_end;
}

static inline unsigned int nstack_walk_frame_size(const struct hipe_sdesc *sdesc)
{
    return sdesc_fsize(sdesc) + 1 + sdesc_arity(sdesc);
}

static inline Eterm *nstack_walk_frame_index(Eterm *nsp, unsigned int i)
{
    return &nsp[i];
}

static inline unsigned long
nstack_walk_frame_ra(const Eterm *nsp, const struct hipe_sdesc *sdesc)
{
    return nsp[sdesc_fsize(sdesc)];
}

static inline Eterm *nstack_walk_next_frame(Eterm *nsp, unsigned int sdesc_size)
{
    return nsp + sdesc_size;
}

#endif /* HIPE_X86_GC_H */