tclExecute.c

Go to the documentation of this file.
00001 /*
00002  * tclExecute.c --
00003  *
00004  *      This file contains procedures that execute byte-compiled Tcl commands.
00005  *
00006  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
00007  * Copyright (c) 1998-2000 by Scriptics Corporation.
00008  * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
00009  * Copyright (c) 2002-2005 by Miguel Sofer.
00010  * Copyright (c) 2005-2007 by Donal K. Fellows.
00011  * Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net>
00012  *
00013  * See the file "license.terms" for information on usage and redistribution of
00014  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00015  *
00016  * RCS: @(#) $Id: tclExecute.c,v 1.363 2008/02/04 20:24:55 msofer Exp $
00017  */
00018 
00019 #include "tclInt.h"
00020 #include "tclCompile.h"
00021 #include "tommath.h"
00022 
00023 #include <math.h>
00024 #include <float.h>
00025 
00026 /*
00027  * Hack to determine whether we may expect IEEE floating point. The hack is
00028  * formally incorrect in that non-IEEE platforms might have the same precision
00029  * and range, but VAX, IBM, and Cray do not; are there any other floating
00030  * point units that we might care about?
00031  */
00032 
00033 #if (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_MAX_EXP == 1024)
00034 #define IEEE_FLOATING_POINT
00035 #endif
00036 
00037 /*
00038  * A mask (should be 2**n-1) that is used to work out when the bytecode engine
00039  * should call Tcl_AsyncReady() to see whether there is a signal that needs
00040  * handling.
00041  */
00042 
00043 #ifndef ASYNC_CHECK_COUNT_MASK
00044 #   define ASYNC_CHECK_COUNT_MASK       63
00045 #endif /* !ASYNC_CHECK_COUNT_MASK */
00046 
00047 /*
00048  * Boolean flag indicating whether the Tcl bytecode interpreter has been
00049  * initialized.
00050  */
00051 
00052 static int execInitialized = 0;
00053 TCL_DECLARE_MUTEX(execMutex)
00054 
00055 #ifdef TCL_COMPILE_DEBUG
00056 /*
00057  * Variable that controls whether execution tracing is enabled and, if so,
00058  * what level of tracing is desired:
00059  *    0: no execution tracing
00060  *    1: trace invocations of Tcl procs only
00061  *    2: trace invocations of all (not compiled away) commands
00062  *    3: display each instruction executed
00063  * This variable is linked to the Tcl variable "tcl_traceExec".
00064  */
00065 
00066 int tclTraceExec = 0;
00067 #endif
00068 
00069 /*
00070  * Mapping from expression instruction opcodes to strings; used for error
00071  * messages. Note that these entries must match the order and number of the
00072  * expression opcodes (e.g., INST_LOR) in tclCompile.h.
00073  *
00074  * Does not include the string for INST_EXPON (and beyond), as that is
00075  * disjoint for backward-compatability reasons.
00076  */
00077 
00078 static const char *operatorStrings[] = {
00079     "||", "&&", "|", "^", "&", "==", "!=", "<", ">", "<=", ">=", "<<", ">>",
00080     "+", "-", "*", "/", "%", "+", "-", "~", "!",
00081     "BUILTIN FUNCTION", "FUNCTION",
00082     "", "", "", "", "", "", "", "", "eq", "ne"
00083 };
00084 
00085 /*
00086  * Mapping from Tcl result codes to strings; used for error and debugging
00087  * messages.
00088  */
00089 
00090 #ifdef TCL_COMPILE_DEBUG
00091 static const char *resultStrings[] = {
00092     "TCL_OK", "TCL_ERROR", "TCL_RETURN", "TCL_BREAK", "TCL_CONTINUE"
00093 };
00094 #endif
00095 
00096 /*
00097  * These are used by evalstats to monitor object usage in Tcl.
00098  */
00099 
00100 #ifdef TCL_COMPILE_STATS
00101 long            tclObjsAlloced = 0;
00102 long            tclObjsFreed = 0;
00103 long            tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 };
00104 #endif /* TCL_COMPILE_STATS */
00105 
00106 /*
00107  * Support pre-8.5 bytecodes unless specifically requested otherwise.
00108  */
00109 
00110 #ifndef TCL_SUPPORT_84_BYTECODE
00111 #define TCL_SUPPORT_84_BYTECODE 1
00112 #endif
00113 
00114 #if TCL_SUPPORT_84_BYTECODE
00115 /*
00116  * We need to know the tclBuiltinFuncTable to support translation of pre-8.5
00117  * math functions to the namespace-based ::tcl::mathfunc::op in 8.5+.
00118  */
00119 
00120 typedef struct {
00121     char *name;         /* Name of function. */
00122     int numArgs;        /* Number of arguments for function. */
00123 } BuiltinFunc;
00124 
00125 /*
00126  * Table describing the built-in math functions. Entries in this table are
00127  * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's
00128  * operand byte.
00129  */
00130 
00131 static BuiltinFunc tclBuiltinFuncTable[] = {
00132     {"acos", 1},
00133     {"asin", 1},
00134     {"atan", 1},
00135     {"atan2", 2},
00136     {"ceil", 1},
00137     {"cos", 1},
00138     {"cosh", 1},
00139     {"exp", 1},
00140     {"floor", 1},
00141     {"fmod", 2},
00142     {"hypot", 2},
00143     {"log", 1},
00144     {"log10", 1},
00145     {"pow", 2},
00146     {"sin", 1},
00147     {"sinh", 1},
00148     {"sqrt", 1},
00149     {"tan", 1},
00150     {"tanh", 1},
00151     {"abs", 1},
00152     {"double", 1},
00153     {"int", 1},
00154     {"rand", 0},
00155     {"round", 1},
00156     {"srand", 1},
00157     {"wide", 1},
00158     {0},
00159 };
00160 
00161 #define LAST_BUILTIN_FUNC       25
00162 #endif
00163 
00164 /*
00165  * These variable-access macros have to coincide with those in tclVar.c
00166  */
00167 
00168 #define VarHashGetValue(hPtr) \
00169     ((Var *) ((char *)hPtr - TclOffset(VarInHash, entry)))
00170 
00171 static inline Var *
00172 VarHashCreateVar(
00173     TclVarHashTable *tablePtr,
00174     Tcl_Obj *key,
00175     int *newPtr)
00176 {
00177     Tcl_HashEntry *hPtr = Tcl_CreateHashEntry((Tcl_HashTable *) tablePtr,
00178             (char *) key, newPtr);
00179 
00180     if (!hPtr) {
00181         return NULL;
00182     }
00183     return VarHashGetValue(hPtr);
00184 }
00185 
00186 #define VarHashFindVar(tablePtr, key) \
00187     VarHashCreateVar((tablePtr), (key), NULL)
00188 
00189 /*
00190  * The new macro for ending an instruction; note that a reasonable C-optimiser
00191  * will resolve all branches at compile time. (result) is always a constant;
00192  * the macro NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is resolved
00193  * at runtime for variable (nCleanup).
00194  *
00195  * ARGUMENTS:
00196  *    pcAdjustment: how much to increment pc
00197  *    nCleanup: how many objects to remove from the stack
00198  *    resultHandling: 0 indicates no object should be pushed on the stack;
00199  *      otherwise, push objResultPtr. If (result < 0), objResultPtr already
00200  *      has the correct reference count.
00201  */
00202 
00203 #define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \
00204     if (nCleanup == 0) {\
00205         if (resultHandling != 0) {\
00206             if ((resultHandling) > 0) {\
00207                 PUSH_OBJECT(objResultPtr);\
00208             } else {\
00209                 *(++tosPtr) = objResultPtr;\
00210             }\
00211         } \
00212         pc += (pcAdjustment);\
00213         goto cleanup0;\
00214     } else if (resultHandling != 0) {\
00215         if ((resultHandling) > 0) {\
00216             Tcl_IncrRefCount(objResultPtr);\
00217         }\
00218         pc += (pcAdjustment);\
00219         switch (nCleanup) {\
00220             case 1: goto cleanup1_pushObjResultPtr;\
00221             case 2: goto cleanup2_pushObjResultPtr;\
00222             default: Tcl_Panic("bad usage of macro NEXT_INST_F");\
00223         }\
00224     } else {\
00225         pc += (pcAdjustment);\
00226         switch (nCleanup) {\
00227             case 1: goto cleanup1;\
00228             case 2: goto cleanup2;\
00229             default: Tcl_Panic("bad usage of macro NEXT_INST_F");\
00230         }\
00231     }
00232 
00233 #define NEXT_INST_V(pcAdjustment, nCleanup, resultHandling) \
00234     pc += (pcAdjustment);\
00235     cleanup = (nCleanup);\
00236     if (resultHandling) {\
00237         if ((resultHandling) > 0) {\
00238             Tcl_IncrRefCount(objResultPtr);\
00239         }\
00240         goto cleanupV_pushObjResultPtr;\
00241     } else {\
00242         goto cleanupV;\
00243     }
00244 
00245 /*
00246  * Macros used to cache often-referenced Tcl evaluation stack information
00247  * in local variables. Note that a DECACHE_STACK_INFO()-CACHE_STACK_INFO()
00248  * pair must surround any call inside TclExecuteByteCode (and a few other
00249  * procedures that use this scheme) that could result in a recursive call
00250  * to TclExecuteByteCode.
00251  */
00252 
00253 #define CACHE_STACK_INFO() \
00254     checkInterp = 1
00255 
00256 #define DECACHE_STACK_INFO() \
00257     esPtr->tosPtr = tosPtr
00258 
00259 /*
00260  * Macros used to access items on the Tcl evaluation stack. PUSH_OBJECT
00261  * increments the object's ref count since it makes the stack have another
00262  * reference pointing to the object. However, POP_OBJECT does not decrement
00263  * the ref count. This is because the stack may hold the only reference to the
00264  * object, so the object would be destroyed if its ref count were decremented
00265  * before the caller had a chance to, e.g., store it in a variable. It is the
00266  * caller's responsibility to decrement the ref count when it is finished with
00267  * an object.
00268  *
00269  * WARNING! It is essential that objPtr only appear once in the PUSH_OBJECT
00270  * macro. The actual parameter might be an expression with side effects, and
00271  * this ensures that it will be executed only once.
00272  */
00273 
00274 #define PUSH_OBJECT(objPtr) \
00275     Tcl_IncrRefCount(*(++tosPtr) = (objPtr))
00276 
00277 #define POP_OBJECT()    *(tosPtr--)
00278 
00279 #define OBJ_AT_TOS      *tosPtr
00280 
00281 #define OBJ_UNDER_TOS   *(tosPtr-1)
00282 
00283 #define OBJ_AT_DEPTH(n) *(tosPtr-(n))
00284 
00285 #define CURR_DEPTH      (tosPtr - initTosPtr)
00286 
00287 /*
00288  * Macros used to trace instruction execution. The macros TRACE,
00289  * TRACE_WITH_OBJ, and O2S are only used inside TclExecuteByteCode. O2S is
00290  * only used in TRACE* calls to get a string from an object.
00291  */
00292 
00293 #ifdef TCL_COMPILE_DEBUG
00294 #   define TRACE(a) \
00295     if (traceInstructions) { \
00296         fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, \
00297                 (int) CURR_DEPTH, \
00298                 (unsigned)(pc - codePtr->codeStart), \
00299                 GetOpcodeName(pc)); \
00300         printf a; \
00301     }
00302 #   define TRACE_APPEND(a) \
00303     if (traceInstructions) { \
00304         printf a; \
00305     }
00306 #   define TRACE_WITH_OBJ(a, objPtr) \
00307     if (traceInstructions) { \
00308         fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, \
00309                 (int) CURR_DEPTH, \
00310                 (unsigned)(pc - codePtr->codeStart), \
00311                 GetOpcodeName(pc)); \
00312         printf a; \
00313         TclPrintObject(stdout, objPtr, 30); \
00314         fprintf(stdout, "\n"); \
00315     }
00316 #   define O2S(objPtr) \
00317     (objPtr ? TclGetString(objPtr) : "")
00318 #else /* !TCL_COMPILE_DEBUG */
00319 #   define TRACE(a)
00320 #   define TRACE_APPEND(a)
00321 #   define TRACE_WITH_OBJ(a, objPtr)
00322 #   define O2S(objPtr)
00323 #endif /* TCL_COMPILE_DEBUG */
00324 
00325 /*
00326  * DTrace instruction probe macros.
00327  */
00328 
00329 #define TCL_DTRACE_INST_NEXT() \
00330     if (TCL_DTRACE_INST_DONE_ENABLED()) {\
00331         if (curInstName) {\
00332             TCL_DTRACE_INST_DONE(curInstName, (int) CURR_DEPTH, tosPtr);\
00333         }\
00334         curInstName = tclInstructionTable[*pc].name;\
00335         if (TCL_DTRACE_INST_START_ENABLED()) {\
00336             TCL_DTRACE_INST_START(curInstName, (int) CURR_DEPTH, tosPtr);\
00337         }\
00338     } else if (TCL_DTRACE_INST_START_ENABLED()) {\
00339         TCL_DTRACE_INST_START(tclInstructionTable[*pc].name, (int) CURR_DEPTH,\
00340                 tosPtr);\
00341     }
00342 #define TCL_DTRACE_INST_LAST() \
00343     if (TCL_DTRACE_INST_DONE_ENABLED() && curInstName) {\
00344         TCL_DTRACE_INST_DONE(curInstName, (int) CURR_DEPTH, tosPtr);\
00345     }
00346 
00347 /*
00348  * Macro used in this file to save a function call for common uses of
00349  * TclGetNumberFromObj(). The ANSI C "prototype" is:
00350  *
00351  * MODULE_SCOPE int GetNumberFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
00352  *                      ClientData *ptrPtr, int *tPtr);
00353  */
00354 
00355 #ifdef NO_WIDE_TYPE
00356 
00357 #define GetNumberFromObj(interp, objPtr, ptrPtr, tPtr)                  \
00358     (((objPtr)->typePtr == &tclIntType)                                 \
00359         ?       (*(tPtr) = TCL_NUMBER_LONG,                             \
00360                 *(ptrPtr) = (ClientData)                                \
00361                     (&((objPtr)->internalRep.longValue)), TCL_OK) :     \
00362     ((objPtr)->typePtr == &tclDoubleType)                               \
00363         ?       (((TclIsNaN((objPtr)->internalRep.doubleValue))         \
00364                     ?   (*(tPtr) = TCL_NUMBER_NAN)                      \
00365                     :   (*(tPtr) = TCL_NUMBER_DOUBLE)),                 \
00366                 *(ptrPtr) = (ClientData)                                \
00367                     (&((objPtr)->internalRep.doubleValue)), TCL_OK) :   \
00368     ((((objPtr)->typePtr == NULL) && ((objPtr)->bytes == NULL)) ||      \
00369     (((objPtr)->bytes != NULL) && ((objPtr)->length == 0)))             \
00370         ? TCL_ERROR :                                                   \
00371     TclGetNumberFromObj((interp), (objPtr), (ptrPtr), (tPtr)))
00372 
00373 #else
00374 
00375 #define GetNumberFromObj(interp, objPtr, ptrPtr, tPtr)                  \
00376     (((objPtr)->typePtr == &tclIntType)                                 \
00377         ?       (*(tPtr) = TCL_NUMBER_LONG,                             \
00378                 *(ptrPtr) = (ClientData)                                \
00379                     (&((objPtr)->internalRep.longValue)), TCL_OK) :     \
00380     ((objPtr)->typePtr == &tclWideIntType)                              \
00381         ?       (*(tPtr) = TCL_NUMBER_WIDE,                             \
00382                 *(ptrPtr) = (ClientData)                                \
00383                     (&((objPtr)->internalRep.wideValue)), TCL_OK) :     \
00384     ((objPtr)->typePtr == &tclDoubleType)                               \
00385         ?       (((TclIsNaN((objPtr)->internalRep.doubleValue))         \
00386                     ?   (*(tPtr) = TCL_NUMBER_NAN)                      \
00387                     :   (*(tPtr) = TCL_NUMBER_DOUBLE)),                 \
00388                 *(ptrPtr) = (ClientData)                                \
00389                     (&((objPtr)->internalRep.doubleValue)), TCL_OK) :   \
00390     ((((objPtr)->typePtr == NULL) && ((objPtr)->bytes == NULL)) ||      \
00391     (((objPtr)->bytes != NULL) && ((objPtr)->length == 0)))             \
00392         ? TCL_ERROR :                                                   \
00393     TclGetNumberFromObj((interp), (objPtr), (ptrPtr), (tPtr)))
00394 
00395 #endif
00396 
00397 /*
00398  * Macro used in this file to save a function call for common uses of
00399  * Tcl_GetBooleanFromObj(). The ANSI C "prototype" is:
00400  *
00401  * MODULE_SCOPE int TclGetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
00402  *                      int *boolPtr);
00403  */
00404 
00405 #define TclGetBooleanFromObj(interp, objPtr, boolPtr)                   \
00406     ((((objPtr)->typePtr == &tclIntType)                                \
00407         || ((objPtr)->typePtr == &tclBooleanType))                      \
00408         ? (*(boolPtr) = ((objPtr)->internalRep.longValue!=0), TCL_OK)   \
00409         : Tcl_GetBooleanFromObj((interp), (objPtr), (boolPtr)))
00410 
00411 /*
00412  * Macro used in this file to save a function call for common uses of
00413  * Tcl_GetWideIntFromObj(). The ANSI C "prototype" is:
00414  *
00415  * MODULE_SCOPE int TclGetWideIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
00416  *                      Tcl_WideInt *wideIntPtr);
00417  */
00418 
00419 #ifdef NO_WIDE_TYPE
00420 #define TclGetWideIntFromObj(interp, objPtr, wideIntPtr)                \
00421     (((objPtr)->typePtr == &tclIntType)                                 \
00422         ? (*(wideIntPtr) = (Tcl_WideInt)                                \
00423                 ((objPtr)->internalRep.longValue), TCL_OK) :            \
00424         Tcl_GetWideIntFromObj((interp), (objPtr), (wideIntPtr)))
00425 #else
00426 #define TclGetWideIntFromObj(interp, objPtr, wideIntPtr)                \
00427     (((objPtr)->typePtr == &tclWideIntType)                             \
00428         ? (*(wideIntPtr) = (objPtr)->internalRep.wideValue, TCL_OK) :   \
00429     ((objPtr)->typePtr == &tclIntType)                                  \
00430         ? (*(wideIntPtr) = (Tcl_WideInt)                                \
00431                 ((objPtr)->internalRep.longValue), TCL_OK) :            \
00432         Tcl_GetWideIntFromObj((interp), (objPtr), (wideIntPtr)))
00433 #endif
00434 
00435 /*
00436  * Macro used to make the check for type overflow more mnemonic. This works by
00437  * comparing sign bits; the rest of the word is irrelevant. The ANSI C
00438  * "prototype" (where inttype_t is any integer type) is:
00439  *
00440  * MODULE_SCOPE int Overflowing(inttype_t a, inttype_t b, inttype_t sum);
00441  *
00442  * Check first the condition most likely to fail in usual code (at least for
00443  * usage in [incr]: do the first summand and the sum have != signs?
00444  */
00445 
00446 #define Overflowing(a,b,sum) ((((a)^(sum)) < 0) && (((a)^(b)) >= 0))
00447 
00448 /*
00449  * Custom object type only used in this file; values of its type should never
00450  * be seen by user scripts.
00451  */
00452 
00453 static Tcl_ObjType dictIteratorType = {
00454     "dictIterator",
00455     NULL, NULL, NULL, NULL
00456 };
00457 
00458 /*
00459  * Auxiliary tables used to compute powers of small integers
00460  */
00461 
00462 #if (LONG_MAX == 0x7fffffff)
00463 
00464 /*
00465  * Maximum base that, when raised to powers 2, 3, ... 8, fits in a 32-bit
00466  * signed integer
00467  */
00468 
00469 static const long MaxBase32[7] = {46340, 1290, 215, 73, 35, 21, 14};
00470 
00471 /*
00472  * Table giving 3, 4, ..., 11, raised to the powers 9, 10, ..., as far as they
00473  * fit in a 32-bit signed integer. Exp32Index[i] gives the starting index of
00474  * powers of i+3; Exp32Value[i] gives the corresponding powers.
00475  */
00476 
00477 static const unsigned short Exp32Index[] = {
00478     0, 11, 18, 23, 26, 29, 31, 32, 33
00479 };
00480 static const long Exp32Value[] = {
00481     19683, 59049, 177147, 531441, 1594323, 4782969, 14348907, 43046721,
00482     129140163, 387420489, 1162261467, 262144, 1048576, 4194304,
00483     16777216, 67108864, 268435456, 1073741824, 1953125, 9765625,
00484     48828125, 244140625, 1220703125, 10077696, 60466176, 362797056,
00485     40353607, 282475249, 1977326743, 134217728, 1073741824, 387420489,
00486     1000000000
00487 };
00488 
00489 #endif /* LONG_MAX == 0x7fffffff -- 32 bit machine */
00490 
00491 #if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
00492 
00493 /*
00494  * Maximum base that, when raised to powers 2, 3, ..., 16, fits in a
00495  * Tcl_WideInt.
00496  */
00497 
00498 static Tcl_WideInt MaxBaseWide[15];
00499 
00500 /*
00501  *Table giving 3, 4, ..., 13 raised to powers greater than 16 when the
00502  * results fit in a 64-bit signed integer.
00503  */
00504 
00505 static const unsigned short Exp64Index[] = {
00506     0, 23, 38, 49, 57, 63, 67, 70, 72, 74, 75, 76
00507 };
00508 static const Tcl_WideInt Exp64Value[] = {
00509     (Tcl_WideInt)243*243*243*3*3,
00510     (Tcl_WideInt)243*243*243*3*3*3,
00511     (Tcl_WideInt)243*243*243*3*3*3*3,
00512     (Tcl_WideInt)243*243*243*243,
00513     (Tcl_WideInt)243*243*243*243*3,
00514     (Tcl_WideInt)243*243*243*243*3*3,
00515     (Tcl_WideInt)243*243*243*243*3*3*3,
00516     (Tcl_WideInt)243*243*243*243*3*3*3*3,
00517     (Tcl_WideInt)243*243*243*243*243,
00518     (Tcl_WideInt)243*243*243*243*243*3,
00519     (Tcl_WideInt)243*243*243*243*243*3*3,
00520     (Tcl_WideInt)243*243*243*243*243*3*3*3,
00521     (Tcl_WideInt)243*243*243*243*243*3*3*3*3,
00522     (Tcl_WideInt)243*243*243*243*243*243,
00523     (Tcl_WideInt)243*243*243*243*243*243*3,
00524     (Tcl_WideInt)243*243*243*243*243*243*3*3,
00525     (Tcl_WideInt)243*243*243*243*243*243*3*3*3,
00526     (Tcl_WideInt)243*243*243*243*243*243*3*3*3*3,
00527     (Tcl_WideInt)243*243*243*243*243*243*243,
00528     (Tcl_WideInt)243*243*243*243*243*243*243*3,
00529     (Tcl_WideInt)243*243*243*243*243*243*243*3*3,
00530     (Tcl_WideInt)243*243*243*243*243*243*243*3*3*3,
00531     (Tcl_WideInt)243*243*243*243*243*243*243*3*3*3*3,
00532     (Tcl_WideInt)1024*1024*1024*4*4,
00533     (Tcl_WideInt)1024*1024*1024*4*4*4,
00534     (Tcl_WideInt)1024*1024*1024*4*4*4*4,
00535     (Tcl_WideInt)1024*1024*1024*1024,
00536     (Tcl_WideInt)1024*1024*1024*1024*4,
00537     (Tcl_WideInt)1024*1024*1024*1024*4*4,
00538     (Tcl_WideInt)1024*1024*1024*1024*4*4*4,
00539     (Tcl_WideInt)1024*1024*1024*1024*4*4*4*4,
00540     (Tcl_WideInt)1024*1024*1024*1024*1024,
00541     (Tcl_WideInt)1024*1024*1024*1024*1024*4,
00542     (Tcl_WideInt)1024*1024*1024*1024*1024*4*4,
00543     (Tcl_WideInt)1024*1024*1024*1024*1024*4*4*4,
00544     (Tcl_WideInt)1024*1024*1024*1024*1024*4*4*4*4,
00545     (Tcl_WideInt)1024*1024*1024*1024*1024*1024,
00546     (Tcl_WideInt)1024*1024*1024*1024*1024*1024*4,
00547     (Tcl_WideInt)3125*3125*3125*5*5,
00548     (Tcl_WideInt)3125*3125*3125*5*5*5,
00549     (Tcl_WideInt)3125*3125*3125*5*5*5*5,
00550     (Tcl_WideInt)3125*3125*3125*3125,
00551     (Tcl_WideInt)3125*3125*3125*3125*5,
00552     (Tcl_WideInt)3125*3125*3125*3125*5*5,
00553     (Tcl_WideInt)3125*3125*3125*3125*5*5*5,
00554     (Tcl_WideInt)3125*3125*3125*3125*5*5*5*5,
00555     (Tcl_WideInt)3125*3125*3125*3125*3125,
00556     (Tcl_WideInt)3125*3125*3125*3125*3125*5,
00557     (Tcl_WideInt)3125*3125*3125*3125*3125*5*5,
00558     (Tcl_WideInt)7776*7776*7776*6*6,
00559     (Tcl_WideInt)7776*7776*7776*6*6*6,
00560     (Tcl_WideInt)7776*7776*7776*6*6*6*6,
00561     (Tcl_WideInt)7776*7776*7776*7776,
00562     (Tcl_WideInt)7776*7776*7776*7776*6,
00563     (Tcl_WideInt)7776*7776*7776*7776*6*6,
00564     (Tcl_WideInt)7776*7776*7776*7776*6*6*6,
00565     (Tcl_WideInt)7776*7776*7776*7776*6*6*6*6,
00566     (Tcl_WideInt)16807*16807*16807*7*7,
00567     (Tcl_WideInt)16807*16807*16807*7*7*7,
00568     (Tcl_WideInt)16807*16807*16807*7*7*7*7,
00569     (Tcl_WideInt)16807*16807*16807*16807,
00570     (Tcl_WideInt)16807*16807*16807*16807*7,
00571     (Tcl_WideInt)16807*16807*16807*16807*7*7,
00572     (Tcl_WideInt)32768*32768*32768*8*8,
00573     (Tcl_WideInt)32768*32768*32768*8*8*8,
00574     (Tcl_WideInt)32768*32768*32768*8*8*8*8,
00575     (Tcl_WideInt)32768*32768*32768*32768,
00576     (Tcl_WideInt)59049*59049*59049*9*9,
00577     (Tcl_WideInt)59049*59049*59049*9*9*9,
00578     (Tcl_WideInt)59049*59049*59049*9*9*9*9,
00579     (Tcl_WideInt)100000*100000*100000*10*10,
00580     (Tcl_WideInt)100000*100000*100000*10*10*10,
00581     (Tcl_WideInt)161051*161051*161051*11*11,
00582     (Tcl_WideInt)161051*161051*161051*11*11*11,
00583     (Tcl_WideInt)248832*248832*248832*12*12,
00584     (Tcl_WideInt)371293*371293*371293*13*13
00585 };
00586 
00587 #endif
00588 
00589 /*
00590  * Declarations for local procedures to this file:
00591  */
00592 
00593 #ifdef TCL_COMPILE_STATS
00594 static int              EvalStatsCmd(ClientData clientData,
00595                             Tcl_Interp *interp, int objc,
00596                             Tcl_Obj *const objv[]);
00597 #endif /* TCL_COMPILE_STATS */
00598 #ifdef TCL_COMPILE_DEBUG
00599 static char *           GetOpcodeName(unsigned char *pc);
00600 #endif /* TCL_COMPILE_DEBUG */
00601 static ExceptionRange * GetExceptRangeForPc(unsigned char *pc, int catchOnly,
00602                             ByteCode *codePtr);
00603 static const char *     GetSrcInfoForPc(unsigned char *pc, ByteCode *codePtr,
00604                             int *lengthPtr);
00605 static Tcl_Obj **       GrowEvaluationStack(ExecEnv *eePtr, int growth,
00606                             int move);
00607 static void             IllegalExprOperandType(Tcl_Interp *interp,
00608                             unsigned char *pc, Tcl_Obj *opndPtr);
00609 static void             InitByteCodeExecution(Tcl_Interp *interp);
00610 #ifdef TCL_COMPILE_DEBUG
00611 static void             PrintByteCodeInfo(ByteCode *codePtr);
00612 static const char *     StringForResultCode(int result);
00613 static void             ValidatePcAndStackTop(ByteCode *codePtr,
00614                             unsigned char *pc, int stackTop,
00615                             int stackLowerBound, int checkStack);
00616 #endif /* TCL_COMPILE_DEBUG */
00617 static void             DeleteExecStack(ExecStack *esPtr);
00618 /* Useful elsewhere, make available in tclInt.h or stubs? */
00619 static Tcl_Obj **       StackAllocWords(Tcl_Interp *interp, int numWords);
00620 static Tcl_Obj **       StackReallocWords(Tcl_Interp *interp, int numWords);
00621 
00622 /*
00623  *----------------------------------------------------------------------
00624  *
00625  * InitByteCodeExecution --
00626  *
00627  *      This procedure is called once to initialize the Tcl bytecode
00628  *      interpreter.
00629  *
00630  * Results:
00631  *      None.
00632  *
00633  * Side effects:
00634  *      This procedure initializes the array of instruction names. If
00635  *      compiling with the TCL_COMPILE_STATS flag, it initializes the array
00636  *      that counts the executions of each instruction and it creates the
00637  *      "evalstats" command. It also establishes the link between the Tcl
00638  *      "tcl_traceExec" and C "tclTraceExec" variables.
00639  *
00640  *----------------------------------------------------------------------
00641  */
00642 
00643 static void
00644 InitByteCodeExecution(
00645     Tcl_Interp *interp)         /* Interpreter for which the Tcl variable
00646                                  * "tcl_traceExec" is linked to control
00647                                  * instruction tracing. */
00648 {
00649 #if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
00650     int i, j;
00651     Tcl_WideInt w, x;
00652 #endif
00653 #ifdef TCL_COMPILE_DEBUG
00654     if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec,
00655             TCL_LINK_INT) != TCL_OK) {
00656         Tcl_Panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
00657     }
00658 #endif
00659 #ifdef TCL_COMPILE_STATS
00660     Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd, NULL, NULL);
00661 #endif /* TCL_COMPILE_STATS */
00662 #if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
00663 
00664     /*
00665      * Fill in a table of what base can be raised to powers 2, 3, ... 16
00666      * without overflowing a Tcl_WideInt
00667      */
00668 
00669     for (i = 2; i <= 16; ++i) {
00670         /*
00671          * Compute an initial guess in floating point.
00672          */
00673 
00674         w = (Tcl_WideInt) pow((double) LLONG_MAX, 1.0 / i) + 1;
00675 
00676         /*
00677          * Correct the guess if it's too high.
00678          */
00679 
00680         for (;;) {
00681             x = LLONG_MAX;
00682             for (j = 0; j < i; ++j) {
00683                 x /= w;
00684             }
00685             if (x == 1) {
00686                 break;
00687             }
00688             --w;
00689         }
00690 
00691         MaxBaseWide[i-2] = w;
00692     }
00693 #endif
00694 }
00695 
00696 /*
00697  *----------------------------------------------------------------------
00698  *
00699  * TclCreateExecEnv --
00700  *
00701  *      This procedure creates a new execution environment for Tcl bytecode
00702  *      execution. An ExecEnv points to a Tcl evaluation stack. An ExecEnv is
00703  *      typically created once for each Tcl interpreter (Interp structure) and
00704  *      recursively passed to TclExecuteByteCode to execute ByteCode sequences
00705  *      for nested commands.
00706  *
00707  * Results:
00708  *      A newly allocated ExecEnv is returned. This points to an empty
00709  *      evaluation stack of the standard initial size.
00710  *
00711  * Side effects:
00712  *      The bytecode interpreter is also initialized here, as this procedure
00713  *      will be called before any call to TclExecuteByteCode.
00714  *
00715  *----------------------------------------------------------------------
00716  */
00717 
00718 #define TCL_STACK_INITIAL_SIZE 2000
00719 
00720 ExecEnv *
00721 TclCreateExecEnv(
00722     Tcl_Interp *interp)         /* Interpreter for which the execution
00723                                  * environment is being created. */
00724 {
00725     ExecEnv *eePtr = (ExecEnv *) ckalloc(sizeof(ExecEnv));
00726     ExecStack *esPtr = (ExecStack *) ckalloc(sizeof(ExecStack)
00727             + (size_t) (TCL_STACK_INITIAL_SIZE-1) * sizeof(Tcl_Obj *));
00728 
00729     eePtr->execStackPtr = esPtr;
00730     TclNewBooleanObj(eePtr->constants[0], 0);
00731     Tcl_IncrRefCount(eePtr->constants[0]);
00732     TclNewBooleanObj(eePtr->constants[1], 1);
00733     Tcl_IncrRefCount(eePtr->constants[1]);
00734 
00735     esPtr->prevPtr = NULL;
00736     esPtr->nextPtr = NULL;
00737     esPtr->markerPtr = NULL;
00738     esPtr->endPtr = &esPtr->stackWords[TCL_STACK_INITIAL_SIZE-1];
00739     esPtr->tosPtr = &esPtr->stackWords[-1];
00740 
00741     Tcl_MutexLock(&execMutex);
00742     if (!execInitialized) {
00743         TclInitAuxDataTypeTable();
00744         InitByteCodeExecution(interp);
00745         execInitialized = 1;
00746     }
00747     Tcl_MutexUnlock(&execMutex);
00748 
00749     return eePtr;
00750 }
00751 #undef TCL_STACK_INITIAL_SIZE
00752 
00753 /*
00754  *----------------------------------------------------------------------
00755  *
00756  * TclDeleteExecEnv --
00757  *
00758  *      Frees the storage for an ExecEnv.
00759  *
00760  * Results:
00761  *      None.
00762  *
00763  * Side effects:
00764  *      Storage for an ExecEnv and its contained storage (e.g. the evaluation
00765  *      stack) is freed.
00766  *
00767  *----------------------------------------------------------------------
00768  */
00769 
00770 static void
00771 DeleteExecStack(
00772     ExecStack *esPtr)
00773 {
00774     if (esPtr->markerPtr) {
00775         Tcl_Panic("freeing an execStack which is still in use");
00776     }
00777 
00778     if (esPtr->prevPtr) {
00779         esPtr->prevPtr->nextPtr = esPtr->nextPtr;
00780     }
00781     if (esPtr->nextPtr) {
00782         esPtr->nextPtr->prevPtr = esPtr->prevPtr;
00783     }
00784     ckfree((char *) esPtr);
00785 }
00786 
00787 void
00788 TclDeleteExecEnv(
00789     ExecEnv *eePtr)             /* Execution environment to free. */
00790 {
00791     ExecStack *esPtr = eePtr->execStackPtr, *tmpPtr;
00792 
00793     /*
00794      * Delete all stacks in this exec env.
00795      */
00796 
00797     while (esPtr->nextPtr) {
00798         esPtr = esPtr->nextPtr;
00799     }
00800     while (esPtr) {
00801         tmpPtr = esPtr;
00802         esPtr = tmpPtr->prevPtr;
00803         DeleteExecStack(tmpPtr);
00804     }
00805 
00806     TclDecrRefCount(eePtr->constants[0]);
00807     TclDecrRefCount(eePtr->constants[1]);
00808     ckfree((char *) eePtr);
00809 }
00810 
00811 /*
00812  *----------------------------------------------------------------------
00813  *
00814  * TclFinalizeExecution --
00815  *
00816  *      Finalizes the execution environment setup so that it can be later
00817  *      reinitialized.
00818  *
00819  * Results:
00820  *      None.
00821  *
00822  * Side effects:
00823  *      After this call, the next time TclCreateExecEnv will be called it will
00824  *      call InitByteCodeExecution.
00825  *
00826  *----------------------------------------------------------------------
00827  */
00828 
00829 void
00830 TclFinalizeExecution(void)
00831 {
00832     Tcl_MutexLock(&execMutex);
00833     execInitialized = 0;
00834     Tcl_MutexUnlock(&execMutex);
00835     TclFinalizeAuxDataTypeTable();
00836 }
00837 
00838 /*
00839  * Auxiliary code to insure that GrowEvaluationStack always returns correctly 
00840  * aligned memory. This assumes that TCL_ALLOCALIGN is a multiple of the
00841  * wordsize 'sizeof(Tcl_Obj *)'. 
00842  */
00843 
00844 #define WALLOCALIGN \
00845     (TCL_ALLOCALIGN/sizeof(Tcl_Obj *))
00846 
00847 static inline int
00848 OFFSET(
00849     Tcl_Obj **markerPtr)
00850 {
00851     /*
00852      * Note that we are only interested in the low bits of the address, so
00853      * that the fact that PTR2INT may lose the high bits is irrelevant.
00854      */
00855 
00856     int mask, base, new;
00857 
00858     mask = WALLOCALIGN-1;
00859     base = (PTR2INT(markerPtr) & mask);
00860     new  = ((base + 1) + mask) & ~mask;
00861     return (new - base);
00862 }
00863 
00864 #define MEMSTART(markerPtr) \
00865     ((markerPtr) + OFFSET(markerPtr))
00866 
00867 
00868 /*
00869  *----------------------------------------------------------------------
00870  *
00871  * GrowEvaluationStack --
00872  *
00873  *      This procedure grows a Tcl evaluation stack stored in an ExecEnv,
00874  *      copying over the words since the last mark if so requested. A mark is
00875  *      set at the beginning of the new area when no copying is requested.
00876  *
00877  * Results:
00878  *      Returns a pointer to the first usable word in the (possibly) grown
00879  *      stack.
00880  *
00881  * Side effects:
00882  *      The size of the evaluation stack may be grown, a marker is set
00883  *
00884  *----------------------------------------------------------------------
00885  */
00886 
00887 static Tcl_Obj **
00888 GrowEvaluationStack(
00889     ExecEnv *eePtr,             /* Points to the ExecEnv with an evaluation
00890                                  * stack to enlarge. */
00891     int growth,                 /* How much larger than the current used
00892                                  * size. */
00893     int move)                   /* 1 if move words since last marker. */
00894 {
00895     ExecStack *esPtr = eePtr->execStackPtr, *oldPtr = NULL;
00896     int newBytes, newElems, currElems;
00897     int needed = growth - (esPtr->endPtr - esPtr->tosPtr);
00898     Tcl_Obj **markerPtr = esPtr->markerPtr, **memStart;
00899 
00900     if (move) {
00901         if (!markerPtr) {
00902             Tcl_Panic("STACK: Reallocating with no previous alloc");
00903         }
00904         if (needed <= 0) {
00905             return MEMSTART(markerPtr);
00906         }
00907     } else {
00908         Tcl_Obj **tmpMarkerPtr = esPtr->tosPtr + 1;
00909         int offset = OFFSET(tmpMarkerPtr);
00910 
00911         if (needed + offset < 0) {
00912             /*
00913              * Put a marker pointing to the previous marker in this stack, and 
00914              * store it in esPtr as the current marker. Return a pointer to
00915              * the start of aligned memory.
00916              */
00917 
00918             esPtr->markerPtr = tmpMarkerPtr;
00919             memStart = tmpMarkerPtr + offset; 
00920             esPtr->tosPtr = memStart - 1;
00921             *esPtr->markerPtr = (Tcl_Obj *) markerPtr;
00922             return memStart;
00923         }
00924     }
00925 
00926     /*
00927      * Reset move to hold the number of words to be moved to new stack (if
00928      * any) and growth to hold the complete stack requirements: add the marker
00929      * and maximal possible offset. 
00930      */
00931 
00932     if (move) {
00933         move = esPtr->tosPtr - MEMSTART(markerPtr) + 1;
00934     }
00935     needed = growth + move + WALLOCALIGN - 1;
00936 
00937     /*
00938      * Check if there is enough room in the next stack (if there is one, it
00939      * should be both empty and the last one!)
00940      */
00941 
00942     if (esPtr->nextPtr) {
00943         oldPtr = esPtr;
00944         esPtr = oldPtr->nextPtr;
00945         currElems = esPtr->endPtr - &esPtr->stackWords[-1];
00946         if (esPtr->markerPtr || (esPtr->tosPtr != &esPtr->stackWords[-1])) {
00947             Tcl_Panic("STACK: Stack after current is in use");
00948         }
00949         if (esPtr->nextPtr) {
00950             Tcl_Panic("STACK: Stack after current is not last");
00951         }
00952         if (needed <= currElems) {
00953             goto newStackReady;
00954         }
00955         DeleteExecStack(esPtr);
00956         esPtr = oldPtr;
00957     } else {
00958         currElems = esPtr->endPtr - &esPtr->stackWords[-1];
00959     }
00960 
00961     /*
00962      * We need to allocate a new stack! It needs to store 'growth' words,
00963      * including the elements to be copied over and the new marker.
00964      */
00965 
00966     newElems = 2*currElems;
00967     while (needed > newElems) {
00968         newElems *= 2;
00969     }
00970     newBytes = sizeof (ExecStack) + (newElems-1) * sizeof(Tcl_Obj *);
00971 
00972     oldPtr = esPtr;
00973     esPtr = (ExecStack *) ckalloc(newBytes);
00974 
00975     oldPtr->nextPtr = esPtr;
00976     esPtr->prevPtr = oldPtr;
00977     esPtr->nextPtr = NULL;
00978     esPtr->endPtr = &esPtr->stackWords[newElems-1];
00979 
00980   newStackReady:
00981     eePtr->execStackPtr = esPtr;
00982 
00983     /*
00984      * Store a NULL marker at the beginning of the stack, to indicate that
00985      * this is the first marker in this stack and that rewinding to here
00986      * should actually be a return to the previous stack.
00987      */
00988 
00989     esPtr->stackWords[0] = NULL;
00990     esPtr->markerPtr = &esPtr->stackWords[0];
00991     memStart = MEMSTART(esPtr->markerPtr);
00992     esPtr->tosPtr = memStart - 1;
00993     
00994     if (move) {
00995         memcpy(memStart, MEMSTART(markerPtr), move*sizeof(Tcl_Obj *));
00996         esPtr->tosPtr += move;
00997         oldPtr->markerPtr = (Tcl_Obj **) *markerPtr;
00998         oldPtr->tosPtr = markerPtr-1;
00999     }
01000 
01001     /*
01002      * Free the old stack if it is now unused.
01003      */
01004 
01005     if (!oldPtr->markerPtr) {
01006         DeleteExecStack(oldPtr);
01007     }
01008 
01009     return memStart;
01010 }
01011 
01012 /*
01013  *--------------------------------------------------------------
01014  *
01015  * TclStackAlloc, TclStackRealloc, TclStackFree --
01016  *
01017  *      Allocate memory from the execution stack; it has to be returned later
01018  *      with a call to TclStackFree.
01019  *
01020  * Results:
01021  *      A pointer to the first byte allocated, or panics if the allocation did
01022  *      not succeed.
01023  *
01024  * Side effects:
01025  *      The execution stack may be grown.
01026  *
01027  *--------------------------------------------------------------
01028  */
01029 
01030 static Tcl_Obj **
01031 StackAllocWords(
01032     Tcl_Interp *interp,
01033     int numWords)
01034 {
01035     /*
01036      * Note that GrowEvaluationStack sets a marker in the stack. This marker
01037      * is read when rewinding, e.g., by TclStackFree.
01038      */
01039 
01040     Interp *iPtr = (Interp *) interp;
01041     ExecEnv *eePtr = iPtr->execEnvPtr;
01042     Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 0);
01043 
01044     eePtr->execStackPtr->tosPtr += numWords;
01045     return resPtr;
01046 }
01047 
01048 static Tcl_Obj **
01049 StackReallocWords(
01050     Tcl_Interp *interp,
01051     int numWords)
01052 {
01053     Interp *iPtr = (Interp *) interp;
01054     ExecEnv *eePtr = iPtr->execEnvPtr;
01055     Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 1);
01056 
01057     eePtr->execStackPtr->tosPtr += numWords;
01058     return resPtr;
01059 }
01060 
01061 void
01062 TclStackFree(
01063     Tcl_Interp *interp,
01064     void *freePtr)
01065 {
01066     Interp *iPtr = (Interp *) interp;
01067     ExecEnv *eePtr;
01068     ExecStack *esPtr;
01069     Tcl_Obj **markerPtr;
01070 
01071     if (iPtr == NULL || iPtr->execEnvPtr == NULL) {
01072         Tcl_Free((char *) freePtr);
01073         return;
01074     }
01075 
01076     /*
01077      * Rewind the stack to the previous marker position. The current marker,
01078      * as set in the last call to GrowEvaluationStack, contains a pointer to
01079      * the previous marker.
01080      */
01081 
01082     eePtr = iPtr->execEnvPtr;
01083     esPtr = eePtr->execStackPtr;
01084     markerPtr = esPtr->markerPtr;
01085 
01086     if (MEMSTART(markerPtr) != (Tcl_Obj **)freePtr) {
01087         Tcl_Panic("TclStackFree: incorrect freePtr. Call out of sequence?");
01088     }
01089 
01090     esPtr->tosPtr = markerPtr-1;
01091     esPtr->markerPtr = (Tcl_Obj **) *markerPtr;
01092     if (*markerPtr) {
01093         return;
01094     }
01095 
01096     /*
01097      * Return to previous stack.
01098      */
01099 
01100     esPtr->tosPtr = &esPtr->stackWords[-1];
01101     if (esPtr->prevPtr) {
01102         eePtr->execStackPtr = esPtr->prevPtr;
01103     }
01104     if (esPtr->nextPtr) {
01105         if (!esPtr->prevPtr) {
01106             eePtr->execStackPtr = esPtr->nextPtr;
01107         }
01108         DeleteExecStack(esPtr);
01109     }
01110 }
01111 
01112 void *
01113 TclStackAlloc(
01114     Tcl_Interp *interp,
01115     int numBytes)
01116 {
01117     Interp *iPtr = (Interp *) interp;
01118     int numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
01119 
01120     if (iPtr == NULL || iPtr->execEnvPtr == NULL) {
01121         return (void *) Tcl_Alloc(numBytes);
01122     }
01123 
01124     return (void *) StackAllocWords(interp, numWords);
01125 }
01126 
01127 void *
01128 TclStackRealloc(
01129     Tcl_Interp *interp,
01130     void *ptr,
01131     int numBytes)
01132 {
01133     Interp *iPtr = (Interp *) interp;
01134     ExecEnv *eePtr;
01135     ExecStack *esPtr;
01136     Tcl_Obj **markerPtr;
01137     int numWords;
01138 
01139     if (iPtr == NULL || iPtr->execEnvPtr == NULL) {
01140         return (void *) Tcl_Realloc((char *) ptr, numBytes);
01141     }
01142 
01143     eePtr = iPtr->execEnvPtr;
01144     esPtr = eePtr->execStackPtr;
01145     markerPtr = esPtr->markerPtr;
01146 
01147     if (MEMSTART(markerPtr) != (Tcl_Obj **)ptr) {
01148         Tcl_Panic("TclStackRealloc: incorrect ptr. Call out of sequence?");
01149     }
01150 
01151     numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
01152     return (void *) StackReallocWords(interp, numWords);
01153 }
01154 
01155 /*
01156  *--------------------------------------------------------------
01157  *
01158  * Tcl_ExprObj --
01159  *
01160  *      Evaluate an expression in a Tcl_Obj.
01161  *
01162  * Results:
01163  *      A standard Tcl object result. If the result is other than TCL_OK, then
01164  *      the interpreter's result contains an error message. If the result is
01165  *      TCL_OK, then a pointer to the expression's result value object is
01166  *      stored in resultPtrPtr. In that case, the object's ref count is
01167  *      incremented to reflect the reference returned to the caller; the
01168  *      caller is then responsible for the resulting object and must, for
01169  *      example, decrement the ref count when it is finished with the object.
01170  *
01171  * Side effects:
01172  *      Any side effects caused by subcommands in the expression, if any. The
01173  *      interpreter result is not modified unless there is an error.
01174  *
01175  *--------------------------------------------------------------
01176  */
01177 
01178 int
01179 Tcl_ExprObj(
01180     Tcl_Interp *interp,         /* Context in which to evaluate the
01181                                  * expression. */
01182     register Tcl_Obj *objPtr,   /* Points to Tcl object containing expression
01183                                  * to evaluate. */
01184     Tcl_Obj **resultPtrPtr)     /* Where the Tcl_Obj* that is the expression
01185                                  * result is stored if no errors occur. */
01186 {
01187     Interp *iPtr = (Interp *) interp;
01188     CompileEnv compEnv;         /* Compilation environment structure allocated
01189                                  * in frame. */
01190     register ByteCode *codePtr = NULL;
01191                                 /* Tcl Internal type of bytecode. Initialized
01192                                  * to avoid compiler warning. */
01193     Tcl_Obj *saveObjPtr;
01194     int result;
01195 
01196     /*
01197      * Get the ByteCode from the object. If it exists, make sure it hasn't
01198      * been invalidated by, e.g., someone redefining a command with a compile
01199      * procedure (this might make the compiled code wrong). If necessary,
01200      * convert the object to be a ByteCode object and compile it. Also, if the
01201      * code was compiled in/for a different interpreter, we recompile it.
01202      *
01203      * Precompiled expressions, however, are immutable and therefore they are
01204      * not recompiled, even if the epoch has changed.
01205      */
01206 
01207     if (objPtr->typePtr == &tclByteCodeType) {
01208         codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
01209         if (((Interp *) *codePtr->interpHandle != iPtr)
01210                 || (codePtr->compileEpoch != iPtr->compileEpoch)) {
01211             if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
01212                 if ((Interp *) *codePtr->interpHandle != iPtr) {
01213                     Tcl_Panic("Tcl_ExprObj: compiled expression jumped interps");
01214                 }
01215                 codePtr->compileEpoch = iPtr->compileEpoch;
01216             } else {
01217                 objPtr->typePtr->freeIntRepProc(objPtr);
01218                 objPtr->typePtr = (Tcl_ObjType *) NULL;
01219             }
01220         }
01221     }
01222     if (objPtr->typePtr != &tclByteCodeType) {
01223         /*
01224          * TIP #280: No invoker (yet) - Expression compilation.
01225          */
01226 
01227         int length;
01228         const char *string = TclGetStringFromObj(objPtr, &length);
01229 
01230         TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0);
01231         TclCompileExpr(interp, string, length, &compEnv, 0);
01232 
01233         /*
01234          * Successful compilation. If the expression yielded no instructions,
01235          * push an zero object as the expression's result.
01236          */
01237 
01238         if (compEnv.codeNext == compEnv.codeStart) {
01239             TclEmitPush(TclRegisterNewLiteral(&compEnv, "0", 1),
01240                     &compEnv);
01241         }
01242 
01243         /*
01244          * Add a "done" instruction as the last instruction and change the
01245          * object into a ByteCode object. Ownership of the literal objects and
01246          * aux data items is given to the ByteCode object.
01247          */
01248 
01249         TclEmitOpcode(INST_DONE, &compEnv);
01250         TclInitByteCodeObj(objPtr, &compEnv);
01251         TclFreeCompileEnv(&compEnv);
01252         codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
01253 #ifdef TCL_COMPILE_DEBUG
01254         if (tclTraceCompile == 2) {
01255             TclPrintByteCodeObj(interp, objPtr);
01256             fflush(stdout);
01257         }
01258 #endif /* TCL_COMPILE_DEBUG */
01259     }
01260 
01261     /*
01262      * Execute the expression after first saving the interpreter's result.
01263      */
01264 
01265     saveObjPtr = Tcl_GetObjResult(interp);
01266     Tcl_IncrRefCount(saveObjPtr);
01267     Tcl_ResetResult(interp);
01268 
01269     /*
01270      * Increment the code's ref count while it is being executed. If
01271      * afterwards no references to it remain, free the code.
01272      */
01273 
01274     codePtr->refCount++;
01275     result = TclExecuteByteCode(interp, codePtr);
01276     codePtr->refCount--;
01277     if (codePtr->refCount <= 0) {
01278         TclCleanupByteCode(codePtr);
01279         objPtr->typePtr = NULL;
01280         objPtr->internalRep.otherValuePtr = NULL;
01281     }
01282 
01283     /*
01284      * If the expression evaluated successfully, store a pointer to its value
01285      * object in resultPtrPtr then restore the old interpreter result. We
01286      * increment the object's ref count to reflect the reference that we are
01287      * returning to the caller. We also decrement the ref count of the
01288      * interpreter's result object after calling Tcl_SetResult since we next
01289      * store into that field directly.
01290      */
01291 
01292     if (result == TCL_OK) {
01293         *resultPtrPtr = iPtr->objResultPtr;
01294         Tcl_IncrRefCount(iPtr->objResultPtr);
01295 
01296         Tcl_SetObjResult(interp, saveObjPtr);
01297     }
01298     TclDecrRefCount(saveObjPtr);
01299     return result;
01300 }
01301 
01302 /*
01303  *----------------------------------------------------------------------
01304  *
01305  * TclCompEvalObj --
01306  *
01307  *      This procedure evaluates the script contained in a Tcl_Obj by first
01308  *      compiling it and then passing it to TclExecuteByteCode.
01309  *
01310  * Results:
01311  *      The return value is one of the return codes defined in tcl.h (such as
01312  *      TCL_OK), and interp->objResultPtr refers to a Tcl object that either
01313  *      contains the result of executing the code or an error message.
01314  *
01315  * Side effects:
01316  *      Almost certainly, depending on the ByteCode's instructions.
01317  *
01318  *----------------------------------------------------------------------
01319  */
01320 
01321 int
01322 TclCompEvalObj(
01323     Tcl_Interp *interp,
01324     Tcl_Obj *objPtr,
01325     const CmdFrame *invoker,
01326     int word)
01327 {
01328     register Interp *iPtr = (Interp *) interp;
01329     register ByteCode *codePtr; /* Tcl Internal type of bytecode. */
01330     int result;
01331     Namespace *namespacePtr;
01332 
01333     /*
01334      * Check that the interpreter is ready to execute scripts. Note that we
01335      * manage the interp's runlevel here: it is a small white lie (maybe), but
01336      * saves a ++/-- pair at each invocation. Amazingly enough, the impact on
01337      * performance is noticeable.
01338      */
01339 
01340     iPtr->numLevels++;
01341     if (TclInterpReady(interp) == TCL_ERROR) {
01342         result = TCL_ERROR;
01343         goto done;
01344     }
01345 
01346     namespacePtr = iPtr->varFramePtr->nsPtr;
01347 
01348     /*
01349      * If the object is not already of tclByteCodeType, compile it (and reset
01350      * the compilation flags in the interpreter; this should be done after any
01351      * compilation). Otherwise, check that it is "fresh" enough.
01352      */
01353 
01354     if (objPtr->typePtr == &tclByteCodeType) {
01355         /*
01356          * Make sure the Bytecode hasn't been invalidated by, e.g., someone
01357          * redefining a command with a compile procedure (this might make the
01358          * compiled code wrong). The object needs to be recompiled if it was
01359          * compiled in/for a different interpreter, or for a different
01360          * namespace, or for the same namespace but with different name
01361          * resolution rules. Precompiled objects, however, are immutable and
01362          * therefore they are not recompiled, even if the epoch has changed.
01363          *
01364          * To be pedantically correct, we should also check that the
01365          * originating procPtr is the same as the current context procPtr
01366          * (assuming one exists at all - none for global level). This code is
01367          * #def'ed out because [info body] was changed to never return a
01368          * bytecode type object, which should obviate us from the extra checks
01369          * here.
01370          */
01371 
01372         codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
01373         if (((Interp *) *codePtr->interpHandle != iPtr)
01374                 || (codePtr->compileEpoch != iPtr->compileEpoch)
01375 #ifdef CHECK_PROC_ORIGINATION   /* [Bug: 3412 Pedantic] */
01376                 || codePtr->procPtr != iPtr->varFramePtr->procPtr
01377 #endif
01378                 || (codePtr->nsPtr != namespacePtr)
01379                 || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {
01380             if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
01381                 if ((Interp *) *codePtr->interpHandle != iPtr) {
01382                     Tcl_Panic("Tcl_EvalObj: compiled script jumped interps");
01383                 }
01384                 codePtr->compileEpoch = iPtr->compileEpoch;
01385             } else {
01386                 /*
01387                  * This byteCode is invalid: free it and recompile.
01388                  */
01389 
01390                 objPtr->typePtr->freeIntRepProc(objPtr);
01391                 goto recompileObj;
01392             }
01393         }
01394 
01395         /*
01396          * Increment the code's ref count while it is being executed. If
01397          * afterwards no references to it remain, free the code.
01398          */
01399 
01400     runCompiledObj:
01401         codePtr->refCount++;
01402         result = TclExecuteByteCode(interp, codePtr);
01403         codePtr->refCount--;
01404         if (codePtr->refCount <= 0) {
01405             TclCleanupByteCode(codePtr);
01406         }
01407         goto done;
01408     }
01409 
01410     recompileObj:
01411     iPtr->errorLine = 1;
01412 
01413     /*
01414      * TIP #280. Remember the invoker for a moment in the interpreter
01415      * structures so that the byte code compiler can pick it up when
01416      * initializing the compilation environment, i.e. the extended location
01417      * information.
01418      */
01419 
01420     iPtr->invokeCmdFramePtr = invoker;
01421     iPtr->invokeWord = word;
01422     tclByteCodeType.setFromAnyProc(interp, objPtr);
01423     iPtr->invokeCmdFramePtr = NULL;
01424     codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
01425     goto runCompiledObj;
01426 
01427     done:
01428     iPtr->numLevels--;
01429     return result;
01430 }
01431 
01432 /*
01433  *----------------------------------------------------------------------
01434  *
01435  * TclIncrObj --
01436  *
01437  *      Increment an integeral value in a Tcl_Obj by an integeral value held
01438  *      in another Tcl_Obj. Caller is responsible for making sure we can
01439  *      update the first object.
01440  *
01441  * Results:
01442  *      TCL_ERROR if either object is non-integer, and TCL_OK otherwise. On
01443  *      error, an error message is left in the interpreter (if it is not NULL,
01444  *      of course).
01445  *
01446  * Side effects:
01447  *      valuePtr gets the new incrmented value.
01448  *
01449  *----------------------------------------------------------------------
01450  */
01451 
01452 int
01453 TclIncrObj(
01454     Tcl_Interp *interp,
01455     Tcl_Obj *valuePtr,
01456     Tcl_Obj *incrPtr)
01457 {
01458     ClientData ptr1, ptr2;
01459     int type1, type2;
01460     mp_int value, incr;
01461 
01462     if (Tcl_IsShared(valuePtr)) {
01463         Tcl_Panic("%s called with shared object", "TclIncrObj");
01464     }
01465 
01466     if (GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK) {
01467         /*
01468          * Produce error message (reparse?!)
01469          */
01470 
01471         return TclGetIntFromObj(interp, valuePtr, &type1);
01472     }
01473     if (GetNumberFromObj(NULL, incrPtr, &ptr2, &type2) != TCL_OK) {
01474         /*
01475          * Produce error message (reparse?!)
01476          */
01477 
01478         TclGetIntFromObj(interp, incrPtr, &type1);
01479         Tcl_AddErrorInfo(interp, "\n    (reading increment)");
01480         return TCL_ERROR;
01481     }
01482 
01483     if ((type1 == TCL_NUMBER_LONG) && (type2 == TCL_NUMBER_LONG)) {
01484         long augend = *((const long *) ptr1);
01485         long addend = *((const long *) ptr2);
01486         long sum = augend + addend;
01487 
01488         /*
01489          * Overflow when (augend and sum have different sign) and (augend and
01490          * addend have the same sign). This is encapsulated in the Overflowing
01491          * macro.
01492          */
01493 
01494         if (!Overflowing(augend, addend, sum)) {
01495             TclSetLongObj(valuePtr, sum);
01496             return TCL_OK;
01497         }
01498 #ifndef NO_WIDE_TYPE
01499         {
01500             Tcl_WideInt w1 = (Tcl_WideInt) augend;
01501             Tcl_WideInt w2 = (Tcl_WideInt) addend;
01502 
01503             /*
01504              * We know the sum value is outside the long range, so we use the
01505              * macro form that doesn't range test again.
01506              */
01507 
01508             TclSetWideIntObj(valuePtr, w1 + w2);
01509             return TCL_OK;
01510         }
01511 #endif
01512     }
01513 
01514     if ((type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) {
01515         /*
01516          * Produce error message (reparse?!)
01517          */
01518 
01519         return TclGetIntFromObj(interp, valuePtr, &type1);
01520     }
01521     if ((type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) {
01522         /*
01523          * Produce error message (reparse?!)
01524          */
01525 
01526         TclGetIntFromObj(interp, incrPtr, &type1);
01527         Tcl_AddErrorInfo(interp, "\n    (reading increment)");
01528         return TCL_ERROR;
01529     }
01530 
01531 #ifndef NO_WIDE_TYPE
01532     if ((type1 != TCL_NUMBER_BIG) && (type2 != TCL_NUMBER_BIG)) {
01533         Tcl_WideInt w1, w2, sum;
01534 
01535         TclGetWideIntFromObj(NULL, valuePtr, &w1);
01536         TclGetWideIntFromObj(NULL, incrPtr, &w2);
01537         sum = w1 + w2;
01538 
01539         /*
01540          * Check for overflow.
01541          */
01542 
01543         if (!Overflowing(w1, w2, sum)) {
01544             Tcl_SetWideIntObj(valuePtr, sum);
01545             return TCL_OK;
01546         }
01547     }
01548 #endif
01549 
01550     Tcl_TakeBignumFromObj(interp, valuePtr, &value);
01551     Tcl_GetBignumFromObj(interp, incrPtr, &incr);
01552     mp_add(&value, &incr, &value);
01553     mp_clear(&incr);
01554     Tcl_SetBignumObj(valuePtr, &value);
01555     return TCL_OK;
01556 }
01557 
01558 /*
01559  *----------------------------------------------------------------------
01560  *
01561  * TclExecuteByteCode --
01562  *
01563  *      This procedure executes the instructions of a ByteCode structure. It
01564  *      returns when a "done" instruction is executed or an error occurs.
01565  *
01566  * Results:
01567  *      The return value is one of the return codes defined in tcl.h (such as
01568  *      TCL_OK), and interp->objResultPtr refers to a Tcl object that either
01569  *      contains the result of executing the code or an error message.
01570  *
01571  * Side effects:
01572  *      Almost certainly, depending on the ByteCode's instructions.
01573  *
01574  *----------------------------------------------------------------------
01575  */
01576 
01577 int
01578 TclExecuteByteCode(
01579     Tcl_Interp *interp,         /* Token for command interpreter. */
01580     ByteCode *codePtr)          /* The bytecode sequence to interpret. */
01581 {
01582     /*
01583      * Compiler cast directive - not a real variable.
01584      *     Interp *iPtr = (Interp *) interp;
01585      */
01586 #define iPtr ((Interp *) interp)
01587 
01588     /*
01589      * Check just the read-traced/write-traced bit of a variable.
01590      */
01591 
01592 #define ReadTraced(varPtr) ((varPtr)->flags & VAR_TRACED_READ)
01593 #define WriteTraced(varPtr) ((varPtr)->flags & VAR_TRACED_WRITE)
01594 
01595     /*
01596      * Constants: variables that do not change during the execution, used
01597      * sporadically.
01598      */
01599 
01600     ExecStack *esPtr;
01601     Tcl_Obj **initTosPtr;       /* Stack top at start of execution. */
01602     ptrdiff_t *initCatchTop;    /* Catch stack top at start of execution. */
01603     Var *compiledLocals;
01604     Namespace *namespacePtr;
01605     CmdFrame *bcFramePtr;       /* TIP #280: Structure for tracking lines. */
01606     Tcl_Obj **constants = &iPtr->execEnvPtr->constants[0];
01607 
01608     /*
01609      * Globals: variables that store state, must remain valid at all times.
01610      */
01611 
01612     ptrdiff_t *catchTop;
01613     register Tcl_Obj **tosPtr;  /* Cached pointer to top of evaluation
01614                                  * stack. */
01615     register unsigned char *pc = codePtr->codeStart;
01616                                 /* The current program counter. */
01617     int instructionCount = 0;   /* Counter that is used to work out when to
01618                                  * call Tcl_AsyncReady() */
01619     Tcl_Obj *expandNestList = NULL;
01620     int checkInterp = 0;        /* Indicates when a check of interp readyness
01621                                  * is necessary. Set by CACHE_STACK_INFO() */
01622 
01623     /*
01624      * Transfer variables - needed only between opcodes, but not while
01625      * executing an instruction.
01626      */
01627 
01628     register int cleanup;
01629     Tcl_Obj *objResultPtr;
01630 
01631     /*
01632      * Result variable - needed only when going to checkForcatch or other
01633      * error handlers; also used as local in some opcodes.
01634      */
01635 
01636     int result = TCL_OK;        /* Return code returned after execution. */
01637 
01638     /*
01639      * Locals - variables that are used within opcodes or bounded sections of
01640      * the file (jumps between opcodes within a family).
01641      * NOTE: These are now defined locally where needed.
01642      */
01643 
01644 #ifdef TCL_COMPILE_DEBUG
01645     int traceInstructions = (tclTraceExec == 3);
01646     char cmdNameBuf[21];
01647 #endif
01648     char *curInstName = NULL;
01649 
01650     /*
01651      * The execution uses a unified stack: first the catch stack, immediately
01652      * above it a CmdFrame, then the execution stack.
01653      *
01654      * Make sure the catch stack is large enough to hold the maximum number of
01655      * catch commands that could ever be executing at the same time (this will
01656      * be no more than the exception range array's depth). Make sure the
01657      * execution stack is large enough to execute this ByteCode.
01658      */
01659 
01660     catchTop = initCatchTop = (ptrdiff_t *) (
01661         GrowEvaluationStack(iPtr->execEnvPtr,
01662                 codePtr->maxExceptDepth + sizeof(CmdFrame) +
01663                     codePtr->maxStackDepth, 0) - 1);
01664     bcFramePtr = (CmdFrame *) (initCatchTop + codePtr->maxExceptDepth + 1);
01665     tosPtr = initTosPtr = ((Tcl_Obj **) (bcFramePtr + 1)) - 1;
01666     esPtr = iPtr->execEnvPtr->execStackPtr;
01667 
01668     /*
01669      * TIP #280: Initialize the frame. Do not push it yet.
01670      */
01671 
01672     bcFramePtr->type = ((codePtr->flags & TCL_BYTECODE_PRECOMPILED)
01673             ? TCL_LOCATION_PREBC : TCL_LOCATION_BC);
01674     bcFramePtr->level = (iPtr->cmdFramePtr ? iPtr->cmdFramePtr->level+1 : 1);
01675     bcFramePtr->framePtr = iPtr->framePtr;
01676     bcFramePtr->nextPtr = iPtr->cmdFramePtr;
01677     bcFramePtr->nline = 0;
01678     bcFramePtr->line = NULL;
01679 
01680     bcFramePtr->data.tebc.codePtr = codePtr;
01681     bcFramePtr->data.tebc.pc = NULL;
01682     bcFramePtr->cmd.str.cmd = NULL;
01683     bcFramePtr->cmd.str.len = 0;
01684 
01685 #ifdef TCL_COMPILE_DEBUG
01686     if (tclTraceExec >= 2) {
01687         PrintByteCodeInfo(codePtr);
01688         fprintf(stdout, "  Starting stack top=%d\n", CURR_DEPTH);
01689         fflush(stdout);
01690     }
01691 #endif
01692 
01693 #ifdef TCL_COMPILE_STATS
01694     iPtr->stats.numExecutions++;
01695 #endif
01696 
01697     namespacePtr = iPtr->varFramePtr->nsPtr;
01698     compiledLocals = iPtr->varFramePtr->compiledLocals;
01699 
01700     /*
01701      * Loop executing instructions until a "done" instruction, a TCL_RETURN,
01702      * or some error.
01703      */
01704 
01705     goto cleanup0;
01706 
01707     /*
01708      * Targets for standard instruction endings; unrolled for speed in the
01709      * most frequent cases (instructions that consume up to two stack
01710      * elements).
01711      *
01712      * This used to be a "for(;;)" loop, with each instruction doing its own
01713      * cleanup.
01714      */
01715 
01716     {
01717         Tcl_Obj *valuePtr;
01718 
01719     cleanupV_pushObjResultPtr:
01720         switch (cleanup) {
01721         case 0:
01722             *(++tosPtr) = (objResultPtr);
01723             goto cleanup0;
01724         default:
01725             cleanup -= 2;
01726             while (cleanup--) {
01727                 valuePtr = POP_OBJECT();
01728                 TclDecrRefCount(valuePtr);
01729             }
01730         case 2:
01731         cleanup2_pushObjResultPtr:
01732             valuePtr = POP_OBJECT();
01733             TclDecrRefCount(valuePtr);
01734         case 1:
01735         cleanup1_pushObjResultPtr:
01736             valuePtr = OBJ_AT_TOS;
01737             TclDecrRefCount(valuePtr);
01738         }
01739         OBJ_AT_TOS = objResultPtr;
01740         goto cleanup0;
01741 
01742     cleanupV:
01743         switch (cleanup) {
01744         default:
01745             cleanup -= 2;
01746             while (cleanup--) {
01747                 valuePtr = POP_OBJECT();
01748                 TclDecrRefCount(valuePtr);
01749             }
01750         case 2:
01751         cleanup2:
01752             valuePtr = POP_OBJECT();
01753             TclDecrRefCount(valuePtr);
01754         case 1:
01755         cleanup1:
01756             valuePtr = POP_OBJECT();
01757             TclDecrRefCount(valuePtr);
01758         case 0:
01759             /*
01760              * We really want to do nothing now, but this is needed for some
01761              * compilers (SunPro CC).
01762              */
01763 
01764             break;
01765         }
01766     }
01767  cleanup0:
01768 
01769 #ifdef TCL_COMPILE_DEBUG
01770     /*
01771      * Skip the stack depth check if an expansion is in progress.
01772      */
01773 
01774     ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, 0,
01775             /*checkStack*/ expandNestList == NULL);
01776     if (traceInstructions) {
01777         fprintf(stdout, "%2d: %2d ", iPtr->numLevels, (int) CURR_DEPTH);
01778         TclPrintInstruction(codePtr, pc);
01779         fflush(stdout);
01780     }
01781 #endif /* TCL_COMPILE_DEBUG */
01782 
01783 #ifdef TCL_COMPILE_STATS
01784     iPtr->stats.instructionCount[*pc]++;
01785 #endif
01786 
01787     /*
01788      * Check for asynchronous handlers [Bug 746722]; we do the check every
01789      * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-1).
01790      */
01791 
01792     if ((instructionCount++ & ASYNC_CHECK_COUNT_MASK) == 0) {
01793         /*
01794          * Check for asynchronous handlers [Bug 746722]; we do the check every
01795          * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-<1).
01796          */
01797 
01798         if (TclAsyncReady(iPtr)) {
01799             int localResult;
01800 
01801             DECACHE_STACK_INFO();
01802             localResult = Tcl_AsyncInvoke(interp, result);
01803             CACHE_STACK_INFO();
01804             if (localResult == TCL_ERROR) {
01805                 result = localResult;
01806                 goto checkForCatch;
01807             }
01808         }
01809         if (TclLimitReady(iPtr->limit)) {
01810             int localResult;
01811 
01812             DECACHE_STACK_INFO();
01813             localResult = Tcl_LimitCheck(interp);
01814             CACHE_STACK_INFO();
01815             if (localResult == TCL_ERROR) {
01816                 result = localResult;
01817                 goto checkForCatch;
01818             }
01819         }
01820     }
01821 
01822      TCL_DTRACE_INST_NEXT();
01823 
01824     /*
01825      * These two instructions account for 26% of all instructions (according
01826      * to measurements on tclbench by Ben Vitale
01827      * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf]
01828      * Resolving them before the switch reduces the cost of branch
01829      * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!)
01830      * reduces total obj size.
01831      */
01832 
01833     if (*pc == INST_LOAD_SCALAR1) {
01834         goto instLoadScalar1;
01835     } else if (*pc == INST_PUSH1) {
01836         goto instPush1Peephole;
01837     }
01838 
01839     switch (*pc) {
01840     case INST_SYNTAX:
01841     case INST_RETURN_IMM: {
01842         int code = TclGetInt4AtPtr(pc+1);
01843         int level = TclGetUInt4AtPtr(pc+5);
01844 
01845         /*
01846          * OBJ_AT_TOS is returnOpts, OBJ_UNDER_TOS is resultObjPtr.
01847          */
01848 
01849         TRACE(("%u %u => ", code, level));
01850         result = TclProcessReturn(interp, code, level, OBJ_AT_TOS);
01851         if (result == TCL_OK) {
01852             TRACE_APPEND(("continuing to next instruction (result=\"%.30s\")",
01853                     O2S(objResultPtr)));
01854             NEXT_INST_F(9, 1, 0);
01855         } else {
01856             Tcl_SetObjResult(interp, OBJ_UNDER_TOS);
01857             if (*pc == INST_SYNTAX) {
01858                 iPtr->flags &= ~ERR_ALREADY_LOGGED;
01859             }
01860             cleanup = 2;
01861             goto processExceptionReturn;
01862         }
01863     }
01864 
01865     case INST_RETURN_STK:
01866         TRACE(("=> "));
01867         objResultPtr = POP_OBJECT();
01868         result = Tcl_SetReturnOptions(interp, OBJ_AT_TOS);
01869         OBJ_AT_TOS = objResultPtr;
01870         if (result == TCL_OK) {
01871             TRACE_APPEND(("continuing to next instruction (result=\"%.30s\")",
01872                     O2S(objResultPtr)));
01873             NEXT_INST_F(1, 0, 0);
01874         } else {
01875             Tcl_SetObjResult(interp, objResultPtr);
01876             cleanup = 1;
01877             goto processExceptionReturn;
01878         }
01879 
01880     case INST_DONE:
01881         if (tosPtr > initTosPtr) {
01882             /*
01883              * Set the interpreter's object result to point to the topmost
01884              * object from the stack, and check for a possible [catch]. The
01885              * stackTop's level and refCount will be handled by "processCatch"
01886              * or "abnormalReturn".
01887              */
01888 
01889             Tcl_SetObjResult(interp, OBJ_AT_TOS);
01890 #ifdef TCL_COMPILE_DEBUG
01891             TRACE_WITH_OBJ(("=> return code=%d, result=", result),
01892                     iPtr->objResultPtr);
01893             if (traceInstructions) {
01894                 fprintf(stdout, "\n");
01895             }
01896 #endif
01897             goto checkForCatch;
01898         } else {
01899             (void) POP_OBJECT();
01900             goto abnormalReturn;
01901         }
01902 
01903     case INST_PUSH1:
01904     instPush1Peephole:
01905         PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]);
01906         TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS);
01907         pc += 2;
01908 #if !TCL_COMPILE_DEBUG
01909         /*
01910          * Runtime peephole optimisation: check if we are pushing again.
01911          */
01912 
01913         if (*pc == INST_PUSH1) {
01914             TCL_DTRACE_INST_NEXT();
01915             goto instPush1Peephole;
01916         }
01917 #endif
01918         NEXT_INST_F(0, 0, 0);
01919 
01920     case INST_PUSH4:
01921         objResultPtr = codePtr->objArrayPtr[TclGetUInt4AtPtr(pc+1)];
01922         TRACE_WITH_OBJ(("%u => ", TclGetUInt4AtPtr(pc+1)), objResultPtr);
01923         NEXT_INST_F(5, 0, 1);
01924 
01925     case INST_POP: {
01926         Tcl_Obj *valuePtr;
01927 
01928         TRACE_WITH_OBJ(("=> discarding "), OBJ_AT_TOS);
01929         valuePtr = POP_OBJECT();
01930         TclDecrRefCount(valuePtr);
01931 
01932         /*
01933          * Runtime peephole optimisation: an INST_POP is scheduled at the end
01934          * of most commands. If the next instruction is an INST_START_CMD,
01935          * fall through to it.
01936          */
01937 
01938         pc++;
01939 #if !TCL_COMPILE_DEBUG
01940         if (*pc == INST_START_CMD) {
01941             TCL_DTRACE_INST_NEXT();
01942             goto instStartCmdPeephole;
01943         }
01944 #endif
01945         NEXT_INST_F(0, 0, 0);
01946     }
01947 
01948     case INST_START_CMD:
01949 #if !TCL_COMPILE_DEBUG
01950     instStartCmdPeephole:
01951 #endif
01952         /*
01953          * Remark that if the interpreter is marked for deletion its
01954          * compileEpoch is modified, so that the epoch check also verifies
01955          * that the interp is not deleted. If no outside call has been made
01956          * since the last check, it is safe to omit the check.
01957          */
01958 
01959         iPtr->cmdCount += TclGetUInt4AtPtr(pc+5);
01960         if (!checkInterp) {
01961         instStartCmdOK:
01962             NEXT_INST_F(9, 0, 0);
01963         } else if (((codePtr->compileEpoch == iPtr->compileEpoch)
01964                 && (codePtr->nsEpoch == namespacePtr->resolverEpoch))
01965                 || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {
01966             checkInterp = 0;
01967             goto instStartCmdOK;
01968         } else {
01969             const char *bytes;
01970             int length, opnd;
01971             Tcl_Obj *newObjResultPtr;
01972 
01973             bytes = GetSrcInfoForPc(pc, codePtr, &length);
01974             DECACHE_STACK_INFO();
01975             result = Tcl_EvalEx(interp, bytes, length, 0);
01976             CACHE_STACK_INFO();
01977             if (result != TCL_OK) {
01978                 cleanup = 0;
01979                 goto processExceptionReturn;
01980             }
01981             opnd = TclGetUInt4AtPtr(pc+1);
01982             objResultPtr = Tcl_GetObjResult(interp);
01983             TclNewObj(newObjResultPtr);
01984             Tcl_IncrRefCount(newObjResultPtr);
01985             iPtr->objResultPtr = newObjResultPtr;
01986             NEXT_INST_V(opnd, 0, -1);
01987         }
01988 
01989     case INST_DUP:
01990         objResultPtr = OBJ_AT_TOS;
01991         TRACE_WITH_OBJ(("=> "), objResultPtr);
01992         NEXT_INST_F(1, 0, 1);
01993 
01994     case INST_OVER: {
01995         int opnd;
01996 
01997         opnd = TclGetUInt4AtPtr(pc+1);
01998         objResultPtr = OBJ_AT_DEPTH(opnd);
01999         TRACE_WITH_OBJ(("=> "), objResultPtr);
02000         NEXT_INST_F(5, 0, 1);
02001     }
02002 
02003     case INST_REVERSE: {
02004         int opnd;
02005         Tcl_Obj **a, **b;
02006 
02007         opnd = TclGetUInt4AtPtr(pc+1);
02008         a = tosPtr-(opnd-1);
02009         b = tosPtr;
02010         while (a<b) {
02011             Tcl_Obj *temp = *a;
02012             *a = *b;
02013             *b = temp;
02014             a++; b--;
02015         }
02016         NEXT_INST_F(5, 0, 0);
02017     }
02018 
02019     case INST_CONCAT1: {
02020         int opnd, length, appendLen = 0;
02021         char *bytes, *p;
02022         Tcl_Obj **currPtr;
02023 
02024         opnd = TclGetUInt1AtPtr(pc+1);
02025 
02026         /*
02027          * Compute the length to be appended.
02028          */
02029 
02030         for (currPtr=&OBJ_AT_DEPTH(opnd-2); currPtr<=&OBJ_AT_TOS; currPtr++) {
02031             bytes = TclGetStringFromObj(*currPtr, &length);
02032             if (bytes != NULL) {
02033                 appendLen += length;
02034             }
02035         }
02036 
02037         /*
02038          * If nothing is to be appended, just return the first object by
02039          * dropping all the others from the stack; this saves both the
02040          * computation and copy of the string rep of the first object,
02041          * enabling the fast '$x[set x {}]' idiom for 'K $x [set x {}]'.
02042          */
02043 
02044         if (appendLen == 0) {
02045             TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
02046             NEXT_INST_V(2, (opnd-1), 0);
02047         }
02048 
02049         /*
02050          * If the first object is shared, we need a new obj for the result;
02051          * otherwise, we can reuse the first object. In any case, make sure it
02052          * has enough room to accomodate all the concatenated bytes. Note that
02053          * if it is unshared its bytes are copied by ckrealloc, so that we set
02054          * the loop parameters to avoid copying them again: p points to the
02055          * end of the already copied bytes, currPtr to the second object.
02056          */
02057 
02058         objResultPtr = OBJ_AT_DEPTH(opnd-1);
02059         bytes = TclGetStringFromObj(objResultPtr, &length);
02060 #if !TCL_COMPILE_DEBUG
02061         if (bytes != tclEmptyStringRep && !Tcl_IsShared(objResultPtr)) {
02062             TclFreeIntRep(objResultPtr);
02063             objResultPtr->typePtr = NULL;
02064             objResultPtr->bytes = ckrealloc(bytes, (length + appendLen + 1));
02065             objResultPtr->length = length + appendLen;
02066             p = TclGetString(objResultPtr) + length;
02067             currPtr = &OBJ_AT_DEPTH(opnd - 2);
02068         } else {
02069 #endif
02070             p = (char *) ckalloc((unsigned) (length + appendLen + 1));
02071             TclNewObj(objResultPtr);
02072             objResultPtr->bytes = p;
02073             objResultPtr->length = length + appendLen;
02074             currPtr = &OBJ_AT_DEPTH(opnd - 1);
02075 #if !TCL_COMPILE_DEBUG
02076         }
02077 #endif
02078 
02079         /*
02080          * Append the remaining characters.
02081          */
02082 
02083         for (; currPtr <= &OBJ_AT_TOS; currPtr++) {
02084             bytes = TclGetStringFromObj(*currPtr, &length);
02085             if (bytes != NULL) {
02086                 memcpy(p, bytes, (size_t) length);
02087                 p += length;
02088             }
02089         }
02090         *p = '\0';
02091 
02092         TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
02093         NEXT_INST_V(2, opnd, 1);
02094     }
02095 
02096     case INST_EXPAND_START: {
02097         /*
02098          * Push an element to the expandNestList. This records the current
02099          * stack depth - i.e., the point in the stack where the expanded
02100          * command starts.
02101          *
02102          * Use a Tcl_Obj as linked list element; slight mem waste, but faster
02103          * allocation than ckalloc. This also abuses the Tcl_Obj structure, as
02104          * we do not define a special tclObjType for it. It is not dangerous
02105          * as the obj is never passed anywhere, so that all manipulations are
02106          * performed here and in INST_INVOKE_EXPANDED (in case of an expansion
02107          * error, also in INST_EXPAND_STKTOP).
02108          */
02109 
02110         Tcl_Obj *objPtr;
02111 
02112         TclNewObj(objPtr);
02113         objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) CURR_DEPTH;
02114         objPtr->internalRep.twoPtrValue.ptr2 = (VOID *) expandNestList;
02115         expandNestList = objPtr;
02116         NEXT_INST_F(1, 0, 0);
02117     }
02118 
02119     case INST_EXPAND_STKTOP: {
02120         int objc, length, i;
02121         Tcl_Obj **objv, *valuePtr;
02122         ptrdiff_t moved;
02123 
02124         /*
02125          * Make sure that the element at stackTop is a list; if not, just
02126          * leave with an error. Note that the element from the expand list
02127          * will be removed at checkForCatch.
02128          */
02129 
02130         valuePtr = OBJ_AT_TOS;
02131         if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK){
02132             TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
02133                     Tcl_GetObjResult(interp));
02134             result = TCL_ERROR;
02135             goto checkForCatch;
02136         }
02137         (void) POP_OBJECT();
02138 
02139         /*
02140          * Make sure there is enough room in the stack to expand this list
02141          * *and* process the rest of the command (at least up to the next
02142          * argument expansion or command end). The operand is the current
02143          * stack depth, as seen by the compiler.
02144          */
02145 
02146         length = objc + (codePtr->maxStackDepth - TclGetInt4AtPtr(pc+1));
02147         DECACHE_STACK_INFO();
02148         moved = (GrowEvaluationStack(iPtr->execEnvPtr, length, 1) - 1)
02149                 - (Tcl_Obj **) initCatchTop;
02150 
02151         if (moved) {
02152             /*
02153              * Change the global data to point to the new stack.
02154              */
02155 
02156             initCatchTop += moved;
02157             catchTop += moved;
02158             initTosPtr += moved;
02159             tosPtr += moved;
02160             esPtr = iPtr->execEnvPtr->execStackPtr;
02161         }
02162 
02163         /*
02164          * Expand the list at stacktop onto the stack; free the list. Knowing
02165          * that it has a freeIntRepProc we use Tcl_DecrRefCount().
02166          */
02167 
02168         for (i = 0; i < objc; i++) {
02169             PUSH_OBJECT(objv[i]);
02170         }
02171 
02172         Tcl_DecrRefCount(valuePtr);
02173         NEXT_INST_F(5, 0, 0);
02174     }
02175 
02176     {
02177         /*
02178          * INVOCATION BLOCK
02179          */
02180 
02181         int objc, pcAdjustment;
02182 
02183     case INST_INVOKE_EXPANDED:
02184         {
02185             Tcl_Obj *objPtr = expandNestList;
02186 
02187             expandNestList = (Tcl_Obj *) objPtr->internalRep.twoPtrValue.ptr2;
02188             objc = CURR_DEPTH
02189                     - (ptrdiff_t) objPtr->internalRep.twoPtrValue.ptr1;
02190             TclDecrRefCount(objPtr);
02191         }
02192 
02193         if (objc) {
02194             pcAdjustment = 1;
02195             goto doInvocation;
02196         } else {
02197             /*
02198              * Nothing was expanded, return {}.
02199              */
02200 
02201             TclNewObj(objResultPtr);
02202             NEXT_INST_F(1, 0, 1);
02203         }
02204 
02205     case INST_INVOKE_STK4:
02206         objc = TclGetUInt4AtPtr(pc+1);
02207         pcAdjustment = 5;
02208         goto doInvocation;
02209 
02210     case INST_INVOKE_STK1:
02211         objc = TclGetUInt1AtPtr(pc+1);
02212         pcAdjustment = 2;
02213 
02214     doInvocation:
02215         {
02216             Tcl_Obj **objv = &OBJ_AT_DEPTH(objc-1);
02217 
02218 #ifdef TCL_COMPILE_DEBUG
02219             if (tclTraceExec >= 2) {
02220                 int i;
02221 
02222                 if (traceInstructions) {
02223                     strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
02224                     TRACE(("%u => call ", objc));
02225                 } else {
02226                     fprintf(stdout, "%d: (%u) invoking ", iPtr->numLevels,
02227                             (unsigned)(pc - codePtr->codeStart));
02228                 }
02229                 for (i = 0;  i < objc;  i++) {
02230                     TclPrintObject(stdout, objv[i], 15);
02231                     fprintf(stdout, " ");
02232                 }
02233                 fprintf(stdout, "\n");
02234                 fflush(stdout);
02235             }
02236 #endif /*TCL_COMPILE_DEBUG*/
02237 
02238             /*
02239              * Reset the instructionCount variable, since we're about to check
02240              * for async stuff anyway while processing TclEvalObjvInternal.
02241              */
02242 
02243             instructionCount = 1;
02244 
02245             /*
02246              * Finally, let TclEvalObjvInternal handle the command.
02247              *
02248              * TIP #280: Record the last piece of info needed by
02249              * 'TclGetSrcInfoForPc', and push the frame.
02250              */
02251 
02252             bcFramePtr->data.tebc.pc = (char *) pc;
02253             iPtr->cmdFramePtr = bcFramePtr;
02254             DECACHE_STACK_INFO();
02255             result = TclEvalObjvInternal(interp, objc, objv,
02256                     /* call from TEBC */(char *) -1, -1, 0);
02257             CACHE_STACK_INFO();
02258             iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;
02259 
02260             if (result == TCL_OK) {
02261                 Tcl_Obj *objPtr;
02262 
02263 #ifndef TCL_COMPILE_DEBUG
02264                 if (*(pc+pcAdjustment) == INST_POP) {
02265                     NEXT_INST_V((pcAdjustment+1), objc, 0);
02266                 }
02267 #endif
02268                 /*
02269                  * Push the call's object result and continue execution with
02270                  * the next instruction.
02271                  */
02272 
02273                 TRACE_WITH_OBJ(("%u => ... after \"%.20s\": TCL_OK, result=",
02274                         objc, cmdNameBuf), Tcl_GetObjResult(interp));
02275 
02276                 objResultPtr = Tcl_GetObjResult(interp);
02277 
02278                 /*
02279                  * Reset the interp's result to avoid possible duplications of
02280                  * large objects [Bug 781585]. We do not call Tcl_ResetResult
02281                  * to avoid any side effects caused by the resetting of
02282                  * errorInfo and errorCode [Bug 804681], which are not needed
02283                  * here. We chose instead to manipulate the interp's object
02284                  * result directly.
02285                  *
02286                  * Note that the result object is now in objResultPtr, it
02287                  * keeps the refCount it had in its role of
02288                  * iPtr->objResultPtr.
02289                  */
02290 
02291                 TclNewObj(objPtr);
02292                 Tcl_IncrRefCount(objPtr);
02293                 iPtr->objResultPtr = objPtr;
02294                 NEXT_INST_V(pcAdjustment, objc, -1);
02295             } else {
02296                 cleanup = objc;
02297                 goto processExceptionReturn;
02298             }
02299         }
02300 
02301 #if TCL_SUPPORT_84_BYTECODE
02302     case INST_CALL_BUILTIN_FUNC1: {
02303         /*
02304          * Call one of the built-in pre-8.5 Tcl math functions. This
02305          * translates to INST_INVOKE_STK1 with the first argument of
02306          * ::tcl::mathfunc::$objv[0]. We need to insert the named math
02307          * function into the stack.
02308          */
02309 
02310         int opnd, numArgs;
02311         Tcl_Obj *objPtr;
02312 
02313         opnd = TclGetUInt1AtPtr(pc+1);
02314         if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) {
02315             TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %d\n", opnd));
02316             Tcl_Panic("TclExecuteByteCode: unrecognized builtin function code %d", opnd);
02317         }
02318 
02319         objPtr = Tcl_NewStringObj("::tcl::mathfunc::", 17);
02320         Tcl_AppendToObj(objPtr, tclBuiltinFuncTable[opnd].name, -1);
02321 
02322         /*
02323          * Only 0, 1 or 2 args.
02324          */
02325 
02326         numArgs = tclBuiltinFuncTable[opnd].numArgs;
02327         if (numArgs == 0) {
02328             PUSH_OBJECT(objPtr);
02329         } else if (numArgs == 1) {
02330             Tcl_Obj *tmpPtr1 = POP_OBJECT();
02331             PUSH_OBJECT(objPtr);
02332             PUSH_OBJECT(tmpPtr1);
02333             Tcl_DecrRefCount(tmpPtr1);
02334         } else {
02335             Tcl_Obj *tmpPtr1, *tmpPtr2;
02336             tmpPtr2 = POP_OBJECT();
02337             tmpPtr1 = POP_OBJECT();
02338             PUSH_OBJECT(objPtr);
02339             PUSH_OBJECT(tmpPtr1);
02340             PUSH_OBJECT(tmpPtr2);
02341             Tcl_DecrRefCount(tmpPtr1);
02342             Tcl_DecrRefCount(tmpPtr2);
02343         }
02344 
02345         objc = numArgs + 1;
02346         pcAdjustment = 2;
02347         goto doInvocation;
02348     }
02349 
02350     case INST_CALL_FUNC1: {
02351         /*
02352          * Call a non-builtin Tcl math function previously registered by a
02353          * call to Tcl_CreateMathFunc pre-8.5. This is essentially
02354          * INST_INVOKE_STK1 converting the first arg to
02355          * ::tcl::mathfunc::$objv[0].
02356          */
02357 
02358         Tcl_Obj *tmpPtr, *objPtr;
02359 
02360         /*
02361          * Number of arguments. The function name is the 0-th argument.
02362          */
02363 
02364         objc = TclGetUInt1AtPtr(pc+1);
02365 
02366         objPtr = OBJ_AT_DEPTH(objc-1);
02367         tmpPtr = Tcl_NewStringObj("::tcl::mathfunc::", 17);
02368         Tcl_AppendObjToObj(tmpPtr, objPtr);
02369         Tcl_DecrRefCount(objPtr);
02370 
02371         /*
02372          * Variation of PUSH_OBJECT.
02373          */
02374 
02375         OBJ_AT_DEPTH(objc-1) = tmpPtr;
02376         Tcl_IncrRefCount(tmpPtr);
02377 
02378         pcAdjustment = 2;
02379         goto doInvocation;
02380     }
02381 #else
02382     /*
02383      * INST_CALL_BUILTIN_FUNC1 and INST_CALL_FUNC1 were made obsolete by the
02384      * changes to add a ::tcl::mathfunc namespace in 8.5. Optional support
02385      * remains for existing bytecode precompiled files.
02386      */
02387 
02388     case INST_CALL_BUILTIN_FUNC1:
02389         Tcl_Panic("TclExecuteByteCode: obsolete INST_CALL_BUILTIN_FUNC1 found");
02390     case INST_CALL_FUNC1:
02391         Tcl_Panic("TclExecuteByteCode: obsolete INST_CALL_FUNC1 found");
02392 #endif
02393     }
02394 
02395     case INST_EVAL_STK: {
02396         /*
02397          * Note to maintainers: it is important that INST_EVAL_STK pop its
02398          * argument from the stack before jumping to checkForCatch! DO NOT
02399          * OPTIMISE!
02400          */
02401 
02402         Tcl_Obj *objPtr = OBJ_AT_TOS;
02403 
02404         DECACHE_STACK_INFO();
02405 
02406         /*
02407          * TIP #280: The invoking context is left NULL for a dynamically
02408          * constructed command. We cannot match its lines to the outer
02409          * context.
02410          */
02411 
02412         result = TclCompEvalObj(interp, objPtr, NULL, 0);
02413         CACHE_STACK_INFO();
02414         if (result == TCL_OK) {
02415             /*
02416              * Normal return; push the eval's object result.
02417              */
02418 
02419             objResultPtr = Tcl_GetObjResult(interp);
02420             TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)),
02421                     Tcl_GetObjResult(interp));
02422 
02423             /*
02424              * Reset the interp's result to avoid possible duplications of
02425              * large objects [Bug 781585]. We do not call Tcl_ResetResult to
02426              * avoid any side effects caused by the resetting of errorInfo and
02427              * errorCode [Bug 804681], which are not needed here. We chose
02428              * instead to manipulate the interp's object result directly.
02429              *
02430              * Note that the result object is now in objResultPtr, it keeps
02431              * the refCount it had in its role of iPtr->objResultPtr.
02432              */
02433 
02434             TclNewObj(objPtr);
02435             Tcl_IncrRefCount(objPtr);
02436             iPtr->objResultPtr = objPtr;
02437             NEXT_INST_F(1, 1, -1);
02438         } else {
02439             cleanup = 1;
02440             goto processExceptionReturn;
02441         }
02442     }
02443 
02444     case INST_EXPR_STK: {
02445         Tcl_Obj *objPtr, *valuePtr;
02446 
02447         objPtr = OBJ_AT_TOS;
02448         DECACHE_STACK_INFO();
02449         /*Tcl_ResetResult(interp);*/
02450         result = Tcl_ExprObj(interp, objPtr, &valuePtr);
02451         CACHE_STACK_INFO();
02452         if (result == TCL_OK) {
02453             objResultPtr = valuePtr;
02454             TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)), valuePtr);
02455             NEXT_INST_F(1, 1, -1);      /* Already has right refct. */
02456         } else {
02457             TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(objPtr)),
02458                     Tcl_GetObjResult(interp));
02459             goto checkForCatch;
02460         }
02461     }
02462 
02463     /*
02464      * ---------------------------------------------------------
02465      *     Start of INST_LOAD instructions.
02466      *
02467      * WARNING: more 'goto' here than your doctor recommended! The different
02468      * instructions set the value of some variables and then jump to some
02469      * common execution code.
02470      */
02471     {
02472         int opnd, pcAdjustment;
02473         Tcl_Obj *part1Ptr, *part2Ptr;
02474         Var *varPtr, *arrayPtr;
02475         Tcl_Obj *objPtr;
02476 
02477     case INST_LOAD_SCALAR1:
02478     instLoadScalar1:
02479         opnd = TclGetUInt1AtPtr(pc+1);
02480         varPtr = &(compiledLocals[opnd]);
02481         while (TclIsVarLink(varPtr)) {
02482             varPtr = varPtr->value.linkPtr;
02483         }
02484         TRACE(("%u => ", opnd));
02485         if (TclIsVarDirectReadable(varPtr)) {
02486             /*
02487              * No errors, no traces: just get the value.
02488              */
02489 
02490             objResultPtr = varPtr->value.objPtr;
02491             TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
02492             NEXT_INST_F(2, 0, 1);
02493         }
02494         pcAdjustment = 2;
02495         cleanup = 0;
02496         arrayPtr = NULL;
02497         part1Ptr = part2Ptr = NULL;
02498         goto doCallPtrGetVar;
02499 
02500     case INST_LOAD_SCALAR4:
02501         opnd = TclGetUInt4AtPtr(pc+1);
02502         varPtr = &(compiledLocals[opnd]);
02503         while (TclIsVarLink(varPtr)) {
02504             varPtr = varPtr->value.linkPtr;
02505         }
02506         TRACE(("%u => ", opnd));
02507         if (TclIsVarDirectReadable(varPtr)) {
02508             /*
02509              * No errors, no traces: just get the value.
02510              */
02511 
02512             objResultPtr = varPtr->value.objPtr;
02513             TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
02514             NEXT_INST_F(5, 0, 1);
02515         }
02516         pcAdjustment = 5;
02517         cleanup = 0;
02518         arrayPtr = NULL;
02519         part1Ptr = part2Ptr = NULL;
02520         goto doCallPtrGetVar;
02521 
02522     case INST_LOAD_ARRAY4:
02523         opnd = TclGetUInt4AtPtr(pc+1);
02524         pcAdjustment = 5;
02525         goto doLoadArray;
02526 
02527     case INST_LOAD_ARRAY1:
02528         opnd = TclGetUInt1AtPtr(pc+1);
02529         pcAdjustment = 2;
02530 
02531     doLoadArray:
02532         part1Ptr = NULL;
02533         part2Ptr = OBJ_AT_TOS;
02534         arrayPtr = &(compiledLocals[opnd]);
02535         while (TclIsVarLink(arrayPtr)) {
02536             arrayPtr = arrayPtr->value.linkPtr;
02537         }
02538         TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
02539         if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) {
02540             varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
02541             if (varPtr && TclIsVarDirectReadable(varPtr)) {
02542                 /*
02543                  * No errors, no traces: just get the value.
02544                  */
02545 
02546                 objResultPtr = varPtr->value.objPtr;
02547                 TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
02548                 NEXT_INST_F(pcAdjustment, 1, 1);
02549             }
02550         }
02551         varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
02552                 TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr, opnd);
02553         if (varPtr == NULL) {
02554             TRACE_APPEND(("ERROR: %.30s\n",
02555                                  O2S(Tcl_GetObjResult(interp))));
02556             result = TCL_ERROR;
02557             goto checkForCatch;
02558         }
02559         cleanup = 1;
02560         goto doCallPtrGetVar;
02561 
02562     case INST_LOAD_ARRAY_STK:
02563         cleanup = 2;
02564         part2Ptr = OBJ_AT_TOS;          /* element name */
02565         objPtr = OBJ_UNDER_TOS;         /* array name */
02566         TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), O2S(part2Ptr)));
02567         goto doLoadStk;
02568 
02569     case INST_LOAD_STK:
02570     case INST_LOAD_SCALAR_STK:
02571         cleanup = 1;
02572         part2Ptr = NULL;
02573         objPtr = OBJ_AT_TOS;            /* variable name */
02574         TRACE(("\"%.30s\" => ", O2S(objPtr)));
02575 
02576     doLoadStk:
02577         part1Ptr = objPtr;
02578         varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr,
02579                 TCL_LEAVE_ERR_MSG, "read", /*createPart1*/0, /*createPart2*/1,
02580                 &arrayPtr);
02581         if (varPtr) {
02582             if (TclIsVarDirectReadable2(varPtr, arrayPtr)) {
02583                 /*
02584                  * No errors, no traces: just get the value.
02585                  */
02586 
02587                 objResultPtr = varPtr->value.objPtr;
02588                 TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
02589                 NEXT_INST_V(1, cleanup, 1);
02590             }
02591             pcAdjustment = 1;
02592             opnd = -1;
02593             goto doCallPtrGetVar;
02594         } else {
02595             TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
02596             result = TCL_ERROR;
02597             goto checkForCatch;
02598         }
02599 
02600     doCallPtrGetVar:
02601         /*
02602          * There are either errors or the variable is traced: call
02603          * TclPtrGetVar to process fully.
02604          */
02605 
02606         DECACHE_STACK_INFO();
02607         objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr,
02608                 part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, opnd);
02609         CACHE_STACK_INFO();
02610         if (objResultPtr) {
02611             TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
02612             NEXT_INST_V(pcAdjustment, cleanup, 1);
02613         } else {
02614             TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
02615             result = TCL_ERROR;
02616             goto checkForCatch;
02617         }
02618     }
02619 
02620     /*
02621      *     End of INST_LOAD instructions.
02622      * ---------------------------------------------------------
02623      */
02624 
02625     /*
02626      * ---------------------------------------------------------
02627      *     Start of INST_STORE and related instructions.
02628      *
02629      * WARNING: more 'goto' here than your doctor recommended! The different
02630      * instructions set the value of some variables and then jump to somme
02631      * common execution code.
02632      */
02633 
02634     {
02635         int opnd, pcAdjustment, storeFlags;
02636         Tcl_Obj *part1Ptr, *part2Ptr;
02637         Var *varPtr, *arrayPtr;
02638         Tcl_Obj *objPtr, *valuePtr;
02639 
02640     case INST_STORE_ARRAY4:
02641         opnd = TclGetUInt4AtPtr(pc+1);
02642         pcAdjustment = 5;
02643         goto doStoreArrayDirect;
02644 
02645     case INST_STORE_ARRAY1:
02646         opnd = TclGetUInt1AtPtr(pc+1);
02647         pcAdjustment = 2;
02648 
02649     doStoreArrayDirect:
02650         valuePtr = OBJ_AT_TOS;
02651         part2Ptr = OBJ_UNDER_TOS;
02652         arrayPtr = &(compiledLocals[opnd]);
02653         TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
02654                 O2S(valuePtr)));
02655         while (TclIsVarLink(arrayPtr)) {
02656             arrayPtr = arrayPtr->value.linkPtr;
02657         }
02658         if (TclIsVarArray(arrayPtr) && !WriteTraced(arrayPtr)) {
02659             varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
02660             if (varPtr && TclIsVarDirectWritable(varPtr)) {
02661                 tosPtr--;
02662                 Tcl_DecrRefCount(OBJ_AT_TOS);
02663                 OBJ_AT_TOS = valuePtr;
02664                 goto doStoreVarDirect;
02665             }
02666         }
02667         cleanup = 2;
02668         storeFlags = TCL_LEAVE_ERR_MSG;
02669         part1Ptr = NULL;
02670         goto doStoreArrayDirectFailed;
02671 
02672     case INST_STORE_SCALAR4:
02673         opnd = TclGetUInt4AtPtr(pc+1);
02674         pcAdjustment = 5;
02675         goto doStoreScalarDirect;
02676 
02677     case INST_STORE_SCALAR1:
02678         opnd = TclGetUInt1AtPtr(pc+1);
02679         pcAdjustment = 2;
02680 
02681     doStoreScalarDirect:
02682         valuePtr = OBJ_AT_TOS;
02683         varPtr = &(compiledLocals[opnd]);
02684         TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
02685         while (TclIsVarLink(varPtr)) {
02686             varPtr = varPtr->value.linkPtr;
02687         }
02688         if (TclIsVarDirectWritable(varPtr)) {
02689     doStoreVarDirect:
02690             /*
02691              * No traces, no errors, plain 'set': we can safely inline. The
02692              * value *will* be set to what's requested, so that the stack top
02693              * remains pointing to the same Tcl_Obj.
02694              */
02695 
02696             valuePtr = varPtr->value.objPtr;
02697             if (valuePtr != NULL) {
02698                 TclDecrRefCount(valuePtr);
02699             }
02700             objResultPtr = OBJ_AT_TOS;
02701             varPtr->value.objPtr = objResultPtr;
02702 #ifndef TCL_COMPILE_DEBUG
02703             if (*(pc+pcAdjustment) == INST_POP) {
02704                 tosPtr--;
02705                 NEXT_INST_F((pcAdjustment+1), 0, 0);
02706             }
02707 #else
02708             TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
02709 #endif
02710             Tcl_IncrRefCount(objResultPtr);
02711             NEXT_INST_F(pcAdjustment, 0, 0);
02712         }
02713         storeFlags = TCL_LEAVE_ERR_MSG;
02714         part1Ptr = NULL;
02715         goto doStoreScalar;
02716 
02717     case INST_LAPPEND_STK:
02718         valuePtr = OBJ_AT_TOS; /* value to append */
02719         part2Ptr = NULL;
02720         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
02721                 | TCL_LIST_ELEMENT | TCL_TRACE_READS);
02722         goto doStoreStk;
02723 
02724     case INST_LAPPEND_ARRAY_STK:
02725         valuePtr = OBJ_AT_TOS; /* value to append */
02726         part2Ptr = OBJ_UNDER_TOS;
02727         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
02728                 | TCL_LIST_ELEMENT | TCL_TRACE_READS);
02729         goto doStoreStk;
02730 
02731     case INST_APPEND_STK:
02732         valuePtr = OBJ_AT_TOS; /* value to append */
02733         part2Ptr = NULL;
02734         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
02735         goto doStoreStk;
02736 
02737     case INST_APPEND_ARRAY_STK:
02738         valuePtr = OBJ_AT_TOS; /* value to append */
02739         part2Ptr = OBJ_UNDER_TOS;
02740         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
02741         goto doStoreStk;
02742 
02743     case INST_STORE_ARRAY_STK:
02744         valuePtr = OBJ_AT_TOS;
02745         part2Ptr = OBJ_UNDER_TOS;
02746         storeFlags = TCL_LEAVE_ERR_MSG;
02747         goto doStoreStk;
02748 
02749     case INST_STORE_STK:
02750     case INST_STORE_SCALAR_STK:
02751         valuePtr = OBJ_AT_TOS;
02752         part2Ptr = NULL;
02753         storeFlags = TCL_LEAVE_ERR_MSG;
02754 
02755     doStoreStk:
02756         objPtr = OBJ_AT_DEPTH(1 + (part2Ptr != NULL)); /* variable name */
02757         part1Ptr = objPtr;
02758 #ifdef TCL_COMPILE_DEBUG
02759         if (part2Ptr == NULL) {
02760             TRACE(("\"%.30s\" <- \"%.30s\" =>", O2S(part1Ptr),O2S(valuePtr)));
02761         } else {
02762             TRACE(("\"%.30s(%.30s)\" <- \"%.30s\" => ",
02763                     O2S(part1Ptr), O2S(part2Ptr), O2S(valuePtr)));
02764         }
02765 #endif
02766         varPtr = TclObjLookupVarEx(interp, objPtr,part2Ptr, TCL_LEAVE_ERR_MSG,
02767                 "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
02768         if (varPtr) {
02769             cleanup = ((part2Ptr == NULL)? 2 : 3);
02770             pcAdjustment = 1;
02771             opnd = -1;
02772             goto doCallPtrSetVar;
02773         } else {
02774             TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
02775             result = TCL_ERROR;
02776             goto checkForCatch;
02777         }
02778 
02779     case INST_LAPPEND_ARRAY4:
02780         opnd = TclGetUInt4AtPtr(pc+1);
02781         pcAdjustment = 5;
02782         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
02783                 | TCL_LIST_ELEMENT | TCL_TRACE_READS);
02784         goto doStoreArray;
02785 
02786     case INST_LAPPEND_ARRAY1:
02787         opnd = TclGetUInt1AtPtr(pc+1);
02788         pcAdjustment = 2;
02789         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
02790                 | TCL_LIST_ELEMENT | TCL_TRACE_READS);
02791         goto doStoreArray;
02792 
02793     case INST_APPEND_ARRAY4:
02794         opnd = TclGetUInt4AtPtr(pc+1);
02795         pcAdjustment = 5;
02796         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
02797         goto doStoreArray;
02798 
02799     case INST_APPEND_ARRAY1:
02800         opnd = TclGetUInt1AtPtr(pc+1);
02801         pcAdjustment = 2;
02802         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
02803         goto doStoreArray;
02804 
02805     doStoreArray:
02806         valuePtr = OBJ_AT_TOS;
02807         part2Ptr = OBJ_UNDER_TOS;
02808         arrayPtr = &(compiledLocals[opnd]);
02809         TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
02810                 O2S(valuePtr)));
02811         while (TclIsVarLink(arrayPtr)) {
02812             arrayPtr = arrayPtr->value.linkPtr;
02813         }
02814         cleanup = 2;
02815         part1Ptr = NULL;
02816 
02817     doStoreArrayDirectFailed:
02818         varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
02819                 TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr, opnd);
02820         if (varPtr) {
02821             goto doCallPtrSetVar;
02822         } else {
02823             TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
02824             result = TCL_ERROR;
02825             goto checkForCatch;
02826         }
02827 
02828     case INST_LAPPEND_SCALAR4:
02829         opnd = TclGetUInt4AtPtr(pc+1);
02830         pcAdjustment = 5;
02831         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
02832                 | TCL_LIST_ELEMENT | TCL_TRACE_READS);
02833         goto doStoreScalar;
02834 
02835     case INST_LAPPEND_SCALAR1:
02836         opnd = TclGetUInt1AtPtr(pc+1);
02837         pcAdjustment = 2;
02838         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
02839                 | TCL_LIST_ELEMENT | TCL_TRACE_READS);
02840         goto doStoreScalar;
02841 
02842     case INST_APPEND_SCALAR4:
02843         opnd = TclGetUInt4AtPtr(pc+1);
02844         pcAdjustment = 5;
02845         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
02846         goto doStoreScalar;
02847 
02848     case INST_APPEND_SCALAR1:
02849         opnd = TclGetUInt1AtPtr(pc+1);
02850         pcAdjustment = 2;
02851         storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
02852         goto doStoreScalar;
02853 
02854     doStoreScalar:
02855         valuePtr = OBJ_AT_TOS;
02856         varPtr = &(compiledLocals[opnd]);
02857         TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
02858         while (TclIsVarLink(varPtr)) {
02859             varPtr = varPtr->value.linkPtr;
02860         }
02861         cleanup = 1;
02862         arrayPtr = NULL;
02863         part1Ptr = part2Ptr = NULL;
02864 
02865     doCallPtrSetVar:
02866         DECACHE_STACK_INFO();
02867         objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr,
02868                 part1Ptr, part2Ptr, valuePtr, storeFlags, opnd);
02869         CACHE_STACK_INFO();
02870         if (objResultPtr) {
02871 #ifndef TCL_COMPILE_DEBUG
02872             if (*(pc+pcAdjustment) == INST_POP) {
02873                 NEXT_INST_V((pcAdjustment+1), cleanup, 0);
02874             }
02875 #endif
02876             TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
02877             NEXT_INST_V(pcAdjustment, cleanup, 1);
02878         } else {
02879             TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
02880             result = TCL_ERROR;
02881             goto checkForCatch;
02882         }
02883     }
02884 
02885     /*
02886      *     End of INST_STORE and related instructions.
02887      * ---------------------------------------------------------
02888      */
02889 
02890     /*
02891      * ---------------------------------------------------------
02892      *     Start of INST_INCR instructions.
02893      *
02894      * WARNING: more 'goto' here than your doctor recommended! The different
02895      * instructions set the value of some variables and then jump to somme
02896      * common execution code.
02897      */
02898 
02899 /*TODO: Consider more untangling here; merge with LOAD and STORE ? */
02900 
02901     {
02902         Tcl_Obj *objPtr, *incrPtr;
02903         int opnd, pcAdjustment;
02904 #ifndef NO_WIDE_TYPE
02905         Tcl_WideInt w;
02906 #endif
02907         long i;
02908         Tcl_Obj *part1Ptr, *part2Ptr;
02909         Var *varPtr, *arrayPtr;
02910 
02911     case INST_INCR_SCALAR1:
02912     case INST_INCR_ARRAY1:
02913     case INST_INCR_ARRAY_STK:
02914     case INST_INCR_SCALAR_STK:
02915     case INST_INCR_STK:
02916         opnd = TclGetUInt1AtPtr(pc+1);
02917         incrPtr = POP_OBJECT();
02918         switch (*pc) {
02919         case INST_INCR_SCALAR1:
02920             pcAdjustment = 2;
02921             goto doIncrScalar;
02922         case INST_INCR_ARRAY1:
02923             pcAdjustment = 2;
02924             goto doIncrArray;
02925         default:
02926             pcAdjustment = 1;
02927             goto doIncrStk;
02928         }
02929 
02930     case INST_INCR_ARRAY_STK_IMM:
02931     case INST_INCR_SCALAR_STK_IMM:
02932     case INST_INCR_STK_IMM:
02933         i = TclGetInt1AtPtr(pc+1);
02934         incrPtr = Tcl_NewIntObj(i);
02935         Tcl_IncrRefCount(incrPtr);
02936         pcAdjustment = 2;
02937 
02938     doIncrStk:
02939         if ((*pc == INST_INCR_ARRAY_STK_IMM)
02940                 || (*pc == INST_INCR_ARRAY_STK)) {
02941             part2Ptr = OBJ_AT_TOS;
02942             objPtr = OBJ_UNDER_TOS;
02943             TRACE(("\"%.30s(%.30s)\" (by %ld) => ",
02944                     O2S(objPtr), O2S(part2Ptr), i));
02945         } else {
02946             part2Ptr = NULL;
02947             objPtr = OBJ_AT_TOS;
02948             TRACE(("\"%.30s\" (by %ld) => ", O2S(objPtr), i));
02949         }
02950         part1Ptr = objPtr;
02951         opnd = -1;
02952         varPtr = TclObjLookupVarEx(interp, objPtr, part2Ptr,
02953                 TCL_LEAVE_ERR_MSG, "read", 1, 1, &arrayPtr);
02954         if (varPtr) {
02955             cleanup = ((part2Ptr == NULL)? 1 : 2);
02956             goto doIncrVar;
02957         } else {
02958             Tcl_AddObjErrorInfo(interp,
02959                     "\n    (reading value of variable to increment)", -1);
02960             TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
02961             result = TCL_ERROR;
02962             Tcl_DecrRefCount(incrPtr);
02963             goto checkForCatch;
02964         }
02965 
02966     case INST_INCR_ARRAY1_IMM:
02967         opnd = TclGetUInt1AtPtr(pc+1);
02968         i = TclGetInt1AtPtr(pc+2);
02969         incrPtr = Tcl_NewIntObj(i);
02970         Tcl_IncrRefCount(incrPtr);
02971         pcAdjustment = 3;
02972 
02973     doIncrArray:
02974         part1Ptr = NULL;
02975         part2Ptr = OBJ_AT_TOS;
02976         arrayPtr = &(compiledLocals[opnd]);
02977         cleanup = 1;
02978         while (TclIsVarLink(arrayPtr)) {
02979             arrayPtr = arrayPtr->value.linkPtr;
02980         }
02981         TRACE(("%u \"%.30s\" (by %ld) => ", opnd, O2S(part2Ptr), i));
02982         varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
02983                 TCL_LEAVE_ERR_MSG, "read", 1, 1, arrayPtr, opnd);
02984         if (varPtr) {
02985             goto doIncrVar;
02986         } else {
02987             TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
02988             result = TCL_ERROR;
02989             Tcl_DecrRefCount(incrPtr);
02990             goto checkForCatch;
02991         }
02992 
02993     case INST_INCR_SCALAR1_IMM:
02994         opnd = TclGetUInt1AtPtr(pc+1);
02995         i = TclGetInt1AtPtr(pc+2);
02996         pcAdjustment = 3;
02997         cleanup = 0;
02998         varPtr = &(compiledLocals[opnd]);
02999         while (TclIsVarLink(varPtr)) {
03000             varPtr = varPtr->value.linkPtr;
03001         }
03002 
03003         if (TclIsVarDirectModifyable(varPtr)) {
03004             ClientData ptr;
03005             int type;
03006 
03007             objPtr = varPtr->value.objPtr;
03008             if (GetNumberFromObj(NULL, objPtr, &ptr, &type) == TCL_OK) {
03009                 if (type == TCL_NUMBER_LONG) {
03010                     long augend = *((const long *)ptr);
03011                     long sum = augend + i;
03012 
03013                     /*
03014                      * Overflow when (augend and sum have different sign) and
03015                      * (augend and i have the same sign). This is encapsulated
03016                      * in the Overflowing macro.
03017                      */
03018 
03019                     if (!Overflowing(augend, i, sum)) {
03020                         TRACE(("%u %ld => ", opnd, i));
03021                         if (Tcl_IsShared(objPtr)) {
03022                             objPtr->refCount--; /* We know it's shared. */
03023                             TclNewLongObj(objResultPtr, sum);
03024                             Tcl_IncrRefCount(objResultPtr);
03025                             varPtr->value.objPtr = objResultPtr;
03026                         } else {
03027                             objResultPtr = objPtr;
03028                             TclSetLongObj(objPtr, sum);
03029                         }
03030                         goto doneIncr;
03031                     }
03032 #ifndef NO_WIDE_TYPE
03033                     {
03034                         w = (Tcl_WideInt)augend;
03035 
03036                         TRACE(("%u %ld => ", opnd, i));
03037                         if (Tcl_IsShared(objPtr)) {
03038                             objPtr->refCount--; /* We know it's shared. */
03039                             objResultPtr = Tcl_NewWideIntObj(w+i);
03040                             Tcl_IncrRefCount(objResultPtr);
03041                             varPtr->value.objPtr = objResultPtr;
03042                         } else {
03043                             objResultPtr = objPtr;
03044 
03045                             /*
03046                              * We know the sum value is outside the long
03047                              * range; use macro form that doesn't range test
03048                              * again.
03049                              */
03050 
03051                             TclSetWideIntObj(objPtr, w+i);
03052                         }
03053                         goto doneIncr;
03054                     }
03055 #endif
03056                 }       /* end if (type == TCL_NUMBER_LONG) */
03057 #ifndef NO_WIDE_TYPE
03058                 if (type == TCL_NUMBER_WIDE) {
03059                     Tcl_WideInt sum;
03060                     w = *((const Tcl_WideInt *)ptr);
03061                     sum = w + i;
03062 
03063                     /*
03064                      * Check for overflow.
03065                      */
03066 
03067                     if (!Overflowing(w, i, sum)) {
03068                         TRACE(("%u %ld => ", opnd, i));
03069                         if (Tcl_IsShared(objPtr)) {
03070                             objPtr->refCount--; /* We know it's shared. */
03071                             objResultPtr = Tcl_NewWideIntObj(sum);
03072                             Tcl_IncrRefCount(objResultPtr);
03073                             varPtr->value.objPtr = objResultPtr;
03074                         } else {
03075                             objResultPtr = objPtr;
03076 
03077                             /*
03078                              * We *do not* know the sum value is outside the
03079                              * long range (wide + long can yield long); use
03080                              * the function call that checks range.
03081                              */
03082 
03083                             Tcl_SetWideIntObj(objPtr, sum);
03084                         }
03085                         goto doneIncr;
03086                     }
03087                 }
03088 #endif
03089             }
03090             if (Tcl_IsShared(objPtr)) {
03091                 objPtr->refCount--;     /* We know it's shared */
03092                 objResultPtr = Tcl_DuplicateObj(objPtr);
03093                 Tcl_IncrRefCount(objResultPtr);
03094                 varPtr->value.objPtr = objResultPtr;
03095             } else {
03096                 objResultPtr = objPtr;
03097             }
03098             TclNewLongObj(incrPtr, i);
03099             result = TclIncrObj(interp, objResultPtr, incrPtr);
03100             Tcl_DecrRefCount(incrPtr);
03101             if (result == TCL_OK) {
03102                 goto doneIncr;
03103             } else {
03104                 TRACE_APPEND(("ERROR: %.30s\n",
03105                         O2S(Tcl_GetObjResult(interp))));
03106                 goto checkForCatch;
03107             }
03108         }
03109 
03110         /*
03111          * All other cases, flow through to generic handling.
03112          */
03113 
03114         TclNewLongObj(incrPtr, i);
03115         Tcl_IncrRefCount(incrPtr);
03116 
03117     doIncrScalar:
03118         varPtr = &(compiledLocals[opnd]);
03119         while (TclIsVarLink(varPtr)) {
03120             varPtr = varPtr->value.linkPtr;
03121         }
03122         arrayPtr = NULL;
03123         part1Ptr = part2Ptr = NULL;
03124         cleanup = 0;
03125         TRACE(("%u %ld => ", opnd, i));
03126 
03127     doIncrVar:
03128         if (TclIsVarDirectModifyable2(varPtr, arrayPtr)) {
03129             objPtr = varPtr->value.objPtr;
03130             if (Tcl_IsShared(objPtr)) {
03131                 objPtr->refCount--;     /* We know it's shared */
03132                 objResultPtr = Tcl_DuplicateObj(objPtr);
03133                 Tcl_IncrRefCount(objResultPtr);
03134                 varPtr->value.objPtr = objResultPtr;
03135             } else {
03136                 objResultPtr = objPtr;
03137             }
03138             result = TclIncrObj(interp, objResultPtr, incrPtr);
03139             Tcl_DecrRefCount(incrPtr);
03140             if (result == TCL_OK) {
03141                 goto doneIncr;
03142             } else {
03143                 TRACE_APPEND(("ERROR: %.30s\n",
03144                         O2S(Tcl_GetObjResult(interp))));
03145                 goto checkForCatch;
03146             }
03147         } else {
03148             DECACHE_STACK_INFO();
03149             objResultPtr = TclPtrIncrObjVar(interp, varPtr, arrayPtr,
03150                     part1Ptr, part2Ptr, incrPtr, TCL_LEAVE_ERR_MSG, opnd);
03151             CACHE_STACK_INFO();
03152             Tcl_DecrRefCount(incrPtr);
03153             if (objResultPtr == NULL) {
03154                 TRACE_APPEND(("ERROR: %.30s\n",
03155                         O2S(Tcl_GetObjResult(interp))));
03156                 result = TCL_ERROR;
03157                 goto checkForCatch;
03158             }
03159         }
03160     doneIncr:
03161         TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
03162 #ifndef TCL_COMPILE_DEBUG
03163         if (*(pc+pcAdjustment) == INST_POP) {
03164             NEXT_INST_V((pcAdjustment+1), cleanup, 0);
03165         }
03166 #endif
03167         NEXT_INST_V(pcAdjustment, cleanup, 1);
03168     }
03169 
03170     /*
03171      *     End of INST_INCR instructions.
03172      * ---------------------------------------------------------
03173      */
03174 
03175     /*
03176      * ---------------------------------------------------------
03177      *     Start of INST_EXIST instructions.
03178      */
03179     {
03180         Tcl_Obj *part1Ptr, *part2Ptr;
03181         Var *varPtr, *arrayPtr;
03182 
03183     case INST_EXIST_SCALAR: {
03184         int opnd = TclGetUInt4AtPtr(pc+1);
03185 
03186         varPtr = &(compiledLocals[opnd]);
03187         while (TclIsVarLink(varPtr)) {
03188             varPtr = varPtr->value.linkPtr;
03189         }
03190         TRACE(("%u => ", opnd));
03191         if (ReadTraced(varPtr)) {
03192             DECACHE_STACK_INFO();
03193             TclObjCallVarTraces(iPtr, NULL, varPtr, NULL, NULL,
03194                     TCL_TRACE_READS, 0, opnd);
03195             CACHE_STACK_INFO();
03196             if (TclIsVarUndefined(varPtr)) {
03197                 TclCleanupVar(varPtr, NULL);
03198                 varPtr = NULL;
03199             }
03200         }
03201 
03202         /*
03203          * Tricky! Arrays always exist.
03204          */
03205 
03206         objResultPtr = constants[!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1];
03207         TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
03208         NEXT_INST_F(5, 0, 1);
03209     }
03210 
03211     case INST_EXIST_ARRAY: {
03212         int opnd = TclGetUInt4AtPtr(pc+1);
03213 
03214         part2Ptr = OBJ_AT_TOS;
03215         arrayPtr = &(compiledLocals[opnd]);
03216         while (TclIsVarLink(arrayPtr)) {
03217             arrayPtr = arrayPtr->value.linkPtr;
03218         }
03219         TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
03220         if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) {
03221             varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
03222             if (!varPtr || !ReadTraced(varPtr)) {
03223                 goto doneExistArray;
03224             }
03225         }
03226         varPtr = TclLookupArrayElement(interp, NULL, part2Ptr, 0, "access",
03227                 0, 1, arrayPtr, opnd);
03228         if (varPtr) {
03229             if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) {
03230                 DECACHE_STACK_INFO();
03231                 TclObjCallVarTraces(iPtr, arrayPtr, varPtr, NULL, part2Ptr,
03232                         TCL_TRACE_READS, 0, opnd);
03233                 CACHE_STACK_INFO();
03234             }
03235             if (TclIsVarUndefined(varPtr)) {
03236                 TclCleanupVar(varPtr, arrayPtr);
03237                 varPtr = NULL;
03238             }
03239         }
03240     doneExistArray:
03241         objResultPtr = constants[!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1];
03242         TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
03243         NEXT_INST_F(5, 1, 1);
03244     }
03245 
03246     case INST_EXIST_ARRAY_STK:
03247         cleanup = 2;
03248         part2Ptr = OBJ_AT_TOS;          /* element name */
03249         part1Ptr = OBJ_UNDER_TOS;       /* array name */
03250         TRACE(("\"%.30s(%.30s)\" => ", O2S(part1Ptr), O2S(part2Ptr)));
03251         goto doExistStk;
03252 
03253     case INST_EXIST_STK:
03254         cleanup = 1;
03255         part2Ptr = NULL;
03256         part1Ptr = OBJ_AT_TOS;          /* variable name */
03257         TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
03258 
03259     doExistStk:
03260         varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, 0, "access",
03261                 /*createPart1*/0, /*createPart2*/1, &arrayPtr);
03262         if (varPtr) {
03263             if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) {
03264                 DECACHE_STACK_INFO();
03265                 TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr,part2Ptr,
03266                         TCL_TRACE_READS, 0, -1);
03267                 CACHE_STACK_INFO();
03268             }
03269             if (TclIsVarUndefined(varPtr)) {
03270                 TclCleanupVar(varPtr, arrayPtr);
03271                 varPtr = NULL;
03272             }
03273         }
03274         objResultPtr = constants[!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1];
03275         TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
03276         NEXT_INST_V(1, cleanup, 1);
03277     }
03278 
03279     /*
03280      *     End of INST_EXIST instructions.
03281      * ---------------------------------------------------------
03282      */
03283 
03284     case INST_UPVAR: {
03285         int opnd;
03286         Var *varPtr, *otherPtr;
03287 
03288         TRACE_WITH_OBJ(("upvar "), OBJ_UNDER_TOS);
03289 
03290         {
03291             CallFrame *framePtr, *savedFramePtr;
03292 
03293             result = TclObjGetFrame(interp, OBJ_UNDER_TOS, &framePtr);
03294             if (result != -1) {
03295                 /*
03296                  * Locate the other variable.
03297                  */
03298 
03299                 savedFramePtr = iPtr->varFramePtr;
03300                 iPtr->varFramePtr = framePtr;
03301                 otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
03302                         (TCL_LEAVE_ERR_MSG), "access",
03303                         /*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
03304                 iPtr->varFramePtr = savedFramePtr;
03305                 if (otherPtr) {
03306                     result = TCL_OK;
03307                     goto doLinkVars;
03308                 }
03309             }
03310             result = TCL_ERROR;
03311             goto checkForCatch;
03312         }
03313 
03314     case INST_VARIABLE:
03315         TRACE(("variable "));
03316         otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
03317                 (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
03318                 /*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
03319         if (otherPtr) {
03320             /*
03321              * Do the [variable] magic.
03322              */
03323 
03324             TclSetVarNamespaceVar(otherPtr);
03325             result = TCL_OK;
03326             goto doLinkVars;
03327         }
03328         result = TCL_ERROR;
03329         goto checkForCatch;
03330 
03331     case INST_NSUPVAR:
03332         TRACE_WITH_OBJ(("nsupvar "), OBJ_UNDER_TOS);
03333 
03334         {
03335             Tcl_Namespace *nsPtr, *savedNsPtr;
03336 
03337             result = TclGetNamespaceFromObj(interp, OBJ_UNDER_TOS, &nsPtr);
03338             if (result == TCL_OK) {
03339                 /*
03340                  * Locate the other variable.
03341                  */
03342 
03343                 savedNsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
03344                 iPtr->varFramePtr->nsPtr = (Namespace *) nsPtr;
03345                 otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
03346                         (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
03347                         /*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
03348                 iPtr->varFramePtr->nsPtr = (Namespace *) savedNsPtr;
03349                 if (otherPtr) {
03350                     goto doLinkVars;
03351                 }
03352             }
03353             result = TCL_ERROR;
03354             goto checkForCatch;
03355         }
03356 
03357     doLinkVars:
03358 
03359         /*
03360          * If we are here, the local variable has already been created: do the
03361          * little work of TclPtrMakeUpvar that remains to be done right here
03362          * if there are no errors; otherwise, let it handle the case.
03363          */
03364 
03365         opnd = TclGetInt4AtPtr(pc+1);;
03366         varPtr = &(compiledLocals[opnd]);
03367         if ((varPtr != otherPtr) && !TclIsVarTraced(varPtr)
03368                 && (TclIsVarUndefined(varPtr) || TclIsVarLink(varPtr))) {
03369             if (!TclIsVarUndefined(varPtr)) {
03370                 /*
03371                  * Then it is a defined link.
03372                  */
03373 
03374                 Var *linkPtr = varPtr->value.linkPtr;
03375 
03376                 if (linkPtr == otherPtr) {
03377                     goto doLinkVarsDone;
03378                 }
03379                 if (TclIsVarInHash(linkPtr)) {
03380                     VarHashRefCount(linkPtr)--;
03381                     if (TclIsVarUndefined(linkPtr)) {
03382                         TclCleanupVar(linkPtr, NULL);
03383                     }
03384                 }
03385             }
03386             TclSetVarLink(varPtr);
03387             varPtr->value.linkPtr = otherPtr;
03388             if (TclIsVarInHash(otherPtr)) {
03389                 VarHashRefCount(otherPtr)++;
03390             }
03391         } else {
03392             result = TclPtrObjMakeUpvar(interp, otherPtr, NULL, 0, opnd);
03393             if (result != TCL_OK) {
03394                 goto checkForCatch;
03395             }
03396         }
03397 
03398         /*
03399          * Do not pop the namespace or frame index, it may be needed for other
03400          * variables - and [variable] did not push it at all.
03401          */
03402 
03403     doLinkVarsDone:
03404         NEXT_INST_F(5, 1, 0);
03405     }
03406 
03407     case INST_JUMP1: {
03408         int opnd = TclGetInt1AtPtr(pc+1);
03409 
03410         TRACE(("%d => new pc %u\n", opnd,
03411                 (unsigned)(pc + opnd - codePtr->codeStart)));
03412         NEXT_INST_F(opnd, 0, 0);
03413     }
03414 
03415     case INST_JUMP4: {
03416         int opnd = TclGetInt4AtPtr(pc+1);
03417 
03418         TRACE(("%d => new pc %u\n", opnd,
03419                 (unsigned)(pc + opnd - codePtr->codeStart)));
03420         NEXT_INST_F(opnd, 0, 0);
03421     }
03422 
03423     {
03424         int jmpOffset[2], b;
03425         Tcl_Obj *valuePtr;
03426 
03427         /* TODO: consider rewrite so we don't compute the offset we're not
03428          * going to take. */
03429     case INST_JUMP_FALSE4:
03430         jmpOffset[0] = TclGetInt4AtPtr(pc+1);   /* FALSE offset */
03431         jmpOffset[1] = 5;                       /* TRUE offset*/
03432         goto doCondJump;
03433 
03434     case INST_JUMP_TRUE4:
03435         jmpOffset[0] = 5;
03436         jmpOffset[1] = TclGetInt4AtPtr(pc+1);
03437         goto doCondJump;
03438 
03439     case INST_JUMP_FALSE1:
03440         jmpOffset[0] = TclGetInt1AtPtr(pc+1);
03441         jmpOffset[1] = 2;
03442         goto doCondJump;
03443 
03444     case INST_JUMP_TRUE1:
03445         jmpOffset[0] = 2;
03446         jmpOffset[1] = TclGetInt1AtPtr(pc+1);
03447 
03448     doCondJump:
03449         valuePtr = OBJ_AT_TOS;
03450 
03451         /* TODO - check claim that taking address of b harms performance */
03452         /* TODO - consider optimization search for constants */
03453         result = TclGetBooleanFromObj(interp, valuePtr, &b);
03454         if (result != TCL_OK) {
03455             TRACE_WITH_OBJ(("%d => ERROR: ", jmpOffset[
03456                     ((*pc == INST_JUMP_FALSE1) || (*pc == INST_JUMP_FALSE4))
03457                     ? 0 : 1]), Tcl_GetObjResult(interp));
03458             goto checkForCatch;
03459         }
03460 
03461 #ifdef TCL_COMPILE_DEBUG
03462         if (b) {
03463             if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
03464                 TRACE(("%d => %.20s true, new pc %u\n", jmpOffset[1],
03465                         O2S(valuePtr),
03466                         (unsigned)(pc + jmpOffset[1] - codePtr->codeStart)));
03467             } else {
03468                 TRACE(("%d => %.20s true\n", jmpOffset[0], O2S(valuePtr)));
03469             }
03470         } else {
03471             if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
03472                 TRACE(("%d => %.20s false\n", jmpOffset[0], O2S(valuePtr)));
03473             } else {
03474                 TRACE(("%d => %.20s false, new pc %u\n", jmpOffset[0],
03475                         O2S(valuePtr),
03476                         (unsigned)(pc + jmpOffset[1] - codePtr->codeStart)));
03477             }
03478         }
03479 #endif
03480         NEXT_INST_F(jmpOffset[b], 1, 0);
03481     }
03482 
03483     case INST_JUMP_TABLE: {
03484         Tcl_HashEntry *hPtr;
03485         JumptableInfo *jtPtr;
03486         int opnd;
03487 
03488         /*
03489          * Jump to location looked up in a hashtable; fall through to next
03490          * instr if lookup fails.
03491          */
03492 
03493         opnd = TclGetInt4AtPtr(pc+1);
03494         jtPtr = (JumptableInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
03495         TRACE(("%d => %.20s ", opnd, O2S(OBJ_AT_TOS)));
03496         hPtr = Tcl_FindHashEntry(&jtPtr->hashTable, TclGetString(OBJ_AT_TOS));
03497         if (hPtr != NULL) {
03498             int jumpOffset = PTR2INT(Tcl_GetHashValue(hPtr));
03499 
03500             TRACE_APPEND(("found in table, new pc %u\n",
03501                     (unsigned)(pc - codePtr->codeStart + jumpOffset)));
03502             NEXT_INST_F(jumpOffset, 1, 0);
03503         } else {
03504             TRACE_APPEND(("not found in table\n"));
03505             NEXT_INST_F(5, 1, 0);
03506         }
03507     }
03508 
03509     /*
03510      * These two instructions are now redundant: the complete logic of the LOR
03511      * and LAND is now handled by the expression compiler.
03512      */
03513 
03514     case INST_LOR:
03515     case INST_LAND: {
03516         /*
03517          * Operands must be boolean or numeric. No int->double conversions are
03518          * performed.
03519          */
03520 
03521         int i1, i2, iResult;
03522         Tcl_Obj *value2Ptr = OBJ_AT_TOS;
03523         Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
03524 
03525         result = TclGetBooleanFromObj(NULL, valuePtr, &i1);
03526         if (result != TCL_OK) {
03527             TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
03528                     (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
03529             IllegalExprOperandType(interp, pc, valuePtr);
03530             goto checkForCatch;
03531         }
03532 
03533         result = TclGetBooleanFromObj(NULL, value2Ptr, &i2);
03534         if (result != TCL_OK) {
03535             TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(value2Ptr),
03536                     (value2Ptr->typePtr? value2Ptr->typePtr->name : "null")));
03537             IllegalExprOperandType(interp, pc, value2Ptr);
03538             goto checkForCatch;
03539         }
03540 
03541         if (*pc == INST_LOR) {
03542             iResult = (i1 || i2);
03543         } else {
03544             iResult = (i1 && i2);
03545         }
03546         objResultPtr = constants[iResult];
03547         TRACE(("%.20s %.20s => %d\n", O2S(valuePtr),O2S(value2Ptr),iResult));
03548         NEXT_INST_F(1, 2, 1);
03549     }
03550 
03551     /*
03552      * ---------------------------------------------------------
03553      *     Start of INST_LIST and related instructions.
03554      */
03555 
03556     case INST_LIST: {
03557         /*
03558          * Pop the opnd (objc) top stack elements into a new list obj and then
03559          * decrement their ref counts.
03560          */
03561 
03562         int opnd;
03563 
03564         opnd = TclGetUInt4AtPtr(pc+1);
03565         objResultPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1));
03566         TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
03567         NEXT_INST_V(5, opnd, 1);
03568     }
03569 
03570     case INST_LIST_LENGTH: {
03571         Tcl_Obj *valuePtr;
03572         int length;
03573 
03574         valuePtr = OBJ_AT_TOS;
03575 
03576         result = TclListObjLength(interp, valuePtr, &length);
03577         if (result == TCL_OK) {
03578             TclNewIntObj(objResultPtr, length);
03579             TRACE(("%.20s => %d\n", O2S(valuePtr), length));
03580             NEXT_INST_F(1, 1, 1);
03581         } else {
03582             TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
03583                     Tcl_GetObjResult(interp));
03584             goto checkForCatch;
03585         }
03586     }
03587 
03588     case INST_LIST_INDEX: {
03589         /*** lindex with objc == 3 ***/
03590 
03591         /* Variables also for INST_LIST_INDEX_IMM */
03592 
03593         int listc, idx, opnd, pcAdjustment;
03594         Tcl_Obj **listv;
03595         Tcl_Obj *valuePtr, *value2Ptr;
03596 
03597         /*
03598          * Pop the two operands.
03599          */
03600 
03601         value2Ptr = OBJ_AT_TOS;
03602         valuePtr = OBJ_UNDER_TOS;
03603 
03604         /*
03605          * Extract the desired list element.
03606          */
03607 
03608         result = TclListObjGetElements(interp, valuePtr, &listc, &listv);
03609         if ((result == TCL_OK) && (value2Ptr->typePtr != &tclListType)
03610                 && (TclGetIntForIndexM(NULL , value2Ptr, listc-1,
03611                         &idx) == TCL_OK)) {
03612             TclDecrRefCount(value2Ptr);
03613             tosPtr--;
03614             pcAdjustment = 1;
03615             goto lindexFastPath;
03616         }
03617 
03618         objResultPtr = TclLindexList(interp, valuePtr, value2Ptr);
03619         if (objResultPtr) {
03620             /*
03621              * Stash the list element on the stack.
03622              */
03623 
03624             TRACE(("%.20s %.20s => %s\n",
03625                     O2S(valuePtr), O2S(value2Ptr), O2S(objResultPtr)));
03626             NEXT_INST_F(1, 2, -1);      /* Already has the correct refCount */
03627         } else {
03628             TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ", O2S(valuePtr),
03629                     O2S(value2Ptr)), Tcl_GetObjResult(interp));
03630             result = TCL_ERROR;
03631             goto checkForCatch;
03632         }
03633 
03634     case INST_LIST_INDEX_IMM:
03635         /*** lindex with objc==3 and index in bytecode stream ***/
03636 
03637         pcAdjustment = 5;
03638 
03639         /*
03640          * Pop the list and get the index.
03641          */
03642 
03643         valuePtr = OBJ_AT_TOS;
03644         opnd = TclGetInt4AtPtr(pc+1);
03645 
03646         /*
03647          * Get the contents of the list, making sure that it really is a list
03648          * in the process.
03649          */
03650 
03651         result = TclListObjGetElements(interp, valuePtr, &listc, &listv);
03652 
03653         if (result == TCL_OK) {
03654             /*
03655              * Select the list item based on the index. Negative operand means
03656              * end-based indexing.
03657              */
03658 
03659             if (opnd < -1) {
03660                 idx = opnd+1 + listc;
03661             } else {
03662                 idx = opnd;
03663             }
03664 
03665         lindexFastPath:
03666             if (idx >= 0 && idx < listc) {
03667                 objResultPtr = listv[idx];
03668             } else {
03669                 TclNewObj(objResultPtr);
03670             }
03671 
03672             TRACE_WITH_OBJ(("\"%.30s\" %d => ", O2S(valuePtr), opnd),
03673                     objResultPtr);
03674             NEXT_INST_F(pcAdjustment, 1, 1);
03675         } else {
03676             TRACE_WITH_OBJ(("\"%.30s\" %d => ERROR: ", O2S(valuePtr), opnd),
03677                     Tcl_GetObjResult(interp));
03678             goto checkForCatch;
03679         }
03680     }
03681 
03682     case INST_LIST_INDEX_MULTI: {
03683         /*
03684          * 'lindex' with multiple index args:
03685          *
03686          * Determine the count of index args.
03687          */
03688 
03689         int numIdx, opnd;
03690 
03691         opnd = TclGetUInt4AtPtr(pc+1);
03692         numIdx = opnd-1;
03693 
03694         /*
03695          * Do the 'lindex' operation.
03696          */
03697 
03698         objResultPtr = TclLindexFlat(interp, OBJ_AT_DEPTH(numIdx),
03699                 numIdx, &OBJ_AT_DEPTH(numIdx - 1));
03700 
03701         /*
03702          * Check for errors.
03703          */
03704 
03705         if (objResultPtr) {
03706             /*
03707              * Set result.
03708              */
03709 
03710             TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
03711             NEXT_INST_V(5, opnd, -1);
03712         } else {
03713             TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
03714             result = TCL_ERROR;
03715             goto checkForCatch;
03716         }
03717     }
03718 
03719     case INST_LSET_FLAT: {
03720         /*
03721          * Lset with 3, 5, or more args. Get the number of index args.
03722          */
03723 
03724         int numIdx,opnd;
03725         Tcl_Obj *valuePtr, *value2Ptr;
03726 
03727         opnd = TclGetUInt4AtPtr(pc + 1);
03728         numIdx = opnd - 2;
03729 
03730         /*
03731          * Get the old value of variable, and remove the stack ref. This is
03732          * safe because the variable still references the object; the ref
03733          * count will never go zero here - we can use the smaller macro
03734          * Tcl_DecrRefCount.
03735          */
03736 
03737         value2Ptr = POP_OBJECT();
03738         Tcl_DecrRefCount(value2Ptr); /* This one should be done here */
03739 
03740         /*
03741          * Get the new element value.
03742          */
03743 
03744         valuePtr = OBJ_AT_TOS;
03745 
03746         /*
03747          * Compute the new variable value.
03748          */
03749 
03750         objResultPtr = TclLsetFlat(interp, value2Ptr, numIdx,
03751                 &OBJ_AT_DEPTH(numIdx), valuePtr);
03752 
03753         /*
03754          * Check for errors.
03755          */
03756 
03757         if (objResultPtr) {
03758             /*
03759              * Set result.
03760              */
03761 
03762             TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
03763             NEXT_INST_V(5, (numIdx+1), -1);
03764         } else {
03765             TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
03766             result = TCL_ERROR;
03767             goto checkForCatch;
03768         }
03769     }
03770 
03771     case INST_LSET_LIST: {
03772         /*
03773          * 'lset' with 4 args.
03774          */
03775 
03776         Tcl_Obj *objPtr, *valuePtr, *value2Ptr;
03777 
03778         /*
03779          * Get the old value of variable, and remove the stack ref. This is
03780          * safe because the variable still references the object; the ref
03781          * count will never go zero here - we can use the smaller macro
03782          * Tcl_DecrRefCount.
03783          */
03784 
03785         objPtr = POP_OBJECT();
03786         Tcl_DecrRefCount(objPtr);       /* This one should be done here. */
03787 
03788         /*
03789          * Get the new element value, and the index list.
03790          */
03791 
03792         valuePtr = OBJ_AT_TOS;
03793         value2Ptr = OBJ_UNDER_TOS;
03794 
03795         /*
03796          * Compute the new variable value.
03797          */
03798 
03799         objResultPtr = TclLsetList(interp, objPtr, value2Ptr, valuePtr);
03800 
03801         /*
03802          * Check for errors.
03803          */
03804 
03805         if (objResultPtr) {
03806             /*
03807              * Set result.
03808              */
03809 
03810             TRACE(("=> %s\n", O2S(objResultPtr)));
03811             NEXT_INST_F(1, 2, -1);
03812         } else {
03813             TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(value2Ptr)),
03814                     Tcl_GetObjResult(interp));
03815             result = TCL_ERROR;
03816             goto checkForCatch;
03817         }
03818     }
03819 
03820     case INST_LIST_RANGE_IMM: {
03821         /*** lrange with objc==4 and both indices in bytecode stream ***/
03822 
03823         int listc, fromIdx, toIdx;
03824         Tcl_Obj **listv, *valuePtr;
03825 
03826         /*
03827          * Pop the list and get the indices.
03828          */
03829 
03830         valuePtr = OBJ_AT_TOS;
03831         fromIdx = TclGetInt4AtPtr(pc+1);
03832         toIdx = TclGetInt4AtPtr(pc+5);
03833 
03834         /*
03835          * Get the contents of the list, making sure that it really is a list
03836          * in the process.
03837          */
03838         result = TclListObjGetElements(interp, valuePtr, &listc, &listv);
03839 
03840         /*
03841          * Skip a lot of work if we're about to throw the result away (common
03842          * with uses of [lassign]).
03843          */
03844 
03845         if (result == TCL_OK) {
03846 #ifndef TCL_COMPILE_DEBUG
03847             if (*(pc+9) == INST_POP) {
03848                 NEXT_INST_F(10, 1, 0);
03849             }
03850 #endif
03851         } else {
03852             TRACE_WITH_OBJ(("\"%.30s\" %d %d => ERROR: ", O2S(valuePtr),
03853                     fromIdx, toIdx), Tcl_GetObjResult(interp));
03854             goto checkForCatch;
03855         }
03856 
03857         /*
03858          * Adjust the indices for end-based handling.
03859          */
03860 
03861         if (fromIdx < -1) {
03862             fromIdx += 1+listc;
03863             if (fromIdx < -1) {
03864                 fromIdx = -1;
03865             }
03866         } else if (fromIdx > listc) {
03867             fromIdx = listc;
03868         }
03869         if (toIdx < -1) {
03870             toIdx += 1+listc;
03871             if (toIdx < -1) {
03872                 toIdx = -1;
03873             }
03874         } else if (toIdx > listc) {
03875             toIdx = listc;
03876         }
03877 
03878         /*
03879          * Check if we are referring to a valid, non-empty list range, and if
03880          * so, build the list of elements in that range.
03881          */
03882 
03883         if (fromIdx<=toIdx && fromIdx<listc && toIdx>=0) {
03884             if (fromIdx<0) {
03885                 fromIdx = 0;
03886             }
03887             if (toIdx >= listc) {
03888                 toIdx = listc-1;
03889             }
03890             objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, listv+fromIdx);
03891         } else {
03892             TclNewObj(objResultPtr);
03893         }
03894 
03895         TRACE_WITH_OBJ(("\"%.30s\" %d %d => ", O2S(valuePtr),
03896                 TclGetInt4AtPtr(pc+1), TclGetInt4AtPtr(pc+5)), objResultPtr);
03897         NEXT_INST_F(9, 1, 1);
03898     }
03899 
03900     case INST_LIST_IN:
03901     case INST_LIST_NOT_IN: {
03902         /*
03903          * Basic list containment operators.
03904          */
03905 
03906         int found, s1len, s2len, llen, i;
03907         Tcl_Obj *valuePtr, *value2Ptr, *o;
03908         char *s1;
03909         const char *s2;
03910 
03911         value2Ptr = OBJ_AT_TOS;
03912         valuePtr = OBJ_UNDER_TOS;
03913 
03914         /* TODO: Consider more efficient tests than strcmp() */
03915         s1 = TclGetStringFromObj(valuePtr, &s1len);
03916         result = TclListObjLength(interp, value2Ptr, &llen);
03917         if (result != TCL_OK) {
03918             TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ERROR: ", O2S(valuePtr),
03919                     O2S(value2Ptr)), Tcl_GetObjResult(interp));
03920             goto checkForCatch;
03921         }
03922         found = 0;
03923         if (llen > 0) {
03924             /*
03925              * An empty list doesn't match anything.
03926              */
03927 
03928             i = 0;
03929             do {
03930                 Tcl_ListObjIndex(NULL, value2Ptr, i, &o);
03931                 if (o != NULL) {
03932                     s2 = TclGetStringFromObj(o, &s2len);
03933                 } else {
03934                     s2 = "";
03935                 }
03936                 if (s1len == s2len) {
03937                     found = (strcmp(s1, s2) == 0);
03938                 }
03939                 i++;
03940             } while (i < llen && found == 0);
03941         }
03942 
03943         if (*pc == INST_LIST_NOT_IN) {
03944             found = !found;
03945         }
03946 
03947         TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), found));
03948 
03949         /*
03950          * Peep-hole optimisation: if you're about to jump, do jump from here.
03951          * We're saving the effort of pushing a boolean value only to pop it
03952          * for branching.
03953          */
03954 
03955         pc++;
03956 #ifndef TCL_COMPILE_DEBUG
03957         switch (*pc) {
03958         case INST_JUMP_FALSE1:
03959             NEXT_INST_F((found ? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
03960         case INST_JUMP_TRUE1:
03961             NEXT_INST_F((found ? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
03962         case INST_JUMP_FALSE4:
03963             NEXT_INST_F((found ? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
03964         case INST_JUMP_TRUE4:
03965             NEXT_INST_F((found ? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
03966         }
03967 #endif
03968         objResultPtr = constants[found];
03969         NEXT_INST_F(0, 2, 1);
03970     }
03971 
03972     /*
03973      *     End of INST_LIST and related instructions.
03974      * ---------------------------------------------------------
03975      */
03976 
03977     case INST_STR_EQ:
03978     case INST_STR_NEQ: {
03979         /*
03980          * String (in)equality check
03981          * TODO: Consider merging into INST_STR_CMP
03982          */
03983 
03984         int iResult;
03985         Tcl_Obj *valuePtr, *value2Ptr;
03986 
03987         value2Ptr = OBJ_AT_TOS;
03988         valuePtr = OBJ_UNDER_TOS;
03989 
03990         if (valuePtr == value2Ptr) {
03991             /*
03992              * On the off-chance that the objects are the same, we don't
03993              * really have to think hard about equality.
03994              */
03995 
03996             iResult = (*pc == INST_STR_EQ);
03997         } else {
03998             char *s1, *s2;
03999             int s1len, s2len;
04000 
04001             s1 = TclGetStringFromObj(valuePtr, &s1len);
04002             s2 = TclGetStringFromObj(value2Ptr, &s2len);
04003             if (s1len == s2len) {
04004                 /*
04005                  * We only need to check (in)equality when we have equal
04006                  * length strings.
04007                  */
04008 
04009                 if (*pc == INST_STR_NEQ) {
04010                     iResult = (strcmp(s1, s2) != 0);
04011                 } else {
04012                     /* INST_STR_EQ */
04013                     iResult = (strcmp(s1, s2) == 0);
04014                 }
04015             } else {
04016                 iResult = (*pc == INST_STR_NEQ);
04017             }
04018         }
04019 
04020         TRACE(("%.20s %.20s => %d\n", O2S(valuePtr),O2S(value2Ptr),iResult));
04021 
04022         /*
04023          * Peep-hole optimisation: if you're about to jump, do jump from here.
04024          */
04025 
04026         pc++;
04027 #ifndef TCL_COMPILE_DEBUG
04028         switch (*pc) {
04029         case INST_JUMP_FALSE1:
04030             NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
04031         case INST_JUMP_TRUE1:
04032             NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
04033         case INST_JUMP_FALSE4:
04034             NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
04035         case INST_JUMP_TRUE4:
04036             NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
04037         }
04038 #endif
04039         objResultPtr = constants[iResult];
04040         NEXT_INST_F(0, 2, 1);
04041     }
04042 
04043     case INST_STR_CMP: {
04044         /*
04045          * String compare.
04046          */
04047 
04048         const char *s1, *s2;
04049         int s1len, s2len, iResult;
04050         Tcl_Obj *valuePtr, *value2Ptr;
04051 
04052     stringCompare:
04053         value2Ptr = OBJ_AT_TOS;
04054         valuePtr = OBJ_UNDER_TOS;
04055 
04056         /*
04057          * The comparison function should compare up to the minimum byte
04058          * length only.
04059          */
04060 
04061         if (valuePtr == value2Ptr) {
04062             /*
04063              * In the pure equality case, set lengths too for the checks below
04064              * (or we could goto beyond it).
04065              */
04066 
04067             iResult = s1len = s2len = 0;
04068         } else if ((valuePtr->typePtr == &tclByteArrayType)
04069                 && (value2Ptr->typePtr == &tclByteArrayType)) {
04070             s1 = (char *) Tcl_GetByteArrayFromObj(valuePtr, &s1len);
04071             s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
04072             iResult = memcmp(s1, s2,
04073                     (size_t) ((s1len < s2len) ? s1len : s2len));
04074         } else if (((valuePtr->typePtr == &tclStringType)
04075                 && (value2Ptr->typePtr == &tclStringType))) {
04076             /*
04077              * Do a unicode-specific comparison if both of the args are of
04078              * String type. If the char length == byte length, we can do a
04079              * memcmp. In benchmark testing this proved the most efficient
04080              * check between the unicode and string comparison operations.
04081              */
04082 
04083             s1len = Tcl_GetCharLength(valuePtr);
04084             s2len = Tcl_GetCharLength(value2Ptr);
04085             if ((s1len == valuePtr->length) && (s2len == value2Ptr->length)) {
04086                 iResult = memcmp(valuePtr->bytes, value2Ptr->bytes,
04087                         (unsigned) ((s1len < s2len) ? s1len : s2len));
04088             } else {
04089                 iResult = TclUniCharNcmp(Tcl_GetUnicode(valuePtr),
04090                         Tcl_GetUnicode(value2Ptr),
04091                         (unsigned) ((s1len < s2len) ? s1len : s2len));
04092             }
04093         } else {
04094             /*
04095              * We can't do a simple memcmp in order to handle the special Tcl
04096              * \xC0\x80 null encoding for utf-8.
04097              */
04098 
04099             s1 = TclGetStringFromObj(valuePtr, &s1len);
04100             s2 = TclGetStringFromObj(value2Ptr, &s2len);
04101             iResult = TclpUtfNcmp2(s1, s2,
04102                     (size_t) ((s1len < s2len) ? s1len : s2len));
04103         }
04104 
04105         /*
04106          * Make sure only -1,0,1 is returned
04107          * TODO: consider peephole opt.
04108          */
04109 
04110         if (iResult == 0) {
04111             iResult = s1len - s2len;
04112         }
04113 
04114         if (*pc != INST_STR_CMP) {
04115             /*
04116              * Take care of the opcodes that goto'ed into here.
04117              */
04118 
04119             switch (*pc) {
04120             case INST_EQ:
04121                 iResult = (iResult == 0);
04122                 break;
04123             case INST_NEQ:
04124                 iResult = (iResult != 0);
04125                 break;
04126             case INST_LT:
04127                 iResult = (iResult < 0);
04128                 break;
04129             case INST_GT:
04130                 iResult = (iResult > 0);
04131                 break;
04132             case INST_LE:
04133                 iResult = (iResult <= 0);
04134                 break;
04135             case INST_GE:
04136                 iResult = (iResult >= 0);
04137                 break;
04138             }
04139         }
04140         if (iResult < 0) {
04141             TclNewIntObj(objResultPtr, -1);
04142             TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), -1));
04143         } else {
04144             objResultPtr = constants[(iResult>0)];
04145             TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr),
04146                 (iResult > 0)));
04147         }
04148 
04149         NEXT_INST_F(1, 2, 1);
04150     }
04151 
04152     case INST_STR_LEN: {
04153         int length;
04154         Tcl_Obj *valuePtr;
04155 
04156         valuePtr = OBJ_AT_TOS;
04157 
04158         if (valuePtr->typePtr == &tclByteArrayType) {
04159             (void) Tcl_GetByteArrayFromObj(valuePtr, &length);
04160         } else {
04161             length = Tcl_GetCharLength(valuePtr);
04162         }
04163         TclNewIntObj(objResultPtr, length);
04164         TRACE(("%.20s => %d\n", O2S(valuePtr), length));
04165         NEXT_INST_F(1, 1, 1);
04166     }
04167 
04168     case INST_STR_INDEX: {
04169         /*
04170          * String compare.
04171          */
04172 
04173         int index, length;
04174         char *bytes;
04175         Tcl_Obj *valuePtr, *value2Ptr;
04176 
04177         bytes = NULL; /* lint */
04178         value2Ptr = OBJ_AT_TOS;
04179         valuePtr = OBJ_UNDER_TOS;
04180 
04181         /*
04182          * If we have a ByteArray object, avoid indexing in the Utf string
04183          * since the byte array contains one byte per character. Otherwise,
04184          * use the Unicode string rep to get the index'th char.
04185          */
04186 
04187         if (valuePtr->typePtr == &tclByteArrayType) {
04188             bytes = (char *)Tcl_GetByteArrayFromObj(valuePtr, &length);
04189         } else {
04190             /*
04191              * Get Unicode char length to calulate what 'end' means.
04192              */
04193 
04194             length = Tcl_GetCharLength(valuePtr);
04195         }
04196 
04197         result = TclGetIntForIndexM(interp, value2Ptr, length - 1, &index);
04198         if (result != TCL_OK) {
04199             goto checkForCatch;
04200         }
04201 
04202         if ((index >= 0) && (index < length)) {
04203             if (valuePtr->typePtr == &tclByteArrayType) {
04204                 objResultPtr = Tcl_NewByteArrayObj((unsigned char *)
04205                         (&bytes[index]), 1);
04206             } else if (valuePtr->bytes && length == valuePtr->length) {
04207                 objResultPtr = Tcl_NewStringObj((const char *)
04208                         (&valuePtr->bytes[index]), 1);
04209             } else {
04210                 char buf[TCL_UTF_MAX];
04211                 Tcl_UniChar ch;
04212 
04213                 ch = Tcl_GetUniChar(valuePtr, index);
04214 
04215                 /*
04216                  * This could be: Tcl_NewUnicodeObj((const Tcl_UniChar *)&ch,
04217                  * 1) but creating the object as a string seems to be faster
04218                  * in practical use.
04219                  */
04220 
04221                 length = Tcl_UniCharToUtf(ch, buf);
04222                 objResultPtr = Tcl_NewStringObj(buf, length);
04223             }
04224         } else {
04225             TclNewObj(objResultPtr);
04226         }
04227 
04228         TRACE(("%.20s %.20s => %s\n", O2S(valuePtr), O2S(value2Ptr),
04229                 O2S(objResultPtr)));
04230         NEXT_INST_F(1, 2, 1);
04231     }
04232 
04233     case INST_STR_MATCH: {
04234         int nocase, match;
04235         Tcl_Obj *valuePtr, *value2Ptr;
04236 
04237         nocase = TclGetInt1AtPtr(pc+1);
04238         valuePtr = OBJ_AT_TOS;          /* String */
04239         value2Ptr = OBJ_UNDER_TOS;      /* Pattern */
04240 
04241         /*
04242          * Check that at least one of the objects is Unicode before promoting
04243          * both.
04244          */
04245 
04246         if ((valuePtr->typePtr == &tclStringType)
04247                 || (value2Ptr->typePtr == &tclStringType)) {
04248             Tcl_UniChar *ustring1, *ustring2;
04249             int length1, length2;
04250 
04251             ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length1);
04252             ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2);
04253             match = TclUniCharMatch(ustring1, length1, ustring2, length2,
04254                     nocase);
04255         } else if ((valuePtr->typePtr == &tclByteArrayType) && !nocase) {
04256             unsigned char *string1, *string2;
04257             int length1, length2;
04258 
04259             string1 = Tcl_GetByteArrayFromObj(valuePtr, &length1);
04260             string2 = Tcl_GetByteArrayFromObj(value2Ptr, &length2);
04261             match = TclByteArrayMatch(string1, length1, string2, length2, 0);
04262         } else {
04263             match = Tcl_StringCaseMatch(TclGetString(valuePtr),
04264                     TclGetString(value2Ptr), nocase);
04265         }
04266 
04267         /*
04268          * Reuse value2Ptr object already on stack if possible. Adjustment is
04269          * 2 due to the nocase byte
04270          * TODO: consider peephole opt.
04271          */
04272 
04273         TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), match));
04274         objResultPtr = constants[match];
04275         NEXT_INST_F(2, 2, 1);
04276     }
04277 
04278     case INST_REGEXP: {
04279         int cflags, match;
04280         Tcl_Obj *valuePtr, *value2Ptr;
04281         Tcl_RegExp regExpr;
04282 
04283         cflags = TclGetInt1AtPtr(pc+1); /* RE compile flages like NOCASE */
04284         valuePtr = OBJ_AT_TOS;          /* String */
04285         value2Ptr = OBJ_UNDER_TOS;      /* Pattern */
04286 
04287         regExpr = Tcl_GetRegExpFromObj(interp, value2Ptr, cflags);
04288         if (regExpr == NULL) {
04289             match = -1;
04290         } else {
04291             match = Tcl_RegExpExecObj(interp, regExpr, valuePtr, 0, 0, 0);
04292         }
04293 
04294         /*
04295          * Adjustment is 2 due to the nocase byte
04296          */
04297 
04298         if (match < 0) {
04299             objResultPtr = Tcl_GetObjResult(interp);
04300             TRACE_WITH_OBJ(("%.20s %.20s => ERROR: ",
04301                     O2S(valuePtr), O2S(value2Ptr)), objResultPtr);
04302             result = TCL_ERROR;
04303             goto checkForCatch;
04304         } else {
04305             TRACE(("%.20s %.20s => %d\n",
04306                     O2S(valuePtr), O2S(value2Ptr), match));
04307             objResultPtr = constants[match];
04308             NEXT_INST_F(2, 2, 1);
04309         }
04310     }
04311 
04312     case INST_EQ:
04313     case INST_NEQ:
04314     case INST_LT:
04315     case INST_GT:
04316     case INST_LE:
04317     case INST_GE: {
04318         Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
04319         Tcl_Obj *value2Ptr = OBJ_AT_TOS;
04320         ClientData ptr1, ptr2;
04321         int iResult = 0, compare = 0, type1, type2;
04322         double d1, d2, tmp;
04323         long l1, l2;
04324         mp_int big1, big2;
04325 #ifndef NO_WIDE_TYPE
04326         Tcl_WideInt w1, w2;
04327 #endif
04328 
04329         if (GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK) {
04330             /*
04331              * At least one non-numeric argument - compare as strings.
04332              */
04333 
04334             goto stringCompare;
04335         }
04336         if (type1 == TCL_NUMBER_NAN) {
04337             /*
04338              * NaN first arg: NaN != to everything, other compares are false.
04339              */
04340 
04341             iResult = (*pc == INST_NEQ);
04342             goto foundResult;
04343         }
04344         if (valuePtr == value2Ptr) {
04345             compare = MP_EQ;
04346             goto convertComparison;
04347         }
04348         if (GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK) {
04349             /*
04350              * At least one non-numeric argument - compare as strings.
04351              */
04352 
04353             goto stringCompare;
04354         }
04355         if (type2 == TCL_NUMBER_NAN) {
04356             /*
04357              * NaN 2nd arg: NaN != to everything, other compares are false.
04358              */
04359 
04360             iResult = (*pc == INST_NEQ);
04361             goto foundResult;
04362         }
04363         switch (type1) {
04364         case TCL_NUMBER_LONG:
04365             l1 = *((const long *)ptr1);
04366             switch (type2) {
04367             case TCL_NUMBER_LONG:
04368                 l2 = *((const long *)ptr2);
04369             longCompare:
04370                 compare = (l1 < l2) ? MP_LT : ((l1 > l2) ? MP_GT : MP_EQ);
04371                 break;
04372 #ifndef NO_WIDE_TYPE
04373             case TCL_NUMBER_WIDE:
04374                 w2 = *((const Tcl_WideInt *)ptr2);
04375                 w1 = (Tcl_WideInt)l1;
04376                 goto wideCompare;
04377 #endif
04378             case TCL_NUMBER_DOUBLE:
04379                 d2 = *((const double *)ptr2);
04380                 d1 = (double) l1;
04381 
04382                 /*
04383                  * If the double has a fractional part, or if the long can be
04384                  * converted to double without loss of precision, then compare
04385                  * as doubles.
04386                  */
04387 
04388                 if (DBL_MANT_DIG > CHAR_BIT*sizeof(long)
04389                         || l1 == (long) d1
04390                         || modf(d2, &tmp) != 0.0) {
04391                     goto doubleCompare;
04392                 }
04393 
04394                 /*
04395                  * Otherwise, to make comparision based on full precision,
04396                  * need to convert the double to a suitably sized integer.
04397                  *
04398                  * Need this to get comparsions like
04399                  *      expr 20000000000000003 < 20000000000000004.0
04400                  * right. Converting the first argument to double will yield
04401                  * two double values that are equivalent within double
04402                  * precision. Converting the double to an integer gets done
04403                  * exactly, then integer comparison can tell the difference.
04404                  */
04405 
04406                 if (d2 < (double)LONG_MIN) {
04407                     compare = MP_GT;
04408                     break;
04409                 }
04410                 if (d2 > (double)LONG_MAX) {
04411                     compare = MP_LT;
04412                     break;
04413                 }
04414                 l2 = (long) d2;
04415                 goto longCompare;
04416             case TCL_NUMBER_BIG:
04417                 Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
04418                 if (mp_cmp_d(&big2, 0) == MP_LT) {
04419                     compare = MP_GT;
04420                 } else {
04421                     compare = MP_LT;
04422                 }
04423                 mp_clear(&big2);
04424             }
04425             break;
04426 
04427 #ifndef NO_WIDE_TYPE
04428         case TCL_NUMBER_WIDE:
04429             w1 = *((const Tcl_WideInt *)ptr1);
04430             switch (type2) {
04431             case TCL_NUMBER_WIDE:
04432                 w2 = *((const Tcl_WideInt *)ptr2);
04433             wideCompare:
04434                 compare = (w1 < w2) ? MP_LT : ((w1 > w2) ? MP_GT : MP_EQ);
04435                 break;
04436             case TCL_NUMBER_LONG:
04437                 l2 = *((const long *)ptr2);
04438                 w2 = (Tcl_WideInt)l2;
04439                 goto wideCompare;
04440             case TCL_NUMBER_DOUBLE:
04441                 d2 = *((const double *)ptr2);
04442                 d1 = (double) w1;
04443                 if (DBL_MANT_DIG > CHAR_BIT*sizeof(Tcl_WideInt)
04444                         || w1 == (Tcl_WideInt) d1
04445                         || modf(d2, &tmp) != 0.0) {
04446                     goto doubleCompare;
04447                 }
04448                 if (d2 < (double)LLONG_MIN) {
04449                     compare = MP_GT;
04450                     break;
04451                 }
04452                 if (d2 > (double)LLONG_MAX) {
04453                     compare = MP_LT;
04454                     break;
04455                 }
04456                 w2 = (Tcl_WideInt) d2;
04457                 goto wideCompare;
04458             case TCL_NUMBER_BIG:
04459                 Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
04460                 if (mp_cmp_d(&big2, 0) == MP_LT) {
04461                     compare = MP_GT;
04462                 } else {
04463                     compare = MP_LT;
04464                 }
04465                 mp_clear(&big2);
04466             }
04467             break;
04468 #endif
04469 
04470         case TCL_NUMBER_DOUBLE:
04471             d1 = *((const double *)ptr1);
04472             switch (type2) {
04473             case TCL_NUMBER_DOUBLE:
04474                 d2 = *((const double *)ptr2);
04475             doubleCompare:
04476                 compare = (d1 < d2) ? MP_LT : ((d1 > d2) ? MP_GT : MP_EQ);
04477                 break;
04478             case TCL_NUMBER_LONG:
04479                 l2 = *((const long *)ptr2);
04480                 d2 = (double) l2;
04481                 if (DBL_MANT_DIG > CHAR_BIT*sizeof(long)
04482                         || l2 == (long) d2
04483                         || modf(d1, &tmp) != 0.0) {
04484                     goto doubleCompare;
04485                 }
04486                 if (d1 < (double)LONG_MIN) {
04487                     compare = MP_LT;
04488                     break;
04489                 }
04490                 if (d1 > (double)LONG_MAX) {
04491                     compare = MP_GT;
04492                     break;
04493                 }
04494                 l1 = (long) d1;
04495                 goto longCompare;
04496 #ifndef NO_WIDE_TYPE
04497             case TCL_NUMBER_WIDE:
04498                 w2 = *((const Tcl_WideInt *)ptr2);
04499                 d2 = (double) w2;
04500                 if (DBL_MANT_DIG > CHAR_BIT*sizeof(Tcl_WideInt)
04501                         || w2 == (Tcl_WideInt) d2
04502                         || modf(d1, &tmp) != 0.0) {
04503                     goto doubleCompare;
04504                 }
04505                 if (d1 < (double)LLONG_MIN) {
04506                     compare = MP_LT;
04507                     break;
04508                 }
04509                 if (d1 > (double)LLONG_MAX) {
04510                     compare = MP_GT;
04511                     break;
04512                 }
04513                 w1 = (Tcl_WideInt) d1;
04514                 goto wideCompare;
04515 #endif
04516             case TCL_NUMBER_BIG:
04517                 if (TclIsInfinite(d1)) {
04518                     compare = (d1 > 0.0) ? MP_GT : MP_LT;
04519                     break;
04520                 }
04521                 Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
04522                 if ((d1 < (double)LONG_MAX) && (d1 > (double)LONG_MIN)) {
04523                     if (mp_cmp_d(&big2, 0) == MP_LT) {
04524                         compare = MP_GT;
04525                     } else {
04526                         compare = MP_LT;
04527                     }
04528                     mp_clear(&big2);
04529                     break;
04530                 }
04531                 if (DBL_MANT_DIG > CHAR_BIT*sizeof(long)
04532                         && modf(d1, &tmp) != 0.0) {
04533                     d2 = TclBignumToDouble(&big2);
04534                     mp_clear(&big2);
04535                     goto doubleCompare;
04536                 }
04537                 Tcl_InitBignumFromDouble(NULL, d1, &big1);
04538                 goto bigCompare;
04539             }
04540             break;
04541 
04542         case TCL_NUMBER_BIG:
04543             Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
04544             switch (type2) {
04545 #ifndef NO_WIDE_TYPE
04546             case TCL_NUMBER_WIDE:
04547 #endif
04548             case TCL_NUMBER_LONG:
04549                 compare = mp_cmp_d(&big1, 0);
04550                 mp_clear(&big1);
04551                 break;
04552             case TCL_NUMBER_DOUBLE:
04553                 d2 = *((const double *)ptr2);
04554                 if (TclIsInfinite(d2)) {
04555                     compare = (d2 > 0.0) ? MP_LT : MP_GT;
04556                     mp_clear(&big1);
04557                     break;
04558                 }
04559                 if ((d2 < (double)LONG_MAX) && (d2 > (double)LONG_MIN)) {
04560                     compare = mp_cmp_d(&big1, 0);
04561                     mp_clear(&big1);
04562                     break;
04563                 }
04564                 if (DBL_MANT_DIG > CHAR_BIT*sizeof(long)
04565                         && modf(d2, &tmp) != 0.0) {
04566                     d1 = TclBignumToDouble(&big1);
04567                     mp_clear(&big1);
04568                     goto doubleCompare;
04569                 }
04570                 Tcl_InitBignumFromDouble(NULL, d2, &big2);
04571                 goto bigCompare;
04572             case TCL_NUMBER_BIG:
04573                 Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
04574             bigCompare:
04575                 compare = mp_cmp(&big1, &big2);
04576                 mp_clear(&big1);
04577                 mp_clear(&big2);
04578             }
04579         }
04580 
04581         /*
04582          * Turn comparison outcome into appropriate result for opcode.
04583          */
04584 
04585     convertComparison:
04586         switch (*pc) {
04587         case INST_EQ:
04588             iResult = (compare == MP_EQ);
04589             break;
04590         case INST_NEQ:
04591             iResult = (compare != MP_EQ);
04592             break;
04593         case INST_LT:
04594             iResult = (compare == MP_LT);
04595             break;
04596         case INST_GT:
04597             iResult = (compare == MP_GT);
04598             break;
04599         case INST_LE:
04600             iResult = (compare != MP_GT);
04601             break;
04602         case INST_GE:
04603             iResult = (compare != MP_LT);
04604             break;
04605         }
04606 
04607         /*
04608          * Peep-hole optimisation: if you're about to jump, do jump from here.
04609          */
04610 
04611     foundResult:
04612         pc++;
04613 #ifndef TCL_COMPILE_DEBUG
04614         switch (*pc) {
04615         case INST_JUMP_FALSE1:
04616             NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
04617         case INST_JUMP_TRUE1:
04618             NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
04619         case INST_JUMP_FALSE4:
04620             NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
04621         case INST_JUMP_TRUE4:
04622             NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
04623         }
04624 #endif
04625         objResultPtr = constants[iResult];
04626         NEXT_INST_F(0, 2, 1);
04627     }
04628 
04629     case INST_MOD:
04630     case INST_LSHIFT:
04631     case INST_RSHIFT: {
04632         Tcl_Obj *value2Ptr = OBJ_AT_TOS;
04633         Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
04634         ClientData ptr1, ptr2;
04635         int invalid, shift, type1, type2;
04636         long l1 = 0;
04637 
04638         result = GetNumberFromObj(NULL, valuePtr, &ptr1, &type1);
04639         if ((result != TCL_OK) || (type1 == TCL_NUMBER_DOUBLE)
04640                 || (type1 == TCL_NUMBER_NAN)) {
04641             result = TCL_ERROR;
04642             TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr),
04643                     O2S(value2Ptr), (valuePtr->typePtr?
04644                     valuePtr->typePtr->name : "null")));
04645             IllegalExprOperandType(interp, pc, valuePtr);
04646             goto checkForCatch;
04647         }
04648 
04649         result = GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2);
04650         if ((result != TCL_OK) || (type2 == TCL_NUMBER_DOUBLE)
04651                 || (type2 == TCL_NUMBER_NAN)) {
04652             result = TCL_ERROR;
04653             TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr),
04654                     O2S(value2Ptr), (value2Ptr->typePtr?
04655                     value2Ptr->typePtr->name : "null")));
04656             IllegalExprOperandType(interp, pc, value2Ptr);
04657             goto checkForCatch;
04658         }
04659 
04660         if (*pc == INST_MOD) {
04661             /* TODO: Attempts to re-use unshared operands on stack */
04662 
04663             long l2 = 0;        /* silence gcc warning */
04664 
04665             if (type2 == TCL_NUMBER_LONG) {
04666                 l2 = *((const long *)ptr2);
04667                 if (l2 == 0) {
04668                     TRACE(("%s %s => DIVIDE BY ZERO\n", O2S(valuePtr),
04669                             O2S(value2Ptr)));
04670                     goto divideByZero;
04671                 }
04672                 if ((l2 == 1) || (l2 == -1)) {
04673                     /*
04674                      * Div. by |1| always yields remainder of 0.
04675                      */
04676 
04677                     objResultPtr = constants[0];
04678                     TRACE(("%s\n", O2S(objResultPtr)));
04679                     NEXT_INST_F(1, 2, 1);
04680                 }
04681             }
04682             if (type1 == TCL_NUMBER_LONG) {
04683                 l1 = *((const long *)ptr1);
04684                 if (l1 == 0) {
04685                     /*
04686                      * 0 % (non-zero) always yields remainder of 0.
04687                      */
04688 
04689                     objResultPtr = constants[0];
04690                     TRACE(("%s\n", O2S(objResultPtr)));
04691                     NEXT_INST_F(1, 2, 1);
04692                 }
04693                 if (type2 == TCL_NUMBER_LONG) {
04694                     /*
04695                      * Both operands are long; do native calculation.
04696                      */
04697 
04698                     long lRemainder, lQuotient = l1 / l2;
04699 
04700                     /*
04701                      * Force Tcl's integer division rules.
04702                      * TODO: examine for logic simplification
04703                      */
04704 
04705                     if ((lQuotient < 0 || (lQuotient == 0 &&
04706                             ((l1 < 0 && l2 > 0) || (l1 > 0 && l2 < 0)))) &&
04707                             (lQuotient * l2 != l1)) {
04708                         lQuotient -= 1;
04709                     }
04710                     lRemainder = l1 - l2*lQuotient;
04711                     TclNewLongObj(objResultPtr, lRemainder);
04712                     TRACE(("%s\n", O2S(objResultPtr)));
04713                     NEXT_INST_F(1, 2, 1);
04714                 }
04715 
04716                 /*
04717                  * First operand fits in long; second does not, so the second
04718                  * has greater magnitude than first. No need to divide to
04719                  * determine the remainder.
04720                  */
04721 
04722 #ifndef NO_WIDE_TYPE
04723                 if (type2 == TCL_NUMBER_WIDE) {
04724                     Tcl_WideInt w2 = *((const Tcl_WideInt *)ptr2);
04725 
04726                     if ((l1 > 0) ^ (w2 > (Tcl_WideInt)0)) {
04727                         /*
04728                          * Arguments are opposite sign; remainder is sum.
04729                          */
04730 
04731                         objResultPtr = Tcl_NewWideIntObj(w2+(Tcl_WideInt)l1);
04732                         TRACE(("%s\n", O2S(objResultPtr)));
04733                         NEXT_INST_F(1, 2, 1);
04734                     }
04735 
04736                     /*
04737                      * Arguments are same sign; remainder is first operand.
04738                      */
04739 
04740                     TRACE(("%s\n", O2S(valuePtr)));
04741                     NEXT_INST_F(1, 1, 0);
04742                 }
04743 #endif
04744                 {
04745                     mp_int big2;
04746 
04747                     Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
04748 
04749                     /* TODO: internals intrusion */
04750                     if ((l1 > 0) ^ (big2.sign == MP_ZPOS)) {
04751                         /*
04752                          * Arguments are opposite sign; remainder is sum.
04753                          */
04754 
04755                         mp_int big1;
04756 
04757                         TclBNInitBignumFromLong(&big1, l1);
04758                         mp_add(&big2, &big1, &big2);
04759                         mp_clear(&big1);
04760                         objResultPtr = Tcl_NewBignumObj(&big2);
04761                         TRACE(("%s\n", O2S(objResultPtr)));
04762                         NEXT_INST_F(1, 2, 1);
04763                     }
04764 
04765                     /*
04766                      * Arguments are same sign; remainder is first operand.
04767                      */
04768 
04769                     mp_clear(&big2);
04770                     TRACE(("%s\n", O2S(valuePtr)));
04771                     NEXT_INST_F(1, 1, 0);
04772                 }
04773             }
04774 #ifndef NO_WIDE_TYPE
04775             if (type1 == TCL_NUMBER_WIDE) {
04776                 Tcl_WideInt w1 = *((const Tcl_WideInt *)ptr1);
04777 
04778                 if (type2 != TCL_NUMBER_BIG) {
04779                     Tcl_WideInt w2, wQuotient, wRemainder;
04780 
04781                     Tcl_GetWideIntFromObj(NULL, value2Ptr, &w2);
04782                     wQuotient = w1 / w2;
04783 
04784                     /*
04785                      * Force Tcl's integer division rules.
04786                      * TODO: examine for logic simplification
04787                      */
04788 
04789                     if (((wQuotient < (Tcl_WideInt) 0)
04790                             || ((wQuotient == (Tcl_WideInt) 0)
04791                             && ((w1 < (Tcl_WideInt)0 && w2 > (Tcl_WideInt)0)
04792                             || (w1 > (Tcl_WideInt)0 && w2 < (Tcl_WideInt)0))))
04793                             && (wQuotient * w2 != w1)) {
04794                         wQuotient -= (Tcl_WideInt) 1;
04795                     }
04796                     wRemainder = w1 - w2*wQuotient;
04797                     objResultPtr = Tcl_NewWideIntObj(wRemainder);
04798                     TRACE(("%s\n", O2S(objResultPtr)));
04799                     NEXT_INST_F(1, 2, 1);
04800                 }
04801                 {
04802                     mp_int big2;
04803                     Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
04804 
04805                     /* TODO: internals intrusion */
04806                     if ((w1 > ((Tcl_WideInt) 0)) ^ (big2.sign == MP_ZPOS)) {
04807                         /*
04808                          * Arguments are opposite sign; remainder is sum.
04809                          */
04810 
04811                         mp_int big1;
04812 
04813                         TclBNInitBignumFromWideInt(&big1, w1);
04814                         mp_add(&big2, &big1, &big2);
04815                         mp_clear(&big1);
04816                         objResultPtr = Tcl_NewBignumObj(&big2);
04817                         TRACE(("%s\n", O2S(objResultPtr)));
04818                         NEXT_INST_F(1, 2, 1);
04819                     }
04820 
04821                     /*
04822                      * Arguments are same sign; remainder is first operand.
04823                      */
04824 
04825                     mp_clear(&big2);
04826                     TRACE(("%s\n", O2S(valuePtr)));
04827                     NEXT_INST_F(1, 1, 0);
04828                 }
04829             }
04830 #endif
04831             {
04832                 mp_int big1, big2, bigResult, bigRemainder;
04833 
04834                 Tcl_GetBignumFromObj(NULL, valuePtr, &big1);
04835                 Tcl_GetBignumFromObj(NULL, value2Ptr, &big2);
04836                 mp_init(&bigResult);
04837                 mp_init(&bigRemainder);
04838                 mp_div(&big1, &big2, &bigResult, &bigRemainder);
04839                 if (!mp_iszero(&bigRemainder)
04840                         && (bigRemainder.sign != big2.sign)) {
04841                     /*
04842                      * Convert to Tcl's integer division rules.
04843                      */
04844 
04845                     mp_sub_d(&bigResult, 1, &bigResult);
04846                     mp_add(&bigRemainder, &big2, &bigRemainder);
04847                 }
04848                 mp_copy(&bigRemainder, &bigResult);
04849                 mp_clear(&bigRemainder);
04850                 mp_clear(&big1);
04851                 mp_clear(&big2);
04852                 TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
04853                 if (Tcl_IsShared(valuePtr)) {
04854                     objResultPtr = Tcl_NewBignumObj(&bigResult);
04855                     TRACE(("%s\n", O2S(objResultPtr)));
04856                     NEXT_INST_F(1, 2, 1);
04857                 }
04858                 Tcl_SetBignumObj(valuePtr, &bigResult);
04859                 TRACE(("%s\n", O2S(valuePtr)));
04860                 NEXT_INST_F(1, 1, 0);
04861             }
04862         }
04863 
04864         /*
04865          * Reject negative shift argument.
04866          */
04867 
04868         switch (type2) {
04869         case TCL_NUMBER_LONG:
04870             invalid = (*((const long *)ptr2) < (long)0);
04871             break;
04872 #ifndef NO_WIDE_TYPE
04873         case TCL_NUMBER_WIDE:
04874             invalid = (*((const Tcl_WideInt *)ptr2) < (Tcl_WideInt)0);
04875             break;
04876 #endif
04877         case TCL_NUMBER_BIG: {
04878             mp_int big2;
04879 
04880             Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
04881             invalid = (mp_cmp_d(&big2, 0) == MP_LT);
04882             mp_clear(&big2);
04883             break;
04884         }
04885         default:
04886             /* Unused, here to silence compiler warning */
04887             invalid = 0;
04888         }
04889         if (invalid) {
04890             Tcl_SetObjResult(interp,
04891                     Tcl_NewStringObj("negative shift argument", -1));
04892             result = TCL_ERROR;
04893             goto checkForCatch;
04894         }
04895 
04896         /*
04897          * Zero shifted any number of bits is still zero.
04898          */
04899 
04900         if ((type1==TCL_NUMBER_LONG) && (*((const long *)ptr1) == (long)0)) {
04901             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
04902             objResultPtr = constants[0];
04903             TRACE(("%s\n", O2S(objResultPtr)));
04904             NEXT_INST_F(1, 2, 1);
04905         }
04906 
04907         if (*pc == INST_LSHIFT) {
04908             /*
04909              * Large left shifts create integer overflow.
04910              *
04911              * BEWARE! Can't use Tcl_GetIntFromObj() here because that
04912              * converts values in the (unsigned) range to their signed int
04913              * counterparts, leading to incorrect results.
04914              */
04915 
04916             if ((type2 != TCL_NUMBER_LONG)
04917                     || (*((const long *)ptr2) > (long) INT_MAX)) {
04918                 /*
04919                  * Technically, we could hold the value (1 << (INT_MAX+1)) in
04920                  * an mp_int, but since we're using mp_mul_2d() to do the
04921                  * work, and it takes only an int argument, that's a good
04922                  * place to draw the line.
04923                  */
04924 
04925                 Tcl_SetObjResult(interp, Tcl_NewStringObj(
04926                         "integer value too large to represent", -1));
04927                 result = TCL_ERROR;
04928                 goto checkForCatch;
04929             }
04930             shift = (int)(*((const long *)ptr2));
04931 
04932             /*
04933              * Handle shifts within the native long range.
04934              */
04935 
04936             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
04937             if ((type1 == TCL_NUMBER_LONG)
04938                     && (size_t) shift < CHAR_BIT*sizeof(long)
04939                     && ((l1 = *(const long *)ptr1) != 0)
04940                     && !((l1>0 ? l1 : ~l1)
04941                             & -(1L<<(CHAR_BIT*sizeof(long) - 1 - shift)))) {
04942                 TclNewLongObj(objResultPtr, (l1<<shift));
04943                 TRACE(("%s\n", O2S(objResultPtr)));
04944                 NEXT_INST_F(1, 2, 1);
04945             }
04946 
04947             /*
04948              * Handle shifts within the native wide range.
04949              */
04950 
04951             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
04952             if ((type1 != TCL_NUMBER_BIG)
04953                     && ((size_t)shift < CHAR_BIT*sizeof(Tcl_WideInt))) {
04954                 Tcl_WideInt w;
04955 
04956                 TclGetWideIntFromObj(NULL, valuePtr, &w);
04957                 if (!((w>0 ? w : ~w)
04958                         & -(((Tcl_WideInt)1)
04959                         << (CHAR_BIT*sizeof(Tcl_WideInt) - 1 - shift)))) {
04960                     objResultPtr = Tcl_NewWideIntObj(w<<shift);
04961                     TRACE(("%s\n", O2S(objResultPtr)));
04962                     NEXT_INST_F(1, 2, 1);
04963                 }
04964             }
04965         } else {
04966             /*
04967              * Quickly force large right shifts to 0 or -1.
04968              */
04969 
04970             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
04971             if ((type2 != TCL_NUMBER_LONG)
04972                     || (*(const long *)ptr2 > INT_MAX)) {
04973                 /*
04974                  * Again, technically, the value to be shifted could be an
04975                  * mp_int so huge that a right shift by (INT_MAX+1) bits could
04976                  * not take us to the result of 0 or -1, but since we're using
04977                  * mp_div_2d to do the work, and it takes only an int
04978                  * argument, we draw the line there.
04979                  */
04980 
04981                 int zero;
04982 
04983                 switch (type1) {
04984                 case TCL_NUMBER_LONG:
04985                     zero = (*(const long *)ptr1 > 0L);
04986                     break;
04987 #ifndef NO_WIDE_TYPE
04988                 case TCL_NUMBER_WIDE:
04989                     zero = (*(const Tcl_WideInt *)ptr1 > (Tcl_WideInt)0);
04990                     break;
04991 #endif
04992                 case TCL_NUMBER_BIG: {
04993                     mp_int big1;
04994                     Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
04995                     zero = (mp_cmp_d(&big1, 0) == MP_GT);
04996                     mp_clear(&big1);
04997                     break;
04998                 }
04999                 default:
05000                     /* Unused, here to silence compiler warning. */
05001                     zero = 0;
05002                 }
05003                 if (zero) {
05004                     objResultPtr = constants[0];
05005                 } else {
05006                     TclNewIntObj(objResultPtr, -1);
05007                 }
05008                 TRACE(("%s\n", O2S(objResultPtr)));
05009                 NEXT_INST_F(1, 2, 1);
05010             }
05011             shift = (int)(*(const long *)ptr2);
05012 
05013             /*
05014              * Handle shifts within the native long range.
05015              */
05016 
05017             if (type1 == TCL_NUMBER_LONG) {
05018                 l1 = *((const long *)ptr1);
05019                 if ((size_t)shift >= CHAR_BIT*sizeof(long)) {
05020                     if (l1 >= (long)0) {
05021                         objResultPtr = constants[0];
05022                     } else {
05023                         TclNewIntObj(objResultPtr, -1);
05024                     }
05025                 } else {
05026                     TclNewLongObj(objResultPtr, (l1 >> shift));
05027                 }
05028                 TRACE(("%s\n", O2S(objResultPtr)));
05029                 NEXT_INST_F(1, 2, 1);
05030             }
05031 
05032 #ifndef NO_WIDE_TYPE
05033             /*
05034              * Handle shifts within the native wide range.
05035              */
05036 
05037             if (type1 == TCL_NUMBER_WIDE) {
05038                 Tcl_WideInt w = *(const Tcl_WideInt *)ptr1;
05039 
05040                 if ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideInt)) {
05041                     if (w >= (Tcl_WideInt)0) {
05042                         objResultPtr = constants[0];
05043                     } else {
05044                         TclNewIntObj(objResultPtr, -1);
05045                     }
05046                 } else {
05047                     objResultPtr = Tcl_NewWideIntObj(w >> shift);
05048                 }
05049                 TRACE(("%s\n", O2S(objResultPtr)));
05050                 NEXT_INST_F(1, 2, 1);
05051             }
05052 #endif
05053         }
05054 
05055         {
05056             mp_int big, bigResult, bigRemainder;
05057 
05058             Tcl_TakeBignumFromObj(NULL, valuePtr, &big);
05059 
05060             mp_init(&bigResult);
05061             if (*pc == INST_LSHIFT) {
05062                 mp_mul_2d(&big, shift, &bigResult);
05063             } else {
05064                 mp_init(&bigRemainder);
05065                 mp_div_2d(&big, shift, &bigResult, &bigRemainder);
05066                 if (mp_cmp_d(&bigRemainder, 0) == MP_LT) {
05067                     /*
05068                      * Convert to Tcl's integer division rules.
05069                      */
05070 
05071                     mp_sub_d(&bigResult, 1, &bigResult);
05072                 }
05073                 mp_clear(&bigRemainder);
05074             }
05075             mp_clear(&big);
05076 
05077             if (!Tcl_IsShared(valuePtr)) {
05078                 Tcl_SetBignumObj(valuePtr, &bigResult);
05079                 TRACE(("%s\n", O2S(valuePtr)));
05080                 NEXT_INST_F(1, 1, 0);
05081             }
05082             objResultPtr = Tcl_NewBignumObj(&bigResult);
05083         }
05084         TRACE(("%s\n", O2S(objResultPtr)));
05085         NEXT_INST_F(1, 2, 1);
05086     }
05087 
05088     case INST_BITOR:
05089     case INST_BITXOR:
05090     case INST_BITAND: {
05091         ClientData ptr1, ptr2;
05092         int type1, type2;
05093         Tcl_Obj *value2Ptr = OBJ_AT_TOS;
05094         Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
05095 
05096         result = GetNumberFromObj(NULL, valuePtr, &ptr1, &type1);
05097         if ((result != TCL_OK)
05098                 || (type1 == TCL_NUMBER_NAN)
05099                 || (type1 == TCL_NUMBER_DOUBLE)) {
05100             result = TCL_ERROR;
05101             TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr),
05102                     O2S(value2Ptr), (valuePtr->typePtr?
05103                     valuePtr->typePtr->name : "null")));
05104             IllegalExprOperandType(interp, pc, valuePtr);
05105             goto checkForCatch;
05106         }
05107         result = GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2);
05108         if ((result != TCL_OK) || (type2 == TCL_NUMBER_NAN)
05109                 || (type2 == TCL_NUMBER_DOUBLE)) {
05110             result = TCL_ERROR;
05111             TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr),
05112                     O2S(value2Ptr), (value2Ptr->typePtr?
05113                     value2Ptr->typePtr->name : "null")));
05114             IllegalExprOperandType(interp, pc, value2Ptr);
05115             goto checkForCatch;
05116         }
05117 
05118         if ((type1 == TCL_NUMBER_BIG) || (type2 == TCL_NUMBER_BIG)) {
05119             mp_int big1, big2, bigResult, *First, *Second;
05120             int numPos;
05121 
05122             Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
05123             Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
05124 
05125             /*
05126              * Count how many positive arguments we have. If only one of the
05127              * arguments is negative, store it in 'Second'.
05128              */
05129 
05130             if (mp_cmp_d(&big1, 0) != MP_LT) {
05131                 numPos = 1 + (mp_cmp_d(&big2, 0) != MP_LT);
05132                 First = &big1;
05133                 Second = &big2;
05134             } else {
05135                 First = &big2;
05136                 Second = &big1;
05137                 numPos = (mp_cmp_d(First, 0) != MP_LT);
05138             }
05139             mp_init(&bigResult);
05140 
05141             switch (*pc) {
05142             case INST_BITAND:
05143                 switch (numPos) {
05144                 case 2:
05145                     /*
05146                      * Both arguments positive, base case.
05147                      */
05148 
05149                     mp_and(First, Second, &bigResult);
05150                     break;
05151                 case 1:
05152                     /*
05153                      * First is positive; second negative:
05154                      * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1))
05155                      */
05156 
05157                     mp_neg(Second, Second);
05158                     mp_sub_d(Second, 1, Second);
05159                     mp_xor(First, Second, &bigResult);
05160                     mp_and(First, &bigResult, &bigResult);
05161                     break;
05162                 case 0:
05163                     /*
05164                      * Both arguments negative:
05165                      * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1
05166                      */
05167 
05168                     mp_neg(First, First);
05169                     mp_sub_d(First, 1, First);
05170                     mp_neg(Second, Second);
05171                     mp_sub_d(Second, 1, Second);
05172                     mp_or(First, Second, &bigResult);
05173                     mp_neg(&bigResult, &bigResult);
05174                     mp_sub_d(&bigResult, 1, &bigResult);
05175                     break;
05176                 }
05177                 break;
05178 
05179             case INST_BITOR:
05180                 switch (numPos) {
05181                 case 2:
05182                     /*
05183                      * Both arguments positive, base case.
05184                      */
05185 
05186                     mp_or(First, Second, &bigResult);
05187                     break;
05188                 case 1:
05189                     /*
05190                      * First is positive; second negative:
05191                      * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1
05192                      */
05193 
05194                     mp_neg(Second, Second);
05195                     mp_sub_d(Second, 1, Second);
05196                     mp_xor(First, Second, &bigResult);
05197                     mp_and(Second, &bigResult, &bigResult);
05198                     mp_neg(&bigResult, &bigResult);
05199                     mp_sub_d(&bigResult, 1, &bigResult);
05200                     break;
05201                 case 0:
05202                     /*
05203                      * Both arguments negative:
05204                      * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1
05205                      */
05206 
05207                     mp_neg(First, First);
05208                     mp_sub_d(First, 1, First);
05209                     mp_neg(Second, Second);
05210                     mp_sub_d(Second, 1, Second);
05211                     mp_and(First, Second, &bigResult);
05212                     mp_neg(&bigResult, &bigResult);
05213                     mp_sub_d(&bigResult, 1, &bigResult);
05214                     break;
05215                 }
05216                 break;
05217 
05218             case INST_BITXOR:
05219                 switch (numPos) {
05220                 case 2:
05221                     /*
05222                      * Both arguments positive, base case.
05223                      */
05224 
05225                     mp_xor(First, Second, &bigResult);
05226                     break;
05227                 case 1:
05228                     /*
05229                      * First is positive; second negative:
05230                      * P^N = ~(P^~N) = -(P^(-N-1))-1
05231                      */
05232 
05233                     mp_neg(Second, Second);
05234                     mp_sub_d(Second, 1, Second);
05235                     mp_xor(First, Second, &bigResult);
05236                     mp_neg(&bigResult, &bigResult);
05237                     mp_sub_d(&bigResult, 1, &bigResult);
05238                     break;
05239                 case 0:
05240                     /*
05241                      * Both arguments negative:
05242                      * a ^ b = (~a ^ ~b) = (-a-1^-b-1)
05243                      */
05244 
05245                     mp_neg(First, First);
05246                     mp_sub_d(First, 1, First);
05247                     mp_neg(Second, Second);
05248                     mp_sub_d(Second, 1, Second);
05249                     mp_xor(First, Second, &bigResult);
05250                     break;
05251                 }
05252                 break;
05253             }
05254 
05255             mp_clear(&big1);
05256             mp_clear(&big2);
05257             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05258             if (Tcl_IsShared(valuePtr)) {
05259                 objResultPtr = Tcl_NewBignumObj(&bigResult);
05260                 TRACE(("%s\n", O2S(objResultPtr)));
05261                 NEXT_INST_F(1, 2, 1);
05262             }
05263             Tcl_SetBignumObj(valuePtr, &bigResult);
05264             TRACE(("%s\n", O2S(valuePtr)));
05265             NEXT_INST_F(1, 1, 0);
05266         }
05267 
05268 #ifndef NO_WIDE_TYPE
05269         if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE)) {
05270             Tcl_WideInt wResult, w1, w2;
05271 
05272             TclGetWideIntFromObj(NULL, valuePtr, &w1);
05273             TclGetWideIntFromObj(NULL, value2Ptr, &w2);
05274 
05275             switch (*pc) {
05276             case INST_BITAND:
05277                 wResult = w1 & w2;
05278                 break;
05279             case INST_BITOR:
05280                 wResult = w1 | w2;
05281                 break;
05282             case INST_BITXOR:
05283                 wResult = w1 ^ w2;
05284                 break;
05285             default:
05286                 /* Unused, here to silence compiler warning. */
05287                 wResult = 0;
05288             }
05289 
05290             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05291             if (Tcl_IsShared(valuePtr)) {
05292                 objResultPtr = Tcl_NewWideIntObj(wResult);
05293                 TRACE(("%s\n", O2S(objResultPtr)));
05294                 NEXT_INST_F(1, 2, 1);
05295             }
05296             Tcl_SetWideIntObj(valuePtr, wResult);
05297             TRACE(("%s\n", O2S(valuePtr)));
05298             NEXT_INST_F(1, 1, 0);
05299         }
05300 #endif
05301         {
05302             long lResult, l1 = *((const long *)ptr1);
05303             long l2 = *((const long *)ptr2);
05304 
05305             switch (*pc) {
05306             case INST_BITAND:
05307                 lResult = l1 & l2;
05308                 break;
05309             case INST_BITOR:
05310                 lResult = l1 | l2;
05311                 break;
05312             case INST_BITXOR:
05313                 lResult = l1 ^ l2;
05314                 break;
05315             default:
05316                 /* Unused, here to silence compiler warning. */
05317                 lResult = 0;
05318             }
05319 
05320             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05321             if (Tcl_IsShared(valuePtr)) {
05322                 TclNewLongObj(objResultPtr, lResult);
05323                 TRACE(("%s\n", O2S(objResultPtr)));
05324                 NEXT_INST_F(1, 2, 1);
05325             }
05326             TclSetLongObj(valuePtr, lResult);
05327             TRACE(("%s\n", O2S(valuePtr)));
05328             NEXT_INST_F(1, 1, 0);
05329         }
05330     }
05331 
05332     case INST_EXPON:
05333     case INST_ADD:
05334     case INST_SUB:
05335     case INST_DIV:
05336     case INST_MULT: {
05337         ClientData ptr1, ptr2;
05338         int type1, type2;
05339         Tcl_Obj *value2Ptr = OBJ_AT_TOS;
05340         Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
05341 
05342         result = GetNumberFromObj(NULL, valuePtr, &ptr1, &type1);
05343         if ((result != TCL_OK)
05344 #ifndef ACCEPT_NAN
05345                 || (type1 == TCL_NUMBER_NAN)
05346 #endif
05347                 ) {
05348             result = TCL_ERROR;
05349             TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n",
05350                     O2S(value2Ptr), O2S(valuePtr),
05351                     (valuePtr->typePtr? valuePtr->typePtr->name: "null")));
05352             IllegalExprOperandType(interp, pc, valuePtr);
05353             goto checkForCatch;
05354         }
05355 
05356 #ifdef ACCEPT_NAN
05357         if (type1 == TCL_NUMBER_NAN) {
05358             /*
05359              * NaN first argument -> result is also NaN.
05360              */
05361 
05362             NEXT_INST_F(1, 1, 0);
05363         }
05364 #endif
05365 
05366         result = GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2);
05367         if ((result != TCL_OK)
05368 #ifndef ACCEPT_NAN
05369                 || (type2 == TCL_NUMBER_NAN)
05370 #endif
05371                 ) {
05372             result = TCL_ERROR;
05373             TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n",
05374                     O2S(value2Ptr), O2S(valuePtr),
05375                     (value2Ptr->typePtr? value2Ptr->typePtr->name: "null")));
05376             IllegalExprOperandType(interp, pc, value2Ptr);
05377             goto checkForCatch;
05378         }
05379 
05380 #ifdef ACCEPT_NAN
05381         if (type2 == TCL_NUMBER_NAN) {
05382             /*
05383              * NaN second argument -> result is also NaN.
05384              */
05385 
05386             objResultPtr = value2Ptr;
05387             NEXT_INST_F(1, 2, 1);
05388         }
05389 #endif
05390 
05391         if ((type1 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_DOUBLE)) {
05392             /*
05393              * At least one of the values is floating-point, so perform
05394              * floating point calculations.
05395              */
05396 
05397             double d1, d2, dResult;
05398 
05399             Tcl_GetDoubleFromObj(NULL, valuePtr, &d1);
05400             Tcl_GetDoubleFromObj(NULL, value2Ptr, &d2);
05401 
05402             switch (*pc) {
05403             case INST_ADD:
05404                 dResult = d1 + d2;
05405                 break;
05406             case INST_SUB:
05407                 dResult = d1 - d2;
05408                 break;
05409             case INST_MULT:
05410                 dResult = d1 * d2;
05411                 break;
05412             case INST_DIV:
05413 #ifndef IEEE_FLOATING_POINT
05414                 if (d2 == 0.0) {
05415                     TRACE(("%.6g %.6g => DIVIDE BY ZERO\n", d1, d2));
05416                     goto divideByZero;
05417                 }
05418 #endif
05419                 /*
05420                  * We presume that we are running with zero-divide unmasked if
05421                  * we're on an IEEE box. Otherwise, this statement might cause
05422                  * demons to fly out our noses.
05423                  */
05424 
05425                 dResult = d1 / d2;
05426                 break;
05427             case INST_EXPON:
05428                 if (d1==0.0 && d2<0.0) {
05429                     TRACE(("%.6g %.6g => EXPONENT OF ZERO\n", d1, d2));
05430                     goto exponOfZero;
05431                 }
05432                 dResult = pow(d1, d2);
05433                 break;
05434             default:
05435                 /* Unused, here to silence compiler warning. */
05436                 dResult = 0;
05437             }
05438 
05439 #ifndef ACCEPT_NAN
05440             /*
05441              * Check now for IEEE floating-point error.
05442              */
05443 
05444             if (TclIsNaN(dResult)) {
05445                 TRACE(("%.20s %.20s => IEEE FLOATING PT ERROR\n",
05446                         O2S(valuePtr), O2S(value2Ptr)));
05447                 TclExprFloatError(interp, dResult);
05448                 result = TCL_ERROR;
05449                 goto checkForCatch;
05450             }
05451 #endif
05452             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05453             if (Tcl_IsShared(valuePtr)) {
05454                 TclNewDoubleObj(objResultPtr, dResult);
05455                 TRACE(("%s\n", O2S(objResultPtr)));
05456                 NEXT_INST_F(1, 2, 1);
05457             }
05458             TclSetDoubleObj(valuePtr, dResult);
05459             TRACE(("%s\n", O2S(valuePtr)));
05460             NEXT_INST_F(1, 1, 0);
05461         }
05462 
05463         if ((sizeof(long) >= 2*sizeof(int)) && (*pc == INST_MULT)
05464                 && (type1 == TCL_NUMBER_LONG) && (type2 == TCL_NUMBER_LONG)) {
05465             long l1 = *((const long *)ptr1);
05466             long l2 = *((const long *)ptr2);
05467 
05468             if ((l1 <= INT_MAX) && (l1 >= INT_MIN)
05469                     && (l2 <= INT_MAX) && (l2 >= INT_MIN)) {
05470                 long lResult = l1 * l2;
05471 
05472                 TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05473                 if (Tcl_IsShared(valuePtr)) {
05474                     TclNewLongObj(objResultPtr,lResult);
05475                     TRACE(("%s\n", O2S(objResultPtr)));
05476                     NEXT_INST_F(1, 2, 1);
05477                 }
05478                 TclSetLongObj(valuePtr, lResult);
05479                 TRACE(("%s\n", O2S(valuePtr)));
05480                 NEXT_INST_F(1, 1, 0);
05481             }
05482         }
05483 
05484         if ((sizeof(Tcl_WideInt) >= 2*sizeof(long)) && (*pc == INST_MULT)
05485                 && (type1 == TCL_NUMBER_LONG) && (type2 == TCL_NUMBER_LONG)) {
05486             Tcl_WideInt w1, w2, wResult;
05487             TclGetWideIntFromObj(NULL, valuePtr, &w1);
05488             TclGetWideIntFromObj(NULL, value2Ptr, &w2);
05489 
05490             wResult = w1 * w2;
05491 
05492             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05493             if (Tcl_IsShared(valuePtr)) {
05494                 objResultPtr = Tcl_NewWideIntObj(wResult);
05495                 TRACE(("%s\n", O2S(objResultPtr)));
05496                 NEXT_INST_F(1, 2, 1);
05497             }
05498             Tcl_SetWideIntObj(valuePtr, wResult);
05499             TRACE(("%s\n", O2S(valuePtr)));
05500             NEXT_INST_F(1, 1, 0);
05501         }
05502 
05503         /* TODO: Attempts to re-use unshared operands on stack. */
05504         if (*pc == INST_EXPON) {
05505             long l1 = 0, l2 = 0;
05506             Tcl_WideInt w1;
05507             int oddExponent = 0, negativeExponent = 0;
05508 
05509             if (type2 == TCL_NUMBER_LONG) {
05510                 l2 = *((const long *) ptr2);
05511                 if (l2 == 0) {
05512                     /*
05513                      * Anything to the zero power is 1.
05514                      */
05515 
05516                     objResultPtr = constants[1];
05517                     NEXT_INST_F(1, 2, 1);
05518                 } else if (l2 == 1) {
05519                     /*
05520                      * Anything to the first power is itself
05521                      */
05522                     NEXT_INST_F(1, 1, 0);
05523                 }
05524             }
05525 
05526             switch (type2) {
05527             case TCL_NUMBER_LONG: {
05528                 negativeExponent = (l2 < 0);
05529                 oddExponent = (int) (l2 & 1);
05530                 break;
05531             }
05532 #ifndef NO_WIDE_TYPE
05533             case TCL_NUMBER_WIDE: {
05534                 Tcl_WideInt w2 = *((const Tcl_WideInt *)ptr2);
05535 
05536                 negativeExponent = (w2 < 0);
05537                 oddExponent = (int) (w2 & (Tcl_WideInt)1);
05538                 break;
05539             }
05540 #endif
05541             case TCL_NUMBER_BIG: {
05542                 mp_int big2;
05543 
05544                 Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
05545                 negativeExponent = (mp_cmp_d(&big2, 0) == MP_LT);
05546                 mp_mod_2d(&big2, 1, &big2);
05547                 oddExponent = !mp_iszero(&big2);
05548                 mp_clear(&big2);
05549                 break;
05550             }
05551             }
05552 
05553             if (negativeExponent) {
05554                 if (type1 == TCL_NUMBER_LONG) {
05555                     l1 = *((const long *)ptr1);
05556                     switch (l1) {
05557                     case 0:
05558                         /*
05559                          * Zero to a negative power is div by zero error.
05560                          */
05561 
05562                         TRACE(("%s %s => EXPONENT OF ZERO\n", O2S(valuePtr),
05563                                 O2S(value2Ptr)));
05564                         goto exponOfZero;
05565                     case -1:
05566                         if (oddExponent) {
05567                             TclNewIntObj(objResultPtr, -1);
05568                         } else {
05569                             objResultPtr = constants[1];
05570                         }
05571                         NEXT_INST_F(1, 2, 1);
05572                     case 1:
05573                         /*
05574                          * 1 to any power is 1.
05575                          */
05576 
05577                         objResultPtr = constants[1];
05578                         NEXT_INST_F(1, 2, 1);
05579                     }
05580                 }
05581 
05582                 /*
05583                  * Integers with magnitude greater than 1 raise to a negative
05584                  * power yield the answer zero (see TIP 123).
05585                  */
05586 
05587                 objResultPtr = constants[0];
05588                 NEXT_INST_F(1, 2, 1);
05589             }
05590 
05591             if (type1 == TCL_NUMBER_LONG) {
05592                 l1 = *((const long *)ptr1);
05593                 switch (l1) {
05594                 case 0:
05595                     /*
05596                      * Zero to a positive power is zero.
05597                      */
05598 
05599                     objResultPtr = constants[0];
05600                     NEXT_INST_F(1, 2, 1);
05601                 case 1:
05602                     /*
05603                      * 1 to any power is 1.
05604                      */
05605 
05606                     objResultPtr = constants[1];
05607                     NEXT_INST_F(1, 2, 1);
05608                 case -1:
05609                     if (oddExponent) {
05610                         TclNewIntObj(objResultPtr, -1);
05611                     } else {
05612                         objResultPtr = constants[1];
05613                     }
05614                     NEXT_INST_F(1, 2, 1);
05615                 }
05616             }
05617             if (type2 == TCL_NUMBER_BIG) {
05618                 Tcl_SetObjResult(interp,
05619                         Tcl_NewStringObj("exponent too large", -1));
05620                 result = TCL_ERROR;
05621                 goto checkForCatch;
05622             }
05623 
05624             if (type1 == TCL_NUMBER_LONG && type2 == TCL_NUMBER_LONG) {
05625                 if (l1 == 2) {
05626                     /*
05627                      * Reduce small powers of 2 to shifts.
05628                      */
05629 
05630                     if ((unsigned long) l2 < CHAR_BIT * sizeof(long) - 1) {
05631                         TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05632                         TclNewLongObj(objResultPtr, (1L << l2));
05633                         TRACE(("%s\n", O2S(objResultPtr)));
05634                         NEXT_INST_F(1, 2, 1);
05635                     }
05636 #if !defined(TCL_WIDE_INT_IS_LONG)
05637                     if ((unsigned long)l2 < CHAR_BIT*sizeof(Tcl_WideInt) - 1){
05638                         TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05639                         objResultPtr =
05640                                 Tcl_NewWideIntObj(((Tcl_WideInt) 1) << l2);
05641                         TRACE(("%s\n", O2S(objResultPtr)));
05642                         NEXT_INST_F(1, 2, 1);
05643                     }
05644 #endif
05645                 }
05646                 if (l1 == -2) {
05647                     int signum = oddExponent ? -1 : 1;
05648 
05649                     /*
05650                      * Reduce small powers of 2 to shifts.
05651                      */
05652 
05653                     if ((unsigned long) l2 < CHAR_BIT * sizeof(long) - 1) {
05654                         TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05655                         TclNewLongObj(objResultPtr, signum * (1L << l2));
05656                         TRACE(("%s\n", O2S(objResultPtr)));
05657                         NEXT_INST_F(1, 2, 1);
05658                     }
05659 #if !defined(TCL_WIDE_INT_IS_LONG)
05660                     if ((unsigned long)l2 < CHAR_BIT*sizeof(Tcl_WideInt) - 1){
05661                         TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05662                         objResultPtr = Tcl_NewWideIntObj(
05663                                 signum * (((Tcl_WideInt) 1) << l2));
05664                         TRACE(("%s\n", O2S(objResultPtr)));
05665                         NEXT_INST_F(1, 2, 1);
05666                     }
05667 #endif
05668                 }
05669 #if (LONG_MAX == 0x7fffffff)
05670                 if (l2 <= 8 &&
05671                         l1 <= MaxBase32[l2-2] && l1 >= -MaxBase32[l2-2]) {
05672                     /*
05673                      * Small powers of 32-bit integers.
05674                      */
05675 
05676                     long lResult = l1 * l1;     /* b**2 */
05677                     switch (l2) {
05678                     case 2:
05679                         break;
05680                     case 3:
05681                         lResult *= l1;          /* b**3 */
05682                         break;
05683                     case 4:
05684                         lResult *= lResult;     /* b**4 */
05685                         break;
05686                     case 5:
05687                         lResult *= lResult;     /* b**4 */
05688                         lResult *= l1;          /* b**5 */
05689                         break;
05690                     case 6:
05691                         lResult *= l1;          /* b**3 */
05692                         lResult *= lResult;     /* b**6 */
05693                         break;
05694                     case 7:
05695                         lResult *= l1;          /* b**3 */
05696                         lResult *= lResult;     /* b**6 */
05697                         lResult *= l1;          /* b**7 */
05698                         break;
05699                     case 8:
05700                         lResult *= lResult;     /* b**4 */
05701                         lResult *= lResult;     /* b**8 */
05702                         break;
05703                     }
05704                     TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05705                     if (Tcl_IsShared(valuePtr)) {
05706                         TclNewLongObj(objResultPtr, lResult);
05707                         TRACE(("%s\n", O2S(objResultPtr)));
05708                         NEXT_INST_F(1, 2, 1);
05709                     }
05710                     Tcl_SetLongObj(valuePtr, lResult);
05711                     TRACE(("%s\n", O2S(valuePtr)));
05712                     NEXT_INST_F(1, 1, 0);
05713                 }
05714                 if (l1 >= 3 &&
05715                         ((unsigned long) l1 < (sizeof(Exp32Index)
05716                                 / sizeof(unsigned short)) - 1)) {
05717                     unsigned short base = Exp32Index[l1-3]
05718                             + (unsigned short) l2 - 9;
05719                     if (base < Exp32Index[l1-2]) {
05720                         /*
05721                          * 32-bit number raised to intermediate power, done by
05722                          * table lookup.
05723                          */
05724 
05725                         TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05726                         if (Tcl_IsShared(valuePtr)) {
05727                             TclNewLongObj(objResultPtr, Exp32Value[base]);
05728                             TRACE(("%s\n", O2S(objResultPtr)));
05729                             NEXT_INST_F(1, 2, 1);
05730                         }
05731                         Tcl_SetLongObj(valuePtr, Exp32Value[base]);
05732                         TRACE(("%s\n", O2S(valuePtr)));
05733                         NEXT_INST_F(1, 1, 0);
05734                     }
05735                 }
05736                 if (-l1 >= 3
05737                     && (unsigned long)(-l1) < (sizeof(Exp32Index)
05738                              / sizeof(unsigned short)) - 1) {
05739                     unsigned short base
05740                         = Exp32Index[-l1-3] + (unsigned short) l2 - 9;
05741                     if (base < Exp32Index[-l1-2]) {
05742                         long lResult = (oddExponent) ?
05743                             -Exp32Value[base] : Exp32Value[base];
05744 
05745                         /*
05746                          * 32-bit number raised to intermediate power, done by
05747                          * table lookup.
05748                          */
05749 
05750                         TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05751                         if (Tcl_IsShared(valuePtr)) {
05752                             TclNewLongObj(objResultPtr, lResult);
05753                             TRACE(("%s\n", O2S(objResultPtr)));
05754                             NEXT_INST_F(1, 2, 1);
05755                         }
05756                         Tcl_SetLongObj(valuePtr, lResult);
05757                         TRACE(("%s\n", O2S(valuePtr)));
05758                         NEXT_INST_F(1, 1, 0);
05759                     }
05760                 }
05761 #endif
05762             }
05763             if (type1 == TCL_NUMBER_LONG) {
05764                 w1 = l1;
05765 #ifndef NO_WIDE_TYPE
05766             } else if (type1 == TCL_NUMBER_WIDE) {
05767                 w1 = *((const Tcl_WideInt*) ptr1);
05768 #endif
05769             } else {
05770                 w1 = 0;
05771             }
05772 #if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
05773             if (w1 != 0 && type2 == TCL_NUMBER_LONG && l2 <= 16
05774                     && w1 <= MaxBaseWide[l2-2] && w1 >= -MaxBaseWide[l2-2]) {
05775                 /*
05776                  * Small powers of integers whose result is wide.
05777                  */
05778 
05779                 Tcl_WideInt wResult = w1 * w1; /* b**2 */
05780 
05781                 switch (l2) {
05782                 case 2:
05783                     break;
05784                 case 3:
05785                     wResult *= l1;      /* b**3 */
05786                     break;
05787                 case 4:
05788                     wResult *= wResult; /* b**4 */
05789                     break;
05790                 case 5:
05791                     wResult *= wResult; /* b**4 */
05792                     wResult *= w1;      /* b**5 */
05793                     break;
05794                 case 6:
05795                     wResult *= w1;      /* b**3 */
05796                     wResult *= wResult; /* b**6 */
05797                     break;
05798                 case 7:
05799                     wResult *= w1;      /* b**3 */
05800                     wResult *= wResult; /* b**6 */
05801                     wResult *= w1;      /* b**7 */
05802                     break;
05803                 case 8:
05804                     wResult *= wResult; /* b**4 */
05805                     wResult *= wResult; /* b**8 */
05806                     break;
05807                 case 9:
05808                     wResult *= wResult; /* b**4 */
05809                     wResult *= wResult; /* b**8 */
05810                     wResult *= w1;      /* b**9 */
05811                     break;
05812                 case 10:
05813                     wResult *= wResult; /* b**4 */
05814                     wResult *= w1;      /* b**5 */
05815                     wResult *= wResult; /* b**10 */
05816                     break;
05817                 case 11:
05818                     wResult *= wResult; /* b**4 */
05819                     wResult *= w1;      /* b**5 */
05820                     wResult *= wResult; /* b**10 */
05821                     wResult *= w1;      /* b**11 */
05822                     break;
05823                 case 12:
05824                     wResult *= w1;      /* b**3 */
05825                     wResult *= wResult; /* b**6 */
05826                     wResult *= wResult; /* b**12 */
05827                     break;
05828                 case 13:
05829                     wResult *= w1;      /* b**3 */
05830                     wResult *= wResult; /* b**6 */
05831                     wResult *= wResult; /* b**12 */
05832                     wResult *= w1;      /* b**13 */
05833                     break;
05834                 case 14:
05835                     wResult *= w1;      /* b**3 */
05836                     wResult *= wResult; /* b**6 */
05837                     wResult *= w1;      /* b**7 */
05838                     wResult *= wResult; /* b**14 */
05839                     break;
05840                 case 15:
05841                     wResult *= w1;      /* b**3 */
05842                     wResult *= wResult; /* b**6 */
05843                     wResult *= w1;      /* b**7 */
05844                     wResult *= wResult; /* b**14 */
05845                     wResult *= w1;      /* b**15 */
05846                     break;
05847                 case 16:
05848                     wResult *= wResult; /* b**4 */
05849                     wResult *= wResult; /* b**8 */
05850                     wResult *= wResult; /* b**16 */
05851                     break;
05852 
05853                 }
05854                 TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05855                 objResultPtr = Tcl_NewWideIntObj(wResult);
05856                 TRACE(("%s\n", O2S(objResultPtr)));
05857                 NEXT_INST_F(1, 2, 1);
05858             }
05859 
05860             /*
05861              * Handle cases of powers > 16 that still fit in a 64-bit word by
05862              * doing table lookup.
05863              */
05864 
05865             if (w1 >= 3 &&
05866                     (Tcl_WideUInt) w1 < (sizeof(Exp64Index)
05867                             / sizeof(unsigned short)) - 1) {
05868                 unsigned short base =
05869                         Exp64Index[w1-3] + (unsigned short) l2 - 17;
05870 
05871                 if (base < Exp64Index[w1-2]) {
05872                     /*
05873                      * 64-bit number raised to intermediate power, done by
05874                      * table lookup.
05875                      */
05876 
05877                     TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05878                     if (Tcl_IsShared(valuePtr)) {
05879                         objResultPtr = Tcl_NewWideIntObj(Exp64Value[base]);
05880                         TRACE(("%s\n", O2S(objResultPtr)));
05881                         NEXT_INST_F(1, 2, 1);
05882                     }
05883                     Tcl_SetWideIntObj(valuePtr, Exp64Value[base]);
05884                     TRACE(("%s\n", O2S(valuePtr)));
05885                     NEXT_INST_F(1, 1, 0);
05886                 }
05887             }
05888             if (-w1 >= 3 &&
05889                     (Tcl_WideUInt) (-w1) < (sizeof(Exp64Index)
05890                             / sizeof(unsigned short)) - 1) {
05891                 unsigned short base =
05892                         Exp64Index[-w1-3] + (unsigned short) l2 - 17;
05893 
05894                 if (base < Exp64Index[-w1-2]) {
05895                     Tcl_WideInt wResult = (oddExponent) ?
05896                             -Exp64Value[base] : Exp64Value[base];
05897                     /*
05898                      * 64-bit number raised to intermediate power, done by
05899                      * table lookup.
05900                      */
05901 
05902                     TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
05903                     if (Tcl_IsShared(valuePtr)) {
05904                         objResultPtr = Tcl_NewWideIntObj(wResult);
05905                         TRACE(("%s\n", O2S(objResultPtr)));
05906                         NEXT_INST_F(1, 2, 1);
05907                     }
05908                     Tcl_SetWideIntObj(valuePtr, wResult);
05909                     TRACE(("%s\n", O2S(valuePtr)));
05910                     NEXT_INST_F(1, 1, 0);
05911                 }
05912             }
05913 #endif
05914 
05915             goto overflow;
05916         }
05917 
05918         if ((*pc != INST_MULT)
05919                 && (type1 != TCL_NUMBER_BIG) && (type2 != TCL_NUMBER_BIG)) {
05920             Tcl_WideInt w1, w2, wResult;
05921 
05922             TclGetWideIntFromObj(NULL, valuePtr, &w1);
05923             TclGetWideIntFromObj(NULL, value2Ptr, &w2);
05924 
05925             switch (*pc) {
05926             case INST_ADD:
05927                 wResult = w1 + w2;
05928 #ifndef NO_WIDE_TYPE
05929                 if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE))
05930 #endif
05931                 {
05932                     /*
05933                      * Check for overflow.
05934                      */
05935 
05936                     if (Overflowing(w1, w2, wResult)) {
05937                         goto overflow;
05938                     }
05939                 }
05940                 break;
05941 
05942             case INST_SUB:
05943                 wResult = w1 - w2;
05944 #ifndef NO_WIDE_TYPE
05945                 if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE))
05946 #endif
05947                 {
05948                     /*
05949                      * Must check for overflow. The macro tests for overflows
05950                      * in sums by looking at the sign bits. As we have a
05951                      * subtraction here, we are adding -w2. As -w2 could in
05952                      * turn overflow, we test with ~w2 instead: it has the
05953                      * opposite sign bit to w2 so it does the job. Note that
05954                      * the only "bad" case (w2==0) is irrelevant for this
05955                      * macro, as in that case w1 and wResult have the same
05956                      * sign and there is no overflow anyway.
05957                      */
05958 
05959                     if (Overflowing(w1, ~w2, wResult)) {
05960                         goto overflow;
05961                     }
05962                 }
05963                 break;
05964 
05965             case INST_DIV:
05966                 if (w2 == 0) {
05967                     TRACE(("%s %s => DIVIDE BY ZERO\n",
05968                             O2S(valuePtr), O2S(value2Ptr)));
05969                     goto divideByZero;
05970                 }
05971 
05972                 /*
05973                  * Need a bignum to represent (LLONG_MIN / -1)
05974                  */
05975 
05976                 if ((w1 == LLONG_MIN) && (w2 == -1)) {
05977                     goto overflow;
05978                 }
05979                 wResult = w1 / w2;
05980 
05981                 /*
05982                  * Force Tcl's integer division rules.
05983                  * TODO: examine for logic simplification
05984                  */
05985 
05986                 if (((wResult < 0) || ((wResult == 0) &&
05987                         ((w1 < 0 && w2 > 0) || (w1 > 0 && w2 < 0)))) &&
05988                         ((wResult * w2) != w1)) {
05989                     wResult -= 1;
05990                 }
05991                 break;
05992             default:
05993                 /*
05994                  * Unused, here to silence compiler warning.
05995                  */
05996 
05997                 wResult = 0;
05998             }
05999 
06000             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
06001             if (Tcl_IsShared(valuePtr)) {
06002                 objResultPtr = Tcl_NewWideIntObj(wResult);
06003                 TRACE(("%s\n", O2S(objResultPtr)));
06004                 NEXT_INST_F(1, 2, 1);
06005             }
06006             Tcl_SetWideIntObj(valuePtr, wResult);
06007             TRACE(("%s\n", O2S(valuePtr)));
06008             NEXT_INST_F(1, 1, 0);
06009         }
06010 
06011     overflow:
06012         {
06013             mp_int big1, big2, bigResult, bigRemainder;
06014 
06015             TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
06016             Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
06017             Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
06018             mp_init(&bigResult);
06019             switch (*pc) {
06020             case INST_ADD:
06021                 mp_add(&big1, &big2, &bigResult);
06022                 break;
06023             case INST_SUB:
06024                 mp_sub(&big1, &big2, &bigResult);
06025                 break;
06026             case INST_MULT:
06027                 mp_mul(&big1, &big2, &bigResult);
06028                 break;
06029             case INST_DIV:
06030                 if (mp_iszero(&big2)) {
06031                     TRACE(("%s %s => DIVIDE BY ZERO\n", O2S(valuePtr),
06032                             O2S(value2Ptr)));
06033                     mp_clear(&big1);
06034                     mp_clear(&big2);
06035                     mp_clear(&bigResult);
06036                     goto divideByZero;
06037                 }
06038                 mp_init(&bigRemainder);
06039                 mp_div(&big1, &big2, &bigResult, &bigRemainder);
06040                 /* TODO: internals intrusion */
06041                 if (!mp_iszero(&bigRemainder)
06042                         && (bigRemainder.sign != big2.sign)) {
06043                     /*
06044                      * Convert to Tcl's integer division rules.
06045                      */
06046 
06047                     mp_sub_d(&bigResult, 1, &bigResult);
06048                     mp_add(&bigRemainder, &big2, &bigRemainder);
06049                 }
06050                 mp_clear(&bigRemainder);
06051                 break;
06052             case INST_EXPON:
06053                 if (big2.used > 1) {
06054                     Tcl_SetObjResult(interp,
06055                             Tcl_NewStringObj("exponent too large", -1));
06056                     mp_clear(&big1);
06057                     mp_clear(&big2);
06058                     mp_clear(&bigResult);
06059                     result = TCL_ERROR;
06060                     goto checkForCatch;
06061                 }
06062                 mp_expt_d(&big1, big2.dp[0], &bigResult);
06063                 break;
06064             }
06065             mp_clear(&big1);
06066             mp_clear(&big2);
06067             if (Tcl_IsShared(valuePtr)) {
06068                 objResultPtr = Tcl_NewBignumObj(&bigResult);
06069                 TRACE(("%s\n", O2S(objResultPtr)));
06070                 NEXT_INST_F(1, 2, 1);
06071             }
06072             Tcl_SetBignumObj(valuePtr, &bigResult);
06073             TRACE(("%s\n", O2S(valuePtr)));
06074             NEXT_INST_F(1, 1, 0);
06075         }
06076     }
06077 
06078     case INST_LNOT: {
06079         int b;
06080         Tcl_Obj *valuePtr = OBJ_AT_TOS;
06081 
06082         /* TODO - check claim that taking address of b harms performance */
06083         /* TODO - consider optimization search for constants */
06084         result = TclGetBooleanFromObj(NULL, valuePtr, &b);
06085         if (result != TCL_OK) {
06086             TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n", O2S(valuePtr),
06087                     (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
06088             IllegalExprOperandType(interp, pc, valuePtr);
06089             goto checkForCatch;
06090         }
06091         /* TODO: Consider peephole opt. */
06092         objResultPtr = constants[!b];
06093         NEXT_INST_F(1, 1, 1);
06094     }
06095 
06096     case INST_BITNOT: {
06097         mp_int big;
06098         ClientData ptr;
06099         int type;
06100         Tcl_Obj *valuePtr = OBJ_AT_TOS;
06101 
06102         result = GetNumberFromObj(NULL, valuePtr, &ptr, &type);
06103         if ((result != TCL_OK)
06104                 || (type == TCL_NUMBER_NAN) || (type == TCL_NUMBER_DOUBLE)) {
06105             /*
06106              * ... ~$NonInteger => raise an error.
06107              */
06108 
06109             result = TCL_ERROR;
06110             TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
06111                     (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
06112             IllegalExprOperandType(interp, pc, valuePtr);
06113             goto checkForCatch;
06114         }
06115         if (type == TCL_NUMBER_LONG) {
06116             long l = *((const long *)ptr);
06117 
06118             if (Tcl_IsShared(valuePtr)) {
06119                 TclNewLongObj(objResultPtr, ~l);
06120                 NEXT_INST_F(1, 1, 1);
06121             }
06122             TclSetLongObj(valuePtr, ~l);
06123             NEXT_INST_F(1, 0, 0);
06124         }
06125 #ifndef NO_WIDE_TYPE
06126         if (type == TCL_NUMBER_WIDE) {
06127             Tcl_WideInt w = *((const Tcl_WideInt *)ptr);
06128 
06129             if (Tcl_IsShared(valuePtr)) {
06130                 objResultPtr = Tcl_NewWideIntObj(~w);
06131                 NEXT_INST_F(1, 1, 1);
06132             }
06133             Tcl_SetWideIntObj(valuePtr, ~w);
06134             NEXT_INST_F(1, 0, 0);
06135         }
06136 #endif
06137         Tcl_TakeBignumFromObj(NULL, valuePtr, &big);
06138         /* ~a = - a - 1 */
06139         mp_neg(&big, &big);
06140         mp_sub_d(&big, 1, &big);
06141         if (Tcl_IsShared(valuePtr)) {
06142             objResultPtr = Tcl_NewBignumObj(&big);
06143             NEXT_INST_F(1, 1, 1);
06144         }
06145         Tcl_SetBignumObj(valuePtr, &big);
06146         NEXT_INST_F(1, 0, 0);
06147     }
06148 
06149     case INST_UMINUS: {
06150         ClientData ptr;
06151         int type;
06152         Tcl_Obj *valuePtr = OBJ_AT_TOS;
06153 
06154         result = GetNumberFromObj(NULL, valuePtr, &ptr, &type);
06155         if ((result != TCL_OK)
06156 #ifndef ACCEPT_NAN
06157                 || (type == TCL_NUMBER_NAN)
06158 #endif
06159                 ) {
06160             result = TCL_ERROR;
06161             TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
06162                     (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
06163             IllegalExprOperandType(interp, pc, valuePtr);
06164             goto checkForCatch;
06165         }
06166         switch (type) {
06167         case TCL_NUMBER_DOUBLE: {
06168             double d;
06169 
06170             if (Tcl_IsShared(valuePtr)) {
06171                 TclNewDoubleObj(objResultPtr, -(*((const double *)ptr)));
06172                 NEXT_INST_F(1, 1, 1);
06173             }
06174             d = *((const double *)ptr);
06175             TclSetDoubleObj(valuePtr, -d);
06176             NEXT_INST_F(1, 0, 0);
06177         }
06178         case TCL_NUMBER_LONG: {
06179             long l = *((const long *)ptr);
06180 
06181             if (l != LONG_MIN) {
06182                 if (Tcl_IsShared(valuePtr)) {
06183                     TclNewLongObj(objResultPtr, -l);
06184                     NEXT_INST_F(1, 1, 1);
06185                 }
06186                 TclSetLongObj(valuePtr, -l);
06187                 NEXT_INST_F(1, 0, 0);
06188             }
06189             /* FALLTHROUGH */
06190         }
06191 #ifndef NO_WIDE_TYPE
06192         case TCL_NUMBER_WIDE: {
06193             Tcl_WideInt w;
06194 
06195             if (type == TCL_NUMBER_LONG) {
06196                 w = (Tcl_WideInt)(*((const long *)ptr));
06197             } else {
06198                 w = *((const Tcl_WideInt *)ptr);
06199             }
06200             if (w != LLONG_MIN) {
06201                 if (Tcl_IsShared(valuePtr)) {
06202                     objResultPtr = Tcl_NewWideIntObj(-w);
06203                     NEXT_INST_F(1, 1, 1);
06204                 }
06205                 Tcl_SetWideIntObj(valuePtr, -w);
06206                 NEXT_INST_F(1, 0, 0);
06207             }
06208             /* FALLTHROUGH */
06209         }
06210 #endif
06211         case TCL_NUMBER_BIG: {
06212             mp_int big;
06213 
06214             switch (type) {
06215 #ifdef NO_WIDE_TYPE
06216             case TCL_NUMBER_LONG:
06217                 TclBNInitBignumFromLong(&big, *(const long *) ptr);
06218                 break;
06219 #else
06220             case TCL_NUMBER_WIDE:
06221                 TclBNInitBignumFromWideInt(&big, *(const Tcl_WideInt *) ptr);
06222                 break;
06223 #endif
06224             case TCL_NUMBER_BIG:
06225                 Tcl_TakeBignumFromObj(NULL, valuePtr, &big);
06226             }
06227             mp_neg(&big, &big);
06228             if (Tcl_IsShared(valuePtr)) {
06229                 objResultPtr = Tcl_NewBignumObj(&big);
06230                 NEXT_INST_F(1, 1, 1);
06231             }
06232             Tcl_SetBignumObj(valuePtr, &big);
06233             NEXT_INST_F(1, 0, 0);
06234         }
06235         case TCL_NUMBER_NAN:
06236             /* -NaN => NaN */
06237             NEXT_INST_F(1, 0, 0);
06238         }
06239     }
06240 
06241     case INST_UPLUS:
06242     case INST_TRY_CVT_TO_NUMERIC: {
06243         /*
06244          * Try to convert the topmost stack object to numeric object. This is
06245          * done in order to support [expr]'s policy of interpreting operands
06246          * if at all possible as numbers first, then strings.
06247          */
06248 
06249         ClientData ptr;
06250         int type;
06251         Tcl_Obj *valuePtr = OBJ_AT_TOS;
06252 
06253         if (GetNumberFromObj(NULL, valuePtr, &ptr, &type) != TCL_OK) {
06254             if (*pc == INST_UPLUS) {
06255                 /*
06256                  * ... +$NonNumeric => raise an error.
06257                  */
06258 
06259                 result = TCL_ERROR;
06260                 TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
06261                         (valuePtr->typePtr? valuePtr->typePtr->name:"null")));
06262                 IllegalExprOperandType(interp, pc, valuePtr);
06263                 goto checkForCatch;
06264             } else {
06265                 /* ... TryConvertToNumeric($NonNumeric) is acceptable */
06266                 TRACE(("\"%.20s\" => not numeric\n", O2S(valuePtr)));
06267                 NEXT_INST_F(1, 0, 0);
06268             }
06269         }
06270 #ifndef ACCEPT_NAN
06271         if (type == TCL_NUMBER_NAN) {
06272             result = TCL_ERROR;
06273             if (*pc == INST_UPLUS) {
06274                 /*
06275                  * ... +$NonNumeric => raise an error.
06276                  */
06277 
06278                 TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
06279                         (valuePtr->typePtr? valuePtr->typePtr->name:"null")));
06280                 IllegalExprOperandType(interp, pc, valuePtr);
06281             } else {
06282                 /*
06283                  * Numeric conversion of NaN -> error.
06284                  */
06285 
06286                 TRACE(("\"%.20s\" => IEEE FLOATING PT ERROR\n",
06287                         O2S(objResultPtr)));
06288                 TclExprFloatError(interp, *((const double *)ptr));
06289             }
06290             goto checkForCatch;
06291         }
06292 #endif
06293 
06294         /*
06295          * Ensure that the numeric value has a string rep the same as the
06296          * formatted version of its internal rep. This is used, e.g., to make
06297          * sure that "expr {0001}" yields "1", not "0001". We implement this
06298          * by _discarding_ the string rep since we know it will be
06299          * regenerated, if needed later, by formatting the internal rep's
06300          * value.
06301          */
06302 
06303         if (valuePtr->bytes == NULL) {
06304             TRACE(("\"%.20s\" => numeric, same Tcl_Obj\n", O2S(valuePtr)));
06305             NEXT_INST_F(1, 0, 0);
06306         }
06307         if (Tcl_IsShared(valuePtr)) {
06308             /*
06309              * Here we do some surgery within the Tcl_Obj internals. We want
06310              * to copy the intrep, but not the string, so we temporarily hide
06311              * the string so we do not copy it.
06312              */
06313 
06314             char *savedString = valuePtr->bytes;
06315 
06316             valuePtr->bytes = NULL;
06317             objResultPtr = Tcl_DuplicateObj(valuePtr);
06318             valuePtr->bytes = savedString;
06319             TRACE(("\"%.20s\" => numeric, new Tcl_Obj\n", O2S(valuePtr)));
06320             NEXT_INST_F(1, 1, 1);
06321         }
06322         TclInvalidateStringRep(valuePtr);
06323         TRACE(("\"%.20s\" => numeric, same Tcl_Obj\n", O2S(valuePtr)));
06324         NEXT_INST_F(1, 0, 0);
06325     }
06326 
06327     case INST_BREAK:
06328         /*
06329         DECACHE_STACK_INFO();
06330         Tcl_ResetResult(interp);
06331         CACHE_STACK_INFO();
06332         */
06333         result = TCL_BREAK;
06334         cleanup = 0;
06335         goto processExceptionReturn;
06336 
06337     case INST_CONTINUE:
06338         /*
06339         DECACHE_STACK_INFO();
06340         Tcl_ResetResult(interp);
06341         CACHE_STACK_INFO();
06342         */
06343         result = TCL_CONTINUE;
06344         cleanup = 0;
06345         goto processExceptionReturn;
06346 
06347     case INST_FOREACH_START4: {
06348         /*
06349          * Initialize the temporary local var that holds the count of the
06350          * number of iterations of the loop body to -1.
06351          */
06352 
06353         int opnd, iterTmpIndex;
06354         ForeachInfo *infoPtr;
06355         Var *iterVarPtr;
06356         Tcl_Obj *oldValuePtr;
06357 
06358         opnd = TclGetUInt4AtPtr(pc+1);
06359         infoPtr = (ForeachInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
06360         iterTmpIndex = infoPtr->loopCtTemp;
06361         iterVarPtr = &(compiledLocals[iterTmpIndex]);
06362         oldValuePtr = iterVarPtr->value.objPtr;
06363 
06364         if (oldValuePtr == NULL) {
06365             TclNewLongObj(iterVarPtr->value.objPtr, -1);
06366             Tcl_IncrRefCount(iterVarPtr->value.objPtr);
06367         } else {
06368             TclSetLongObj(oldValuePtr, -1);
06369         }
06370         TRACE(("%u => loop iter count temp %d\n", opnd, iterTmpIndex));
06371 
06372 #ifndef TCL_COMPILE_DEBUG
06373         /*
06374          * Remark that the compiler ALWAYS sets INST_FOREACH_STEP4 immediately
06375          * after INST_FOREACH_START4 - let us just fall through instead of
06376          * jumping back to the top.
06377          */
06378 
06379         pc += 5;
06380         TCL_DTRACE_INST_NEXT();
06381 #else
06382         NEXT_INST_F(5, 0, 0);
06383 #endif
06384     }
06385 
06386     case INST_FOREACH_STEP4: {
06387         /*
06388          * "Step" a foreach loop (i.e., begin its next iteration) by assigning
06389          * the next value list element to each loop var.
06390          */
06391 
06392         ForeachInfo *infoPtr;
06393         ForeachVarList *varListPtr;
06394         Tcl_Obj *listPtr,*valuePtr, *value2Ptr, **elements;
06395         Var *iterVarPtr, *listVarPtr, *varPtr;
06396         int opnd, numLists, iterNum, listTmpIndex, listLen, numVars;
06397         int varIndex, valIndex, continueLoop, j;
06398         long i;
06399 
06400         opnd = TclGetUInt4AtPtr(pc+1);
06401         infoPtr = (ForeachInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
06402         numLists = infoPtr->numLists;
06403 
06404         /*
06405          * Increment the temp holding the loop iteration number.
06406          */
06407 
06408         iterVarPtr = &(compiledLocals[infoPtr->loopCtTemp]);
06409         valuePtr = iterVarPtr->value.objPtr;
06410         iterNum = (valuePtr->internalRep.longValue + 1);
06411         TclSetLongObj(valuePtr, iterNum);
06412 
06413         /*
06414          * Check whether all value lists are exhausted and we should stop the
06415          * loop.
06416          */
06417 
06418         continueLoop = 0;
06419         listTmpIndex = infoPtr->firstValueTemp;
06420         for (i = 0;  i < numLists;  i++) {
06421             varListPtr = infoPtr->varLists[i];
06422             numVars = varListPtr->numVars;
06423 
06424             listVarPtr = &(compiledLocals[listTmpIndex]);
06425             listPtr = listVarPtr->value.objPtr;
06426             result = TclListObjLength(interp, listPtr, &listLen);
06427             if (result == TCL_OK) {
06428                 if (listLen > (iterNum * numVars)) {
06429                     continueLoop = 1;
06430                 }
06431                 listTmpIndex++;
06432             } else {
06433                 TRACE_WITH_OBJ(("%u => ERROR converting list %ld, \"%s\": ",
06434                         opnd, i, O2S(listPtr)), Tcl_GetObjResult(interp));
06435                 goto checkForCatch;
06436             }
06437         }
06438 
06439         /*
06440          * If some var in some var list still has a remaining list element
06441          * iterate one more time. Assign to var the next element from its
06442          * value list. We already checked above that each list temp holds a
06443          * valid list object (by calling Tcl_ListObjLength), but cannot rely
06444          * on that check remaining valid: one list could have been shimmered
06445          * as a side effect of setting a traced variable.
06446          */
06447 
06448         if (continueLoop) {
06449             listTmpIndex = infoPtr->firstValueTemp;
06450             for (i = 0;  i < numLists;  i++) {
06451                 varListPtr = infoPtr->varLists[i];
06452                 numVars = varListPtr->numVars;
06453 
06454                 listVarPtr = &(compiledLocals[listTmpIndex]);
06455                 listPtr = TclListObjCopy(NULL, listVarPtr->value.objPtr);
06456                 TclListObjGetElements(interp, listPtr, &listLen, &elements);
06457 
06458                 valIndex = (iterNum * numVars);
06459                 for (j = 0;  j < numVars;  j++) {
06460                     if (valIndex >= listLen) {
06461                         TclNewObj(valuePtr);
06462                     } else {
06463                         valuePtr = elements[valIndex];
06464                     }
06465 
06466                     varIndex = varListPtr->varIndexes[j];
06467                     varPtr = &(compiledLocals[varIndex]);
06468                     while (TclIsVarLink(varPtr)) {
06469                         varPtr = varPtr->value.linkPtr;
06470                     }
06471                     if (TclIsVarDirectWritable(varPtr)) {
06472                         value2Ptr = varPtr->value.objPtr;
06473                         if (valuePtr != value2Ptr) {
06474                             if (value2Ptr != NULL) {
06475                                 TclDecrRefCount(value2Ptr);
06476                             }
06477                             varPtr->value.objPtr = valuePtr;
06478                             Tcl_IncrRefCount(valuePtr);
06479                         }
06480                     } else {
06481                         DECACHE_STACK_INFO();
06482                         value2Ptr = TclPtrSetVar(interp, varPtr, NULL, NULL,
06483                                 NULL, valuePtr, TCL_LEAVE_ERR_MSG, varIndex);
06484                         CACHE_STACK_INFO();
06485                         if (value2Ptr == NULL) {
06486                             TRACE_WITH_OBJ((
06487                                     "%u => ERROR init. index temp %d: ",
06488                                     opnd,varIndex), Tcl_GetObjResult(interp));
06489                             result = TCL_ERROR;
06490                             TclDecrRefCount(listPtr);
06491                             goto checkForCatch;
06492                         }
06493                     }
06494                     valIndex++;
06495                 }
06496                 TclDecrRefCount(listPtr);
06497                 listTmpIndex++;
06498             }
06499         }
06500         TRACE(("%u => %d lists, iter %d, %s loop\n", opnd, numLists,
06501                 iterNum, (continueLoop? "continue" : "exit")));
06502 
06503         /*
06504          * Run-time peep-hole optimisation: the compiler ALWAYS follows
06505          * INST_FOREACH_STEP4 with an INST_JUMP_FALSE. We just skip that
06506          * instruction and jump direct from here.
06507          */
06508 
06509         pc += 5;
06510         if (*pc == INST_JUMP_FALSE1) {
06511             NEXT_INST_F((continueLoop? 2 : TclGetInt1AtPtr(pc+1)), 0, 0);
06512         } else {
06513             NEXT_INST_F((continueLoop? 5 : TclGetInt4AtPtr(pc+1)), 0, 0);
06514         }
06515     }
06516 
06517     case INST_BEGIN_CATCH4:
06518         /*
06519          * Record start of the catch command with exception range index equal
06520          * to the operand. Push the current stack depth onto the special catch
06521          * stack.
06522          */
06523 
06524         *(++catchTop) = CURR_DEPTH;
06525         TRACE(("%u => catchTop=%d, stackTop=%d\n",
06526                 TclGetUInt4AtPtr(pc+1), (catchTop - initCatchTop - 1),
06527                 (int) CURR_DEPTH));
06528         NEXT_INST_F(5, 0, 0);
06529 
06530     case INST_END_CATCH:
06531         catchTop--;
06532         Tcl_ResetResult(interp);
06533         result = TCL_OK;
06534         TRACE(("=> catchTop=%d\n", (catchTop - initCatchTop - 1)));
06535         NEXT_INST_F(1, 0, 0);
06536 
06537     case INST_PUSH_RESULT:
06538         objResultPtr = Tcl_GetObjResult(interp);
06539         TRACE_WITH_OBJ(("=> "), objResultPtr);
06540 
06541         /*
06542          * See the comments at INST_INVOKE_STK
06543          */
06544         {
06545             Tcl_Obj *newObjResultPtr;
06546 
06547             TclNewObj(newObjResultPtr);
06548             Tcl_IncrRefCount(newObjResultPtr);
06549             iPtr->objResultPtr = newObjResultPtr;
06550         }
06551 
06552         NEXT_INST_F(1, 0, -1);
06553 
06554     case INST_PUSH_RETURN_CODE:
06555         TclNewIntObj(objResultPtr, result);
06556         TRACE(("=> %u\n", result));
06557         NEXT_INST_F(1, 0, 1);
06558 
06559     case INST_PUSH_RETURN_OPTIONS:
06560         objResultPtr = Tcl_GetReturnOptions(interp, result);
06561         TRACE_WITH_OBJ(("=> "), objResultPtr);
06562         NEXT_INST_F(1, 0, 1);
06563 
06564 /* TODO: normalize "valPtr" to "valuePtr" */
06565     {
06566         int opnd, opnd2, allocateDict;
06567         Tcl_Obj *dictPtr, *valPtr;
06568         Var *varPtr;
06569 
06570     case INST_DICT_GET:
06571         opnd = TclGetUInt4AtPtr(pc+1);
06572         TRACE(("%u => ", opnd));
06573         dictPtr = OBJ_AT_DEPTH(opnd);
06574         if (opnd > 1) {
06575             dictPtr = TclTraceDictPath(interp, dictPtr, opnd-1,
06576                     &OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ);
06577             if (dictPtr == NULL) {
06578                 TRACE_WITH_OBJ((
06579                         "%u => ERROR tracing dictionary path into \"%s\": ",
06580                         opnd, O2S(OBJ_AT_DEPTH(opnd))),
06581                         Tcl_GetObjResult(interp));
06582                 result = TCL_ERROR;
06583                 goto checkForCatch;
06584             }
06585         }
06586         result = Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, &objResultPtr);
06587         if ((result == TCL_OK) && objResultPtr) {
06588             TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
06589             NEXT_INST_V(5, opnd+1, 1);
06590         }
06591         if (result != TCL_OK) {
06592             TRACE_WITH_OBJ((
06593                     "%u => ERROR reading leaf dictionary key \"%s\": ",
06594                     opnd, O2S(dictPtr)), Tcl_GetObjResult(interp));
06595         } else {
06596             /*Tcl_ResetResult(interp);*/
06597             Tcl_AppendResult(interp, "key \"", TclGetString(OBJ_AT_TOS),
06598                     "\" not known in dictionary", NULL);
06599             TRACE_WITH_OBJ(("%u => ERROR ", opnd), Tcl_GetObjResult(interp));
06600             result = TCL_ERROR;
06601         }
06602         goto checkForCatch;
06603 
06604     case INST_DICT_SET:
06605     case INST_DICT_UNSET:
06606     case INST_DICT_INCR_IMM:
06607         opnd = TclGetUInt4AtPtr(pc+1);
06608         opnd2 = TclGetUInt4AtPtr(pc+5);
06609 
06610         varPtr = &(compiledLocals[opnd2]);
06611         while (TclIsVarLink(varPtr)) {
06612             varPtr = varPtr->value.linkPtr;
06613         }
06614         TRACE(("%u %u => ", opnd, opnd2));
06615         if (TclIsVarDirectReadable(varPtr)) {
06616             dictPtr = varPtr->value.objPtr;
06617         } else {
06618             DECACHE_STACK_INFO();
06619             dictPtr = TclPtrGetVar(interp, varPtr, NULL,NULL,NULL, 0, opnd2);
06620             CACHE_STACK_INFO();
06621         }
06622         if (dictPtr == NULL) {
06623             TclNewObj(dictPtr);
06624             allocateDict = 1;
06625         } else {
06626             allocateDict = Tcl_IsShared(dictPtr);
06627             if (allocateDict) {
06628                 dictPtr = Tcl_DuplicateObj(dictPtr);
06629             }
06630         }
06631 
06632         switch (*pc) {
06633         case INST_DICT_SET:
06634             cleanup = opnd + 1;
06635             result = Tcl_DictObjPutKeyList(interp, dictPtr, opnd,
06636                     &OBJ_AT_DEPTH(opnd), OBJ_AT_TOS);
06637             break;
06638         case INST_DICT_INCR_IMM:
06639             cleanup = 1;
06640             opnd = TclGetInt4AtPtr(pc+1);
06641             result = Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, &valPtr);
06642             if (result != TCL_OK) {
06643                 break;
06644             }
06645             if (valPtr == NULL) {
06646                 Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS,Tcl_NewIntObj(opnd));
06647             } else {
06648                 Tcl_Obj *incrPtr = Tcl_NewIntObj(opnd);
06649 
06650                 Tcl_IncrRefCount(incrPtr);
06651                 if (Tcl_IsShared(valPtr)) {
06652                     valPtr = Tcl_DuplicateObj(valPtr);
06653                     Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS, valPtr);
06654                 }
06655                 result = TclIncrObj(interp, valPtr, incrPtr);
06656                 if (result == TCL_OK) {
06657                     Tcl_InvalidateStringRep(dictPtr);
06658                 }
06659                 TclDecrRefCount(incrPtr);
06660             }
06661             break;
06662         case INST_DICT_UNSET:
06663             cleanup = opnd;
06664             result = Tcl_DictObjRemoveKeyList(interp, dictPtr, opnd,
06665                     &OBJ_AT_DEPTH(opnd-1));
06666             break;
06667         default:
06668             cleanup = 0; /* stop compiler warning */
06669             Tcl_Panic("Should not happen!");
06670         }
06671 
06672         if (result != TCL_OK) {
06673             if (allocateDict) {
06674                 TclDecrRefCount(dictPtr);
06675             }
06676             TRACE_WITH_OBJ(("%u %u => ERROR updating dictionary: ",
06677                     opnd, opnd2), Tcl_GetObjResult(interp));
06678             goto checkForCatch;
06679         }
06680 
06681         if (TclIsVarDirectWritable(varPtr)) {
06682             if (allocateDict) {
06683                 Tcl_Obj *oldValuePtr = varPtr->value.objPtr;
06684 
06685                 Tcl_IncrRefCount(dictPtr);
06686                 if (oldValuePtr != NULL) {
06687                     TclDecrRefCount(oldValuePtr);
06688                 }
06689                 varPtr->value.objPtr = dictPtr;
06690             }
06691             objResultPtr = dictPtr;
06692         } else {
06693             Tcl_IncrRefCount(dictPtr);
06694             DECACHE_STACK_INFO();
06695             objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
06696                     dictPtr, TCL_LEAVE_ERR_MSG, opnd2);
06697             CACHE_STACK_INFO();
06698             TclDecrRefCount(dictPtr);
06699             if (objResultPtr == NULL) {
06700                 TRACE_APPEND(("ERROR: %.30s\n",
06701                         O2S(Tcl_GetObjResult(interp))));
06702                 result = TCL_ERROR;
06703                 goto checkForCatch;
06704             }
06705         }
06706 #ifndef TCL_COMPILE_DEBUG
06707         if (*(pc+9) == INST_POP) {
06708             NEXT_INST_V(10, cleanup, 0);
06709         }
06710 #endif
06711         TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
06712         NEXT_INST_V(9, cleanup, 1);
06713 
06714     case INST_DICT_APPEND:
06715     case INST_DICT_LAPPEND:
06716         opnd = TclGetUInt4AtPtr(pc+1);
06717 
06718         varPtr = &(compiledLocals[opnd]);
06719         while (TclIsVarLink(varPtr)) {
06720             varPtr = varPtr->value.linkPtr;
06721         }
06722         TRACE(("%u => ", opnd));
06723         if (TclIsVarDirectReadable(varPtr)) {
06724             dictPtr = varPtr->value.objPtr;
06725         } else {
06726             DECACHE_STACK_INFO();
06727             dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
06728             CACHE_STACK_INFO();
06729         }
06730         if (dictPtr == NULL) {
06731             TclNewObj(dictPtr);
06732             allocateDict = 1;
06733         } else {
06734             allocateDict = Tcl_IsShared(dictPtr);
06735             if (allocateDict) {
06736                 dictPtr = Tcl_DuplicateObj(dictPtr);
06737             }
06738         }
06739 
06740         result = Tcl_DictObjGet(interp, dictPtr, OBJ_UNDER_TOS, &valPtr);
06741         if (result != TCL_OK) {
06742             if (allocateDict) {
06743                 TclDecrRefCount(dictPtr);
06744             }
06745             goto checkForCatch;
06746         }
06747 
06748         /*
06749          * Note that a non-existent key results in a NULL valPtr, which is a
06750          * case handled separately below. What we *can* say at this point is
06751          * that the write-back will always succeed.
06752          */
06753 
06754         switch (*pc) {
06755         case INST_DICT_APPEND:
06756             if (valPtr == NULL) {
06757                 valPtr = OBJ_AT_TOS;
06758             } else {
06759                 if (Tcl_IsShared(valPtr)) {
06760                     valPtr = Tcl_DuplicateObj(valPtr);
06761                 }
06762                 Tcl_AppendObjToObj(valPtr, OBJ_AT_TOS);
06763             }
06764             break;
06765         case INST_DICT_LAPPEND:
06766             /*
06767              * More complex because list-append can fail.
06768              */
06769 
06770             if (valPtr == NULL) {
06771                 valPtr = Tcl_NewListObj(1, &OBJ_AT_TOS);
06772             } else if (Tcl_IsShared(valPtr)) {
06773                 valPtr = Tcl_DuplicateObj(valPtr);
06774                 result = Tcl_ListObjAppendElement(interp, valPtr, OBJ_AT_TOS);
06775                 if (result != TCL_OK) {
06776                     TclDecrRefCount(valPtr);
06777                     if (allocateDict) {
06778                         TclDecrRefCount(dictPtr);
06779                     }
06780                     goto checkForCatch;
06781                 }
06782             } else {
06783                 result = Tcl_ListObjAppendElement(interp, valPtr, OBJ_AT_TOS);
06784                 if (result != TCL_OK) {
06785                     if (allocateDict) {
06786                         TclDecrRefCount(dictPtr);
06787                     }
06788                     goto checkForCatch;
06789                 }
06790             }
06791             break;
06792         default:
06793             Tcl_Panic("Should not happen!");
06794         }
06795 
06796         Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS, valPtr);
06797 
06798         if (TclIsVarDirectWritable(varPtr)) {
06799             if (allocateDict) {
06800                 Tcl_Obj *oldValuePtr = varPtr->value.objPtr;
06801 
06802                 Tcl_IncrRefCount(dictPtr);
06803                 if (oldValuePtr != NULL) {
06804                     TclDecrRefCount(oldValuePtr);
06805                 }
06806                 varPtr->value.objPtr = dictPtr;
06807             }
06808             objResultPtr = dictPtr;
06809         } else {
06810             Tcl_IncrRefCount(dictPtr);
06811             DECACHE_STACK_INFO();
06812             objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
06813                     dictPtr, TCL_LEAVE_ERR_MSG, opnd);
06814             CACHE_STACK_INFO();
06815             TclDecrRefCount(dictPtr);
06816             if (objResultPtr == NULL) {
06817                 TRACE_APPEND(("ERROR: %.30s\n",
06818                         O2S(Tcl_GetObjResult(interp))));
06819                 result = TCL_ERROR;
06820                 goto checkForCatch;
06821             }
06822         }
06823 #ifndef TCL_COMPILE_DEBUG
06824         if (*(pc+5) == INST_POP) {
06825             NEXT_INST_F(6, 2, 0);
06826         }
06827 #endif
06828         TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
06829         NEXT_INST_F(5, 2, 1);
06830     }
06831 
06832     {
06833         int opnd, done;
06834         Tcl_Obj *statePtr, *dictPtr, *keyPtr, *valuePtr, *emptyPtr;
06835         Var *varPtr;
06836         Tcl_DictSearch *searchPtr;
06837 
06838     case INST_DICT_FIRST:
06839         opnd = TclGetUInt4AtPtr(pc+1);
06840         TRACE(("%u => ", opnd));
06841         dictPtr = POP_OBJECT();
06842         searchPtr = (Tcl_DictSearch *) ckalloc(sizeof(Tcl_DictSearch));
06843         result = Tcl_DictObjFirst(interp, dictPtr, searchPtr, &keyPtr,
06844                 &valuePtr, &done);
06845         if (result != TCL_OK) {
06846             ckfree((char *) searchPtr);
06847             goto checkForCatch;
06848         }
06849         TclNewObj(statePtr);
06850         statePtr->typePtr = &dictIteratorType;
06851         statePtr->internalRep.twoPtrValue.ptr1 = (void *) searchPtr;
06852         statePtr->internalRep.twoPtrValue.ptr2 = (void *) dictPtr;
06853         varPtr = (compiledLocals + opnd);
06854         if (varPtr->value.objPtr) {
06855             if (varPtr->value.objPtr->typePtr != &dictIteratorType) {
06856                 TclDecrRefCount(varPtr->value.objPtr);
06857             } else {
06858                 Tcl_Panic("mis-issued dictFirst!");
06859             }
06860         }
06861         varPtr->value.objPtr = statePtr;
06862         Tcl_IncrRefCount(statePtr);
06863         goto pushDictIteratorResult;
06864 
06865     case INST_DICT_NEXT:
06866         opnd = TclGetUInt4AtPtr(pc+1);
06867         TRACE(("%u => ", opnd));
06868         statePtr = compiledLocals[opnd].value.objPtr;
06869         if (statePtr == NULL || statePtr->typePtr != &dictIteratorType) {
06870             Tcl_Panic("mis-issued dictNext!");
06871         }
06872         searchPtr = (Tcl_DictSearch *) statePtr->internalRep.twoPtrValue.ptr1;
06873         Tcl_DictObjNext(searchPtr, &keyPtr, &valuePtr, &done);
06874     pushDictIteratorResult:
06875         if (done) {
06876             TclNewObj(emptyPtr);
06877             PUSH_OBJECT(emptyPtr);
06878             PUSH_OBJECT(emptyPtr);
06879         } else {
06880             PUSH_OBJECT(valuePtr);
06881             PUSH_OBJECT(keyPtr);
06882         }
06883         TRACE_APPEND(("\"%.30s\" \"%.30s\" %d",
06884                 O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), done));
06885         objResultPtr = constants[done];
06886         /* TODO: consider opt like INST_FOREACH_STEP4 */
06887         NEXT_INST_F(5, 0, 1);
06888 
06889     case INST_DICT_DONE:
06890         opnd = TclGetUInt4AtPtr(pc+1);
06891         TRACE(("%u => ", opnd));
06892         statePtr = compiledLocals[opnd].value.objPtr;
06893         if (statePtr == NULL) {
06894             Tcl_Panic("mis-issued dictDone!");
06895         }
06896 
06897         if (statePtr->typePtr == &dictIteratorType) {
06898             /*
06899              * First kill the search, and then release the reference to the
06900              * dictionary that we were holding.
06901              */
06902 
06903             searchPtr = (Tcl_DictSearch *)
06904                     statePtr->internalRep.twoPtrValue.ptr1;
06905             Tcl_DictObjDone(searchPtr);
06906             ckfree((char *) searchPtr);
06907 
06908             dictPtr = (Tcl_Obj *) statePtr->internalRep.twoPtrValue.ptr2;
06909             TclDecrRefCount(dictPtr);
06910 
06911             /*
06912              * Set the internal variable to an empty object to signify that we
06913              * don't hold an iterator.
06914              */
06915 
06916             TclDecrRefCount(statePtr);
06917             TclNewObj(emptyPtr);
06918             compiledLocals[opnd].value.objPtr = emptyPtr;
06919             Tcl_IncrRefCount(emptyPtr);
06920         }
06921         NEXT_INST_F(5, 0, 0);
06922     }
06923 
06924     {
06925         int opnd, opnd2, i, length, allocdict;
06926         Tcl_Obj **keyPtrPtr, *dictPtr;
06927         DictUpdateInfo *duiPtr;
06928         Var *varPtr;
06929 
06930     case INST_DICT_UPDATE_START:
06931         opnd = TclGetUInt4AtPtr(pc+1);
06932         opnd2 = TclGetUInt4AtPtr(pc+5);
06933         varPtr = &(compiledLocals[opnd]);
06934         duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
06935         while (TclIsVarLink(varPtr)) {
06936             varPtr = varPtr->value.linkPtr;
06937         }
06938         TRACE(("%u => ", opnd));
06939         if (TclIsVarDirectReadable(varPtr)) {
06940             dictPtr = varPtr->value.objPtr;
06941         } else {
06942             DECACHE_STACK_INFO();
06943             dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL,
06944                     TCL_LEAVE_ERR_MSG, opnd);
06945             CACHE_STACK_INFO();
06946             if (dictPtr == NULL) {
06947                 goto dictUpdateStartFailed;
06948             }
06949         }
06950         if (TclListObjGetElements(interp, OBJ_AT_TOS, &length,
06951                 &keyPtrPtr) != TCL_OK) {
06952             goto dictUpdateStartFailed;
06953         }
06954         if (length != duiPtr->length) {
06955             Tcl_Panic("dictUpdateStart argument length mismatch");
06956         }
06957         for (i=0 ; i<length ; i++) {
06958             Tcl_Obj *valPtr;
06959 
06960             if (Tcl_DictObjGet(interp, dictPtr, keyPtrPtr[i],
06961                     &valPtr) != TCL_OK) {
06962                 goto dictUpdateStartFailed;
06963             }
06964             varPtr = &(compiledLocals[duiPtr->varIndices[i]]);
06965             while (TclIsVarLink(varPtr)) {
06966                 varPtr = varPtr->value.linkPtr;
06967             }
06968             DECACHE_STACK_INFO();
06969             if (valPtr == NULL) {
06970                 TclObjUnsetVar2(interp,
06971                         localName(iPtr->varFramePtr, duiPtr->varIndices[i]),
06972                         NULL, 0);
06973             } else if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
06974                     valPtr, TCL_LEAVE_ERR_MSG,
06975                     duiPtr->varIndices[i]) == NULL) {
06976                 CACHE_STACK_INFO();
06977             dictUpdateStartFailed:
06978                 result = TCL_ERROR;
06979                 goto checkForCatch;
06980             }
06981             CACHE_STACK_INFO();
06982         }
06983         NEXT_INST_F(9, 0, 0);
06984 
06985     case INST_DICT_UPDATE_END:
06986         opnd = TclGetUInt4AtPtr(pc+1);
06987         opnd2 = TclGetUInt4AtPtr(pc+5);
06988         varPtr = &(compiledLocals[opnd]);
06989         duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
06990         while (TclIsVarLink(varPtr)) {
06991             varPtr = varPtr->value.linkPtr;
06992         }
06993         TRACE(("%u => ", opnd));
06994         if (TclIsVarDirectReadable(varPtr)) {
06995             dictPtr = varPtr->value.objPtr;
06996         } else {
06997             DECACHE_STACK_INFO();
06998             dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
06999             CACHE_STACK_INFO();
07000         }
07001         if (dictPtr == NULL) {
07002             NEXT_INST_F(9, 1, 0);
07003         }
07004         if (Tcl_DictObjSize(interp, dictPtr, &length) != TCL_OK
07005                 || TclListObjGetElements(interp, OBJ_AT_TOS, &length,
07006                         &keyPtrPtr) != TCL_OK) {
07007             result = TCL_ERROR;
07008             goto checkForCatch;
07009         }
07010         allocdict = Tcl_IsShared(dictPtr);
07011         if (allocdict) {
07012             dictPtr = Tcl_DuplicateObj(dictPtr);
07013         }
07014         for (i=0 ; i<length ; i++) {
07015             Tcl_Obj *valPtr;
07016             Var *var2Ptr;
07017 
07018             var2Ptr = &(compiledLocals[duiPtr->varIndices[i]]);
07019             while (TclIsVarLink(var2Ptr)) {
07020                 var2Ptr = var2Ptr->value.linkPtr;
07021             }
07022             if (TclIsVarDirectReadable(var2Ptr)) {
07023                 valPtr = var2Ptr->value.objPtr;
07024             } else {
07025                 DECACHE_STACK_INFO();
07026                 valPtr = TclPtrGetVar(interp, var2Ptr, NULL, NULL, NULL, 0,
07027                         duiPtr->varIndices[i]);
07028                 CACHE_STACK_INFO();
07029             }
07030             if (valPtr == NULL) {
07031                 Tcl_DictObjRemove(interp, dictPtr, keyPtrPtr[i]);
07032             } else if (dictPtr == valPtr) {
07033                 Tcl_DictObjPut(interp, dictPtr, keyPtrPtr[i],
07034                         Tcl_DuplicateObj(valPtr));
07035             } else {
07036                 Tcl_DictObjPut(interp, dictPtr, keyPtrPtr[i], valPtr);
07037             }
07038         }
07039         if (TclIsVarDirectWritable(varPtr)) {
07040             Tcl_IncrRefCount(dictPtr);
07041             TclDecrRefCount(varPtr->value.objPtr);
07042             varPtr->value.objPtr = dictPtr;
07043         } else {
07044             DECACHE_STACK_INFO();
07045             objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
07046                     dictPtr, TCL_LEAVE_ERR_MSG, opnd);
07047             CACHE_STACK_INFO();
07048             if (objResultPtr == NULL) {
07049                 if (allocdict) {
07050                     TclDecrRefCount(dictPtr);
07051                 }
07052                 result = TCL_ERROR;
07053                 goto checkForCatch;
07054             }
07055         }
07056         NEXT_INST_F(9, 1, 0);
07057     }
07058 
07059     default:
07060         Tcl_Panic("TclExecuteByteCode: unrecognized opCode %u", *pc);
07061     } /* end of switch on opCode */
07062 
07063     /*
07064      * Division by zero in an expression. Control only reaches this point by
07065      * "goto divideByZero".
07066      */
07067 
07068  divideByZero:
07069     Tcl_SetObjResult(interp, Tcl_NewStringObj("divide by zero", -1));
07070     Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", NULL);
07071 
07072     result = TCL_ERROR;
07073     goto checkForCatch;
07074 
07075     /*
07076      * Exponentiation of zero by negative number in an expression. Control
07077      * only reaches this point by "goto exponOfZero".
07078      */
07079 
07080  exponOfZero:
07081     Tcl_SetObjResult(interp, Tcl_NewStringObj(
07082             "exponentiation of zero by negative power", -1));
07083     Tcl_SetErrorCode(interp, "ARITH", "DOMAIN",
07084             "exponentiation of zero by negative power", NULL);
07085     result = TCL_ERROR;
07086     goto checkForCatch;
07087 
07088     /*
07089      * Block for variables needed to process exception returns.
07090      */
07091 
07092     {
07093         ExceptionRange *rangePtr;
07094                                 /* Points to closest loop or catch exception
07095                                  * range enclosing the pc. Used by various
07096                                  * instructions and processCatch to process
07097                                  * break, continue, and errors. */
07098         Tcl_Obj *valuePtr;
07099         const char *bytes;
07100         int length;
07101 #if TCL_COMPILE_DEBUG
07102         int opnd;
07103 #endif
07104 
07105         /*
07106          * An external evaluation (INST_INVOKE or INST_EVAL) returned
07107          * something different from TCL_OK, or else INST_BREAK or
07108          * INST_CONTINUE were called.
07109          */
07110 
07111     processExceptionReturn:
07112 #if TCL_COMPILE_DEBUG
07113         switch (*pc) {
07114         case INST_INVOKE_STK1:
07115             opnd = TclGetUInt1AtPtr(pc+1);
07116             TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
07117             break;
07118         case INST_INVOKE_STK4:
07119             opnd = TclGetUInt4AtPtr(pc+1);
07120             TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
07121             break;
07122         case INST_EVAL_STK:
07123             /*
07124              * Note that the object at stacktop has to be used before doing
07125              * the cleanup.
07126              */
07127 
07128             TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
07129             break;
07130         default:
07131             TRACE(("=> "));
07132         }
07133 #endif
07134         if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
07135             rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 0, codePtr);
07136             if (rangePtr == NULL) {
07137                 TRACE_APPEND(("no encl. loop or catch, returning %s\n",
07138                         StringForResultCode(result)));
07139                 goto abnormalReturn;
07140             }
07141             if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
07142                 TRACE_APPEND(("%s ...\n", StringForResultCode(result)));
07143                 goto processCatch;
07144             }
07145             while (cleanup--) {
07146                 valuePtr = POP_OBJECT();
07147                 TclDecrRefCount(valuePtr);
07148             }
07149             if (result == TCL_BREAK) {
07150                 result = TCL_OK;
07151                 pc = (codePtr->codeStart + rangePtr->breakOffset);
07152                 TRACE_APPEND(("%s, range at %d, new pc %d\n",
07153                         StringForResultCode(result),
07154                         rangePtr->codeOffset, rangePtr->breakOffset));
07155                 NEXT_INST_F(0, 0, 0);
07156             } else {
07157                 if (rangePtr->continueOffset == -1) {
07158                     TRACE_APPEND((
07159                             "%s, loop w/o continue, checking for catch\n",
07160                             StringForResultCode(result)));
07161                     goto checkForCatch;
07162                 }
07163                 result = TCL_OK;
07164                 pc = (codePtr->codeStart + rangePtr->continueOffset);
07165                 TRACE_APPEND(("%s, range at %d, new pc %d\n",
07166                         StringForResultCode(result),
07167                         rangePtr->codeOffset, rangePtr->continueOffset));
07168                 NEXT_INST_F(0, 0, 0);
07169             }
07170 #if TCL_COMPILE_DEBUG
07171         } else if (traceInstructions) {
07172             if ((result != TCL_ERROR) && (result != TCL_RETURN)) {
07173                 Tcl_Obj *objPtr = Tcl_GetObjResult(interp);
07174                 TRACE_APPEND(("OTHER RETURN CODE %d, result= \"%s\"\n ",
07175                         result, O2S(objPtr)));
07176             } else {
07177                 Tcl_Obj *objPtr = Tcl_GetObjResult(interp);
07178                 TRACE_APPEND(("%s, result= \"%s\"\n",
07179                         StringForResultCode(result), O2S(objPtr)));
07180             }
07181 #endif
07182         }
07183 
07184         /*
07185          * Execution has generated an "exception" such as TCL_ERROR. If the
07186          * exception is an error, record information about what was being
07187          * executed when the error occurred. Find the closest enclosing catch
07188          * range, if any. If no enclosing catch range is found, stop execution
07189          * and return the "exception" code.
07190          */
07191 
07192         checkForCatch:
07193         if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
07194             bytes = GetSrcInfoForPc(pc, codePtr, &length);
07195             if (bytes != NULL) {
07196                 DECACHE_STACK_INFO();
07197                 Tcl_LogCommandInfo(interp, codePtr->source, bytes, length);
07198                 CACHE_STACK_INFO();
07199             }
07200         }
07201         iPtr->flags &= ~ERR_ALREADY_LOGGED;
07202 
07203         /*
07204          * Clear all expansions that may have started after the last
07205          * INST_BEGIN_CATCH.
07206          */
07207 
07208         while ((expandNestList != NULL) && ((catchTop == initCatchTop) ||
07209                 (*catchTop <=
07210                 (ptrdiff_t) expandNestList->internalRep.twoPtrValue.ptr1))) {
07211             Tcl_Obj *objPtr = expandNestList->internalRep.twoPtrValue.ptr2;
07212 
07213             TclDecrRefCount(expandNestList);
07214             expandNestList = objPtr;
07215         }
07216 
07217         /*
07218          * We must not catch an exceeded limit. Instead, it blows outwards
07219          * until we either hit another interpreter (presumably where the limit
07220          * is not exceeded) or we get to the top-level.
07221          */
07222 
07223         if (TclLimitExceeded(iPtr->limit)) {
07224 #ifdef TCL_COMPILE_DEBUG
07225             if (traceInstructions) {
07226                 fprintf(stdout, "   ... limit exceeded, returning %s\n",
07227                         StringForResultCode(result));
07228             }
07229 #endif
07230             goto abnormalReturn;
07231         }
07232         if (catchTop == initCatchTop) {
07233 #ifdef TCL_COMPILE_DEBUG
07234             if (traceInstructions) {
07235                 fprintf(stdout, "   ... no enclosing catch, returning %s\n",
07236                         StringForResultCode(result));
07237             }
07238 #endif
07239             goto abnormalReturn;
07240         }
07241         rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 1, codePtr);
07242         if (rangePtr == NULL) {
07243             /*
07244              * This is only possible when compiling a [catch] that sends its
07245              * script to INST_EVAL. Cannot correct the compiler without
07246              * breakingcompat with previous .tbc compiled scripts.
07247              */
07248 
07249 #ifdef TCL_COMPILE_DEBUG
07250             if (traceInstructions) {
07251                 fprintf(stdout, "   ... no enclosing catch, returning %s\n",
07252                         StringForResultCode(result));
07253             }
07254 #endif
07255             goto abnormalReturn;
07256         }
07257 
07258         /*
07259          * A catch exception range (rangePtr) was found to handle an
07260          * "exception". It was found either by checkForCatch just above or by
07261          * an instruction during break, continue, or error processing. Jump to
07262          * its catchOffset after unwinding the operand stack to the depth it
07263          * had when starting to execute the range's catch command.
07264          */
07265 
07266     processCatch:
07267         while (CURR_DEPTH > *catchTop) {
07268             valuePtr = POP_OBJECT();
07269             TclDecrRefCount(valuePtr);
07270         }
07271 #ifdef TCL_COMPILE_DEBUG
07272         if (traceInstructions) {
07273             fprintf(stdout, "  ... found catch at %d, catchTop=%d, "
07274                     "unwound to %ld, new pc %u\n",
07275                     rangePtr->codeOffset, catchTop - initCatchTop - 1,
07276                     (long) *catchTop, (unsigned) rangePtr->catchOffset);
07277         }
07278 #endif
07279         pc = (codePtr->codeStart + rangePtr->catchOffset);
07280         NEXT_INST_F(0, 0, 0);   /* Restart the execution loop at pc. */
07281 
07282         /*
07283          * end of infinite loop dispatching on instructions.
07284          */
07285 
07286         /*
07287          * Abnormal return code. Restore the stack to state it had when
07288          * starting to execute the ByteCode. Panic if the stack is below the
07289          * initial level.
07290          */
07291 
07292     abnormalReturn:
07293         TCL_DTRACE_INST_LAST();
07294         while (tosPtr > initTosPtr) {
07295             Tcl_Obj *objPtr = POP_OBJECT();
07296 
07297             Tcl_DecrRefCount(objPtr);
07298         }
07299 
07300         /*
07301          * Clear all expansions.
07302          */
07303 
07304         while (expandNestList) {
07305             Tcl_Obj *objPtr = expandNestList->internalRep.twoPtrValue.ptr2;
07306 
07307             TclDecrRefCount(expandNestList);
07308             expandNestList = objPtr;
07309         }
07310         if (tosPtr < initTosPtr) {
07311             fprintf(stderr,
07312                     "\nTclExecuteByteCode: abnormal return at pc %u: "
07313                     "stack top %d < entry stack top %d\n",
07314                     (unsigned)(pc - codePtr->codeStart),
07315                     (unsigned) CURR_DEPTH, (unsigned) 0);
07316             Tcl_Panic("TclExecuteByteCode execution failure: end stack top < start stack top");
07317         }
07318     }
07319 
07320     /*
07321      * Restore the stack to the state it had previous to this bytecode.
07322      */
07323 
07324     TclStackFree(interp, initCatchTop+1);
07325     return result;
07326 #undef iPtr
07327 }
07328 
07329 #ifdef TCL_COMPILE_DEBUG
07330 /*
07331  *----------------------------------------------------------------------
07332  *
07333  * PrintByteCodeInfo --
07334  *
07335  *      This procedure prints a summary about a bytecode object to stdout. It
07336  *      is called by TclExecuteByteCode when starting to execute the bytecode
07337  *      object if tclTraceExec has the value 2 or more.
07338  *
07339  * Results:
07340  *      None.
07341  *
07342  * Side effects:
07343  *      None.
07344  *
07345  *----------------------------------------------------------------------
07346  */
07347 
07348 static void
07349 PrintByteCodeInfo(
07350     register ByteCode *codePtr) /* The bytecode whose summary is printed to
07351                                  * stdout. */
07352 {
07353     Proc *procPtr = codePtr->procPtr;
07354     Interp *iPtr = (Interp *) *codePtr->interpHandle;
07355 
07356     fprintf(stdout, "\nExecuting ByteCode 0x%p, refCt %u, epoch %u, interp 0x%p (epoch %u)\n",
07357             codePtr, codePtr->refCount, codePtr->compileEpoch, iPtr,
07358             iPtr->compileEpoch);
07359 
07360     fprintf(stdout, "  Source: ");
07361     TclPrintSource(stdout, codePtr->source, 60);
07362 
07363     fprintf(stdout, "\n  Cmds %d, src %d, inst %u, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n",
07364             codePtr->numCommands, codePtr->numSrcBytes,
07365             codePtr->numCodeBytes, codePtr->numLitObjects,
07366             codePtr->numAuxDataItems, codePtr->maxStackDepth,
07367 #ifdef TCL_COMPILE_STATS
07368             codePtr->numSrcBytes?
07369                     ((float)codePtr->structureSize)/codePtr->numSrcBytes :
07370 #endif
07371             0.0);
07372 
07373 #ifdef TCL_COMPILE_STATS
07374     fprintf(stdout, "  Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n",
07375             (unsigned long) codePtr->structureSize,
07376             (unsigned long) (sizeof(ByteCode)-sizeof(size_t)-sizeof(Tcl_Time)),
07377             codePtr->numCodeBytes,
07378             (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
07379             (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)),
07380             (unsigned long) (codePtr->numAuxDataItems * sizeof(AuxData)),
07381             codePtr->numCmdLocBytes);
07382 #endif /* TCL_COMPILE_STATS */
07383     if (procPtr != NULL) {
07384         fprintf(stdout,
07385                 "  Proc 0x%p, refCt %d, args %d, compiled locals %d\n",
07386                 procPtr, procPtr->refCount, procPtr->numArgs,
07387                 procPtr->numCompiledLocals);
07388     }
07389 }
07390 #endif /* TCL_COMPILE_DEBUG */
07391 
07392 /*
07393  *----------------------------------------------------------------------
07394  *
07395  * ValidatePcAndStackTop --
07396  *
07397  *      This procedure is called by TclExecuteByteCode when debugging to
07398  *      verify that the program counter and stack top are valid during
07399  *      execution.
07400  *
07401  * Results:
07402  *      None.
07403  *
07404  * Side effects:
07405  *      Prints a message to stderr and panics if either the pc or stack top
07406  *      are invalid.
07407  *
07408  *----------------------------------------------------------------------
07409  */
07410 
07411 #ifdef TCL_COMPILE_DEBUG
07412 static void
07413 ValidatePcAndStackTop(
07414     register ByteCode *codePtr, /* The bytecode whose summary is printed to
07415                                  * stdout. */
07416     unsigned char *pc,          /* Points to first byte of a bytecode
07417                                  * instruction. The program counter. */
07418     int stackTop,               /* Current stack top. Must be between
07419                                  * stackLowerBound and stackUpperBound
07420                                  * (inclusive). */
07421     int stackLowerBound,        /* Smallest legal value for stackTop. */
07422     int checkStack)             /* 0 if the stack depth check should be
07423                                  * skipped. */
07424 {
07425     int stackUpperBound = stackLowerBound + codePtr->maxStackDepth;
07426                                 /* Greatest legal value for stackTop. */
07427     unsigned relativePc = (unsigned) (pc - codePtr->codeStart);
07428     unsigned long codeStart = (unsigned long) codePtr->codeStart;
07429     unsigned long codeEnd = (unsigned long)
07430             (codePtr->codeStart + codePtr->numCodeBytes);
07431     unsigned char opCode = *pc;
07432 
07433     if (((unsigned long) pc < codeStart) || ((unsigned long) pc > codeEnd)) {
07434         fprintf(stderr, "\nBad instruction pc 0x%p in TclExecuteByteCode\n",
07435                 pc);
07436         Tcl_Panic("TclExecuteByteCode execution failure: bad pc");
07437     }
07438     if ((unsigned) opCode > LAST_INST_OPCODE) {
07439         fprintf(stderr, "\nBad opcode %d at pc %u in TclExecuteByteCode\n",
07440                 (unsigned) opCode, relativePc);
07441         Tcl_Panic("TclExecuteByteCode execution failure: bad opcode");
07442     }
07443     if (checkStack &&
07444             ((stackTop < stackLowerBound) || (stackTop > stackUpperBound))) {
07445         int numChars;
07446         const char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars);
07447 
07448         fprintf(stderr, "\nBad stack top %d at pc %u in TclExecuteByteCode (min %i, max %i)",
07449                 stackTop, relativePc, stackLowerBound, stackUpperBound);
07450         if (cmd != NULL) {
07451             Tcl_Obj *message;
07452 
07453             TclNewLiteralStringObj(message, "\n executing ");
07454             Tcl_IncrRefCount(message);
07455             Tcl_AppendLimitedToObj(message, cmd, numChars, 100, NULL);
07456             fprintf(stderr,"%s\n", Tcl_GetString(message));
07457             Tcl_DecrRefCount(message);
07458         } else {
07459             fprintf(stderr, "\n");
07460         }
07461         Tcl_Panic("TclExecuteByteCode execution failure: bad stack top");
07462     }
07463 }
07464 #endif /* TCL_COMPILE_DEBUG */
07465 
07466 /*
07467  *----------------------------------------------------------------------
07468  *
07469  * IllegalExprOperandType --
07470  *
07471  *      Used by TclExecuteByteCode to append an error message to the interp
07472  *      result when an illegal operand type is detected by an expression
07473  *      instruction. The argument opndPtr holds the operand object in error.
07474  *
07475  * Results:
07476  *      None.
07477  *
07478  * Side effects:
07479  *      An error message is appended to the interp result.
07480  *
07481  *----------------------------------------------------------------------
07482  */
07483 
07484 static void
07485 IllegalExprOperandType(
07486     Tcl_Interp *interp,         /* Interpreter to which error information
07487                                  * pertains. */
07488     unsigned char *pc,          /* Points to the instruction being executed
07489                                  * when the illegal type was found. */
07490     Tcl_Obj *opndPtr)           /* Points to the operand holding the value
07491                                  * with the illegal type. */
07492 {
07493     ClientData ptr;
07494     int type;
07495     unsigned char opcode = *pc;
07496     const char *description, *operator = operatorStrings[opcode - INST_LOR];
07497 
07498     if (opcode == INST_EXPON) {
07499         operator = "**";
07500     }
07501 
07502     if (GetNumberFromObj(NULL, opndPtr, &ptr, &type) != TCL_OK) {
07503         int numBytes;
07504         const char *bytes = Tcl_GetStringFromObj(opndPtr, &numBytes);
07505 
07506         if (numBytes == 0) {
07507             description = "empty string";
07508         } else if (TclCheckBadOctal(NULL, bytes)) {
07509             description = "invalid octal number";
07510         } else {
07511             description = "non-numeric string";
07512         }
07513     } else if (type == TCL_NUMBER_NAN) {
07514         description = "non-numeric floating-point value";
07515     } else if (type == TCL_NUMBER_DOUBLE) {
07516         description = "floating-point value";
07517     } else {
07518         /* TODO: No caller needs this. Eliminate? */
07519         description = "(big) integer";
07520     }
07521 
07522     Tcl_SetObjResult(interp, Tcl_ObjPrintf(
07523             "can't use %s as operand of \"%s\"", description, operator));
07524 }
07525 
07526 /*
07527  *----------------------------------------------------------------------
07528  *
07529  * TclGetSrcInfoForPc, GetSrcInfoForPc, TclGetSrcInfoForCmd --
07530  *
07531  *      Given a program counter value, finds the closest command in the
07532  *      bytecode code unit's CmdLocation array and returns information about
07533  *      that command's source: a pointer to its first byte and the number of
07534  *      characters.
07535  *
07536  * Results:
07537  *      If a command is found that encloses the program counter value, a
07538  *      pointer to the command's source is returned and the length of the
07539  *      source is stored at *lengthPtr. If multiple commands resulted in code
07540  *      at pc, information about the closest enclosing command is returned. If
07541  *      no matching command is found, NULL is returned and *lengthPtr is
07542  *      unchanged.
07543  *
07544  * Side effects:
07545  *      The CmdFrame at *cfPtr is updated.
07546  *
07547  *----------------------------------------------------------------------
07548  */
07549 
07550 const char *
07551 TclGetSrcInfoForCmd(
07552     Interp *iPtr,
07553     int *lenPtr)
07554 {
07555     CmdFrame *cfPtr = iPtr->cmdFramePtr;
07556     ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr;
07557 
07558     return GetSrcInfoForPc((unsigned char *) cfPtr->data.tebc.pc,
07559             codePtr, lenPtr);
07560 }
07561 
07562 void
07563 TclGetSrcInfoForPc(
07564     CmdFrame *cfPtr)
07565 {
07566     ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr;
07567 
07568     if (cfPtr->cmd.str.cmd == NULL) {
07569         cfPtr->cmd.str.cmd = GetSrcInfoForPc(
07570                 (unsigned char *) cfPtr->data.tebc.pc, codePtr,
07571                 &cfPtr->cmd.str.len);
07572     }
07573 
07574     if (cfPtr->cmd.str.cmd != NULL) {
07575         /*
07576          * We now have the command. We can get the srcOffset back and from
07577          * there find the list of word locations for this command.
07578          */
07579 
07580         ExtCmdLoc *eclPtr;
07581         ECL *locPtr = NULL;
07582         int srcOffset, i;
07583         Interp *iPtr = (Interp *) *codePtr->interpHandle;
07584         Tcl_HashEntry *hePtr =
07585                 Tcl_FindHashEntry(iPtr->lineBCPtr, (char *) codePtr);
07586 
07587         if (!hePtr) {
07588             return;
07589         }
07590 
07591         srcOffset = cfPtr->cmd.str.cmd - codePtr->source;
07592         eclPtr = (ExtCmdLoc *) Tcl_GetHashValue (hePtr);
07593 
07594         for (i=0; i < eclPtr->nuloc; i++) {
07595             if (eclPtr->loc[i].srcOffset == srcOffset) {
07596                 locPtr = eclPtr->loc+i;
07597                 break;
07598             }
07599         }
07600         if (locPtr == NULL) {
07601             Tcl_Panic("LocSearch failure");
07602         }
07603 
07604         cfPtr->line = locPtr->line;
07605         cfPtr->nline = locPtr->nline;
07606         cfPtr->type = eclPtr->type;
07607 
07608         if (eclPtr->type == TCL_LOCATION_SOURCE) {
07609             cfPtr->data.eval.path = eclPtr->path;
07610             Tcl_IncrRefCount(cfPtr->data.eval.path);
07611         }
07612 
07613         /*
07614          * Do not set cfPtr->data.eval.path NULL for non-SOURCE. Needed for
07615          * cfPtr->data.tebc.codePtr.
07616          */
07617     }
07618 }
07619 
07620 static const char *
07621 GetSrcInfoForPc(
07622     unsigned char *pc,          /* The program counter value for which to
07623                                  * return the closest command's source info.
07624                                  * This points to a bytecode instruction in
07625                                  * codePtr's code. */
07626     ByteCode *codePtr,          /* The bytecode sequence in which to look up
07627                                  * the command source for the pc. */
07628     int *lengthPtr)             /* If non-NULL, the location where the length
07629                                  * of the command's source should be stored.
07630                                  * If NULL, no length is stored. */
07631 {
07632     register int pcOffset = (pc - codePtr->codeStart);
07633     int numCmds = codePtr->numCommands;
07634     unsigned char *codeDeltaNext, *codeLengthNext;
07635     unsigned char *srcDeltaNext, *srcLengthNext;
07636     int codeOffset, codeLen, codeEnd, srcOffset, srcLen, delta, i;
07637     int bestDist = INT_MAX;     /* Distance of pc to best cmd's start pc. */
07638     int bestSrcOffset = -1;     /* Initialized to avoid compiler warning. */
07639     int bestSrcLength = -1;     /* Initialized to avoid compiler warning. */
07640 
07641     if ((pcOffset < 0) || (pcOffset >= codePtr->numCodeBytes)) {
07642         return NULL;
07643     }
07644 
07645     /*
07646      * Decode the code and source offset and length for each command. The
07647      * closest enclosing command is the last one whose code started before
07648      * pcOffset.
07649      */
07650 
07651     codeDeltaNext = codePtr->codeDeltaStart;
07652     codeLengthNext = codePtr->codeLengthStart;
07653     srcDeltaNext = codePtr->srcDeltaStart;
07654     srcLengthNext = codePtr->srcLengthStart;
07655     codeOffset = srcOffset = 0;
07656     for (i = 0;  i < numCmds;  i++) {
07657         if ((unsigned) *codeDeltaNext == (unsigned) 0xFF) {
07658             codeDeltaNext++;
07659             delta = TclGetInt4AtPtr(codeDeltaNext);
07660             codeDeltaNext += 4;
07661         } else {
07662             delta = TclGetInt1AtPtr(codeDeltaNext);
07663             codeDeltaNext++;
07664         }
07665         codeOffset += delta;
07666 
07667         if ((unsigned) *codeLengthNext == (unsigned) 0xFF) {
07668             codeLengthNext++;
07669             codeLen = TclGetInt4AtPtr(codeLengthNext);
07670             codeLengthNext += 4;
07671         } else {
07672             codeLen = TclGetInt1AtPtr(codeLengthNext);
07673             codeLengthNext++;
07674         }
07675         codeEnd = (codeOffset + codeLen - 1);
07676 
07677         if ((unsigned) *srcDeltaNext == (unsigned) 0xFF) {
07678             srcDeltaNext++;
07679             delta = TclGetInt4AtPtr(srcDeltaNext);
07680             srcDeltaNext += 4;
07681         } else {
07682             delta = TclGetInt1AtPtr(srcDeltaNext);
07683             srcDeltaNext++;
07684         }
07685         srcOffset += delta;
07686 
07687         if ((unsigned) *srcLengthNext == (unsigned) 0xFF) {
07688             srcLengthNext++;
07689             srcLen = TclGetInt4AtPtr(srcLengthNext);
07690             srcLengthNext += 4;
07691         } else {
07692             srcLen = TclGetInt1AtPtr(srcLengthNext);
07693             srcLengthNext++;
07694         }
07695 
07696         if (codeOffset > pcOffset) {    /* Best cmd already found */
07697             break;
07698         }
07699         if (pcOffset <= codeEnd) {      /* This cmd's code encloses pc */
07700             int dist = (pcOffset - codeOffset);
07701 
07702             if (dist <= bestDist) {
07703                 bestDist = dist;
07704                 bestSrcOffset = srcOffset;
07705                 bestSrcLength = srcLen;
07706             }
07707         }
07708     }
07709 
07710     if (bestDist == INT_MAX) {
07711         return NULL;
07712     }
07713 
07714     if (lengthPtr != NULL) {
07715         *lengthPtr = bestSrcLength;
07716     }
07717     return (codePtr->source + bestSrcOffset);
07718 }
07719 
07720 /*
07721  *----------------------------------------------------------------------
07722  *
07723  * GetExceptRangeForPc --
07724  *
07725  *      Given a program counter value, return the closest enclosing
07726  *      ExceptionRange.
07727  *
07728  * Results:
07729  *      In the normal case, catchOnly is 0 (false) and this procedure returns
07730  *      a pointer to the most closely enclosing ExceptionRange structure
07731  *      regardless of whether it is a loop or catch exception range. This is
07732  *      appropriate when processing a TCL_BREAK or TCL_CONTINUE, which will be
07733  *      "handled" either by a loop exception range or a closer catch range. If
07734  *      catchOnly is nonzero, this procedure ignores loop exception ranges and
07735  *      returns a pointer to the closest catch range. If no matching
07736  *      ExceptionRange is found that encloses pc, a NULL is returned.
07737  *
07738  * Side effects:
07739  *      None.
07740  *
07741  *----------------------------------------------------------------------
07742  */
07743 
07744 static ExceptionRange *
07745 GetExceptRangeForPc(
07746     unsigned char *pc,          /* The program counter value for which to
07747                                  * search for a closest enclosing exception
07748                                  * range. This points to a bytecode
07749                                  * instruction in codePtr's code. */
07750     int catchOnly,              /* If 0, consider either loop or catch
07751                                  * ExceptionRanges in search. If nonzero
07752                                  * consider only catch ranges (and ignore any
07753                                  * closer loop ranges). */
07754     ByteCode *codePtr)          /* Points to the ByteCode in which to search
07755                                  * for the enclosing ExceptionRange. */
07756 {
07757     ExceptionRange *rangeArrayPtr;
07758     int numRanges = codePtr->numExceptRanges;
07759     register ExceptionRange *rangePtr;
07760     int pcOffset = pc - codePtr->codeStart;
07761     register int start;
07762 
07763     if (numRanges == 0) {
07764         return NULL;
07765     }
07766 
07767     /*
07768      * This exploits peculiarities of our compiler: nested ranges are always
07769      * *after* their containing ranges, so that by scanning backwards we are
07770      * sure that the first matching range is indeed the deepest.
07771      */
07772 
07773     rangeArrayPtr = codePtr->exceptArrayPtr;
07774     rangePtr = rangeArrayPtr + numRanges;
07775     while (--rangePtr >= rangeArrayPtr) {
07776         start = rangePtr->codeOffset;
07777         if ((start <= pcOffset) &&
07778                 (pcOffset < (start + rangePtr->numCodeBytes))) {
07779             if ((!catchOnly)
07780                     || (rangePtr->type == CATCH_EXCEPTION_RANGE)) {
07781                 return rangePtr;
07782             }
07783         }
07784     }
07785     return NULL;
07786 }
07787 
07788 /*
07789  *----------------------------------------------------------------------
07790  *
07791  * GetOpcodeName --
07792  *
07793  *      This procedure is called by the TRACE and TRACE_WITH_OBJ macros used
07794  *      in TclExecuteByteCode when debugging. It returns the name of the
07795  *      bytecode instruction at a specified instruction pc.
07796  *
07797  * Results:
07798  *      A character string for the instruction.
07799  *
07800  * Side effects:
07801  *      None.
07802  *
07803  *----------------------------------------------------------------------
07804  */
07805 
07806 #ifdef TCL_COMPILE_DEBUG
07807 static char *
07808 GetOpcodeName(
07809     unsigned char *pc)          /* Points to the instruction whose name should
07810                                  * be returned. */
07811 {
07812     unsigned char opCode = *pc;
07813 
07814     return tclInstructionTable[opCode].name;
07815 }
07816 #endif /* TCL_COMPILE_DEBUG */
07817 
07818 /*
07819  *----------------------------------------------------------------------
07820  *
07821  * TclExprFloatError --
07822  *
07823  *      This procedure is called when an error occurs during a floating-point
07824  *      operation. It reads errno and sets interp->objResultPtr accordingly.
07825  *
07826  * Results:
07827  *      interp->objResultPtr is set to hold an error message.
07828  *
07829  * Side effects:
07830  *      None.
07831  *
07832  *----------------------------------------------------------------------
07833  */
07834 
07835 void
07836 TclExprFloatError(
07837     Tcl_Interp *interp,         /* Where to store error message. */
07838     double value)               /* Value returned after error; used to
07839                                  * distinguish underflows from overflows. */
07840 {
07841     const char *s;
07842 
07843     if ((errno == EDOM) || TclIsNaN(value)) {
07844         s = "domain error: argument not in valid range";
07845         Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1));
07846         Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", s, NULL);
07847     } else if ((errno == ERANGE) || TclIsInfinite(value)) {
07848         if (value == 0.0) {
07849             s = "floating-point value too small to represent";
07850             Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1));
07851             Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", s, NULL);
07852         } else {
07853             s = "floating-point value too large to represent";
07854             Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1));
07855             Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", s, NULL);
07856         }
07857     } else {
07858         Tcl_Obj *objPtr = Tcl_ObjPrintf(
07859                 "unknown floating-point error, errno = %d", errno);
07860 
07861         Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN",
07862                 Tcl_GetString(objPtr), NULL);
07863         Tcl_SetObjResult(interp, objPtr);
07864     }
07865 }
07866 
07867 #ifdef TCL_COMPILE_STATS
07868 /*
07869  *----------------------------------------------------------------------
07870  *
07871  * TclLog2 --
07872  *
07873  *      Procedure used while collecting compilation statistics to determine
07874  *      the log base 2 of an integer.
07875  *
07876  * Results:
07877  *      Returns the log base 2 of the operand. If the argument is less than or
07878  *      equal to zero, a zero is returned.
07879  *
07880  * Side effects:
07881  *      None.
07882  *
07883  *----------------------------------------------------------------------
07884  */
07885 
07886 int
07887 TclLog2(
07888     register int value)         /* The integer for which to compute the log
07889                                  * base 2. */
07890 {
07891     register int n = value;
07892     register int result = 0;
07893 
07894     while (n > 1) {
07895         n = n >> 1;
07896         result++;
07897     }
07898     return result;
07899 }
07900 
07901 /*
07902  *----------------------------------------------------------------------
07903  *
07904  * EvalStatsCmd --
07905  *
07906  *      Implements the "evalstats" command that prints instruction execution
07907  *      counts to stdout.
07908  *
07909  * Results:
07910  *      Standard Tcl results.
07911  *
07912  * Side effects:
07913  *      None.
07914  *
07915  *----------------------------------------------------------------------
07916  */
07917 
07918 static int
07919 EvalStatsCmd(
07920     ClientData unused,          /* Unused. */
07921     Tcl_Interp *interp,         /* The current interpreter. */
07922     int objc,                   /* The number of arguments. */
07923     Tcl_Obj *const objv[])      /* The argument strings. */
07924 {
07925     Interp *iPtr = (Interp *) interp;
07926     LiteralTable *globalTablePtr = &iPtr->literalTable;
07927     ByteCodeStats *statsPtr = &iPtr->stats;
07928     double totalCodeBytes, currentCodeBytes;
07929     double totalLiteralBytes, currentLiteralBytes;
07930     double objBytesIfUnshared, strBytesIfUnshared, sharingBytesSaved;
07931     double strBytesSharedMultX, strBytesSharedOnce;
07932     double numInstructions, currentHeaderBytes;
07933     long numCurrentByteCodes, numByteCodeLits;
07934     long refCountSum, literalMgmtBytes, sum;
07935     int numSharedMultX, numSharedOnce;
07936     int decadeHigh, minSizeDecade, maxSizeDecade, length, i;
07937     char *litTableStats;
07938     LiteralEntry *entryPtr;
07939 
07940 #define Percent(a,b) ((a) * 100.0 / (b))
07941 
07942     numInstructions = 0.0;
07943     for (i = 0;  i < 256;  i++) {
07944         if (statsPtr->instructionCount[i] != 0) {
07945             numInstructions += statsPtr->instructionCount[i];
07946         }
07947     }
07948 
07949     totalLiteralBytes = sizeof(LiteralTable)
07950             + iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)
07951             + (statsPtr->numLiteralsCreated * sizeof(LiteralEntry))
07952             + (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj))
07953             + statsPtr->totalLitStringBytes;
07954     totalCodeBytes = statsPtr->totalByteCodeBytes + totalLiteralBytes;
07955 
07956     numCurrentByteCodes =
07957             statsPtr->numCompilations - statsPtr->numByteCodesFreed;
07958     currentHeaderBytes = numCurrentByteCodes
07959             * (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time));
07960     literalMgmtBytes = sizeof(LiteralTable)
07961             + (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *))
07962             + (iPtr->literalTable.numEntries * sizeof(LiteralEntry));
07963     currentLiteralBytes = literalMgmtBytes
07964             + iPtr->literalTable.numEntries * sizeof(Tcl_Obj)
07965             + statsPtr->currentLitStringBytes;
07966     currentCodeBytes = statsPtr->currentByteCodeBytes + currentLiteralBytes;
07967 
07968     /*
07969      * Summary statistics, total and current source and ByteCode sizes.
07970      */
07971 
07972     fprintf(stdout, "\n----------------------------------------------------------------\n");
07973     fprintf(stdout,
07974             "Compilation and execution statistics for interpreter 0x%p\n",
07975             iPtr);
07976 
07977     fprintf(stdout, "\nNumber ByteCodes executed        %ld\n",
07978             statsPtr->numExecutions);
07979     fprintf(stdout, "Number ByteCodes compiled  %ld\n",
07980             statsPtr->numCompilations);
07981     fprintf(stdout, "  Mean executions/compile  %.1f\n",
07982             statsPtr->numExecutions / (float)statsPtr->numCompilations);
07983 
07984     fprintf(stdout, "\nInstructions executed            %.0f\n",
07985             numInstructions);
07986     fprintf(stdout, "  Mean inst/compile                %.0f\n",
07987             numInstructions / statsPtr->numCompilations);
07988     fprintf(stdout, "  Mean inst/execution              %.0f\n",
07989             numInstructions / statsPtr->numExecutions);
07990 
07991     fprintf(stdout, "\nTotal ByteCodes                  %ld\n",
07992             statsPtr->numCompilations);
07993     fprintf(stdout, "  Source bytes                     %.6g\n",
07994             statsPtr->totalSrcBytes);
07995     fprintf(stdout, "  Code bytes                       %.6g\n",
07996             totalCodeBytes);
07997     fprintf(stdout, "    ByteCode bytes         %.6g\n",
07998             statsPtr->totalByteCodeBytes);
07999     fprintf(stdout, "    Literal bytes          %.6g\n",
08000             totalLiteralBytes);
08001     fprintf(stdout, "      table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
08002             (unsigned long) sizeof(LiteralTable),
08003             (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
08004             (unsigned long) (statsPtr->numLiteralsCreated * sizeof(LiteralEntry)),
08005             (unsigned long) (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj)),
08006             statsPtr->totalLitStringBytes);
08007     fprintf(stdout, "  Mean code/compile                %.1f\n",
08008             totalCodeBytes / statsPtr->numCompilations);
08009     fprintf(stdout, "  Mean code/source         %.1f\n",
08010             totalCodeBytes / statsPtr->totalSrcBytes);
08011 
08012     fprintf(stdout, "\nCurrent (active) ByteCodes       %ld\n",
08013             numCurrentByteCodes);
08014     fprintf(stdout, "  Source bytes                     %.6g\n",
08015             statsPtr->currentSrcBytes);
08016     fprintf(stdout, "  Code bytes                       %.6g\n",
08017             currentCodeBytes);
08018     fprintf(stdout, "    ByteCode bytes         %.6g\n",
08019             statsPtr->currentByteCodeBytes);
08020     fprintf(stdout, "    Literal bytes          %.6g\n",
08021             currentLiteralBytes);
08022     fprintf(stdout, "      table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
08023             (unsigned long) sizeof(LiteralTable),
08024             (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
08025             (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)),
08026             (unsigned long) (iPtr->literalTable.numEntries * sizeof(Tcl_Obj)),
08027             statsPtr->currentLitStringBytes);
08028     fprintf(stdout, "  Mean code/source         %.1f\n",
08029             currentCodeBytes / statsPtr->currentSrcBytes);
08030     fprintf(stdout, "  Code + source bytes              %.6g (%0.1f mean code/src)\n",
08031             (currentCodeBytes + statsPtr->currentSrcBytes),
08032             (currentCodeBytes / statsPtr->currentSrcBytes) + 1.0);
08033 
08034     /*
08035      * Tcl_IsShared statistics check
08036      *
08037      * This gives the refcount of each obj as Tcl_IsShared was called for it.
08038      * Shared objects must be duplicated before they can be modified.
08039      */
08040 
08041     numSharedMultX = 0;
08042     fprintf(stdout, "\nTcl_IsShared object check (all objects):\n");
08043     fprintf(stdout, "  Object had refcount <=1 (not shared)     %ld\n",
08044             tclObjsShared[1]);
08045     for (i = 2;  i < TCL_MAX_SHARED_OBJ_STATS;  i++) {
08046         fprintf(stdout, "  refcount ==%d                %ld\n",
08047                 i, tclObjsShared[i]);
08048         numSharedMultX += tclObjsShared[i];
08049     }
08050     fprintf(stdout, "  refcount >=%d            %ld\n",
08051             i, tclObjsShared[0]);
08052     numSharedMultX += tclObjsShared[0];
08053     fprintf(stdout, "  Total shared objects                     %d\n",
08054             numSharedMultX);
08055 
08056     /*
08057      * Literal table statistics.
08058      */
08059 
08060     numByteCodeLits = 0;
08061     refCountSum = 0;
08062     numSharedMultX = 0;
08063     numSharedOnce = 0;
08064     objBytesIfUnshared = 0.0;
08065     strBytesIfUnshared = 0.0;
08066     strBytesSharedMultX = 0.0;
08067     strBytesSharedOnce = 0.0;
08068     for (i = 0;  i < globalTablePtr->numBuckets;  i++) {
08069         for (entryPtr = globalTablePtr->buckets[i];  entryPtr != NULL;
08070                 entryPtr = entryPtr->nextPtr) {
08071             if (entryPtr->objPtr->typePtr == &tclByteCodeType) {
08072                 numByteCodeLits++;
08073             }
08074             (void) Tcl_GetStringFromObj(entryPtr->objPtr, &length);
08075             refCountSum += entryPtr->refCount;
08076             objBytesIfUnshared += (entryPtr->refCount * sizeof(Tcl_Obj));
08077             strBytesIfUnshared += (entryPtr->refCount * (length+1));
08078             if (entryPtr->refCount > 1) {
08079                 numSharedMultX++;
08080                 strBytesSharedMultX += (length+1);
08081             } else {
08082                 numSharedOnce++;
08083                 strBytesSharedOnce += (length+1);
08084             }
08085         }
08086     }
08087     sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared)
08088             - currentLiteralBytes;
08089 
08090     fprintf(stdout, "\nTotal objects (all interps)      %ld\n",
08091             tclObjsAlloced);
08092     fprintf(stdout, "Current objects                    %ld\n",
08093             (tclObjsAlloced - tclObjsFreed));
08094     fprintf(stdout, "Total literal objects              %ld\n",
08095             statsPtr->numLiteralsCreated);
08096 
08097     fprintf(stdout, "\nCurrent literal objects          %d (%0.1f%% of current objects)\n",
08098             globalTablePtr->numEntries,
08099             Percent(globalTablePtr->numEntries, tclObjsAlloced-tclObjsFreed));
08100     fprintf(stdout, "  ByteCode literals                %ld (%0.1f%% of current literals)\n",
08101             numByteCodeLits,
08102             Percent(numByteCodeLits, globalTablePtr->numEntries));
08103     fprintf(stdout, "  Literals reused > 1x             %d\n",
08104             numSharedMultX);
08105     fprintf(stdout, "  Mean reference count             %.2f\n",
08106             ((double) refCountSum) / globalTablePtr->numEntries);
08107     fprintf(stdout, "  Mean len, str reused >1x         %.2f\n",
08108             (numSharedMultX ? strBytesSharedMultX/numSharedMultX : 0.0));
08109     fprintf(stdout, "  Mean len, str used 1x            %.2f\n",
08110             (numSharedOnce ? strBytesSharedOnce/numSharedOnce : 0.0));
08111     fprintf(stdout, "  Total sharing savings            %.6g (%0.1f%% of bytes if no sharing)\n",
08112             sharingBytesSaved,
08113             Percent(sharingBytesSaved, objBytesIfUnshared+strBytesIfUnshared));
08114     fprintf(stdout, "    Bytes with sharing             %.6g\n",
08115             currentLiteralBytes);
08116     fprintf(stdout, "      table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
08117             (unsigned long) sizeof(LiteralTable),
08118             (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
08119             (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)),
08120             (unsigned long) (iPtr->literalTable.numEntries * sizeof(Tcl_Obj)),
08121             statsPtr->currentLitStringBytes);
08122     fprintf(stdout, "    Bytes if no sharing            %.6g = objects %.6g + strings %.6g\n",
08123             (objBytesIfUnshared + strBytesIfUnshared),
08124             objBytesIfUnshared, strBytesIfUnshared);
08125     fprintf(stdout, "  String sharing savings   %.6g = unshared %.6g - shared %.6g\n",
08126             (strBytesIfUnshared - statsPtr->currentLitStringBytes),
08127             strBytesIfUnshared, statsPtr->currentLitStringBytes);
08128     fprintf(stdout, "  Literal mgmt overhead            %ld (%0.1f%% of bytes with sharing)\n",
08129             literalMgmtBytes,
08130             Percent(literalMgmtBytes, currentLiteralBytes));
08131     fprintf(stdout, "    table %lu + buckets %lu + entries %lu\n",
08132             (unsigned long) sizeof(LiteralTable),
08133             (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
08134             (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)));
08135 
08136     /*
08137      * Breakdown of current ByteCode space requirements.
08138      */
08139 
08140     fprintf(stdout, "\nBreakdown of current ByteCode requirements:\n");
08141     fprintf(stdout, "                         Bytes      Pct of    Avg per\n");
08142     fprintf(stdout, "                                     total    ByteCode\n");
08143     fprintf(stdout, "Total             %12.6g     100.00%%   %8.1f\n",
08144             statsPtr->currentByteCodeBytes,
08145             statsPtr->currentByteCodeBytes / numCurrentByteCodes);
08146     fprintf(stdout, "Header            %12.6g   %8.1f%%   %8.1f\n",
08147             currentHeaderBytes,
08148             Percent(currentHeaderBytes, statsPtr->currentByteCodeBytes),
08149             currentHeaderBytes / numCurrentByteCodes);
08150     fprintf(stdout, "Instructions      %12.6g   %8.1f%%   %8.1f\n",
08151             statsPtr->currentInstBytes,
08152             Percent(statsPtr->currentInstBytes,statsPtr->currentByteCodeBytes),
08153             statsPtr->currentInstBytes / numCurrentByteCodes);
08154     fprintf(stdout, "Literal ptr array %12.6g   %8.1f%%   %8.1f\n",
08155             statsPtr->currentLitBytes,
08156             Percent(statsPtr->currentLitBytes,statsPtr->currentByteCodeBytes),
08157             statsPtr->currentLitBytes / numCurrentByteCodes);
08158     fprintf(stdout, "Exception table   %12.6g   %8.1f%%   %8.1f\n",
08159             statsPtr->currentExceptBytes,
08160             Percent(statsPtr->currentExceptBytes,statsPtr->currentByteCodeBytes),
08161             statsPtr->currentExceptBytes / numCurrentByteCodes);
08162     fprintf(stdout, "Auxiliary data    %12.6g   %8.1f%%   %8.1f\n",
08163             statsPtr->currentAuxBytes,
08164             Percent(statsPtr->currentAuxBytes,statsPtr->currentByteCodeBytes),
08165             statsPtr->currentAuxBytes / numCurrentByteCodes);
08166     fprintf(stdout, "Command map       %12.6g   %8.1f%%   %8.1f\n",
08167             statsPtr->currentCmdMapBytes,
08168             Percent(statsPtr->currentCmdMapBytes,statsPtr->currentByteCodeBytes),
08169             statsPtr->currentCmdMapBytes / numCurrentByteCodes);
08170 
08171     /*
08172      * Detailed literal statistics.
08173      */
08174 
08175     fprintf(stdout, "\nLiteral string sizes:\n");
08176     fprintf(stdout, "    Up to length           Percentage\n");
08177     maxSizeDecade = 0;
08178     for (i = 31;  i >= 0;  i--) {
08179         if (statsPtr->literalCount[i] > 0) {
08180             maxSizeDecade = i;
08181             break;
08182         }
08183     }
08184     sum = 0;
08185     for (i = 0;  i <= maxSizeDecade;  i++) {
08186         decadeHigh = (1 << (i+1)) - 1;
08187         sum += statsPtr->literalCount[i];
08188         fprintf(stdout, "       %10d            %8.0f%%\n",
08189                 decadeHigh, Percent(sum, statsPtr->numLiteralsCreated));
08190     }
08191 
08192     litTableStats = TclLiteralStats(globalTablePtr);
08193     fprintf(stdout, "\nCurrent literal table statistics:\n%s\n",
08194             litTableStats);
08195     ckfree((char *) litTableStats);
08196 
08197     /*
08198      * Source and ByteCode size distributions.
08199      */
08200 
08201     fprintf(stdout, "\nSource sizes:\n");
08202     fprintf(stdout, "    Up to size             Percentage\n");
08203     minSizeDecade = maxSizeDecade = 0;
08204     for (i = 0;  i < 31;  i++) {
08205         if (statsPtr->srcCount[i] > 0) {
08206             minSizeDecade = i;
08207             break;
08208         }
08209     }
08210     for (i = 31;  i >= 0;  i--) {
08211         if (statsPtr->srcCount[i] > 0) {
08212             maxSizeDecade = i;
08213             break;
08214         }
08215     }
08216     sum = 0;
08217     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
08218         decadeHigh = (1 << (i+1)) - 1;
08219         sum += statsPtr->srcCount[i];
08220         fprintf(stdout, "       %10d            %8.0f%%\n",
08221                 decadeHigh, Percent(sum, statsPtr->numCompilations));
08222     }
08223 
08224     fprintf(stdout, "\nByteCode sizes:\n");
08225     fprintf(stdout, "    Up to size             Percentage\n");
08226     minSizeDecade = maxSizeDecade = 0;
08227     for (i = 0;  i < 31;  i++) {
08228         if (statsPtr->byteCodeCount[i] > 0) {
08229             minSizeDecade = i;
08230             break;
08231         }
08232     }
08233     for (i = 31;  i >= 0;  i--) {
08234         if (statsPtr->byteCodeCount[i] > 0) {
08235             maxSizeDecade = i;
08236             break;
08237         }
08238     }
08239     sum = 0;
08240     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
08241         decadeHigh = (1 << (i+1)) - 1;
08242         sum += statsPtr->byteCodeCount[i];
08243         fprintf(stdout, "       %10d            %8.0f%%\n",
08244                 decadeHigh, Percent(sum, statsPtr->numCompilations));
08245     }
08246 
08247     fprintf(stdout, "\nByteCode longevity (excludes Current ByteCodes):\n");
08248     fprintf(stdout, "          Up to ms         Percentage\n");
08249     minSizeDecade = maxSizeDecade = 0;
08250     for (i = 0;  i < 31;  i++) {
08251         if (statsPtr->lifetimeCount[i] > 0) {
08252             minSizeDecade = i;
08253             break;
08254         }
08255     }
08256     for (i = 31;  i >= 0;  i--) {
08257         if (statsPtr->lifetimeCount[i] > 0) {
08258             maxSizeDecade = i;
08259             break;
08260         }
08261     }
08262     sum = 0;
08263     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
08264         decadeHigh = (1 << (i+1)) - 1;
08265         sum += statsPtr->lifetimeCount[i];
08266         fprintf(stdout, "       %12.3f          %8.0f%%\n",
08267                 decadeHigh/1000.0, Percent(sum, statsPtr->numByteCodesFreed));
08268     }
08269 
08270     /*
08271      * Instruction counts.
08272      */
08273 
08274     fprintf(stdout, "\nInstruction counts:\n");
08275     for (i = 0;  i <= LAST_INST_OPCODE;  i++) {
08276         if (statsPtr->instructionCount[i] == 0) {
08277             fprintf(stdout, "%20s %8ld %6.1f%%\n",
08278                     tclInstructionTable[i].name,
08279                     statsPtr->instructionCount[i],
08280                     Percent(statsPtr->instructionCount[i], numInstructions));
08281         }
08282     }
08283 
08284     fprintf(stdout, "\nInstructions NEVER executed:\n");
08285     for (i = 0;  i <= LAST_INST_OPCODE;  i++) {
08286         if (statsPtr->instructionCount[i] == 0) {
08287             fprintf(stdout, "%20s\n", tclInstructionTable[i].name);
08288         }
08289     }
08290 
08291 #ifdef TCL_MEM_DEBUG
08292     fprintf(stdout, "\nHeap Statistics:\n");
08293     TclDumpMemoryInfo(stdout);
08294 #endif
08295     fprintf(stdout, "\n----------------------------------------------------------------\n");
08296     return TCL_OK;
08297 }
08298 #endif /* TCL_COMPILE_STATS */
08299 
08300 #ifdef TCL_COMPILE_DEBUG
08301 /*
08302  *----------------------------------------------------------------------
08303  *
08304  * StringForResultCode --
08305  *
08306  *      Procedure that returns a human-readable string representing a Tcl
08307  *      result code such as TCL_ERROR.
08308  *
08309  * Results:
08310  *      If the result code is one of the standard Tcl return codes, the result
08311  *      is a string representing that code such as "TCL_ERROR". Otherwise, the
08312  *      result string is that code formatted as a sequence of decimal digit
08313  *      characters. Note that the resulting string must not be modified by the
08314  *      caller.
08315  *
08316  * Side effects:
08317  *      None.
08318  *
08319  *----------------------------------------------------------------------
08320  */
08321 
08322 static const char *
08323 StringForResultCode(
08324     int result)                 /* The Tcl result code for which to generate a
08325                                  * string. */
08326 {
08327     static char buf[TCL_INTEGER_SPACE];
08328 
08329     if ((result >= TCL_OK) && (result <= TCL_CONTINUE)) {
08330         return resultStrings[result];
08331     }
08332     TclFormatInt(buf, result);
08333     return buf;
08334 }
08335 #endif /* TCL_COMPILE_DEBUG */
08336 
08337 /*
08338  * Local Variables:
08339  * mode: c
08340  * c-basic-offset: 4
08341  * fill-column: 78
08342  * End:
08343  */



Generated on Wed Mar 12 12:18:16 2008 by  doxygen 1.5.1