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