aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/hipe/hipe_stack.h
blob: 81f2e53dbc555a76485ddb2072a1892a67d18ad8 (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
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2001-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%
 */


#ifndef HIPE_STACK_H
#define HIPE_STACK_H

#include "hipe_arch.h"

/*
 * Stack descriptors.
 */

#include <stddef.h>	/* offsetof() */

struct hipe_sdesc {
    struct {
	unsigned long hvalue;	/* return address */
	struct hipe_sdesc *next;	/* hash collision chain */
    } bucket;
    unsigned int fsize : 23;    /* frame size */
    unsigned int has_exnra : 1; /* exn handler presence flag */
    unsigned int arity : 8;
#ifdef DEBUG
    Eterm dbg_M, dbg_F;
    unsigned dbg_A;
#endif
    unsigned int livebits[1]; /* size depends on arch & data in summary field */
};

struct hipe_sdesc_with_exnra {
    unsigned long exnra;
    struct hipe_sdesc sdesc;
};

static __inline__ unsigned int sdesc_fsize(const struct hipe_sdesc *sdesc)
{
    return sdesc->fsize;
}

static __inline__ unsigned int sdesc_arity(const struct hipe_sdesc *sdesc)
{
    return sdesc->arity;
}

static __inline__ unsigned long sdesc_exnra(const struct hipe_sdesc *sdesc)
{
    if (sdesc->has_exnra) {
	const char *tmp;
	tmp = (const char*)sdesc - offsetof(struct hipe_sdesc_with_exnra, sdesc);
	return ((const struct hipe_sdesc_with_exnra*)tmp)->exnra;
    }
    return 0;
}

struct hipe_sdesc_table {
    unsigned int log2size;
    unsigned int mask;		/* INV: mask == (1 << log2size)-1 */
    unsigned int used;
    struct hipe_sdesc **bucket;
};
extern struct hipe_sdesc_table hipe_sdesc_table;

extern struct hipe_sdesc *hipe_put_sdesc(struct hipe_sdesc*);
extern void hipe_init_sdesc_table(struct hipe_sdesc*);
extern struct hipe_sdesc *hipe_decode_sdesc(Eterm);

#if !defined(__GNUC__) || (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
#define __builtin_expect(x, expected_value) (x)
#endif
#define likely(x)	__builtin_expect((x),1)
#define unlikely(x)	__builtin_expect((x),0)

static __inline__ const struct hipe_sdesc *hipe_find_sdesc(unsigned long ra)
{
    unsigned int i = (ra >> HIPE_RA_LSR_COUNT) & hipe_sdesc_table.mask;
    const struct hipe_sdesc *sdesc = hipe_sdesc_table.bucket[i];
    if (likely(sdesc->bucket.hvalue == ra))
	return sdesc;
    do {
	sdesc = sdesc->bucket.next;
    } while (sdesc->bucket.hvalue != ra);
    return sdesc;
}

AEXTERN(void,nbif_stack_trap_ra,(void));

extern void hipe_print_nstack(Process*);
extern void hipe_find_handler(Process*);
extern void (*hipe_handle_stack_trap(Process*))(void);
extern void hipe_update_stack_trap(Process*, const struct hipe_sdesc*);
extern int hipe_fill_stacktrace(Process*, int, Eterm**);

#if 0 && defined(HIPE_NSTACK_GROWS_UP)
#define hipe_nstack_start(p)	((p)->hipe.nstack)
#define hipe_nstack_used(p)	((p)->hipe.nsp - (p)->hipe.nstack)
#define hipe_nstack_avail(p)	((p)->hipe.nstend - (p)->hipe.nsp)
#endif
#if defined(HIPE_NSTACK_GROWS_DOWN)
#define hipe_nstack_start(p)	((p)->hipe.nsp)
#define hipe_nstack_used(p)	((p)->hipe.nstend - (p)->hipe.nsp)
#define hipe_nstack_avail(p)	((unsigned)((p)->hipe.nsp - (p)->hipe.nstack))
#endif

/* ensure that at least nwords words are available on the native stack */
static __inline__ void hipe_check_nstack(Process *p, unsigned nwords)
{
    extern void hipe_inc_nstack(Process *p);

    while (hipe_nstack_avail(p) < nwords)
	hipe_inc_nstack(p);
}

/*
 * GC support procedures
 */
extern Eterm *fullsweep_nstack(Process *p, Eterm *n_htop);
extern void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop);
extern Eterm *sweep_literals_nstack(Process *p, Eterm *n_htop, char *area,
				    Uint area_size);
extern int nstack_any_heap_ref_ptrs(Process *, char* mod_start, Uint mod_size);

#endif /* HIPE_STACK_H */