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