1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2000-2016. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include "sys.h"
25 #include "beam_catches.h"
26 #include "global.h"
27
28 /* R14B04 has about 380 catches when starting erlang */
29 #define DEFAULT_TABSIZE (1024)
30 typedef struct {
31 ErtsCodePtr cp;
32 unsigned cdr;
33 } beam_catch_t;
34
35 #ifdef DEBUG
36 # define IF_DEBUG(x) x
37 #else
38 # define IF_DEBUG(x)
39 #endif
40
41 struct bc_pool {
42 int free_list;
43 unsigned high_mark;
44 unsigned tabsize;
45 beam_catch_t *beam_catches;
46 /*
47 * Note that the 'beam_catches' area is shared by pools. Used slots
48 * are readonly as long as the module is not purgable. The free-list is
49 * protected by the code_ix lock.
50 */
51
52 IF_DEBUG(int is_staging;)
53 };
54
55 static struct bc_pool bccix[ERTS_NUM_CODE_IX];
56
beam_catches_init(void)57 void beam_catches_init(void)
58 {
59 int i;
60
61 bccix[0].tabsize = DEFAULT_TABSIZE;
62 bccix[0].free_list = -1;
63 bccix[0].high_mark = 0;
64 bccix[0].beam_catches = erts_alloc(ERTS_ALC_T_CATCHES,
65 sizeof(beam_catch_t)*DEFAULT_TABSIZE);
66 IF_DEBUG(bccix[0].is_staging = 0);
67 for (i=1; i<ERTS_NUM_CODE_IX; i++) {
68 bccix[i] = bccix[i-1];
69 }
70 /* For initial load: */
71 IF_DEBUG(bccix[erts_staging_code_ix()].is_staging = 1);
72 }
73
74
gc_old_vec(beam_catch_t * vec)75 static void gc_old_vec(beam_catch_t* vec)
76 {
77 int i;
78 for (i=0; i<ERTS_NUM_CODE_IX; i++) {
79 if (bccix[i].beam_catches == vec) {
80 return;
81 }
82 }
83 erts_free(ERTS_ALC_T_CATCHES, vec);
84 }
85
86
beam_catches_start_staging(void)87 void beam_catches_start_staging(void)
88 {
89 ErtsCodeIndex dst = erts_staging_code_ix();
90 ErtsCodeIndex src = erts_active_code_ix();
91 beam_catch_t* prev_vec = bccix[dst].beam_catches;
92
93 ASSERT(!bccix[src].is_staging && !bccix[dst].is_staging);
94
95 bccix[dst] = bccix[src];
96 gc_old_vec(prev_vec);
97 IF_DEBUG(bccix[dst].is_staging = 1);
98 }
99
beam_catches_end_staging(int commit)100 void beam_catches_end_staging(int commit)
101 {
102 IF_DEBUG(bccix[erts_staging_code_ix()].is_staging = 0);
103 }
104
beam_catches_cons(ErtsCodePtr cp,unsigned cdr,ErtsCodePtr ** cppp)105 unsigned beam_catches_cons(ErtsCodePtr cp, unsigned cdr, ErtsCodePtr **cppp)
106 {
107 int i;
108 struct bc_pool* p = &bccix[erts_staging_code_ix()];
109
110 ASSERT(p->is_staging);
111 /*
112 * Allocate from free_list while it is non-empty.
113 * If free_list is empty, allocate at high_mark.
114 */
115 if (p->free_list >= 0) {
116 i = p->free_list;
117 p->free_list = p->beam_catches[i].cdr;
118 }
119 else {
120 if (p->high_mark >= p->tabsize) {
121 /* No free slots and table is full: realloc table */
122 beam_catch_t* prev_vec = p->beam_catches;
123 unsigned newsize = p->tabsize*2;
124
125 p->beam_catches = erts_alloc(ERTS_ALC_T_CATCHES,
126 newsize*sizeof(beam_catch_t));
127 sys_memcpy(p->beam_catches, prev_vec,
128 p->tabsize*sizeof(beam_catch_t));
129 gc_old_vec(prev_vec);
130 p->tabsize = newsize;
131 }
132 i = p->high_mark++;
133 }
134
135 p->beam_catches[i].cp = cp;
136 p->beam_catches[i].cdr = cdr;
137 if (cppp) {
138 *cppp = &p->beam_catches[i].cp;
139 }
140
141 return i;
142 }
143
beam_catches_car(unsigned i)144 ErtsCodePtr beam_catches_car(unsigned i)
145 {
146 struct bc_pool* p = &bccix[erts_active_code_ix()];
147
148 if (i >= p->tabsize ) {
149 erts_exit(ERTS_ERROR_EXIT, "beam_catches_delmod: index %#x is out of range\r\n", i);
150 }
151 return p->beam_catches[i].cp;
152 }
153
beam_catches_car_staging(unsigned i)154 ErtsCodePtr beam_catches_car_staging(unsigned i)
155 {
156 struct bc_pool* p = &bccix[erts_staging_code_ix()];
157
158 if (i >= p->tabsize ) {
159 erts_exit(ERTS_ERROR_EXIT, "beam_catches_delmod: index %#x is out of range\r\n", i);
160 }
161 return p->beam_catches[i].cp;
162 }
163
beam_catches_delmod(unsigned head,const BeamCodeHeader * hdr,unsigned code_bytes,ErtsCodeIndex code_ix)164 void beam_catches_delmod(unsigned head,
165 const BeamCodeHeader *hdr,
166 unsigned code_bytes,
167 ErtsCodeIndex code_ix)
168 {
169 struct bc_pool* p = &bccix[code_ix];
170 const char *code_start;
171 unsigned i, cdr;
172
173 code_start = (const char*)hdr;
174
175 ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_staging_code_ix()].is_staging);
176
177 for(i = head; i != (unsigned)-1;) {
178 const char *catch_addr = (char*)p->beam_catches[i].cp;
179
180 if (i >= p->tabsize) {
181 erts_exit(ERTS_ERROR_EXIT,
182 "beam_catches_delmod: index %#x is out of range\r\n", i);
183 }
184
185 if (!ErtsInArea(catch_addr, code_start, code_bytes)) {
186 erts_exit(ERTS_ERROR_EXIT,
187 "beam_catches_delmod: item %#x has cp %p which is not "
188 "in module's range [%p,%p[\r\n",
189 i,
190 p->beam_catches[i].cp,
191 code_start,
192 &code_start[code_bytes]);
193 }
194
195 p->beam_catches[i].cp = NULL;
196 cdr = p->beam_catches[i].cdr;
197 p->beam_catches[i].cdr = p->free_list;
198 p->free_list = i;
199 i = cdr;
200 }
201 }
202