0
|
1
|
|
2 /* Digital Mars DMDScript source code.
|
|
3 * Copyright (c) 2000-2002 by Chromium Communications
|
|
4 * D version Copyright (c) 2004-2006 by Digital Mars
|
|
5 * All Rights Reserved
|
|
6 * written by Walter Bright
|
|
7 * www.digitalmars.com
|
|
8 * Use at your own risk. There is no warranty, express or implied.
|
|
9 * License for redistribution is by the GNU General Public License in gpl.txt.
|
|
10 *
|
|
11 * A binary, non-exclusive license for commercial use can be
|
|
12 * purchased from www.digitalmars.com/dscript/buy.html.
|
|
13 *
|
|
14 * DMDScript is implemented in the D Programming Language,
|
|
15 * www.digitalmars.com/d/
|
|
16 *
|
|
17 * For a C++ implementation of DMDScript, including COM support,
|
|
18 * see www.digitalmars.com/dscript/cppscript.html.
|
|
19 */
|
|
20
|
|
21
|
|
22 module dmdscript.irstate;
|
|
23
|
|
24 import std.c.stdarg;
|
|
25 import std.c.stdlib;
|
|
26 import std.c.string;
|
|
27 import std.outbuffer;
|
|
28 import std.gc;
|
|
29
|
|
30 import dmdscript.script;
|
|
31 import dmdscript.statement;
|
|
32 import dmdscript.opcodes;
|
|
33 import dmdscript.ir;
|
|
34 import dmdscript.identifier;
|
|
35
|
|
36 // The state of the interpreter machine as seen by the code generator, not
|
|
37 // the interpreter.
|
|
38
|
|
39 struct IRstate
|
|
40 {
|
|
41 OutBuffer codebuf; // accumulate code here
|
|
42 Statement breakTarget; // current statement that 'break' applies to
|
|
43 Statement continueTarget; // current statement that 'continue' applies to
|
|
44 ScopeStatement scopeContext; // current ScopeStatement we're inside
|
|
45 uint[] fixups;
|
|
46
|
|
47 //void next(); // close out current Block, and start a new one
|
|
48
|
|
49 uint locali = 1; // leave location 0 as our "null"
|
|
50 uint nlocals = 1;
|
|
51
|
|
52 void ctor()
|
|
53 {
|
|
54 codebuf = new OutBuffer();
|
|
55 }
|
|
56
|
|
57 void validate()
|
|
58 {
|
|
59 assert(codebuf.offset <= codebuf.data.length);
|
|
60 if (codebuf.data.length > std.gc.capacity(codebuf.data.ptr))
|
|
61 printf("ptr %p, length %d, capacity %d\n", codebuf.data.ptr, codebuf.data.length, std.gc.capacity(codebuf.data.ptr));
|
|
62 assert(codebuf.data.length <= std.gc.capacity(codebuf.data.ptr));
|
|
63 for (uint u = 0; u < codebuf.offset;)
|
|
64 {
|
|
65 IR* code = cast(IR*)(codebuf.data.ptr + u);
|
|
66 assert(code.opcode < IRMAX);
|
|
67 u += IR.size(code.opcode) * 4;
|
|
68 }
|
|
69 }
|
|
70
|
|
71 /**********************************
|
|
72 * Allocate a block of local variables, and return an
|
|
73 * index to them.
|
|
74 */
|
|
75
|
|
76 uint alloc(uint nlocals)
|
|
77 {
|
|
78 uint n;
|
|
79
|
|
80 n = locali;
|
|
81 locali += nlocals;
|
|
82 if (locali > this.nlocals)
|
|
83 this.nlocals = locali;
|
|
84 assert(n);
|
|
85 return n * INDEX_FACTOR;
|
|
86 }
|
|
87
|
|
88 /****************************************
|
|
89 * Release this block of n locals starting at local.
|
|
90 */
|
|
91
|
|
92 void release(uint local, uint n)
|
|
93 {
|
|
94 /+
|
|
95 local /= INDEX_FACTOR;
|
|
96 if (local + n == locali)
|
|
97 locali = local;
|
|
98 +/
|
|
99 }
|
|
100
|
|
101 uint mark()
|
|
102 {
|
|
103 return locali;
|
|
104 }
|
|
105
|
|
106 void release(uint i)
|
|
107 {
|
|
108 //locali = i;
|
|
109 }
|
|
110
|
|
111 static uint combine(uint loc, uint opcode)
|
|
112 {
|
|
113 return (loc << 16) | opcode;
|
|
114 }
|
|
115
|
|
116 /***************************************
|
|
117 * Generate code.
|
|
118 */
|
|
119
|
|
120 void gen0(Loc loc, uint opcode)
|
|
121 {
|
|
122 codebuf.write(combine(loc, opcode));
|
|
123 }
|
|
124
|
|
125 void gen1(Loc loc, uint opcode, uint arg)
|
|
126 {
|
|
127 codebuf.reserve(2 * uint.sizeof);
|
|
128 version (all)
|
|
129 {
|
|
130 // Inline ourselves for speed (compiler doesn't do a good job)
|
|
131 uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset);
|
|
132 codebuf.offset += 2 * uint.sizeof;
|
|
133 data[0] = combine(loc, opcode);
|
|
134 data[1] = arg;
|
|
135 }
|
|
136 else
|
|
137 {
|
|
138 codebuf.write4n(combine(loc, opcode));
|
|
139 codebuf.write4n(arg);
|
|
140 }
|
|
141 }
|
|
142
|
|
143 void gen2(Loc loc, uint opcode, uint arg1, uint arg2)
|
|
144 {
|
|
145 codebuf.reserve(3 * uint.sizeof);
|
|
146 version (all)
|
|
147 {
|
|
148 // Inline ourselves for speed (compiler doesn't do a good job)
|
|
149 uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset);
|
|
150 codebuf.offset += 3 * uint.sizeof;
|
|
151 data[0] = combine(loc, opcode);
|
|
152 data[1] = arg1;
|
|
153 data[2] = arg2;
|
|
154 }
|
|
155 else
|
|
156 {
|
|
157 codebuf.write4n(combine(loc, opcode));
|
|
158 codebuf.write4n(arg1);
|
|
159 codebuf.write4n(arg2);
|
|
160 }
|
|
161 }
|
|
162
|
|
163 void gen3(Loc loc, uint opcode, uint arg1, uint arg2, uint arg3)
|
|
164 {
|
|
165 codebuf.reserve(4 * uint.sizeof);
|
|
166 version (all)
|
|
167 {
|
|
168 // Inline ourselves for speed (compiler doesn't do a good job)
|
|
169 uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset);
|
|
170 codebuf.offset += 4 * uint.sizeof;
|
|
171 data[0] = combine(loc, opcode);
|
|
172 data[1] = arg1;
|
|
173 data[2] = arg2;
|
|
174 data[3] = arg3;
|
|
175 }
|
|
176 else
|
|
177 {
|
|
178 codebuf.write4n(combine(loc, opcode));
|
|
179 codebuf.write4n(arg1);
|
|
180 codebuf.write4n(arg2);
|
|
181 codebuf.write4n(arg3);
|
|
182 }
|
|
183 }
|
|
184
|
|
185 void gen4(Loc loc, uint opcode, uint arg1, uint arg2, uint arg3, uint arg4)
|
|
186 {
|
|
187 codebuf.reserve(5 * uint.sizeof);
|
|
188 version (all)
|
|
189 {
|
|
190 // Inline ourselves for speed (compiler doesn't do a good job)
|
|
191 uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset);
|
|
192 codebuf.offset += 5 * uint.sizeof;
|
|
193 data[0] = combine(loc, opcode);
|
|
194 data[1] = arg1;
|
|
195 data[2] = arg2;
|
|
196 data[3] = arg3;
|
|
197 data[4] = arg4;
|
|
198 }
|
|
199 else
|
|
200 {
|
|
201 codebuf.write4n(combine(loc, opcode));
|
|
202 codebuf.write4n(arg1);
|
|
203 codebuf.write4n(arg2);
|
|
204 codebuf.write4n(arg3);
|
|
205 codebuf.write4n(arg4);
|
|
206 }
|
|
207 }
|
|
208
|
|
209 void gen(Loc loc, uint opcode, uint argc, ...)
|
|
210 {
|
|
211 codebuf.reserve((1 + argc) * uint.sizeof);
|
|
212 codebuf.write(combine(loc, opcode));
|
|
213 for (uint i = 1; i <= argc; i++)
|
|
214 {
|
|
215 codebuf.write(va_arg!(uint)(_argptr));
|
|
216 }
|
|
217 }
|
|
218
|
|
219 void pops(uint npops)
|
|
220 {
|
|
221 while (npops--)
|
|
222 gen0(0, IRpop);
|
|
223 }
|
|
224
|
|
225 /******************************
|
|
226 * Get the current "instruction pointer"
|
|
227 */
|
|
228
|
|
229 uint getIP()
|
|
230 {
|
|
231 if (!codebuf)
|
|
232 return 0;
|
|
233 return codebuf.offset / 4;
|
|
234 }
|
|
235
|
|
236 /******************************
|
|
237 * Patch a value into the existing codebuf.
|
|
238 */
|
|
239
|
|
240 void patchJmp(uint index, uint value)
|
|
241 {
|
|
242 assert((index + 1) * 4 < codebuf.offset);
|
|
243 (cast(uint *)(codebuf.data))[index + 1] = value - index;
|
|
244 }
|
|
245
|
|
246 /*******************************
|
|
247 * Add this IP to list of jump instructions to patch.
|
|
248 */
|
|
249
|
|
250 void addFixup(uint index)
|
|
251 {
|
|
252 fixups ~= index;
|
|
253 }
|
|
254
|
|
255 /*******************************
|
|
256 * Go through the list of fixups and patch them.
|
|
257 */
|
|
258
|
|
259 void doFixups()
|
|
260 {
|
|
261 uint i;
|
|
262 uint index;
|
|
263 uint value;
|
|
264 Statement s;
|
|
265
|
|
266 for (i = 0; i < fixups.length; i++)
|
|
267 {
|
|
268 index = fixups[i];
|
|
269 assert((index + 1) * 4 < codebuf.offset);
|
|
270 s = (cast(Statement *)codebuf.data)[index + 1];
|
|
271 value = s.getTarget();
|
|
272 patchJmp(index, value);
|
|
273 }
|
|
274 }
|
|
275
|
|
276
|
|
277 void optimize()
|
|
278 {
|
|
279 // Determine the length of the code array
|
|
280 IR *c;
|
|
281 IR *c2;
|
|
282 IR *code;
|
|
283 uint length;
|
|
284 uint i;
|
|
285
|
|
286 code = cast(IR *) codebuf.data;
|
|
287 for (c = code; c.opcode != IRend; c += IR.size(c.opcode))
|
|
288 { }
|
|
289 length = c - code + 1;
|
|
290
|
|
291 // Allocate a bit vector for the array
|
|
292 bit[] b = new bit[length];
|
|
293
|
|
294 // Set bit for each target of a jump
|
|
295 for (c = code; c.opcode != IRend; c += IR.size(c.opcode))
|
|
296 {
|
|
297 switch (c.opcode)
|
|
298 {
|
|
299 case IRjf:
|
|
300 case IRjt:
|
|
301 case IRjfb:
|
|
302 case IRjtb:
|
|
303 case IRjmp:
|
|
304 case IRjlt:
|
|
305 case IRjle:
|
|
306 case IRjltc:
|
|
307 case IRjlec:
|
|
308 case IRtrycatch:
|
|
309 case IRtryfinally:
|
|
310 //writef("set %d\n", (c - code) + (c + 1).offset);
|
|
311 b[(c - code) + (c + 1).offset] = true;
|
|
312 break;
|
|
313 default:
|
|
314 break;
|
|
315 }
|
|
316 }
|
|
317
|
|
318 // Allocate array of IR contents for locals.
|
|
319 IR*[] local;
|
|
320 IR*[] p1 = null;
|
|
321
|
|
322 // Allocate on stack for smaller arrays
|
|
323 IR** plocals;
|
|
324 if (nlocals < 128)
|
|
325 plocals = cast(IR **)alloca(nlocals * local[0].sizeof);
|
|
326
|
|
327 if (plocals)
|
|
328 { local = plocals[0 .. nlocals];
|
|
329 local[] = null;
|
|
330 }
|
|
331 else
|
|
332 { p1 = new IR*[nlocals];
|
|
333 local = p1;
|
|
334 }
|
|
335
|
|
336 // Optimize
|
|
337 for (c = code; c.opcode != IRend; c += IR.size(c.opcode))
|
|
338 {
|
|
339 uint offset = (c - code);
|
|
340
|
|
341 if (b[offset]) // if target of jump
|
|
342 {
|
|
343 // Reset contents of locals
|
|
344 local[] = null;
|
|
345 }
|
|
346
|
|
347 switch (c.opcode)
|
|
348 {
|
|
349 case IRnop:
|
|
350 break;
|
|
351
|
|
352 case IRnumber:
|
|
353 case IRstring:
|
|
354 case IRboolean:
|
|
355 local[(c + 1).index / INDEX_FACTOR] = c;
|
|
356 break;
|
|
357
|
|
358 case IRadd:
|
|
359 case IRsub:
|
|
360 case IRcle:
|
|
361 local[(c + 1).index / INDEX_FACTOR] = c;
|
|
362 break;
|
|
363
|
|
364 case IRputthis:
|
|
365 local[(c + 1).index / INDEX_FACTOR] = c;
|
|
366 goto Lreset;
|
|
367
|
|
368 case IRputscope:
|
|
369 local[(c + 1).index / INDEX_FACTOR] = c;
|
|
370 break;
|
|
371
|
|
372 case IRgetscope:
|
|
373 {
|
|
374 Identifier* cs = (c + 2).id;
|
|
375 IR *cimax = null;
|
|
376 for (i = nlocals; i--; )
|
|
377 {
|
|
378 IR *ci = local[i];
|
|
379 if (ci &&
|
|
380 (ci.opcode == IRgetscope || ci.opcode == IRputscope) &&
|
|
381 (ci + 2).id.value.string == cs.value.string
|
|
382 )
|
|
383 {
|
|
384 if (cimax)
|
|
385 {
|
|
386 if (cimax < ci)
|
|
387 cimax = ci; // select most recent instruction
|
|
388 }
|
|
389 else
|
|
390 cimax = ci;
|
|
391 }
|
|
392 }
|
|
393 if (1 && cimax)
|
|
394 {
|
|
395 //writef("IRgetscope . IRmov %d, %d\n", (c + 1).index, (cimax + 1).index);
|
|
396 c.opcode = IRmov;
|
|
397 (c + 2).index = (cimax + 1).index;
|
|
398 local[(c + 1).index / INDEX_FACTOR] = cimax;
|
|
399 }
|
|
400 else
|
|
401 local[(c + 1).index / INDEX_FACTOR] = c;
|
|
402 break;
|
|
403 }
|
|
404
|
|
405 case IRnew:
|
|
406 local[(c + 1).index / INDEX_FACTOR] = c;
|
|
407 goto Lreset;
|
|
408
|
|
409 case IRcallscope:
|
|
410 case IRputcall:
|
|
411 case IRputcalls:
|
|
412 case IRputcallscope:
|
|
413 case IRputcallv:
|
|
414 case IRcallv:
|
|
415 local[(c + 1).index / INDEX_FACTOR] = c;
|
|
416 goto Lreset;
|
|
417
|
|
418 case IRmov:
|
|
419 local[(c + 1).index / INDEX_FACTOR] = local[(c + 2).index / INDEX_FACTOR];
|
|
420 break;
|
|
421
|
|
422 case IRput:
|
|
423 case IRpostincscope:
|
|
424 case IRaddassscope:
|
|
425 goto Lreset;
|
|
426
|
|
427 case IRjf:
|
|
428 case IRjfb:
|
|
429 case IRjtb:
|
|
430 case IRjmp:
|
|
431 case IRjt:
|
|
432 case IRret:
|
|
433 case IRjlt:
|
|
434 case IRjle:
|
|
435 case IRjltc:
|
|
436 case IRjlec:
|
|
437 break;
|
|
438
|
|
439 default:
|
|
440 Lreset:
|
|
441 // Reset contents of locals
|
|
442 local[] = null;
|
|
443 break;
|
|
444 }
|
|
445 }
|
|
446
|
|
447 delete p1;
|
|
448
|
|
449 //return;
|
|
450 // Remove all IRnop's
|
|
451 for (c = code; c.opcode != IRend; )
|
|
452 {
|
|
453 uint offset;
|
|
454 uint o;
|
|
455 uint c2off;
|
|
456
|
|
457 if (c.opcode == IRnop)
|
|
458 {
|
|
459 offset = (c - code);
|
|
460 for (c2 = code; c2.opcode != IRend; c2 += IR.size(c2.opcode))
|
|
461 {
|
|
462 switch (c2.opcode)
|
|
463 {
|
|
464 case IRjf:
|
|
465 case IRjt:
|
|
466 case IRjfb:
|
|
467 case IRjtb:
|
|
468 case IRjmp:
|
|
469 case IRjlt:
|
|
470 case IRjle:
|
|
471 case IRjltc:
|
|
472 case IRjlec:
|
|
473 case IRnextscope:
|
|
474 case IRtryfinally:
|
|
475 case IRtrycatch:
|
|
476 c2off = c2 - code;
|
|
477 o = c2off + (c2 + 1).offset;
|
|
478 if (c2off <= offset && offset < o)
|
|
479 (c2 + 1).offset--;
|
|
480 else if (c2off > offset && o <= offset)
|
|
481 (c2 + 1).offset++;
|
|
482 break;
|
|
483 /+
|
|
484 case IRtrycatch:
|
|
485 o = (c2 + 1).offset;
|
|
486 if (offset < o)
|
|
487 (c2 + 1).offset--;
|
|
488 break;
|
|
489 +/
|
|
490 default:
|
|
491 continue;
|
|
492 }
|
|
493 }
|
|
494
|
|
495 length--;
|
|
496 memmove(c, c + 1, (length - offset) * uint.sizeof);
|
|
497 }
|
|
498 else
|
|
499 c += IR.size(c.opcode);
|
|
500 }
|
|
501 }
|
|
502 }
|