codeBlock.cpp
Engine/source/console/codeBlock.cpp
Classes:
class
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "console/console.h" 25#include "console/compiler.h" 26#include "console/codeBlock.h" 27#include "console/telnetDebugger.h" 28#include "console/ast.h" 29#include "core/strings/unicode.h" 30#include "core/strings/stringFunctions.h" 31#include "core/stringTable.h" 32#include "core/stream/fileStream.h" 33 34using namespace Compiler; 35 36bool CodeBlock::smInFunction = false; 37CodeBlock * CodeBlock::smCodeBlockList = NULL; 38CodeBlock * CodeBlock::smCurrentCodeBlock = NULL; 39ConsoleParser *CodeBlock::smCurrentParser = NULL; 40 41//------------------------------------------------------------------------- 42 43CodeBlock::CodeBlock() 44{ 45 globalStrings = NULL; 46 functionStrings = NULL; 47 functionStringsMaxLen = 0; 48 globalStringsMaxLen = 0; 49 globalFloats = NULL; 50 functionFloats = NULL; 51 lineBreakPairs = NULL; 52 breakList = NULL; 53 breakListSize = 0; 54 55 refCount = 0; 56 code = NULL; 57 name = NULL; 58 fullPath = NULL; 59 modPath = NULL; 60} 61 62CodeBlock::~CodeBlock() 63{ 64 // Make sure we aren't lingering in the current code block... 65 AssertFatal(smCurrentCodeBlock != this, "CodeBlock::~CodeBlock - Caught lingering in smCurrentCodeBlock!"); 66 67 if(name) 68 removeFromCodeList(); 69 delete[] const_cast<char*>(globalStrings); 70 delete[] const_cast<char*>(functionStrings); 71 72 functionStringsMaxLen = 0; 73 globalStringsMaxLen = 0; 74 75 delete[] globalFloats; 76 delete[] functionFloats; 77 delete[] code; 78 delete[] breakList; 79} 80 81//------------------------------------------------------------------------- 82 83StringTableEntry CodeBlock::getCurrentCodeBlockName() 84{ 85 if (CodeBlock::getCurrentBlock()) 86 return CodeBlock::getCurrentBlock()->name; 87 else 88 return NULL; 89} 90 91StringTableEntry CodeBlock::getCurrentCodeBlockFullPath() 92{ 93 if (CodeBlock::getCurrentBlock()) 94 return CodeBlock::getCurrentBlock()->fullPath; 95 else 96 return NULL; 97} 98 99StringTableEntry CodeBlock::getCurrentCodeBlockModName() 100{ 101 if (CodeBlock::getCurrentBlock()) 102 return CodeBlock::getCurrentBlock()->modPath; 103 else 104 return NULL; 105} 106 107CodeBlock *CodeBlock::find(StringTableEntry name) 108{ 109 for(CodeBlock *walk = CodeBlock::getCodeBlockList(); walk; walk = walk->nextFile) 110 if(walk->name == name) 111 return walk; 112 return NULL; 113} 114 115//------------------------------------------------------------------------- 116 117void CodeBlock::addToCodeList() 118{ 119 // remove any code blocks with my name 120 for(CodeBlock **walk = &smCodeBlockList; *walk;walk = &((*walk)->nextFile)) 121 { 122 if((*walk)->name == name) 123 { 124 *walk = (*walk)->nextFile; 125 break; 126 } 127 } 128 nextFile = smCodeBlockList; 129 smCodeBlockList = this; 130} 131 132void CodeBlock::clearAllBreaks() 133{ 134 if(!lineBreakPairs) 135 return; 136 for(U32 i = 0; i < lineBreakPairCount; i++) 137 { 138 U32 *p = lineBreakPairs + i * 2; 139 code[p[1]] = p[0] & 0xFF; 140 } 141} 142 143void CodeBlock::clearBreakpoint(U32 lineNumber) 144{ 145 if(!lineBreakPairs) 146 return; 147 for(U32 i = 0; i < lineBreakPairCount; i++) 148 { 149 U32 *p = lineBreakPairs + i * 2; 150 if((p[0] >> 8) == lineNumber) 151 { 152 code[p[1]] = p[0] & 0xFF; 153 return; 154 } 155 } 156} 157 158void CodeBlock::setAllBreaks() 159{ 160 if(!lineBreakPairs) 161 return; 162 for(U32 i = 0; i < lineBreakPairCount; i++) 163 { 164 U32 *p = lineBreakPairs + i * 2; 165 code[p[1]] = OP_BREAK; 166 } 167} 168 169bool CodeBlock::setBreakpoint(U32 lineNumber) 170{ 171 if(!lineBreakPairs) 172 return false; 173 174 for(U32 i = 0; i < lineBreakPairCount; i++) 175 { 176 U32 *p = lineBreakPairs + i * 2; 177 if((p[0] >> 8) == lineNumber) 178 { 179 code[p[1]] = OP_BREAK; 180 return true; 181 } 182 } 183 184 return false; 185} 186 187U32 CodeBlock::findFirstBreakLine(U32 lineNumber) 188{ 189 if(!lineBreakPairs) 190 return 0; 191 192 for(U32 i = 0; i < lineBreakPairCount; i++) 193 { 194 U32 *p = lineBreakPairs + i * 2; 195 U32 line = (p[0] >> 8); 196 197 if( lineNumber <= line ) 198 return line; 199 } 200 201 return 0; 202} 203 204struct LinePair 205{ 206 U32 instLine; 207 U32 ip; 208}; 209 210void CodeBlock::findBreakLine(U32 ip, U32 &line, U32 &instruction) 211{ 212 U32 min = 0; 213 U32 max = lineBreakPairCount - 1; 214 LinePair *p = (LinePair *) lineBreakPairs; 215 216 U32 found; 217 if(!lineBreakPairCount || p[min].ip > ip || p[max].ip < ip) 218 { 219 line = 0; 220 instruction = OP_INVALID; 221 return; 222 } 223 else if(p[min].ip == ip) 224 found = min; 225 else if(p[max].ip == ip) 226 found = max; 227 else 228 { 229 for(;;) 230 { 231 if(min == max - 1) 232 { 233 found = min; 234 break; 235 } 236 U32 mid = (min + max) >> 1; 237 if(p[mid].ip == ip) 238 { 239 found = mid; 240 break; 241 } 242 else if(p[mid].ip > ip) 243 max = mid; 244 else 245 min = mid; 246 } 247 } 248 instruction = p[found].instLine & 0xFF; 249 line = p[found].instLine >> 8; 250} 251 252const char *CodeBlock::getFileLine(U32 ip) 253{ 254 static char nameBuffer[256]; 255 U32 line, inst; 256 findBreakLine(ip, line, inst); 257 258 dSprintf(nameBuffer, sizeof(nameBuffer), "%s (%d)", name ? name : "<input>", line); 259 return nameBuffer; 260} 261 262void CodeBlock::removeFromCodeList() 263{ 264 for(CodeBlock **walk = &smCodeBlockList; *walk; walk = &((*walk)->nextFile)) 265 { 266 if(*walk == this) 267 { 268 *walk = nextFile; 269 270 // clear out all breakpoints 271 clearAllBreaks(); 272 break; 273 } 274 } 275 276 // Let the telnet debugger know that this code 277 // block has been unloaded and that it needs to 278 // remove references to it. 279 if ( TelDebugger ) 280 TelDebugger->clearCodeBlockPointers( this ); 281} 282 283void CodeBlock::calcBreakList() 284{ 285 U32 size = 0; 286 S32 line = -1; 287 U32 seqCount = 0; 288 U32 i; 289 for(i = 0; i < lineBreakPairCount; i++) 290 { 291 U32 lineNumber = lineBreakPairs[i * 2]; 292 if(lineNumber == U32(line + 1)) 293 seqCount++; 294 else 295 { 296 if(seqCount) 297 size++; 298 size++; 299 seqCount = 1; 300 } 301 line = lineNumber; 302 } 303 if(seqCount) 304 size++; 305 306 breakList = new U32[size]; 307 breakListSize = size; 308 line = -1; 309 seqCount = 0; 310 size = 0; 311 312 for(i = 0; i < lineBreakPairCount; i++) 313 { 314 U32 lineNumber = lineBreakPairs[i * 2]; 315 316 if(lineNumber == U32(line + 1)) 317 seqCount++; 318 else 319 { 320 if(seqCount) 321 breakList[size++] = seqCount; 322 breakList[size++] = lineNumber - getMax(0, line) - 1; 323 seqCount = 1; 324 } 325 326 line = lineNumber; 327 } 328 329 if(seqCount) 330 breakList[size++] = seqCount; 331 332 for(i = 0; i < lineBreakPairCount; i++) 333 { 334 U32 *p = lineBreakPairs + i * 2; 335 p[0] = (p[0] << 8) | code[p[1]]; 336 } 337 338 // Let the telnet debugger know that this code 339 // block has been loaded and that it can add break 340 // points it has for it. 341 if ( TelDebugger ) 342 TelDebugger->addAllBreakpoints( this ); 343} 344 345bool CodeBlock::read(StringTableEntry fileName, Stream &st) 346{ 347 const StringTableEntry exePath = Platform::getMainDotCsDir(); 348 const StringTableEntry cwd = Platform::getCurrentDirectory(); 349 350 name = fileName; 351 352 if(fileName) 353 { 354 fullPath = NULL; 355 356 if(Platform::isFullPath(fileName)) 357 fullPath = fileName; 358 359 if(dStrnicmp(exePath, fileName, dStrlen(exePath)) == 0) 360 name = StringTable->insert(fileName + dStrlen(exePath) + 1, true); 361 else if(dStrnicmp(cwd, fileName, dStrlen(cwd)) == 0) 362 name = StringTable->insert(fileName + dStrlen(cwd) + 1, true); 363 364 if(fullPath == NULL) 365 { 366 char buf[1024]; 367 fullPath = StringTable->insert(Platform::makeFullPathName(fileName, buf, sizeof(buf)), true); 368 } 369 370 modPath = Con::getModNameFromPath(fileName); 371 } 372 373 // 374 addToCodeList(); 375 376 U32 globalSize,size,i; 377 st.read(&size); 378 if(size) 379 { 380 globalStrings = new char[size]; 381 globalStringsMaxLen = size; 382 st.read(size, globalStrings); 383 } 384 globalSize = size; 385 st.read(&size); 386 if(size) 387 { 388 functionStrings = new char[size]; 389 functionStringsMaxLen = size; 390 st.read(size, functionStrings); 391 } 392 st.read(&size); 393 if(size) 394 { 395 globalFloats = new F64[size]; 396 for(U32 i = 0; i < size; i++) 397 st.read(&globalFloats[i]); 398 } 399 st.read(&size); 400 if(size) 401 { 402 functionFloats = new F64[size]; 403 for(U32 i = 0; i < size; i++) 404 st.read(&functionFloats[i]); 405 } 406 U32 codeLength; 407 st.read(&codeLength); 408 st.read(&lineBreakPairCount); 409 410 U32 totSize = codeLength + lineBreakPairCount * 2; 411 code = new U32[totSize]; 412 413 for(i = 0; i < codeLength; i++) 414 { 415 U8 b; 416 st.read(&b); 417 if(b == 0xFF) 418 st.read(&code[i]); 419 else 420 code[i] = b; 421 } 422 423 for(i = codeLength; i < totSize; i++) 424 st.read(&code[i]); 425 426 lineBreakPairs = code + codeLength; 427 428 // StringTable-ize our identifiers. 429 U32 identCount; 430 st.read(&identCount); 431 while(identCount--) 432 { 433 U32 offset; 434 st.read(&offset); 435 StringTableEntry ste; 436 if(offset < globalSize) 437 ste = StringTable->insert(globalStrings + offset); 438 else 439 ste = StringTable->insert(""); 440 U32 count; 441 st.read(&count); 442 while(count--) 443 { 444 U32 ip; 445 st.read(&ip); 446 code[ip] = *((U32 *) &ste); 447 } 448 } 449 450 if(lineBreakPairCount) 451 calcBreakList(); 452 453 return true; 454} 455 456 457bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, const char *inScript, bool overrideNoDso) 458{ 459 AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread"); 460 461 // This will return true, but return value is ignored 462 char *script; 463 chompUTF8BOM( inScript, &script ); 464 465 gSyntaxError = false; 466 467 consoleAllocReset(); 468 469 STEtoCode = compileSTEtoCode; 470 471 gStatementList = NULL; 472 gAnonFunctionList = NULL; 473 474 // Set up the parser. 475 smCurrentParser = getParserForFile(fileName); 476 AssertISV(smCurrentParser, avar("CodeBlock::compile - no parser available for '%s'!", fileName)); 477 478 // Now do some parsing. 479 smCurrentParser->setScanBuffer(script, fileName); 480 smCurrentParser->restart(NULL); 481 smCurrentParser->parse(); 482 if (gStatementList) 483 { 484 if (gAnonFunctionList) 485 { 486 // Prepend anonymous functions to statement list, so they're defined already when 487 // the statements run. 488 gAnonFunctionList->append(gStatementList); 489 gStatementList = gAnonFunctionList; 490 } 491 } 492 493 494 if(gSyntaxError) 495 { 496 consoleAllocReset(); 497 return false; 498 } 499 500#ifdef TORQUE_NO_DSO_GENERATION 501 if(!overrideNoDso) 502 return false; 503#endif // !TORQUE_NO_DSO_GENERATION 504 505 FileStream st; 506 if(!st.open(codeFileName, Torque::FS::File::Write)) 507 return false; 508 st.write(U32(Con::DSOVersion)); 509 510 // Reset all our value tables... 511 resetTables(); 512 513 smInFunction = false; 514 515 CodeStream codeStream; 516 U32 lastIp; 517 if(gStatementList) 518 { 519 lastIp = compileBlock(gStatementList, codeStream, 0) + 1; 520 } 521 else 522 { 523 codeSize = 1; 524 lastIp = 0; 525 } 526 527 codeStream.emit(OP_RETURN); 528 codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs); 529 530 lineBreakPairCount = codeStream.getNumLineBreaks(); 531 532 // Write string table data... 533 getGlobalStringTable().write(st); 534 getFunctionStringTable().write(st); 535 536 // Write float table data... 537 getGlobalFloatTable().write(st); 538 getFunctionFloatTable().write(st); 539 540 if(lastIp != codeSize) 541 Con::errorf(ConsoleLogEntry::General, "CodeBlock::compile - precompile size mismatch, a precompile/compile function pair is probably mismatched."); 542 543 U32 totSize = codeSize + codeStream.getNumLineBreaks() * 2; 544 st.write(codeSize); 545 st.write(lineBreakPairCount); 546 547 // Write out our bytecode, doing a bit of compression for low numbers. 548 U32 i; 549 for(i = 0; i < codeSize; i++) 550 { 551 if(code[i] < 0xFF) 552 st.write(U8(code[i])); 553 else 554 { 555 st.write(U8(0xFF)); 556 st.write(code[i]); 557 } 558 } 559 560 // Write the break info... 561 for(i = codeSize; i < totSize; i++) 562 st.write(code[i]); 563 564 getIdentTable().write(st); 565 566 consoleAllocReset(); 567 st.close(); 568 569 return true; 570 571 572} 573 574ConsoleValueRef CodeBlock::compileExec(StringTableEntry fileName, const char *inString, bool noCalls, S32 setFrame) 575{ 576 AssertFatal(Con::isMainThread(), "Compiling code on a secondary thread"); 577 578 // Check for a UTF8 script file 579 char *string; 580 chompUTF8BOM( inString, &string ); 581 582 STEtoCode = evalSTEtoCode; 583 consoleAllocReset(); 584 585 name = fileName; 586 587 if(fileName) 588 { 589 const StringTableEntry exePath = Platform::getMainDotCsDir(); 590 const StringTableEntry cwd = Platform::getCurrentDirectory(); 591 592 fullPath = NULL; 593 594 if(Platform::isFullPath(fileName)) 595 fullPath = fileName; 596 597 if(dStrnicmp(exePath, fileName, dStrlen(exePath)) == 0) 598 name = StringTable->insert(fileName + dStrlen(exePath) + 1, true); 599 else if(dStrnicmp(cwd, fileName, dStrlen(cwd)) == 0) 600 name = StringTable->insert(fileName + dStrlen(cwd) + 1, true); 601 602 if(fullPath == NULL) 603 { 604 char buf[1024]; 605 fullPath = StringTable->insert(Platform::makeFullPathName(fileName, buf, sizeof(buf)), true); 606 } 607 608 modPath = Con::getModNameFromPath(fileName); 609 } 610 611 if(name) 612 addToCodeList(); 613 614 gStatementList = NULL; 615 gAnonFunctionList = NULL; 616 617 // Set up the parser. 618 smCurrentParser = getParserForFile(fileName); 619 AssertISV(smCurrentParser, avar("CodeBlock::compile - no parser available for '%s'!", fileName)); 620 621 // Now do some parsing. 622 smCurrentParser->setScanBuffer(string, fileName); 623 smCurrentParser->restart(NULL); 624 smCurrentParser->parse(); 625 if (gStatementList) 626 { 627 if (gAnonFunctionList) 628 { 629 // Prepend anonymous functions to statement list, so they're defined already when 630 // the statements run. 631 gAnonFunctionList->append(gStatementList); 632 gStatementList = gAnonFunctionList; 633 } 634 } 635 636 if(!gStatementList) 637 { 638 delete this; 639 return ConsoleValueRef(); 640 } 641 642 resetTables(); 643 644 smInFunction = false; 645 646 CodeStream codeStream; 647 U32 lastIp = compileBlock(gStatementList, codeStream, 0); 648 649 lineBreakPairCount = codeStream.getNumLineBreaks(); 650 651 globalStrings = getGlobalStringTable().build(); 652 globalStringsMaxLen = getGlobalStringTable().totalLen; 653 654 functionStrings = getFunctionStringTable().build(); 655 functionStringsMaxLen = getFunctionStringTable().totalLen; 656 657 globalFloats = getGlobalFloatTable().build(); 658 functionFloats = getFunctionFloatTable().build(); 659 660 codeStream.emit(OP_RETURN); 661 codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs); 662 663 //dumpInstructions(0, false); 664 665 consoleAllocReset(); 666 667 if(lineBreakPairCount && fileName) 668 calcBreakList(); 669 670 if(lastIp+1 != codeSize) 671 Con::warnf(ConsoleLogEntry::General, "precompile size mismatch, precompile: %d compile: %d", codeSize, lastIp); 672 673 return exec(0, fileName, NULL, 0, 0, noCalls, NULL, setFrame); 674} 675 676//------------------------------------------------------------------------- 677 678void CodeBlock::incRefCount() 679{ 680 refCount++; 681} 682 683void CodeBlock::decRefCount() 684{ 685 refCount--; 686 if(!refCount) 687 delete this; 688} 689 690//------------------------------------------------------------------------- 691 692String CodeBlock::getFunctionArgs( U32 ip ) 693{ 694 StringBuilder str; 695 696 U32 fnArgc = code[ ip + 5 ]; 697 for( U32 i = 0; i < fnArgc; ++ i ) 698 { 699 StringTableEntry var = CodeToSTE(code, ip + (i*2) + 6); 700 701 if( i != 0 ) 702 str.append( ", " ); 703 704 str.append( "string " ); 705 706 // Try to capture junked parameters 707 if( var[ 0 ] ) 708 str.append( var + 1 ); 709 else 710 str.append( "JUNK" ); 711 } 712 713 return str.end(); 714} 715 716//------------------------------------------------------------------------- 717 718void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn ) 719{ 720 U32 ip = startIp; 721 smInFunction = false; 722 U32 endFuncIp = 0; 723 724 while( ip < codeSize ) 725 { 726 if (ip > endFuncIp) 727 { 728 smInFunction = false; 729 } 730 731 switch( code[ ip ++ ] ) 732 { 733 734 case OP_FUNC_DECL: 735 { 736 StringTableEntry fnName = CodeToSTE(code, ip); 737 StringTableEntry fnNamespace = CodeToSTE(code, ip+2); 738 StringTableEntry fnPackage = CodeToSTE(code, ip+4); 739 bool hasBody = bool(code[ip+6]); 740 U32 newIp = code[ ip + 7 ]; 741 U32 argc = code[ ip + 8 ]; 742 endFuncIp = newIp; 743 744 Con::printf( "%i: OP_FUNC_DECL name=%s nspace=%s package=%s hasbody=%i newip=%i argc=%i", 745 ip - 1, fnName, fnNamespace, fnPackage, hasBody, newIp, argc ); 746 747 // Skip args. 748 749 ip += 9 + (argc * 2); 750 smInFunction = true; 751 break; 752 } 753 754 case OP_CREATE_OBJECT: 755 { 756 StringTableEntry objParent = CodeToSTE(code, ip); 757 bool isDataBlock = code[ip + 2]; 758 bool isInternal = code[ip + 3]; 759 bool isSingleton = code[ip + 4]; 760 U32 lineNumber = code[ip + 5]; 761 U32 failJump = code[ip + 6]; 762 763 Con::printf( "%i: OP_CREATE_OBJECT objParent=%s isDataBlock=%i isInternal=%i isSingleton=%i lineNumber=%i failJump=%i", 764 ip - 1, objParent, isDataBlock, isInternal, isSingleton, lineNumber, failJump ); 765 766 ip += 7; 767 break; 768 } 769 770 case OP_ADD_OBJECT: 771 { 772 bool placeAtRoot = code[ip++]; 773 Con::printf( "%i: OP_ADD_OBJECT placeAtRoot=%i", ip - 1, placeAtRoot ); 774 break; 775 } 776 777 case OP_END_OBJECT: 778 { 779 bool placeAtRoot = code[ip++]; 780 Con::printf( "%i: OP_END_OBJECT placeAtRoot=%i", ip - 1, placeAtRoot ); 781 break; 782 } 783 784 case OP_FINISH_OBJECT: 785 { 786 Con::printf( "%i: OP_FINISH_OBJECT", ip - 1 ); 787 break; 788 } 789 790 case OP_JMPIFFNOT: 791 { 792 Con::printf( "%i: OP_JMPIFFNOT ip=%i", ip - 1, code[ ip ] ); 793 ++ ip; 794 break; 795 } 796 797 case OP_JMPIFNOT: 798 { 799 Con::printf( "%i: OP_JMPIFNOT ip=%i", ip - 1, code[ ip ] ); 800 ++ ip; 801 break; 802 } 803 804 case OP_JMPIFF: 805 { 806 Con::printf( "%i: OP_JMPIFF ip=%i", ip - 1, code[ ip ] ); 807 ++ ip; 808 break; 809 } 810 811 case OP_JMPIF: 812 { 813 Con::printf( "%i: OP_JMPIF ip=%i", ip - 1, code[ ip ] ); 814 ++ ip; 815 break; 816 } 817 818 case OP_JMPIFNOT_NP: 819 { 820 Con::printf( "%i: OP_JMPIFNOT_NP ip=%i", ip - 1, code[ ip ] ); 821 ++ ip; 822 break; 823 } 824 825 case OP_JMPIF_NP: 826 { 827 Con::printf( "%i: OP_JMPIF_NP ip=%i", ip - 1, code[ ip ] ); 828 ++ ip; 829 break; 830 } 831 832 case OP_JMP: 833 { 834 Con::printf( "%i: OP_JMP ip=%i", ip - 1, code[ ip ] ); 835 ++ ip; 836 break; 837 } 838 839 case OP_RETURN: 840 { 841 Con::printf( "%i: OP_RETURN", ip - 1 ); 842 843 if( upToReturn ) 844 return; 845 846 break; 847 } 848 849 case OP_RETURN_VOID: 850 { 851 Con::printf( "%i: OP_RETURNVOID", ip - 1 ); 852 853 if( upToReturn ) 854 return; 855 856 break; 857 } 858 859 case OP_RETURN_UINT: 860 { 861 Con::printf( "%i: OP_RETURNUINT", ip - 1 ); 862 863 if( upToReturn ) 864 return; 865 866 break; 867 } 868 869 case OP_RETURN_FLT: 870 { 871 Con::printf( "%i: OP_RETURNFLT", ip - 1 ); 872 873 if( upToReturn ) 874 return; 875 876 break; 877 } 878 879 case OP_CMPEQ: 880 { 881 Con::printf( "%i: OP_CMPEQ", ip - 1 ); 882 break; 883 } 884 885 case OP_CMPGR: 886 { 887 Con::printf( "%i: OP_CMPGR", ip - 1 ); 888 break; 889 } 890 891 case OP_CMPGE: 892 { 893 Con::printf( "%i: OP_CMPGE", ip - 1 ); 894 break; 895 } 896 897 case OP_CMPLT: 898 { 899 Con::printf( "%i: OP_CMPLT", ip - 1 ); 900 break; 901 } 902 903 case OP_CMPLE: 904 { 905 Con::printf( "%i: OP_CMPLE", ip - 1 ); 906 break; 907 } 908 909 case OP_CMPNE: 910 { 911 Con::printf( "%i: OP_CMPNE", ip - 1 ); 912 break; 913 } 914 915 case OP_XOR: 916 { 917 Con::printf( "%i: OP_XOR", ip - 1 ); 918 break; 919 } 920 921 case OP_MOD: 922 { 923 Con::printf( "%i: OP_MOD", ip - 1 ); 924 break; 925 } 926 927 case OP_BITAND: 928 { 929 Con::printf( "%i: OP_BITAND", ip - 1 ); 930 break; 931 } 932 933 case OP_BITOR: 934 { 935 Con::printf( "%i: OP_BITOR", ip - 1 ); 936 break; 937 } 938 939 case OP_NOT: 940 { 941 Con::printf( "%i: OP_NOT", ip - 1 ); 942 break; 943 } 944 945 case OP_NOTF: 946 { 947 Con::printf( "%i: OP_NOTF", ip - 1 ); 948 break; 949 } 950 951 case OP_ONESCOMPLEMENT: 952 { 953 Con::printf( "%i: OP_ONESCOMPLEMENT", ip - 1 ); 954 break; 955 } 956 957 case OP_SHR: 958 { 959 Con::printf( "%i: OP_SHR", ip - 1 ); 960 break; 961 } 962 963 case OP_SHL: 964 { 965 Con::printf( "%i: OP_SHL", ip - 1 ); 966 break; 967 } 968 969 case OP_AND: 970 { 971 Con::printf( "%i: OP_AND", ip - 1 ); 972 break; 973 } 974 975 case OP_OR: 976 { 977 Con::printf( "%i: OP_OR", ip - 1 ); 978 break; 979 } 980 981 case OP_ADD: 982 { 983 Con::printf( "%i: OP_ADD", ip - 1 ); 984 break; 985 } 986 987 case OP_SUB: 988 { 989 Con::printf( "%i: OP_SUB", ip - 1 ); 990 break; 991 } 992 993 case OP_MUL: 994 { 995 Con::printf( "%i: OP_MUL", ip - 1 ); 996 break; 997 } 998 999 case OP_DIV: 1000 { 1001 Con::printf( "%i: OP_DIV", ip - 1 ); 1002 break; 1003 } 1004 1005 case OP_NEG: 1006 { 1007 Con::printf( "%i: OP_NEG", ip - 1 ); 1008 break; 1009 } 1010 1011 case OP_SETCURVAR: 1012 { 1013 StringTableEntry var = CodeToSTE(code, ip); 1014 1015 Con::printf( "%i: OP_SETCURVAR var=%s", ip - 1, var ); 1016 ip += 2; 1017 break; 1018 } 1019 1020 case OP_SETCURVAR_CREATE: 1021 { 1022 StringTableEntry var = CodeToSTE(code, ip); 1023 1024 Con::printf( "%i: OP_SETCURVAR_CREATE var=%s", ip - 1, var ); 1025 ip += 2; 1026 break; 1027 } 1028 1029 case OP_SETCURVAR_ARRAY: 1030 { 1031 Con::printf( "%i: OP_SETCURVAR_ARRAY", ip - 1 ); 1032 break; 1033 } 1034 1035 case OP_SETCURVAR_ARRAY_CREATE: 1036 { 1037 Con::printf( "%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1 ); 1038 break; 1039 } 1040 1041 case OP_LOADVAR_UINT: 1042 { 1043 Con::printf( "%i: OP_LOADVAR_UINT", ip - 1 ); 1044 break; 1045 } 1046 1047 case OP_LOADVAR_FLT: 1048 { 1049 Con::printf( "%i: OP_LOADVAR_FLT", ip - 1 ); 1050 break; 1051 } 1052 1053 case OP_LOADVAR_STR: 1054 { 1055 Con::printf( "%i: OP_LOADVAR_STR", ip - 1 ); 1056 break; 1057 } 1058 1059 case OP_LOADVAR_VAR: 1060 { 1061 Con::printf( "%i: OP_LOADVAR_VAR", ip - 1 ); 1062 break; 1063 } 1064 1065 case OP_SAVEVAR_UINT: 1066 { 1067 Con::printf( "%i: OP_SAVEVAR_UINT", ip - 1 ); 1068 break; 1069 } 1070 1071 case OP_SAVEVAR_FLT: 1072 { 1073 Con::printf( "%i: OP_SAVEVAR_FLT", ip - 1 ); 1074 break; 1075 } 1076 1077 case OP_SAVEVAR_STR: 1078 { 1079 Con::printf( "%i: OP_SAVEVAR_STR", ip - 1 ); 1080 break; 1081 } 1082 1083 case OP_SAVEVAR_VAR: 1084 { 1085 Con::printf( "%i: OP_SAVEVAR_VAR", ip - 1 ); 1086 break; 1087 } 1088 1089 case OP_SETCUROBJECT: 1090 { 1091 Con::printf( "%i: OP_SETCUROBJECT", ip - 1 ); 1092 break; 1093 } 1094 1095 case OP_SETCUROBJECT_NEW: 1096 { 1097 Con::printf( "%i: OP_SETCUROBJECT_NEW", ip - 1 ); 1098 break; 1099 } 1100 1101 case OP_SETCUROBJECT_INTERNAL: 1102 { 1103 Con::printf( "%i: OP_SETCUROBJECT_INTERNAL", ip - 1 ); 1104 ++ ip; 1105 break; 1106 } 1107 1108 case OP_SETCURFIELD: 1109 { 1110 StringTableEntry curField = CodeToSTE(code, ip); 1111 Con::printf( "%i: OP_SETCURFIELD field=%s", ip - 1, curField ); 1112 ip += 2; 1113 break; 1114 } 1115 1116 case OP_SETCURFIELD_ARRAY: 1117 { 1118 Con::printf( "%i: OP_SETCURFIELD_ARRAY", ip - 1 ); 1119 break; 1120 } 1121 1122 case OP_SETCURFIELD_TYPE: 1123 { 1124 U32 type = code[ ip ]; 1125 Con::printf( "%i: OP_SETCURFIELD_TYPE type=%i", ip - 1, type ); 1126 ++ ip; 1127 break; 1128 } 1129 1130 case OP_LOADFIELD_UINT: 1131 { 1132 Con::printf( "%i: OP_LOADFIELD_UINT", ip - 1 ); 1133 break; 1134 } 1135 1136 case OP_LOADFIELD_FLT: 1137 { 1138 Con::printf( "%i: OP_LOADFIELD_FLT", ip - 1 ); 1139 break; 1140 } 1141 1142 case OP_LOADFIELD_STR: 1143 { 1144 Con::printf( "%i: OP_LOADFIELD_STR", ip - 1 ); 1145 break; 1146 } 1147 1148 case OP_SAVEFIELD_UINT: 1149 { 1150 Con::printf( "%i: OP_SAVEFIELD_UINT", ip - 1 ); 1151 break; 1152 } 1153 1154 case OP_SAVEFIELD_FLT: 1155 { 1156 Con::printf( "%i: OP_SAVEFIELD_FLT", ip - 1 ); 1157 break; 1158 } 1159 1160 case OP_SAVEFIELD_STR: 1161 { 1162 Con::printf( "%i: OP_SAVEFIELD_STR", ip - 1 ); 1163 break; 1164 } 1165 1166 case OP_STR_TO_UINT: 1167 { 1168 Con::printf( "%i: OP_STR_TO_UINT", ip - 1 ); 1169 break; 1170 } 1171 1172 case OP_STR_TO_FLT: 1173 { 1174 Con::printf( "%i: OP_STR_TO_FLT", ip - 1 ); 1175 break; 1176 } 1177 1178 case OP_STR_TO_NONE: 1179 { 1180 Con::printf( "%i: OP_STR_TO_NONE", ip - 1 ); 1181 break; 1182 } 1183 1184 case OP_FLT_TO_UINT: 1185 { 1186 Con::printf( "%i: OP_FLT_TO_UINT", ip - 1 ); 1187 break; 1188 } 1189 1190 case OP_FLT_TO_STR: 1191 { 1192 Con::printf( "%i: OP_FLT_TO_STR", ip - 1 ); 1193 break; 1194 } 1195 1196 case OP_FLT_TO_NONE: 1197 { 1198 Con::printf( "%i: OP_FLT_TO_NONE", ip - 1 ); 1199 break; 1200 } 1201 1202 case OP_UINT_TO_FLT: 1203 { 1204 Con::printf( "%i: OP_SAVEFIELD_STR", ip - 1 ); 1205 break; 1206 } 1207 1208 case OP_UINT_TO_STR: 1209 { 1210 Con::printf( "%i: OP_UINT_TO_STR", ip - 1 ); 1211 break; 1212 } 1213 1214 case OP_UINT_TO_NONE: 1215 { 1216 Con::printf( "%i: OP_UINT_TO_NONE", ip - 1 ); 1217 break; 1218 } 1219 1220 case OP_COPYVAR_TO_NONE: 1221 { 1222 Con::printf( "%i: OP_COPYVAR_TO_NONE", ip - 1 ); 1223 break; 1224 } 1225 1226 case OP_LOADIMMED_UINT: 1227 { 1228 U32 val = code[ ip ]; 1229 Con::printf( "%i: OP_LOADIMMED_UINT val=%i", ip - 1, val ); 1230 ++ ip; 1231 break; 1232 } 1233 1234 case OP_LOADIMMED_FLT: 1235 { 1236 F64 val = (smInFunction ? functionFloats : globalFloats)[ code[ ip ] ]; 1237 Con::printf( "%i: OP_LOADIMMED_FLT val=%f", ip - 1, val ); 1238 ++ ip; 1239 break; 1240 } 1241 1242 case OP_TAG_TO_STR: 1243 { 1244 const char* str = (smInFunction ? functionStrings : globalStrings) + code[ ip ]; 1245 Con::printf( "%i: OP_TAG_TO_STR str=%s", ip - 1, str ); 1246 ++ ip; 1247 break; 1248 } 1249 1250 case OP_LOADIMMED_STR: 1251 { 1252 const char* str = (smInFunction ? functionStrings : globalStrings) + code[ ip ]; 1253 Con::printf( "%i: OP_LOADIMMED_STR str=%s", ip - 1, str ); 1254 ++ ip; 1255 break; 1256 } 1257 1258 case OP_DOCBLOCK_STR: 1259 { 1260 const char* str = (smInFunction ? functionStrings : globalStrings) + code[ ip ]; 1261 Con::printf( "%i: OP_DOCBLOCK_STR str=%s", ip - 1, str ); 1262 ++ ip; 1263 break; 1264 } 1265 1266 case OP_LOADIMMED_IDENT: 1267 { 1268 StringTableEntry str = CodeToSTE(code, ip); 1269 Con::printf( "%i: OP_LOADIMMED_IDENT str=%s", ip - 1, str ); 1270 ip += 2; 1271 break; 1272 } 1273 1274 case OP_CALLFUNC_RESOLVE: 1275 { 1276 StringTableEntry fnNamespace = CodeToSTE(code, ip+2); 1277 StringTableEntry fnName = CodeToSTE(code, ip); 1278 U32 callType = code[ip+2]; 1279 1280 Con::printf( "%i: OP_CALLFUNC_RESOLVE name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, 1281 callType == FuncCallExprNode::FunctionCall ? "FunctionCall" 1282 : callType == FuncCallExprNode::MethodCall ? "MethodCall" : "ParentCall" ); 1283 1284 ip += 5; 1285 break; 1286 } 1287 1288 case OP_CALLFUNC: 1289 { 1290 StringTableEntry fnNamespace = CodeToSTE(code, ip+2); 1291 StringTableEntry fnName = CodeToSTE(code, ip); 1292 U32 callType = code[ip+4]; 1293 1294 Con::printf( "%i: OP_CALLFUNC name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, 1295 callType == FuncCallExprNode::FunctionCall ? "FunctionCall" 1296 : callType == FuncCallExprNode::MethodCall ? "MethodCall" : "ParentCall" ); 1297 1298 ip += 5; 1299 break; 1300 } 1301 1302 case OP_ADVANCE_STR: 1303 { 1304 Con::printf( "%i: OP_ADVANCE_STR", ip - 1 ); 1305 break; 1306 } 1307 1308 case OP_ADVANCE_STR_APPENDCHAR: 1309 { 1310 char ch = code[ ip ]; 1311 Con::printf( "%i: OP_ADVANCE_STR_APPENDCHAR char=%c", ip - 1, ch ); 1312 ++ ip; 1313 break; 1314 } 1315 1316 case OP_ADVANCE_STR_COMMA: 1317 { 1318 Con::printf( "%i: OP_ADVANCE_STR_COMMA", ip - 1 ); 1319 break; 1320 } 1321 1322 case OP_ADVANCE_STR_NUL: 1323 { 1324 Con::printf( "%i: OP_ADVANCE_STR_NUL", ip - 1 ); 1325 break; 1326 } 1327 1328 case OP_REWIND_STR: 1329 { 1330 Con::printf( "%i: OP_REWIND_STR", ip - 1 ); 1331 break; 1332 } 1333 1334 case OP_TERMINATE_REWIND_STR: 1335 { 1336 Con::printf( "%i: OP_TERMINATE_REWIND_STR", ip - 1 ); 1337 break; 1338 } 1339 1340 case OP_COMPARE_STR: 1341 { 1342 Con::printf( "%i: OP_COMPARE_STR", ip - 1 ); 1343 break; 1344 } 1345 1346 case OP_PUSH: 1347 { 1348 Con::printf( "%i: OP_PUSH", ip - 1 ); 1349 break; 1350 } 1351 1352 case OP_PUSH_UINT: 1353 { 1354 Con::printf( "%i: OP_PUSH_UINT", ip - 1 ); 1355 break; 1356 } 1357 1358 case OP_PUSH_FLT: 1359 { 1360 Con::printf( "%i: OP_PUSH_FLT", ip - 1 ); 1361 break; 1362 } 1363 1364 case OP_PUSH_VAR: 1365 { 1366 Con::printf( "%i: OP_PUSH_VAR", ip - 1 ); 1367 break; 1368 } 1369 1370 case OP_PUSH_FRAME: 1371 { 1372 Con::printf( "%i: OP_PUSH_FRAME", ip - 1 ); 1373 break; 1374 } 1375 1376 case OP_ASSERT: 1377 { 1378 const char* message = (smInFunction ? functionStrings : globalStrings) + code[ ip ]; 1379 Con::printf( "%i: OP_ASSERT message=%s", ip - 1, message ); 1380 ++ ip; 1381 break; 1382 } 1383 1384 case OP_BREAK: 1385 { 1386 Con::printf( "%i: OP_BREAK", ip - 1 ); 1387 break; 1388 } 1389 1390 case OP_ITER_BEGIN: 1391 { 1392 StringTableEntry varName = CodeToSTE(code, ip); 1393 U32 failIp = code[ ip + 2 ]; 1394 1395 Con::printf( "%i: OP_ITER_BEGIN varName=%s failIp=%i", ip - 1, varName, failIp ); 1396 1397 ip += 3; 1398 break; 1399 } 1400 1401 case OP_ITER_BEGIN_STR: 1402 { 1403 StringTableEntry varName = CodeToSTE(code, ip); 1404 U32 failIp = code[ ip + 2 ]; 1405 1406 Con::printf( "%i: OP_ITER_BEGIN varName=%s failIp=%i", ip - 1, varName, failIp ); 1407 1408 ip += 3; 1409 break; 1410 } 1411 1412 case OP_ITER: 1413 { 1414 U32 breakIp = code[ ip ]; 1415 1416 Con::printf( "%i: OP_ITER breakIp=%i", ip - 1, breakIp ); 1417 1418 ++ ip; 1419 break; 1420 } 1421 1422 case OP_ITER_END: 1423 { 1424 Con::printf( "%i: OP_ITER_END", ip - 1 ); 1425 break; 1426 } 1427 1428 default: 1429 Con::printf( "%i: !!INVALID!!", ip - 1 ); 1430 break; 1431 } 1432 } 1433 1434 smInFunction = false; 1435} 1436
