summaryrefslogtreecommitdiffstats
path: root/generic/tclExecute.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2007-09-04 17:43:42 (GMT)
committerdgp <dgp@users.sourceforge.net>2007-09-04 17:43:42 (GMT)
commit6071dd54232192dfc2f58917e4e64fd8d3940368 (patch)
tree6bd7a89eb2e5d78bce73e0e1b76b8e8683e5a5b3 /generic/tclExecute.c
parente0cfac8e8cf8670ea3513386a39250c155c0e22f (diff)
downloadtcl-6071dd54232192dfc2f58917e4e64fd8d3940368.zip
tcl-6071dd54232192dfc2f58917e4e64fd8d3940368.tar.gz
tcl-6071dd54232192dfc2f58917e4e64fd8d3940368.tar.bz2
merge updates from HEAD
Diffstat (limited to 'generic/tclExecute.c')
-rw-r--r--generic/tclExecute.c1238
1 files changed, 812 insertions, 426 deletions
diff --git a/generic/tclExecute.c b/generic/tclExecute.c
index 8a05056..4501de3 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.285.2.11 2007/07/01 17:31:23 dgp Exp $
+ * RCS: @(#) $Id: tclExecute.c,v 1.285.2.12 2007/09/04 17:43:50 dgp Exp $
*/
#include "tclInt.h"
@@ -87,7 +87,7 @@ int tclTraceExec = 0;
* expression opcodes (e.g., INST_LOR) in tclCompile.h.
*
* Does not include the string for INST_EXPON (and beyond), as that is
- * disjoint for backward-compatability reasons
+ * disjoint for backward-compatability reasons.
*/
static const char *operatorStrings[] = {
@@ -119,7 +119,7 @@ long tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 };
#endif /* TCL_COMPILE_STATS */
/*
- * Support pre-8.5 bytecodes unless specifically requested otherwise
+ * Support pre-8.5 bytecodes unless specifically requested otherwise.
*/
#ifndef TCL_SUPPORT_84_BYTECODE
@@ -177,6 +177,27 @@ static BuiltinFunc tclBuiltinFuncTable[] = {
#endif
/*
+ * These variable-access macros have to coincide with those in tclVar.c
+ */
+
+#define VarHashGetValue(hPtr) \
+ ((Var *) ((char *)hPtr - TclOffset(VarInHash, entry)))
+
+static inline Var *
+VarHashCreateVar(TclVarHashTable *tablePtr, Tcl_Obj *key, int *newPtr)
+{
+ Tcl_HashEntry *hPtr = Tcl_CreateHashEntry((Tcl_HashTable *) tablePtr, (char *) key, newPtr);
+ if (hPtr) {
+ return VarHashGetValue(hPtr);
+ } else {
+ return NULL;
+ }
+}
+
+#define VarHashFindVar(tablePtr, key) \
+ VarHashCreateVar((tablePtr), (key), NULL)
+
+/*
* The new macro for ending an instruction; note that a reasonable C-optimiser
* will resolve all branches at compile time. (result) is always a constant;
* the macro NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is resolved
@@ -401,6 +422,19 @@ static BuiltinFunc tclBuiltinFuncTable[] = {
#endif
/*
+ * Macro used to make the check for type overflow more mnemonic. This works by
+ * comparing sign bits; the rest of the word is irrelevant. The ANSI C
+ * "prototype" (where inttype_t is any integer type) is:
+ *
+ * MODULE_SCOPE int Overflowing(inttype_t a, inttype_t b, inttype_t sum);
+ *
+ * Check first the condition most likely to fail in usual code (at least for
+ * usage in [incr]: do the first summand and the sum have != signs?
+ */
+
+#define Overflowing(a,b,sum) ((((a)^(sum)) < 0) && (((a)^(b)) >= 0))
+
+/*
* Custom object type only used in this file; values of its type should never
* be seen by user scripts.
*/
@@ -411,6 +445,138 @@ static Tcl_ObjType dictIteratorType = {
};
/*
+ * Auxiliary tables used to compute powers of small integers
+ */
+
+#if (LONG_MAX == 0x7fffffff)
+
+/*
+ * Maximum base that, when raised to powers 2, 3, ... 8, fits in a 32-bit
+ * signed integer
+ */
+
+static const long MaxBase32[7] = {46340, 1290, 215, 73, 35, 21, 14};
+
+/*
+ * Table giving 3, 4, ..., 11, raised to the powers 9, 10, ...,
+ * as far as they fit in a 32-bit signed integer. Exp32Index[i] gives
+ * the starting index of powers of i+3; Exp32Value[i] gives the corresponding
+ * powers.
+ */
+
+static const unsigned short Exp32Index[] = {
+ 0, 11, 18, 23, 26, 29, 31, 32, 33
+};
+static const long Exp32Value[] = {
+ 19683, 59049, 177147, 531441, 1594323, 4782969, 14348907, 43046721,
+ 129140163, 387420489, 1162261467, 262144, 1048576, 4194304,
+ 16777216, 67108864, 268435456, 1073741824, 1953125, 9765625,
+ 48828125, 244140625, 1220703125, 10077696, 60466176, 362797056,
+ 40353607, 282475249, 1977326743, 134217728, 1073741824, 387420489,
+ 1000000000
+};
+
+#endif /* LONG_MAX == 0x7fffffff -- 32 bit machine */
+
+#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
+
+/*
+ * Maximum base that, when raised to powers 2, 3, ..., 16, fits in a
+ * Tcl_WideInt.
+ */
+
+static Tcl_WideInt MaxBaseWide[15];
+
+/*
+ *Table giving 3, 4, ..., 13 raised to powers greater than 16 when the
+ * results fit in a 64-bit signed integer.
+ */
+
+static const unsigned short Exp64Index[] = {
+ 0, 23, 38, 49, 57, 63, 67, 70, 72, 74, 75, 76
+};
+static const Tcl_WideInt Exp64Value[] = {
+ (Tcl_WideInt)243*243*243*3*3,
+ (Tcl_WideInt)243*243*243*3*3*3,
+ (Tcl_WideInt)243*243*243*3*3*3*3,
+ (Tcl_WideInt)243*243*243*243,
+ (Tcl_WideInt)243*243*243*243*3,
+ (Tcl_WideInt)243*243*243*243*3*3,
+ (Tcl_WideInt)243*243*243*243*3*3*3,
+ (Tcl_WideInt)243*243*243*243*3*3*3*3,
+ (Tcl_WideInt)243*243*243*243*243,
+ (Tcl_WideInt)243*243*243*243*243*3,
+ (Tcl_WideInt)243*243*243*243*243*3*3,
+ (Tcl_WideInt)243*243*243*243*243*3*3*3,
+ (Tcl_WideInt)243*243*243*243*243*3*3*3*3,
+ (Tcl_WideInt)243*243*243*243*243*243,
+ (Tcl_WideInt)243*243*243*243*243*243*3,
+ (Tcl_WideInt)243*243*243*243*243*243*3*3,
+ (Tcl_WideInt)243*243*243*243*243*243*3*3*3,
+ (Tcl_WideInt)243*243*243*243*243*243*3*3*3*3,
+ (Tcl_WideInt)243*243*243*243*243*243*243,
+ (Tcl_WideInt)243*243*243*243*243*243*243*3,
+ (Tcl_WideInt)243*243*243*243*243*243*243*3*3,
+ (Tcl_WideInt)243*243*243*243*243*243*243*3*3*3,
+ (Tcl_WideInt)243*243*243*243*243*243*243*3*3*3*3,
+ (Tcl_WideInt)1024*1024*1024*4*4,
+ (Tcl_WideInt)1024*1024*1024*4*4*4,
+ (Tcl_WideInt)1024*1024*1024*4*4*4*4,
+ (Tcl_WideInt)1024*1024*1024*1024,
+ (Tcl_WideInt)1024*1024*1024*1024*4,
+ (Tcl_WideInt)1024*1024*1024*1024*4*4,
+ (Tcl_WideInt)1024*1024*1024*1024*4*4*4,
+ (Tcl_WideInt)1024*1024*1024*1024*4*4*4*4,
+ (Tcl_WideInt)1024*1024*1024*1024*1024,
+ (Tcl_WideInt)1024*1024*1024*1024*1024*4,
+ (Tcl_WideInt)1024*1024*1024*1024*1024*4*4,
+ (Tcl_WideInt)1024*1024*1024*1024*1024*4*4*4,
+ (Tcl_WideInt)1024*1024*1024*1024*1024*4*4*4*4,
+ (Tcl_WideInt)1024*1024*1024*1024*1024*1024,
+ (Tcl_WideInt)1024*1024*1024*1024*1024*1024*4,
+ (Tcl_WideInt)3125*3125*3125*5*5,
+ (Tcl_WideInt)3125*3125*3125*5*5*5,
+ (Tcl_WideInt)3125*3125*3125*5*5*5*5,
+ (Tcl_WideInt)3125*3125*3125*3125,
+ (Tcl_WideInt)3125*3125*3125*3125*5,
+ (Tcl_WideInt)3125*3125*3125*3125*5*5,
+ (Tcl_WideInt)3125*3125*3125*3125*5*5*5,
+ (Tcl_WideInt)3125*3125*3125*3125*5*5*5*5,
+ (Tcl_WideInt)3125*3125*3125*3125*3125,
+ (Tcl_WideInt)3125*3125*3125*3125*3125*5,
+ (Tcl_WideInt)3125*3125*3125*3125*3125*5*5,
+ (Tcl_WideInt)7776*7776*7776*6*6,
+ (Tcl_WideInt)7776*7776*7776*6*6*6,
+ (Tcl_WideInt)7776*7776*7776*6*6*6*6,
+ (Tcl_WideInt)7776*7776*7776*7776,
+ (Tcl_WideInt)7776*7776*7776*7776*6,
+ (Tcl_WideInt)7776*7776*7776*7776*6*6,
+ (Tcl_WideInt)7776*7776*7776*7776*6*6*6,
+ (Tcl_WideInt)7776*7776*7776*7776*6*6*6*6,
+ (Tcl_WideInt)16807*16807*16807*7*7,
+ (Tcl_WideInt)16807*16807*16807*7*7*7,
+ (Tcl_WideInt)16807*16807*16807*7*7*7*7,
+ (Tcl_WideInt)16807*16807*16807*16807,
+ (Tcl_WideInt)16807*16807*16807*16807*7,
+ (Tcl_WideInt)16807*16807*16807*16807*7*7,
+ (Tcl_WideInt)32768*32768*32768*8*8,
+ (Tcl_WideInt)32768*32768*32768*8*8*8,
+ (Tcl_WideInt)32768*32768*32768*8*8*8*8,
+ (Tcl_WideInt)32768*32768*32768*32768,
+ (Tcl_WideInt)59049*59049*59049*9*9,
+ (Tcl_WideInt)59049*59049*59049*9*9*9,
+ (Tcl_WideInt)59049*59049*59049*9*9*9*9,
+ (Tcl_WideInt)100000*100000*100000*10*10,
+ (Tcl_WideInt)100000*100000*100000*10*10*10,
+ (Tcl_WideInt)161051*161051*161051*11*11,
+ (Tcl_WideInt)161051*161051*161051*11*11*11,
+ (Tcl_WideInt)248832*248832*248832*12*12,
+ (Tcl_WideInt)371293*371293*371293*13*13
+};
+
+#endif
+
+/*
* Declarations for local procedures to this file:
*/
@@ -426,7 +592,8 @@ static ExceptionRange * GetExceptRangeForPc(unsigned char *pc, int catchOnly,
ByteCode *codePtr);
static const char * GetSrcInfoForPc(unsigned char *pc, ByteCode *codePtr,
int *lengthPtr);
-static Tcl_Obj ** GrowEvaluationStack(ExecEnv *eePtr, int growth, int move);
+static Tcl_Obj ** GrowEvaluationStack(ExecEnv *eePtr, int growth,
+ int move);
static void IllegalExprOperandType(Tcl_Interp *interp,
unsigned char *pc, Tcl_Obj *opndPtr);
static void InitByteCodeExecution(Tcl_Interp *interp);
@@ -437,13 +604,10 @@ static void ValidatePcAndStackTop(ByteCode *codePtr,
unsigned char *pc, int stackTop,
int stackLowerBound, int checkStack);
#endif /* TCL_COMPILE_DEBUG */
-
static void DeleteExecStack(ExecStack *esPtr);
-
/* 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);
-
/*
*----------------------------------------------------------------------
@@ -472,6 +636,9 @@ InitByteCodeExecution(
* "tcl_traceExec" is linked to control
* instruction tracing. */
{
+#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
+ int i;
+#endif
#ifdef TCL_COMPILE_DEBUG
if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec,
TCL_LINK_INT) != TCL_OK) {
@@ -482,6 +649,11 @@ InitByteCodeExecution(
Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd,
(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
#endif /* TCL_COMPILE_STATS */
+#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
+ for (i = 2; i <= 16; ++i) {
+ MaxBaseWide[i-2] = (Tcl_WideInt) pow((double) LLONG_MAX, 1.0 / i);
+ }
+#endif
}
/*
@@ -672,7 +844,7 @@ GrowEvaluationStack(
* store it in esPtr as the current marker. Return a pointer to one
* word past the marker.
*/
-
+
esPtr->markerPtr = ++esPtr->tosPtr;
*esPtr->markerPtr = (Tcl_Obj *) markerPtr;
return esPtr->markerPtr + 1;
@@ -739,7 +911,7 @@ GrowEvaluationStack(
* 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->tosPtr = &esPtr->stackWords[0];
@@ -764,10 +936,10 @@ GrowEvaluationStack(
/*
*--------------------------------------------------------------
*
- * TclStackAlloc --
+ * TclStackAlloc, TclStackRealloc, TclStackFree --
*
* Allocate memory from the execution stack; it has to be returned later
- * with a call to TclStackFree
+ * with a call to TclStackFree.
*
* Results:
* A pointer to the first byte allocated, or panics if the allocation did
@@ -788,7 +960,7 @@ StackAllocWords(
* 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);
@@ -829,14 +1001,14 @@ TclStackFree(
* 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;
if ((markerPtr+1) != (Tcl_Obj **)freePtr) {
- Tcl_Panic("TclStackFree: incorrect freePtr. Call out of sequence?");
+ Tcl_Panic("TclStackFree: incorrect freePtr. Call out of sequence?");
}
esPtr->tosPtr = markerPtr-1;
@@ -897,7 +1069,7 @@ TclStackRealloc(
markerPtr = esPtr->markerPtr;
if ((markerPtr+1) != (Tcl_Obj **)ptr) {
- Tcl_Panic("TclStackRealloc: incorrect ptr. Call out of sequence?");
+ Tcl_Panic("TclStackRealloc: incorrect ptr. Call out of sequence?");
}
numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
@@ -939,46 +1111,11 @@ Tcl_ExprObj(
Interp *iPtr = (Interp *) interp;
CompileEnv compEnv; /* Compilation environment structure allocated
* in frame. */
- LiteralTable *localTablePtr = &(compEnv.localLitTable);
register ByteCode *codePtr = NULL;
/* Tcl Internal type of bytecode. Initialized
* to avoid compiler warning. */
- AuxData *auxDataPtr;
- LiteralEntry *entryPtr;
- Tcl_Obj *saveObjPtr, *resultPtr;
- char *string;
- int length, i, result;
-
- /*
- * First handle some common expressions specially.
- */
-
- string = Tcl_GetStringFromObj(objPtr, &length);
- if (length == 1) {
- if (*string == '0') {
- TclNewBooleanObj(resultPtr, 0);
- Tcl_IncrRefCount(resultPtr);
- *resultPtrPtr = resultPtr;
- return TCL_OK;
- } else if (*string == '1') {
- TclNewBooleanObj(resultPtr, 1);
- Tcl_IncrRefCount(resultPtr);
- *resultPtrPtr = resultPtr;
- return TCL_OK;
- }
- } else if ((length == 2) && (*string == '!')) {
- if (*(string+1) == '0') {
- TclNewBooleanObj(resultPtr, 1);
- Tcl_IncrRefCount(resultPtr);
- *resultPtrPtr = resultPtr;
- return TCL_OK;
- } else if (*(string+1) == '1') {
- TclNewBooleanObj(resultPtr, 0);
- Tcl_IncrRefCount(resultPtr);
- *resultPtrPtr = resultPtr;
- return TCL_OK;
- }
- }
+ Tcl_Obj *saveObjPtr;
+ int result;
/*
* Get the ByteCode from the object. If it exists, make sure it hasn't
@@ -1007,49 +1144,12 @@ Tcl_ExprObj(
}
}
if (objPtr->typePtr != &tclByteCodeType) {
- /*
- * TIP #280: No invoker (yet) - Expression compilation
- */
+ /* TIP #280: No invoker (yet) - Expression compilation. */
+ int length;
+ const char *string = Tcl_GetStringFromObj(objPtr, &length);
TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0);
- result = TclCompileExpr(interp, string, length, &compEnv);
-
- /*
- * Free the compilation environment's literal table bucket array if it
- * was dynamically allocated.
- */
-
- if (localTablePtr->buckets != localTablePtr->staticBuckets) {
- ckfree((char *) localTablePtr->buckets);
- }
-
- if (result != TCL_OK) {
- /*
- * Compilation errors. Free storage allocated for compilation.
- */
-
-#ifdef TCL_COMPILE_DEBUG
- TclVerifyLocalLiteralTable(&compEnv);
-#endif /*TCL_COMPILE_DEBUG*/
- entryPtr = compEnv.literalArrayPtr;
- for (i = 0; i < compEnv.literalArrayNext; i++) {
- TclReleaseLiteral(interp, entryPtr->objPtr);
- entryPtr++;
- }
-#ifdef TCL_COMPILE_DEBUG
- TclVerifyGlobalLiteralTable(iPtr);
-#endif /*TCL_COMPILE_DEBUG*/
-
- auxDataPtr = compEnv.auxDataArrayPtr;
- for (i = 0; i < compEnv.auxDataArrayNext; i++) {
- if (auxDataPtr->type->freeProc != NULL) {
- auxDataPtr->type->freeProc(auxDataPtr->clientData);
- }
- auxDataPtr++;
- }
- TclFreeCompileEnv(&compEnv);
- return result;
- }
+ TclCompileExpr(interp, string, length, &compEnv);
/*
* Successful compilation. If the expression yielded no instructions,
@@ -1074,6 +1174,7 @@ Tcl_ExprObj(
#ifdef TCL_COMPILE_DEBUG
if (tclTraceCompile == 2) {
TclPrintByteCodeObj(interp, objPtr);
+ fflush(stdout);
}
#endif /* TCL_COMPILE_DEBUG */
}
@@ -1204,8 +1305,9 @@ TclCompEvalObj(
codePtr->compileEpoch = iPtr->compileEpoch;
} else {
/*
- * This byteCode is invalid: free it and recompile
+ * This byteCode is invalid: free it and recompile.
*/
+
objPtr->typePtr->freeIntRepProc(objPtr);
goto recompileObj;
}
@@ -1296,15 +1398,16 @@ TclIncrObj(
long sum = augend + addend;
/*
- * Test for overflow.
+ * Overflow when (augend and sum have different sign) and (augend and
+ * addend have the same sign). This is encapsulated in the Overflowing
+ * macro.
*/
- if ((augend >= 0 || addend >= 0 || sum < 0)
- && (sum >= 0 || addend < 0 || augend < 0)) {
+ if (!Overflowing(augend, addend, sum)) {
TclSetLongObj(valuePtr, sum);
return TCL_OK;
}
-#ifndef TCL_WIDE_INT_IS_LONG
+#ifndef NO_WIDE_TYPE
{
Tcl_WideInt w1 = (Tcl_WideInt)augend;
Tcl_WideInt w2 = (Tcl_WideInt)addend;
@@ -1348,8 +1451,7 @@ TclIncrObj(
* Check for overflow.
*/
- if ((w1 >= 0 || w2 >= 0 || sum < 0)
- && (w1 < 0 || w2 < 0 || sum >= 0)) {
+ if (!Overflowing(w1, w2, sum)) {
Tcl_SetWideIntObj(valuePtr, sum);
return TCL_OK;
}
@@ -1559,8 +1661,9 @@ TclExecuteByteCode(
case 0:
/*
* We really want to do nothing now, but this is needed for some
- * compilers (SunPro CC)
+ * compilers (SunPro CC).
*/
+
break;
}
}
@@ -1568,7 +1671,7 @@ TclExecuteByteCode(
#ifdef TCL_COMPILE_DEBUG
/*
- * Skip the stack depth check if an expansion is in progress
+ * Skip the stack depth check if an expansion is in progress.
*/
ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, 0,
@@ -1619,7 +1722,23 @@ TclExecuteByteCode(
}
}
+ /*
+ * These two instructions account for 26% of all instructions (according
+ * to measurements on tclbench by Ben Vitale
+ * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf]
+ * Resolving them before the switch reduces the cost of branch
+ * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!)
+ * reduces total obj size.
+ */
+
+ if (*pc == INST_LOAD_SCALAR1) {
+ goto instLoadScalar1;
+ } else if (*pc == INST_PUSH1) {
+ goto instPush1Peephole;
+ }
+
switch (*pc) {
+ case INST_SYNTAX:
case INST_RETURN_IMM: {
int code = TclGetInt4AtPtr(pc+1);
int level = TclGetUInt4AtPtr(pc+5);
@@ -1636,6 +1755,9 @@ TclExecuteByteCode(
NEXT_INST_F(9, 1, 0);
} else {
Tcl_SetObjResult(interp, OBJ_UNDER_TOS);
+ if (*pc == INST_SYNTAX) {
+ iPtr->flags &= ~ERR_ALREADY_LOGGED;
+ }
cleanup = 2;
goto processExceptionReturn;
}
@@ -1680,9 +1802,7 @@ TclExecuteByteCode(
}
case INST_PUSH1:
-#if !TCL_COMPILE_DEBUG
instPush1Peephole:
-#endif
PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]);
TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS);
pc += 2;
@@ -1975,7 +2095,6 @@ TclExecuteByteCode(
doInvocation:
{
Tcl_Obj **objv = &OBJ_AT_DEPTH(objc-1);
- Command *cmdPtr;
#ifdef TCL_COMPILE_DEBUG
if (tclTraceExec >= 2) {
@@ -2014,43 +2133,19 @@ TclExecuteByteCode(
bcFramePtr->data.tebc.pc = (char *) pc;
iPtr->cmdFramePtr = bcFramePtr;
DECACHE_STACK_INFO();
- cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[0]);
-
- if (cmdPtr
- && !((cmdPtr->flags & CMD_HAS_EXEC_TRACES) || iPtr->tracePtr)
- && !(checkInterp && (codePtr->compileEpoch != iPtr->compileEpoch))
- ) {
- cmdPtr->refCount++;
- iPtr->cmdCount++;
- result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp, objc, objv);
-
- if (Tcl_AsyncReady()) {
- result = Tcl_AsyncInvoke(interp, result);
- }
- if (result == TCL_OK && TclLimitReady(iPtr->limit)) {
- result = Tcl_LimitCheck(interp);
- }
- TclCleanupCommandMacro(cmdPtr);
- } 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.
- */
- int length;
- const char *bytes;
-
- bytes = GetSrcInfoForPc(pc, codePtr, &length);
- result = TclEvalObjvInternal(interp, objc, objv, bytes,
- length, 0);
- }
-
+ result = TclEvalObjvInternal(interp, objc, objv,
+ /* call from TEBC */(char *) -1, -1, 0);
CACHE_STACK_INFO();
iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;
if (result == TCL_OK) {
Tcl_Obj *objPtr;
+#ifndef TCL_COMPILE_DEBUG
+ if (*(pc+pcAdjustment) == INST_POP) {
+ NEXT_INST_V((pcAdjustment+1), objc, 0);
+ }
+#endif
/*
* Push the call's object result and continue execution with
* the next instruction.
@@ -2256,14 +2351,14 @@ TclExecuteByteCode(
*/
{
int opnd, pcAdjustment;
- char *part1, *part2;
+ Tcl_Obj *part1Ptr, *part2Ptr;
Var *varPtr, *arrayPtr;
Tcl_Obj *objPtr;
case INST_LOAD_SCALAR1:
+ instLoadScalar1:
opnd = TclGetUInt1AtPtr(pc+1);
varPtr = &(compiledLocals[opnd]);
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
@@ -2280,13 +2375,12 @@ TclExecuteByteCode(
pcAdjustment = 2;
cleanup = 0;
arrayPtr = NULL;
- part2 = NULL;
+ part1Ptr = part2Ptr = NULL;
goto doCallPtrGetVar;
case INST_LOAD_SCALAR4:
opnd = TclGetUInt4AtPtr(pc+1);
varPtr = &(compiledLocals[opnd]);
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
@@ -2303,38 +2397,80 @@ TclExecuteByteCode(
pcAdjustment = 5;
cleanup = 0;
arrayPtr = NULL;
- part2 = NULL;
+ part1Ptr = part2Ptr = NULL;
+ goto doCallPtrGetVar;
+
+ case INST_LOAD_ARRAY4:
+ opnd = TclGetUInt4AtPtr(pc+1);
+ pcAdjustment = 5;
+ goto doLoadArray;
+
+ case INST_LOAD_ARRAY1:
+ opnd = TclGetUInt1AtPtr(pc+1);
+ pcAdjustment = 2;
+
+ doLoadArray:
+ part1Ptr = NULL;
+ part2Ptr = OBJ_AT_TOS;
+ arrayPtr = &(compiledLocals[opnd]);
+ while (TclIsVarLink(arrayPtr)) {
+ arrayPtr = arrayPtr->value.linkPtr;
+ }
+ TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
+ if (TclIsVarArray(arrayPtr) && !(arrayPtr->flags & VAR_TRACED_READ)) {
+ varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
+ if (varPtr && TclIsVarDirectReadable(varPtr)) {
+ /*
+ * No errors, no traces: just get the value.
+ */
+
+ objResultPtr = varPtr->value.objPtr;
+ TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
+ NEXT_INST_F(pcAdjustment, 1, 1);
+ }
+ }
+ varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
+ TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr, opnd);
+ if (varPtr == NULL) {
+ TRACE_APPEND(("ERROR: %.30s\n",
+ O2S(Tcl_GetObjResult(interp))));
+ result = TCL_ERROR;
+ goto checkForCatch;
+ }
+ cleanup = 1;
goto doCallPtrGetVar;
case INST_LOAD_ARRAY_STK:
cleanup = 2;
- part2 = Tcl_GetString(OBJ_AT_TOS); /* element name */
- objPtr = OBJ_UNDER_TOS; /* array name */
- TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), part2));
+ part2Ptr = OBJ_AT_TOS; /* element name */
+ objPtr = OBJ_UNDER_TOS; /* array name */
+ TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), O2S(part2Ptr)));
goto doLoadStk;
case INST_LOAD_STK:
case INST_LOAD_SCALAR_STK:
cleanup = 1;
- part2 = NULL;
- objPtr = OBJ_AT_TOS; /* variable name */
+ part2Ptr = NULL;
+ objPtr = OBJ_AT_TOS; /* variable name */
TRACE(("\"%.30s\" => ", O2S(objPtr)));
doLoadStk:
- part1 = TclGetString(objPtr);
- varPtr = TclObjLookupVar(interp, objPtr, part2, TCL_LEAVE_ERR_MSG,
- "read", /*createPart1*/ 0, /*createPart2*/ 1, &arrayPtr);
+ part1Ptr = objPtr;
+ varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr,
+ TCL_LEAVE_ERR_MSG, "read", /*createPart1*/0, /*createPart2*/1,
+ &arrayPtr);
if (varPtr) {
- if (TclIsVarDirectReadable(varPtr)
- && ((arrayPtr == NULL) || TclIsVarUntraced(arrayPtr))) {
+ if (TclIsVarDirectReadable2(varPtr, arrayPtr)) {
/*
* No errors, no traces: just get the value.
*/
+
objResultPtr = varPtr->value.objPtr;
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(1, cleanup, 1);
}
pcAdjustment = 1;
+ opnd = -1;
goto doCallPtrGetVar;
} else {
TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
@@ -2342,57 +2478,6 @@ TclExecuteByteCode(
goto checkForCatch;
}
- case INST_LOAD_ARRAY4:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- goto doLoadArray;
-
- case INST_LOAD_ARRAY1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
-
- doLoadArray:
- part2 = TclGetString(OBJ_AT_TOS);
- arrayPtr = &(compiledLocals[opnd]);
- part1 = arrayPtr->name;
- while (TclIsVarLink(arrayPtr)) {
- arrayPtr = arrayPtr->value.linkPtr;
- }
- TRACE(("%u \"%.30s\" => ", opnd, part2));
- if (!TclIsVarUndefined(arrayPtr)
- && TclIsVarArray(arrayPtr)
- && TclIsVarUntraced(arrayPtr)) {
- Tcl_HashEntry *hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr,
- part2);
- if (hPtr) {
- varPtr = (Var *) Tcl_GetHashValue(hPtr);
- } else {
- goto doLoadArrayNextBranch;
- }
- } else {
- doLoadArrayNextBranch:
- varPtr = TclLookupArrayElement(interp, part1, part2,
- TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr);
- if (varPtr == NULL) {
- TRACE_APPEND(("ERROR: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- result = TCL_ERROR;
- goto checkForCatch;
- }
- }
- if (TclIsVarDirectReadable(varPtr)
- && ((arrayPtr == NULL) || TclIsVarUntraced(arrayPtr))) {
- /*
- * No errors, no traces: just get the value.
- */
-
- objResultPtr = varPtr->value.objPtr;
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_F(pcAdjustment, 1, 1);
- }
- cleanup = 1;
- goto doCallPtrGetVar;
-
doCallPtrGetVar:
/*
* There are either errors or the variable is traced: call
@@ -2400,8 +2485,8 @@ TclExecuteByteCode(
*/
DECACHE_STACK_INFO();
- objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, part2,
- TCL_LEAVE_ERR_MSG);
+ objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr,
+ TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (objResultPtr) {
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
@@ -2429,64 +2514,142 @@ TclExecuteByteCode(
{
int opnd, pcAdjustment, storeFlags;
- char *part1, *part2;
+ Tcl_Obj *part1Ptr, *part2Ptr;
Var *varPtr, *arrayPtr;
Tcl_Obj *objPtr, *valuePtr;
+ case INST_STORE_ARRAY4:
+ opnd = TclGetUInt4AtPtr(pc+1);
+ pcAdjustment = 5;
+ goto doStoreArrayDirect;
+
+ case INST_STORE_ARRAY1:
+ opnd = TclGetUInt1AtPtr(pc+1);
+ pcAdjustment = 2;
+
+ doStoreArrayDirect:
+ valuePtr = OBJ_AT_TOS;
+ part2Ptr = OBJ_UNDER_TOS;
+ arrayPtr = &(compiledLocals[opnd]);
+ TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
+ O2S(valuePtr)));
+ while (TclIsVarLink(arrayPtr)) {
+ arrayPtr = arrayPtr->value.linkPtr;
+ }
+ if (TclIsVarArray(arrayPtr) && !(arrayPtr->flags & VAR_TRACED_WRITE)) {
+ varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
+ if (varPtr && TclIsVarDirectWritable(varPtr)) {
+ tosPtr--;
+ Tcl_DecrRefCount(OBJ_AT_TOS);
+ OBJ_AT_TOS = valuePtr;
+ goto doStoreVarDirect;
+ }
+ }
+ cleanup = 2;
+ storeFlags = TCL_LEAVE_ERR_MSG;
+ part1Ptr = NULL;
+ goto doStoreArrayDirectFailed;
+
+ case INST_STORE_SCALAR4:
+ opnd = TclGetUInt4AtPtr(pc+1);
+ pcAdjustment = 5;
+ goto doStoreScalarDirect;
+
+ case INST_STORE_SCALAR1:
+ opnd = TclGetUInt1AtPtr(pc+1);
+ pcAdjustment = 2;
+
+ doStoreScalarDirect:
+ valuePtr = OBJ_AT_TOS;
+ varPtr = &(compiledLocals[opnd]);
+ TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
+ while (TclIsVarLink(varPtr)) {
+ varPtr = varPtr->value.linkPtr;
+ }
+ if (TclIsVarDirectWritable(varPtr)) {
+ doStoreVarDirect:
+ /*
+ * No traces, no errors, plain 'set': we can safely inline. The
+ * value *will* be set to what's requested, so that the stack top
+ * remains pointing to the same Tcl_Obj.
+ */
+
+ valuePtr = varPtr->value.objPtr;
+ if (valuePtr != NULL) {
+ TclDecrRefCount(valuePtr);
+ }
+ objResultPtr = OBJ_AT_TOS;
+ varPtr->value.objPtr = objResultPtr;
+#ifndef TCL_COMPILE_DEBUG
+ if (*(pc+pcAdjustment) == INST_POP) {
+ tosPtr--;
+ NEXT_INST_F((pcAdjustment+1), 0, 0);
+ }
+#else
+ TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
+#endif
+ Tcl_IncrRefCount(objResultPtr);
+ NEXT_INST_F(pcAdjustment, 0, 0);
+ }
+ storeFlags = TCL_LEAVE_ERR_MSG;
+ part1Ptr = NULL;
+ goto doStoreScalar;
+
case INST_LAPPEND_STK:
valuePtr = OBJ_AT_TOS; /* value to append */
- part2 = NULL;
+ part2Ptr = NULL;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
| TCL_LIST_ELEMENT | TCL_TRACE_READS);
goto doStoreStk;
case INST_LAPPEND_ARRAY_STK:
valuePtr = OBJ_AT_TOS; /* value to append */
- part2 = TclGetString(OBJ_UNDER_TOS);
+ part2Ptr = OBJ_UNDER_TOS;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
| TCL_LIST_ELEMENT | TCL_TRACE_READS);
goto doStoreStk;
case INST_APPEND_STK:
valuePtr = OBJ_AT_TOS; /* value to append */
- part2 = NULL;
+ part2Ptr = NULL;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
goto doStoreStk;
case INST_APPEND_ARRAY_STK:
valuePtr = OBJ_AT_TOS; /* value to append */
- part2 = TclGetString(OBJ_UNDER_TOS);
+ part2Ptr = OBJ_UNDER_TOS;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
goto doStoreStk;
case INST_STORE_ARRAY_STK:
valuePtr = OBJ_AT_TOS;
- part2 = TclGetString(OBJ_UNDER_TOS);
+ part2Ptr = OBJ_UNDER_TOS;
storeFlags = TCL_LEAVE_ERR_MSG;
goto doStoreStk;
case INST_STORE_STK:
case INST_STORE_SCALAR_STK:
valuePtr = OBJ_AT_TOS;
- part2 = NULL;
+ part2Ptr = NULL;
storeFlags = TCL_LEAVE_ERR_MSG;
doStoreStk:
- objPtr = OBJ_AT_DEPTH(1 + (part2 != NULL)); /* variable name */
- part1 = TclGetString(objPtr);
+ objPtr = OBJ_AT_DEPTH(1 + (part2Ptr != NULL)); /* variable name */
+ part1Ptr = objPtr;
#ifdef TCL_COMPILE_DEBUG
- if (part2 == NULL) {
- TRACE(("\"%.30s\" <- \"%.30s\" =>", part1, O2S(valuePtr)));
+ if (part2Ptr == NULL) {
+ TRACE(("\"%.30s\" <- \"%.30s\" =>", O2S(part1Ptr), O2S(valuePtr)));
} else {
TRACE(("\"%.30s(%.30s)\" <- \"%.30s\" => ",
- part1, part2, O2S(valuePtr)));
+ O2S(part1Ptr), O2S(part2Ptr), O2S(valuePtr)));
}
#endif
- varPtr = TclObjLookupVar(interp, objPtr, part2, TCL_LEAVE_ERR_MSG,
+ varPtr = TclObjLookupVarEx(interp, objPtr, part2Ptr, TCL_LEAVE_ERR_MSG,
"set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
if (varPtr) {
- cleanup = ((part2 == NULL)? 2 : 3);
+ cleanup = ((part2Ptr == NULL)? 2 : 3);
pcAdjustment = 1;
+ opnd = -1;
goto doCallPtrSetVar;
} else {
TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
@@ -2520,39 +2683,21 @@ TclExecuteByteCode(
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
goto doStoreArray;
- case INST_STORE_ARRAY4:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- storeFlags = TCL_LEAVE_ERR_MSG;
- goto doStoreArray;
-
- case INST_STORE_ARRAY1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
- storeFlags = TCL_LEAVE_ERR_MSG;
-
doStoreArray:
valuePtr = OBJ_AT_TOS;
- part2 = TclGetString(OBJ_UNDER_TOS);
+ part2Ptr = OBJ_UNDER_TOS;
arrayPtr = &(compiledLocals[opnd]);
- part1 = arrayPtr->name;
- cleanup = 2;
- TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, part2, O2S(valuePtr)));
+ TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
+ O2S(valuePtr)));
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
- if (!TclIsVarUndefined(arrayPtr)
- && TclIsVarArray(arrayPtr)
- && TclIsVarUntraced(arrayPtr)) {
- Tcl_HashEntry *hPtr = Tcl_FindHashEntry(arrayPtr->value.tablePtr,
- part2);
- if (hPtr) {
- varPtr = (Var *) Tcl_GetHashValue(hPtr);
- goto doCallPtrSetVar;
- }
- }
- varPtr = TclLookupArrayElement(interp, part1, part2,
- TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr);
+ cleanup = 2;
+ part1Ptr = NULL;
+
+ doStoreArrayDirectFailed:
+ varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
+ TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr, opnd);
if (varPtr) {
goto doCallPtrSetVar;
} else {
@@ -2587,78 +2732,34 @@ TclExecuteByteCode(
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
goto doStoreScalar;
- case INST_STORE_SCALAR4:
- opnd = TclGetUInt4AtPtr(pc+1);
- pcAdjustment = 5;
- storeFlags = TCL_LEAVE_ERR_MSG;
- goto doStoreScalar;
-
- case INST_STORE_SCALAR1:
- opnd = TclGetUInt1AtPtr(pc+1);
- pcAdjustment = 2;
- storeFlags = TCL_LEAVE_ERR_MSG;
-
doStoreScalar:
valuePtr = OBJ_AT_TOS;
varPtr = &(compiledLocals[opnd]);
- part1 = varPtr->name;
TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
cleanup = 1;
arrayPtr = NULL;
- part2 = NULL;
+ part1Ptr = part2Ptr = NULL;
doCallPtrSetVar:
- if ((storeFlags == TCL_LEAVE_ERR_MSG)
- && TclIsVarDirectWritable(varPtr)
- && ((arrayPtr == NULL) || TclIsVarUntraced(arrayPtr))) {
- /*
- * No traces, no errors, plain 'set': we can safely inline. The
- * value *will* be set to what's requested, so that the stack top
- * remains pointing to the same Tcl_Obj.
- */
-
- valuePtr = varPtr->value.objPtr;
- objResultPtr = OBJ_AT_TOS;
- if (valuePtr != objResultPtr) {
- if (valuePtr != NULL) {
- TclDecrRefCount(valuePtr);
- } else {
- TclSetVarScalar(varPtr);
- TclClearVarUndefined(varPtr);
- }
- varPtr->value.objPtr = objResultPtr;
- Tcl_IncrRefCount(objResultPtr);
- }
+ DECACHE_STACK_INFO();
+ objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr,
+ part1Ptr, part2Ptr, valuePtr, storeFlags, opnd);
+ CACHE_STACK_INFO();
+ if (objResultPtr) {
#ifndef TCL_COMPILE_DEBUG
if (*(pc+pcAdjustment) == INST_POP) {
NEXT_INST_V((pcAdjustment+1), cleanup, 0);
}
-#else
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
#endif
+ TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(pcAdjustment, cleanup, 1);
} else {
- DECACHE_STACK_INFO();
- objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr,
- part1, part2, valuePtr, storeFlags);
- CACHE_STACK_INFO();
- if (objResultPtr) {
-#ifndef TCL_COMPILE_DEBUG
- if (*(pc+pcAdjustment) == INST_POP) {
- NEXT_INST_V((pcAdjustment+1), cleanup, 0);
- }
-#endif
- TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
- NEXT_INST_V(pcAdjustment, cleanup, 1);
- } else {
- TRACE_APPEND(("ERROR: %.30s\n",
- O2S(Tcl_GetObjResult(interp))));
- result = TCL_ERROR;
- goto checkForCatch;
- }
+ TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
+ result = TCL_ERROR;
+ goto checkForCatch;
}
}
@@ -2685,7 +2786,7 @@ TclExecuteByteCode(
Tcl_WideInt w;
#endif
long i;
- char *part1, *part2;
+ Tcl_Obj *part1Ptr, *part2Ptr;
Var *varPtr, *arrayPtr;
case INST_INCR_SCALAR1:
@@ -2718,21 +2819,21 @@ TclExecuteByteCode(
doIncrStk:
if ((*pc == INST_INCR_ARRAY_STK_IMM)
|| (*pc == INST_INCR_ARRAY_STK)) {
- part2 = TclGetString(OBJ_AT_TOS);
+ part2Ptr = OBJ_AT_TOS;
objPtr = OBJ_UNDER_TOS;
TRACE(("\"%.30s(%.30s)\" (by %ld) => ",
- O2S(objPtr), part2, i));
+ O2S(objPtr), O2S(part2Ptr), i));
} else {
- part2 = NULL;
+ part2Ptr = NULL;
objPtr = OBJ_AT_TOS;
TRACE(("\"%.30s\" (by %ld) => ", O2S(objPtr), i));
}
- part1 = TclGetString(objPtr);
-
- varPtr = TclObjLookupVar(interp, objPtr, part2, TCL_LEAVE_ERR_MSG,
+ part1Ptr = objPtr;
+ opnd = -1;
+ varPtr = TclObjLookupVarEx(interp, objPtr, part2Ptr, TCL_LEAVE_ERR_MSG,
"read", 1, 1, &arrayPtr);
if (varPtr) {
- cleanup = ((part2 == NULL)? 1 : 2);
+ cleanup = ((part2Ptr == NULL)? 1 : 2);
goto doIncrVar;
} else {
Tcl_AddObjErrorInfo(interp,
@@ -2751,16 +2852,16 @@ TclExecuteByteCode(
pcAdjustment = 3;
doIncrArray:
- part2 = TclGetString(OBJ_AT_TOS);
+ part1Ptr = NULL;
+ part2Ptr = OBJ_AT_TOS;
arrayPtr = &(compiledLocals[opnd]);
- part1 = arrayPtr->name;
cleanup = 1;
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
- TRACE(("%u \"%.30s\" (by %ld) => ", opnd, part2, i));
- varPtr = TclLookupArrayElement(interp, part1, part2,
- TCL_LEAVE_ERR_MSG, "read", 1, 1, arrayPtr);
+ TRACE(("%u \"%.30s\" (by %ld) => ", opnd, O2S(part2Ptr), i));
+ varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
+ TCL_LEAVE_ERR_MSG, "read", 1, 1, arrayPtr, opnd);
if (varPtr) {
goto doIncrVar;
} else {
@@ -2780,7 +2881,7 @@ TclExecuteByteCode(
varPtr = varPtr->value.linkPtr;
}
- if (TclIsVarDirectReadable(varPtr)) {
+ if (TclIsVarDirectModifyable(varPtr)) {
ClientData ptr;
int type;
@@ -2791,13 +2892,12 @@ TclExecuteByteCode(
long sum = augend + i;
/*
- * Test for overflow.
- * TODO: faster checking with known limits on i?
+ * Overflow when (augend and sum have different sign) and
+ * (augend and i have the same sign). This is encapsulated
+ * in the Overflowing macro.
*/
- if ((augend >= 0 || i >= 0 || sum < 0)
- && (sum >= 0 || i < 0 || augend < 0)) {
-
+ if (!Overflowing(augend, i, sum)) {
TRACE(("%u %ld => ", opnd, i));
if (Tcl_IsShared(objPtr)) {
objPtr->refCount--; /* We know it's shared. */
@@ -2845,8 +2945,7 @@ TclExecuteByteCode(
* Check for overflow.
*/
- if ((w >= 0 || i >= 0 || sum < 0)
- && (w < 0 || i < 0 || sum >= 0)) {
+ if (!Overflowing(w, i, sum)) {
TRACE(("%u %ld => ", opnd, i));
if (Tcl_IsShared(objPtr)) {
objPtr->refCount--; /* We know it's shared. */
@@ -2898,18 +2997,16 @@ TclExecuteByteCode(
doIncrScalar:
varPtr = &(compiledLocals[opnd]);
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
arrayPtr = NULL;
- part2 = NULL;
+ part1Ptr = part2Ptr = NULL;
cleanup = 0;
TRACE(("%u %ld => ", opnd, i));
doIncrVar:
- if (TclIsVarDirectReadable(varPtr)
- && ((arrayPtr == NULL) || TclIsVarUntraced(arrayPtr))) {
+ if (TclIsVarDirectModifyable2(varPtr, arrayPtr)) {
objPtr = varPtr->value.objPtr;
if (Tcl_IsShared(objPtr)) {
objPtr->refCount--; /* We know it's shared */
@@ -2931,7 +3028,7 @@ TclExecuteByteCode(
} else {
DECACHE_STACK_INFO();
objResultPtr = TclPtrIncrObjVar(interp, varPtr, arrayPtr,
- part1, part2, incrPtr, TCL_LEAVE_ERR_MSG);
+ part1Ptr, part2Ptr, incrPtr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
Tcl_DecrRefCount(incrPtr);
if (objResultPtr == NULL) {
@@ -2968,12 +3065,12 @@ TclExecuteByteCode(
result = TclObjGetFrame(interp, OBJ_UNDER_TOS, &framePtr);
if (result != -1) {
/*
- * Locate the other variable
+ * Locate the other variable.
*/
savedFramePtr = iPtr->varFramePtr;
iPtr->varFramePtr = framePtr;
- otherPtr = TclObjLookupVar(interp, OBJ_AT_TOS, NULL,
+ otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
(TCL_LEAVE_ERR_MSG), "access",
/*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
iPtr->varFramePtr = savedFramePtr;
@@ -2988,18 +3085,15 @@ TclExecuteByteCode(
case INST_VARIABLE:
TRACE(("variable "));
- otherPtr = TclObjLookupVar(interp, OBJ_AT_TOS, NULL,
+ otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
(TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
/*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
if (otherPtr) {
/*
- * Do the [variable] magic
+ * Do the [variable] magic.
*/
- if (!TclIsVarNamespaceVar(otherPtr)) {
- TclSetVarNamespaceVar(otherPtr);
- otherPtr->refCount++;
- }
+ TclSetVarNamespaceVar(otherPtr);
result = TCL_OK;
goto doLinkVars;
}
@@ -3015,12 +3109,12 @@ TclExecuteByteCode(
result = TclGetNamespaceFromObj(interp, OBJ_UNDER_TOS, &nsPtr);
if ((result == TCL_OK) && nsPtr) {
/*
- * Locate the other variable
+ * Locate the other variable.
*/
savedNsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
iPtr->varFramePtr->nsPtr = (Namespace *) nsPtr;
- otherPtr = TclObjLookupVar(interp, OBJ_AT_TOS, NULL,
+ otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
(TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
/*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
iPtr->varFramePtr->nsPtr = (Namespace *) savedNsPtr;
@@ -3051,7 +3145,7 @@ TclExecuteByteCode(
opnd = TclGetInt4AtPtr(pc+1);;
varPtr = &(compiledLocals[opnd]);
- if ((varPtr != otherPtr) && (varPtr->tracePtr == NULL)
+ if ((varPtr != otherPtr) && !TclIsVarTraced(varPtr)
&& (TclIsVarUndefined(varPtr) || TclIsVarLink(varPtr))) {
if (!TclIsVarUndefined(varPtr)) {
/* Then it is a defined link */
@@ -3059,17 +3153,20 @@ TclExecuteByteCode(
if (linkPtr == otherPtr) {
goto doLinkVarsDone;
}
- linkPtr->refCount--;
- if (TclIsVarUndefined(linkPtr)) {
- TclCleanupVar(linkPtr, NULL);
+ if (TclIsVarInHash(linkPtr)) {
+ VarHashRefCount(linkPtr)--;
+ if (TclIsVarUndefined(linkPtr)) {
+ TclCleanupVar(linkPtr, NULL);
+ }
}
}
TclSetVarLink(varPtr);
- TclClearVarUndefined(varPtr);
varPtr->value.linkPtr = otherPtr;
- otherPtr->refCount++;
+ if (TclIsVarInHash(otherPtr)) {
+ VarHashRefCount(otherPtr)++;
+ }
} else {
- result = TclPtrMakeUpvar(interp, otherPtr, NULL, 0, opnd);
+ result = TclPtrObjMakeUpvar(interp, otherPtr, NULL, 0, opnd);
if (result != TCL_OK) {
goto checkForCatch;
}
@@ -3273,20 +3370,20 @@ TclExecuteByteCode(
Tcl_Obj *valuePtr, *value2Ptr;
/*
- * Pop the two operands
+ * Pop the two operands.
*/
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
/*
- * Extract the desired list element
+ * Extract the desired list element.
*/
objResultPtr = TclLindexList(interp, valuePtr, value2Ptr);
if (objResultPtr) {
/*
- * Stash the list element on the stack
+ * Stash the list element on the stack.
*/
TRACE(("%.20s %.20s => %s\n",
@@ -3308,7 +3405,7 @@ TclExecuteByteCode(
Tcl_Obj *valuePtr;
/*
- * Pop the list and get the index
+ * Pop the list and get the index.
*/
valuePtr = OBJ_AT_TOS;
@@ -3367,13 +3464,14 @@ TclExecuteByteCode(
numIdx, &OBJ_AT_DEPTH(numIdx - 1));
/*
- * Check for errors
+ * Check for errors.
*/
if (objResultPtr) {
/*
- * Set result
+ * Set result.
*/
+
TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
NEXT_INST_V(5, opnd, -1);
} else {
@@ -3411,19 +3509,19 @@ TclExecuteByteCode(
valuePtr = OBJ_AT_TOS;
/*
- * Compute the new variable value
+ * Compute the new variable value.
*/
objResultPtr = TclLsetFlat(interp, value2Ptr, numIdx,
&OBJ_AT_DEPTH(numIdx), valuePtr);
/*
- * Check for errors
+ * Check for errors.
*/
if (objResultPtr) {
/*
- * Set result
+ * Set result.
*/
TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
@@ -3453,25 +3551,25 @@ TclExecuteByteCode(
Tcl_DecrRefCount(objPtr); /* This one should be done here */
/*
- * Get the new element value, and the index list
+ * Get the new element value, and the index list.
*/
valuePtr = OBJ_AT_TOS;
value2Ptr = OBJ_UNDER_TOS;
/*
- * Compute the new variable value
+ * Compute the new variable value.
*/
objResultPtr = TclLsetList(interp, objPtr, value2Ptr, valuePtr);
/*
- * Check for errors
+ * Check for errors.
*/
if (objResultPtr) {
/*
- * Set result
+ * Set result.
*/
TRACE(("=> %s\n", O2S(objResultPtr)));
@@ -3491,7 +3589,7 @@ TclExecuteByteCode(
Tcl_Obj **listv, *valuePtr;
/*
- * Pop the list and get the indices
+ * Pop the list and get the indices.
*/
valuePtr = OBJ_AT_TOS;
@@ -3507,7 +3605,7 @@ TclExecuteByteCode(
/*
* Skip a lot of work if we're about to throw the result away (common
- * with uses of [lassign].)
+ * with uses of [lassign]).
*/
if (result == TCL_OK) {
@@ -3710,7 +3808,7 @@ TclExecuteByteCode(
case INST_STR_CMP: {
/*
- * String compare
+ * String compare.
*/
const char *s1, *s2;
@@ -3835,8 +3933,9 @@ TclExecuteByteCode(
case INST_STR_INDEX: {
/*
- * String compare
+ * String compare.
*/
+
int index, length;
char *bytes;
Tcl_Obj *valuePtr, *value2Ptr;
@@ -4297,7 +4396,7 @@ TclExecuteByteCode(
}
if ((l2 == 1) || (l2 == -1)) {
/*
- * Div. by |1| always yields remainder of 0
+ * Div. by |1| always yields remainder of 0.
*/
objResultPtr = constants[0];
@@ -4309,7 +4408,7 @@ TclExecuteByteCode(
l1 = *((const long *)ptr1);
if (l1 == 0) {
/*
- * 0 % (non-zero) always yields remainder of 0
+ * 0 % (non-zero) always yields remainder of 0.
*/
objResultPtr = constants[0];
@@ -4325,7 +4424,6 @@ TclExecuteByteCode(
/*
* Force Tcl's integer division rules.
- *
* TODO: examine for logic simplification
*/
@@ -4410,7 +4508,6 @@ TclExecuteByteCode(
/*
* Force Tcl's integer division rules.
- *
* TODO: examine for logic simplification
*/
@@ -4502,10 +4599,14 @@ TclExecuteByteCode(
invalid = (*((const Tcl_WideInt *)ptr2) < (Tcl_WideInt)0);
break;
#endif
- case TCL_NUMBER_BIG:
- /* TODO: const correctness? */
- invalid = (mp_cmp_d((mp_int *)ptr2, 0) == MP_LT);
+ case TCL_NUMBER_BIG: {
+ mp_int big2;
+
+ Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
+ invalid = (mp_cmp_d(&big2, 0) == MP_LT);
+ mp_clear(&big2);
break;
+ }
default:
/* Unused, here to silence compiler warning */
invalid = 0;
@@ -4588,7 +4689,7 @@ TclExecuteByteCode(
}
} else {
/*
- * Quickly force large right shifts to 0 or -1
+ * Quickly force large right shifts to 0 or -1.
*/
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
@@ -4613,10 +4714,13 @@ TclExecuteByteCode(
zero = (*(const Tcl_WideInt *)ptr1 > (Tcl_WideInt)0);
break;
#endif
- case TCL_NUMBER_BIG:
- /* TODO: const correctness ? */
- zero = (mp_cmp_d((mp_int *)ptr1, 0) == MP_GT);
+ case TCL_NUMBER_BIG: {
+ mp_int big1;
+ Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
+ zero = (mp_cmp_d(&big1, 0) == MP_GT);
+ mp_clear(&big1);
break;
+ }
default:
/* Unused, here to silence compiler warning. */
zero = 0;
@@ -5122,7 +5226,8 @@ TclExecuteByteCode(
/* TODO: Attempts to re-use unshared operands on stack */
if (*pc == INST_EXPON) {
- long l1, l2 = 0;
+ long l1 = 0, l2 = 0;
+ Tcl_WideInt w1;
int oddExponent = 0, negativeExponent = 0;
if (type2 == TCL_NUMBER_LONG) {
@@ -5134,8 +5239,14 @@ TclExecuteByteCode(
objResultPtr = constants[1];
NEXT_INST_F(1, 2, 1);
+ } else if (l2 == 1) {
+ /*
+ * Anything to the first power is itself
+ */
+ NEXT_INST_F(1, 1, 0);
}
}
+
switch (type2) {
case TCL_NUMBER_LONG: {
negativeExponent = (l2 < 0);
@@ -5233,7 +5344,282 @@ TclExecuteByteCode(
result = TCL_ERROR;
goto checkForCatch;
}
- /* TODO: Perform those computations that fit in native types */
+
+ if (type1 == TCL_NUMBER_LONG && type2 == TCL_NUMBER_LONG) {
+ if (l1 == 2) {
+ /*
+ * Reduce small powers of 2 to shifts.
+ */
+ if ((unsigned long) l2 < CHAR_BIT * sizeof(long) - 1) {
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ TclNewLongObj(objResultPtr, (1L << l2));
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+#if !defined(TCL_WIDE_INT_IS_LONG)
+ if ((unsigned long) l2 < CHAR_BIT * sizeof(Tcl_WideInt) - 1) {
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ objResultPtr
+ = Tcl_NewWideIntObj(((Tcl_WideInt) 1) << l2);
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+#endif
+ }
+ if (l1 == -2) {
+ int signum = oddExponent ? -1 : 1;
+ /*
+ * Reduce small powers of 2 to shifts.
+ */
+ if ((unsigned long) l2 < CHAR_BIT * sizeof(long) - 1) {
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ TclNewLongObj(objResultPtr, signum * (1L << l2));
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+#if !defined(TCL_WIDE_INT_IS_LONG)
+ if ((unsigned long) l2 < CHAR_BIT * sizeof(Tcl_WideInt) - 1) {
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ objResultPtr
+ = Tcl_NewWideIntObj(signum *
+ (((Tcl_WideInt) 1) << l2));
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+#endif
+ }
+#if (LONG_MAX == 0x7fffffff)
+ if (l2 <= 8 &&
+ l1 <= MaxBase32[l2-2] && l1 >= -MaxBase32[l2-2]) {
+ /*
+ * Small powers of 32-bit integers
+ */
+ long lResult = l1 * l1; /* b**2 */
+ switch (l2) {
+ case 2:
+ break;
+ case 3:
+ lResult *= l1; /* b**3 */
+ break;
+ case 4:
+ lResult *= lResult; /* b**4 */
+ break;
+ case 5:
+ lResult *= lResult; /* b**4 */
+ lResult *= l1; /* b**5 */
+ break;
+ case 6:
+ lResult *= l1; /* b**3 */
+ lResult *= lResult; /* b**6 */
+ break;
+ case 7:
+ lResult *= l1; /* b**3 */
+ lResult *= lResult; /* b**6 */
+ lResult *= l1; /* b**7 */
+ break;
+ case 8:
+ lResult *= lResult; /* b**4 */
+ lResult *= lResult; /* b**8 */
+ break;
+ }
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ if (Tcl_IsShared(valuePtr)) {
+ TclNewLongObj(objResultPtr, lResult);
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+ Tcl_SetLongObj(valuePtr, lResult);
+ TRACE(("%s\n", O2S(valuePtr)));
+ NEXT_INST_F(1, 1, 0);
+ }
+ if (l1 >= 3
+ && (unsigned long) l1 < (sizeof(Exp32Index)
+ / sizeof(unsigned short)) - 1) {
+ unsigned short base = Exp32Index[l1-3] + l2 - 9;
+ if (base < Exp32Index[l1-2]) {
+ /*
+ * 32-bit number raised to intermediate power,
+ * done by table lookup
+ */
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ if (Tcl_IsShared(valuePtr)) {
+ TclNewLongObj(objResultPtr, Exp32Value[base]);
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+ Tcl_SetLongObj(valuePtr, Exp32Value[base]);
+ TRACE(("%s\n", O2S(valuePtr)));
+ NEXT_INST_F(1, 1, 0);
+ }
+ }
+ if (-l1 >= 3
+ && (unsigned long)(-l1) < (sizeof(Exp32Index)
+ / sizeof(unsigned short)) - 1) {
+ unsigned short base = Exp32Index[-l1-3] + l2 - 9;
+ if (base < Exp32Index[-l1-2]) {
+ long lResult = (oddExponent) ?
+ -Exp32Value[base] : Exp32Value[base];
+ /*
+ * 32-bit number raised to intermediate power,
+ * done by table lookup
+ */
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ if (Tcl_IsShared(valuePtr)) {
+ TclNewLongObj(objResultPtr, lResult);
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+ Tcl_SetLongObj(valuePtr, lResult);
+ TRACE(("%s\n", O2S(valuePtr)));
+ NEXT_INST_F(1, 1, 0);
+ }
+ }
+#endif
+ }
+ if (type1 == TCL_NUMBER_LONG) {
+ w1 = l1;
+#ifndef NO_WIDE_TYPE
+ } else if (type1 == TCL_NUMBER_WIDE) {
+ w1 = *((const Tcl_WideInt*) ptr1);
+#endif
+ } else {
+ w1 = 0;
+ }
+#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
+ if (w1 != 0 && type2 == TCL_NUMBER_LONG
+ && l2 <= 16
+ && w1 <= MaxBaseWide[l2-2] && w1 >= -MaxBaseWide[l2-2]) {
+ /*
+ * Small powers of integers whose result is wide
+ */
+ Tcl_WideInt wResult = w1 * w1; /* b**2 */
+ switch (l2) {
+ case 2:
+ break;
+ case 3:
+ wResult *= l1; /* b**3 */
+ break;
+ case 4:
+ wResult *= wResult; /* b**4 */
+ break;
+ case 5:
+ wResult *= wResult; /* b**4 */
+ wResult *= w1; /* b**5 */
+ break;
+ case 6:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ break;
+ case 7:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= w1; /* b**7 */
+ break;
+ case 8:
+ wResult *= wResult; /* b**4 */
+ wResult *= wResult; /* b**8 */
+ break;
+ case 9:
+ wResult *= wResult; /* b**4 */
+ wResult *= wResult; /* b**8 */
+ wResult *= w1; /* b**9 */
+ break;
+ case 10:
+ wResult *= wResult; /* b**4 */
+ wResult *= w1; /* b**5 */
+ wResult *= wResult; /* b**10 */
+ break;
+ case 11:
+ wResult *= wResult; /* b**4 */
+ wResult *= w1; /* b**5 */
+ wResult *= wResult; /* b**10 */
+ wResult *= w1; /* b**11 */
+ break;
+ case 12:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= wResult; /* b**12 */
+ break;
+ case 13:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= wResult; /* b**12 */
+ wResult *= w1; /* b**13 */
+ break;
+ case 14:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= w1; /* b**7 */
+ wResult *= wResult; /* b**14 */
+ break;
+ case 15:
+ wResult *= w1; /* b**3 */
+ wResult *= wResult; /* b**6 */
+ wResult *= w1; /* b**7 */
+ wResult *= wResult; /* b**14 */
+ wResult *= w1; /* b**15 */
+ break;
+ case 16:
+ wResult *= wResult; /* b**4 */
+ wResult *= wResult; /* b**8 */
+ wResult *= wResult; /* b**16 */
+ break;
+
+ }
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ objResultPtr = Tcl_NewWideIntObj(wResult);
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+
+ /*
+ * Handle cases of powers > 16 that still fit in a 64-bit
+ * word by doing table lookup
+ */
+ if (w1 >= 3
+ && (Tcl_WideUInt) w1 < (sizeof(Exp64Index)
+ / sizeof(unsigned short)) - 1) {
+ unsigned short base = Exp64Index[w1-3] + l2 - 17;
+ if (base < Exp64Index[w1-2]) {
+ /*
+ * 64-bit number raised to intermediate power,
+ * done by table lookup
+ */
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ if (Tcl_IsShared(valuePtr)) {
+ objResultPtr = Tcl_NewWideIntObj(Exp64Value[base]);
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+ Tcl_SetWideIntObj(valuePtr, Exp64Value[base]);
+ TRACE(("%s\n", O2S(valuePtr)));
+ NEXT_INST_F(1, 1, 0);
+ }
+ }
+ if (-w1 >= 3
+ && (Tcl_WideUInt) (-w1) < (sizeof(Exp64Index)
+ / sizeof(unsigned short)) - 1) {
+ unsigned short base = Exp64Index[-w1-3] + l2 - 17;
+ if (base < Exp64Index[-w1-2]) {
+ Tcl_WideInt wResult = (oddExponent) ?
+ -Exp64Value[base] : Exp64Value[base];
+ /*
+ * 64-bit number raised to intermediate power,
+ * done by table lookup
+ */
+ TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
+ if (Tcl_IsShared(valuePtr)) {
+ objResultPtr = Tcl_NewWideIntObj(wResult);
+ TRACE(("%s\n", O2S(objResultPtr)));
+ NEXT_INST_F(1, 2, 1);
+ }
+ Tcl_SetWideIntObj(valuePtr, wResult);
+ TRACE(("%s\n", O2S(valuePtr)));
+ NEXT_INST_F(1, 1, 0);
+ }
+ }
+#endif
+
goto overflow;
}
@@ -5254,8 +5640,7 @@ TclExecuteByteCode(
* Check for overflow.
*/
- if (((w1 < 0) && (w2 < 0) && (wResult >= 0))
- || ((w1 > 0) && (w2 > 0) && (wResult < 0))) {
+ if (Overflowing(w1, w2, wResult)) {
goto overflow;
}
}
@@ -5268,11 +5653,17 @@ TclExecuteByteCode(
#endif
{
/*
- * Must check for overflow.
+ * Must check for overflow. The macro tests for overflows
+ * in sums by looking at the sign bits. As we have a
+ * subtraction here, we are adding -w2. As -w2 could in turn
+ * overflow, we test with ~w2 instead: it has the opposite
+ * sign bit to w2 so it does the job. Note that the only
+ * "bad" case (w2==0) is irrelevant for this macro, as in
+ * that case w1 and wResult have the same sign and there
+ * is no overflow anyway.
*/
- if (((w1 < 0) && (w2 > 0) && (wResult > 0))
- || ((w1 >= 0) && (w2 < 0) && (wResult < 0))) {
+ if (Overflowing(w1, ~w2, wResult)) {
goto overflow;
}
}
@@ -5681,8 +6072,6 @@ TclExecuteByteCode(
} else {
TclSetLongObj(oldValuePtr, -1);
}
- TclSetVarScalar(iterVarPtr);
- TclClearVarUndefined(iterVarPtr);
TRACE(("%u => loop iter count temp %d\n", opnd, iterTmpIndex));
#ifndef TCL_COMPILE_DEBUG
@@ -5712,7 +6101,6 @@ TclExecuteByteCode(
int iterNum, listTmpIndex, listLen, numVars;
int varIndex, valIndex, continueLoop, j;
long i;
- char *part1;
opnd = TclGetUInt4AtPtr(pc+1);
infoPtr = (ForeachInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
@@ -5782,7 +6170,6 @@ TclExecuteByteCode(
varIndex = varListPtr->varIndexes[j];
varPtr = &(compiledLocals[varIndex]);
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
@@ -5791,17 +6178,14 @@ TclExecuteByteCode(
if (valuePtr != value2Ptr) {
if (value2Ptr != NULL) {
TclDecrRefCount(value2Ptr);
- } else {
- TclSetVarScalar(varPtr);
- TclClearVarUndefined(varPtr);
}
varPtr->value.objPtr = valuePtr;
Tcl_IncrRefCount(valuePtr);
}
} else {
DECACHE_STACK_INFO();
- value2Ptr = TclPtrSetVar(interp, varPtr, NULL, part1,
- NULL, valuePtr, TCL_LEAVE_ERR_MSG);
+ value2Ptr = TclPtrSetVar(interp, varPtr, NULL, NULL,
+ NULL, valuePtr, TCL_LEAVE_ERR_MSG, varIndex);
CACHE_STACK_INFO();
if (value2Ptr == NULL) {
TRACE_WITH_OBJ((
@@ -5887,7 +6271,6 @@ TclExecuteByteCode(
int opnd, opnd2, allocateDict;
Tcl_Obj *dictPtr, *valPtr;
Var *varPtr;
- char *part1;
case INST_DICT_GET:
opnd = TclGetUInt4AtPtr(pc+1);
@@ -5932,7 +6315,6 @@ TclExecuteByteCode(
opnd2 = TclGetUInt4AtPtr(pc+5);
varPtr = &(compiledLocals[opnd2]);
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
@@ -5941,7 +6323,7 @@ TclExecuteByteCode(
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
- dictPtr = TclPtrGetVar(interp, varPtr, NULL, part1, NULL, 0);
+ dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd2);
CACHE_STACK_INFO();
}
if (dictPtr == NULL) {
@@ -6010,9 +6392,6 @@ TclExecuteByteCode(
Tcl_IncrRefCount(dictPtr);
if (oldValuePtr != NULL) {
Tcl_DecrRefCount(oldValuePtr);
- } else {
- TclSetVarScalar(varPtr);
- TclClearVarUndefined(varPtr);
}
varPtr->value.objPtr = dictPtr;
}
@@ -6020,8 +6399,8 @@ TclExecuteByteCode(
} else {
Tcl_IncrRefCount(dictPtr);
DECACHE_STACK_INFO();
- objResultPtr = TclPtrSetVar(interp, varPtr, NULL, part1, NULL,
- dictPtr, TCL_LEAVE_ERR_MSG);
+ objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
+ dictPtr, TCL_LEAVE_ERR_MSG, opnd2);
CACHE_STACK_INFO();
Tcl_DecrRefCount(dictPtr);
if (objResultPtr == NULL) {
@@ -6045,7 +6424,6 @@ TclExecuteByteCode(
cleanup = 2;
varPtr = &(compiledLocals[opnd]);
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
@@ -6054,7 +6432,7 @@ TclExecuteByteCode(
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
- dictPtr = TclPtrGetVar(interp, varPtr, NULL, part1, NULL, 0);
+ dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
CACHE_STACK_INFO();
}
if (dictPtr == NULL) {
@@ -6132,9 +6510,6 @@ TclExecuteByteCode(
Tcl_IncrRefCount(dictPtr);
if (oldValuePtr != NULL) {
Tcl_DecrRefCount(oldValuePtr);
- } else {
- TclSetVarScalar(varPtr);
- TclClearVarUndefined(varPtr);
}
varPtr->value.objPtr = dictPtr;
}
@@ -6142,8 +6517,8 @@ TclExecuteByteCode(
} else {
Tcl_IncrRefCount(dictPtr);
DECACHE_STACK_INFO();
- objResultPtr = TclPtrSetVar(interp, varPtr, NULL, part1, NULL,
- dictPtr, TCL_LEAVE_ERR_MSG);
+ objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
+ dictPtr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
Tcl_DecrRefCount(dictPtr);
if (objResultPtr == NULL) {
@@ -6184,14 +6559,13 @@ TclExecuteByteCode(
statePtr->typePtr = &dictIteratorType;
statePtr->internalRep.twoPtrValue.ptr1 = (void *) searchPtr;
statePtr->internalRep.twoPtrValue.ptr2 = (void *) dictPtr;
- varPtr = compiledLocals + opnd;
- if (varPtr->value.objPtr == NULL) {
- TclSetVarScalar(compiledLocals + opnd);
- TclClearVarUndefined(compiledLocals + opnd);
- } else if (varPtr->value.objPtr->typePtr == &dictIteratorType) {
- Tcl_Panic("mis-issued dictFirst!");
- } else {
- Tcl_DecrRefCount(varPtr->value.objPtr);
+ varPtr = (compiledLocals + opnd);
+ if (varPtr->value.objPtr) {
+ if (varPtr->value.objPtr->typePtr != &dictIteratorType) {
+ Tcl_DecrRefCount(varPtr->value.objPtr);
+ } else {
+ Tcl_Panic("mis-issued dictFirst!");
+ }
}
varPtr->value.objPtr = statePtr;
Tcl_IncrRefCount(statePtr);
@@ -6261,14 +6635,12 @@ TclExecuteByteCode(
Tcl_Obj **keyPtrPtr, *dictPtr;
DictUpdateInfo *duiPtr;
Var *varPtr;
- char *part1;
case INST_DICT_UPDATE_START:
opnd = TclGetUInt4AtPtr(pc+1);
opnd2 = TclGetUInt4AtPtr(pc+5);
varPtr = &(compiledLocals[opnd]);
duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
@@ -6277,8 +6649,8 @@ TclExecuteByteCode(
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
- dictPtr = TclPtrGetVar(interp, varPtr, NULL, part1, NULL,
- TCL_LEAVE_ERR_MSG);
+ dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL,
+ TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (dictPtr == NULL) {
goto dictUpdateStartFailed;
@@ -6299,15 +6671,17 @@ TclExecuteByteCode(
goto dictUpdateStartFailed;
}
varPtr = &(compiledLocals[duiPtr->varIndices[i]]);
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
DECACHE_STACK_INFO();
if (valPtr == NULL) {
- Tcl_UnsetVar(interp, part1, 0);
- } else if (TclPtrSetVar(interp, varPtr, NULL, part1, NULL,
- valPtr, TCL_LEAVE_ERR_MSG) == NULL) {
+ TclObjUnsetVar2(interp,
+ localName(iPtr->varFramePtr, duiPtr->varIndices[i]),
+ NULL, 0);
+ } else if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
+ valPtr, TCL_LEAVE_ERR_MSG,
+ duiPtr->varIndices[i]) == NULL) {
CACHE_STACK_INFO();
dictUpdateStartFailed:
cleanup = 1;
@@ -6323,7 +6697,6 @@ TclExecuteByteCode(
opnd2 = TclGetUInt4AtPtr(pc+5);
varPtr = &(compiledLocals[opnd]);
duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
- part1 = varPtr->name;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
@@ -6332,7 +6705,7 @@ TclExecuteByteCode(
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
- dictPtr = TclPtrGetVar(interp, varPtr, NULL, part1, NULL, 0);
+ dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
CACHE_STACK_INFO();
}
if (dictPtr == NULL) {
@@ -6352,10 +6725,8 @@ TclExecuteByteCode(
for (i=0 ; i<length ; i++) {
Tcl_Obj *valPtr;
Var *var2Ptr;
- char *part1a;
var2Ptr = &(compiledLocals[duiPtr->varIndices[i]]);
- part1a = var2Ptr->name;
while (TclIsVarLink(var2Ptr)) {
var2Ptr = var2Ptr->value.linkPtr;
}
@@ -6363,7 +6734,8 @@ TclExecuteByteCode(
valPtr = var2Ptr->value.objPtr;
} else {
DECACHE_STACK_INFO();
- valPtr = TclPtrGetVar(interp, var2Ptr, NULL, part1a, NULL, 0);
+ valPtr = TclPtrGetVar(interp, var2Ptr, NULL, NULL, NULL, 0,
+ duiPtr->varIndices[i]);
CACHE_STACK_INFO();
}
if (valPtr == NULL) {
@@ -6378,8 +6750,8 @@ TclExecuteByteCode(
varPtr->value.objPtr = dictPtr;
} else {
DECACHE_STACK_INFO();
- objResultPtr = TclPtrSetVar(interp, varPtr, NULL, part1, NULL,
- dictPtr, TCL_LEAVE_ERR_MSG);
+ objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
+ dictPtr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (objResultPtr == NULL) {
if (allocdict) {
@@ -6424,7 +6796,7 @@ TclExecuteByteCode(
goto checkForCatch;
/*
- * Block for variables needed to process exception returns
+ * Block for variables needed to process exception returns.
*/
{
@@ -6530,7 +6902,9 @@ TclExecuteByteCode(
if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
bytes = GetSrcInfoForPc(pc, codePtr, &length);
if (bytes != NULL) {
+ DECACHE_STACK_INFO();
Tcl_LogCommandInfo(interp, codePtr->source, bytes, length);
+ CACHE_STACK_INFO();
}
}
iPtr->flags &= ~ERR_ALREADY_LOGGED;
@@ -6858,7 +7232,7 @@ IllegalExprOperandType(
/*
*----------------------------------------------------------------------
*
- * TclGetSrcInfoForPc, GetSrcInfoForPc --
+ * TclGetSrcInfoForPc, GetSrcInfoForPc, TclGetSrcInfoForCmd --
*
* Given a program counter value, finds the closest command in the
* bytecode code unit's CmdLocation array and returns information about
@@ -6879,6 +7253,18 @@ 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);
+}
+
void
TclGetSrcInfoForPc(
CmdFrame *cfPtr)