Mercurial > projects > dmdscript-tango
comparison dmdscript_tango/opcodes.d @ 0:55c2951c07be
initial, files origin, premoved tree
author | saaadel |
---|---|
date | Sun, 24 Jan 2010 12:34:47 +0200 |
parents | |
children | 8363a4bf6a8f |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:55c2951c07be |
---|---|
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.opcodes; | |
23 | |
24 import std.stdio; | |
25 import std.string; | |
26 | |
27 import dmdscript.script; | |
28 import dmdscript.dobject; | |
29 import dmdscript.statement; | |
30 import dmdscript.functiondefinition; | |
31 import dmdscript.value; | |
32 import dmdscript.iterator; | |
33 import dmdscript.scopex; | |
34 import dmdscript.identifier; | |
35 import dmdscript.ir; | |
36 import dmdscript.errmsgs; | |
37 import dmdscript.property; | |
38 import dmdscript.ddeclaredfunction; | |
39 import dmdscript.dfunction; | |
40 | |
41 //debug=VERIFY; // verify integrity of code | |
42 | |
43 version = SCOPECACHING; // turn scope caching on | |
44 //version = SCOPECACHE_LOG; // log statistics on it | |
45 | |
46 // Catch & Finally are "fake" Dobjects that sit in the scope | |
47 // chain to implement our exception handling context. | |
48 | |
49 class Catch : Dobject | |
50 { | |
51 // This is so scope_get() will skip over these objects | |
52 Value* Get(d_string PropertyName) { return null; } | |
53 Value* Get(d_string PropertyName, uint hash) { return null; } | |
54 | |
55 // This is so we can distinguish between a real Dobject | |
56 // and these fakers | |
57 d_string getTypeof() { return null; } | |
58 | |
59 uint offset; // offset of CatchBlock | |
60 d_string name; // catch identifier | |
61 | |
62 this(uint offset, d_string name) | |
63 { | |
64 super(null); | |
65 this.offset = offset; | |
66 this.name = name; | |
67 } | |
68 | |
69 int isCatch() { return true; } | |
70 } | |
71 | |
72 class Finally : Dobject | |
73 { | |
74 Value* Get(d_string PropertyName) { return null; } | |
75 Value* Get(d_string PropertyName, uint hash) { return null; } | |
76 d_string getTypeof() { return null; } | |
77 | |
78 IR *finallyblock; // code for FinallyBlock | |
79 | |
80 this(IR *finallyblock) | |
81 { | |
82 super(null); | |
83 this.finallyblock = finallyblock; | |
84 } | |
85 | |
86 int isFinally() { return true; } | |
87 } | |
88 | |
89 | |
90 /************************ | |
91 * Look for identifier in scope. | |
92 */ | |
93 | |
94 Value* scope_get(Dobject[] scopex, Identifier* id, Dobject *pthis) | |
95 { uint d; | |
96 Dobject o; | |
97 Value* v; | |
98 | |
99 //writef("scope_get: scope = %p, scope.data = %p\n", scopex, scopex.data); | |
100 //writefln("scope_get: scopex = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString()); | |
101 d = scopex.length; | |
102 for (;;) | |
103 { | |
104 if (!d) | |
105 { v = null; | |
106 *pthis = null; | |
107 break; | |
108 } | |
109 d--; | |
110 o = scopex[d]; | |
111 //writef("o = %x, hash = x%x, s = '%s'\n", o, hash, s); | |
112 v = o.Get(id); | |
113 if (v) | |
114 { *pthis = o; | |
115 break; | |
116 } | |
117 } | |
118 return v; | |
119 } | |
120 | |
121 Value* scope_get_lambda(Dobject[] scopex, Identifier* id, Dobject *pthis) | |
122 { uint d; | |
123 Dobject o; | |
124 Value* v; | |
125 | |
126 //writefln("scope_get_lambda: scope = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString()); | |
127 d = scopex.length; | |
128 for (;;) | |
129 { | |
130 if (!d) | |
131 { v = null; | |
132 *pthis = null; | |
133 break; | |
134 } | |
135 d--; | |
136 o = scopex[d]; | |
137 //printf("o = %p ", o); | |
138 //writefln("o = %s", o); | |
139 //printf("o = %x, hash = x%x, s = '%.*s'\n", o, hash, s); | |
140 //v = o.GetLambda(s, hash); | |
141 v = o.Get(id); | |
142 if (v) | |
143 { *pthis = o; | |
144 break; | |
145 } | |
146 } | |
147 //writefln("v = %x", cast(uint)cast(void*)v); | |
148 return v; | |
149 } | |
150 | |
151 Value* scope_get(Dobject[] scopex, Identifier* id) | |
152 { uint d; | |
153 Dobject o; | |
154 Value* v; | |
155 | |
156 //writefln("scope_get: scopex = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString()); | |
157 d = scopex.length; | |
158 // 1 is most common case for d | |
159 if (d == 1) | |
160 { | |
161 return scopex[0].Get(id); | |
162 } | |
163 for (;;) | |
164 { | |
165 if (!d) | |
166 { v = null; | |
167 break; | |
168 } | |
169 d--; | |
170 o = scopex[d]; | |
171 //writefln("\to = %s", o); | |
172 v = o.Get(id); | |
173 if (v) | |
174 break; | |
175 //writefln("\tnot found"); | |
176 } | |
177 return v; | |
178 } | |
179 | |
180 /************************************ | |
181 * Find last object in scopex, null if none. | |
182 */ | |
183 | |
184 Dobject scope_tos(Dobject[] scopex) | |
185 { uint d; | |
186 Dobject o; | |
187 | |
188 for (d = scopex.length; d;) | |
189 { | |
190 d--; | |
191 o = scopex[d]; | |
192 if (o.getTypeof() != null) // if not a Finally or a Catch | |
193 return o; | |
194 } | |
195 return null; | |
196 } | |
197 | |
198 /***************************************** | |
199 */ | |
200 | |
201 void PutValue(CallContext *cc, d_string s, Value* a) | |
202 { | |
203 // ECMA v3 8.7.2 | |
204 // Look for the object o in the scope chain. | |
205 // If we find it, put its value. | |
206 // If we don't find it, put it into the global object | |
207 | |
208 uint d; | |
209 uint hash; | |
210 Value* v; | |
211 Dobject o; | |
212 | |
213 d = cc.scopex.length; | |
214 if (d == cc.globalroot) | |
215 { | |
216 o = scope_tos(cc.scopex); | |
217 o.Put(s, a, 0); | |
218 return; | |
219 } | |
220 | |
221 hash = Value.calcHash(s); | |
222 | |
223 for (;; d--) | |
224 { | |
225 assert(d > 0); | |
226 o = cc.scopex[d - 1]; | |
227 if (d == cc.globalroot) | |
228 { | |
229 o.Put(s, a, 0); | |
230 return; | |
231 } | |
232 v = o.Get(s, hash); | |
233 if (v) | |
234 { | |
235 // Overwrite existing property with new one | |
236 o.Put(s, a, 0); | |
237 break; | |
238 } | |
239 } | |
240 } | |
241 | |
242 | |
243 void PutValue(CallContext *cc, Identifier* id, Value* a) | |
244 { | |
245 // ECMA v3 8.7.2 | |
246 // Look for the object o in the scope chain. | |
247 // If we find it, put its value. | |
248 // If we don't find it, put it into the global object | |
249 | |
250 uint d; | |
251 Value* v; | |
252 Dobject o; | |
253 | |
254 d = cc.scopex.length; | |
255 if (d == cc.globalroot) | |
256 { | |
257 o = scope_tos(cc.scopex); | |
258 } | |
259 else | |
260 { | |
261 for (;; d--) | |
262 { | |
263 assert(d > 0); | |
264 o = cc.scopex[d - 1]; | |
265 if (d == cc.globalroot) | |
266 break; | |
267 v = o.Get(id); | |
268 if (v) | |
269 { | |
270 // Overwrite existing property with new one | |
271 break; | |
272 } | |
273 } | |
274 } | |
275 o.Put(id, a, 0); | |
276 } | |
277 | |
278 | |
279 /***************************************** | |
280 * Helper function for Values that cannot be converted to Objects. | |
281 */ | |
282 | |
283 Value* cannotConvert(Value* b, int linnum) | |
284 { | |
285 ErrInfo errinfo; | |
286 | |
287 errinfo.linnum = linnum; | |
288 if (b.isUndefinedOrNull()) | |
289 { | |
290 b = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT4], | |
291 b.getType()); | |
292 } | |
293 else | |
294 { | |
295 b = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT2], | |
296 b.getType(), b.toString()); | |
297 } | |
298 return b; | |
299 } | |
300 | |
301 const uint INDEX_FACTOR = 16; // or 1 | |
302 | |
303 struct IR | |
304 { | |
305 union | |
306 { | |
307 struct | |
308 { | |
309 version (LittleEndian) | |
310 { | |
311 ubyte opcode; | |
312 ubyte padding; | |
313 ushort linnum; | |
314 } | |
315 else | |
316 { | |
317 ushort linnum; | |
318 ubyte padding; | |
319 ubyte opcode; | |
320 } | |
321 } | |
322 IR* code; | |
323 Value* value; | |
324 uint index; // index into local variable table | |
325 uint hash; // cached hash value | |
326 int offset; | |
327 Identifier* id; | |
328 d_boolean boolean; | |
329 Statement target; // used for backpatch fixups | |
330 Dobject object; | |
331 void* ptr; | |
332 } | |
333 | |
334 /**************************** | |
335 * This is the main interpreter loop. | |
336 */ | |
337 | |
338 static void *call(CallContext *cc, Dobject othis, | |
339 IR *code, Value* ret, Value* locals) | |
340 { Value* a; | |
341 Value* b; | |
342 Value* c; | |
343 Value* v; | |
344 Iterator *iter; | |
345 Identifier *id; | |
346 d_string s; | |
347 d_string s2; | |
348 d_number n; | |
349 d_boolean bo; | |
350 d_int32 i32; | |
351 d_uint32 u32; | |
352 d_boolean res; | |
353 tchar[] tx; | |
354 tchar[] ty; | |
355 Dobject o; | |
356 Dobject[] scopex; | |
357 uint dimsave; | |
358 uint offset; | |
359 Catch ca; | |
360 Finally f; | |
361 IR* codestart = code; | |
362 d_number inc; | |
363 | |
364 /*************************************** | |
365 * Cache for getscope's | |
366 */ | |
367 | |
368 version (SCOPECACHING) | |
369 { | |
370 struct ScopeCache | |
371 { | |
372 d_string s; | |
373 Value* v; // never null, and never from a Dcomobject | |
374 } | |
375 int si; | |
376 ScopeCache zero; | |
377 ScopeCache[16] scopecache; | |
378 version (SCOPECACHE_LOG) int scopecache_cnt = 0; | |
379 | |
380 uint SCOPECACHE_SI(tchar* s) { return (cast(uint)(s)) & 15; } | |
381 void SCOPECACHE_CLEAR() { scopecache[] = zero; } | |
382 } | |
383 else | |
384 { | |
385 uint SCOPECACHE_SI(d_string s) { return 0; } | |
386 void SCOPECACHE_CLEAR() { } | |
387 } | |
388 | |
389 version (all) | |
390 { | |
391 // Eliminate the scale factor of Value.sizeof by computing it at compile time | |
392 Value* GETa(IR* code) { return cast(Value*)(cast(void*)locals + (code + 1).index * (16 / INDEX_FACTOR)); } | |
393 Value* GETb(IR* code) { return cast(Value*)(cast(void*)locals + (code + 2).index * (16 / INDEX_FACTOR)); } | |
394 Value* GETc(IR* code) { return cast(Value*)(cast(void*)locals + (code + 3).index * (16 / INDEX_FACTOR)); } | |
395 Value* GETd(IR* code) { return cast(Value*)(cast(void*)locals + (code + 4).index * (16 / INDEX_FACTOR)); } | |
396 Value* GETe(IR* code) { return cast(Value*)(cast(void*)locals + (code + 5).index * (16 / INDEX_FACTOR)); } | |
397 } | |
398 else | |
399 { | |
400 Value* GETa(IR* code) { return &locals[(code + 1).index]; } | |
401 Value* GETb(IR* code) { return &locals[(code + 2).index]; } | |
402 Value* GETc(IR* code) { return &locals[(code + 3).index]; } | |
403 Value* GETd(IR* code) { return &locals[(code + 4).index]; } | |
404 Value* GETe(IR* code) { return &locals[(code + 5).index]; } | |
405 } | |
406 | |
407 uint GETlinnum(IR* code) { return code.linnum; } | |
408 | |
409 debug (VERIFY) uint checksum = IR.verify(__LINE__, code); | |
410 | |
411 version (none) | |
412 { | |
413 writef("+printfunc\n"); | |
414 printfunc(code); | |
415 writef("-printfunc\n"); | |
416 } | |
417 scopex = cc.scopex; | |
418 //printf("call: scope = %p, length = %d\n", scopex.ptr, scopex.length); | |
419 dimsave = scopex.length; | |
420 //if (logflag) | |
421 // writef("IR.call(othis = %p, code = %p, locals = %p)\n",othis,code,locals); | |
422 | |
423 debug | |
424 { | |
425 uint debug_scoperoot = cc.scoperoot; | |
426 uint debug_globalroot = cc.globalroot; | |
427 uint debug_scopedim = scopex.length; | |
428 uint debug_scopeallocdim = scopex.allocdim; | |
429 Dobject debug_global = cc.global; | |
430 Dobject debug_variable = cc.variable; | |
431 | |
432 void** debug_pscoperootdata = cast(void**)mem.malloc((void*).sizeof*debug_scoperoot); | |
433 void** debug_pglobalrootdata = cast(void**)mem.malloc((void*).sizeof*debug_globalroot); | |
434 | |
435 memcpy(debug_pscoperootdata, scopex.data, (void*).sizeof*debug_scoperoot); | |
436 memcpy(debug_pglobalrootdata, scopex.data, (void*).sizeof*debug_globalroot); | |
437 } | |
438 | |
439 assert(code); | |
440 //Value.copy(ret, &vundefined); | |
441 assert(othis); | |
442 | |
443 Lnext: | |
444 //writef("cc = %x, interrupt = %d\n", cc, cc.Interrupt); | |
445 if (cc.Interrupt) // see if script was interrupted | |
446 goto Linterrupt; | |
447 for (;;) | |
448 { | |
449 version (none) | |
450 { | |
451 writef("%2d:", code - codestart); | |
452 print(code - codestart, code); | |
453 } | |
454 | |
455 debug | |
456 { | |
457 assert(scopex == cc.scopex); | |
458 assert(debug_scoperoot == cc.scoperoot); | |
459 assert(debug_globalroot == cc.globalroot); | |
460 assert(debug_global == cc.global); | |
461 assert(debug_variable == cc.variable); | |
462 assert(scopex.length >= debug_scoperoot); | |
463 assert(scopex.length >= debug_globalroot); | |
464 assert(scopex.length >= debug_scopedim); | |
465 assert(scopex.allocdim >= debug_scopeallocdim); | |
466 assert(0 == memcmp(debug_pscoperootdata, scopex.data, (void*).sizeof*debug_scoperoot)); | |
467 assert(0 == memcmp(debug_pglobalrootdata, scopex.data, (void*).sizeof*debug_globalroot)); | |
468 assert(scopex); | |
469 } | |
470 | |
471 | |
472 /+ | |
473 v = &vundefined; | |
474 tx = v.getType(); | |
475 assert(tx == TypeUndefined); | |
476 +/ | |
477 //writef("\tIR%d:\n", code.opcode); | |
478 switch (code.opcode) | |
479 { | |
480 case IRerror: | |
481 assert(0); | |
482 break; | |
483 | |
484 case IRnop: | |
485 code++; | |
486 break; | |
487 | |
488 case IRget: // a = b.c | |
489 a = GETa(code); | |
490 b = GETb(code); | |
491 o = b.toObject(); | |
492 if (!o) | |
493 { | |
494 a = cannotConvert(b, GETlinnum(code)); | |
495 goto Lthrow; | |
496 } | |
497 c = GETc(code); | |
498 if (c.vtype == V_NUMBER && | |
499 (i32 = cast(d_int32)c.number) == c.number && | |
500 i32 >= 0) | |
501 { | |
502 //writef("IRget %d\n", i32); | |
503 v = o.Get(cast(d_uint32)i32, c); | |
504 } | |
505 else | |
506 { | |
507 s = c.toString(); | |
508 v = o.Get(s); | |
509 } | |
510 if (!v) | |
511 v = &vundefined; | |
512 Value.copy(a,v); | |
513 code += 4; | |
514 break; | |
515 | |
516 case IRput: // b.c = a | |
517 a = GETa(code); | |
518 b = GETb(code); | |
519 c = GETc(code); | |
520 if (c.vtype == V_NUMBER && | |
521 (i32 = cast(d_int32)c.number) == c.number && | |
522 i32 >= 0) | |
523 { | |
524 //writef("IRput %d\n", i32); | |
525 if (b.vtype == V_OBJECT) | |
526 a = b.object.Put(cast(d_uint32)i32, c, a, 0); | |
527 else | |
528 a = b.Put(cast(d_uint32)i32, c, a); | |
529 } | |
530 else | |
531 { | |
532 s = c.toString(); | |
533 a = b.Put(s, a); | |
534 } | |
535 if (a) goto Lthrow; | |
536 code += 4; | |
537 break; | |
538 | |
539 case IRgets: // a = b.s | |
540 a = GETa(code); | |
541 b = GETb(code); | |
542 s = (code + 3).id.value.string; | |
543 o = b.toObject(); | |
544 if (!o) | |
545 { | |
546 //writef("%s %s.%s cannot convert to Object", b.getType(), b.toString(), s); | |
547 ErrInfo errinfo; | |
548 a = Dobject.RuntimeError(&errinfo, | |
549 errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT3], | |
550 b.getType(), b.toString(), | |
551 s); | |
552 goto Lthrow; | |
553 } | |
554 v = o.Get(s); | |
555 if (!v) | |
556 { | |
557 //writef("IRgets: %s.%s is undefined\n", b.getType(), d_string_ptr(s)); | |
558 v = &vundefined; | |
559 } | |
560 Value.copy(a,v); | |
561 code += 4; | |
562 goto Lnext; | |
563 | |
564 case IRgetscope: // a = s | |
565 a = GETa(code); | |
566 id = (code + 2).id; | |
567 s = id.value.string; | |
568 version (SCOPECACHING) | |
569 { | |
570 si = SCOPECACHE_SI(s.ptr); | |
571 if (s is scopecache[si].s) | |
572 { | |
573 version (SCOPECACHE_LOG) scopecache_cnt++; | |
574 Value.copy(a, scopecache[si].v); | |
575 code += 3; | |
576 break; | |
577 } | |
578 //writefln("miss %s, was %s, s.ptr = %x, cache.ptr = %x", s, scopecache[si].s, cast(uint)s.ptr, cast(uint)scopecache[si].s.ptr); | |
579 } | |
580 version (all) | |
581 { | |
582 // Inline scope_get() for speed | |
583 { uint d; | |
584 | |
585 d = scopex.length; | |
586 // 1 is most common case for d | |
587 if (d == 1) | |
588 { | |
589 o = scopex[0]; | |
590 v = o.Get(id); | |
591 } | |
592 else | |
593 { | |
594 o = null; | |
595 for (;;) | |
596 { | |
597 if (!d) | |
598 { v = null; | |
599 break; | |
600 } | |
601 d--; | |
602 o = scopex[d]; | |
603 v = o.Get(id); | |
604 //writef("o = %x, v = %x\n", o, v); | |
605 if (v) | |
606 break; | |
607 } | |
608 } | |
609 } | |
610 if (!v) | |
611 v = &vundefined; | |
612 else | |
613 { | |
614 version (SCOPECACHING) | |
615 { | |
616 if (1) //!o.isDcomobject()) | |
617 { | |
618 scopecache[si].s = s; | |
619 scopecache[si].v = v; | |
620 } | |
621 } | |
622 } | |
623 } | |
624 else | |
625 { | |
626 v = scope_get(scopex, id); | |
627 if (!v) | |
628 v = &vundefined; | |
629 } | |
630 //writef("v = %p\n", v); | |
631 //writef("v = %g\n", v.toNumber()); | |
632 //writef("v = %s\n", d_string_ptr(v.toString())); | |
633 Value.copy(a, v); | |
634 code += 3; | |
635 break; | |
636 | |
637 case IRaddass: // a = (b.c += a) | |
638 c = GETc(code); | |
639 s = c.toString(); | |
640 goto Laddass; | |
641 | |
642 case IRaddasss: // a = (b.s += a) | |
643 s = (code + 3).id.value.string; | |
644 Laddass: | |
645 b = GETb(code); | |
646 v = b.Get(s); | |
647 goto Laddass2; | |
648 | |
649 case IRaddassscope: // a = (s += a) | |
650 b = null; // Needed for the b.Put() below to shutup a compiler use-without-init warning | |
651 id = (code + 2).id; | |
652 s = id.value.string; | |
653 version (SCOPECACHING) | |
654 { | |
655 si = SCOPECACHE_SI(s.ptr); | |
656 if (s is scopecache[si].s) | |
657 v = scopecache[si].v; | |
658 else | |
659 v = scope_get(scopex, id); | |
660 } | |
661 else | |
662 { | |
663 v = scope_get(scopex, id); | |
664 } | |
665 Laddass2: | |
666 a = GETa(code); | |
667 if (!v) | |
668 { | |
669 v = &vundefined; | |
670 a.putVundefined(); | |
671 /+ | |
672 if (b) | |
673 { | |
674 a = b.Put(s, v); | |
675 //if (a) goto Lthrow; | |
676 } | |
677 else | |
678 { | |
679 PutValue(cc, s, v); | |
680 } | |
681 +/ | |
682 } | |
683 else if (a.vtype == V_NUMBER && v.vtype == V_NUMBER) | |
684 { a.number += v.number; | |
685 v.number = a.number; | |
686 } | |
687 else | |
688 { | |
689 v.toPrimitive(v, null); | |
690 a.toPrimitive(a, null); | |
691 if (v.isString()) | |
692 { | |
693 s2 = v.toString() ~ a.toString(); | |
694 a.putVstring(s2); | |
695 Value.copy(v, a); | |
696 } | |
697 else if (a.isString()) | |
698 { | |
699 s2 = v.toString() ~ a.toString(); | |
700 a.putVstring(s2); | |
701 Value.copy(v, a); | |
702 } | |
703 else | |
704 { | |
705 a.putVnumber(a.toNumber() + v.toNumber()); | |
706 v.number = a.number; | |
707 } | |
708 } | |
709 code += 4; | |
710 break; | |
711 | |
712 case IRputs: // b.s = a | |
713 a = GETa(code); | |
714 b = GETb(code); | |
715 o = b.toObject(); | |
716 if (!o) | |
717 { | |
718 a = cannotConvert(b, GETlinnum(code)); | |
719 goto Lthrow; | |
720 } | |
721 a = o.Put((code + 3).id.value.string, a, 0); | |
722 if (a) goto Lthrow; | |
723 code += 4; | |
724 goto Lnext; | |
725 | |
726 case IRputscope: // s = a | |
727 PutValue(cc, (code + 2).id, GETa(code)); | |
728 code += 3; | |
729 break; | |
730 | |
731 case IRputdefault: // b = a | |
732 a = GETa(code); | |
733 b = GETb(code); | |
734 o = b.toObject(); | |
735 if (!o) | |
736 { | |
737 ErrInfo errinfo; | |
738 a = Dobject.RuntimeError(&errinfo, | |
739 errmsgtbl[ERR_CANNOT_ASSIGN], a.getType(), | |
740 b.getType()); | |
741 goto Lthrow; | |
742 } | |
743 a = o.PutDefault(a); | |
744 if (a) | |
745 goto Lthrow; | |
746 code += 3; | |
747 break; | |
748 | |
749 case IRputthis: // s = a | |
750 a = cc.variable.Put((code + 2).id.value.string, GETa(code), 0); | |
751 //if (a) goto Lthrow; | |
752 code += 3; | |
753 break; | |
754 | |
755 case IRmov: // a = b | |
756 Value.copy(GETa(code), GETb(code)); | |
757 code += 3; | |
758 break; | |
759 | |
760 case IRstring: // a = "string" | |
761 GETa(code).putVstring((code + 2).id.value.string); | |
762 code += 3; | |
763 break; | |
764 | |
765 case IRobject: // a = object | |
766 { FunctionDefinition fd; | |
767 fd = cast(FunctionDefinition)(code + 2).ptr; | |
768 Dfunction fobject = new DdeclaredFunction(fd); | |
769 fobject.scopex = scopex; | |
770 GETa(code).putVobject(fobject); | |
771 code += 3; | |
772 break; | |
773 } | |
774 | |
775 case IRthis: // a = this | |
776 GETa(code).putVobject(othis); | |
777 //writef("IRthis: %s, othis = %x\n", GETa(code).getType(), othis); | |
778 code += 2; | |
779 break; | |
780 | |
781 case IRnumber: // a = number | |
782 GETa(code).putVnumber(*cast(d_number *)(code + 2)); | |
783 code += 4; | |
784 break; | |
785 | |
786 case IRboolean: // a = boolean | |
787 GETa(code).putVboolean((code + 2).boolean); | |
788 code += 3; | |
789 break; | |
790 | |
791 case IRnull: // a = null | |
792 GETa(code).putVnull(); | |
793 code += 2; | |
794 break; | |
795 | |
796 case IRundefined: // a = undefined | |
797 GETa(code).putVundefined(); | |
798 code += 2; | |
799 break; | |
800 | |
801 case IRthisget: // a = othis.ident | |
802 a = GETa(code); | |
803 v = othis.Get((code + 2).id.value.string); | |
804 if (!v) | |
805 v = &vundefined; | |
806 Value.copy(a, v); | |
807 code += 3; | |
808 break; | |
809 | |
810 case IRneg: // a = -a | |
811 a = GETa(code); | |
812 n = a.toNumber(); | |
813 a.putVnumber(-n); | |
814 code += 2; | |
815 break; | |
816 | |
817 case IRpos: // a = a | |
818 a = GETa(code); | |
819 n = a.toNumber(); | |
820 a.putVnumber(n); | |
821 code += 2; | |
822 break; | |
823 | |
824 case IRcom: // a = ~a | |
825 a = GETa(code); | |
826 i32 = a.toInt32(); | |
827 a.putVnumber(~i32); | |
828 code += 2; | |
829 break; | |
830 | |
831 case IRnot: // a = !a | |
832 a = GETa(code); | |
833 a.putVboolean(!a.toBoolean()); | |
834 code += 2; | |
835 break; | |
836 | |
837 case IRtypeof: // a = typeof a | |
838 // ECMA 11.4.3 says that if the result of (a) | |
839 // is a Reference and GetBase(a) is null, | |
840 // then the result is "undefined". I don't know | |
841 // what kind of script syntax will generate this. | |
842 a = GETa(code); | |
843 a.putVstring(a.getTypeof()); | |
844 code += 2; | |
845 break; | |
846 | |
847 case IRinstance: // a = b instanceof c | |
848 { | |
849 Dobject co; | |
850 | |
851 // ECMA v3 11.8.6 | |
852 | |
853 b = GETb(code); | |
854 o = b.toObject(); | |
855 c = GETc(code); | |
856 if (c.isPrimitive()) | |
857 { | |
858 ErrInfo errinfo; | |
859 a = Dobject.RuntimeError(&errinfo, | |
860 errmsgtbl[ERR_RHS_MUST_BE_OBJECT], | |
861 "instanceof", c.getType()); | |
862 goto Lthrow; | |
863 } | |
864 co = c.toObject(); | |
865 a = GETa(code); | |
866 v = cast(Value*)co.HasInstance(a, b); | |
867 if (v) | |
868 { a = v; | |
869 goto Lthrow; | |
870 } | |
871 code += 4; | |
872 break; | |
873 } | |
874 case IRadd: // a = b + c | |
875 a = GETa(code); | |
876 b = GETb(code); | |
877 c = GETc(code); | |
878 | |
879 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER) | |
880 { | |
881 a.putVnumber(b.number + c.number); | |
882 } | |
883 else | |
884 { | |
885 char vtmpb[Value.sizeof]; | |
886 Value* vb = cast(Value*)vtmpb; | |
887 char vtmpc[Value.sizeof]; | |
888 Value* vc = cast(Value*)vtmpc; | |
889 | |
890 v = cast(Value*)b.toPrimitive(vb, null); | |
891 if (v) | |
892 { a = v; | |
893 goto Lthrow; | |
894 } | |
895 v = cast(Value*)c.toPrimitive(vc, null); | |
896 if (v) | |
897 { a = v; | |
898 goto Lthrow; | |
899 } | |
900 if (vb.isString() || vc.isString()) | |
901 { | |
902 s = vb.toString() ~ vc.toString(); | |
903 a.putVstring(s); | |
904 } | |
905 else | |
906 { | |
907 a.putVnumber(vb.toNumber() + vc.toNumber()); | |
908 } | |
909 } | |
910 | |
911 code += 4; | |
912 break; | |
913 | |
914 case IRsub: // a = b - c | |
915 a = GETa(code); | |
916 b = GETb(code); | |
917 c = GETc(code); | |
918 a.putVnumber(b.toNumber() - c.toNumber()); | |
919 code += 4; | |
920 break; | |
921 | |
922 case IRmul: // a = b * c | |
923 a = GETa(code); | |
924 b = GETb(code); | |
925 c = GETc(code); | |
926 a.putVnumber(b.toNumber() * c.toNumber()); | |
927 code += 4; | |
928 break; | |
929 | |
930 case IRdiv: // a = b / c | |
931 a = GETa(code); | |
932 b = GETb(code); | |
933 c = GETc(code); | |
934 | |
935 //writef("%g / %g = %g\n", b.toNumber() , c.toNumber(), b.toNumber() / c.toNumber()); | |
936 a.putVnumber(b.toNumber() / c.toNumber()); | |
937 code += 4; | |
938 break; | |
939 | |
940 case IRmod: // a = b % c | |
941 a = GETa(code); | |
942 b = GETb(code); | |
943 c = GETc(code); | |
944 a.putVnumber(b.toNumber() % c.toNumber()); | |
945 code += 4; | |
946 break; | |
947 | |
948 case IRshl: // a = b << c | |
949 a = GETa(code); | |
950 b = GETb(code); | |
951 c = GETc(code); | |
952 i32 = b.toInt32(); | |
953 u32 = c.toUint32() & 0x1F; | |
954 i32 <<= u32; | |
955 a.putVnumber(i32); | |
956 code += 4; | |
957 break; | |
958 | |
959 case IRshr: // a = b >> c | |
960 a = GETa(code); | |
961 b = GETb(code); | |
962 c = GETc(code); | |
963 i32 = b.toInt32(); | |
964 u32 = c.toUint32() & 0x1F; | |
965 i32 >>= cast(d_int32) u32; | |
966 a.putVnumber(i32); | |
967 code += 4; | |
968 break; | |
969 | |
970 case IRushr: // a = b >>> c | |
971 a = GETa(code); | |
972 b = GETb(code); | |
973 c = GETc(code); | |
974 i32 = b.toUint32(); | |
975 u32 = c.toUint32() & 0x1F; | |
976 u32 = (cast(d_uint32) i32) >> u32; | |
977 a.putVnumber(u32); | |
978 code += 4; | |
979 break; | |
980 | |
981 case IRand: // a = b & c | |
982 a = GETa(code); | |
983 b = GETb(code); | |
984 c = GETc(code); | |
985 a.putVnumber(b.toInt32() & c.toInt32()); | |
986 code += 4; | |
987 break; | |
988 | |
989 case IRor: // a = b | c | |
990 a = GETa(code); | |
991 b = GETb(code); | |
992 c = GETc(code); | |
993 a.putVnumber(b.toInt32() | c.toInt32()); | |
994 code += 4; | |
995 break; | |
996 | |
997 case IRxor: // a = b ^ c | |
998 a = GETa(code); | |
999 b = GETb(code); | |
1000 c = GETc(code); | |
1001 a.putVnumber(b.toInt32() ^ c.toInt32()); | |
1002 code += 4; | |
1003 break; | |
1004 | |
1005 /********************/ | |
1006 | |
1007 case IRpreinc: // a = ++b.c | |
1008 c = GETc(code); | |
1009 s = c.toString(); | |
1010 goto Lpreinc; | |
1011 case IRpreincs: // a = ++b.s | |
1012 s = (code + 3).id.value.string; | |
1013 Lpreinc: | |
1014 inc = 1; | |
1015 Lpre: | |
1016 a = GETa(code); | |
1017 b = GETb(code); | |
1018 v = b.Get(s); | |
1019 if (!v) | |
1020 v = &vundefined; | |
1021 n = v.toNumber(); | |
1022 a.putVnumber(n + inc); | |
1023 b.Put(s, a); | |
1024 code += 4; | |
1025 break; | |
1026 | |
1027 case IRpreincscope: // a = ++s | |
1028 inc = 1; | |
1029 Lprescope: | |
1030 a = GETa(code); | |
1031 id = (code + 2).id; | |
1032 s = id.value.string; | |
1033 version (SCOPECACHING) | |
1034 { | |
1035 si = SCOPECACHE_SI(s.ptr); | |
1036 if (s is scopecache[si].s) | |
1037 { | |
1038 v = scopecache[si].v; | |
1039 n = v.toNumber() + inc; | |
1040 v.putVnumber(n); | |
1041 a.putVnumber(n); | |
1042 } | |
1043 else | |
1044 { | |
1045 v = scope_get(scopex, id, &o); | |
1046 if (v) | |
1047 { n = v.toNumber() + inc; | |
1048 v.putVnumber(n); | |
1049 a.putVnumber(n); | |
1050 } | |
1051 else | |
1052 a.putVundefined(); | |
1053 } | |
1054 } | |
1055 else | |
1056 { | |
1057 v = scope_get(scopex, id, &o); | |
1058 if (v) | |
1059 { n = v.toNumber(); | |
1060 v.putVnumber(n + inc); | |
1061 Value.copy(a, v); | |
1062 } | |
1063 else | |
1064 a.putVundefined(); | |
1065 } | |
1066 code += 4; | |
1067 break; | |
1068 | |
1069 case IRpredec: // a = --b.c | |
1070 c = GETc(code); | |
1071 s = c.toString(); | |
1072 goto Lpredec; | |
1073 case IRpredecs: // a = --b.s | |
1074 s = (code + 3).id.value.string; | |
1075 Lpredec: | |
1076 inc = -1; | |
1077 goto Lpre; | |
1078 | |
1079 case IRpredecscope: // a = --s | |
1080 inc = -1; | |
1081 goto Lprescope; | |
1082 | |
1083 /********************/ | |
1084 | |
1085 case IRpostinc: // a = b.c++ | |
1086 c = GETc(code); | |
1087 s = c.toString(); | |
1088 goto Lpostinc; | |
1089 case IRpostincs: // a = b.s++ | |
1090 s = (code + 3).id.value.string; | |
1091 Lpostinc: | |
1092 a = GETa(code); | |
1093 b = GETb(code); | |
1094 v = b.Get(s); | |
1095 if (!v) | |
1096 v = &vundefined; | |
1097 n = v.toNumber(); | |
1098 a.putVnumber(n + 1); | |
1099 b.Put(s, a); | |
1100 a.putVnumber(n); | |
1101 code += 4; | |
1102 break; | |
1103 | |
1104 case IRpostincscope: // a = s++ | |
1105 id = (code + 2).id; | |
1106 v = scope_get(scopex, id, &o); | |
1107 if (v && v != &vundefined) | |
1108 { | |
1109 n = v.toNumber(); | |
1110 a = GETa(code); | |
1111 v.putVnumber(n + 1); | |
1112 a.putVnumber(n); | |
1113 } | |
1114 else | |
1115 GETa(code).putVundefined(); | |
1116 code += 3; | |
1117 break; | |
1118 | |
1119 case IRpostdec: // a = b.c-- | |
1120 c = GETc(code); | |
1121 s = c.toString(); | |
1122 goto Lpostdec; | |
1123 case IRpostdecs: // a = b.s-- | |
1124 s = (code + 3).id.value.string; | |
1125 Lpostdec: | |
1126 a = GETa(code); | |
1127 b = GETb(code); | |
1128 v = b.Get(s); | |
1129 if (!v) | |
1130 v = &vundefined; | |
1131 n = v.toNumber(); | |
1132 a.putVnumber(n - 1); | |
1133 b.Put(s, a); | |
1134 a.putVnumber(n); | |
1135 code += 4; | |
1136 break; | |
1137 | |
1138 case IRpostdecscope: // a = s-- | |
1139 id = (code + 2).id; | |
1140 v = scope_get(scopex, id, &o); | |
1141 if (v && v != &vundefined) | |
1142 { n = v.toNumber(); | |
1143 a = GETa(code); | |
1144 v.putVnumber(n - 1); | |
1145 a.putVnumber(n); | |
1146 } | |
1147 else | |
1148 GETa(code).putVundefined(); | |
1149 code += 3; | |
1150 break; | |
1151 | |
1152 case IRdel: // a = delete b.c | |
1153 case IRdels: // a = delete b.s | |
1154 b = GETb(code); | |
1155 if (b.isPrimitive()) | |
1156 bo = true; | |
1157 else | |
1158 { | |
1159 o = b.toObject(); | |
1160 if (!o) | |
1161 { | |
1162 a = cannotConvert(b, GETlinnum(code)); | |
1163 goto Lthrow; | |
1164 } | |
1165 s = (code.opcode == IRdel) | |
1166 ? GETc(code).toString() | |
1167 : (code + 3).id.value.string; | |
1168 if (o.implementsDelete()) | |
1169 bo = o.Delete(s); | |
1170 else | |
1171 bo = !o.HasProperty(s); | |
1172 } | |
1173 GETa(code).putVboolean(bo); | |
1174 code += 4; | |
1175 break; | |
1176 | |
1177 case IRdelscope: // a = delete s | |
1178 id = (code + 2).id; | |
1179 s = id.value.string; | |
1180 //o = scope_tos(scopex); // broken way | |
1181 if (!scope_get(scopex, id, &o)) | |
1182 bo = true; | |
1183 else if (o.implementsDelete()) | |
1184 bo = o.Delete(s); | |
1185 else | |
1186 bo = !o.HasProperty(s); | |
1187 GETa(code).putVboolean(bo); | |
1188 code += 3; | |
1189 break; | |
1190 | |
1191 /* ECMA requires that if one of the numeric operands is NAN, | |
1192 * then the result of the comparison is false. D generates a | |
1193 * correct test for NAN operands. | |
1194 */ | |
1195 | |
1196 case IRclt: // a = (b < c) | |
1197 a = GETa(code); | |
1198 b = GETb(code); | |
1199 c = GETc(code); | |
1200 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER) | |
1201 res = (b.number < c.number); | |
1202 else | |
1203 { | |
1204 b.toPrimitive(b, TypeNumber); | |
1205 c.toPrimitive(c, TypeNumber); | |
1206 if (b.isString() && c.isString()) | |
1207 { d_string x = b.toString(); | |
1208 d_string y = c.toString(); | |
1209 | |
1210 res = std.string.cmp(x, y) < 0; | |
1211 } | |
1212 else | |
1213 res = b.toNumber() < c.toNumber(); | |
1214 } | |
1215 a.putVboolean(res); | |
1216 code += 4; | |
1217 break; | |
1218 | |
1219 case IRcle: // a = (b <= c) | |
1220 a = GETa(code); | |
1221 b = GETb(code); | |
1222 c = GETc(code); | |
1223 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER) | |
1224 res = (b.number <= c.number); | |
1225 else | |
1226 { | |
1227 b.toPrimitive(b, TypeNumber); | |
1228 c.toPrimitive(c, TypeNumber); | |
1229 if (b.isString() && c.isString()) | |
1230 { d_string x = b.toString(); | |
1231 d_string y = c.toString(); | |
1232 | |
1233 res = std.string.cmp(x, y) <= 0; | |
1234 } | |
1235 else | |
1236 res = b.toNumber() <= c.toNumber(); | |
1237 } | |
1238 a.putVboolean(res); | |
1239 code += 4; | |
1240 break; | |
1241 | |
1242 case IRcgt: // a = (b > c) | |
1243 a = GETa(code); | |
1244 b = GETb(code); | |
1245 c = GETc(code); | |
1246 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER) | |
1247 res = (b.number > c.number); | |
1248 else | |
1249 { | |
1250 b.toPrimitive(b, TypeNumber); | |
1251 c.toPrimitive(c, TypeNumber); | |
1252 if (b.isString() && c.isString()) | |
1253 { d_string x = b.toString(); | |
1254 d_string y = c.toString(); | |
1255 | |
1256 res = std.string.cmp(x, y) > 0; | |
1257 } | |
1258 else | |
1259 res = b.toNumber() > c.toNumber(); | |
1260 } | |
1261 a.putVboolean(res); | |
1262 code += 4; | |
1263 break; | |
1264 | |
1265 | |
1266 case IRcge: // a = (b >= c) | |
1267 a = GETa(code); | |
1268 b = GETb(code); | |
1269 c = GETc(code); | |
1270 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER) | |
1271 res = (b.number >= c.number); | |
1272 else | |
1273 { | |
1274 b.toPrimitive(b, TypeNumber); | |
1275 c.toPrimitive(c, TypeNumber); | |
1276 if (b.isString() && c.isString()) | |
1277 { d_string x = b.toString(); | |
1278 d_string y = c.toString(); | |
1279 | |
1280 res = std.string.cmp(x, y) >= 0; | |
1281 } | |
1282 else | |
1283 res = b.toNumber() >= c.toNumber(); | |
1284 } | |
1285 a.putVboolean(res); | |
1286 code += 4; | |
1287 break; | |
1288 | |
1289 case IRceq: // a = (b == c) | |
1290 case IRcne: // a = (b != c) | |
1291 a = GETa(code); | |
1292 b = GETb(code); | |
1293 c = GETc(code); | |
1294 Lagain: | |
1295 tx = b.getType(); | |
1296 ty = c.getType(); | |
1297 if (logflag) writef("tx('%s', '%s')\n", tx, ty); | |
1298 if (tx == ty) | |
1299 { | |
1300 if (tx == TypeUndefined || | |
1301 tx == TypeNull) | |
1302 res = true; | |
1303 else if (tx == TypeNumber) | |
1304 { d_number x = b.number; | |
1305 d_number y = c.number; | |
1306 | |
1307 res = (x == y); | |
1308 //writef("x = %g, y = %g, res = %d\n", x, y, res); | |
1309 } | |
1310 else if (tx == TypeString) | |
1311 { | |
1312 if (logflag) | |
1313 { | |
1314 writef("b = %x, c = %x\n", b, c); | |
1315 writef("cmp('%s', '%s')\n", b.string, c.string); | |
1316 writef("cmp(%d, %d)\n", b.string.length, c.string.length); | |
1317 } | |
1318 res = (b.string == c.string); | |
1319 } | |
1320 else if (tx == TypeBoolean) | |
1321 res = (b.dbool == c.dbool); | |
1322 else // TypeObject | |
1323 { | |
1324 res = b.object == c.object; | |
1325 } | |
1326 } | |
1327 else if (tx == TypeNull && ty == TypeUndefined) | |
1328 res = true; | |
1329 else if (tx == TypeUndefined && ty == TypeNull) | |
1330 res = true; | |
1331 else if (tx == TypeNumber && ty == TypeString) | |
1332 { | |
1333 c.putVnumber(c.toNumber()); | |
1334 goto Lagain; | |
1335 } | |
1336 else if (tx == TypeString && ty == TypeNumber) | |
1337 { | |
1338 b.putVnumber(b.toNumber()); | |
1339 goto Lagain; | |
1340 } | |
1341 else if (tx == TypeBoolean) | |
1342 { | |
1343 b.putVnumber(b.toNumber()); | |
1344 goto Lagain; | |
1345 } | |
1346 else if (ty == TypeBoolean) | |
1347 { | |
1348 c.putVnumber(c.toNumber()); | |
1349 goto Lagain; | |
1350 } | |
1351 else if (ty == TypeObject) | |
1352 { | |
1353 v = cast(Value*)c.toPrimitive(c, null); | |
1354 if (v) | |
1355 { a = v; | |
1356 goto Lthrow; | |
1357 } | |
1358 goto Lagain; | |
1359 } | |
1360 else if (tx == TypeObject) | |
1361 { | |
1362 v = cast(Value*)b.toPrimitive(b, null); | |
1363 if (v) | |
1364 { a = v; | |
1365 goto Lthrow; | |
1366 } | |
1367 goto Lagain; | |
1368 } | |
1369 else | |
1370 { | |
1371 res = false; | |
1372 } | |
1373 | |
1374 res ^= (code.opcode == IRcne); | |
1375 //Lceq: | |
1376 a.putVboolean(res); | |
1377 code += 4; | |
1378 break; | |
1379 | |
1380 case IRcid: // a = (b === c) | |
1381 case IRcnid: // a = (b !== c) | |
1382 a = GETa(code); | |
1383 b = GETb(code); | |
1384 c = GETc(code); | |
1385 tx = b.getType(); | |
1386 ty = c.getType(); | |
1387 if (tx == ty) | |
1388 { | |
1389 if (tx == TypeUndefined || | |
1390 tx == TypeNull) | |
1391 res = true; | |
1392 else if (tx == TypeNumber) | |
1393 { d_number x = b.number; | |
1394 d_number y = c.number; | |
1395 | |
1396 // Ensure that a NAN operand produces false | |
1397 if (code.opcode == IRcid) | |
1398 res = (x == y); | |
1399 else | |
1400 res = (x <> y); | |
1401 goto Lcid; | |
1402 } | |
1403 else if (tx == TypeString) | |
1404 res = (b.string == c.string); | |
1405 else if (tx == TypeBoolean) | |
1406 res = (b.dbool == c.dbool); | |
1407 else // TypeObject | |
1408 { | |
1409 res = b.object == c.object; | |
1410 } | |
1411 } | |
1412 else | |
1413 { | |
1414 res = false; | |
1415 } | |
1416 | |
1417 res ^= (code.opcode == IRcnid); | |
1418 Lcid: | |
1419 a.putVboolean(res); | |
1420 code += 4; | |
1421 break; | |
1422 | |
1423 case IRjt: // if (b) goto t | |
1424 b = GETb(code); | |
1425 if (b.toBoolean()) | |
1426 code += (code + 1).offset; | |
1427 else | |
1428 code += 3; | |
1429 break; | |
1430 | |
1431 case IRjf: // if (!b) goto t | |
1432 b = GETb(code); | |
1433 if (!b.toBoolean()) | |
1434 code += (code + 1).offset; | |
1435 else | |
1436 code += 3; | |
1437 break; | |
1438 | |
1439 case IRjtb: // if (b) goto t | |
1440 b = GETb(code); | |
1441 if (b.dbool) | |
1442 code += (code + 1).offset; | |
1443 else | |
1444 code += 3; | |
1445 break; | |
1446 | |
1447 case IRjfb: // if (!b) goto t | |
1448 b = GETb(code); | |
1449 if (!b.dbool) | |
1450 code += (code + 1).offset; | |
1451 else | |
1452 code += 3; | |
1453 break; | |
1454 | |
1455 case IRjmp: | |
1456 code += (code + 1).offset; | |
1457 break; | |
1458 | |
1459 case IRjlt: // if (b < c) goto c | |
1460 b = GETb(code); | |
1461 c = GETc(code); | |
1462 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER) | |
1463 { | |
1464 if (b.number < c.number) | |
1465 code += 4; | |
1466 else | |
1467 code += (code + 1).offset; | |
1468 break; | |
1469 } | |
1470 else | |
1471 { | |
1472 b.toPrimitive(b, TypeNumber); | |
1473 c.toPrimitive(c, TypeNumber); | |
1474 if (b.isString() && c.isString()) | |
1475 { d_string x = b.toString(); | |
1476 d_string y = c.toString(); | |
1477 | |
1478 res = std.string.cmp(x, y) < 0; | |
1479 } | |
1480 else | |
1481 res = b.toNumber() < c.toNumber(); | |
1482 } | |
1483 if (!res) | |
1484 code += (code + 1).offset; | |
1485 else | |
1486 code += 4; | |
1487 break; | |
1488 | |
1489 case IRjle: // if (b <= c) goto c | |
1490 b = GETb(code); | |
1491 c = GETc(code); | |
1492 if (b.vtype == V_NUMBER && c.vtype == V_NUMBER) | |
1493 { | |
1494 if (b.number <= c.number) | |
1495 code += 4; | |
1496 else | |
1497 code += (code + 1).offset; | |
1498 break; | |
1499 } | |
1500 else | |
1501 { | |
1502 b.toPrimitive(b, TypeNumber); | |
1503 c.toPrimitive(c, TypeNumber); | |
1504 if (b.isString() && c.isString()) | |
1505 { d_string x = b.toString(); | |
1506 d_string y = c.toString(); | |
1507 | |
1508 res = std.string.cmp(x, y) <= 0; | |
1509 } | |
1510 else | |
1511 res = b.toNumber() <= c.toNumber(); | |
1512 } | |
1513 if (!res) | |
1514 code += (code + 1).offset; | |
1515 else | |
1516 code += 4; | |
1517 break; | |
1518 | |
1519 case IRjltc: // if (b < constant) goto c | |
1520 b = GETb(code); | |
1521 res = (b.toNumber() < *cast(d_number *)(code + 3)); | |
1522 if (!res) | |
1523 code += (code + 1).offset; | |
1524 else | |
1525 code += 5; | |
1526 break; | |
1527 | |
1528 case IRjlec: // if (b <= constant) goto c | |
1529 b = GETb(code); | |
1530 res = (b.toNumber() <= *cast(d_number *)(code + 3)); | |
1531 if (!res) | |
1532 code += (code + 1).offset; | |
1533 else | |
1534 code += 5; | |
1535 break; | |
1536 | |
1537 case IRiter: // a = iter(b) | |
1538 a = GETa(code); | |
1539 b = GETb(code); | |
1540 o = b.toObject(); | |
1541 if (!o) | |
1542 { | |
1543 a = cannotConvert(b, GETlinnum(code)); | |
1544 goto Lthrow; | |
1545 } | |
1546 a = o.putIterator(a); | |
1547 if (a) | |
1548 goto Lthrow; | |
1549 code += 3; | |
1550 break; | |
1551 | |
1552 case IRnext: // a, b.c, iter | |
1553 // if (!(b.c = iter)) goto a; iter = iter.next | |
1554 s = GETc(code).toString(); | |
1555 goto case_next; | |
1556 | |
1557 case IRnexts: // a, b.s, iter | |
1558 s = (code + 3).id.value.string; | |
1559 case_next: | |
1560 iter = GETd(code).iter; | |
1561 v = iter.next(); | |
1562 if (!v) | |
1563 code += (code + 1).offset; | |
1564 else | |
1565 { | |
1566 b = GETb(code); | |
1567 b.Put(s, v); | |
1568 code += 5; | |
1569 } | |
1570 break; | |
1571 | |
1572 case IRnextscope: // a, s, iter | |
1573 s = (code + 2).id.value.string; | |
1574 iter = GETc(code).iter; | |
1575 v = iter.next(); | |
1576 if (!v) | |
1577 code += (code + 1).offset; | |
1578 else | |
1579 { | |
1580 o = scope_tos(scopex); | |
1581 o.Put(s, v, 0); | |
1582 code += 4; | |
1583 } | |
1584 break; | |
1585 | |
1586 case IRcall: // a = b.c(argc, argv) | |
1587 s = GETc(code).toString(); | |
1588 goto case_call; | |
1589 | |
1590 case IRcalls: // a = b.s(argc, argv) | |
1591 s = (code + 3).id.value.string; | |
1592 goto case_call; | |
1593 | |
1594 case_call: | |
1595 a = GETa(code); | |
1596 b = GETb(code); | |
1597 o = b.toObject(); | |
1598 if (!o) | |
1599 { | |
1600 goto Lcallerror; | |
1601 } | |
1602 { | |
1603 //writef("v.call\n"); | |
1604 v = o.Get(s); | |
1605 if (!v) | |
1606 goto Lcallerror; | |
1607 //writef("calling... '%s'\n", v.toString()); | |
1608 cc.callerothis = othis; | |
1609 a.putVundefined(); | |
1610 a = cast(Value*)v.Call(cc, o, a, GETe(code)[0 .. (code + 4).index]); | |
1611 //writef("regular call, a = %x\n", a); | |
1612 } | |
1613 debug (VERIFY) | |
1614 assert(checksum == IR.verify(__LINE__, codestart)); | |
1615 if (a) | |
1616 goto Lthrow; | |
1617 code += 6; | |
1618 goto Lnext; | |
1619 | |
1620 Lcallerror: | |
1621 { | |
1622 //writef("%s %s.%s is undefined and has no Call method\n", b.getType(), b.toString(), s); | |
1623 ErrInfo errinfo; | |
1624 a = Dobject.RuntimeError(&errinfo, | |
1625 errmsgtbl[ERR_UNDEFINED_NO_CALL3], | |
1626 b.getType(), b.toString(), | |
1627 s); | |
1628 goto Lthrow; | |
1629 } | |
1630 | |
1631 case IRcallscope: // a = s(argc, argv) | |
1632 id = (code + 2).id; | |
1633 s = id.value.string; | |
1634 a = GETa(code); | |
1635 v = scope_get_lambda(scopex, id, &o); | |
1636 //writefln("v.toString() = '%s'", v.toString()); | |
1637 if (!v) | |
1638 { | |
1639 ErrInfo errinfo; | |
1640 a = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_UNDEFINED_NO_CALL2], "property", s); | |
1641 goto Lthrow; | |
1642 } | |
1643 // Should we pass othis or o? I think othis. | |
1644 cc.callerothis = othis; // pass othis to eval() | |
1645 a.putVundefined(); | |
1646 a = cast(Value*)v.Call(cc, o, a, GETd(code)[0 .. (code + 3).index] ); | |
1647 //writef("callscope result = %x\n", a); | |
1648 debug (VERIFY) | |
1649 assert(checksum == IR.verify(__LINE__, codestart)); | |
1650 if (a) | |
1651 goto Lthrow; | |
1652 code += 5; | |
1653 goto Lnext; | |
1654 | |
1655 case IRcallv: // v(argc, argv) = a | |
1656 a = GETa(code); | |
1657 b = GETb(code); | |
1658 o = b.toObject(); | |
1659 if (!o) | |
1660 { | |
1661 //writef("%s %s is undefined and has no Call method\n", b.getType(), b.toString()); | |
1662 ErrInfo errinfo; | |
1663 a = Dobject.RuntimeError(&errinfo, | |
1664 errmsgtbl[ERR_UNDEFINED_NO_CALL2], | |
1665 b.getType(), b.toString()); | |
1666 goto Lthrow; | |
1667 } | |
1668 cc.callerothis = othis; // pass othis to eval() | |
1669 a.putVundefined(); | |
1670 a = cast(Value*)o.Call(cc, o, a, GETd(code)[0 .. (code + 3).index]); | |
1671 if (a) | |
1672 goto Lthrow; | |
1673 code += 5; | |
1674 goto Lnext; | |
1675 | |
1676 case IRputcall: // b.c(argc, argv) = a | |
1677 s = GETc(code).toString(); | |
1678 goto case_putcall; | |
1679 | |
1680 case IRputcalls: // b.s(argc, argv) = a | |
1681 s = (code + 3).id.value.string; | |
1682 goto case_putcall; | |
1683 | |
1684 case_putcall: | |
1685 a = GETa(code); | |
1686 b = GETb(code); | |
1687 o = b.toObject(); | |
1688 if (!o) | |
1689 goto Lcallerror; | |
1690 //v = o.GetLambda(s, Value.calcHash(s)); | |
1691 v = o.Get(s, Value.calcHash(s)); | |
1692 if (!v) | |
1693 goto Lcallerror; | |
1694 //writef("calling... '%s'\n", v.toString()); | |
1695 o = v.toObject(); | |
1696 if (!o) | |
1697 { | |
1698 ErrInfo errinfo; | |
1699 a = Dobject.RuntimeError(&errinfo, | |
1700 errmsgtbl[ERR_CANNOT_ASSIGN_TO2], | |
1701 b.getType(), s); | |
1702 goto Lthrow; | |
1703 } | |
1704 a = cast(Value*)o.put_Value(a, GETe(code)[0 .. (code + 4).index] ); | |
1705 if (a) | |
1706 goto Lthrow; | |
1707 code += 6; | |
1708 goto Lnext; | |
1709 | |
1710 case IRputcallscope: // a = s(argc, argv) | |
1711 id = (code + 2).id; | |
1712 s = id.value.string; | |
1713 v = scope_get_lambda(scopex, id, &o); | |
1714 if (!v) | |
1715 { | |
1716 ErrInfo errinfo; | |
1717 a = Dobject.RuntimeError(&errinfo, | |
1718 errmsgtbl[ERR_UNDEFINED_NO_CALL2], | |
1719 "property", s); | |
1720 goto Lthrow; | |
1721 } | |
1722 o = v.toObject(); | |
1723 if (!o) | |
1724 { | |
1725 ErrInfo errinfo; | |
1726 a = Dobject.RuntimeError(&errinfo, | |
1727 errmsgtbl[ERR_CANNOT_ASSIGN_TO], | |
1728 s); | |
1729 goto Lthrow; | |
1730 } | |
1731 a = cast(Value*)o.put_Value(GETa(code), GETd(code)[0 .. (code + 3).index] ); | |
1732 if (a) | |
1733 goto Lthrow; | |
1734 code += 5; | |
1735 goto Lnext; | |
1736 | |
1737 case IRputcallv: // v(argc, argv) = a | |
1738 b = GETb(code); | |
1739 o = b.toObject(); | |
1740 if (!o) | |
1741 { | |
1742 //writef("%s %s is undefined and has no Call method\n", b.getType(), b.toString()); | |
1743 ErrInfo errinfo; | |
1744 a = Dobject.RuntimeError(&errinfo, | |
1745 errmsgtbl[ERR_UNDEFINED_NO_CALL2], | |
1746 b.getType(), b.toString()); | |
1747 goto Lthrow; | |
1748 } | |
1749 a = cast(Value*)o.put_Value(GETa(code), GETd(code)[0 .. (code + 3).index] ); | |
1750 if (a) | |
1751 goto Lthrow; | |
1752 code += 5; | |
1753 goto Lnext; | |
1754 | |
1755 case IRnew: // a = new b(argc, argv) | |
1756 a = GETa(code); | |
1757 b = GETb(code); | |
1758 a.putVundefined(); | |
1759 a = cast(Value*)b.Construct(cc, a, GETd(code)[0 .. (code + 3).index] ); | |
1760 debug (VERIFY) | |
1761 assert(checksum == IR.verify(__LINE__, codestart)); | |
1762 if (a) | |
1763 goto Lthrow; | |
1764 code += 5; | |
1765 goto Lnext; | |
1766 | |
1767 case IRpush: | |
1768 SCOPECACHE_CLEAR(); | |
1769 a = GETa(code); | |
1770 o = a.toObject(); | |
1771 if (!o) | |
1772 { | |
1773 a = cannotConvert(a, GETlinnum(code)); | |
1774 goto Lthrow; | |
1775 } | |
1776 scopex ~= o; // push entry onto scope chain | |
1777 cc.scopex = scopex; | |
1778 code += 2; | |
1779 break; | |
1780 | |
1781 case IRpop: | |
1782 SCOPECACHE_CLEAR(); | |
1783 o = scopex[length - 1]; | |
1784 scopex = scopex[0 .. length - 1]; // pop entry off scope chain | |
1785 // If it's a Finally, we need to execute | |
1786 // the finally block | |
1787 code += 1; | |
1788 if (o.isFinally()) // test could be eliminated with virtual func | |
1789 { | |
1790 f = cast(Finally)o; | |
1791 cc.finallyret = 0; | |
1792 a = cast(Value*)call(cc, othis, f.finallyblock, ret, locals); | |
1793 debug (VERIFY) | |
1794 assert(checksum == IR.verify(__LINE__, codestart)); | |
1795 if (a) | |
1796 goto Lthrow; | |
1797 if (cc.finallyret) | |
1798 cc.finallyret = 0; | |
1799 else | |
1800 { // The rest of any unwinding is already done | |
1801 return null; | |
1802 } | |
1803 } | |
1804 goto Lnext; | |
1805 | |
1806 case IRfinallyret: | |
1807 cc.finallyret = 1; | |
1808 case IRret: | |
1809 version (SCOPECACHE_LOG) | |
1810 printf("scopecache_cnt = %d\n", scopecache_cnt); | |
1811 return null; | |
1812 | |
1813 case IRretexp: | |
1814 a = GETa(code); | |
1815 Value.copy(ret, a); | |
1816 //writef("returns: %s\n", ret.toString()); | |
1817 return null; | |
1818 | |
1819 case IRimpret: | |
1820 a = GETa(code); | |
1821 Value.copy(ret, a); | |
1822 //writef("implicit return: %s\n", ret.toString()); | |
1823 code += 2; | |
1824 goto Lnext; | |
1825 | |
1826 case IRthrow: | |
1827 a = GETa(code); | |
1828 cc.linnum = GETlinnum(code); | |
1829 Lthrow: | |
1830 //writef("Lthrow: linnum = %d\n", GETlinnum(code)); | |
1831 a.getErrInfo(null, GETlinnum(code)); | |
1832 SCOPECACHE_CLEAR(); | |
1833 for (;;) | |
1834 { | |
1835 if (scopex.length <= dimsave) | |
1836 { | |
1837 ret.putVundefined(); | |
1838 // 'a' may be pointing into the stack, which means | |
1839 // it gets scrambled on return. Therefore, we copy | |
1840 // its contents into a safe area in CallContext. | |
1841 assert(cc.value.sizeof == Value.sizeof); | |
1842 Value.copy(cast(Value*)cc.value, a); | |
1843 return cast(Value*)cc.value; | |
1844 } | |
1845 o = scopex[length - 1]; | |
1846 scopex = scopex[0 .. length - 1]; // pop entry off scope chain | |
1847 if (o.isCatch()) | |
1848 { ca = cast(Catch)o; | |
1849 //writef("catch('%s')\n", ca.name); | |
1850 o = new Dobject(Dobject.getPrototype()); | |
1851 version (JSCRIPT_CATCH_BUG) | |
1852 { | |
1853 PutValue(cc, ca.name, a); | |
1854 } | |
1855 else | |
1856 { | |
1857 o.Put(ca.name, a, DontDelete); | |
1858 } | |
1859 scopex ~= o; | |
1860 cc.scopex = scopex; | |
1861 code = codestart + ca.offset; | |
1862 break; | |
1863 } | |
1864 else | |
1865 { | |
1866 if (o.isFinally()) | |
1867 { | |
1868 f = cast(Finally)o; | |
1869 v = cast(Value*)call(cc, othis, f.finallyblock, ret, locals); | |
1870 if (v) | |
1871 { a = v; | |
1872 //writef("changing a\n"); | |
1873 } | |
1874 } | |
1875 } | |
1876 } | |
1877 goto Lnext; | |
1878 | |
1879 case IRtrycatch: | |
1880 SCOPECACHE_CLEAR(); | |
1881 offset = (code - codestart) + (code + 1).offset; | |
1882 s = (code + 2).id.value.string; | |
1883 ca = new Catch(offset, s); | |
1884 scopex ~= ca; | |
1885 cc.scopex = scopex; | |
1886 code += 3; | |
1887 break; | |
1888 | |
1889 case IRtryfinally: | |
1890 SCOPECACHE_CLEAR(); | |
1891 f = new Finally(code + (code + 1).offset); | |
1892 scopex ~= f; | |
1893 cc.scopex = scopex; | |
1894 code += 2; | |
1895 break; | |
1896 | |
1897 case IRassert: | |
1898 { | |
1899 ErrInfo errinfo; | |
1900 errinfo.linnum = (code + 1).index; | |
1901 version (all) // Not supported under some com servers | |
1902 { | |
1903 a = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_ASSERT], (code + 1).index); | |
1904 goto Lthrow; | |
1905 } | |
1906 else | |
1907 { | |
1908 RuntimeErrorx(ERR_ASSERT, (code + 1).index); | |
1909 } | |
1910 code += 2; | |
1911 break; | |
1912 } | |
1913 | |
1914 default: | |
1915 //writef("1: Unrecognized IR instruction %d\n", code.opcode); | |
1916 assert(0); // unrecognized IR instruction | |
1917 } | |
1918 } | |
1919 | |
1920 Linterrupt: | |
1921 ret.putVundefined(); | |
1922 return null; | |
1923 } | |
1924 | |
1925 /******************************************* | |
1926 * This is a 'disassembler' for our interpreted code. | |
1927 * Useful for debugging. | |
1928 */ | |
1929 | |
1930 static void print(uint address, IR *code) | |
1931 { | |
1932 switch (code.opcode) | |
1933 { | |
1934 case IRerror: | |
1935 writef("\tIRerror\n"); | |
1936 break; | |
1937 | |
1938 case IRnop: | |
1939 writef("\tIRnop\n"); | |
1940 break; | |
1941 | |
1942 case IRend: | |
1943 writef("\tIRend\n"); | |
1944 break; | |
1945 | |
1946 case IRget: // a = b.c | |
1947 writef("\tIRget %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
1948 break; | |
1949 | |
1950 case IRput: // b.c = a | |
1951 writef("\tIRput %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
1952 break; | |
1953 | |
1954 case IRgets: // a = b.s | |
1955 writef("\tIRgets %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string); | |
1956 break; | |
1957 | |
1958 case IRgetscope: // a = othis.ident | |
1959 writef("\tIRgetscope %d, '%s', hash=%d\n",(code + 1).index,(code + 2).id.value.string,(code + 2).id.value.hash); | |
1960 break; | |
1961 | |
1962 case IRaddass: // b.c += a | |
1963 writef("\tIRaddass %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
1964 break; | |
1965 | |
1966 case IRaddasss: // b.s += a | |
1967 writef("\tIRaddasss %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string); | |
1968 break; | |
1969 | |
1970 case IRaddassscope: // othis.ident += a | |
1971 writef("\tIRaddassscope %d, '%s', hash=%d\n",(code + 1).index,(code + 2).id.value.string,(code + 3).index); | |
1972 break; | |
1973 | |
1974 case IRputs: // b.s = a | |
1975 writef("\tIRputs %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string); | |
1976 break; | |
1977 | |
1978 case IRputscope: // s = a | |
1979 writef("\tIRputscope %d, '%s'\n",(code + 1).index, (code + 2).id.value.string); | |
1980 break; | |
1981 | |
1982 case IRputdefault: // b = a | |
1983 writef("\tIRputdefault %d, %d\n",(code + 1).index, (code + 2).index); | |
1984 break; | |
1985 | |
1986 case IRputthis: // b = s | |
1987 writef("\tIRputthis '%s', %d\n",(code + 2).id.value.string,(code + 1).index); | |
1988 break; | |
1989 | |
1990 case IRmov: // a = b | |
1991 writef("\tIRmov %d, %d\n", (code + 1).index, (code + 2).index); | |
1992 break; | |
1993 | |
1994 case IRstring: // a = "string" | |
1995 writef("\tIRstring %d, '%s'\n",(code + 1).index,(code + 2).id.value.string); | |
1996 break; | |
1997 | |
1998 case IRobject: // a = object | |
1999 writef("\tIRobject %d, %x\n",(code + 1).index,cast(void*)(code + 2).object); | |
2000 break; | |
2001 | |
2002 case IRthis: // a = this | |
2003 writef("\tIRthis %d\n",(code + 1).index); | |
2004 break; | |
2005 | |
2006 case IRnumber: // a = number | |
2007 writef("\tIRnumber %d, %g\n",(code + 1).index,*cast(d_number *)(code + 2)); | |
2008 break; | |
2009 | |
2010 case IRboolean: // a = boolean | |
2011 writef("\tIRboolean %d, %d\n",(code + 1).index, (code + 2).boolean); | |
2012 break; | |
2013 | |
2014 case IRnull: // a = null | |
2015 writef("\tIRnull %d\n",(code + 1).index); | |
2016 break; | |
2017 | |
2018 case IRundefined: // a = undefined | |
2019 writef("\tIRundefined %d\n",(code + 1).index); | |
2020 break; | |
2021 | |
2022 case IRthisget: // a = othis.ident | |
2023 writef("\tIRthisget %d, '%s'\n",(code + 1).index,(code + 2).id.value.string); | |
2024 break; | |
2025 | |
2026 case IRneg: // a = -a | |
2027 writef("\tIRneg %d\n",(code + 1).index); | |
2028 break; | |
2029 | |
2030 case IRpos: // a = a | |
2031 writef("\tIRpos %d\n",(code + 1).index); | |
2032 break; | |
2033 | |
2034 case IRcom: // a = ~a | |
2035 writef("\tIRcom %d\n",(code + 1).index); | |
2036 break; | |
2037 | |
2038 case IRnot: // a = !a | |
2039 writef("\tIRnot %d\n",(code + 1).index); | |
2040 break; | |
2041 | |
2042 case IRtypeof: // a = typeof a | |
2043 writef("\tIRtypeof %d\n", (code + 1).index); | |
2044 break; | |
2045 | |
2046 case IRinstance: // a = b instanceof c | |
2047 writef("\tIRinstance %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index); | |
2048 break; | |
2049 | |
2050 case IRadd: // a = b + c | |
2051 writef("\tIRadd %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2052 break; | |
2053 | |
2054 case IRsub: // a = b - c | |
2055 writef("\tIRsub %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2056 break; | |
2057 | |
2058 case IRmul: // a = b * c | |
2059 writef("\tIRmul %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2060 break; | |
2061 | |
2062 case IRdiv: // a = b / c | |
2063 writef("\tIRdiv %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2064 break; | |
2065 | |
2066 case IRmod: // a = b % c | |
2067 writef("\tIRmod %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2068 break; | |
2069 | |
2070 case IRshl: // a = b << c | |
2071 writef("\tIRshl %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2072 break; | |
2073 | |
2074 case IRshr: // a = b >> c | |
2075 writef("\tIRshr %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2076 break; | |
2077 | |
2078 case IRushr: // a = b >>> c | |
2079 writef("\tIRushr %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2080 break; | |
2081 | |
2082 case IRand: // a = b & c | |
2083 writef("\tIRand %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2084 break; | |
2085 | |
2086 case IRor: // a = b | c | |
2087 writef("\tIRor %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2088 break; | |
2089 | |
2090 case IRxor: // a = b ^ c | |
2091 writef("\tIRxor %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2092 break; | |
2093 | |
2094 case IRpreinc: // a = ++b.c | |
2095 writef("\tIRpreinc %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2096 break; | |
2097 | |
2098 case IRpreincs: // a = ++b.s | |
2099 writef("\tIRpreincs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string); | |
2100 break; | |
2101 | |
2102 case IRpreincscope: // a = ++s | |
2103 writef("\tIRpreincscope %d, '%s', hash=%d\n",(code + 1).index, (code + 2).id.value.string, (code + 3).hash); | |
2104 break; | |
2105 | |
2106 case IRpredec: // a = --b.c | |
2107 writef("\tIRpredec %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2108 break; | |
2109 | |
2110 case IRpredecs: // a = --b.s | |
2111 writef("\tIRpredecs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string); | |
2112 break; | |
2113 | |
2114 case IRpredecscope: // a = --s | |
2115 writef("\tIRpredecscope %d, '%s', hash=%d\n",(code + 1).index, (code + 2).id.value.string, (code + 3).hash); | |
2116 break; | |
2117 | |
2118 case IRpostinc: // a = b.c++ | |
2119 writef("\tIRpostinc %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2120 break; | |
2121 | |
2122 case IRpostincs: // a = b.s++ | |
2123 writef("\tIRpostincs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string); | |
2124 break; | |
2125 | |
2126 case IRpostincscope: // a = s++ | |
2127 writef("\tIRpostincscope %d, %s\n",(code + 1).index, (code + 2).id.value.string); | |
2128 break; | |
2129 | |
2130 case IRpostdec: // a = b.c-- | |
2131 writef("\tIRpostdec %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2132 break; | |
2133 | |
2134 case IRpostdecs: // a = b.s-- | |
2135 writef("\tIRpostdecs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string); | |
2136 break; | |
2137 | |
2138 case IRpostdecscope: // a = s-- | |
2139 writef("\tIRpostdecscope %d, %s\n",(code + 1).index, (code + 2).id.value.string); | |
2140 break; | |
2141 | |
2142 case IRdel: // a = delete b.c | |
2143 writef("\tIRdel %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2144 break; | |
2145 | |
2146 case IRdels: // a = delete b.s | |
2147 writef("\tIRdels %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string); | |
2148 break; | |
2149 | |
2150 case IRdelscope: // a = delete s | |
2151 writef("\tIRdelscope %d, '%s'\n",(code + 1).index, (code + 2).id.value.string); | |
2152 break; | |
2153 | |
2154 case IRclt: // a = (b < c) | |
2155 writef("\tIRclt %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2156 break; | |
2157 | |
2158 case IRcle: // a = (b <= c) | |
2159 writef("\tIRcle %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2160 break; | |
2161 | |
2162 case IRcgt: // a = (b > c) | |
2163 writef("\tIRcgt %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2164 break; | |
2165 | |
2166 case IRcge: // a = (b >= c) | |
2167 writef("\tIRcge %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2168 break; | |
2169 | |
2170 case IRceq: // a = (b == c) | |
2171 writef("\tIRceq %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2172 break; | |
2173 | |
2174 case IRcne: // a = (b != c) | |
2175 writef("\tIRcne %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2176 break; | |
2177 | |
2178 case IRcid: // a = (b === c) | |
2179 writef("\tIRcid %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2180 break; | |
2181 | |
2182 case IRcnid: // a = (b !== c) | |
2183 writef("\tIRcnid %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index); | |
2184 break; | |
2185 | |
2186 case IRjt: // if (b) goto t | |
2187 writef("\tIRjt %d, %d\n", (code + 1).index + address, (code + 2).index); | |
2188 break; | |
2189 | |
2190 case IRjf: // if (!b) goto t | |
2191 writef("\tIRjf %d, %d\n", (code + 1).index + address, (code + 2).index); | |
2192 break; | |
2193 | |
2194 case IRjtb: // if (b) goto t | |
2195 writef("\tIRjtb %d, %d\n", (code + 1).index + address, (code + 2).index); | |
2196 break; | |
2197 | |
2198 case IRjfb: // if (!b) goto t | |
2199 writef("\tIRjfb %d, %d\n", (code + 1).index + address, (code + 2).index); | |
2200 break; | |
2201 | |
2202 case IRjmp: | |
2203 writef("\tIRjmp %d\n", (code + 1).offset + address); | |
2204 break; | |
2205 | |
2206 case IRjlt: // if (b < c) goto t | |
2207 writef("\tIRjlt %d, %d, %d\n",(code + 1).index + address, (code + 2).index, (code + 3).index); | |
2208 break; | |
2209 | |
2210 case IRjle: // if (b <= c) goto t | |
2211 writef("\tIRjle %d, %d, %d\n",(code + 1).index + address, (code + 2).index, (code + 3).index); | |
2212 break; | |
2213 | |
2214 case IRjltc: // if (b < constant) goto t | |
2215 writef("\tIRjltc %d, %d, %g\n",(code + 1).index + address, (code + 2).index, *cast(d_number *)(code + 3)); | |
2216 break; | |
2217 | |
2218 case IRjlec: // if (b <= constant) goto t | |
2219 writef("\tIRjlec %d, %d, %g\n",(code + 1).index + address, (code + 2).index, *cast(d_number *)(code + 3)); | |
2220 break; | |
2221 | |
2222 case IRiter: // a = iter(b) | |
2223 writef("\tIRiter %d, %d\n",(code + 1).index, (code + 2).index); | |
2224 break; | |
2225 | |
2226 case IRnext: // a, b.c, iter | |
2227 writef("\tIRnext %d, %d, %d, %d\n", | |
2228 (code + 1).index, | |
2229 (code + 2).index, | |
2230 (code + 3).index, | |
2231 (code + 4).index); | |
2232 break; | |
2233 | |
2234 case IRnexts: // a, b.s, iter | |
2235 writef("\tIRnexts %d, %d, '%s', %d\n", | |
2236 (code + 1).index, | |
2237 (code + 2).index, | |
2238 (code + 3).id.value.string, | |
2239 (code + 4).index); | |
2240 break; | |
2241 | |
2242 case IRnextscope: // a, s, iter | |
2243 writef | |
2244 ("\tIRnextscope %d, '%s', %d\n", | |
2245 (code + 1).index, | |
2246 (code + 2).id.value.string, | |
2247 (code + 3).index); | |
2248 break; | |
2249 | |
2250 case IRcall: // a = b.c(argc, argv) | |
2251 writef("\tIRcall %d,%d,%d, argc=%d, argv=%d \n", | |
2252 (code + 1).index, | |
2253 (code + 2).index, | |
2254 (code + 3).index, | |
2255 (code + 4).index, | |
2256 (code + 5).index); | |
2257 break; | |
2258 | |
2259 case IRcalls: // a = b.s(argc, argv) | |
2260 writef | |
2261 ("\tIRcalls %d,%d,'%s', argc=%d, argv=%d \n", | |
2262 (code + 1).index, | |
2263 (code + 2).index, | |
2264 (code + 3).id.value.string, | |
2265 (code + 4).index, | |
2266 (code + 5).index); | |
2267 break; | |
2268 | |
2269 case IRcallscope: // a = s(argc, argv) | |
2270 writef | |
2271 ("\tIRcallscope %d,'%s', argc=%d, argv=%d \n", | |
2272 (code + 1).index, | |
2273 (code + 2).id.value.string, | |
2274 (code + 3).index, | |
2275 (code + 4).index); | |
2276 break; | |
2277 | |
2278 case IRputcall: // a = b.c(argc, argv) | |
2279 writef("\tIRputcall %d,%d,%d, argc=%d, argv=%d \n", | |
2280 (code + 1).index, | |
2281 (code + 2).index, | |
2282 (code + 3).index, | |
2283 (code + 4).index, | |
2284 (code + 5).index); | |
2285 break; | |
2286 | |
2287 case IRputcalls: // a = b.s(argc, argv) | |
2288 writef | |
2289 ("\tIRputcalls %d,%d,'%s', argc=%d, argv=%d \n", | |
2290 (code + 1).index, | |
2291 (code + 2).index, | |
2292 (code + 3).id.value.string, | |
2293 (code + 4).index, | |
2294 (code + 5).index); | |
2295 break; | |
2296 | |
2297 case IRputcallscope: // a = s(argc, argv) | |
2298 writef | |
2299 ("\tIRputcallscope %d,'%s', argc=%d, argv=%d \n", | |
2300 (code + 1).index, | |
2301 (code + 2).id.value.string, | |
2302 (code + 3).index, | |
2303 (code + 4).index); | |
2304 break; | |
2305 | |
2306 case IRcallv: // a = v(argc, argv) | |
2307 writef("\tIRcallv %d, %d(argc=%d, argv=%d)\n", | |
2308 (code + 1).index, | |
2309 (code + 2).index, | |
2310 (code + 3).index, | |
2311 (code + 4).index); | |
2312 break; | |
2313 | |
2314 case IRputcallv: // a = v(argc, argv) | |
2315 writef("\tIRputcallv %d, %d(argc=%d, argv=%d)\n", | |
2316 (code + 1).index, | |
2317 (code + 2).index, | |
2318 (code + 3).index, | |
2319 (code + 4).index); | |
2320 break; | |
2321 | |
2322 case IRnew: // a = new b(argc, argv) | |
2323 writef("\tIRnew %d,%d, argc=%d, argv=%d \n", | |
2324 (code + 1).index, | |
2325 (code + 2).index, | |
2326 (code + 3).index, | |
2327 (code + 4).index); | |
2328 break; | |
2329 | |
2330 case IRpush: | |
2331 writef("\tIRpush %d\n",(code + 1).index); | |
2332 break; | |
2333 | |
2334 case IRpop: | |
2335 writef("\tIRpop\n"); | |
2336 break; | |
2337 | |
2338 case IRret: | |
2339 writef("\tIRret\n"); | |
2340 return; | |
2341 | |
2342 case IRretexp: | |
2343 writef("\tIRretexp %d\n",(code + 1).index); | |
2344 return; | |
2345 | |
2346 case IRimpret: | |
2347 writef("\tIRimpret %d\n",(code + 1).index); | |
2348 return; | |
2349 | |
2350 case IRthrow: | |
2351 writef("\tIRthrow %d\n",(code + 1).index); | |
2352 break; | |
2353 | |
2354 case IRassert: | |
2355 writef("\tIRassert %d\n",(code + 1).index); | |
2356 break; | |
2357 | |
2358 case IRtrycatch: | |
2359 writef("\tIRtrycatch %d, '%s'\n", (code + 1).offset + address, (code + 2).id.value.string); | |
2360 break; | |
2361 | |
2362 case IRtryfinally: | |
2363 writef("\tIRtryfinally %d\n", (code + 1).offset + address); | |
2364 break; | |
2365 | |
2366 case IRfinallyret: | |
2367 writef("\tIRfinallyret\n"); | |
2368 break; | |
2369 | |
2370 default: | |
2371 writef("2: Unrecognized IR instruction %d\n", code.opcode); | |
2372 assert(0); // unrecognized IR instruction | |
2373 } | |
2374 } | |
2375 | |
2376 /********************************* | |
2377 * Give size of opcode. | |
2378 */ | |
2379 | |
2380 static uint size(uint opcode) | |
2381 { uint sz = 9999; | |
2382 | |
2383 switch (opcode) | |
2384 { | |
2385 case IRerror: | |
2386 case IRnop: | |
2387 case IRend: | |
2388 sz = 1; | |
2389 break; | |
2390 | |
2391 case IRget: // a = b.c | |
2392 case IRaddass: | |
2393 sz = 4; | |
2394 break; | |
2395 | |
2396 case IRput: // b.c = a | |
2397 sz = 4; | |
2398 break; | |
2399 | |
2400 case IRgets: // a = b.s | |
2401 case IRaddasss: | |
2402 sz = 4; | |
2403 break; | |
2404 | |
2405 case IRgetscope: // a = s | |
2406 sz = 3; | |
2407 break; | |
2408 | |
2409 case IRaddassscope: | |
2410 sz = 4; | |
2411 break; | |
2412 | |
2413 case IRputs: // b.s = a | |
2414 sz = 4; | |
2415 break; | |
2416 | |
2417 case IRputscope: // s = a | |
2418 case IRputdefault: // b = a | |
2419 sz = 3; | |
2420 break; | |
2421 | |
2422 case IRputthis: // a = s | |
2423 sz = 3; | |
2424 break; | |
2425 | |
2426 case IRmov: // a = b | |
2427 sz = 3; | |
2428 break; | |
2429 | |
2430 case IRstring: // a = "string" | |
2431 sz = 3; | |
2432 break; | |
2433 | |
2434 case IRobject: // a = object | |
2435 sz = 3; | |
2436 break; | |
2437 | |
2438 case IRthis: // a = this | |
2439 sz = 2; | |
2440 break; | |
2441 | |
2442 case IRnumber: // a = number | |
2443 sz = 4; | |
2444 break; | |
2445 | |
2446 case IRboolean: // a = boolean | |
2447 sz = 3; | |
2448 break; | |
2449 | |
2450 case IRnull: // a = null | |
2451 sz = 2; | |
2452 break; | |
2453 | |
2454 case IRundefined: // a = undefined | |
2455 sz = 2; | |
2456 break; | |
2457 | |
2458 case IRthisget: // a = othis.ident | |
2459 sz = 3; | |
2460 break; | |
2461 | |
2462 case IRneg: // a = -a | |
2463 case IRpos: // a = a | |
2464 case IRcom: // a = ~a | |
2465 case IRnot: // a = !a | |
2466 case IRtypeof: // a = typeof a | |
2467 sz = 2; | |
2468 break; | |
2469 | |
2470 case IRinstance: // a = b instanceof c | |
2471 case IRadd: // a = b + c | |
2472 case IRsub: // a = b - c | |
2473 case IRmul: // a = b * c | |
2474 case IRdiv: // a = b / c | |
2475 case IRmod: // a = b % c | |
2476 case IRshl: // a = b << c | |
2477 case IRshr: // a = b >> c | |
2478 case IRushr: // a = b >>> c | |
2479 case IRand: // a = b & c | |
2480 case IRor: // a = b | c | |
2481 case IRxor: // a = b ^ c | |
2482 sz = 4; | |
2483 break; | |
2484 | |
2485 case IRpreinc: // a = ++b.c | |
2486 case IRpreincs: // a = ++b.s | |
2487 case IRpredec: // a = --b.c | |
2488 case IRpredecs: // a = --b.s | |
2489 case IRpostinc: // a = b.c++ | |
2490 case IRpostincs: // a = b.s++ | |
2491 case IRpostdec: // a = b.c-- | |
2492 case IRpostdecs: // a = b.s-- | |
2493 sz = 4; | |
2494 break; | |
2495 | |
2496 case IRpostincscope: // a = s++ | |
2497 case IRpostdecscope: // a = s-- | |
2498 sz = 3; | |
2499 break; | |
2500 | |
2501 case IRpreincscope: // a = ++s | |
2502 case IRpredecscope: // a = --s | |
2503 sz = 4; | |
2504 break; | |
2505 | |
2506 case IRdel: // a = delete b.c | |
2507 case IRdels: // a = delete b.s | |
2508 sz = 4; | |
2509 break; | |
2510 | |
2511 case IRdelscope: // a = delete s | |
2512 sz = 3; | |
2513 break; | |
2514 | |
2515 case IRclt: // a = (b < c) | |
2516 case IRcle: // a = (b <= c) | |
2517 case IRcgt: // a = (b > c) | |
2518 case IRcge: // a = (b >= c) | |
2519 case IRceq: // a = (b == c) | |
2520 case IRcne: // a = (b != c) | |
2521 case IRcid: // a = (b === c) | |
2522 case IRcnid: // a = (b !== c) | |
2523 case IRjlt: // if (b < c) goto t | |
2524 case IRjle: // if (b <= c) goto t | |
2525 sz = 4; | |
2526 break; | |
2527 | |
2528 case IRjltc: // if (b < constant) goto t | |
2529 case IRjlec: // if (b <= constant) goto t | |
2530 sz = 5; | |
2531 break; | |
2532 | |
2533 case IRjt: // if (b) goto t | |
2534 case IRjf: // if (!b) goto t | |
2535 case IRjtb: // if (b) goto t | |
2536 case IRjfb: // if (!b) goto t | |
2537 sz = 3; | |
2538 break; | |
2539 | |
2540 case IRjmp: | |
2541 sz = 2; | |
2542 break; | |
2543 | |
2544 case IRiter: // a = iter(b) | |
2545 sz = 3; | |
2546 break; | |
2547 | |
2548 case IRnext: // a, b.c, iter | |
2549 case IRnexts: // a, b.s, iter | |
2550 sz = 5; | |
2551 break; | |
2552 | |
2553 case IRnextscope: // a, s, iter | |
2554 sz = 4; | |
2555 break; | |
2556 | |
2557 case IRcall: // a = b.c(argc, argv) | |
2558 case IRcalls: // a = b.s(argc, argv) | |
2559 case IRputcall: // b.c(argc, argv) = a | |
2560 case IRputcalls: // b.s(argc, argv) = a | |
2561 sz = 6; | |
2562 break; | |
2563 | |
2564 case IRcallscope: // a = s(argc, argv) | |
2565 case IRputcallscope: // s(argc, argv) = a | |
2566 case IRcallv: | |
2567 case IRputcallv: | |
2568 sz = 5; | |
2569 break; | |
2570 | |
2571 case IRnew: // a = new b(argc, argv) | |
2572 sz = 5; | |
2573 break; | |
2574 | |
2575 case IRpush: | |
2576 sz = 2; | |
2577 break; | |
2578 | |
2579 case IRpop: | |
2580 sz = 1; | |
2581 break; | |
2582 | |
2583 case IRfinallyret: | |
2584 case IRret: | |
2585 sz = 1; | |
2586 break; | |
2587 | |
2588 case IRretexp: | |
2589 case IRimpret: | |
2590 case IRthrow: | |
2591 sz = 2; | |
2592 break; | |
2593 | |
2594 case IRtrycatch: | |
2595 sz = 3; | |
2596 break; | |
2597 | |
2598 case IRtryfinally: | |
2599 sz = 2; | |
2600 break; | |
2601 | |
2602 case IRassert: | |
2603 sz = 2; | |
2604 break; | |
2605 | |
2606 default: | |
2607 writef("3: Unrecognized IR instruction %d, IRMAX = %d\n", opcode, IRMAX); | |
2608 assert(0); // unrecognized IR instruction | |
2609 } | |
2610 assert(sz <= 6); | |
2611 return sz; | |
2612 } | |
2613 | |
2614 static void printfunc(IR *code) | |
2615 { | |
2616 IR *codestart = code; | |
2617 | |
2618 for (;;) | |
2619 { | |
2620 writef("%2d(%d):", code - codestart, code.linnum); | |
2621 print(code - codestart, code); | |
2622 if (code.opcode == IRend) | |
2623 return; | |
2624 code += size(code.opcode); | |
2625 } | |
2626 } | |
2627 | |
2628 /*************************************** | |
2629 * Verify that it is a correct sequence of code. | |
2630 * Useful for isolating memory corruption bugs. | |
2631 */ | |
2632 | |
2633 static uint verify(uint linnum, IR *codestart) | |
2634 { | |
2635 debug (VERIFY) | |
2636 { | |
2637 uint checksum = 0; | |
2638 uint sz; | |
2639 uint i; | |
2640 IR *code; | |
2641 | |
2642 // Verify code | |
2643 for (code = codestart;;) | |
2644 { | |
2645 switch (code.opcode) | |
2646 { | |
2647 case IRend: | |
2648 return checksum; | |
2649 | |
2650 case IRerror: | |
2651 writef("verify failure line %u\n", linnum); | |
2652 assert(0); | |
2653 break; | |
2654 | |
2655 default: | |
2656 if (code.opcode >= IRMAX) | |
2657 { writef("undefined opcode %d in code %p\n", code.opcode, codestart); | |
2658 assert(0); | |
2659 } | |
2660 sz = IR.size(code.opcode); | |
2661 for (i = 0; i < sz; i++) | |
2662 { checksum += code.opcode; | |
2663 code++; | |
2664 } | |
2665 break; | |
2666 } | |
2667 } | |
2668 } | |
2669 else | |
2670 return 0; | |
2671 } | |
2672 } |