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