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 | |
57 | MalStkPtr |
58 | newGlobalStack(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 | |
69 | MalStkPtr |
70 | reallocGlobalStack(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 | */ |
94 | void |
95 | freeStack(MalStkPtr stk) |
96 | { |
97 | if (stk != NULL) { |
98 | clearStack(stk); |
99 | GDKfree(stk); |
100 | } |
101 | } |
102 | |
103 | void |
104 | clearStack(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 | |