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 setVariable(long offset, Object val, boolean isGlobal) {
157 if (isGlobal) {
158 globals[(int) offset] = val;
159 return val;
160 } else {
161 locals[(int) offset] = val;
162 return val;
163 }
164 }
165
166
167 void removeVariable(long offset, boolean isGlobal) {
168 if (isGlobal) {
169 globals[(int) offset] = null;
170 } else {
171 locals[(int) offset] = null;
172 }
173 }
174
175 void setFilelistVariable(int offset, Object value) {
176 globals[offset] = value;
177 }
178
179 void pushFrame(long numFormalParams, int positionIdx) {
180 localsStack.push(locals == null ? NULL_LOCALS_SENTINEL : locals);
181 locals = new Object[(int) numFormalParams];
182 returnIndexes.push(positionIdx);
183 }
184
185
186 int popFrame() {
187 Object[] restoredLocals = localsStack.pop();
188 locals = restoredLocals == NULL_LOCALS_SENTINEL ? null : restoredLocals;
189 return returnIndexes.pop();
190 }
191
192 void popAllFrames() {
193 for (int i = localsStack.size(); i > 0; i--) {
194 Object[] restoredLocals = localsStack.pop();
195 locals = restoredLocals == NULL_LOCALS_SENTINEL ? null : restoredLocals;
196 returnIndexes.pop();
197 }
198 }
199
200 private Object returnValue;
201
202 void setReturnValue(Object obj) {
203 returnValue = obj;
204 }
205
206 Object getReturnValue() {
207 Object retval;
208 if (returnValue == null) {
209 retval = BLANK;
210 } else {
211 retval = returnValue;
212 }
213 returnValue = null;
214 return retval;
215 }
216
217 private void setGlobalLayoutMetadata(int numGlobals, Map<String, Integer> offsetsByName) {
218 List<String> namesByOffset = new ArrayList<String>(Collections.nCopies(numGlobals, (String) null));
219 if (offsetsByName != null) {
220 for (Map.Entry<String, Integer> entry : offsetsByName.entrySet()) {
221 int offset = entry.getValue().intValue();
222 if (offset >= 0 && offset < numGlobals) {
223 namesByOffset.set(offset, entry.getKey());
224 }
225 }
226 }
227 setGlobalLayoutMetadata(namesByOffset);
228 }
229
230 private void setGlobalLayoutMetadata(List<String> namesByOffset) {
231 globalNamesByOffset = new ArrayList<String>(namesByOffset);
232 Map<String, Integer> offsetsByName = new LinkedHashMap<String, Integer>();
233 for (int i = 0; i < namesByOffset.size(); i++) {
234 String name = namesByOffset.get(i);
235 if (name != null) {
236 offsetsByName.put(name, Integer.valueOf(i));
237 }
238 }
239 globalOffsetsByName = offsetsByName;
240 }
241 }