diff options
Diffstat (limited to 'generic/tclExecute.c')
-rw-r--r-- | generic/tclExecute.c | 294 |
1 files changed, 50 insertions, 244 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 029f402..32cbf6a 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -173,13 +173,13 @@ static BuiltinFunc const tclBuiltinFuncTable[] = { typedef struct TEBCdata { ByteCode *codePtr; /* Constant until the BC returns */ + Tcl_Obj *srcPtr; /* -----------------------------------------*/ const unsigned char *pc; /* These fields are used on return TO this */ 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; void *stack[1]; /* Start of the actual combined catch and obj * stacks; the struct will be expanded as * necessary */ @@ -797,6 +797,35 @@ ReleaseDictIterator( objPtr->typePtr = NULL; } +static void UpdateStringOfBcSource(Tcl_Obj *objPtr); + +static const Tcl_ObjType bcSourceType = { + "bcSource", /* name */ + NULL, /* freeIntRepProc */ + NULL, /* dupIntRepProc */ + UpdateStringOfBcSource, /* updateStringProc */ + NULL /* setFromAnyProc */ +}; + +static void +UpdateStringOfBcSource( + Tcl_Obj *objPtr) +{ + int len; + const char *bytes; + unsigned char *pc = objPtr->internalRep.twoPtrValue.ptr1; + ByteCode *codePtr = objPtr->internalRep.twoPtrValue.ptr2; + + bytes = GetSrcInfoForPc(pc, codePtr, &len, NULL); + objPtr->bytes = (char *) ckalloc((unsigned) len + 1); + memcpy(objPtr->bytes, bytes, len); + objPtr->bytes[len] = '\0'; + objPtr->length = len; +} + + + + /* *---------------------------------------------------------------------- * @@ -1504,14 +1533,10 @@ CompileExprObj( } } if (objPtr->typePtr != &exprCodeType) { - /* - * TIP #280: No invoker (yet) - Expression compilation. - */ - int length; const char *string = TclGetStringFromObj(objPtr, &length); - TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0); + TclInitCompileEnv(interp, &compEnv, string, length); TclCompileExpr(interp, string, length, &compEnv, 0); /* @@ -1634,9 +1659,7 @@ FreeExprCodeInternalRep( ByteCode * TclCompileObj( Tcl_Interp *interp, - Tcl_Obj *objPtr, - const CmdFrame *invoker, - int word) + Tcl_Obj *objPtr) { register Interp *iPtr = (Interp *) interp; register ByteCode *codePtr; /* Tcl Internal type of bytecode. */ @@ -1691,109 +1714,13 @@ TclCompileObj( goto recompileObj; } - /* - * #280. - * Literal sharing fix. This part of the fix is not required by 8.4 - * nor 8.5, because they eval-direct any literals, so just saving the - * argument locations per command in bytecode is enough, embedded - * 'eval' commands, etc. get the correct information. - * - * But in 8.6 all the embedded script are compiled, and the resulting - * bytecode stored in the literal. Now the shared literal has bytecode - * with location data for _one_ particular location this literal is - * found at. If we get executed from a different location the bytecode - * has to be recompiled to get the correct locations. Not doing this - * will execute the saved bytecode with data for a different location, - * causing 'info frame' to point to the wrong place in the sources. - * - * Future optimizations ... - * (1) Save the location data (ExtCmdLoc) keyed by start line. In that - * case we recompile once per location of the literal, but not - * continously, because the moment we have all locations we do not - * need to recompile any longer. - * - * (2) Alternative: Do not recompile, tell the execution engine the - * offset between saved starting line and actual one. Then modify - * the users to adjust the locations they have by this offset. - * - * (3) Alternative 2: Do not fully recompile, adjust just the location - * information. - */ - - if (invoker == NULL) { - return codePtr; - } else { - Tcl_HashEntry *hePtr = - Tcl_FindHashEntry(iPtr->lineBCPtr, codePtr); - ExtCmdLoc *eclPtr; - CmdFrame *ctxCopyPtr; - int redo; - - if (!hePtr) { - return codePtr; - } - - eclPtr = Tcl_GetHashValue(hePtr); - redo = 0; - ctxCopyPtr = TclStackAlloc(interp, sizeof(CmdFrame)); - *ctxCopyPtr = *invoker; - - if (invoker->type == TCL_LOCATION_BC) { - /* - * Note: Type BC => ctx.data.eval.path is not used. - * ctx.data.tebc.codePtr used instead - */ - - TclGetSrcInfoForPc(ctxCopyPtr); - if (ctxCopyPtr->type == TCL_LOCATION_SOURCE) { - /* - * The reference made by 'TclGetSrcInfoForPc' is dead. - */ - - Tcl_DecrRefCount(ctxCopyPtr->data.eval.path); - ctxCopyPtr->data.eval.path = NULL; - } - } - - if (word < ctxCopyPtr->nline) { - /* - * Note: We do not care if the line[word] is -1. This is a - * difference and requires a recompile (location changed from - * absolute to relative, literal is used fixed and through - * variable) - * - * Example: - * test info-32.0 using literal of info-24.8 - * (dict with ... vs set body ...). - */ - - redo = ((eclPtr->type == TCL_LOCATION_SOURCE) - && (eclPtr->start != ctxCopyPtr->line[word])) - || ((eclPtr->type == TCL_LOCATION_BC) - && (ctxCopyPtr->type == TCL_LOCATION_SOURCE)); - } - - TclStackFree(interp, ctxCopyPtr); - if (!redo) { - return codePtr; - } - } + return codePtr; } 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. - */ - - iPtr->invokeCmdFramePtr = invoker; - iPtr->invokeWord = word; TclSetByteCodeFromAny(interp, objPtr, NULL, NULL); - iPtr->invokeCmdFramePtr = NULL; codePtr = objPtr->internalRep.twoPtrValue.ptr1; if (iPtr->varFramePtr->localCachePtr) { codePtr->localCachePtr = iPtr->varFramePtr->localCachePtr; @@ -1946,7 +1873,6 @@ TclIncrObj( * *---------------------------------------------------------------------- */ -#define bcFramePtr (&TD->cmdFrame) #define initCatchTop ((ptrdiff_t *) (&TD->stack[-1])) #define initTosPtr ((Tcl_Obj **) (initCatchTop+codePtr->maxExceptDepth)) #define esPtr (iPtr->execEnvPtr->execStackPtr) @@ -1973,7 +1899,7 @@ TclNRExecuteByteCode( * Reserve the stack, setup the TEBCdataPtr (TD) and CallFrame * * The execution uses a unified stack: first a TEBCdata, immediately - * above it a CmdFrame, then the catch stack, then the execution stack. + * above it the catch stack, then the execution stack. * * Make sure the catch stack is large enough to hold the maximum number of * catch commands that could ever be executing at the same time (this will @@ -1985,31 +1911,16 @@ TclNRExecuteByteCode( esPtr->tosPtr = initTosPtr; TD->codePtr = codePtr; + TD->srcPtr = Tcl_NewObj(); + TD->srcPtr->typePtr = &bcSourceType; + TclInvalidateStringRep(TD->srcPtr); + TD->pc = codePtr->codeStart; TD->catchTop = initCatchTop; TD->cleanup = 0; TD->auxObjList = NULL; TD->checkInterp = 0; - /* - * TIP #280: Initialize the frame. Do not push it yet: it will be pushed - * every time that we call out from this TD, popped when we return to it. - */ - - bcFramePtr->type = ((codePtr->flags & TCL_BYTECODE_PRECOMPILED) - ? TCL_LOCATION_PREBC : TCL_LOCATION_BC); - bcFramePtr->level = (iPtr->cmdFramePtr ? iPtr->cmdFramePtr->level+1 : 1); - bcFramePtr->numLevels = iPtr->numLevels; - bcFramePtr->framePtr = iPtr->framePtr; - bcFramePtr->nextPtr = iPtr->cmdFramePtr; - bcFramePtr->nline = 0; - bcFramePtr->line = NULL; - bcFramePtr->litarg = NULL; - bcFramePtr->data.tebc.codePtr = codePtr; - bcFramePtr->data.tebc.pc = NULL; - bcFramePtr->cmd.str.cmd = NULL; - bcFramePtr->cmd.str.len = 0; - #ifdef TCL_COMPILE_STATS iPtr->stats.numExecutions++; #endif @@ -2075,6 +1986,7 @@ TEBCresume( #define auxObjList (TD->auxObjList) #define catchTop (TD->catchTop) #define codePtr (TD->codePtr) +#define srcPtr (TD->srcPtr) #define checkInterp (TD->checkInterp) /* Indicates when a check of interp readyness is * necessary. Set by CACHE_STACK_INFO() */ @@ -2115,7 +2027,6 @@ TEBCresume( int starting = 1; traceInstructions = (tclTraceExec == 3); #endif - TEBC_DATA_DIG(); #ifdef TCL_COMPILE_DEBUG @@ -2130,11 +2041,6 @@ TEBCresume( if (iPtr->execEnvPtr->rewind) { result = TCL_ERROR; } - NRE_ASSERT(iPtr->cmdFramePtr == bcFramePtr); - iPtr->cmdFramePtr = bcFramePtr->nextPtr; - if (iPtr->flags & INTERP_DEBUG_FRAME) { - TclArgumentBCRelease((Tcl_Interp *) iPtr, bcFramePtr); - } if (codePtr->flags & TCL_BYTECODE_RECOMPILE) { iPtr->flags |= ERR_ALREADY_LOGGED; codePtr->flags &= ~TCL_BYTECODE_RECOMPILE; @@ -2392,6 +2298,7 @@ TEBCresume( NULL); goto gotError; } + NRE_ASSERT(!COR_IS_SUSPENDED(corPtr)); #ifdef TCL_COMPILE_DEBUG TRACE_WITH_OBJ(("yield, result="), iPtr->objResultPtr); @@ -2399,17 +2306,6 @@ TEBCresume( fprintf(stdout, "\n"); } #endif - /* TIP #280: Record the last piece of info needed by - * 'TclGetSrcInfoForPc', and push the frame. - */ - - bcFramePtr->data.tebc.pc = (char *) pc; - iPtr->cmdFramePtr = bcFramePtr; - - if (iPtr->flags & INTERP_DEBUG_FRAME) { - TclArgumentBCEnter((Tcl_Interp *) iPtr, objv, objc, - codePtr, bcFramePtr, pc - codePtr->codeStart); - } pc++; cleanup = 1; @@ -2757,8 +2653,6 @@ TEBCresume( case INST_EXPR_STK: { ByteCode *newCodePtr; - bcFramePtr->data.tebc.pc = (char *) pc; - iPtr->cmdFramePtr = bcFramePtr; DECACHE_STACK_INFO(); newCodePtr = CompileExprObj(interp, OBJ_AT_TOS); CACHE_STACK_INFO(); @@ -2774,13 +2668,10 @@ TEBCresume( instEvalStk: case INST_EVAL_STK: - bcFramePtr->data.tebc.pc = (char *) pc; - iPtr->cmdFramePtr = bcFramePtr; - cleanup = 1; pc += 1; TEBC_YIELD(); - return TclNREvalObjEx(interp, OBJ_AT_TOS, 0, NULL, 0); + return TclNREvalObjEx(interp, OBJ_AT_TOS, 0); case INST_INVOKE_EXPANDED: CLANG_ASSERT(auxObjList); @@ -2833,21 +2724,14 @@ TEBCresume( /* * Finally, let TclEvalObjv handle the command. - * - * TIP #280: Record the last piece of info needed by - * 'TclGetSrcInfoForPc', and push the frame. */ - bcFramePtr->data.tebc.pc = (char *) pc; - iPtr->cmdFramePtr = bcFramePtr; - - if (iPtr->flags & INTERP_DEBUG_FRAME) { - TclArgumentBCEnter((Tcl_Interp *) iPtr, objv, objc, - codePtr, bcFramePtr, pc - codePtr->codeStart); + if (!(codePtr->flags & TCL_BYTECODE_PRECOMPILED)) { + srcPtr->internalRep.twoPtrValue.ptr1 = (unsigned char *) pc; + srcPtr->internalRep.twoPtrValue.ptr2 = codePtr; + iPtr->cmdSourcePtr = srcPtr; } - DECACHE_STACK_INFO(); - pc += pcAdjustment; TEBC_YIELD(); return TclNREvalObjv(interp, objc, objv, @@ -2985,12 +2869,6 @@ TEBCresume( } objPtr = copyPtr; } - bcFramePtr->data.tebc.pc = (char *) pc; - iPtr->cmdFramePtr = bcFramePtr; - if (iPtr->flags & INTERP_DEBUG_FRAME) { - TclArgumentBCEnter((Tcl_Interp *) iPtr, objv, objc, - codePtr, bcFramePtr, pc - codePtr->codeStart); - } iPtr->ensembleRewrite.sourceObjs = objv; iPtr->ensembleRewrite.numRemovedObjs = opnd; iPtr->ensembleRewrite.numInsertedObjs = 1; @@ -3000,7 +2878,7 @@ TEBCresume( TclNRAddCallback(interp, TclClearRootEnsemble, NULL,NULL,NULL,NULL); TclSkipTailcall(interp); - return TclNREvalObjEx(interp, objPtr, TCL_EVAL_INVOKE, NULL, INT_MIN); + return TclNREvalObjEx(interp, objPtr, TCL_EVAL_INVOKE); /* * ----------------------------------------------------------------- @@ -6902,8 +6780,8 @@ TEBCresume( bytes = GetSrcInfoForPc(pc, codePtr, &length, &pcBeg); DECACHE_STACK_INFO(); - TclLogCommandInfo(interp, codePtr->source, bytes, - bytes ? length : 0, pcBeg, tosPtr); + Tcl_LogCommandInfo(interp, codePtr->source, bytes, + bytes ? length : 0); CACHE_STACK_INFO(); } iPtr->flags &= ~ERR_ALREADY_LOGGED; @@ -7042,10 +6920,9 @@ TEBCresume( (unsigned) CURR_DEPTH, (unsigned) 0); Tcl_Panic("TclNRExecuteByteCode execution failure: end stack top < start stack top"); } - CLANG_ASSERT(bcFramePtr); } - iPtr->cmdFramePtr = bcFramePtr->nextPtr; + TclDecrRefCount(srcPtr); if (--codePtr->refCount <= 0) { TclCleanupByteCode(codePtr); } @@ -7091,9 +6968,8 @@ TEBCresume( } #undef codePtr +#undef srcPtr #undef iPtr -#undef bcFramePtr -#undef initCatchTop #undef initTosPtr #undef auxObjList #undef catchTop @@ -8680,76 +8556,6 @@ IllegalExprOperandType( *---------------------------------------------------------------------- */ -const char * -TclGetSrcInfoForCmd( - Interp *iPtr, - int *lenPtr) -{ - CmdFrame *cfPtr = iPtr->cmdFramePtr; - ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr; - - return GetSrcInfoForPc((unsigned char *) cfPtr->data.tebc.pc, - codePtr, lenPtr, NULL); -} - -void -TclGetSrcInfoForPc( - CmdFrame *cfPtr) -{ - ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr; - - if (cfPtr->cmd.str.cmd == NULL) { - cfPtr->cmd.str.cmd = GetSrcInfoForPc( - (unsigned char *) cfPtr->data.tebc.pc, codePtr, - &cfPtr->cmd.str.len, NULL); - } - - if (cfPtr->cmd.str.cmd != NULL) { - /* - * We now have the command. We can get the srcOffset back and from - * there find the list of word locations for this command. - */ - - ExtCmdLoc *eclPtr; - ECL *locPtr = NULL; - int srcOffset, i; - Interp *iPtr = (Interp *) *codePtr->interpHandle; - Tcl_HashEntry *hePtr = - Tcl_FindHashEntry(iPtr->lineBCPtr, codePtr); - - if (!hePtr) { - return; - } - - srcOffset = cfPtr->cmd.str.cmd - codePtr->source; - eclPtr = Tcl_GetHashValue(hePtr); - - for (i=0; i < eclPtr->nuloc; i++) { - if (eclPtr->loc[i].srcOffset == srcOffset) { - locPtr = eclPtr->loc+i; - break; - } - } - if (locPtr == NULL) { - Tcl_Panic("LocSearch failure"); - } - - cfPtr->line = locPtr->line; - cfPtr->nline = locPtr->nline; - cfPtr->type = eclPtr->type; - - if (eclPtr->type == TCL_LOCATION_SOURCE) { - cfPtr->data.eval.path = eclPtr->path; - Tcl_IncrRefCount(cfPtr->data.eval.path); - } - - /* - * Do not set cfPtr->data.eval.path NULL for non-SOURCE. Needed for - * cfPtr->data.tebc.codePtr. - */ - } -} - static const char * GetSrcInfoForPc( const unsigned char *pc, /* The program counter value for which to |