1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * (author) M. L. Kersten
11 * @node Stack Management, The MAL Optimizer, Garbage Collection, The MAL Interpreter
12 * @+ MAL runtime stack
13 * The runtime context of a MAL procedure is allocated on the runtime stack
14 * of the corresponding interpreter.
15 * Access to the elements in the stack are through index offsets,
16 * determined during MAL procedure parsing.
17 *
18 * The scope administration for MAL procedures is
19 * decoupled from their actual runtime behavior. This means we are
20 * more relaxed on space allocation, because the size is determined
21 * by the number of MAL procedure definitions instead of the runtime
22 * calling behavior. (See mal_interpreter for details on value stack
23 * management)
24 *
25 * The variable names and types are kept in the stack to ease debugging.
26 * The underlying string value need not be garbage collected.
27 * Runtime storage for variables are allocated on the stack of the
28 * interpreter thread. The physical stack is often limited in size,
29 * which calls for safeguarding their value and garbage collection before returning.
30 * A malicious procedure or implementation will lead to memory leakage.
31 *
32 * A system command (linked C-routine) may be interested in extending the
33 * stack. This is precluded, because it could interfere with the recursive
34 * calling sequence of procedures. To accommodate the (rare) case, the routine
35 * should issue an exception to be handled by the interpreter before retrying.
36 * All other errors are turned into an exception, followed by continuing
37 * at the exception handling block of the MAL procedure.
38 *
39 * The interpreter should be protected against physical stack overflow.
40 * The solution chosen is to maintain an incremental depth size.
41 * Once it exceeds a threshold, we call upon the kernel to
42 * ensure we are still within safe bounds.
43 */
44/*
45 * The clearStack operation throws away any space occupied by variables
46 * Freeing the stack itself is automatic upon return from the interpreter
47 * context. Since the stack is allocated and zeroed on the calling stack,
48 * it may happen that entries are never set to a real value.
49 * This can be recognized by the vtype component
50 */
51#include "monetdb_config.h"
52#include "mal_stack.h"
53#include "mal_exception.h"
54
55/* #define DEBUG_MAL_STACK*/
56
57MalStkPtr
58newGlobalStack(int size)
59{
60 MalStkPtr s;
61
62 s = (MalStkPtr) GDKzalloc(stackSize(size) + offsetof(MalStack, stk));
63 if (!s)
64 return NULL;
65 s->stksize = size;
66 return s;
67}
68
69MalStkPtr
70reallocGlobalStack(MalStkPtr old, int cnt)
71{
72 int k;
73 MalStkPtr s;
74
75 if (old->stksize > cnt)
76 return old;
77 k = ((cnt / STACKINCR) + 1) * STACKINCR;
78 s = newGlobalStack(k);
79 if (!s) {
80 return NULL;
81 }
82 memcpy(s, old, stackSize(old->stksize));
83 s->stksize = k;
84 GDKfree(old);
85 return s;
86}
87
88/*
89 * When you add a value to the stack, you should ensure that
90 * there is space left. It should only be used for global
91 * stack frames, because the others are allocated in the
92 * runtime stack.
93 */
94void
95freeStack(MalStkPtr stk)
96{
97 if (stk != NULL) {
98 clearStack(stk);
99 GDKfree(stk);
100 }
101}
102
103void
104clearStack(MalStkPtr s)
105{
106 ValPtr v;
107 int i;
108
109 if (!s) return;
110
111 i = s->stktop;
112
113 for (v = s->stk; i >= 0; i--, v++)
114 if (ATOMextern(v->vtype) && v->val.pval) {
115 GDKfree(v->val.pval);
116 v->vtype = 0;
117 v->val.pval = NULL;
118 } else if (BATatoms[v->vtype].atomUnfix) {
119 BATatoms[v->vtype].atomUnfix(VALget(v));
120 v->vtype = 0;
121 v->val.pval = NULL;
122 }
123 s->stkbot = 0;
124}
125
126