diff options
Diffstat (limited to 'generic/tclExecute.c')
-rw-r--r-- | generic/tclExecute.c | 657 |
1 files changed, 540 insertions, 117 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 2ed1537..26d3e04 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -171,21 +171,19 @@ static BuiltinFunc const tclBuiltinFuncTable[] = { typedef struct TEBCdata { ByteCode *codePtr; /* Constant until the BC returns */ /* -----------------------------------------*/ - Tcl_Obj **tosPtr; const unsigned char *pc; /* These fields are used on return TO this */ - int catchDepth; /* this level: they record the state when a */ + ptrdiff_t *catchTop; /* this level: they record the state when a */ int cleanup; /* new codePtr was received for NR */ Tcl_Obj *auxObjList; /* execution. */ int checkInterp; CmdFrame cmdFrame; - unsigned int capacity; void * stack[1]; /* Start of the actual combined catch and obj * stacks; the struct will be expanded as * necessary */ } TEBCdata; #define TEBC_YIELD() \ - TD->tosPtr = tosPtr; \ + esPtr->tosPtr = tosPtr; \ TD->pc = pc; \ TD->cleanup = cleanup; \ TclNRAddCallback(interp, TEBCresume, TD, \ @@ -194,7 +192,7 @@ typedef struct TEBCdata { #define TEBC_DATA_DIG() \ pc = TD->pc; \ cleanup = TD->cleanup; \ - tosPtr = TD->tosPtr + tosPtr = esPtr->tosPtr #define PUSH_TAUX_OBJ(objPtr) \ @@ -298,6 +296,20 @@ VarHashCreateVar( } while (0) /* + * Macros used to cache often-referenced Tcl evaluation stack information + * in local variables. Note that a DECACHE_STACK_INFO()-CACHE_STACK_INFO() + * pair must surround any call inside TclNRExecuteByteCode (and a few other + * procedures that use this scheme) that could result in a recursive call + * to TclNRExecuteByteCode. + */ + +#define CACHE_STACK_INFO() \ + checkInterp = 1 + +#define DECACHE_STACK_INFO() \ + esPtr->tosPtr = tosPtr + +/* * Macros used to access items on the Tcl evaluation stack. PUSH_OBJECT * increments the object's ref count since it makes the stack have another * reference pointing to the object. However, POP_OBJECT does not decrement @@ -671,6 +683,7 @@ static void ValidatePcAndStackTop(ByteCode *codePtr, int stackLowerBound, int checkStack); #endif /* TCL_COMPILE_DEBUG */ static ByteCode * CompileExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr); +static void DeleteExecStack(ExecStack *esPtr); static void DupExprCodeInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); MODULE_SCOPE int TclCompareTwoNumbers(Tcl_Obj *valuePtr, @@ -686,10 +699,16 @@ static ExceptionRange * GetExceptRangeForPc(const unsigned char *pc, static const char * GetSrcInfoForPc(const unsigned char *pc, ByteCode *codePtr, int *lengthPtr, const unsigned char **pcBeg); +static Tcl_Obj ** GrowEvaluationStack(ExecEnv *eePtr, int growth, + int move); static void IllegalExprOperandType(Tcl_Interp *interp, const unsigned char *pc, Tcl_Obj *opndPtr); static void InitByteCodeExecution(Tcl_Interp *interp); +static inline int OFFSET(void *ptr); static void ReleaseDictIterator(Tcl_Obj *objPtr); +/* Useful elsewhere, make available in tclInt.h or stubs? */ +static Tcl_Obj ** StackAllocWords(Tcl_Interp *interp, int numWords); +static Tcl_Obj ** StackReallocWords(Tcl_Interp *interp, int numWords); static Tcl_NRPostProc CopyCallback; static Tcl_NRPostProc ExprObjCallback; @@ -826,7 +845,10 @@ TclCreateExecEnv( * [sizeof(Tcl_Obj*)] */ { ExecEnv *eePtr = ckalloc(sizeof(ExecEnv)); + ExecStack *esPtr = ckalloc(sizeof(ExecStack) + + (size_t) (size-1) * sizeof(Tcl_Obj *)); + eePtr->execStackPtr = esPtr; TclNewBooleanObj(eePtr->constants[0], 0); Tcl_IncrRefCount(eePtr->constants[0]); TclNewBooleanObj(eePtr->constants[1], 1); @@ -836,6 +858,12 @@ TclCreateExecEnv( eePtr->corPtr = NULL; eePtr->rewind = 0; + esPtr->prevPtr = NULL; + esPtr->nextPtr = NULL; + esPtr->markerPtr = NULL; + esPtr->endPtr = &esPtr->stackWords[size-1]; + esPtr->tosPtr = &esPtr->stackWords[-1]; + Tcl_MutexLock(&execMutex); if (!execInitialized) { TclInitAuxDataTypeTable(); @@ -864,14 +892,42 @@ TclCreateExecEnv( *---------------------------------------------------------------------- */ +static void +DeleteExecStack( + ExecStack *esPtr) +{ + if (esPtr->markerPtr) { + Tcl_Panic("freeing an execStack which is still in use"); + } + + if (esPtr->prevPtr) { + esPtr->prevPtr->nextPtr = esPtr->nextPtr; + } + if (esPtr->nextPtr) { + esPtr->nextPtr->prevPtr = esPtr->prevPtr; + } + ckfree(esPtr); +} + void TclDeleteExecEnv( ExecEnv *eePtr) /* Execution environment to free. */ { + ExecStack *esPtr = eePtr->execStackPtr, *tmpPtr; + /* * Delete all stacks in this exec env. */ + while (esPtr->nextPtr) { + esPtr = esPtr->nextPtr; + } + while (esPtr) { + tmpPtr = esPtr; + esPtr = tmpPtr->prevPtr; + DeleteExecStack(tmpPtr); + } + TclDecrRefCount(eePtr->constants[0]); TclDecrRefCount(eePtr->constants[1]); if (eePtr->callbackPtr) { @@ -911,6 +967,339 @@ TclFinalizeExecution(void) } /* + * Auxiliary code to insure that GrowEvaluationStack always returns correctly + * aligned memory. + * + * WALLOCALIGN represents the alignment reqs in words, just as TCL_ALLOCALIGN + * represents the reqs in bytes. This assumes that TCL_ALLOCALIGN is a + * multiple of the wordsize 'sizeof(Tcl_Obj *)'. + */ + +#define WALLOCALIGN \ + (TCL_ALLOCALIGN/sizeof(Tcl_Obj *)) + +/* + * OFFSET computes how many words have to be skipped until the next aligned + * word. Note that we are only interested in the low order bits of ptr, so + * that any possible information loss in PTR2INT is of no consequence. + */ + +static inline int +OFFSET( + void *ptr) +{ + int mask = TCL_ALLOCALIGN-1; + int base = PTR2INT(ptr) & mask; + return (TCL_ALLOCALIGN - base)/sizeof(Tcl_Obj *); +} + +/* + * Given a marker, compute where the following aligned memory starts. + */ + +#define MEMSTART(markerPtr) \ + ((markerPtr) + OFFSET(markerPtr)) + +/* + *---------------------------------------------------------------------- + * + * GrowEvaluationStack -- + * + * This procedure grows a Tcl evaluation stack stored in an ExecEnv, + * copying over the words since the last mark if so requested. A mark is + * set at the beginning of the new area when no copying is requested. + * + * Results: + * Returns a pointer to the first usable word in the (possibly) grown + * stack. + * + * Side effects: + * The size of the evaluation stack may be grown, a marker is set + * + *---------------------------------------------------------------------- + */ + +static Tcl_Obj ** +GrowEvaluationStack( + ExecEnv *eePtr, /* Points to the ExecEnv with an evaluation + * stack to enlarge. */ + int growth, /* How much larger than the current used + * size. */ + int move) /* 1 if move words since last marker. */ +{ + ExecStack *esPtr = eePtr->execStackPtr, *oldPtr = NULL; + int newBytes, newElems, currElems; + int needed = growth - (esPtr->endPtr - esPtr->tosPtr); + Tcl_Obj **markerPtr = esPtr->markerPtr, **memStart; + int moveWords = 0; + + if (move) { + if (!markerPtr) { + Tcl_Panic("STACK: Reallocating with no previous alloc"); + } + if (needed <= 0) { + return MEMSTART(markerPtr); + } + } else { + Tcl_Obj **tmpMarkerPtr = esPtr->tosPtr + 1; + int offset = OFFSET(tmpMarkerPtr); + + if (needed + offset < 0) { + /* + * Put a marker pointing to the previous marker in this stack, and + * store it in esPtr as the current marker. Return a pointer to + * the start of aligned memory. + */ + + esPtr->markerPtr = tmpMarkerPtr; + memStart = tmpMarkerPtr + offset; + esPtr->tosPtr = memStart - 1; + *esPtr->markerPtr = (Tcl_Obj *) markerPtr; + return memStart; + } + } + + /* + * Reset move to hold the number of words to be moved to new stack (if + * any) and growth to hold the complete stack requirements: add one for + * the marker, (WALLOCALIGN-1) for the maximal possible offset. + */ + + if (move) { + moveWords = esPtr->tosPtr - MEMSTART(markerPtr) + 1; + } + needed = growth + moveWords + WALLOCALIGN; + + /* + * Check if there is enough room in the next stack (if there is one, it + * should be both empty and the last one!) + */ + + if (esPtr->nextPtr) { + oldPtr = esPtr; + esPtr = oldPtr->nextPtr; + currElems = esPtr->endPtr - &esPtr->stackWords[-1]; + if (esPtr->markerPtr || (esPtr->tosPtr != &esPtr->stackWords[-1])) { + Tcl_Panic("STACK: Stack after current is in use"); + } + if (esPtr->nextPtr) { + Tcl_Panic("STACK: Stack after current is not last"); + } + if (needed <= currElems) { + goto newStackReady; + } + DeleteExecStack(esPtr); + esPtr = oldPtr; + } else { + currElems = esPtr->endPtr - &esPtr->stackWords[-1]; + } + + /* + * We need to allocate a new stack! It needs to store 'growth' words, + * including the elements to be copied over and the new marker. + */ + + newElems = 2*currElems; + while (needed > newElems) { + newElems *= 2; + } + newBytes = sizeof(ExecStack) + (newElems-1) * sizeof(Tcl_Obj *); + + oldPtr = esPtr; + esPtr = ckalloc(newBytes); + + oldPtr->nextPtr = esPtr; + esPtr->prevPtr = oldPtr; + esPtr->nextPtr = NULL; + esPtr->endPtr = &esPtr->stackWords[newElems-1]; + + newStackReady: + eePtr->execStackPtr = esPtr; + + /* + * Store a NULL marker at the beginning of the stack, to indicate that + * this is the first marker in this stack and that rewinding to here + * should actually be a return to the previous stack. + */ + + esPtr->stackWords[0] = NULL; + esPtr->markerPtr = &esPtr->stackWords[0]; + memStart = MEMSTART(esPtr->markerPtr); + esPtr->tosPtr = memStart - 1; + + if (move) { + memcpy(memStart, MEMSTART(markerPtr), moveWords*sizeof(Tcl_Obj *)); + esPtr->tosPtr += moveWords; + oldPtr->markerPtr = (Tcl_Obj **) *markerPtr; + oldPtr->tosPtr = markerPtr-1; + } + + /* + * Free the old stack if it is now unused. + */ + + if (!oldPtr->markerPtr) { + DeleteExecStack(oldPtr); + } + + return memStart; +} + +/* + *-------------------------------------------------------------- + * + * TclStackAlloc, TclStackRealloc, TclStackFree -- + * + * Allocate memory from the execution stack; it has to be returned later + * with a call to TclStackFree. + * + * Results: + * A pointer to the first byte allocated, or panics if the allocation did + * not succeed. + * + * Side effects: + * The execution stack may be grown. + * + *-------------------------------------------------------------- + */ + +static Tcl_Obj ** +StackAllocWords( + Tcl_Interp *interp, + int numWords) +{ + /* + * Note that GrowEvaluationStack sets a marker in the stack. This marker + * is read when rewinding, e.g., by TclStackFree. + */ + + Interp *iPtr = (Interp *) interp; + ExecEnv *eePtr = iPtr->execEnvPtr; + Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 0); + + eePtr->execStackPtr->tosPtr += numWords; + return resPtr; +} + +static Tcl_Obj ** +StackReallocWords( + Tcl_Interp *interp, + int numWords) +{ + Interp *iPtr = (Interp *) interp; + ExecEnv *eePtr = iPtr->execEnvPtr; + Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 1); + + eePtr->execStackPtr->tosPtr += numWords; + return resPtr; +} + +void +TclStackFree( + Tcl_Interp *interp, + void *freePtr) +{ + Interp *iPtr = (Interp *) interp; + ExecEnv *eePtr; + ExecStack *esPtr; + Tcl_Obj **markerPtr, *marker; + + if (iPtr == NULL || iPtr->execEnvPtr == NULL) { + Tcl_Free((char *) freePtr); + return; + } + + /* + * Rewind the stack to the previous marker position. The current marker, + * as set in the last call to GrowEvaluationStack, contains a pointer to + * the previous marker. + */ + + eePtr = iPtr->execEnvPtr; + esPtr = eePtr->execStackPtr; + markerPtr = esPtr->markerPtr; + marker = *markerPtr; + + if ((freePtr != NULL) && (MEMSTART(markerPtr) != (Tcl_Obj **)freePtr)) { + Tcl_Panic("TclStackFree: incorrect freePtr (%p != %p). Call out of sequence?", + freePtr, MEMSTART(markerPtr)); + } + + esPtr->tosPtr = markerPtr - 1; + esPtr->markerPtr = (Tcl_Obj **) marker; + if (marker) { + return; + } + + /* + * Return to previous active stack. Note that repeated expansions or + * reallocs could have generated several unused intervening stacks: free + * them too. + */ + + while (esPtr->nextPtr) { + esPtr = esPtr->nextPtr; + } + esPtr->tosPtr = &esPtr->stackWords[-1]; + while (esPtr->prevPtr) { + ExecStack *tmpPtr = esPtr->prevPtr; + if (tmpPtr->tosPtr == &tmpPtr->stackWords[-1]) { + DeleteExecStack(tmpPtr); + } else { + break; + } + } + if (esPtr->prevPtr) { + eePtr->execStackPtr = esPtr->prevPtr; + } else { + eePtr->execStackPtr = esPtr; + } +} + +void * +TclStackAlloc( + Tcl_Interp *interp, + int numBytes) +{ + Interp *iPtr = (Interp *) interp; + int numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *); + + if (iPtr == NULL || iPtr->execEnvPtr == NULL) { + return (void *) Tcl_Alloc(numBytes); + } + + return (void *) StackAllocWords(interp, numWords); +} + +void * +TclStackRealloc( + Tcl_Interp *interp, + void *ptr, + int numBytes) +{ + Interp *iPtr = (Interp *) interp; + ExecEnv *eePtr; + ExecStack *esPtr; + Tcl_Obj **markerPtr; + int numWords; + + if (iPtr == NULL || iPtr->execEnvPtr == NULL) { + return (void *) Tcl_Realloc((char *) ptr, numBytes); + } + + eePtr = iPtr->execEnvPtr; + esPtr = eePtr->execStackPtr; + markerPtr = esPtr->markerPtr; + + if (MEMSTART(markerPtr) != (Tcl_Obj **)ptr) { + Tcl_Panic("TclStackRealloc: incorrect ptr. Call out of sequence?"); + } + + numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *); + return (void *) StackReallocWords(interp, numWords); +} + +/* *-------------------------------------------------------------- * * Tcl_ExprObj -- @@ -1308,7 +1697,7 @@ TclCompileObj( int redo = 0; if (invoker) { - CmdFrame *ctxPtr = ckalloc(sizeof(CmdFrame)); + CmdFrame *ctxPtr = TclStackAlloc(interp,sizeof(CmdFrame)); *ctxPtr = *invoker; if (invoker->type == TCL_LOCATION_BC) { @@ -1347,7 +1736,7 @@ TclCompileObj( && (ctxPtr->type == TCL_LOCATION_SOURCE)); } - ckfree(ctxPtr); + TclStackFree(interp, ctxPtr); } if (redo) { @@ -1532,15 +1921,10 @@ TclIncrObj( *---------------------------------------------------------------------- */ #define bcFramePtr (&TD->cmdFrame) -#define catchStack (TD->stack) -#define initTosPtr ((Tcl_Obj **) &TD->stack[codePtr->maxExceptDepth - 1]) - -#define capacity2size(cap) \ - (sizeof(TEBCdata) + sizeof(void *)*(cap + codePtr->maxExceptDepth - 1)) +#define initCatchTop ((ptrdiff_t *) (&TD->stack[-1])) +#define initTosPtr ((Tcl_Obj **) (initCatchTop+codePtr->maxExceptDepth)) +#define esPtr (iPtr->execEnvPtr->execStackPtr) -#define size2capacity(s) \ - (((s - sizeof(TEBCdata))/sizeof(void *)) - codePtr->maxExceptDepth + 1) - int TclNRExecuteByteCode( Tcl_Interp *interp, /* Token for command interpreter. */ @@ -1548,7 +1932,10 @@ TclNRExecuteByteCode( { Interp *iPtr = (Interp *) interp; TEBCdata *TD; - unsigned int size = capacity2size(codePtr->maxStackDepth); + int size = sizeof(TEBCdata) -1 + + + (codePtr->maxStackDepth + codePtr->maxExceptDepth) + *(sizeof(void *)); + int numWords = (size + sizeof(Tcl_Obj *) - 1)/sizeof(Tcl_Obj *); if (iPtr->execEnvPtr->rewind) { return TCL_ERROR; @@ -1568,19 +1955,12 @@ TclNRExecuteByteCode( * execution stack is large enough to execute this ByteCode. */ - TD = ckalloc(size); - size = TclAllocMaximize(TD); - if (size == UINT_MAX) { - TD->capacity = codePtr->maxStackDepth; - } else { - TD->capacity = size2capacity(size); - } - - TD->tosPtr = initTosPtr; + TD = (TEBCdata *) GrowEvaluationStack(iPtr->execEnvPtr, numWords, 0); + esPtr->tosPtr = initTosPtr; TD->codePtr = codePtr; TD->pc = codePtr->codeStart; - TD->catchDepth = -1; + TD->catchTop = initCatchTop; TD->cleanup = 0; TD->auxObjList = NULL; TD->checkInterp = 0; @@ -1668,11 +2048,11 @@ TEBCresume( TEBCdata *TD = data[0]; #define auxObjList (TD->auxObjList) -#define catchDepth (TD->catchDepth) +#define catchTop (TD->catchTop) #define codePtr (TD->codePtr) #define checkInterp (TD->checkInterp) /* Indicates when a check of interp readyness - * is necessary. Set by checkInterp = 1 */ + * is necessary. Set by CACHE_STACK_INFO() */ /* * Globals: variables that store state, must remain valid at all times. @@ -1733,7 +2113,7 @@ TEBCresume( codePtr->flags &= ~TCL_BYTECODE_RECOMPILE; } - checkInterp = 1; + CACHE_STACK_INFO(); if (result == TCL_OK) { #ifndef TCL_COMPILE_DEBUG if (*pc == INST_POP) { @@ -1873,28 +2253,29 @@ TEBCresume( */ if ((instructionCount++ & ASYNC_CHECK_COUNT_MASK) == 0) { + DECACHE_STACK_INFO(); if (TclAsyncReady(iPtr)) { result = Tcl_AsyncInvoke(interp, result); if (result == TCL_ERROR) { - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } } if (TclCanceled(iPtr)) { if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) { - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } } if (TclLimitReady(iPtr->limit)) { if (Tcl_LimitCheck(interp) == TCL_ERROR) { - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } } - checkInterp = 1; + CACHE_STACK_INFO(); } TCL_DTRACE_INST_NEXT(); @@ -2262,7 +2643,7 @@ TEBCresume( case INST_EXPAND_STKTOP: { int i; - unsigned int reqWords; + ptrdiff_t moved; /* * Make sure that the element at stackTop is a list; if not, just @@ -2276,6 +2657,7 @@ TEBCresume( Tcl_GetObjResult(interp)); goto gotError; } + (void) POP_OBJECT(); /* * Make sure there is enough room in the stack to expand this list @@ -2284,30 +2666,24 @@ TEBCresume( * stack depth, as seen by the compiler. */ - reqWords = - /* how many were needed originally */ - codePtr->maxStackDepth - /* plus how many we already consumed in previous expansions */ - + (CURR_DEPTH - TclGetInt4AtPtr(pc+1)) - /* plus how many are needed for this expansion */ - + objc - 1; + length = objc + (codePtr->maxStackDepth - TclGetInt4AtPtr(pc+1)); + DECACHE_STACK_INFO(); + moved = GrowEvaluationStack(iPtr->execEnvPtr, length, 1) + - (Tcl_Obj **) TD; + if (moved) { + /* + * Change the global data to point to the new stack: move the + * TEBCdataPtr TD, recompute the position of every other + * stack-allocated parameter, update the stack pointers. + */ - (void) POP_OBJECT(); - if (reqWords > TD->capacity) { - ptrdiff_t depth; - unsigned int size = capacity2size(reqWords); - - depth = tosPtr - initTosPtr; - TD = ckrealloc(TD, size); - size = TclAllocMaximize(TD); - if (size == UINT_MAX) { - TD->capacity = reqWords; - } else { - TD->capacity = size2capacity(size); - } - tosPtr = initTosPtr + depth; + esPtr = iPtr->execEnvPtr->execStackPtr; + TD = (TEBCdata *) (((Tcl_Obj **)TD) + moved); + + catchTop += moved; + tosPtr += moved; } - + /* * Expand the list at stacktop onto the stack; free the list. Knowing * that it has a freeIntRepProc we use Tcl_DecrRefCount(). @@ -2326,8 +2702,9 @@ TEBCresume( bcFramePtr->data.tebc.pc = (char *) pc; iPtr->cmdFramePtr = bcFramePtr; + DECACHE_STACK_INFO(); newCodePtr = CompileExprObj(interp, OBJ_AT_TOS); - checkInterp = 1; + CACHE_STACK_INFO(); cleanup = 1; pc++; TEBC_YIELD(); @@ -2413,6 +2790,8 @@ TEBCresume( codePtr, bcFramePtr, pc - codePtr->codeStart); } + DECACHE_STACK_INFO(); + pc += pcAdjustment; TEBC_YIELD(); return TclNREvalObjv(interp, objc, objv, @@ -2637,9 +3016,10 @@ TEBCresume( * TclPtrGetVar to process fully. */ + DECACHE_STACK_INFO(); objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); if (!objResultPtr) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); goto gotError; @@ -2883,9 +3263,10 @@ TEBCresume( part1Ptr = part2Ptr = NULL; doCallPtrSetVar: + DECACHE_STACK_INFO(); objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, valuePtr, storeFlags, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); if (!objResultPtr) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); goto gotError; @@ -3146,9 +3527,10 @@ TEBCresume( } Tcl_DecrRefCount(incrPtr); } else { + DECACHE_STACK_INFO(); objResultPtr = TclPtrIncrObjVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, incrPtr, TCL_LEAVE_ERR_MSG, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); Tcl_DecrRefCount(incrPtr); if (objResultPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", @@ -3180,9 +3562,10 @@ TEBCresume( } TRACE(("%u => ", opnd)); if (ReadTraced(varPtr)) { + DECACHE_STACK_INFO(); TclObjCallVarTraces(iPtr, NULL, varPtr, NULL, NULL, TCL_TRACE_READS, 0, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); if (TclIsVarUndefined(varPtr)) { TclCleanupVar(varPtr, NULL); varPtr = NULL; @@ -3215,9 +3598,10 @@ TEBCresume( 0, 1, arrayPtr, opnd); if (varPtr) { if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) { + DECACHE_STACK_INFO(); TclObjCallVarTraces(iPtr, arrayPtr, varPtr, NULL, part2Ptr, TCL_TRACE_READS, 0, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); } if (TclIsVarUndefined(varPtr)) { TclCleanupVar(varPtr, arrayPtr); @@ -3247,9 +3631,10 @@ TEBCresume( /*createPart1*/0, /*createPart2*/1, &arrayPtr); if (varPtr) { if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) { + DECACHE_STACK_INFO(); TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr,part2Ptr, TCL_TRACE_READS, 0, -1); - checkInterp = 1; + CACHE_STACK_INFO(); } if (TclIsVarUndefined(varPtr)) { TclCleanupVar(varPtr, arrayPtr); @@ -3293,11 +3678,12 @@ TEBCresume( } slowUnsetScalar: + DECACHE_STACK_INFO(); if (TclPtrUnsetVar(interp, varPtr, NULL, NULL, NULL, flags, opnd) != TCL_OK && flags) { goto errorInUnset; } - checkInterp = 1; + CACHE_STACK_INFO(); NEXT_INST_F(6, 0, 0); case INST_UNSET_ARRAY: @@ -3334,6 +3720,7 @@ TEBCresume( } } slowUnsetArray: + DECACHE_STACK_INFO(); varPtr = TclLookupArrayElement(interp, NULL, part2Ptr, flags, "unset", 0, 0, arrayPtr, opnd); if (!varPtr) { @@ -3344,7 +3731,7 @@ TEBCresume( flags, opnd) != TCL_OK && (flags & TCL_LEAVE_ERR_MSG)) { goto errorInUnset; } - checkInterp = 1; + CACHE_STACK_INFO(); NEXT_INST_F(6, 1, 0); case INST_UNSET_ARRAY_STK: @@ -3364,15 +3751,16 @@ TEBCresume( TRACE(("%s \"%.30s\"\n", (flags?"normal":"noerr"), O2S(part1Ptr))); doUnsetStk: + DECACHE_STACK_INFO(); if (TclObjUnsetVar2(interp, part1Ptr, part2Ptr, flags) != TCL_OK && (flags & TCL_LEAVE_ERR_MSG)) { goto errorInUnset; } - checkInterp = 1; + CACHE_STACK_INFO(); NEXT_INST_V(2, cleanup, 0); errorInUnset: - checkInterp = 1; + CACHE_STACK_INFO(); TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); goto gotError; @@ -3393,8 +3781,9 @@ TEBCresume( } varPtr->value.objPtr = NULL; } else { + DECACHE_STACK_INFO(); TclPtrUnsetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); } NEXT_INST_F(5, 0, 0); } @@ -3635,16 +4024,18 @@ TEBCresume( if (TclGetBooleanFromObj(NULL, valuePtr, &i1) != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } if (TclGetBooleanFromObj(NULL, value2Ptr, &i2) != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(value2Ptr), (value2Ptr->typePtr? value2Ptr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } @@ -4421,8 +4812,9 @@ TEBCresume( TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr), O2S(value2Ptr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } @@ -4431,8 +4823,9 @@ TEBCresume( TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr), O2S(value2Ptr), (value2Ptr->typePtr? value2Ptr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } @@ -4490,10 +4883,11 @@ TEBCresume( Tcl_SetResult(interp, "negative shift argument", TCL_STATIC); #if 0 + DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", "domain error: argument not in valid range", NULL); - checkInterp = 1; + CACHE_STACK_INFO(); #endif goto gotError; } else if (l1 == 0) { @@ -4537,10 +4931,11 @@ TEBCresume( Tcl_SetResult(interp, "negative shift argument", TCL_STATIC); #if 0 + DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", "domain error: argument not in valid range", NULL); - checkInterp = 1; + CACHE_STACK_INFO(); #endif goto gotError; } else if (l1 == 0) { @@ -4560,9 +4955,10 @@ TEBCresume( "integer value too large to represent", TCL_STATIC); #if 0 + DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", "integer value too large to represent", NULL); - checkInterp = 1; + CACHE_STACK_INFO(); #endif goto gotError; } else { @@ -4645,8 +5041,9 @@ TEBCresume( TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(value2Ptr), O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name: "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } @@ -4665,8 +5062,9 @@ TEBCresume( TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(value2Ptr), O2S(valuePtr), (value2Ptr->typePtr? value2Ptr->typePtr->name: "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, value2Ptr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } @@ -4813,8 +5211,9 @@ TEBCresume( if (TclGetBooleanFromObj(NULL, valuePtr, &b) != TCL_OK) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n", O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } /* TODO: Consider peephole opt. */ @@ -4832,8 +5231,9 @@ TEBCresume( TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } if (type1 == TCL_NUMBER_LONG) { @@ -4858,8 +5258,9 @@ TEBCresume( || IsErroringNaNType(type1)) { TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name : "null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } switch (type1) { @@ -4903,8 +5304,9 @@ TEBCresume( TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name:"null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } @@ -4920,8 +5322,9 @@ TEBCresume( TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr), (valuePtr->typePtr? valuePtr->typePtr->name:"null"))); + DECACHE_STACK_INFO(); IllegalExprOperandType(interp, pc, valuePtr); - checkInterp = 1; + CACHE_STACK_INFO(); } else { /* * Numeric conversion of NaN -> error. @@ -4929,8 +5332,9 @@ TEBCresume( TRACE(("\"%.20s\" => IEEE FLOATING PT ERROR\n", O2S(objResultPtr))); + DECACHE_STACK_INFO(); TclExprFloatError(interp, *((const double *) ptr1)); - checkInterp = 1; + CACHE_STACK_INFO(); } goto gotError; } @@ -4975,8 +5379,9 @@ TEBCresume( case INST_BREAK: /* + DECACHE_STACK_INFO(); Tcl_ResetResult(interp); - checkInterp = 1; + CACHE_STACK_INFO(); */ result = TCL_BREAK; cleanup = 0; @@ -4984,8 +5389,9 @@ TEBCresume( case INST_CONTINUE: /* + DECACHE_STACK_INFO(); Tcl_ResetResult(interp); - checkInterp = 1; + CACHE_STACK_INFO(); */ result = TCL_CONTINUE; cleanup = 0; @@ -5118,16 +5524,17 @@ TEBCresume( Tcl_IncrRefCount(valuePtr); } } else { + DECACHE_STACK_INFO(); if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL, valuePtr, TCL_LEAVE_ERR_MSG, varIndex)==NULL){ - checkInterp = 1; + CACHE_STACK_INFO(); TRACE_WITH_OBJ(( "%u => ERROR init. index temp %d: ", opnd,varIndex), Tcl_GetObjResult(interp)); TclDecrRefCount(listPtr); goto gotError; } - checkInterp = 1; + CACHE_STACK_INFO(); } valIndex++; } @@ -5159,18 +5566,19 @@ TEBCresume( * stack. */ - catchStack[++catchDepth] = INT2PTR(CURR_DEPTH); - TRACE(("%u => catchDepth=%d, stackTop=%d\n", - TclGetUInt4AtPtr(pc+1), (int) (catchDepth), + *(++catchTop) = CURR_DEPTH; + TRACE(("%u => catchTop=%d, stackTop=%d\n", + TclGetUInt4AtPtr(pc+1), (int) (catchTop - initCatchTop - 1), (int) CURR_DEPTH)); NEXT_INST_F(5, 0, 0); case INST_END_CATCH: - catchDepth--; + catchTop--; + DECACHE_STACK_INFO(); Tcl_ResetResult(interp); - checkInterp = 1; + CACHE_STACK_INFO(); result = TCL_OK; - TRACE(("=> catchDepth=%d\n", (int) (catchDepth))); + TRACE(("=> catchTop=%d\n", (int) (catchTop - initCatchTop - 1))); NEXT_INST_F(1, 0, 0); case INST_PUSH_RESULT: @@ -5192,8 +5600,9 @@ TEBCresume( NEXT_INST_F(1, 0, 1); case INST_PUSH_RETURN_OPTIONS: + DECACHE_STACK_INFO(); objResultPtr = Tcl_GetReturnOptions(interp, result); - checkInterp = 1; + CACHE_STACK_INFO(); TRACE_WITH_OBJ(("=> "), objResultPtr); NEXT_INST_F(1, 0, 1); @@ -5245,12 +5654,13 @@ TEBCresume( TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_V(5, opnd+1, 1); } + DECACHE_STACK_INFO(); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "key \"", TclGetString(OBJ_AT_TOS), "\" not known in dictionary", NULL); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT", TclGetString(OBJ_AT_TOS), NULL); - checkInterp = 1; + CACHE_STACK_INFO(); TRACE_WITH_OBJ(("%u => ERROR ", opnd), Tcl_GetObjResult(interp)); } else { TRACE_WITH_OBJ(( @@ -5273,8 +5683,9 @@ TEBCresume( if (TclIsVarDirectReadable(varPtr)) { dictPtr = varPtr->value.objPtr; } else { + DECACHE_STACK_INFO(); dictPtr = TclPtrGetVar(interp, varPtr, NULL,NULL,NULL, 0, opnd2); - checkInterp = 1; + CACHE_STACK_INFO(); } if (dictPtr == NULL) { TclNewObj(dictPtr); @@ -5346,9 +5757,10 @@ TEBCresume( objResultPtr = dictPtr; } else { Tcl_IncrRefCount(dictPtr); + DECACHE_STACK_INFO(); objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL, dictPtr, TCL_LEAVE_ERR_MSG, opnd2); - checkInterp = 1; + CACHE_STACK_INFO(); TclDecrRefCount(dictPtr); if (objResultPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", @@ -5375,8 +5787,9 @@ TEBCresume( if (TclIsVarDirectReadable(varPtr)) { dictPtr = varPtr->value.objPtr; } else { + DECACHE_STACK_INFO(); dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); } if (dictPtr == NULL) { TclNewObj(dictPtr); @@ -5480,9 +5893,10 @@ TEBCresume( objResultPtr = dictPtr; } else { Tcl_IncrRefCount(dictPtr); + DECACHE_STACK_INFO(); objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL, dictPtr, TCL_LEAVE_ERR_MSG, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); TclDecrRefCount(dictPtr); if (objResultPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", @@ -5584,9 +5998,10 @@ TEBCresume( if (TclIsVarDirectReadable(varPtr)) { dictPtr = varPtr->value.objPtr; } else { + DECACHE_STACK_INFO(); dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, TCL_LEAVE_ERR_MSG, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); if (dictPtr == NULL) { goto gotError; } @@ -5607,6 +6022,7 @@ TEBCresume( while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } + DECACHE_STACK_INFO(); if (valuePtr == NULL) { TclObjUnsetVar2(interp, localName(iPtr->varFramePtr, duiPtr->varIndices[i]), @@ -5614,10 +6030,10 @@ TEBCresume( } else if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL, valuePtr, TCL_LEAVE_ERR_MSG, duiPtr->varIndices[i]) == NULL) { - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; } - checkInterp = 1; + CACHE_STACK_INFO(); } NEXT_INST_F(9, 0, 0); @@ -5633,8 +6049,9 @@ TEBCresume( if (TclIsVarDirectReadable(varPtr)) { dictPtr = varPtr->value.objPtr; } else { + DECACHE_STACK_INFO(); dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); } if (dictPtr == NULL) { NEXT_INST_F(9, 1, 0); @@ -5660,9 +6077,10 @@ TEBCresume( if (TclIsVarDirectReadable(var2Ptr)) { valuePtr = var2Ptr->value.objPtr; } else { + DECACHE_STACK_INFO(); valuePtr = TclPtrGetVar(interp, var2Ptr, NULL, NULL, NULL, 0, duiPtr->varIndices[i]); - checkInterp = 1; + CACHE_STACK_INFO(); } if (valuePtr == NULL) { Tcl_DictObjRemove(interp, dictPtr, keyPtrPtr[i]); @@ -5678,9 +6096,10 @@ TEBCresume( TclDecrRefCount(varPtr->value.objPtr); varPtr->value.objPtr = dictPtr; } else { + DECACHE_STACK_INFO(); objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL, dictPtr, TCL_LEAVE_ERR_MSG, opnd); - checkInterp = 1; + CACHE_STACK_INFO(); if (objResultPtr == NULL) { if (allocdict) { TclDecrRefCount(dictPtr); @@ -5796,9 +6215,10 @@ TEBCresume( */ divideByZero: + DECACHE_STACK_INFO(); Tcl_SetResult(interp, "divide by zero", TCL_STATIC); Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", NULL); - checkInterp = 1; + CACHE_STACK_INFO(); goto gotError; /* @@ -5807,11 +6227,12 @@ TEBCresume( */ exponOfZero: + DECACHE_STACK_INFO(); Tcl_SetResult(interp, "exponentiation of zero by negative power", TCL_STATIC); Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", "exponentiation of zero by negative power", NULL); - checkInterp = 1; + CACHE_STACK_INFO(); /* * Almost all error paths feed through here rather than assigning to @@ -5837,8 +6258,9 @@ TEBCresume( const unsigned char *pcBeg; bytes = GetSrcInfoForPc(pc, codePtr, &length, &pcBeg); + DECACHE_STACK_INFO(); TclLogCommandInfo(interp, codePtr->source, bytes, bytes ? length : 0, pcBeg, tosPtr); - checkInterp = 1; + CACHE_STACK_INFO(); } iPtr->flags &= ~ERR_ALREADY_LOGGED; @@ -5848,8 +6270,8 @@ TEBCresume( */ while (auxObjList) { - if ((catchDepth >=0) && (PTR2INT(catchStack[catchDepth]) > - PTR2INT(auxObjList->internalRep.twoPtrValue.ptr1))) { + if ((catchTop != initCatchTop) && (*catchTop > + (ptrdiff_t) auxObjList->internalRep.twoPtrValue.ptr1)) { break; } POP_TAUX_OBJ(); @@ -5889,7 +6311,7 @@ TEBCresume( #endif goto abnormalReturn; } - if (catchDepth == -1) { + if (catchTop == initCatchTop) { #ifdef TCL_COMPILE_DEBUG if (traceInstructions) { fprintf(stdout, " ... no enclosing catch, returning %s\n", @@ -5924,16 +6346,16 @@ TEBCresume( */ processCatch: - while (CURR_DEPTH > PTR2INT(catchStack[catchDepth])) { + while (CURR_DEPTH > *catchTop) { valuePtr = POP_OBJECT(); TclDecrRefCount(valuePtr); } #ifdef TCL_COMPILE_DEBUG if (traceInstructions) { - fprintf(stdout, " ... found catch at %d, catchDepth=%d, " + fprintf(stdout, " ... found catch at %d, catchTop=%d, " "unwound to %ld, new pc %u\n", - rangePtr->codeOffset, (int) catchDepth, - PTR2INT(catchStack[catchDepth]), (unsigned) rangePtr->catchOffset); + rangePtr->codeOffset, (int) (catchTop - initCatchTop - 1), + (long) *catchTop, (unsigned) rangePtr->catchOffset); } #endif pc = (codePtr->codeStart + rangePtr->catchOffset); @@ -5982,7 +6404,7 @@ TEBCresume( if (--codePtr->refCount <= 0) { TclCleanupByteCode(codePtr); } - ckfree(TD); /* free my stack */ + TclStackFree(interp, TD); /* free my stack */ return result; } @@ -5990,9 +6412,10 @@ TEBCresume( #undef codePtr #undef iPtr #undef bcFramePtr +#undef initCatchTop #undef initTosPtr #undef auxObjList -#undef catchDepth +#undef catchTop #undef TCONST /* |