Small typo fixes (harmless).
[BearSSL] / T0 / WordInterpreted.cs
1 /*
2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 using System;
26 using System.Collections.Generic;
27
28 /*
29 * The implementation for interpreted words.
30 */
31
32 class WordInterpreted : Word {
33
34 /*
35 * Get the number of local variables for this word.
36 */
37 internal int NumLocals {
38 get; private set;
39 }
40
41 /*
42 * Get the sequence of opcodes for this word.
43 */
44 internal Opcode[] Code {
45 get; private set;
46 }
47
48 string[] toResolve;
49
50 internal WordInterpreted(T0Comp owner, string name,
51 int numLocals, Opcode[] code, string[] toResolve)
52 : base(owner, name)
53 {
54 this.Code = code;
55 this.toResolve = toResolve;
56 NumLocals = numLocals;
57 }
58
59 internal override void Resolve()
60 {
61 if (toResolve == null) {
62 return;
63 }
64 for (int i = 0; i < toResolve.Length; i ++) {
65 string tt = toResolve[i];
66 if (tt == null) {
67 continue;
68 }
69 Code[i].ResolveTarget(TC.Lookup(tt));
70 }
71 toResolve = null;
72 }
73
74 internal override void Run(CPU cpu)
75 {
76 Resolve();
77 cpu.Enter(Code, NumLocals);
78 }
79
80 internal override List<Word> GetReferences()
81 {
82 Resolve();
83 List<Word> r = new List<Word>();
84 foreach (Opcode op in Code) {
85 Word w = op.GetReference(TC);
86 if (w != null) {
87 r.Add(w);
88 }
89 }
90 return r;
91 }
92
93 internal override List<ConstData> GetDataBlocks()
94 {
95 Resolve();
96 List<ConstData> r = new List<ConstData>();
97 foreach (Opcode op in Code) {
98 ConstData cd = op.GetDataBlock(TC);
99 if (cd != null) {
100 r.Add(cd);
101 }
102 }
103 return r;
104 }
105
106 internal override void GenerateCodeElements(List<CodeElement> dst)
107 {
108 Resolve();
109 int n = Code.Length;
110 CodeElement[] gcode = new CodeElement[n];
111 for (int i = 0; i < n; i ++) {
112 gcode[i] = Code[i].ToCodeElement();
113 }
114 for (int i = 0; i < n; i ++) {
115 Code[i].FixUp(gcode, i);
116 }
117 dst.Add(new CodeElementUInt((uint)NumLocals));
118 for (int i = 0; i < n; i ++) {
119 dst.Add(gcode[i]);
120 }
121 }
122
123 int flowAnalysis;
124 int maxDataStack;
125 int maxReturnStack;
126
127 bool MergeSA(int[] sa, int j, int c)
128 {
129 if (sa[j] == Int32.MinValue) {
130 sa[j] = c;
131 return true;
132 } else if (sa[j] != c) {
133 throw new Exception(string.Format(
134 "In word '{0}', offset {1}:"
135 + " stack action mismatch ({2} / {3})",
136 Name, j, sa[j], c));
137 } else {
138 return false;
139 }
140 }
141
142 internal override void AnalyseFlow()
143 {
144 switch (flowAnalysis) {
145 case 0:
146 break;
147 case 1:
148 return;
149 default:
150 throw new Exception("recursive call detected in '"
151 + Name + "'");
152 }
153 flowAnalysis = 2;
154 int n = Code.Length;
155 int[] sa = new int[n];
156 for (int i = 0; i < n; i ++) {
157 sa[i] = Int32.MinValue;
158 }
159 sa[0] = 0;
160 int[] toExplore = new int[n];
161 int tX = 0, tY = 0;
162 int off = 0;
163
164 int exitSA = Int32.MinValue;
165 int mds = 0;
166 int mrs = 0;
167
168 int maxDepth = 0;
169
170 for (;;) {
171 Opcode op = Code[off];
172 bool mft = op.MayFallThrough;
173 int c = sa[off];
174 int a;
175 if (op is OpcodeCall) {
176 Word w = op.GetReference(TC);
177 w.AnalyseFlow();
178 SType se = w.StackEffect;
179 if (!se.IsKnown) {
180 throw new Exception(string.Format(
181 "call from '{0}' to '{1}'"
182 + " with unknown stack effect",
183 Name, w.Name));
184 }
185 if (se.NoExit) {
186 mft = false;
187 a = 0;
188 } else {
189 a = se.DataOut - se.DataIn;
190 }
191 mds = Math.Max(mds, c + w.MaxDataStack);
192 mrs = Math.Max(mrs, w.MaxReturnStack);
193 maxDepth = Math.Min(maxDepth, c - se.DataIn);
194 } else if (op is OpcodeRet) {
195 if (exitSA == Int32.MinValue) {
196 exitSA = c;
197 } else if (exitSA != c) {
198 throw new Exception(string.Format(
199 "'{0}': exit stack action"
200 + " mismatch: {1} / {2}"
201 + " (offset {3})",
202 Name, exitSA, c, off));
203 }
204 a = 0;
205 } else {
206 a = op.StackAction;
207 mds = Math.Max(mds, c + a);
208 }
209 c += a;
210 maxDepth = Math.Min(maxDepth, c);
211
212 int j = op.JumpDisp;
213 if (j != 0) {
214 j += off + 1;
215 toExplore[tY ++] = j;
216 MergeSA(sa, j, c);
217 }
218 off ++;
219 if (!mft || !MergeSA(sa, off, c)) {
220 if (tX < tY) {
221 off = toExplore[tX ++];
222 } else {
223 break;
224 }
225 }
226 }
227
228 maxDataStack = mds;
229 maxReturnStack = 1 + NumLocals + mrs;
230
231 /*
232 * TODO: see about this warning. Usage of a 'fail'
233 * word (that does not exit) within a 'case..endcase'
234 * structure will make an unreachable opcode. In a future
235 * version we might want to automatically remove dead
236 * opcodes.
237 for (int i = 0; i < n; i ++) {
238 if (sa[i] == Int32.MinValue) {
239 Console.WriteLine("warning: word '{0}',"
240 + " offset {1}: unreachable opcode",
241 Name, i);
242 continue;
243 }
244 }
245 */
246
247 SType computed;
248 if (exitSA == Int32.MinValue) {
249 computed = new SType(-maxDepth, -1);
250 } else {
251 computed = new SType(-maxDepth, -maxDepth + exitSA);
252 }
253
254 if (StackEffect.IsKnown) {
255 if (!computed.IsSubOf(StackEffect)) {
256 throw new Exception(string.Format(
257 "word '{0}':"
258 + " computed stack effect {1}"
259 + " does not match declared {2}",
260 Name, computed.ToString(),
261 StackEffect.ToString()));
262 }
263 } else {
264 StackEffect = computed;
265 }
266
267 flowAnalysis = 1;
268 }
269
270 internal override int MaxDataStack {
271 get {
272 AnalyseFlow();
273 return maxDataStack;
274 }
275 }
276
277 internal override int MaxReturnStack {
278 get {
279 AnalyseFlow();
280 return maxReturnStack;
281 }
282 }
283 }