1 #include <stdlib.h>
2 #include "lib/mlrutil.h"
3 #include "lib/mlr_globals.h"
4 #include "containers/local_stack.h"
5 
6 // ================================================================
_local_stack_alloc(int size,int ephemeral)7 static local_stack_frame_t* _local_stack_alloc(int size, int ephemeral) {
8 	local_stack_frame_t* pframe = mlr_malloc_or_die(sizeof(local_stack_frame_t));
9 
10 	pframe->in_use = FALSE;
11 	pframe->ephemeral = ephemeral;
12 	pframe->size = size;
13 	pframe->subframe_base = 0;
14 	pframe->pvars = mlr_malloc_or_die(size * sizeof(local_stack_frame_entry_t));
15 	for (int i = 0; i < size; i++) {
16 		local_stack_frame_entry_t* pentry = &pframe->pvars[i];
17 		pentry->xvalue = mlhmmv_xvalue_wrap_terminal(mv_absent());
18 		pentry->name = NULL;
19 		// Any type can be written here, unless otherwise specified by a typed definition
20 		pentry->type_mask = TYPE_MASK_ANY;
21 	}
22 
23 	return pframe;
24 }
25 
26 // ----------------------------------------------------------------
local_stack_frame_alloc(int size)27 local_stack_frame_t* local_stack_frame_alloc(int size) {
28 	return _local_stack_alloc(size, FALSE);
29 }
30 
31 // ----------------------------------------------------------------
local_stack_frame_free(local_stack_frame_t * pframe)32 void local_stack_frame_free(local_stack_frame_t* pframe) {
33 	if (pframe == NULL)
34 		return;
35 	for (int i = 0; i < pframe->size; i++) {
36 		mlhmmv_xvalue_free(&pframe->pvars[i].xvalue);
37 	}
38 	free(pframe->pvars);
39 	free(pframe);
40 }
41 
42 // ----------------------------------------------------------------
local_stack_frame_enter(local_stack_frame_t * pframe)43 local_stack_frame_t* local_stack_frame_enter(local_stack_frame_t* pframe) {
44 	if (!pframe->in_use) {
45 		pframe->in_use = TRUE;
46 		LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME NON-EPH ENTER %p %d\n", pframe, pframe->size));
47 		return pframe;
48 	} else {
49 		local_stack_frame_t* prv = _local_stack_alloc(pframe->size, TRUE);
50 		LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME EPH ENTER %p/%p %d\n", pframe, prv, pframe->size));
51 		prv->in_use = TRUE;
52 		return prv;
53 	}
54 }
55 
56 // ----------------------------------------------------------------
local_stack_frame_exit(local_stack_frame_t * pframe)57 void local_stack_frame_exit (local_stack_frame_t* pframe) {
58 	MLR_INTERNAL_CODING_ERROR_UNLESS(mlhmmv_xvalue_is_absent_and_nonterminal(&pframe->pvars[0].xvalue));
59 	if (!pframe->ephemeral) {
60 		pframe->in_use = FALSE;
61 		LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME NON-EPH EXIT %p %d\n", pframe, pframe->size));
62 	} else {
63 		local_stack_frame_free(pframe);
64 		LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME EPH EXIT %p %d\n", pframe, pframe->size));
65 	}
66 }
67 
68 // ================================================================
local_stack_alloc()69 local_stack_t* local_stack_alloc() {
70 	local_stack_t* pstack = mlr_malloc_or_die(sizeof(local_stack_t));
71 
72 	pstack->pframes = sllv_alloc();
73 
74 	return pstack;
75 }
76 
77 // ----------------------------------------------------------------
local_stack_free(local_stack_t * pstack)78 void local_stack_free(local_stack_t* pstack) {
79 	if (pstack == NULL)
80 		return;
81 	for (sllve_t* pe = pstack->pframes->phead; pe != NULL; pe = pe->pnext) {
82 		local_stack_frame_free(pe->pvvalue);
83 	}
84 	sllv_free(pstack->pframes);
85 	free(pstack);
86 }
87 
88 // ----------------------------------------------------------------
local_stack_push(local_stack_t * pstack,local_stack_frame_t * pframe)89 void local_stack_push(local_stack_t* pstack, local_stack_frame_t* pframe) {
90 	sllv_push(pstack->pframes, pframe);
91 }
92 
local_stack_pop(local_stack_t * pstack)93 local_stack_frame_t* local_stack_pop(local_stack_t* pstack) {
94 	return sllv_pop(pstack->pframes);
95 }
96 
97 // ----------------------------------------------------------------
local_stack_frame_ref_terminal_from_indexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,sllmv_t * pmvkeys)98 mv_t local_stack_frame_ref_terminal_from_indexed(local_stack_frame_t* pframe,
99 	int vardef_frame_relative_index, sllmv_t* pmvkeys)
100 {
101 	LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p GET %d\n", pframe, vardef_frame_relative_index));
102 	LOCAL_STACK_BOUNDS_CHECK(pframe, "GET", FALSE, vardef_frame_relative_index);
103 
104 	local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
105 	mlhmmv_xvalue_t* pbase_xval = &pentry->xvalue;
106 
107 	if (!(TYPE_MASK_MAP & pentry->type_mask)) {
108 		local_stack_frame_throw_type_mismatch_for_read(pentry);
109 	}
110 
111 #ifdef LOCAL_STACK_TRACE_ENABLE
112 	if (pbase_xval == NULL) {
113 		printf("VALUE IS NULL\n");
114 	} else if (pbase_xval->is_terminal) {
115 		char* s = mv_alloc_format_val(&pbase_xval->terminal_mlrval);
116 		printf("VALUE IS %s\n", s);
117 		free(s);
118 	} else if (pbase_xval->pnext_level == NULL) {
119 		LOCAL_STACK_TRACE(printf("VALUE IS EMPTY\n"));
120 	} else {
121 		printf("VALUE IS:\n");
122 		printf("PTR IS %p\n", pbase_xval->pnext_level);
123 		mlhmmv_level_print_stacked(pbase_xval->pnext_level, 0, TRUE, TRUE, "", stdout);
124 	}
125 #endif
126 
127 	// xxx this is a mess; clean it up.
128 	int error = 0;
129 	// Maybe null
130 	mlhmmv_xvalue_t* pxval;
131 	if (pmvkeys == NULL || pmvkeys->length == 0) {
132 		pxval = pbase_xval;
133 	} else {
134 		if (pbase_xval->is_terminal) {
135 			return mv_absent();
136 		} else {
137 			pxval = mlhmmv_level_look_up_and_ref_xvalue(pbase_xval->pnext_level, pmvkeys, &error);
138 		}
139 	}
140 	if (pxval != NULL && pxval->is_terminal) {
141 		return pxval->terminal_mlrval;
142 	} else {
143 		return mv_absent();
144 	}
145 }
146 
147 // ----------------------------------------------------------------
local_stack_frame_ref_extended_from_indexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,sllmv_t * pmvkeys)148 mlhmmv_xvalue_t* local_stack_frame_ref_extended_from_indexed(local_stack_frame_t* pframe,
149 	int vardef_frame_relative_index, sllmv_t* pmvkeys)
150 {
151 	LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p GET %d\n", pframe, vardef_frame_relative_index));
152 	LOCAL_STACK_BOUNDS_CHECK(pframe, "GET", FALSE, vardef_frame_relative_index);
153 
154 	local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
155 	mlhmmv_xvalue_t* pmvalue = &pentry->xvalue;
156 
157 	if (!(TYPE_MASK_MAP & pentry->type_mask)) {
158 		local_stack_frame_throw_type_mismatch_for_read(pentry);
159 	}
160 
161 #ifdef LOCAL_STACK_TRACE_ENABLE
162 	if (pmvalue == NULL) {
163 		printf("VALUE IS NULL\n");
164 	} else if (pmvalue->is_terminal) {
165 		char* s = mv_alloc_format_val(&pmvalue->terminal_mlrval);
166 		printf("VALUE IS %s\n", s);
167 		free(s);
168 	} else if (pmvalue->pnext_level == NULL) {
169 		LOCAL_STACK_TRACE(printf("VALUE IS EMPTY\n"));
170 	} else {
171 		printf("VALUE IS:\n");
172 		printf("PTR IS %p\n", pmvalue->pnext_level);
173 		mlhmmv_level_print_stacked(pmvalue->pnext_level, 0, TRUE, TRUE, "", stdout);
174 	}
175 #endif
176 
177 	if (pmvkeys == NULL) { // base-level access
178 		return pmvalue;
179 	} else {
180 		int error = 0;
181 		// Maybe null
182 		return mlhmmv_level_look_up_and_ref_xvalue(pmvalue->pnext_level, pmvkeys, &error);
183 	}
184 }
185 
186 // ----------------------------------------------------------------
local_stack_frame_define_terminal(local_stack_frame_t * pframe,char * variable_name,int vardef_frame_relative_index,int type_mask,mv_t val)187 void local_stack_frame_define_terminal(local_stack_frame_t* pframe, char* variable_name,
188 	int vardef_frame_relative_index, int type_mask, mv_t val)
189 {
190 	LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
191 	LOCAL_STACK_BOUNDS_CHECK(pframe, "DEFINE", TRUE, vardef_frame_relative_index);
192 	local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
193 
194 	pentry->name = variable_name; // no strdup, for performance -- caller must ensure extent
195 	pentry->type_mask = type_mask;
196 
197 	if (!(type_mask_from_mv(&val) & pentry->type_mask)) {
198 		local_stack_frame_throw_type_mismatch_for_write(pentry, &val);
199 	}
200 
201 	mlhmmv_xvalue_free(&pentry->xvalue);
202 
203 	if (mv_is_absent(&val)) {
204 		mv_free(&val); // xxx doc ownership semantics at header file
205 	} else {
206 		pentry->xvalue = mlhmmv_xvalue_wrap_terminal(val); // xxx deep-copy?
207 	}
208 }
209 
210 // ----------------------------------------------------------------
local_stack_frame_define_extended(local_stack_frame_t * pframe,char * variable_name,int vardef_frame_relative_index,int type_mask,mlhmmv_xvalue_t xval)211 void local_stack_frame_define_extended(local_stack_frame_t* pframe, char* variable_name,
212 	int vardef_frame_relative_index, int type_mask, mlhmmv_xvalue_t xval)
213 {
214 	LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
215 	LOCAL_STACK_BOUNDS_CHECK(pframe, "ASSIGN", TRUE, vardef_frame_relative_index);
216 	local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
217 
218 	pentry->name = variable_name; // no strdup, for performance -- caller must ensure extent
219 	pentry->type_mask = type_mask;
220 
221 	if (xval.is_terminal) {
222 		if (!(type_mask_from_mv(&xval.terminal_mlrval) & pentry->type_mask)) {
223 			local_stack_frame_throw_type_mismatch_for_write(pentry, &xval.terminal_mlrval);
224 		}
225 	} else {
226 		if (!(TYPE_MASK_MAP & pentry->type_mask)) {
227 			local_stack_frame_throw_type_mismatch_for_write(pentry, &xval.terminal_mlrval);
228 		}
229 	}
230 
231 	if (!mlhmmv_xvalue_is_absent_and_nonterminal(&xval)) {
232 		mlhmmv_xvalue_free(&pentry->xvalue);
233 		pentry->xvalue = xval;
234 	}
235 }
236 
237 // ----------------------------------------------------------------
local_stack_frame_assign_terminal_indexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,sllmv_t * pmvkeys,mv_t terminal_value)238 void local_stack_frame_assign_terminal_indexed(local_stack_frame_t* pframe,
239 	int vardef_frame_relative_index, sllmv_t* pmvkeys,
240 	mv_t terminal_value)
241 {
242 	LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
243 	LOCAL_STACK_BOUNDS_CHECK(pframe, "ASSIGN", TRUE, vardef_frame_relative_index);
244 	local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
245 
246 	if (!(TYPE_MASK_MAP & pentry->type_mask)) {
247 		local_stack_frame_throw_type_mismatch_for_write(pentry, &terminal_value);
248 	}
249 
250 	mlhmmv_xvalue_t* pmvalue = &pentry->xvalue;
251 
252 	if (pmvalue->is_terminal) {
253 		mv_free(&pmvalue->terminal_mlrval);
254 		*pmvalue = mlhmmv_xvalue_alloc_empty_map();
255 	}
256 	mlhmmv_level_put_terminal(pmvalue->pnext_level, pmvkeys->phead, &terminal_value);
257 
258 	LOCAL_STACK_TRACE(printf("VALUE IS:\n"));
259 	LOCAL_STACK_TRACE(mlhmmv_level_print_stacked(pmvalue->pnext_level, 0, TRUE, TRUE, "", stdout));
260 }
261 
262 // ----------------------------------------------------------------
local_stack_frame_assign_extended_nonindexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,mlhmmv_xvalue_t xval)263 void local_stack_frame_assign_extended_nonindexed(local_stack_frame_t* pframe,
264 	int vardef_frame_relative_index, mlhmmv_xvalue_t xval)
265 {
266 	LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
267 	LOCAL_STACK_BOUNDS_CHECK(pframe, "ASSIGN", TRUE, vardef_frame_relative_index);
268 	local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
269 
270 	if (xval.is_terminal) {
271 		if (!(type_mask_from_mv(&xval.terminal_mlrval) & pentry->type_mask)) {
272 			local_stack_frame_throw_type_mismatch_for_write(pentry, &xval.terminal_mlrval);
273 		}
274 	} else {
275 		if (!(TYPE_MASK_MAP & pentry->type_mask)) {
276 			local_stack_frame_throw_type_mismatch_for_write(pentry, &xval.terminal_mlrval);
277 		}
278 	}
279 
280 	mlhmmv_xvalue_free(&pentry->xvalue);
281 	pentry->xvalue = xval;
282 }
283 
284 // ----------------------------------------------------------------
local_stack_frame_assign_extended_indexed(local_stack_frame_t * pframe,int vardef_frame_relative_index,sllmv_t * pmvkeys,mlhmmv_xvalue_t new_value)285 void local_stack_frame_assign_extended_indexed(local_stack_frame_t* pframe,
286 	int vardef_frame_relative_index, sllmv_t* pmvkeys,
287 	mlhmmv_xvalue_t new_value)
288 {
289 	LOCAL_STACK_TRACE(printf("LOCAL STACK FRAME %p SET %d\n", pframe, vardef_frame_relative_index));
290 	LOCAL_STACK_BOUNDS_CHECK(pframe, "ASSIGN", TRUE, vardef_frame_relative_index);
291 	local_stack_frame_entry_t* pentry = &pframe->pvars[vardef_frame_relative_index];
292 
293 	if (!(TYPE_MASK_MAP & pentry->type_mask)) {
294 		local_stack_frame_throw_type_xmismatch_for_write(pentry, &new_value);
295 	}
296 
297 	mlhmmv_xvalue_t* pmvalue = &pentry->xvalue;
298 
299 	if (pmvalue->is_terminal) {
300 		mv_free(&pmvalue->terminal_mlrval);
301 		*pmvalue = mlhmmv_xvalue_alloc_empty_map();
302 	}
303 	mlhmmv_level_put_xvalue(pmvalue->pnext_level, pmvkeys->phead, &new_value);
304 
305 	LOCAL_STACK_TRACE(printf("VALUE IS:\n"));
306 	LOCAL_STACK_TRACE(mlhmmv_level_print_stacked(pmvalue->pnext_level, 0, TRUE, TRUE, "", stdout));
307 }
308 
309 // ----------------------------------------------------------------
310 static int local_stack_bounds_check_announce_first_call = TRUE;
311 
local_stack_bounds_check(local_stack_frame_t * pframe,char * op,int set,int vardef_frame_relative_index)312 void local_stack_bounds_check(local_stack_frame_t* pframe, char* op, int set, int vardef_frame_relative_index) {
313 	if (local_stack_bounds_check_announce_first_call) {
314 		fprintf(stderr, "%s: local-stack bounds-checking is enabled\n", MLR_GLOBALS.bargv0);
315 		local_stack_bounds_check_announce_first_call = FALSE;
316 	}
317 	if (vardef_frame_relative_index < 0) {
318 		fprintf(stderr, "OP=%s FRAME=%p IDX=%d/%d STACK UNDERFLOW\n",
319 			op, pframe, vardef_frame_relative_index, pframe->size);
320 		exit(1);
321 	}
322 	if (set && vardef_frame_relative_index == 0) {
323 		fprintf(stderr, "OP=%s FRAME=%p IDX=%d/%d ABSENT WRITE\n",
324 			op, pframe, vardef_frame_relative_index, pframe->size);
325 		exit(1);
326 	}
327 	if (vardef_frame_relative_index >= pframe->size) {
328 		fprintf(stderr, "OP=%s FRAME=%p IDX=%d/%d STACK OVERFLOW\n",
329 			op, pframe, vardef_frame_relative_index, pframe->size);
330 		exit(1);
331 	}
332 }
333 
334 // ----------------------------------------------------------------
local_stack_frame_throw_type_mismatch_for_write(local_stack_frame_entry_t * pentry,mv_t * pval)335 void local_stack_frame_throw_type_mismatch_for_write(local_stack_frame_entry_t* pentry, mv_t* pval) {
336 	MLR_INTERNAL_CODING_ERROR_IF(pentry->name == NULL);
337 	char* sval = mv_alloc_format_val_quoting_strings(pval);
338 	fprintf(stderr, "%s: %s type assertion for variable %s unmet by value %s with type %s.\n",
339 		MLR_GLOBALS.bargv0, type_mask_to_desc(pentry->type_mask), pentry->name,
340 		sval, mt_describe_type_simple(pval->type));
341 	free(sval);
342 	exit(1);
343 }
344 
local_stack_frame_throw_type_xmismatch_for_write(local_stack_frame_entry_t * pentry,mlhmmv_xvalue_t * pxval)345 void local_stack_frame_throw_type_xmismatch_for_write(local_stack_frame_entry_t* pentry, mlhmmv_xvalue_t* pxval) {
346 	MLR_INTERNAL_CODING_ERROR_IF(pentry->name == NULL);
347 	char* sval = mv_alloc_format_val_quoting_strings(&pxval->terminal_mlrval); // xxx temp -- maybe not terminal
348 	fprintf(stderr, "%s: %s type assertion for variable %s unmet by value %s with type %s.\n",
349 		MLR_GLOBALS.bargv0, type_mask_to_desc(pentry->type_mask), pentry->name,
350 		sval, mlhmmv_xvalue_describe_type_simple(pxval));
351 	free(sval);
352 	exit(1);
353 }
354 
355 // ----------------------------------------------------------------
local_stack_frame_throw_type_mismatch_for_read(local_stack_frame_entry_t * pentry)356 void local_stack_frame_throw_type_mismatch_for_read(local_stack_frame_entry_t* pentry) {
357 	MLR_INTERNAL_CODING_ERROR_IF(pentry->name == NULL);
358 	fprintf(stderr, "%s: %s type assertion for variable %s unmet on read.\n",
359 		MLR_GLOBALS.bargv0, type_mask_to_desc(pentry->type_mask), pentry->name);
360 	exit(1);
361 }
362 
local_stack_frame_throw_type_xmismatch_for_read(local_stack_frame_entry_t * pentry)363 void local_stack_frame_throw_type_xmismatch_for_read(local_stack_frame_entry_t* pentry) {
364 	MLR_INTERNAL_CODING_ERROR_IF(pentry->name == NULL);
365 	fprintf(stderr, "%s: %s type assertion for variable %s unmet on read.\n",
366 		MLR_GLOBALS.bargv0, type_mask_to_desc(pentry->type_mask), pentry->name);
367 	exit(1);
368 }
369