Changes in external/tcl/tclCompile.c [adeddd8:d7d2da3] in git
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
external/tcl/tclCompile.c
radeddd8 rd7d2da3 17 17 #include "tclInt.h" 18 18 #include "tclCompile.h" 19 20 /* 21 * Variable that controls whether compilation tracing is enabled and, if so, 22 * what level of tracing is desired: 23 * 0: no compilation tracing 24 * 1: summarize compilation of top level cmds and proc bodies 25 * 2: display all instructions of each ByteCode compiled 26 * This variable is linked to the Tcl variable "tcl_traceCompile". 27 */ 28 29 int tclTraceCompile = 0; 30 static int traceInitialized = 0; 31 32 /* 33 * Count of the number of compilations and various other compilation- 34 * related statistics. 35 */ 36 37 #ifdef TCL_COMPILE_STATS 38 long tclNumCompilations = 0; 39 double tclTotalSourceBytes = 0.0; 40 double tclTotalCodeBytes = 0.0; 41 42 double tclTotalInstBytes = 0.0; 43 double tclTotalObjBytes = 0.0; 44 double tclTotalExceptBytes = 0.0; 45 double tclTotalAuxBytes = 0.0; 46 double tclTotalCmdMapBytes = 0.0; 47 48 double tclCurrentSourceBytes = 0.0; 49 double tclCurrentCodeBytes = 0.0; 50 51 int tclSourceCount[32]; 52 int tclByteCodeCount[32]; 53 #endif /* TCL_COMPILE_STATS */ 19 54 20 55 /* … … 408 443 *---------------------------------------------------------------------- 409 444 * 445 * TclPrintByteCodeObj -- 446 * 447 * This procedure prints ("disassembles") the instructions of a 448 * bytecode object to stdout. 449 * 450 * Results: 451 * None. 452 * 453 * Side effects: 454 * None. 455 * 456 *---------------------------------------------------------------------- 457 */ 458 459 void 460 TclPrintByteCodeObj(interp, objPtr) 461 Tcl_Interp *interp; /* Used only for Tcl_GetStringFromObj. */ 462 Tcl_Obj *objPtr; /* The bytecode object to disassemble. */ 463 { 464 ByteCode* codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; 465 unsigned char *codeStart, *codeLimit, *pc; 466 unsigned char *codeDeltaNext, *codeLengthNext; 467 unsigned char *srcDeltaNext, *srcLengthNext; 468 int codeOffset, codeLen, srcOffset, srcLen; 469 int numCmds, numObjs, delta, objBytes, i; 470 471 if (codePtr->refCount <= 0) { 472 return; /* already freed */ 473 } 474 475 codeStart = codePtr->codeStart; 476 codeLimit = (codeStart + codePtr->numCodeBytes); 477 numCmds = codePtr->numCommands; 478 numObjs = codePtr->numObjects; 479 480 objBytes = (numObjs * sizeof(Tcl_Obj)); 481 for (i = 0; i < numObjs; i++) { 482 Tcl_Obj *litObjPtr = codePtr->objArrayPtr[i]; 483 if (litObjPtr->bytes != NULL) { 484 objBytes += litObjPtr->length; 485 } 486 } 487 488 /* 489 * Print header lines describing the ByteCode. 490 */ 491 492 fprintf(stdout, "\nByteCode 0x%x, ref ct %u, epoch %u, interp 0x%x(epoch %u)\n", 493 (unsigned int) codePtr, codePtr->refCount, 494 codePtr->compileEpoch, (unsigned int) codePtr->iPtr, 495 codePtr->iPtr->compileEpoch); 496 fprintf(stdout, " Source "); 497 TclPrintSource(stdout, codePtr->source, 498 TclMin(codePtr->numSrcChars, 70)); 499 fprintf(stdout, "\n Cmds %d, chars %d, inst %d, objs %u, aux %d, stk depth %u, code/src %.2f\n", 500 numCmds, codePtr->numSrcChars, codePtr->numCodeBytes, numObjs, 501 codePtr->numAuxDataItems, codePtr->maxStackDepth, 502 (codePtr->numSrcChars? 503 ((float)codePtr->totalSize)/((float)codePtr->numSrcChars) : 0.0)); 504 fprintf(stdout, " Code %zu = %u(header)+%d(inst)+%d(objs)+%u(exc)+%u(aux)+%d(cmd map)\n", 505 codePtr->totalSize, sizeof(ByteCode), codePtr->numCodeBytes, 506 objBytes, (codePtr->numExcRanges * sizeof(ExceptionRange)), 507 (codePtr->numAuxDataItems * sizeof(AuxData)), 508 codePtr->numCmdLocBytes); 509 510 /* 511 * If the ByteCode is the compiled body of a Tcl procedure, print 512 * information about that procedure. Note that we don't know the 513 * procedure's name since ByteCode's can be shared among procedures. 514 */ 515 516 if (codePtr->procPtr != NULL) { 517 Proc *procPtr = codePtr->procPtr; 518 int numCompiledLocals = procPtr->numCompiledLocals; 519 fprintf(stdout, 520 " Proc 0x%x, ref ct %d, args %d, compiled locals %d\n", 521 (unsigned int) procPtr, procPtr->refCount, procPtr->numArgs, 522 numCompiledLocals); 523 if (numCompiledLocals > 0) { 524 CompiledLocal *localPtr = procPtr->firstLocalPtr; 525 for (i = 0; i < numCompiledLocals; i++) { 526 fprintf(stdout, " %d: slot %d%s%s%s%s%s%s", 527 i, localPtr->frameIndex, 528 ((localPtr->flags & VAR_SCALAR)? ", scalar" : ""), 529 ((localPtr->flags & VAR_ARRAY)? ", array" : ""), 530 ((localPtr->flags & VAR_LINK)? ", link" : ""), 531 ((localPtr->flags & VAR_ARGUMENT)? ", arg" : ""), 532 ((localPtr->flags & VAR_TEMPORARY)? ", temp" : ""), 533 ((localPtr->flags & VAR_RESOLVED)? ", resolved" : "")); 534 if (TclIsVarTemporary(localPtr)) { 535 fprintf(stdout, "\n"); 536 } else { 537 fprintf(stdout, ", name=\"%s\"\n", localPtr->name); 538 } 539 localPtr = localPtr->nextPtr; 540 } 541 } 542 } 543 544 /* 545 * Print the ExceptionRange array. 546 */ 547 548 if (codePtr->numExcRanges > 0) { 549 fprintf(stdout, " Exception ranges %d, depth %d:\n", 550 codePtr->numExcRanges, codePtr->maxExcRangeDepth); 551 for (i = 0; i < codePtr->numExcRanges; i++) { 552 ExceptionRange *rangePtr = &(codePtr->excRangeArrayPtr[i]); 553 fprintf(stdout, " %d: level %d, %s, pc %d-%d, ", 554 i, rangePtr->nestingLevel, 555 ((rangePtr->type == LOOP_EXCEPTION_RANGE)? "loop":"catch"), 556 rangePtr->codeOffset, 557 (rangePtr->codeOffset + rangePtr->numCodeBytes - 1)); 558 switch (rangePtr->type) { 559 case LOOP_EXCEPTION_RANGE: 560 fprintf(stdout, "continue %d, break %d\n", 561 rangePtr->continueOffset, rangePtr->breakOffset); 562 break; 563 case CATCH_EXCEPTION_RANGE: 564 fprintf(stdout, "catch %d\n", rangePtr->catchOffset); 565 break; 566 default: 567 panic("TclPrintSource: unrecognized ExceptionRange type %d\n", 568 rangePtr->type); 569 } 570 } 571 } 572 573 /* 574 * If there were no commands (e.g., an expression or an empty string 575 * was compiled), just print all instructions and return. 576 */ 577 578 if (numCmds == 0) { 579 pc = codeStart; 580 while (pc < codeLimit) { 581 fprintf(stdout, " "); 582 pc += TclPrintInstruction(codePtr, pc); 583 } 584 return; 585 } 586 587 /* 588 * Print table showing the code offset, source offset, and source 589 * length for each command. These are encoded as a sequence of bytes. 590 */ 591 592 fprintf(stdout, " Commands %d:", numCmds); 593 codeDeltaNext = codePtr->codeDeltaStart; 594 codeLengthNext = codePtr->codeLengthStart; 595 srcDeltaNext = codePtr->srcDeltaStart; 596 srcLengthNext = codePtr->srcLengthStart; 597 codeOffset = srcOffset = 0; 598 for (i = 0; i < numCmds; i++) { 599 if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) { 600 codeDeltaNext++; 601 delta = TclGetInt4AtPtr(codeDeltaNext); 602 codeDeltaNext += 4; 603 } else { 604 delta = TclGetInt1AtPtr(codeDeltaNext); 605 codeDeltaNext++; 606 } 607 codeOffset += delta; 608 609 if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) { 610 codeLengthNext++; 611 codeLen = TclGetInt4AtPtr(codeLengthNext); 612 codeLengthNext += 4; 613 } else { 614 codeLen = TclGetInt1AtPtr(codeLengthNext); 615 codeLengthNext++; 616 } 617 618 if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) { 619 srcDeltaNext++; 620 delta = TclGetInt4AtPtr(srcDeltaNext); 621 srcDeltaNext += 4; 622 } else { 623 delta = TclGetInt1AtPtr(srcDeltaNext); 624 srcDeltaNext++; 625 } 626 srcOffset += delta; 627 628 if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) { 629 srcLengthNext++; 630 srcLen = TclGetInt4AtPtr(srcLengthNext); 631 srcLengthNext += 4; 632 } else { 633 srcLen = TclGetInt1AtPtr(srcLengthNext); 634 srcLengthNext++; 635 } 636 637 fprintf(stdout, "%s%4d: pc %d-%d, source %d-%d", 638 ((i % 2)? " " : "\n "), 639 (i+1), codeOffset, (codeOffset + codeLen - 1), 640 srcOffset, (srcOffset + srcLen - 1)); 641 } 642 if ((numCmds > 0) && ((numCmds % 2) != 0)) { 643 fprintf(stdout, "\n"); 644 } 645 646 /* 647 * Print each instruction. If the instruction corresponds to the start 648 * of a command, print the command's source. Note that we don't need 649 * the code length here. 650 */ 651 652 codeDeltaNext = codePtr->codeDeltaStart; 653 srcDeltaNext = codePtr->srcDeltaStart; 654 srcLengthNext = codePtr->srcLengthStart; 655 codeOffset = srcOffset = 0; 656 pc = codeStart; 657 for (i = 0; i < numCmds; i++) { 658 if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) { 659 codeDeltaNext++; 660 delta = TclGetInt4AtPtr(codeDeltaNext); 661 codeDeltaNext += 4; 662 } else { 663 delta = TclGetInt1AtPtr(codeDeltaNext); 664 codeDeltaNext++; 665 } 666 codeOffset += delta; 667 668 if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) { 669 srcDeltaNext++; 670 delta = TclGetInt4AtPtr(srcDeltaNext); 671 srcDeltaNext += 4; 672 } else { 673 delta = TclGetInt1AtPtr(srcDeltaNext); 674 srcDeltaNext++; 675 } 676 srcOffset += delta; 677 678 if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) { 679 srcLengthNext++; 680 srcLen = TclGetInt4AtPtr(srcLengthNext); 681 srcLengthNext += 4; 682 } else { 683 srcLen = TclGetInt1AtPtr(srcLengthNext); 684 srcLengthNext++; 685 } 686 687 /* 688 * Print instructions before command i. 689 */ 690 691 while ((pc-codeStart) < codeOffset) { 692 fprintf(stdout, " "); 693 pc += TclPrintInstruction(codePtr, pc); 694 } 695 696 fprintf(stdout, " Command %d: ", (i+1)); 697 TclPrintSource(stdout, (codePtr->source + srcOffset), 698 TclMin(srcLen, 70)); 699 fprintf(stdout, "\n"); 700 } 701 if (pc < codeLimit) { 702 /* 703 * Print instructions after the last command. 704 */ 705 706 while (pc < codeLimit) { 707 fprintf(stdout, " "); 708 pc += TclPrintInstruction(codePtr, pc); 709 } 710 } 711 } 712 713 714 /* 715 *---------------------------------------------------------------------- 716 * 717 * TclPrintInstruction -- 718 * 719 * This procedure prints ("disassembles") one instruction from a 720 * bytecode object to stdout. 721 * 722 * Results: 723 * Returns the length in bytes of the current instruiction. 724 * 725 * Side effects: 726 * None. 727 * 728 *---------------------------------------------------------------------- 729 */ 730 731 int 732 TclPrintInstruction(codePtr, pc) 733 ByteCode* codePtr; /* Bytecode containing the instruction. */ 734 unsigned char *pc; /* Points to first byte of instruction. */ 735 { 736 Proc *procPtr = codePtr->procPtr; 737 unsigned char opCode = *pc; 738 register InstructionDesc *instDesc = &instructionTable[opCode]; 739 unsigned char *codeStart = codePtr->codeStart; 740 unsigned int pcOffset = (pc - codeStart); 741 int opnd, elemLen, i, j; 742 Tcl_Obj *elemPtr; 743 char *string; 744 745 fprintf(stdout, "(%u) %s ", pcOffset, instDesc->name); 746 for (i = 0; i < instDesc->numOperands; i++) { 747 switch (instDesc->opTypes[i]) { 748 case OPERAND_INT1: 749 opnd = TclGetInt1AtPtr(pc+1+i); 750 if ((i == 0) && ((opCode == INST_JUMP1) 751 || (opCode == INST_JUMP_TRUE1) 752 || (opCode == INST_JUMP_FALSE1))) { 753 fprintf(stdout, "%d # pc %u", opnd, (pcOffset + opnd)); 754 } else { 755 fprintf(stdout, "%d", opnd); 756 } 757 break; 758 case OPERAND_INT4: 759 opnd = TclGetInt4AtPtr(pc+1+i); 760 if ((i == 0) && ((opCode == INST_JUMP4) 761 || (opCode == INST_JUMP_TRUE4) 762 || (opCode == INST_JUMP_FALSE4))) { 763 fprintf(stdout, "%d # pc %u", opnd, (pcOffset + opnd)); 764 } else { 765 fprintf(stdout, "%d", opnd); 766 } 767 break; 768 case OPERAND_UINT1: 769 opnd = TclGetUInt1AtPtr(pc+1+i); 770 if ((i == 0) && (opCode == INST_PUSH1)) { 771 elemPtr = codePtr->objArrayPtr[opnd]; 772 string = Tcl_GetStringFromObj(elemPtr, &elemLen); 773 fprintf(stdout, "%u # ", (unsigned int) opnd); 774 TclPrintSource(stdout, string, TclMin(elemLen, 40)); 775 } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR1) 776 || (opCode == INST_LOAD_ARRAY1) 777 || (opCode == INST_STORE_SCALAR1) 778 || (opCode == INST_STORE_ARRAY1))) { 779 int localCt = procPtr->numCompiledLocals; 780 CompiledLocal *localPtr = procPtr->firstLocalPtr; 781 if (opnd >= localCt) { 782 panic("TclPrintInstruction: bad local var index %u (%u locals)\n", 783 (unsigned int) opnd, localCt); 784 return instDesc->numBytes; 785 } 786 for (j = 0; j < opnd; j++) { 787 localPtr = localPtr->nextPtr; 788 } 789 if (TclIsVarTemporary(localPtr)) { 790 fprintf(stdout, "%u # temp var %u", 791 (unsigned int) opnd, (unsigned int) opnd); 792 } else { 793 fprintf(stdout, "%u # var ", (unsigned int) opnd); 794 TclPrintSource(stdout, localPtr->name, 40); 795 } 796 } else { 797 fprintf(stdout, "%u ", (unsigned int) opnd); 798 } 799 break; 800 case OPERAND_UINT4: 801 opnd = TclGetUInt4AtPtr(pc+1+i); 802 if (opCode == INST_PUSH4) { 803 elemPtr = codePtr->objArrayPtr[opnd]; 804 string = Tcl_GetStringFromObj(elemPtr, &elemLen); 805 fprintf(stdout, "%u # ", opnd); 806 TclPrintSource(stdout, string, TclMin(elemLen, 40)); 807 } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR4) 808 || (opCode == INST_LOAD_ARRAY4) 809 || (opCode == INST_STORE_SCALAR4) 810 || (opCode == INST_STORE_ARRAY4))) { 811 int localCt = procPtr->numCompiledLocals; 812 CompiledLocal *localPtr = procPtr->firstLocalPtr; 813 if (opnd >= localCt) { 814 panic("TclPrintInstruction: bad local var index %u (%u locals)\n", 815 (unsigned int) opnd, localCt); 816 return instDesc->numBytes; 817 } 818 for (j = 0; j < opnd; j++) { 819 localPtr = localPtr->nextPtr; 820 } 821 if (TclIsVarTemporary(localPtr)) { 822 fprintf(stdout, "%u # temp var %u", 823 (unsigned int) opnd, (unsigned int) opnd); 824 } else { 825 fprintf(stdout, "%u # var ", (unsigned int) opnd); 826 TclPrintSource(stdout, localPtr->name, 40); 827 } 828 } else { 829 fprintf(stdout, "%u ", (unsigned int) opnd); 830 } 831 break; 832 case OPERAND_NONE: 833 default: 834 break; 835 } 836 } 837 fprintf(stdout, "\n"); 838 return instDesc->numBytes; 839 } 840 841 842 /* 843 *---------------------------------------------------------------------- 844 * 410 845 * TclPrintSource -- 411 846 * … … 537 972 register int i; 538 973 974 #ifdef TCL_COMPILE_STATS 975 tclCurrentSourceBytes -= (double) codePtr->numSrcChars; 976 tclCurrentCodeBytes -= (double) codePtr->totalSize; 977 #endif /* TCL_COMPILE_STATS */ 978 539 979 /* 540 980 * A single heap object holds the ByteCode structure and its code, … … 627 1067 int length, result; 628 1068 1069 if (!traceInitialized) { 1070 if (Tcl_LinkVar(interp, "tcl_traceCompile", 1071 (char *) &tclTraceCompile, TCL_LINK_INT) != TCL_OK) { 1072 panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable"); 1073 } 1074 traceInitialized = 1; 1075 } 1076 629 1077 string = Tcl_GetStringFromObj(objPtr, &length); 630 1078 TclInitCompileEnv(interp, &compEnv, string); … … 665 1113 TclFreeCompileEnv(&compEnv); 666 1114 1115 if (result == TCL_OK) { 1116 if (tclTraceCompile == 2) { 1117 TclPrintByteCodeObj(interp, objPtr); 1118 } 1119 } 667 1120 return result; 668 1121 } … … 858 1311 int numObjects, i; 859 1312 Namespace *namespacePtr; 1313 #ifdef TCL_COMPILE_STATS 1314 int srcLenLog2, sizeLog2; 1315 #endif /*TCL_COMPILE_STATS*/ 860 1316 861 1317 codeBytes = (envPtr->codeNext - envPtr->codeStart); … … 886 1342 } 887 1343 totalSize = (size + objBytes); 1344 1345 #ifdef TCL_COMPILE_STATS 1346 tclNumCompilations++; 1347 tclTotalSourceBytes += (double) srcLen; 1348 tclTotalCodeBytes += (double) totalSize; 1349 1350 tclTotalInstBytes += (double) codeBytes; 1351 tclTotalObjBytes += (double) objBytes; 1352 tclTotalExceptBytes += exceptArrayBytes; 1353 tclTotalAuxBytes += (double) auxDataArrayBytes; 1354 tclTotalCmdMapBytes += (double) cmdLocBytes; 1355 1356 tclCurrentSourceBytes += (double) srcLen; 1357 tclCurrentCodeBytes += (double) totalSize; 1358 1359 srcLenLog2 = TclLog2(srcLen); 1360 sizeLog2 = TclLog2((int) totalSize); 1361 if ((srcLenLog2 > 31) || (sizeLog2 > 31)) { 1362 panic("TclInitByteCodeObj: bad source or code sizes\n"); 1363 } 1364 tclSourceCount[srcLenLog2]++; 1365 tclByteCodeCount[sizeLog2]++; 1366 #endif /* TCL_COMPILE_STATS */ 888 1367 889 1368 if (envPtr->iPtr->varFramePtr != NULL) { … … 1341 1820 cmdCodeOffset); 1342 1821 1822 if ((!(flags & TCL_BRACKET_TERM)) 1823 && (tclTraceCompile >= 1) && (envPtr->procPtr == NULL)) { 1824 /* 1825 * Display a line summarizing the top level command we are about 1826 * to compile. 1827 */ 1828 1829 char *p = cmdSrcStart; 1830 int numChars, complete; 1831 1832 while ((CHAR_TYPE(p, lastChar) != TCL_COMMAND_END) 1833 || ((*p == ']') && !(flags & TCL_BRACKET_TERM))) { 1834 p++; 1835 } 1836 numChars = (p - cmdSrcStart); 1837 complete = 1; 1838 if (numChars > 60) { 1839 numChars = 60; 1840 complete = 0; 1841 } else if ((numChars >= 2) && (*p == '\n') && (*(p-1) == '{')) { 1842 complete = 0; 1843 } 1844 fprintf(stdout, "Compiling: %.*s%s\n", 1845 numChars, cmdSrcStart, (complete? "" : " ...")); 1846 } 1847 1343 1848 while ((type != TCL_COMMAND_END) 1344 1849 || ((c == ']') && !(flags & TCL_BRACKET_TERM))) {
Note:
See TracChangeset
for help on using the changeset viewer.