1 package io.jawk.backend;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import java.util.ArrayDeque;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.Deque;
30 import java.util.LinkedHashMap;
31 import java.util.List;
32 import java.util.Map;
33 import io.jawk.intermediate.UninitializedObject;
34
35
36
37
38 class RuntimeStack {
39
40 static final UninitializedObject BLANK = new UninitializedObject();
41 private static final Object[] NULL_LOCALS_SENTINEL = new Object[0];
42
43 private Object[] globals = null;
44 private List<String> globalNamesByOffset = Collections.emptyList();
45 private Map<String, Integer> globalOffsetsByName = Collections.emptyMap();
46 private Object[] locals = null;
47 private Deque<Object[]> localsStack = new ArrayDeque<Object[]>();
48 private Deque<Integer> returnIndexes = new ArrayDeque<Integer>();
49
50 @SuppressWarnings("unused")
51 public void dump() {
52 System.out.println("globals = " + Arrays.toString(globals));
53 System.out.println("globalNamesByOffset = " + globalNamesByOffset);
54 System.out.println("locals = " + Arrays.toString(locals));
55 System.out.println("localsStack = " + localsStack);
56 System.out.println("returnIndexes = " + returnIndexes);
57 }
58
59 Object[] getNumGlobals() {
60 return globals;
61 }
62
63 void reset() {
64 clearGlobals();
65 resetTransientState();
66 }
67
68 void clearGlobals() {
69 globals = null;
70 globalNamesByOffset = Collections.emptyList();
71 globalOffsetsByName = Collections.emptyMap();
72 }
73
74 void resetTransientState() {
75 locals = null;
76 localsStack.clear();
77 returnIndexes.clear();
78 returnValue = null;
79 }
80
81
82 void setNumGlobals(long l, Map<String, Integer> offsetsByName) {
83 globals = new Object[(int) l];
84 for (int i = 0; i < l; i++) {
85 globals[i] = null;
86 }
87 setGlobalLayoutMetadata((int) l, offsetsByName);
88
89
90 }
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 void rebindGlobals(List<String> namesByOffset) {
107 globals = new Object[namesByOffset.size()];
108 for (int i = 0; i < globals.length; i++) {
109 globals[i] = null;
110 }
111 setGlobalLayoutMetadata(namesByOffset);
112 }
113
114 Map<String, Object> snapshotGlobalVariables() {
115 Map<String, Object> snapshot = new LinkedHashMap<String, Object>();
116 if (globals == null) {
117 return snapshot;
118 }
119 for (int i = 0; i < globals.length && i < globalNamesByOffset.size(); i++) {
120 String name = globalNamesByOffset.get(i);
121 if (name != null) {
122 snapshot.put(name, globals[i]);
123 }
124 }
125 return snapshot;
126 }
127
128 boolean hasGlobalVariable(String name) {
129 return globalOffsetsByName.containsKey(name);
130 }
131
132 Object getGlobalVariable(String name) {
133 Integer offset = globalOffsetsByName.get(name);
134 return offset == null ? null : globals[offset.intValue()];
135 }
136
137 void setGlobalVariable(String name, Object value) {
138 Integer offset = globalOffsetsByName.get(name);
139 if (offset != null) {
140 globals[offset.intValue()] = value;
141 }
142 }
143
144 String getGlobalName(int offset) {
145 return offset >= 0 && offset < globalNamesByOffset.size() ? globalNamesByOffset.get(offset) : null;
146 }
147
148 Object getVariable(long offset, boolean isGlobal) {
149 if (isGlobal) {
150 return globals[(int) offset];
151 } else {
152 return locals[(int) offset];
153 }
154 }
155
156 Object[] getVariableFrame(boolean isGlobal) {
157 return isGlobal ? globals : locals;
158 }
159
160 int frameCount() {
161 return localsStack.size();
162 }
163
164 Object setVariable(long offset, Object val, boolean isGlobal) {
165 if (isGlobal) {
166 globals[(int) offset] = val;
167 return val;
168 } else {
169 locals[(int) offset] = val;
170 return val;
171 }
172 }
173
174
175 void removeVariable(long offset, boolean isGlobal) {
176 if (isGlobal) {
177 globals[(int) offset] = null;
178 } else {
179 locals[(int) offset] = null;
180 }
181 }
182
183 void setFilelistVariable(int offset, Object value) {
184 globals[offset] = value;
185 }
186
187 void pushFrame(long numFormalParams, int positionIdx) {
188 localsStack.push(locals == null ? NULL_LOCALS_SENTINEL : locals);
189 locals = new Object[(int) numFormalParams];
190 returnIndexes.push(positionIdx);
191 }
192
193
194 int popFrame() {
195 Object[] restoredLocals = localsStack.pop();
196 locals = restoredLocals == NULL_LOCALS_SENTINEL ? null : restoredLocals;
197 return returnIndexes.pop();
198 }
199
200 void popAllFrames() {
201 for (int i = localsStack.size(); i > 0; i--) {
202 Object[] restoredLocals = localsStack.pop();
203 locals = restoredLocals == NULL_LOCALS_SENTINEL ? null : restoredLocals;
204 returnIndexes.pop();
205 }
206 }
207
208 private Object returnValue;
209
210 void setReturnValue(Object obj) {
211 returnValue = obj;
212 }
213
214 Object getReturnValue() {
215 Object retval;
216 if (returnValue == null) {
217 retval = BLANK;
218 } else {
219 retval = returnValue;
220 }
221 returnValue = null;
222 return retval;
223 }
224
225 private void setGlobalLayoutMetadata(int numGlobals, Map<String, Integer> offsetsByName) {
226 List<String> namesByOffset = new ArrayList<String>(Collections.nCopies(numGlobals, (String) null));
227 if (offsetsByName != null) {
228 for (Map.Entry<String, Integer> entry : offsetsByName.entrySet()) {
229 int offset = entry.getValue().intValue();
230 if (offset >= 0 && offset < numGlobals) {
231 namesByOffset.set(offset, entry.getKey());
232 }
233 }
234 }
235 setGlobalLayoutMetadata(namesByOffset);
236 }
237
238 private void setGlobalLayoutMetadata(List<String> namesByOffset) {
239 globalNamesByOffset = new ArrayList<String>(namesByOffset);
240 Map<String, Integer> offsetsByName = new LinkedHashMap<String, Integer>();
241 for (int i = 0; i < namesByOffset.size(); i++) {
242 String name = namesByOffset.get(i);
243 if (name != null) {
244 offsetsByName.put(name, Integer.valueOf(i));
245 }
246 }
247 globalOffsetsByName = offsetsByName;
248 }
249 }