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 }