diff options
Diffstat (limited to 'generic/tclExecute.c')
-rw-r--r-- | generic/tclExecute.c | 159 |
1 files changed, 94 insertions, 65 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 1d354e8..35bac19 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.283 2007/05/11 09:41:57 dkf Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.284 2007/05/17 12:05:18 dkf Exp $ */ #include "tclInt.h" @@ -343,6 +343,31 @@ long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 }; Tcl_GetWideIntFromObj((interp), (objPtr), (wideIntPtr))) #endif +/* + * Inline version of Tcl_LimitReady() to limit number of calls out of this + * file in the critical path. Note that this code isn't particularly readable; + * the non-inline version (in tclInterp.c) is much easier to understand. Note + * also that this macro takes different args (iPtr->limit) to the non-inline + * version. + */ + +#define TclLimitReady(limit) \ + (((limit).active == 0) ? 0 : \ + (++(limit).granularityTicker, \ + ((((limit).active & TCL_LIMIT_COMMANDS) && \ + (((limit).cmdGranularity == 1) || \ + ((limit).granularityTicker % (limit).cmdGranularity == 0))) \ + ? 1 : \ + (((limit).active & TCL_LIMIT_TIME) && \ + (((limit).timeGranularity == 1) || \ + ((limit).granularityTicker % (limit).timeGranularity == 0)))\ + ? 1 : 0))) + +/* + * Custom object type only used in this file; values of its type should never + * be seen by user scripts. + */ + static Tcl_ObjType dictIteratorType = { "dictIterator", NULL, NULL, NULL, NULL @@ -990,7 +1015,7 @@ TclCompEvalObj( * Increment the code's ref count while it is being executed. If * afterwards no references to it remain, free the code. */ - + runCompiledObj: codePtr->refCount++; result = TclExecuteByteCode(interp, codePtr); @@ -1001,19 +1026,19 @@ TclCompEvalObj( iPtr->numLevels--; return result; } - + recompileObj: iPtr->errorLine = 1; - + /* * TIP #280. Remember the invoker for a moment in the interpreter * structures so that the byte code compiler can pick it up when - * initializing the compilation environment, i.e. the extended - * location information. + * initializing the compilation environment, i.e. the extended location + * information. */ - + iPtr->invokeCmdFramePtr = invoker; - iPtr->invokeWord = word; + iPtr->invokeWord = word; result = tclByteCodeType.setFromAnyProc(interp, objPtr); iPtr->invokeCmdFramePtr = NULL; if (result == TCL_OK) { @@ -1024,7 +1049,6 @@ TclCompEvalObj( return result; } } - /* *---------------------------------------------------------------------- @@ -1368,13 +1392,13 @@ TclExecuteByteCode( if ((instructionCount++ & ASYNC_CHECK_COUNT_MASK) == 0) { /* - * Check for asynchronous handlers [Bug 746722]; we do the check every + * Check for asynchronous handlers [Bug 746722]; we do the check every * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-<1). */ if (Tcl_AsyncReady()) { int localResult; - + DECACHE_STACK_INFO(); localResult = Tcl_AsyncInvoke(interp, result); CACHE_STACK_INFO(); @@ -1383,9 +1407,9 @@ TclExecuteByteCode( goto checkForCatch; } } - if (Tcl_LimitReady(interp)) { + if (TclLimitReady(iPtr->limit)) { int localResult; - + DECACHE_STACK_INFO(); localResult = Tcl_LimitCheck(interp); CACHE_STACK_INFO(); @@ -1404,7 +1428,7 @@ TclExecuteByteCode( /* * OBJ_AT_TOS is returnOpts, OBJ_UNDER_TOS is resultObjPtr. */ - + TRACE(("%u %u => ", code, level)); result = TclProcessReturn(interp, code, level, OBJ_AT_TOS); if (result == TCL_OK) { @@ -1436,12 +1460,12 @@ TclExecuteByteCode( case INST_DONE: if (CURR_DEPTH > initStackDepth) { /* - * Set the interpreter's object result to point to the topmost object - * from the stack, and check for a possible [catch]. The stackTop's - * level and refCount will be handled by "processCatch" or - * "abnormalReturn". + * Set the interpreter's object result to point to the topmost + * object from the stack, and check for a possible [catch]. The + * stackTop's level and refCount will be handled by "processCatch" + * or "abnormalReturn". */ - + Tcl_SetObjResult(interp, OBJ_AT_TOS); #ifdef TCL_COMPILE_DEBUG TRACE_WITH_OBJ(("=> return code=%d, result=", result), @@ -1514,8 +1538,8 @@ TclExecuteByteCode( */ iPtr->cmdCount += TclGetUInt4AtPtr(pc+5); - if (!checkInterp) { - instStartCmdOK: + if (!checkInterp) { + instStartCmdOK: #if 0 && !TCL_COMPILE_DEBUG /* * Peephole optimisations: check if there are several @@ -1537,8 +1561,8 @@ TclExecuteByteCode( NEXT_INST_F(9, 0, 0); #endif } else if (((codePtr->compileEpoch == iPtr->compileEpoch) - && (codePtr->nsEpoch == namespacePtr->resolverEpoch)) - || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) { + && (codePtr->nsEpoch == namespacePtr->resolverEpoch)) + || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) { checkInterp = 0; goto instStartCmdOK; } else { @@ -1587,7 +1611,7 @@ TclExecuteByteCode( * Compute the length to be appended. */ - for (currPtr = &OBJ_AT_DEPTH(opnd-2); currPtr <= &OBJ_AT_TOS; currPtr++) { + for (currPtr=&OBJ_AT_DEPTH(opnd-2); currPtr<=&OBJ_AT_TOS; currPtr++) { bytes = Tcl_GetStringFromObj(*currPtr, &length); if (bytes != NULL) { appendLen += length; @@ -1706,14 +1730,14 @@ TclExecuteByteCode( CACHE_STACK_INFO(); /* - * Expand the list at stacktop onto the stack; free the list. Knowing - * that it has a freeIntRepProc we use Tcl_DecrRefCount(). + * Expand the list at stacktop onto the stack; free the list. Knowing + * that it has a freeIntRepProc we use Tcl_DecrRefCount(). */ for (i = 0; i < objc; i++) { PUSH_OBJECT(objv[i]); } - + Tcl_DecrRefCount(valuePtr); NEXT_INST_F(5, 0, 0); } @@ -1823,34 +1847,36 @@ TclExecuteByteCode( if (cmdPtr && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES) && iPtr->tracePtr == NULL - && (!checkInterp || (codePtr->compileEpoch == iPtr->compileEpoch))) { + && (!checkInterp + || (codePtr->compileEpoch == iPtr->compileEpoch))) { /* * No traces, the interp is ok: avoid the call out to TEOVi */ - + cmdPtr->refCount++; iPtr->cmdCount++; iPtr->ensembleRewrite.sourceObjs = NULL; - result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv); + result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, + objc, objv); TclCleanupCommand(cmdPtr); if (Tcl_AsyncReady()) { result = Tcl_AsyncInvoke(interp, result); } - if (result == TCL_OK && Tcl_LimitReady(interp)) { + if (result == TCL_OK && TclLimitReady(iPtr->limit)) { result = Tcl_LimitCheck(interp); } } else { - /* - * If trace procedures will be called, we need a command string to - * pass to TclEvalObjvInternal; note that a copy of the string - * will be made there to include the ending \0. + * If trace procedures will be called, we need a command + * string to pass to TclEvalObjvInternal; note that a copy of + * the string will be made there to include the ending \0. */ - + bytes = GetSrcInfoForPc(pc, codePtr, &length); - result = TclEvalObjvInternal(interp, objc, objv, bytes, length, 0); + result = TclEvalObjvInternal(interp, objc, objv, bytes, + length, 0); } - + CACHE_STACK_INFO(); iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr; @@ -2033,7 +2059,7 @@ TclExecuteByteCode( case INST_LOAD_ARRAY_STK: cleanup = 2; part2 = Tcl_GetString(OBJ_AT_TOS); /* element name */ - objPtr = OBJ_UNDER_TOS; /* array name */ + objPtr = OBJ_UNDER_TOS; /* array name */ TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), part2)); goto doLoadStk; @@ -2086,14 +2112,15 @@ TclExecuteByteCode( if (!TclIsVarUndefined(arrayPtr) && TclIsVarArray(arrayPtr) && TclIsVarUntraced(arrayPtr)) { - Tcl_HashEntry *hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr, part2); + Tcl_HashEntry *hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr, + part2); if (hPtr) { varPtr = (Var *) Tcl_GetHashValue(hPtr); } else { goto doLoadArrayNextBranch; } } else { - doLoadArrayNextBranch: + doLoadArrayNextBranch: varPtr = TclLookupArrayElement(interp, part1, part2, TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr); if (varPtr == NULL) { @@ -2266,7 +2293,8 @@ TclExecuteByteCode( if (!TclIsVarUndefined(arrayPtr) && TclIsVarArray(arrayPtr) && TclIsVarUntraced(arrayPtr)) { - Tcl_HashEntry *hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr, part2); + Tcl_HashEntry *hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr, + part2); if (hPtr) { varPtr = (Var *) Tcl_GetHashValue(hPtr); goto doCallPtrSetVar; @@ -2677,7 +2705,7 @@ TclExecuteByteCode( case INST_UPVAR: { int opnd; Var *varPtr, *otherPtr; - + TRACE_WITH_OBJ(("upvar "), OBJ_UNDER_TOS); { @@ -2688,7 +2716,7 @@ TclExecuteByteCode( /* * Locate the other variable */ - + savedFramePtr = iPtr->varFramePtr; iPtr->varFramePtr = framePtr; otherPtr = TclObjLookupVar(interp, OBJ_AT_TOS, NULL, @@ -2696,27 +2724,27 @@ TclExecuteByteCode( /*createPart1*/ 1, /*createPart2*/ 1, &varPtr); iPtr->varFramePtr = savedFramePtr; if (otherPtr) { - result = TCL_OK; + result = TCL_OK; goto doLinkVars; } } result = TCL_ERROR; goto checkForCatch; } - + case INST_VARIABLE: - case INST_NSUPVAR: + case INST_NSUPVAR: TRACE_WITH_OBJ(("nsupvar "), OBJ_UNDER_TOS); { Tcl_Namespace *nsPtr, *savedNsPtr; - + result = TclGetNamespaceFromObj(interp, OBJ_UNDER_TOS, &nsPtr); if ((result == TCL_OK) && nsPtr) { /* * Locate the other variable */ - + savedNsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr; iPtr->varFramePtr->nsPtr = (Namespace *) nsPtr; otherPtr = TclObjLookupVar(interp, OBJ_AT_TOS, NULL, @@ -2727,31 +2755,32 @@ TclExecuteByteCode( /* * Do the [variable] magic if necessary */ - - if ((*pc == INST_VARIABLE) && !TclIsVarNamespaceVar(otherPtr)) { + + if ((*pc == INST_VARIABLE) + && !TclIsVarNamespaceVar(otherPtr)) { TclSetVarNamespaceVar(otherPtr); otherPtr->refCount++; } } else { result = TCL_ERROR; goto checkForCatch; - } + } } else { if (nsPtr == NULL) { /* * The namespace does not exist, leave an error message. */ + Tcl_SetObjResult(interp, Tcl_Format(NULL, - "namespace \"%s\" does not exist", 1, - &OBJ_UNDER_TOS)); + "namespace \"%s\" does not exist", 1, + &OBJ_UNDER_TOS)); result = TCL_ERROR; } goto checkForCatch; } - } - - doLinkVars: + + doLinkVars: /* * If we are here, the local variable has already been created: do the @@ -2762,7 +2791,7 @@ TclExecuteByteCode( opnd = TclGetInt4AtPtr(pc+1);; varPtr = &(compiledLocals[opnd]); if ((varPtr != otherPtr) && (varPtr->tracePtr == NULL) - && (TclIsVarUndefined(varPtr) || TclIsVarLink(varPtr))) { + && (TclIsVarUndefined(varPtr) || TclIsVarLink(varPtr))) { if (!TclIsVarUndefined(varPtr)) { /* Then it is a defined link */ Var *linkPtr = varPtr->value.linkPtr; @@ -2790,7 +2819,7 @@ TclExecuteByteCode( * variables. */ - doLinkVarsDone: + doLinkVarsDone: NEXT_INST_F(5, 1, 0); } @@ -3034,7 +3063,7 @@ TclExecuteByteCode( * Select the list item based on the index. Negative operand means * end-based indexing. */ - + if (opnd < -1) { idx = opnd+1 + listc; } else { @@ -3045,7 +3074,7 @@ TclExecuteByteCode( } else { TclNewObj(objResultPtr); } - + TRACE_WITH_OBJ(("\"%.30s\" %d => ", O2S(valuePtr), opnd), objResultPtr); NEXT_INST_F(5, 1, 1); @@ -3107,7 +3136,7 @@ TclExecuteByteCode( * Get the old value of variable, and remove the stack ref. This is * safe because the variable still references the object; the ref * count will never go zero here - we can use the smaller macro - * Tcl_DecrRefCount. + * Tcl_DecrRefCount. */ value2Ptr = POP_OBJECT(); @@ -3134,7 +3163,7 @@ TclExecuteByteCode( /* * Set result */ - + TRACE(("%d => %s\n", opnd, O2S(objResultPtr))); NEXT_INST_V(5, (numIdx+1), -1); } else { @@ -3155,7 +3184,7 @@ TclExecuteByteCode( * Get the old value of variable, and remove the stack ref. This is * safe because the variable still references the object; the ref * count will never go zero here - we can use the smaller macro - * Tcl_DecrRefCount. + * Tcl_DecrRefCount. */ objPtr = POP_OBJECT(); @@ -3182,7 +3211,7 @@ TclExecuteByteCode( /* * Set result */ - + TRACE(("=> %s\n", O2S(objResultPtr))); NEXT_INST_F(1, 2, -1); } else { |