aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/beam_catches.c
blob: 406ef1db5f505544d3f56cc68456638b0cb08e3d (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
/*
 * %CopyrightBegin%
 *
 * Copyright Ericsson AB 2000-2011. All Rights Reserved.
 *
 * The contents of this file are subject to the Erlang Public License,
 * Version 1.1, (the "License"); you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * Erlang Public License along with this software. If not, it can be
 * retrieved online at http://www.erlang.org/.
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * %CopyrightEnd%
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "sys.h"
#include "beam_catches.h"
#include "global.h"

/* R14B04 has about 380 catches when starting erlang */
#define DEFAULT_TABSIZE (1024)
typedef struct {
    BeamInstr *cp;
    unsigned cdr;
} beam_catch_t;

static int free_list;
static unsigned high_mark;
static unsigned tabsize;
static beam_catch_t *beam_catches;

void beam_catches_init(void)
{
    tabsize   = DEFAULT_TABSIZE;
    free_list = -1;
    high_mark = 0;

    beam_catches = erts_alloc(ERTS_ALC_T_CODE, sizeof(beam_catch_t)*DEFAULT_TABSIZE);
}

unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr)
{
    int i;

    /*
     * Allocate from free_list while it is non-empty.
     * If free_list is empty, allocate at high_mark.
     *
     * This avoids the need to initialise the free list in
     * beam_catches_init(), which would cost O(TABSIZ) time.
     */
    if( free_list >= 0 ) {
	i = free_list;
	free_list = beam_catches[i].cdr;
    } else if( high_mark < tabsize ) {
	i = high_mark;
	high_mark++;
    } else {
	/* No free slots and table is full: realloc table */
	tabsize      = 2*tabsize;
	beam_catches = erts_realloc(ERTS_ALC_T_CODE, beam_catches, sizeof(beam_catch_t)*tabsize);
	i = high_mark;
	high_mark++;
    }

    beam_catches[i].cp  = cp;
    beam_catches[i].cdr = cdr;

    return i;
}

BeamInstr *beam_catches_car(unsigned i)
{
    if( i >= tabsize ) {
	erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i);
    }
    return beam_catches[i].cp;
}

void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes)
{
    unsigned i, cdr;

    for(i = head; i != (unsigned)-1;) {
	if( i >= tabsize ) {
	    erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i);
	}
	if( (char*)beam_catches[i].cp - (char*)code >= code_bytes ) {
	    erl_exit(1,
		    "beam_catches_delmod: item %#x has cp %#lx which is not "
		    "in module's range [%#lx,%#lx[\r\n",
		    i, (long)beam_catches[i].cp,
		    (long)code, (long)((char*)code + code_bytes));
	}
	beam_catches[i].cp = 0;
	cdr = beam_catches[i].cdr;
	beam_catches[i].cdr = free_list;
	free_list = i;
	i = cdr;
    }
}