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(uint offset, d_string name)
71     {
72         super(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(IR * finallyblock)
101     {
102         super(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(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();
265             o.Put(s, a, 0);
266             break;
267         }
268         if(d == cc.globalroot)
269         {
270             o.Put(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();
303                 break;// Overwrite existing property with new one
304             }
305             if(d == cc.globalroot)
306                 break;
307         }
308     }
309     o.Put(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, int linnum)
318 {
319     ErrInfo errinfo;
320 
321     errinfo.linnum = linnum;
322     if(b.isUndefinedOrNull())
323     {
324         b = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT4],
325                                  b.getType());
326     }
327     else
328     {
329         b = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT2],
330                                  b.getType(), b.toString());
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(Dobject.getPrototype());
450                         version(JSCRIPT_CATCH_BUG)
451                         {
452                             PutValue(cc, ca.name, a);
453                         }
454                         else
455                         {
456                             o.Put(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();
645                     if(!o)
646                     {
647                         a = cannotConvert(b, 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();
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(cast(d_uint32)i32, c, a, 0);
680                         else
681                             a = b.Put(cast(d_uint32)i32, c, a);
682                     }
683                     else
684                     {
685                         s = c.toString();
686                         a = b.Put(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();
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                                                  errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT3],
704                                                  b.getType(), b.toString(),
705                                                  s);
706                         goto Lthrow;
707                     }
708                     v = o.Get(s);
709                     if(!v)
710                     {
711                         //writef("IRgets: %s.%s is undefined\n", b.getType(), d_string_ptr(s));
712                         v = &vundefined;
713                     }
714                     Value.copy(a, v);
715                     code += 4;
716                     goto Lnext;
717                 case IRcheckref: // s
718 	                id = (code+1).id;
719 	                s = id.value..string;
720 	                if(!scope_get(scopex, id))
721 		                throw new ErrorValue(Dobject.ReferenceError(errmsgtbl[ERR_UNDEFINED_VAR],s)); 
722 	                code += 2;
723 	                break;
724                 case IRgetscope:            // a = s
725                     a = GETa(code);
726                     id = (code + 2).id;
727                     s = id.value..string;
728                     version(SCOPECACHING)
729                     {
730                         si = SCOPECACHE_SI(s.ptr);
731                         if(s is scopecache[si].s)
732                         {
733                             version(SCOPECACHE_LOG)
734                                 scopecache_cnt++;
735                             Value.copy(a, scopecache[si].v);
736                             code += 3;
737                             break;
738                         }
739                         //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);
740                     }
741                     version(all)
742                     {
743                         v = scope_get(scopex,id);
744                         if(!v){
745                             v = signalingUndefined(s);
746                             PutValue(cc,id,v);
747                         }
748                         else
749                         {
750                             version(SCOPECACHING)
751                             {
752                                 if(1) //!o.isDcomobject())
753                                 {
754                                     scopecache[si].s = s;
755                                     scopecache[si].v = v;
756                                 }
757                             }
758                         }
759                     }
760                     //writef("v = %p\n", v);
761                     //writef("v = %g\n", v.toNumber());
762                     //writef("v = %s\n", d_string_ptr(v.toString()));
763                     Value.copy(a, v);
764                     code += 3;
765                     break;
766 
767                 case IRaddass:              // a = (b.c += a)
768                     c = GETc(code);
769                     s = c.toString();
770                     goto Laddass;
771 
772                 case IRaddasss:             // a = (b.s += a)
773                     s = (code + 3).id.value..string;
774                     Laddass:
775                     b = GETb(code);
776                     v = b.Get(s);
777                     goto Laddass2;
778 
779                 case IRaddassscope:         // a = (s += a)
780                     b = null;               // Needed for the b.Put() below to shutup a compiler use-without-init warning
781                     id = (code + 2).id;
782                     s = id.value..string;
783                     version(SCOPECACHING)
784                     {
785                         si = SCOPECACHE_SI(s.ptr);
786                         if(s is scopecache[si].s)
787                             v = scopecache[si].v;
788                         else
789                             v = scope_get(scopex, id);
790                     }
791                     else
792                     {
793                         v = scope_get(scopex, id);
794                     }
795                     Laddass2:
796                     a = GETa(code);
797                     if(!v)
798                     {
799 						throw new ErrorValue(Dobject.ReferenceError(errmsgtbl[ERR_UNDEFINED_VAR],s));
800                         //a.putVundefined();
801                         /+
802                                             if (b)
803                                             {
804                                                 a = b.Put(s, v);
805                                                 //if (a) goto Lthrow;
806                                             }
807                                             else
808                                             {
809                                                 PutValue(cc, s, v);
810                                             }
811                          +/
812                     }
813                     else if(a.vtype == V_NUMBER && v.vtype == V_NUMBER)
814                     {
815                         a.number += v.number;
816                         v.number = a.number;
817                     }
818                     else
819                     {
820                         v.toPrimitive(v, null);
821                         a.toPrimitive(a, null);
822                         if(v.isString())
823                         {
824                             s2 = v.toString() ~a.toString();
825                             a.putVstring(s2);
826                             Value.copy(v, a);
827                         }
828                         else if(a.isString())
829                         {
830                             s2 = v.toString() ~a.toString();
831                             a.putVstring(s2);
832                             Value.copy(v, a);
833                         }
834                         else
835                         {
836                             a.putVnumber(a.toNumber() + v.toNumber());
837                             *v = *a;//full copy
838                         }
839                     }
840                     code += 4;
841                     break;
842 
843                 case IRputs:            // b.s = a
844                     a = GETa(code);
845                     b = GETb(code);
846                     o = b.toObject();
847                     if(!o)
848                     {
849                         a = cannotConvert(b, GETlinnum(code));
850                         goto Lthrow;
851                     }
852                     a = o.Put((code + 3).id.value..string, a, 0);
853                     if(a)
854                         goto Lthrow;
855                     code += 4;
856                     goto Lnext;
857 
858                 case IRputscope:            // s = a
859                     a = GETa(code);
860                     a.checkReference();
861                     PutValue(cc, (code + 2).id, a);
862                     code += 3;
863                     break;
864 
865                 case IRputdefault:              // b = a
866                     a = GETa(code);
867                     b = GETb(code);
868                     o = b.toObject();
869                     if(!o)
870                     {
871                         ErrInfo errinfo;
872                         a = Dobject.RuntimeError(&errinfo,
873                                                  errmsgtbl[ERR_CANNOT_ASSIGN], a.getType(),
874                                                  b.getType());
875                         goto Lthrow;
876                     }
877                     a = o.PutDefault(a);
878                     if(a)
879                         goto Lthrow;
880                     code += 3;
881                     break;
882 
883                 case IRputthis:             // s = a
884                     //a = cc.variable.Put((code + 2).id.value.string, GETa(code), DontDelete);
885                     o = scope_tos(scopex);
886                     assert(o);
887                     if(o.HasProperty((code + 2).id.value..string))
888                         a = o.Put((code+2).id.value..string,GETa(code),DontDelete);
889                     else
890                         a = cc.variable.Put((code + 2).id.value..string, GETa(code), DontDelete);
891                     if (a) goto Lthrow;
892                     code += 3;
893                     break;
894 
895                 case IRmov:                 // a = b
896                     Value.copy(GETa(code), GETb(code));
897                     code += 3;
898                     break;
899 
900                 case IRstring:              // a = "string"
901                     GETa(code).putVstring((code + 2).id.value..string);
902                     code += 3;
903                     break;
904 
905                 case IRobject:              // a = object
906                 { FunctionDefinition fd;
907                   fd = cast(FunctionDefinition)(code + 2).ptr;
908                   Dfunction fobject = new DdeclaredFunction(fd);
909                   fobject.scopex = scopex;
910                   GETa(code).putVobject(fobject);
911                   code += 3;
912                   break; }
913 
914                 case IRthis:                // a = this
915                     GETa(code).putVobject(othis);
916                     //writef("IRthis: %s, othis = %x\n", GETa(code).getType(), othis);
917                     code += 2;
918                     break;
919 
920                 case IRnumber:              // a = number
921                     GETa(code).putVnumber(*cast(d_number *)(code + 2));
922                     code += 2 + d_number.sizeof/Op.sizeof;
923                     break;
924 
925                 case IRboolean:             // a = boolean
926                     GETa(code).putVboolean((code + 2).boolean);
927                     code += 3;
928                     break;
929 
930                 case IRnull:                // a = null
931                     GETa(code).putVnull();
932                     code += 2;
933                     break;
934 
935                 case IRundefined:           // a = undefined
936                     GETa(code).putVundefined();
937                     code += 2;
938                     break;
939 
940                 case IRthisget:             // a = othis.ident
941                     a = GETa(code);
942                     v = othis.Get((code + 2).id.value..string);
943                     if(!v)
944                         v = &vundefined;
945                     Value.copy(a, v);
946                     code += 3;
947                     break;
948 
949                 case IRneg:                 // a = -a
950                     a = GETa(code);
951                     n = a.toNumber();
952                     a.putVnumber(-n);
953                     code += 2;
954                     break;
955 
956                 case IRpos:                 // a = a
957                     a = GETa(code);
958                     n = a.toNumber();
959                     a.putVnumber(n);
960                     code += 2;
961                     break;
962 
963                 case IRcom:                 // a = ~a
964                     a = GETa(code);
965                     i32 = a.toInt32();
966                     a.putVnumber(~i32);
967                     code += 2;
968                     break;
969 
970                 case IRnot:                 // a = !a
971                     a = GETa(code);
972                     a.putVboolean(!a.toBoolean());
973                     code += 2;
974                     break;
975 
976                 case IRtypeof:      // a = typeof a
977                     // ECMA 11.4.3 says that if the result of (a)
978                     // is a Reference and GetBase(a) is null,
979                     // then the result is "undefined". I don't know
980                     // what kind of script syntax will generate this.
981                     a = GETa(code);
982                     a.putVstring(a.getTypeof());
983                     code += 2;
984                     break;
985 
986                 case IRinstance:        // a = b instanceof c
987                 {
988                     Dobject co;
989 
990                     // ECMA v3 11.8.6
991 
992                     b = GETb(code);
993                     o = b.toObject();
994                     c = GETc(code);
995                     if(c.isPrimitive())
996                     {
997                         ErrInfo errinfo;
998                         a = Dobject.RuntimeError(&errinfo,
999                                                  errmsgtbl[ERR_RHS_MUST_BE_OBJECT],
1000                                                  "instanceof", c.getType());
1001                         goto Lthrow;
1002                     }
1003                     co = c.toObject();
1004                     a = GETa(code);
1005                     v = cast(Value*)co.HasInstance(a, b);
1006                     if(v)
1007                     {
1008                         a = v;
1009                         goto Lthrow;
1010                     }
1011                     code += 4;
1012                     break;
1013                 }
1014                 case IRadd:                     // a = b + c
1015                     a = GETa(code);
1016                     b = GETb(code);
1017                     c = GETc(code);
1018 
1019                     if(b.vtype == V_NUMBER && c.vtype == V_NUMBER)
1020                     {
1021                         a.putVnumber(b.number + c.number);
1022                     }
1023                     else
1024                     {
1025                         char[Value.sizeof] vtmpb;
1026                         Value* vb = cast(Value*)vtmpb;
1027                         char[Value.sizeof] vtmpc;
1028                         Value* vc = cast(Value*)vtmpc;
1029 
1030                         b.toPrimitive(vb, null);
1031                         c.toPrimitive(vc, null);
1032 
1033                         if(vb.isString() || vc.isString())
1034                         {
1035                             s = vb.toString() ~vc.toString();
1036                             a.putVstring(s);
1037                         }
1038                         else
1039                         {
1040                             a.putVnumber(vb.toNumber() + vc.toNumber());
1041                         }
1042                     }
1043 
1044                     code += 4;
1045                     break;
1046 
1047                 case IRsub:                 // a = b - c
1048                     a = GETa(code);
1049                     b = GETb(code);
1050                     c = GETc(code);
1051                     a.putVnumber(b.toNumber() - c.toNumber());
1052                     code += 4;
1053                     break;
1054 
1055                 case IRmul:                 // a = b * c
1056                     a = GETa(code);
1057                     b = GETb(code);
1058                     c = GETc(code);
1059                     a.putVnumber(b.toNumber() * c.toNumber());
1060                     code += 4;
1061                     break;
1062 
1063                 case IRdiv:                 // a = b / c
1064                     a = GETa(code);
1065                     b = GETb(code);
1066                     c = GETc(code);
1067 
1068                     //writef("%g / %g = %g\n", b.toNumber() , c.toNumber(), b.toNumber() / c.toNumber());
1069                     a.putVnumber(b.toNumber() / c.toNumber());
1070                     code += 4;
1071                     break;
1072 
1073                 case IRmod:                 // a = b % c
1074                     a = GETa(code);
1075                     b = GETb(code);
1076                     c = GETc(code);
1077                     a.putVnumber(b.toNumber() % c.toNumber());
1078                     code += 4;
1079                     break;
1080 
1081                 case IRshl:                 // a = b << c
1082                     a = GETa(code);
1083                     b = GETb(code);
1084                     c = GETc(code);
1085                     i32 = b.toInt32();
1086                     u32 = c.toUint32() & 0x1F;
1087                     i32 <<= u32;
1088                     a.putVnumber(i32);
1089                     code += 4;
1090                     break;
1091 
1092                 case IRshr:                 // a = b >> c
1093                     a = GETa(code);
1094                     b = GETb(code);
1095                     c = GETc(code);
1096                     i32 = b.toInt32();
1097                     u32 = c.toUint32() & 0x1F;
1098                     i32 >>= cast(d_int32)u32;
1099                     a.putVnumber(i32);
1100                     code += 4;
1101                     break;
1102 
1103                 case IRushr:                // a = b >>> c
1104                     a = GETa(code);
1105                     b = GETb(code);
1106                     c = GETc(code);
1107                     i32 = b.toUint32();
1108                     u32 = c.toUint32() & 0x1F;
1109                     u32 = (cast(d_uint32)i32) >> u32;
1110                     a.putVnumber(u32);
1111                     code += 4;
1112                     break;
1113 
1114                 case IRand:         // a = b & c
1115                     a = GETa(code);
1116                     b = GETb(code);
1117                     c = GETc(code);
1118                     a.putVnumber(b.toInt32() & c.toInt32());
1119                     code += 4;
1120                     break;
1121 
1122                 case IRor:          // a = b | c
1123                     a = GETa(code);
1124                     b = GETb(code);
1125                     c = GETc(code);
1126                     a.putVnumber(b.toInt32() | c.toInt32());
1127                     code += 4;
1128                     break;
1129 
1130                 case IRxor:         // a = b ^ c
1131                     a = GETa(code);
1132                     b = GETb(code);
1133                     c = GETc(code);
1134                     a.putVnumber(b.toInt32() ^ c.toInt32());
1135                     code += 4;
1136                     break;
1137 				case IRin:          // a = b in c
1138 					a = GETa(code);
1139 					b = GETb(code);
1140 					c = GETc(code);
1141 					s = b.toString();
1142 					o = c.toObject();
1143 					if(!o){
1144 						ErrInfo errinfo;
1145 						throw new ErrorValue(Dobject.RuntimeError(&errinfo,errmsgtbl[ERR_RHS_MUST_BE_OBJECT],"in",c.toString()));
1146 					}
1147 					a.putVboolean(o.HasProperty(s));
1148 					code += 4;
1149 					break;
1150 					
1151                 /********************/
1152 
1153                 case IRpreinc:     // a = ++b.c
1154                     c = GETc(code);
1155                     s = c.toString();
1156                     goto Lpreinc;
1157                 case IRpreincs:    // a = ++b.s
1158                     s = (code + 3).id.value..string;
1159                     Lpreinc:
1160                     inc = 1;
1161                     Lpre:
1162                     a = GETa(code);
1163                     b = GETb(code);
1164                     v = b.Get(s);
1165                     if(!v)
1166                         v = &vundefined;
1167                     n = v.toNumber();
1168                     a.putVnumber(n + inc);
1169                     b.Put(s, a);
1170                     code += 4;
1171                     break;
1172 
1173                 case IRpreincscope:        // a = ++s
1174                     inc = 1;
1175                     Lprescope:
1176                     a = GETa(code);
1177                     id = (code + 2).id;
1178                     s = id.value..string;
1179                     version(SCOPECACHING)
1180                     {
1181                         si = SCOPECACHE_SI(s.ptr);
1182                         if(s is scopecache[si].s)
1183                         {
1184                             v = scopecache[si].v;
1185                             n = v.toNumber() + inc;
1186                             v.putVnumber(n);
1187                             a.putVnumber(n);
1188                         }
1189                         else
1190                         {
1191                             v = scope_get(scopex, id, &o);
1192                             if(v)
1193                             {
1194                                 n = v.toNumber() + inc;
1195                                 v.putVnumber(n);
1196                                 a.putVnumber(n);
1197                             }
1198                             else
1199                             {
1200                                 //FIXED: as per ECMA v5 should throw ReferenceError
1201                                 a = Dobject.ReferenceError(errmsgtbl[ERR_UNDEFINED_VAR], s);
1202                                 //a.putVundefined();
1203                                 goto Lthrow;
1204                             }
1205                         }
1206                     }
1207                     else
1208                     {
1209                         v = scope_get(scopex, id, &o);
1210                         if(v)
1211                         {
1212                             n = v.toNumber();
1213                             v.putVnumber(n + inc);
1214                             Value.copy(a, v);
1215                         }
1216                         else
1217                              throw new ErrorValue(Dobject.ReferenceError(errmsgtbl[ERR_UNDEFINED_VAR], s));
1218                     }
1219                     code += 4;
1220                     break;
1221 
1222                 case IRpredec:     // a = --b.c
1223                     c = GETc(code);
1224                     s = c.toString();
1225                     goto Lpredec;
1226                 case IRpredecs:    // a = --b.s
1227                     s = (code + 3).id.value..string;
1228                     Lpredec:
1229                     inc = -1;
1230                     goto Lpre;
1231 
1232                 case IRpredecscope:        // a = --s
1233                     inc = -1;
1234                     goto Lprescope;
1235 
1236                 /********************/
1237 
1238                 case IRpostinc:     // a = b.c++
1239                     c = GETc(code);
1240                     s = c.toString();
1241                     goto Lpostinc;
1242                 case IRpostincs:    // a = b.s++
1243                     s = (code + 3).id.value..string;
1244                     Lpostinc:
1245                     a = GETa(code);
1246                     b = GETb(code);
1247                     v = b.Get(s);
1248                     if(!v)
1249                         v = &vundefined;
1250                     n = v.toNumber();
1251                     a.putVnumber(n + 1);
1252                     b.Put(s, a);
1253                     a.putVnumber(n);
1254                     code += 4;
1255                     break;
1256 
1257                 case IRpostincscope:        // a = s++
1258                     id = (code + 2).id;
1259                     v = scope_get(scopex, id, &o);
1260                     if(v && v != &vundefined)
1261                     {
1262                         a = GETa(code);
1263                         n = v.toNumber();
1264                         v.putVnumber(n + 1);
1265                         a.putVnumber(n);
1266                     }
1267                     else
1268                     {
1269                         //GETa(code).putVundefined();
1270                         //FIXED: as per ECMA v5 should throw ReferenceError
1271                         throw new ErrorValue(Dobject.ReferenceError(id.value..string));
1272                         //v = signalingUndefined(id.value.string);
1273                     }
1274                     code += 3;
1275                     break;
1276 
1277                 case IRpostdec:     // a = b.c--
1278                     c = GETc(code);
1279                     s = c.toString();
1280                     goto Lpostdec;
1281                 case IRpostdecs:    // a = b.s--
1282                     s = (code + 3).id.value..string;
1283                     Lpostdec:
1284                     a = GETa(code);
1285                     b = GETb(code);
1286                     v = b.Get(s);
1287                     if(!v)
1288                         v = &vundefined;
1289                     n = v.toNumber();
1290                     a.putVnumber(n - 1);
1291                     b.Put(s, a);
1292                     a.putVnumber(n);
1293                     code += 4;
1294                     break;
1295 
1296                 case IRpostdecscope:        // a = s--
1297                     id = (code + 2).id;
1298                     v = scope_get(scopex, id, &o);
1299                     if(v && v != &vundefined)
1300                     {
1301                         n = v.toNumber();
1302                         a = GETa(code);
1303                         v.putVnumber(n - 1);
1304                         a.putVnumber(n);
1305                     }
1306                     else
1307                     {
1308                         //GETa(code).putVundefined();
1309                         //FIXED: as per ECMA v5 should throw ReferenceError
1310                         throw new ErrorValue(Dobject.ReferenceError(id.value..string));
1311                         //v = signalingUndefined(id.value.string);
1312                     }
1313                     code += 3;
1314                     break;
1315 
1316                 case IRdel:     // a = delete b.c
1317                 case IRdels:    // a = delete b.s
1318                     b = GETb(code);
1319                     if(b.isPrimitive())
1320                         bo = true;
1321                     else
1322                     {
1323                         o = b.toObject();
1324                         if(!o)
1325                         {
1326                             a = cannotConvert(b, GETlinnum(code));
1327                             goto Lthrow;
1328                         }
1329                         s = (code.opcode == IRdel)
1330                             ? GETc(code).toString()
1331                             : (code + 3).id.value..string;
1332                         if(o.implementsDelete())
1333                             bo = o.Delete(s);
1334                         else
1335                             bo = !o.HasProperty(s);
1336                     }
1337                     GETa(code).putVboolean(bo);
1338                     code += 4;
1339                     break;
1340 
1341                 case IRdelscope:    // a = delete s
1342                     id = (code + 2).id;
1343                     s = id.value..string;
1344                     //o = scope_tos(scopex);		// broken way
1345                     if(!scope_get(scopex, id, &o))
1346                         bo = true;
1347                     else if(o.implementsDelete())
1348                         bo = o.Delete(s);
1349                     else
1350                         bo = !o.HasProperty(s);
1351                     GETa(code).putVboolean(bo);
1352                     code += 3;
1353                     break;
1354 
1355                 /* ECMA requires that if one of the numeric operands is NAN,
1356                  * then the result of the comparison is false. D generates a
1357                  * correct test for NAN operands.
1358                  */
1359 
1360                 case IRclt:         // a = (b <   c)
1361                     a = GETa(code);
1362                     b = GETb(code);
1363                     c = GETc(code);
1364                     if(b.vtype == V_NUMBER && c.vtype == V_NUMBER)
1365                         res = (b.number < c.number);
1366                     else
1367                     {
1368                         b.toPrimitive(b, TypeNumber);
1369                         c.toPrimitive(c, TypeNumber);
1370                         if(b.isString() && c.isString())
1371                         {
1372                             d_string x = b.toString();
1373                             d_string y = c.toString();
1374 
1375                             res = std..string.cmp(x, y) < 0;
1376                         }
1377                         else
1378                             res = b.toNumber() < c.toNumber();
1379                     }
1380                     a.putVboolean(res);
1381                     code += 4;
1382                     break;
1383 
1384                 case IRcle:         // a = (b <=  c)
1385                     a = GETa(code);
1386                     b = GETb(code);
1387                     c = GETc(code);
1388                     if(b.vtype == V_NUMBER && c.vtype == V_NUMBER)
1389                         res = (b.number <= c.number);
1390                     else
1391                     {
1392                         b.toPrimitive(b, TypeNumber);
1393                         c.toPrimitive(c, TypeNumber);
1394                         if(b.isString() && c.isString())
1395                         {
1396                             d_string x = b.toString();
1397                             d_string y = c.toString();
1398 
1399                             res = std..string.cmp(x, y) <= 0;
1400                         }
1401                         else
1402                             res = b.toNumber() <= c.toNumber();
1403                     }
1404                     a.putVboolean(res);
1405                     code += 4;
1406                     break;
1407 
1408                 case IRcgt:         // a = (b >   c)
1409                     a = GETa(code);
1410                     b = GETb(code);
1411                     c = GETc(code);
1412                     if(b.vtype == V_NUMBER && c.vtype == V_NUMBER)
1413                         res = (b.number > c.number);
1414                     else
1415                     {
1416                         b.toPrimitive(b, TypeNumber);
1417                         c.toPrimitive(c, TypeNumber);
1418                         if(b.isString() && c.isString())
1419                         {
1420                             d_string x = b.toString();
1421                             d_string y = c.toString();
1422 
1423                             res = std..string.cmp(x, y) > 0;
1424                         }
1425                         else
1426                             res = b.toNumber() > c.toNumber();
1427                     }
1428                     a.putVboolean(res);
1429                     code += 4;
1430                     break;
1431 
1432 
1433                 case IRcge:         // a = (b >=  c)
1434                     a = GETa(code);
1435                     b = GETb(code);
1436                     c = GETc(code);
1437                     if(b.vtype == V_NUMBER && c.vtype == V_NUMBER)
1438                         res = (b.number >= c.number);
1439                     else
1440                     {
1441                         b.toPrimitive(b, TypeNumber);
1442                         c.toPrimitive(c, TypeNumber);
1443                         if(b.isString() && c.isString())
1444                         {
1445                             d_string x = b.toString();
1446                             d_string y = c.toString();
1447 
1448                             res = std..string.cmp(x, y) >= 0;
1449                         }
1450                         else
1451                             res = b.toNumber() >= c.toNumber();
1452                     }
1453                     a.putVboolean(res);
1454                     code += 4;
1455                     break;
1456 
1457                 case IRceq:         // a = (b ==  c)
1458                 case IRcne:         // a = (b !=  c)
1459                     a = GETa(code);
1460                     b = GETb(code);
1461                     c = GETc(code);
1462                     Lagain:
1463                     tx = b.getType();
1464                     ty = c.getType();
1465                     if(logflag)
1466                         writef("tx('%s', '%s')\n", tx, ty);
1467                     if(tx == ty)
1468                     {
1469                         if(tx == TypeUndefined ||
1470                            tx == TypeNull)
1471                             res = true;
1472                         else if(tx == TypeNumber)
1473                         {
1474                             d_number x = b.number;
1475                             d_number y = c.number;
1476 
1477                             res = (x == y);
1478                             //writef("x = %g, y = %g, res = %d\n", x, y, res);
1479                         }
1480                         else if(tx == TypeString)
1481                         {
1482                             if(logflag)
1483                             {
1484                                 writef("b = %x, c = %x\n", b, c);
1485                                 writef("cmp('%s', '%s')\n", b..string, c..string);
1486                                 writef("cmp(%d, %d)\n", b..string.length, c..string.length);
1487                             }
1488                             res = (b..string == c..string);
1489                         }
1490                         else if(tx == TypeBoolean)
1491                             res = (b.dbool == c.dbool);
1492                         else // TypeObject
1493                         {
1494                             res = b.object == c.object;
1495                         }
1496                     }
1497                     else if(tx == TypeNull && ty == TypeUndefined)
1498                         res = true;
1499                     else if(tx == TypeUndefined && ty == TypeNull)
1500                         res = true;
1501                     else if(tx == TypeNumber && ty == TypeString)
1502                     {
1503                         c.putVnumber(c.toNumber());
1504                         goto Lagain;
1505                     }
1506                     else if(tx == TypeString && ty == TypeNumber)
1507                     {
1508                         b.putVnumber(b.toNumber());
1509                         goto Lagain;
1510                     }
1511                     else if(tx == TypeBoolean)
1512                     {
1513                         b.putVnumber(b.toNumber());
1514                         goto Lagain;
1515                     }
1516                     else if(ty == TypeBoolean)
1517                     {
1518                         c.putVnumber(c.toNumber());
1519                         goto Lagain;
1520                     }
1521                     else if(ty == TypeObject)
1522                     {
1523                         v = cast(Value*)c.toPrimitive(c, null);
1524                         if(v)
1525                         {
1526                             a = v;
1527                             goto Lthrow;
1528                         }
1529                         goto Lagain;
1530                     }
1531                     else if(tx == TypeObject)
1532                     {
1533                         v = cast(Value*)b.toPrimitive(b, null);
1534                         if(v)
1535                         {
1536                             a = v;
1537                             goto Lthrow;
1538                         }
1539                         goto Lagain;
1540                     }
1541                     else
1542                     {
1543                         res = false;
1544                     }
1545 
1546                     res ^= (code.opcode == IRcne);
1547                     //Lceq:
1548                     a.putVboolean(res);
1549                     code += 4;
1550                     break;
1551 
1552                 case IRcid:         // a = (b === c)
1553                 case IRcnid:        // a = (b !== c)
1554                     a = GETa(code);
1555                     b = GETb(code);
1556                     c = GETc(code);
1557                     version(none)
1558                     {
1559                         writeln("***\n");
1560                         print(code-codestart,code);
1561                         writeln();
1562                     }
1563                     tx = b.getType();
1564                     ty = c.getType();
1565                     if(tx == ty)
1566                     {
1567                         if(tx == TypeUndefined ||
1568                            tx == TypeNull)
1569                             res = true;
1570                         else if(tx == TypeNumber)
1571                         {
1572                             d_number x = b.number;
1573                             d_number y = c.number;
1574 
1575                             // Ensure that a NAN operand produces false
1576                             if(code.opcode == IRcid)
1577                                 res = (x == y);
1578                             else
1579                                 res = (x != y);
1580                             goto Lcid;
1581                         }
1582                         else if(tx == TypeString)
1583                             res = (b..string == c..string);
1584                         else if(tx == TypeBoolean)
1585                             res = (b.dbool == c.dbool);
1586                         else // TypeObject
1587                         {
1588                             res = b.object == c.object;
1589                         }
1590                     }
1591                     else
1592                     {
1593                         res = false;
1594                     }
1595 
1596                     res ^= (code.opcode == IRcnid);
1597                     Lcid:
1598                     a.putVboolean(res);
1599                     code += 4;
1600                     break;
1601 
1602                 case IRjt:          // if (b) goto t
1603                     b = GETb(code);
1604                     if(b.toBoolean())
1605                         code += (code + 1).offset;
1606                     else
1607                         code += 3;
1608                     break;
1609 
1610                 case IRjf:          // if (!b) goto t
1611                     b = GETb(code);
1612                     if(!b.toBoolean())
1613                         code += (code + 1).offset;
1614                     else
1615                         code += 3;
1616                     break;
1617 
1618                 case IRjtb:         // if (b) goto t
1619                     b = GETb(code);
1620                     if(b.dbool)
1621                         code += (code + 1).offset;
1622                     else
1623                         code += 3;
1624                     break;
1625 
1626                 case IRjfb:         // if (!b) goto t
1627                     b = GETb(code);
1628                     if(!b.dbool)
1629                         code += (code + 1).offset;
1630                     else
1631                         code += 3;
1632                     break;
1633 
1634                 case IRjmp:
1635                     code += (code + 1).offset;
1636                     break;
1637 
1638                 case IRjlt:         // if (b <   c) goto c
1639                     b = GETb(code);
1640                     c = GETc(code);
1641                     if(b.vtype == V_NUMBER && c.vtype == V_NUMBER)
1642                     {
1643                         if(b.number < c.number)
1644                             code += 4;
1645                         else
1646                             code += (code + 1).offset;
1647                         break;
1648                     }
1649                     else
1650                     {
1651                         b.toPrimitive(b, TypeNumber);
1652                         c.toPrimitive(c, TypeNumber);
1653                         if(b.isString() && c.isString())
1654                         {
1655                             d_string x = b.toString();
1656                             d_string y = c.toString();
1657 
1658                             res = std..string.cmp(x, y) < 0;
1659                         }
1660                         else
1661                             res = b.toNumber() < c.toNumber();
1662                     }
1663                     if(!res)
1664                         code += (code + 1).offset;
1665                     else
1666                         code += 4;
1667                     break;
1668 
1669                 case IRjle:         // if (b <=  c) goto c
1670                     b = GETb(code);
1671                     c = GETc(code);
1672                     if(b.vtype == V_NUMBER && c.vtype == V_NUMBER)
1673                     {
1674                         if(b.number <= c.number)
1675                             code += 4;
1676                         else
1677                             code += (code + 1).offset;
1678                         break;
1679                     }
1680                     else
1681                     {
1682                         b.toPrimitive(b, TypeNumber);
1683                         c.toPrimitive(c, TypeNumber);
1684                         if(b.isString() && c.isString())
1685                         {
1686                             d_string x = b.toString();
1687                             d_string y = c.toString();
1688 
1689                             res = std..string.cmp(x, y) <= 0;
1690                         }
1691                         else
1692                             res = b.toNumber() <= c.toNumber();
1693                     }
1694                     if(!res)
1695                         code += (code + 1).offset;
1696                     else
1697                         code += 4;
1698                     break;
1699 
1700                 case IRjltc:        // if (b < constant) goto c
1701                     b = GETb(code);
1702                     res = (b.toNumber() < *cast(d_number *)(code + 3));
1703                     if(!res)
1704                         code += (code + 1).offset;
1705                     else
1706                         code += 3 + d_number.sizeof/Op.sizeof;
1707                     break;
1708 
1709                 case IRjlec:        // if (b <= constant) goto c
1710                     b = GETb(code);
1711                     res = (b.toNumber() <= *cast(d_number *)(code + 3));
1712                     if(!res)
1713                         code += (code + 1).offset;
1714                     else
1715                         code += 3 + d_number.sizeof/Op.sizeof;
1716                     break;
1717 
1718                 case IRiter:                // a = iter(b)
1719                     a = GETa(code);
1720                     b = GETb(code);
1721                     o = b.toObject();
1722                     if(!o)
1723                     {
1724                         a = cannotConvert(b, GETlinnum(code));
1725                         goto Lthrow;
1726                     }
1727                     a = o.putIterator(a);
1728                     if(a)
1729                         goto Lthrow;
1730                     code += 3;
1731                     break;
1732 
1733                 case IRnext:        // a, b.c, iter
1734                                     // if (!(b.c = iter)) goto a; iter = iter.next
1735                     s = GETc(code).toString();
1736                     goto case_next;
1737 
1738                 case IRnexts:       // a, b.s, iter
1739                     s = (code + 3).id.value..string;
1740                     case_next:
1741                     iter = GETd(code).iter;
1742                     v = iter.next();
1743                     if(!v)
1744                         code += (code + 1).offset;
1745                     else
1746                     {
1747                         b = GETb(code);
1748                         b.Put(s, v);
1749                         code += 5;
1750                     }
1751                     break;
1752 
1753                 case IRnextscope:   // a, s, iter
1754                     s = (code + 2).id.value..string;
1755                     iter = GETc(code).iter;
1756                     v = iter.next();
1757                     if(!v)
1758                         code += (code + 1).offset;
1759                     else
1760                     {
1761                         o = scope_tos(scopex);
1762                         o.Put(s, v, 0);
1763                         code += 4;
1764                     }
1765                     break;
1766 
1767                 case IRcall:        // a = b.c(argc, argv)
1768                     s = GETc(code).toString();
1769                     goto case_call;
1770 
1771                 case IRcalls:       // a = b.s(argc, argv)
1772                     s = (code + 3).id.value..string;
1773                     goto case_call;
1774 
1775                     case_call:               
1776                     a = GETa(code);
1777                     b = GETb(code);
1778                     o = b.toObject();
1779                     if(!o)
1780                     {
1781                         goto Lcallerror;
1782                     }
1783                     {
1784                         //writef("v.call\n");
1785                         v = o.Get(s);
1786                         if(!v)
1787                             goto Lcallerror;
1788                         //writef("calling... '%s'\n", v.toString());
1789                         cc.callerothis = othis;
1790                         a.putVundefined();
1791                         a = cast(Value*)v.Call(cc, o, a, GETe(code)[0 .. (code + 4).index]);
1792                         //writef("regular call, a = %x\n", a);
1793                     }
1794                     debug(VERIFY)
1795                         assert(checksum == IR.verify(__LINE__, codestart));
1796                     if(a)
1797                         goto Lthrow;
1798                     code += 6;
1799                     goto Lnext;
1800 
1801                     Lcallerror:
1802                     {
1803                         //writef("%s %s.%s is undefined and has no Call method\n", b.getType(), b.toString(), s);
1804                         ErrInfo errinfo;
1805                         a = Dobject.RuntimeError(&errinfo,
1806                                                  errmsgtbl[ERR_UNDEFINED_NO_CALL3],
1807                                                  b.getType(), b.toString(),
1808                                                  s);
1809                         goto Lthrow;
1810                     }
1811 
1812                 case IRcallscope:   // a = s(argc, argv)
1813                     id = (code + 2).id;
1814                     s = id.value..string;
1815                     a = GETa(code);
1816                     v = scope_get_lambda(scopex, id, &o);
1817                     //writefln("v.toString() = '%s'", v.toString());
1818                     if(!v)
1819                     {
1820                         ErrInfo errinfo;
1821                         a = Dobject.ReferenceError(errmsgtbl[ERR_UNDEFINED_VAR],s);
1822                         //a = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_UNDEFINED_NO_CALL2], "property", s);
1823                         goto Lthrow;
1824                     }
1825                     // Should we pass othis or o? I think othis.
1826                     cc.callerothis = othis;        // pass othis to eval()
1827                     a.putVundefined();
1828                     a = cast(Value*)v.Call(cc, o, a, GETd(code)[0 .. (code + 3).index]);
1829                     //writef("callscope result = %x\n", a);
1830                     debug(VERIFY)
1831                         assert(checksum == IR.verify(__LINE__, codestart));
1832                     if(a)
1833                         goto Lthrow;
1834                     code += 5;
1835                     goto Lnext;
1836 
1837                 case IRcallv:   // v(argc, argv) = a
1838                     a = GETa(code);
1839                     b = GETb(code);
1840                     o = b.toObject();
1841                     if(!o)
1842                     {
1843                         //writef("%s %s is undefined and has no Call method\n", b.getType(), b.toString());
1844                         ErrInfo errinfo;
1845                         a = Dobject.RuntimeError(&errinfo,
1846                                                  errmsgtbl[ERR_UNDEFINED_NO_CALL2],
1847                                                  b.getType(), b.toString());
1848                         goto Lthrow;
1849                     }
1850                     cc.callerothis = othis;        // pass othis to eval()
1851                     a.putVundefined();
1852                     a = cast(Value*)o.Call(cc, o, a, GETd(code)[0 .. (code + 3).index]);
1853                     if(a)
1854                         goto Lthrow;
1855                     code += 5;
1856                     goto Lnext;
1857 
1858                 case IRputcall:        // b.c(argc, argv) = a
1859                     s = GETc(code).toString();
1860                     goto case_putcall;
1861 
1862                 case IRputcalls:       //  b.s(argc, argv) = a
1863                     s = (code + 3).id.value..string;
1864                     goto case_putcall;
1865 
1866                     case_putcall:
1867                     a = GETa(code);
1868                     b = GETb(code);
1869                     o = b.toObject();
1870                     if(!o)
1871                         goto Lcallerror;
1872                     //v = o.GetLambda(s, Value.calcHash(s));
1873                     v = o.Get(s, Value.calcHash(s));
1874                     if(!v)
1875                         goto Lcallerror;
1876                     //writef("calling... '%s'\n", v.toString());
1877                     o = v.toObject();
1878                     if(!o)
1879                     {
1880                         ErrInfo errinfo;
1881                         a = Dobject.RuntimeError(&errinfo,
1882                                                  errmsgtbl[ERR_CANNOT_ASSIGN_TO2],
1883                                                  b.getType(), s);
1884                         goto Lthrow;
1885                     }
1886                     a = cast(Value*)o.put_Value(a, GETe(code)[0 .. (code + 4).index]);
1887                     if(a)
1888                         goto Lthrow;
1889                     code += 6;
1890                     goto Lnext;
1891 
1892                 case IRputcallscope:   // a = s(argc, argv)
1893                     id = (code + 2).id;
1894                     s = id.value..string;
1895                     v = scope_get_lambda(scopex, id, &o);
1896                     if(!v)
1897                     {
1898                         ErrInfo errinfo;
1899                         a = Dobject.RuntimeError(&errinfo,
1900                                                  errmsgtbl[ERR_UNDEFINED_NO_CALL2],
1901                                                  "property", s);
1902                         goto Lthrow;
1903                     }
1904                     o = v.toObject();
1905                     if(!o)
1906                     {
1907                         ErrInfo errinfo;
1908                         a = Dobject.RuntimeError(&errinfo,
1909                                                  errmsgtbl[ERR_CANNOT_ASSIGN_TO],
1910                                                  s);
1911                         goto Lthrow;
1912                     }
1913                     a = cast(Value*)o.put_Value(GETa(code), GETd(code)[0 .. (code + 3).index]);
1914                     if(a)
1915                         goto Lthrow;
1916                     code += 5;
1917                     goto Lnext;
1918 
1919                 case IRputcallv:        // v(argc, argv) = a
1920                     b = GETb(code);
1921                     o = b.toObject();
1922                     if(!o)
1923                     {
1924                         //writef("%s %s is undefined and has no Call method\n", b.getType(), b.toString());
1925                         ErrInfo errinfo;
1926                         a = Dobject.RuntimeError(&errinfo,
1927                                                  errmsgtbl[ERR_UNDEFINED_NO_CALL2],
1928                                                  b.getType(), b.toString());
1929                         goto Lthrow;
1930                     }
1931                     a = cast(Value*)o.put_Value(GETa(code), GETd(code)[0 .. (code + 3).index]);
1932                     if(a)
1933                         goto Lthrow;
1934                     code += 5;
1935                     goto Lnext;
1936 
1937                 case IRnew: // a = new b(argc, argv)
1938                     a = GETa(code);
1939                     b = GETb(code);
1940                     a.putVundefined();
1941                     a = cast(Value*)b.Construct(cc, a, GETd(code)[0 .. (code + 3).index]);
1942                     debug(VERIFY)
1943                         assert(checksum == IR.verify(__LINE__, codestart));
1944                     if(a)
1945                         goto Lthrow;
1946                     code += 5;
1947                     goto Lnext;
1948 
1949                 case IRpush:
1950                     SCOPECACHE_CLEAR();
1951                     a = GETa(code);
1952                     o = a.toObject();
1953                     if(!o)
1954                     {
1955                         a = cannotConvert(a, GETlinnum(code));
1956                         goto Lthrow;
1957                     }
1958                     scopex ~= o;                // push entry onto scope chain
1959                     cc.scopex = scopex;
1960                     code += 2;
1961                     break;
1962 
1963                 case IRpop:
1964                     SCOPECACHE_CLEAR();
1965                     o = scopex[$ - 1];
1966                     scopex = scopex[0 .. $ - 1];        // pop entry off scope chain
1967                     cc.scopex = scopex;
1968                     // If it's a Finally, we need to execute
1969                     // the finally block
1970                     code += 1;
1971                     
1972                     if(o.isFinally())   // test could be eliminated with virtual func
1973                     {
1974                         f = cast(Finally)o;
1975                         callFinally(f);
1976                         debug(VERIFY)
1977                             assert(checksum == IR.verify(__LINE__, codestart));
1978                     }
1979 
1980                     goto Lnext;
1981 
1982                 case IRfinallyret:
1983                     assert(finallyStack.length);
1984                     code = finallyStack[$-1];
1985                     finallyStack = finallyStack[0..$-1];
1986                     goto Lnext;
1987                 case IRret:
1988                     version(SCOPECACHE_LOG)
1989                         printf("scopecache_cnt = %d\n", scopecache_cnt);
1990                     return null;
1991 
1992                 case IRretexp:
1993                     a = GETa(code);
1994                     a.checkReference();
1995                     Value.copy(ret, a);
1996                     //writef("returns: %s\n", ret.toString());
1997                     return null;
1998 
1999                 case IRimpret:
2000                     a = GETa(code);
2001                     a.checkReference();
2002                     Value.copy(ret, a);
2003                     //writef("implicit return: %s\n", ret.toString());
2004                     code += 2;
2005                     goto Lnext;
2006 
2007                 case IRthrow:
2008                     a = GETa(code);
2009                     cc.linnum = GETlinnum(code);
2010                     Lthrow:
2011                     assert(scopex[0] !is null);     
2012                     v = unwindStack(a);
2013                     if(v) 
2014                         return v;
2015                     break;
2016                 case IRtrycatch:
2017                     SCOPECACHE_CLEAR();
2018                     offset = cast(uint)(code - codestart) + (code + 1).offset;
2019                     s = (code + 2).id.value..string;
2020                     ca = new Catch(offset, s);
2021                     scopex ~= ca;
2022                     cc.scopex = scopex;
2023                     code += 3;
2024                     break;
2025 
2026                 case IRtryfinally:
2027                     SCOPECACHE_CLEAR();
2028                     f = new Finally(code + (code + 1).offset);
2029                     scopex ~= f;
2030                     cc.scopex = scopex;
2031                     code += 2;
2032                     break;
2033 
2034                 case IRassert:
2035                 {
2036                     ErrInfo errinfo;
2037                     errinfo.linnum = cast(uint)(code + 1).index;
2038                     version(all)  // Not supported under some com servers
2039                     {
2040                         a = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_ASSERT], (code + 1).index);
2041                         goto Lthrow;
2042                     }
2043                     else
2044                     {
2045                         RuntimeErrorx(ERR_ASSERT, (code + 1).index);
2046                         code += 2;
2047                         break;
2048                     }
2049                 }
2050 
2051                 default:
2052                     //writef("1: Unrecognized IR instruction %d\n", code.opcode);
2053                     assert(0);              // unrecognized IR instruction
2054                 }
2055              }
2056             catch(ErrorValue err)
2057             {
2058                 import std.stdio; writefln("ERROR: %s", err.toString());
2059                 v = unwindStack(&err.value);
2060                 if(v)//v is exception that was not caught
2061                     return v;
2062             }
2063         }
2064         
2065         Linterrupt:
2066         ret.putVundefined();
2067         return null;
2068     }
2069 
2070     /*******************************************
2071      * This is a 'disassembler' for our interpreted code.
2072      * Useful for debugging.
2073      */
2074 
2075     static void print(uint address, IR *code)
2076     {
2077         switch(code.opcode)
2078         {
2079         case IRerror:
2080             writef("\tIRerror\n");
2081             break;
2082 
2083         case IRnop:
2084             writef("\tIRnop\n");
2085             break;
2086 
2087         case IRend:
2088             writef("\tIRend\n");
2089             break;
2090 
2091         case IRget:                 // a = b.c
2092             writef("\tIRget       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2093             break;
2094 
2095         case IRput:                 // b.c = a
2096             writef("\tIRput       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2097             break;
2098 
2099         case IRgets:                // a = b.s
2100             writef("\tIRgets      %d, %d, '%s'\n", (code + 1).index, (code + 2).index, (code + 3).id.value..string);
2101             break;
2102 
2103         case IRgetscope:            // a = othis.ident
2104             writef("\tIRgetscope  %d, '%s', hash=%d\n", (code + 1).index, (code + 2).id.value..string, (code + 2).id.value.hash);
2105             break;
2106 
2107         case IRaddass:              // b.c += a
2108             writef("\tIRaddass    %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2109             break;
2110 
2111         case IRaddasss:             // b.s += a
2112             writef("\tIRaddasss   %d, %d, '%s'\n", (code + 1).index, (code + 2).index, (code + 3).id.value..string);
2113             break;
2114 
2115         case IRaddassscope:         // othis.ident += a
2116             writef("\tIRaddassscope  %d, '%s', hash=%d\n", (code + 1).index, (code + 2).id.value..string, (code + 3).index);
2117             break;
2118 
2119         case IRputs:                // b.s = a
2120             writef("\tIRputs      %d, %d, '%s'\n", (code + 1).index, (code + 2).index, (code + 3).id.value..string);
2121             break;
2122 
2123         case IRputscope:            // s = a
2124             writef("\tIRputscope  %d, '%s'\n", (code + 1).index, (code + 2).id.value..string);
2125             break;
2126 
2127         case IRputdefault:                // b = a
2128             writef("\tIRputdefault %d, %d\n", (code + 1).index, (code + 2).index);
2129             break;
2130 
2131         case IRputthis:             // b = s
2132             writef("\tIRputthis   '%s', %d\n", (code + 2).id.value..string, (code + 1).index);
2133             break;
2134 
2135         case IRmov:                 // a = b
2136             writef("\tIRmov       %d, %d\n", (code + 1).index, (code + 2).index);
2137             break;
2138 
2139         case IRstring:              // a = "string"
2140             writef("\tIRstring    %d, '%s'\n", (code + 1).index, (code + 2).id.value..string);
2141             break;
2142 
2143         case IRobject:              // a = object
2144             writef("\tIRobject    %d, %x\n", (code + 1).index, cast(void*)(code + 2).object);
2145             break;
2146 
2147         case IRthis:                // a = this
2148             writef("\tIRthis      %d\n", (code + 1).index);
2149             break;
2150 
2151         case IRnumber:              // a = number
2152             writef("\tIRnumber    %d, %g\n", (code + 1).index, *cast(d_number *)(code + 2));
2153             break;
2154 
2155         case IRboolean:             // a = boolean
2156             writef("\tIRboolean   %d, %d\n", (code + 1).index, (code + 2).boolean);
2157             break;
2158 
2159         case IRnull:                // a = null
2160             writef("\tIRnull      %d\n", (code + 1).index);
2161             break;
2162 
2163         case IRundefined:           // a = undefined
2164             writef("\tIRundefined %d\n", (code + 1).index);
2165             break;
2166 
2167         case IRthisget:             // a = othis.ident
2168             writef("\tIRthisget   %d, '%s'\n", (code + 1).index, (code + 2).id.value..string);
2169             break;
2170 
2171         case IRneg:                 // a = -a
2172             writef("\tIRneg      %d\n", (code + 1).index);
2173             break;
2174 
2175         case IRpos:                 // a = a
2176             writef("\tIRpos      %d\n", (code + 1).index);
2177             break;
2178 
2179         case IRcom:                 // a = ~a
2180             writef("\tIRcom      %d\n", (code + 1).index);
2181             break;
2182 
2183         case IRnot:                 // a = !a
2184             writef("\tIRnot      %d\n", (code + 1).index);
2185             break;
2186 
2187         case IRtypeof:              // a = typeof a
2188             writef("\tIRtypeof   %d\n", (code + 1).index);
2189             break;
2190 
2191         case IRinstance:            // a = b instanceof c
2192             writef("\tIRinstance  %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2193             break;
2194 
2195         case IRadd:                 // a = b + c
2196             writef("\tIRadd       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2197             break;
2198 
2199         case IRsub:                 // a = b - c
2200             writef("\tIRsub       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2201             break;
2202 
2203         case IRmul:                 // a = b * c
2204             writef("\tIRmul       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2205             break;
2206 
2207         case IRdiv:                 // a = b / c
2208             writef("\tIRdiv       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2209             break;
2210 
2211         case IRmod:                 // a = b % c
2212             writef("\tIRmod       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2213             break;
2214 
2215         case IRshl:                 // a = b << c
2216             writef("\tIRshl       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2217             break;
2218 
2219         case IRshr:                 // a = b >> c
2220             writef("\tIRshr       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2221             break;
2222 
2223         case IRushr:                // a = b >>> c
2224             writef("\tIRushr      %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2225             break;
2226 
2227         case IRand:                 // a = b & c
2228             writef("\tIRand       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2229             break;
2230 
2231         case IRor:                  // a = b | c
2232             writef("\tIRor        %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2233             break;
2234 
2235         case IRxor:                 // a = b ^ c
2236             writef("\tIRxor       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2237             break;
2238 			
2239         case IRin:                 // a = b in c
2240             writef("\tIRin        %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2241             break;
2242 
2243         case IRpreinc:                  // a = ++b.c
2244             writef("\tIRpreinc  %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2245             break;
2246 
2247         case IRpreincs:            // a = ++b.s
2248             writef("\tIRpreincs %d, %d, %s\n", (code + 1).index, (code + 2).index, (code + 3).id.value..string);
2249             break;
2250 
2251         case IRpreincscope:        // a = ++s
2252             writef("\tIRpreincscope %d, '%s', hash=%d\n", (code + 1).index, (code + 2).id.value..string, (code + 3).hash);
2253             break;
2254 
2255         case IRpredec:             // a = --b.c
2256             writef("\tIRpredec  %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2257             break;
2258 
2259         case IRpredecs:            // a = --b.s
2260             writef("\tIRpredecs %d, %d, %s\n", (code + 1).index, (code + 2).index, (code + 3).id.value..string);
2261             break;
2262 
2263         case IRpredecscope:        // a = --s
2264             writef("\tIRpredecscope %d, '%s', hash=%d\n", (code + 1).index, (code + 2).id.value..string, (code + 3).hash);
2265             break;
2266 
2267         case IRpostinc:     // a = b.c++
2268             writef("\tIRpostinc  %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2269             break;
2270 
2271         case IRpostincs:            // a = b.s++
2272             writef("\tIRpostincs %d, %d, %s\n", (code + 1).index, (code + 2).index, (code + 3).id.value..string);
2273             break;
2274 
2275         case IRpostincscope:        // a = s++
2276             writef("\tIRpostincscope %d, %s\n", (code + 1).index, (code + 2).id.value..string);
2277             break;
2278 
2279         case IRpostdec:             // a = b.c--
2280             writef("\tIRpostdec  %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2281             break;
2282 
2283         case IRpostdecs:            // a = b.s--
2284             writef("\tIRpostdecs %d, %d, %s\n", (code + 1).index, (code + 2).index, (code + 3).id.value..string);
2285             break;
2286 
2287         case IRpostdecscope:        // a = s--
2288             writef("\tIRpostdecscope %d, %s\n", (code + 1).index, (code + 2).id.value..string);
2289             break;
2290 
2291         case IRdel:                 // a = delete b.c
2292             writef("\tIRdel       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2293             break;
2294 
2295         case IRdels:                // a = delete b.s
2296             writef("\tIRdels      %d, %d, '%s'\n", (code + 1).index, (code + 2).index, (code + 3).id.value..string);
2297             break;
2298 
2299         case IRdelscope:            // a = delete s
2300             writef("\tIRdelscope  %d, '%s'\n", (code + 1).index, (code + 2).id.value..string);
2301             break;
2302 
2303         case IRclt:                 // a = (b <   c)
2304             writef("\tIRclt       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2305             break;
2306 
2307         case IRcle:                 // a = (b <=  c)
2308             writef("\tIRcle       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2309             break;
2310 
2311         case IRcgt:                 // a = (b >   c)
2312             writef("\tIRcgt       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2313             break;
2314 
2315         case IRcge:                 // a = (b >=  c)
2316             writef("\tIRcge       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2317             break;
2318 
2319         case IRceq:                 // a = (b ==  c)
2320             writef("\tIRceq       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2321             break;
2322 
2323         case IRcne:                 // a = (b !=  c)
2324             writef("\tIRcne       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2325             break;
2326 
2327         case IRcid:                 // a = (b === c)
2328             writef("\tIRcid       %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2329             break;
2330 
2331         case IRcnid:        // a = (b !== c)
2332             writef("\tIRcnid      %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
2333             break;
2334 
2335         case IRjt:                  // if (b) goto t
2336             writef("\tIRjt        %d, %d\n", (code + 1).index + address, (code + 2).index);
2337             break;
2338 
2339         case IRjf:                  // if (!b) goto t
2340             writef("\tIRjf        %d, %d\n", (code + 1).index + address, (code + 2).index);
2341             break;
2342 
2343         case IRjtb:                 // if (b) goto t
2344             writef("\tIRjtb       %d, %d\n", (code + 1).index + address, (code + 2).index);
2345             break;
2346 
2347         case IRjfb:                 // if (!b) goto t
2348             writef("\tIRjfb       %d, %d\n", (code + 1).index + address, (code + 2).index);
2349             break;
2350 
2351         case IRjmp:
2352             writef("\tIRjmp       %d\n", (code + 1).offset + address);
2353             break;
2354 
2355         case IRjlt:                 // if (b < c) goto t
2356             writef("\tIRjlt       %d, %d, %d\n", (code + 1).index + address, (code + 2).index, (code + 3).index);
2357             break;
2358 
2359         case IRjle:                 // if (b <= c) goto t
2360             writef("\tIRjle       %d, %d, %d\n", (code + 1).index + address, (code + 2).index, (code + 3).index);
2361             break;
2362 
2363         case IRjltc:                // if (b < constant) goto t
2364             writef("\tIRjltc      %d, %d, %g\n", (code + 1).index + address, (code + 2).index, *cast(d_number *)(code + 3));
2365             break;
2366 
2367         case IRjlec:                // if (b <= constant) goto t
2368             writef("\tIRjlec      %d, %d, %g\n", (code + 1).index + address, (code + 2).index, *cast(d_number *)(code + 3));
2369             break;
2370 
2371         case IRiter:                // a = iter(b)
2372             writef("\tIRiter    %d, %d\n", (code + 1).index, (code + 2).index);
2373             break;
2374 
2375         case IRnext:                // a, b.c, iter
2376             writef("\tIRnext    %d, %d, %d, %d\n",
2377                    (code + 1).index,
2378                    (code + 2).index,
2379                    (code + 3).index,
2380                    (code + 4).index);
2381             break;
2382 
2383         case IRnexts:               // a, b.s, iter
2384             writef("\tIRnexts   %d, %d, '%s', %d\n",
2385                    (code + 1).index,
2386                    (code + 2).index,
2387                    (code + 3).id.value..string,
2388                    (code + 4).index);
2389             break;
2390 
2391         case IRnextscope:           // a, s, iter
2392             writef
2393                 ("\tIRnextscope   %d, '%s', %d\n",
2394                 (code + 1).index,
2395                 (code + 2).id.value..string,
2396                 (code + 3).index);
2397             break;
2398 
2399         case IRcall:                // a = b.c(argc, argv)
2400             writef("\tIRcall     %d,%d,%d, argc=%d, argv=%d \n",
2401                    (code + 1).index,
2402                    (code + 2).index,
2403                    (code + 3).index,
2404                    (code + 4).index,
2405                    (code + 5).index);
2406             break;
2407 
2408         case IRcalls:               // a = b.s(argc, argv)
2409             writef
2410                 ("\tIRcalls     %d,%d,'%s', argc=%d, argv=%d \n",
2411                 (code + 1).index,
2412                 (code + 2).index,
2413                 (code + 3).id.value..string,
2414                 (code + 4).index,
2415                 (code + 5).index);
2416             break;
2417 
2418         case IRcallscope:           // a = s(argc, argv)
2419             writef
2420                 ("\tIRcallscope %d,'%s', argc=%d, argv=%d \n",
2421                 (code + 1).index,
2422                 (code + 2).id.value..string,
2423                 (code + 3).index,
2424                 (code + 4).index);
2425             break;
2426 
2427         case IRputcall:                // a = b.c(argc, argv)
2428             writef("\tIRputcall  %d,%d,%d, argc=%d, argv=%d \n",
2429                    (code + 1).index,
2430                    (code + 2).index,
2431                    (code + 3).index,
2432                    (code + 4).index,
2433                    (code + 5).index);
2434             break;
2435 
2436         case IRputcalls:               // a = b.s(argc, argv)
2437             writef
2438                 ("\tIRputcalls  %d,%d,'%s', argc=%d, argv=%d \n",
2439                 (code + 1).index,
2440                 (code + 2).index,
2441                 (code + 3).id.value..string,
2442                 (code + 4).index,
2443                 (code + 5).index);
2444             break;
2445 
2446         case IRputcallscope:           // a = s(argc, argv)
2447             writef
2448                 ("\tIRputcallscope %d,'%s', argc=%d, argv=%d \n",
2449                 (code + 1).index,
2450                 (code + 2).id.value..string,
2451                 (code + 3).index,
2452                 (code + 4).index);
2453             break;
2454 
2455         case IRcallv:               // a = v(argc, argv)
2456             writef("\tIRcallv    %d, %d(argc=%d, argv=%d)\n",
2457                    (code + 1).index,
2458                    (code + 2).index,
2459                    (code + 3).index,
2460                    (code + 4).index);
2461             break;
2462 
2463         case IRputcallv:               // a = v(argc, argv)
2464             writef("\tIRputcallv %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 IRnew:         // a = new b(argc, argv)
2472             writef("\tIRnew      %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 IRpush:
2480             writef("\tIRpush    %d\n", (code + 1).index);
2481             break;
2482 
2483         case IRpop:
2484             writef("\tIRpop\n");
2485             break;
2486 
2487         case IRret:
2488             writef("\tIRret\n");
2489             return;
2490 
2491         case IRretexp:
2492             writef("\tIRretexp    %d\n", (code + 1).index);
2493             return;
2494 
2495         case IRimpret:
2496             writef("\tIRimpret    %d\n", (code + 1).index);
2497             return;
2498 
2499         case IRthrow:
2500             writef("\tIRthrow     %d\n", (code + 1).index);
2501             break;
2502 
2503         case IRassert:
2504             writef("\tIRassert    %d\n", (code + 1).index);
2505             break;
2506 		case IRcheckref:
2507 			writef("\tIRcheckref  %d\n",(code+1).index);
2508 			break;
2509         case IRtrycatch:
2510             writef("\tIRtrycatch  %d, '%s'\n", (code + 1).offset + address, (code + 2).id.value..string);
2511             break;
2512 
2513         case IRtryfinally:
2514             writef("\tIRtryfinally %d\n", (code + 1).offset + address);
2515             break;
2516 
2517         case IRfinallyret:
2518             writef("\tIRfinallyret\n");
2519             break;
2520 
2521         default:
2522             writef("2: Unrecognized IR instruction %d\n", code.opcode);
2523             assert(0);              // unrecognized IR instruction
2524         }
2525     }
2526 
2527     /*********************************
2528      * Give size of opcode.
2529      */
2530 
2531     static uint size(uint opcode)
2532     {
2533         uint sz = 9999;
2534 
2535         switch(opcode)
2536         {
2537         case IRerror:
2538         case IRnop:
2539         case IRend:
2540             sz = 1;
2541             break;
2542 
2543         case IRget:                 // a = b.c
2544         case IRaddass:
2545             sz = 4;
2546             break;
2547 
2548         case IRput:                 // b.c = a
2549             sz = 4;
2550             break;
2551 
2552         case IRgets:                // a = b.s
2553         case IRaddasss:
2554             sz = 4;
2555             break;
2556 
2557         case IRgetscope:            // a = s
2558             sz = 3;
2559             break;
2560 
2561         case IRaddassscope:
2562             sz = 4;
2563             break;
2564 
2565         case IRputs:                // b.s = a
2566             sz = 4;
2567             break;
2568 
2569         case IRputscope:        // s = a
2570         case IRputdefault:      // b = a
2571             sz = 3;
2572             break;
2573 
2574         case IRputthis:             // a = s
2575             sz = 3;
2576             break;
2577 
2578         case IRmov:                 // a = b
2579             sz = 3;
2580             break;
2581 
2582         case IRstring:              // a = "string"
2583             sz = 3;
2584             break;
2585 
2586         case IRobject:              // a = object
2587             sz = 3;
2588             break;
2589 
2590         case IRthis:                // a = this
2591             sz = 2;
2592             break;
2593 
2594         case IRnumber:              // a = number
2595             sz = 2 + d_number.sizeof/Op.sizeof;
2596             break;
2597 
2598         case IRboolean:             // a = boolean
2599             sz = 3;
2600             break;
2601 
2602         case IRnull:                // a = null
2603             sz = 2;
2604             break;
2605 			
2606 		case IRcheckref:
2607         case IRundefined:           // a = undefined
2608             sz = 2;
2609             break;
2610 		
2611 
2612         case IRthisget:             // a = othis.ident
2613             sz = 3;
2614             break;
2615 		
2616         case IRneg:                 // a = -a
2617         case IRpos:                 // a = a
2618         case IRcom:                 // a = ~a
2619         case IRnot:                 // a = !a
2620         case IRtypeof:              // a = typeof a
2621             sz = 2;
2622             break;
2623 
2624         case IRinstance:            // a = b instanceof c
2625         case IRadd:                 // a = b + c
2626         case IRsub:                 // a = b - c
2627         case IRmul:                 // a = b * c
2628         case IRdiv:                 // a = b / c
2629         case IRmod:                 // a = b % c
2630         case IRshl:                 // a = b << c
2631         case IRshr:                 // a = b >> c
2632         case IRushr:                // a = b >>> c
2633         case IRand:                 // a = b & c
2634         case IRor:                  // a = b | c
2635         case IRxor:                 // a = b ^ c
2636 		case IRin:                  // a = b in c
2637             sz = 4;
2638             break;
2639 
2640         case IRpreinc:             // a = ++b.c
2641         case IRpreincs:            // a = ++b.s
2642         case IRpredec:             // a = --b.c
2643         case IRpredecs:            // a = --b.s
2644         case IRpostinc:            // a = b.c++
2645         case IRpostincs:           // a = b.s++
2646         case IRpostdec:            // a = b.c--
2647         case IRpostdecs:           // a = b.s--
2648             sz = 4;
2649             break;
2650 
2651         case IRpostincscope:        // a = s++
2652         case IRpostdecscope:        // a = s--
2653             sz = 3;
2654             break;
2655 
2656         case IRpreincscope:     // a = ++s
2657         case IRpredecscope:     // a = --s
2658             sz = 4;
2659             break;
2660 
2661         case IRdel:                 // a = delete b.c
2662         case IRdels:                // a = delete b.s
2663             sz = 4;
2664             break;
2665 
2666         case IRdelscope:            // a = delete s
2667             sz = 3;
2668             break;
2669 
2670         case IRclt:                 // a = (b <   c)
2671         case IRcle:                 // a = (b <=  c)
2672         case IRcgt:                 // a = (b >   c)
2673         case IRcge:                 // a = (b >=  c)
2674         case IRceq:                 // a = (b ==  c)
2675         case IRcne:                 // a = (b !=  c)
2676         case IRcid:                 // a = (b === c)
2677         case IRcnid:                // a = (b !== c)
2678         case IRjlt:                 // if (b < c) goto t
2679         case IRjle:                 // if (b <= c) goto t
2680             sz = 4;
2681             break;
2682 
2683         case IRjltc:                // if (b < constant) goto t
2684         case IRjlec:                // if (b <= constant) goto t
2685             sz = 3 + d_number.sizeof/Op.sizeof;
2686             break;
2687 
2688         case IRjt:                  // if (b) goto t
2689         case IRjf:                  // if (!b) goto t
2690         case IRjtb:                 // if (b) goto t
2691         case IRjfb:                 // if (!b) goto t
2692             sz = 3;
2693             break;
2694 
2695         case IRjmp:
2696             sz = 2;
2697             break;
2698 
2699         case IRiter:                // a = iter(b)
2700             sz = 3;
2701             break;
2702 
2703         case IRnext:                // a, b.c, iter
2704         case IRnexts:               // a, b.s, iter
2705             sz = 5;
2706             break;
2707 
2708         case IRnextscope:           // a, s, iter
2709             sz = 4;
2710             break;
2711 
2712         case IRcall:                // a = b.c(argc, argv)
2713         case IRcalls:               // a = b.s(argc, argv)
2714         case IRputcall:             //  b.c(argc, argv) = a
2715         case IRputcalls:            //  b.s(argc, argv) = a
2716             sz = 6;
2717             break;
2718 
2719         case IRcallscope:           // a = s(argc, argv)
2720         case IRputcallscope:        // s(argc, argv) = a
2721         case IRcallv:
2722         case IRputcallv:
2723             sz = 5;
2724             break;
2725 
2726         case IRnew:                 // a = new b(argc, argv)
2727             sz = 5;
2728             break;
2729 
2730         case IRpush:
2731             sz = 2;
2732             break;
2733 
2734         case IRpop:
2735             sz = 1;
2736             break;
2737 
2738         case IRfinallyret:
2739         case IRret:
2740             sz = 1;
2741             break;
2742 
2743         case IRretexp:
2744         case IRimpret:
2745         case IRthrow:
2746             sz = 2;
2747             break;
2748 
2749         case IRtrycatch:
2750             sz = 3;
2751             break;
2752 
2753         case IRtryfinally:
2754             sz = 2;
2755             break;
2756 
2757         case IRassert:
2758             sz = 2;
2759             break;
2760 
2761         default:
2762             writef("3: Unrecognized IR instruction %d, IRMAX = %d\n", opcode, IRMAX);
2763             assert(0);              // unrecognized IR instruction
2764         }
2765         assert(sz <= 6);
2766         return sz;
2767     }
2768 
2769     static void printfunc(IR *code)
2770     {
2771         IR *codestart = code;
2772 
2773         for(;; )
2774         {
2775             //writef("%2d(%d):", code - codestart, code.linnum);
2776             writef("%2d:", code - codestart);
2777             print(cast(uint)(code - codestart), code);
2778             if(code.opcode == IRend)
2779                 return;
2780             code += size(code.opcode);
2781         }
2782     }
2783 
2784     /***************************************
2785      * Verify that it is a correct sequence of code.
2786      * Useful for isolating memory corruption bugs.
2787      */
2788 
2789     static uint verify(uint linnum, IR *codestart)
2790     {
2791         debug(VERIFY)
2792         {
2793             uint checksum = 0;
2794             uint sz;
2795             uint i;
2796             IR *code;
2797 
2798             // Verify code
2799             for(code = codestart;; )
2800             {
2801                 switch(code.opcode)
2802                 {
2803                 case IRend:
2804                     return checksum;
2805 
2806                 case IRerror:
2807                     writef("verify failure line %u\n", linnum);
2808                     assert(0);
2809                     break;
2810 
2811                 default:
2812                     if(code.opcode >= IRMAX)
2813                     {
2814                         writef("undefined opcode %d in code %p\n", code.opcode, codestart);
2815                         assert(0);
2816                     }
2817                     sz = IR.size(code.opcode);
2818                     for(i = 0; i < sz; i++)
2819                     {
2820                         checksum += code.opcode;
2821                         code++;
2822                     }
2823                     break;
2824                 }
2825             }
2826         }
2827         else
2828             return 0;
2829     }
2830 }