📄 tclcompile.c
字号:
char *lastChar, int flags, CompileEnv *envPtr));static int CompileExprWord _ANSI_ARGS_((Tcl_Interp *interp, char *string, char *lastChar, int flags, CompileEnv *envPtr));static int CompileMultipartWord _ANSI_ARGS_(( Tcl_Interp *interp, char *string, char *lastChar, int flags, CompileEnv *envPtr));static int CompileWord _ANSI_ARGS_((Tcl_Interp *interp, char *string, char *lastChar, int flags, CompileEnv *envPtr));static int CreateExceptionRange _ANSI_ARGS_(( ExceptionRangeType type, CompileEnv *envPtr));static void DupByteCodeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr));static ClientData DupForeachInfo _ANSI_ARGS_((ClientData clientData));static unsigned char * EncodeCmdLocMap _ANSI_ARGS_(( CompileEnv *envPtr, ByteCode *codePtr, unsigned char *startPtr));static void EnterCmdExtentData _ANSI_ARGS_(( CompileEnv *envPtr, int cmdNumber, int numSrcChars, int numCodeBytes));static void EnterCmdStartData _ANSI_ARGS_(( CompileEnv *envPtr, int cmdNumber, int srcOffset, int codeOffset));static void ExpandObjectArray _ANSI_ARGS_((CompileEnv *envPtr));static void FreeForeachInfo _ANSI_ARGS_(( ClientData clientData));static void FreeByteCodeInternalRep _ANSI_ARGS_(( Tcl_Obj *objPtr));static void FreeArgInfo _ANSI_ARGS_((ArgInfo *argInfoPtr));static int GetCmdLocEncodingSize _ANSI_ARGS_(( CompileEnv *envPtr));static void InitArgInfo _ANSI_ARGS_((ArgInfo *argInfoPtr));static int IsLocalScalar _ANSI_ARGS_((char *name, int len));static int LookupCompiledLocal _ANSI_ARGS_(( char *name, int nameChars, int createIfNew, int flagsIfCreated, Proc *procPtr));static int SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *objPtr));static void UpdateStringOfByteCode _ANSI_ARGS_((Tcl_Obj *objPtr));/* * The structure below defines the bytecode Tcl object type by * means of procedures that can be invoked by generic object code. */Tcl_ObjType tclByteCodeType = { "bytecode", /* name */ FreeByteCodeInternalRep, /* freeIntRepProc */ DupByteCodeInternalRep, /* dupIntRepProc */ UpdateStringOfByteCode, /* updateStringProc */ SetByteCodeFromAny /* setFromAnyProc */};/* * The structures below define the AuxData types defined in this file. */AuxDataType tclForeachInfoType = { "ForeachInfo", /* name */ DupForeachInfo, /* dupProc */ FreeForeachInfo /* freeProc */};/* *---------------------------------------------------------------------- * * TclPrintByteCodeObj -- * * This procedure prints ("disassembles") the instructions of a * bytecode object to stdout. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */voidTclPrintByteCodeObj(interp, objPtr) Tcl_Interp *interp; /* Used only for Tcl_GetStringFromObj. */ Tcl_Obj *objPtr; /* The bytecode object to disassemble. */{ ByteCode* codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr; unsigned char *codeStart, *codeLimit, *pc; unsigned char *codeDeltaNext, *codeLengthNext; unsigned char *srcDeltaNext, *srcLengthNext; int codeOffset, codeLen, srcOffset, srcLen; int numCmds, numObjs, delta, objBytes, i; if (codePtr->refCount <= 0) { return; /* already freed */ } codeStart = codePtr->codeStart; codeLimit = (codeStart + codePtr->numCodeBytes); numCmds = codePtr->numCommands; numObjs = codePtr->numObjects; objBytes = (numObjs * sizeof(Tcl_Obj)); for (i = 0; i < numObjs; i++) { Tcl_Obj *litObjPtr = codePtr->objArrayPtr[i]; if (litObjPtr->bytes != NULL) { objBytes += litObjPtr->length; } } /* * Print header lines describing the ByteCode. */ fprintf(stdout, "\nByteCode 0x%x, ref ct %u, epoch %u, interp 0x%x(epoch %u)\n", (unsigned int) codePtr, codePtr->refCount, codePtr->compileEpoch, (unsigned int) codePtr->iPtr, codePtr->iPtr->compileEpoch); fprintf(stdout, " Source "); TclPrintSource(stdout, codePtr->source, TclMin(codePtr->numSrcChars, 70)); fprintf(stdout, "\n Cmds %d, chars %d, inst %d, objs %u, aux %d, stk depth %u, code/src %.2f\n", numCmds, codePtr->numSrcChars, codePtr->numCodeBytes, numObjs, codePtr->numAuxDataItems, codePtr->maxStackDepth, (codePtr->numSrcChars? ((float)codePtr->totalSize)/((float)codePtr->numSrcChars) : 0.0)); fprintf(stdout, " Code %d = %d(header)+%d(inst)+%d(objs)+%d(exc)+%d(aux)+%d(cmd map)\n", codePtr->totalSize, sizeof(ByteCode), codePtr->numCodeBytes, objBytes, (codePtr->numExcRanges * sizeof(ExceptionRange)), (codePtr->numAuxDataItems * sizeof(AuxData)), codePtr->numCmdLocBytes); /* * If the ByteCode is the compiled body of a Tcl procedure, print * information about that procedure. Note that we don't know the * procedure's name since ByteCode's can be shared among procedures. */ if (codePtr->procPtr != NULL) { Proc *procPtr = codePtr->procPtr; int numCompiledLocals = procPtr->numCompiledLocals; fprintf(stdout, " Proc 0x%x, ref ct %d, args %d, compiled locals %d\n", (unsigned int) procPtr, procPtr->refCount, procPtr->numArgs, numCompiledLocals); if (numCompiledLocals > 0) { CompiledLocal *localPtr = procPtr->firstLocalPtr; for (i = 0; i < numCompiledLocals; i++) { fprintf(stdout, " %d: slot %d%s%s%s%s%s%s", i, localPtr->frameIndex, ((localPtr->flags & VAR_SCALAR)? ", scalar" : ""), ((localPtr->flags & VAR_ARRAY)? ", array" : ""), ((localPtr->flags & VAR_LINK)? ", link" : ""), ((localPtr->flags & VAR_ARGUMENT)? ", arg" : ""), ((localPtr->flags & VAR_TEMPORARY)? ", temp" : ""), ((localPtr->flags & VAR_RESOLVED)? ", resolved" : "")); if (TclIsVarTemporary(localPtr)) { fprintf(stdout, "\n"); } else { fprintf(stdout, ", name=\"%s\"\n", localPtr->name); } localPtr = localPtr->nextPtr; } } } /* * Print the ExceptionRange array. */ if (codePtr->numExcRanges > 0) { fprintf(stdout, " Exception ranges %d, depth %d:\n", codePtr->numExcRanges, codePtr->maxExcRangeDepth); for (i = 0; i < codePtr->numExcRanges; i++) { ExceptionRange *rangePtr = &(codePtr->excRangeArrayPtr[i]); fprintf(stdout, " %d: level %d, %s, pc %d-%d, ", i, rangePtr->nestingLevel, ((rangePtr->type == LOOP_EXCEPTION_RANGE)? "loop":"catch"), rangePtr->codeOffset, (rangePtr->codeOffset + rangePtr->numCodeBytes - 1)); switch (rangePtr->type) { case LOOP_EXCEPTION_RANGE: fprintf(stdout, "continue %d, break %d\n", rangePtr->continueOffset, rangePtr->breakOffset); break; case CATCH_EXCEPTION_RANGE: fprintf(stdout, "catch %d\n", rangePtr->catchOffset); break; default: panic("TclPrintSource: unrecognized ExceptionRange type %d\n", rangePtr->type); } } } /* * If there were no commands (e.g., an expression or an empty string * was compiled), just print all instructions and return. */ if (numCmds == 0) { pc = codeStart; while (pc < codeLimit) { fprintf(stdout, " "); pc += TclPrintInstruction(codePtr, pc); } return; } /* * Print table showing the code offset, source offset, and source * length for each command. These are encoded as a sequence of bytes. */ fprintf(stdout, " Commands %d:", numCmds); codeDeltaNext = codePtr->codeDeltaStart; codeLengthNext = codePtr->codeLengthStart; srcDeltaNext = codePtr->srcDeltaStart; srcLengthNext = codePtr->srcLengthStart; codeOffset = srcOffset = 0; for (i = 0; i < numCmds; i++) { if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) { codeDeltaNext++; delta = TclGetInt4AtPtr(codeDeltaNext); codeDeltaNext += 4; } else { delta = TclGetInt1AtPtr(codeDeltaNext); codeDeltaNext++; } codeOffset += delta; if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) { codeLengthNext++; codeLen = TclGetInt4AtPtr(codeLengthNext); codeLengthNext += 4; } else { codeLen = TclGetInt1AtPtr(codeLengthNext); codeLengthNext++; } if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) { srcDeltaNext++; delta = TclGetInt4AtPtr(srcDeltaNext); srcDeltaNext += 4; } else { delta = TclGetInt1AtPtr(srcDeltaNext); srcDeltaNext++; } srcOffset += delta; if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) { srcLengthNext++; srcLen = TclGetInt4AtPtr(srcLengthNext); srcLengthNext += 4; } else { srcLen = TclGetInt1AtPtr(srcLengthNext); srcLengthNext++; } fprintf(stdout, "%s%4d: pc %d-%d, source %d-%d", ((i % 2)? " " : "\n "), (i+1), codeOffset, (codeOffset + codeLen - 1), srcOffset, (srcOffset + srcLen - 1)); } if ((numCmds > 0) && ((numCmds % 2) != 0)) { fprintf(stdout, "\n"); } /* * Print each instruction. If the instruction corresponds to the start * of a command, print the command's source. Note that we don't need * the code length here. */ codeDeltaNext = codePtr->codeDeltaStart; srcDeltaNext = codePtr->srcDeltaStart; srcLengthNext = codePtr->srcLengthStart; codeOffset = srcOffset = 0; pc = codeStart; for (i = 0; i < numCmds; i++) { if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) { codeDeltaNext++; delta = TclGetInt4AtPtr(codeDeltaNext); codeDeltaNext += 4; } else { delta = TclGetInt1AtPtr(codeDeltaNext); codeDeltaNext++; } codeOffset += delta; if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) { srcDeltaNext++; delta = TclGetInt4AtPtr(srcDeltaNext); srcDeltaNext += 4; } else { delta = TclGetInt1AtPtr(srcDeltaNext); srcDeltaNext++; } srcOffset += delta; if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) { srcLengthNext++; srcLen = TclGetInt4AtPtr(srcLengthNext); srcLengthNext += 4; } else { srcLen = TclGetInt1AtPtr(srcLengthNext); srcLengthNext++; } /* * Print instructions before command i. */ while ((pc-codeStart) < codeOffset) { fprintf(stdout, " "); pc += TclPrintInstruction(codePtr, pc); } fprintf(stdout, " Command %d: ", (i+1)); TclPrintSource(stdout, (codePtr->source + srcOffset), TclMin(srcLen, 70)); fprintf(stdout, "\n"); } if (pc < codeLimit) { /* * Print instructions after the last command. */ while (pc < codeLimit) { fprintf(stdout, " "); pc += TclPrintInstruction(codePtr, pc); } }}/* *---------------------------------------------------------------------- * * TclPrintInstruction -- * * This procedure prints ("disassembles") one instruction from a * bytecode object to stdout. * * Results: * Returns the length in bytes of the current instruiction. * * Side effects: * None. * *---------------------------------------------------------------------- */intTclPrintInstruction(codePtr, pc) ByteCode* codePtr; /* Bytecode containing the instruction. */ unsigned char *pc; /* Points to first byte of instruction. */{ Proc *procPtr = codePtr->procPtr; unsigned char opCode = *pc; register InstructionDesc *instDesc = &instructionTable[opCode]; unsigned char *codeStart = codePtr->codeStart; unsigned int pcOffset = (pc - codeStart); int opnd, elemLen, i, j; Tcl_Obj *elemPtr; char *string; fprintf(stdout, "(%u) %s ", pcOffset, instDesc->name); for (i = 0; i < instDesc->numOperands; i++) { switch (instDesc->opTypes[i]) { case OPERAND_INT1: opnd = TclGetInt1AtPtr(pc+1+i); if ((i == 0) && ((opCode == INST_JUMP1) || (opCode == INST_JUMP_TRUE1) || (opCode == INST_JUMP_FALSE1))) { fprintf(stdout, "%d # pc %u", opnd, (pcOffset + opnd));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -