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