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