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