os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclExecute.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /* 
     2  * tclExecute.c --
     3  *
     4  *	This file contains procedures that execute byte-compiled Tcl
     5  *	commands.
     6  *
     7  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
     8  * Copyright (c) 1998-2000 by Scriptics Corporation.
     9  * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
    10  * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved.  
    11  *
    12  * See the file "license.terms" for information on usage and redistribution
    13  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    14  *
    15  * RCS: @(#) $Id: tclExecute.c,v 1.94.2.21 2007/03/13 16:26:32 dgp Exp $
    16  */
    17 
    18 #include "tclInt.h"
    19 #include "tclCompile.h"
    20 #include "tclMath.h"
    21 
    22 /*
    23  * The stuff below is a bit of a hack so that this file can be used
    24  * in environments that include no UNIX, i.e. no errno.  Just define
    25  * errno here.
    26  */
    27 
    28 #ifndef TCL_GENERIC_ONLY
    29 #   include "tclPort.h"
    30 #else /* TCL_GENERIC_ONLY */
    31 #   ifndef NO_FLOAT_H
    32 #	include <float.h>
    33 #   else /* NO_FLOAT_H */
    34 #	ifndef NO_VALUES_H
    35 #	    include <values.h>
    36 #	endif /* !NO_VALUES_H */
    37 #   endif /* !NO_FLOAT_H */
    38 #   define NO_ERRNO_H
    39 #endif /* !TCL_GENERIC_ONLY */
    40 
    41 #ifdef NO_ERRNO_H
    42 int errno;
    43 #   define EDOM   33
    44 #   define ERANGE 34
    45 #endif
    46 
    47 /*
    48  * Need DBL_MAX for IS_INF() macro...
    49  */
    50 #ifndef DBL_MAX
    51 #   ifdef MAXDOUBLE
    52 #	define DBL_MAX MAXDOUBLE
    53 #   else /* !MAXDOUBLE */
    54 /*
    55  * This value is from the Solaris headers, but doubles seem to be the
    56  * same size everywhere.  Long doubles aren't, but we don't use those.
    57  */
    58 #	define DBL_MAX 1.79769313486231570e+308
    59 #   endif /* MAXDOUBLE */
    60 #endif /* !DBL_MAX */
    61 
    62 /*
    63  * Boolean flag indicating whether the Tcl bytecode interpreter has been
    64  * initialized.
    65  */
    66 
    67 static int execInitialized = 0;
    68 TCL_DECLARE_MUTEX(execMutex)
    69 
    70 #ifdef TCL_COMPILE_DEBUG
    71 /*
    72  * Variable that controls whether execution tracing is enabled and, if so,
    73  * what level of tracing is desired:
    74  *    0: no execution tracing
    75  *    1: trace invocations of Tcl procs only
    76  *    2: trace invocations of all (not compiled away) commands
    77  *    3: display each instruction executed
    78  * This variable is linked to the Tcl variable "tcl_traceExec".
    79  */
    80 
    81 int tclTraceExec = 0;
    82 #endif
    83 
    84 /*
    85  * Mapping from expression instruction opcodes to strings; used for error
    86  * messages. Note that these entries must match the order and number of the
    87  * expression opcodes (e.g., INST_LOR) in tclCompile.h.
    88  */
    89 
    90 static char *operatorStrings[] = {
    91     "||", "&&", "|", "^", "&", "==", "!=", "<", ">", "<=", ">=", "<<", ">>",
    92     "+", "-", "*", "/", "%", "+", "-", "~", "!",
    93     "BUILTIN FUNCTION", "FUNCTION",
    94     "", "", "", "", "", "", "", "", "eq", "ne",
    95 };
    96 
    97 /*
    98  * Mapping from Tcl result codes to strings; used for error and debugging
    99  * messages. 
   100  */
   101 
   102 #ifdef TCL_COMPILE_DEBUG
   103 static char *resultStrings[] = {
   104     "TCL_OK", "TCL_ERROR", "TCL_RETURN", "TCL_BREAK", "TCL_CONTINUE"
   105 };
   106 #endif
   107 
   108 /*
   109  * These are used by evalstats to monitor object usage in Tcl.
   110  */
   111 
   112 #ifdef TCL_COMPILE_STATS
   113 long		tclObjsAlloced = 0;
   114 long		tclObjsFreed   = 0;
   115 #define TCL_MAX_SHARED_OBJ_STATS 5
   116 long		tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 };
   117 #endif /* TCL_COMPILE_STATS */
   118 
   119 /*
   120  * Macros for testing floating-point values for certain special cases. Test
   121  * for not-a-number by comparing a value against itself; test for infinity
   122  * by comparing against the largest floating-point value.
   123  */
   124 
   125 #define IS_NAN(v) ((v) != (v))
   126 #define IS_INF(v) (((v) > DBL_MAX) || ((v) < -DBL_MAX))
   127 
   128 /*
   129  * The new macro for ending an instruction; note that a
   130  * reasonable C-optimiser will resolve all branches
   131  * at compile time. (result) is always a constant; the macro 
   132  * NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is
   133  * resolved at runtime for variable (nCleanup).
   134  *
   135  * ARGUMENTS:
   136  *    pcAdjustment: how much to increment pc
   137  *    nCleanup: how many objects to remove from the stack
   138  *    result: 0 indicates no object should be pushed on the
   139  *       stack; otherwise, push objResultPtr. If (result < 0),
   140  *       objResultPtr already has the correct reference count.
   141  */
   142 
   143 #define NEXT_INST_F(pcAdjustment, nCleanup, result) \
   144      if (nCleanup == 0) {\
   145 	 if (result != 0) {\
   146 	     if ((result) > 0) {\
   147 		 PUSH_OBJECT(objResultPtr);\
   148 	     } else {\
   149 		 stackPtr[++stackTop] = objResultPtr;\
   150 	     }\
   151 	 } \
   152 	 pc += (pcAdjustment);\
   153 	 goto cleanup0;\
   154      } else if (result != 0) {\
   155 	 if ((result) > 0) {\
   156 	     Tcl_IncrRefCount(objResultPtr);\
   157 	 }\
   158 	 pc += (pcAdjustment);\
   159 	 switch (nCleanup) {\
   160 	     case 1: goto cleanup1_pushObjResultPtr;\
   161 	     case 2: goto cleanup2_pushObjResultPtr;\
   162 	     default: panic("ERROR: bad usage of macro NEXT_INST_F");\
   163 	 }\
   164      } else {\
   165 	 pc += (pcAdjustment);\
   166 	 switch (nCleanup) {\
   167 	     case 1: goto cleanup1;\
   168 	     case 2: goto cleanup2;\
   169 	     default: panic("ERROR: bad usage of macro NEXT_INST_F");\
   170 	 }\
   171      }
   172 
   173 #define NEXT_INST_V(pcAdjustment, nCleanup, result) \
   174     pc += (pcAdjustment);\
   175     cleanup = (nCleanup);\
   176     if (result) {\
   177 	if ((result) > 0) {\
   178 	    Tcl_IncrRefCount(objResultPtr);\
   179 	}\
   180 	goto cleanupV_pushObjResultPtr;\
   181     } else {\
   182 	goto cleanupV;\
   183     }
   184 
   185 
   186 /*
   187  * Macros used to cache often-referenced Tcl evaluation stack information
   188  * in local variables. Note that a DECACHE_STACK_INFO()-CACHE_STACK_INFO()
   189  * pair must surround any call inside TclExecuteByteCode (and a few other
   190  * procedures that use this scheme) that could result in a recursive call
   191  * to TclExecuteByteCode.
   192  */
   193 
   194 #define CACHE_STACK_INFO() \
   195     stackPtr = eePtr->stackPtr; \
   196     stackTop = eePtr->stackTop
   197 
   198 #define DECACHE_STACK_INFO() \
   199     eePtr->stackTop = stackTop
   200 
   201 
   202 /*
   203  * Macros used to access items on the Tcl evaluation stack. PUSH_OBJECT
   204  * increments the object's ref count since it makes the stack have another
   205  * reference pointing to the object. However, POP_OBJECT does not decrement
   206  * the ref count. This is because the stack may hold the only reference to
   207  * the object, so the object would be destroyed if its ref count were
   208  * decremented before the caller had a chance to, e.g., store it in a
   209  * variable. It is the caller's responsibility to decrement the ref count
   210  * when it is finished with an object.
   211  *
   212  * WARNING! It is essential that objPtr only appear once in the PUSH_OBJECT
   213  * macro. The actual parameter might be an expression with side effects,
   214  * and this ensures that it will be executed only once. 
   215  */
   216     
   217 #define PUSH_OBJECT(objPtr) \
   218     Tcl_IncrRefCount(stackPtr[++stackTop] = (objPtr))
   219     
   220 #define POP_OBJECT() \
   221     (stackPtr[stackTop--])
   222 
   223 /*
   224  * Macros used to trace instruction execution. The macros TRACE,
   225  * TRACE_WITH_OBJ, and O2S are only used inside TclExecuteByteCode.
   226  * O2S is only used in TRACE* calls to get a string from an object.
   227  */
   228 
   229 #ifdef TCL_COMPILE_DEBUG
   230 #   define TRACE(a) \
   231     if (traceInstructions) { \
   232         fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, stackTop, \
   233 	       (unsigned int)(pc - codePtr->codeStart), \
   234 	       GetOpcodeName(pc)); \
   235 	printf a; \
   236     }
   237 #   define TRACE_APPEND(a) \
   238     if (traceInstructions) { \
   239 	printf a; \
   240     }
   241 #   define TRACE_WITH_OBJ(a, objPtr) \
   242     if (traceInstructions) { \
   243         fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, stackTop, \
   244 	       (unsigned int)(pc - codePtr->codeStart), \
   245 	       GetOpcodeName(pc)); \
   246 	printf a; \
   247         TclPrintObject(stdout, objPtr, 30); \
   248         fprintf(stdout, "\n"); \
   249     }
   250 #   define O2S(objPtr) \
   251     (objPtr ? TclGetString(objPtr) : "")
   252 #else /* !TCL_COMPILE_DEBUG */
   253 #   define TRACE(a)
   254 #   define TRACE_APPEND(a) 
   255 #   define TRACE_WITH_OBJ(a, objPtr)
   256 #   define O2S(objPtr)
   257 #endif /* TCL_COMPILE_DEBUG */
   258 
   259 /*
   260  * Macro to read a string containing either a wide or an int and
   261  * decide which it is while decoding it at the same time.  This
   262  * enforces the policy that integer constants between LONG_MIN and
   263  * LONG_MAX (inclusive) are represented by normal longs, and integer
   264  * constants outside that range are represented by wide ints.
   265  *
   266  * GET_WIDE_OR_INT is the same as REQUIRE_WIDE_OR_INT except it never
   267  * generates an error message.
   268  */
   269 #define REQUIRE_WIDE_OR_INT(resultVar, objPtr, longVar, wideVar)	\
   270     (resultVar) = Tcl_GetWideIntFromObj(interp, (objPtr), &(wideVar));	\
   271     if ((resultVar) == TCL_OK && (wideVar) >= Tcl_LongAsWide(LONG_MIN)	\
   272 	    && (wideVar) <= Tcl_LongAsWide(LONG_MAX)) {			\
   273 	(objPtr)->typePtr = &tclIntType;				\
   274 	(objPtr)->internalRep.longValue = (longVar)			\
   275 		= Tcl_WideAsLong(wideVar);				\
   276     }
   277 #define GET_WIDE_OR_INT(resultVar, objPtr, longVar, wideVar)		\
   278     (resultVar) = Tcl_GetWideIntFromObj((Tcl_Interp *) NULL, (objPtr),	\
   279 	    &(wideVar));						\
   280     if ((resultVar) == TCL_OK && (wideVar) >= Tcl_LongAsWide(LONG_MIN)	\
   281 	    && (wideVar) <= Tcl_LongAsWide(LONG_MAX)) {			\
   282 	(objPtr)->typePtr = &tclIntType;				\
   283 	(objPtr)->internalRep.longValue = (longVar)			\
   284 		= Tcl_WideAsLong(wideVar);				\
   285     }
   286 /*
   287  * Combined with REQUIRE_WIDE_OR_INT, this gets a long value from
   288  * an obj.
   289  */
   290 #define FORCE_LONG(objPtr, longVar, wideVar)				\
   291     if ((objPtr)->typePtr == &tclWideIntType) {				\
   292 	(longVar) = Tcl_WideAsLong(wideVar);				\
   293     }
   294 #define IS_INTEGER_TYPE(typePtr)					\
   295 	((typePtr) == &tclIntType || (typePtr) == &tclWideIntType)
   296 #define IS_NUMERIC_TYPE(typePtr)					\
   297 	(IS_INTEGER_TYPE(typePtr) || (typePtr) == &tclDoubleType)
   298 
   299 #define W0	Tcl_LongAsWide(0)
   300 /*
   301  * For tracing that uses wide values.
   302  */
   303 #define LLD				"%" TCL_LL_MODIFIER "d"
   304 
   305 #ifndef TCL_WIDE_INT_IS_LONG
   306 /*
   307  * Extract a double value from a general numeric object.
   308  */
   309 #define GET_DOUBLE_VALUE(doubleVar, objPtr, typePtr)			\
   310     if ((typePtr) == &tclIntType) {					\
   311 	(doubleVar) = (double) (objPtr)->internalRep.longValue;		\
   312     } else if ((typePtr) == &tclWideIntType) {				\
   313 	(doubleVar) = Tcl_WideAsDouble((objPtr)->internalRep.wideValue);\
   314     } else {								\
   315 	(doubleVar) = (objPtr)->internalRep.doubleValue;		\
   316     }
   317 #else /* TCL_WIDE_INT_IS_LONG */
   318 #define GET_DOUBLE_VALUE(doubleVar, objPtr, typePtr)			\
   319     if (((typePtr) == &tclIntType) || ((typePtr) == &tclWideIntType)) { \
   320 	(doubleVar) = (double) (objPtr)->internalRep.longValue;		\
   321     } else {								\
   322 	(doubleVar) = (objPtr)->internalRep.doubleValue;		\
   323     }
   324 #endif /* TCL_WIDE_INT_IS_LONG */
   325 
   326 /*
   327  * Declarations for local procedures to this file:
   328  */
   329 
   330 static int		TclExecuteByteCode _ANSI_ARGS_((Tcl_Interp *interp,
   331 			    ByteCode *codePtr));
   332 static int		ExprAbsFunc _ANSI_ARGS_((Tcl_Interp *interp,
   333 			    ExecEnv *eePtr, ClientData clientData));
   334 static int		ExprBinaryFunc _ANSI_ARGS_((Tcl_Interp *interp,
   335 			    ExecEnv *eePtr, ClientData clientData));
   336 static int		ExprCallMathFunc _ANSI_ARGS_((Tcl_Interp *interp,
   337 			    ExecEnv *eePtr, int objc, Tcl_Obj **objv));
   338 static int		ExprDoubleFunc _ANSI_ARGS_((Tcl_Interp *interp,
   339 			    ExecEnv *eePtr, ClientData clientData));
   340 static int		ExprIntFunc _ANSI_ARGS_((Tcl_Interp *interp,
   341 			    ExecEnv *eePtr, ClientData clientData));
   342 static int		ExprRandFunc _ANSI_ARGS_((Tcl_Interp *interp,
   343 			    ExecEnv *eePtr, ClientData clientData));
   344 static int		ExprRoundFunc _ANSI_ARGS_((Tcl_Interp *interp,
   345 			    ExecEnv *eePtr, ClientData clientData));
   346 static int		ExprSrandFunc _ANSI_ARGS_((Tcl_Interp *interp,
   347 			    ExecEnv *eePtr, ClientData clientData));
   348 static int		ExprUnaryFunc _ANSI_ARGS_((Tcl_Interp *interp,
   349 			    ExecEnv *eePtr, ClientData clientData));
   350 static int		ExprWideFunc _ANSI_ARGS_((Tcl_Interp *interp,
   351 			    ExecEnv *eePtr, ClientData clientData));
   352 #ifdef TCL_COMPILE_STATS
   353 static int              EvalStatsCmd _ANSI_ARGS_((ClientData clientData,
   354                             Tcl_Interp *interp, int objc,
   355 			    Tcl_Obj *CONST objv[]));
   356 #endif /* TCL_COMPILE_STATS */
   357 #ifdef TCL_COMPILE_DEBUG
   358 static char *		GetOpcodeName _ANSI_ARGS_((unsigned char *pc));
   359 #endif /* TCL_COMPILE_DEBUG */
   360 static ExceptionRange *	GetExceptRangeForPc _ANSI_ARGS_((unsigned char *pc,
   361 			    int catchOnly, ByteCode* codePtr));
   362 static char *		GetSrcInfoForPc _ANSI_ARGS_((unsigned char *pc,
   363         		    ByteCode* codePtr, int *lengthPtr));
   364 static void		GrowEvaluationStack _ANSI_ARGS_((ExecEnv *eePtr));
   365 static void		IllegalExprOperandType _ANSI_ARGS_((
   366 			    Tcl_Interp *interp, unsigned char *pc,
   367 			    Tcl_Obj *opndPtr));
   368 static void		InitByteCodeExecution _ANSI_ARGS_((
   369 			    Tcl_Interp *interp));
   370 #ifdef TCL_COMPILE_DEBUG
   371 static void		PrintByteCodeInfo _ANSI_ARGS_((ByteCode *codePtr));
   372 static char *		StringForResultCode _ANSI_ARGS_((int result));
   373 static void		ValidatePcAndStackTop _ANSI_ARGS_((
   374 			    ByteCode *codePtr, unsigned char *pc,
   375 			    int stackTop, int stackLowerBound));
   376 #endif /* TCL_COMPILE_DEBUG */
   377 static int		VerifyExprObjType _ANSI_ARGS_((Tcl_Interp *interp,
   378 			    Tcl_Obj *objPtr));
   379 			    
   380 /*
   381 ========== Begin of math function wrappers =============
   382 The math function wrappers bellow are need to avoid the "Import relocation does not refer to code segment" error
   383 message reported from ELF2E32 tool.
   384 */
   385 
   386 static double Tcl_acos(double x)
   387 	{
   388 	return acos(x);
   389 	}
   390 	
   391 static double Tcl_asin(double x)
   392 	{
   393 	return asin(x);
   394 	}
   395 	
   396 static double Tcl_atan(double x)
   397 	{
   398 	return atan(x);
   399 	}
   400 	
   401 static double Tcl_atan2(double x, double y)
   402 	{
   403 	return atan2(x, y);
   404 	}
   405 
   406 static double Tcl_ceil(double num)
   407 	{
   408 	return ceil(num);
   409 	}
   410 	
   411 static double Tcl_cos(double x)
   412 	{
   413 	return cos(x);
   414 	}
   415 	
   416 static double Tcl_cosh(double x)
   417 	{
   418 	return cosh(x);
   419 	}
   420 	
   421 static double Tcl_exp(double x)
   422 	{
   423 	return exp(x);
   424 	}
   425 	
   426 static double Tcl_floor(double x)
   427 	{
   428 	return floor(x);
   429 	}
   430 
   431 static double Tcl_fmod(double numerator, double denominator)
   432 	{
   433 	return fmod(numerator, denominator);	
   434 	}
   435 	
   436 static double Tcl_hypot(double x, double y)
   437 	{
   438 	return hypot(x, y);	
   439 	}
   440 
   441 static double Tcl_log(double x)
   442 	{
   443 	return log(x);
   444 	}
   445 
   446 static double Tcl_log10(double x)
   447 	{
   448 	return log10(x);
   449 	}
   450 
   451 static double Tcl_pow(double base, double exponent)
   452 	{
   453 	return pow(base, exponent);
   454 	}
   455 
   456 static double Tcl_sin(double x)
   457 	{
   458 	return sin(x);
   459 	}
   460 	
   461 static double Tcl_sinh(double x)
   462 	{
   463 	return sinh(x);
   464 	}
   465 	
   466 static double Tcl_sqrt(double x)
   467 	{
   468 	return sqrt(x);
   469 	}
   470 	
   471 static double Tcl_tan(double x)
   472 	{
   473 	return tan(x);
   474 	}
   475 	
   476 static double Tcl_tanh(double x)
   477 	{
   478 	return tanh(x);
   479 	}
   480 	
   481 /*   
   482 ========== End of math function wrappers ===============
   483 */
   484 
   485 /*
   486  * Table describing the built-in math functions. Entries in this table are
   487  * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's
   488  * operand byte.
   489  */
   490 
   491 BuiltinFunc tclBuiltinFuncTable[] = {
   492 #ifndef TCL_NO_MATH
   493     {"acos", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_acos},
   494     {"asin", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_asin},
   495     {"atan", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_atan},
   496     {"atan2", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) Tcl_atan2},
   497     {"ceil", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_ceil},
   498     {"cos", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_cos},
   499     {"cosh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_cosh},
   500     {"exp", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_exp},
   501     {"floor", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_floor},
   502     {"fmod", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) Tcl_fmod},
   503     {"hypot", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) Tcl_hypot},
   504     {"log", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_log},
   505     {"log10", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_log10},
   506     {"pow", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) Tcl_pow},
   507     {"sin", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_sin},
   508     {"sinh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_sinh},
   509     {"sqrt", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_sqrt},
   510     {"tan", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_tan},
   511     {"tanh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) Tcl_tanh},
   512 #endif
   513     {"abs", 1, {TCL_EITHER}, ExprAbsFunc, 0},
   514     {"double", 1, {TCL_EITHER}, ExprDoubleFunc, 0},
   515     {"int", 1, {TCL_EITHER}, ExprIntFunc, 0},
   516     {"rand", 0, {TCL_EITHER}, ExprRandFunc, 0},	/* NOTE: rand takes no args. */
   517     {"round", 1, {TCL_EITHER}, ExprRoundFunc, 0},
   518     {"srand", 1, {TCL_INT}, ExprSrandFunc, 0},
   519     {"wide", 1, {TCL_EITHER}, ExprWideFunc, 0},
   520     {0},
   521 };
   522 
   523 /*
   524  *----------------------------------------------------------------------
   525  *
   526  * InitByteCodeExecution --
   527  *
   528  *	This procedure is called once to initialize the Tcl bytecode
   529  *	interpreter.
   530  *
   531  * Results:
   532  *	None.
   533  *
   534  * Side effects:
   535  *	This procedure initializes the array of instruction names. If
   536  *	compiling with the TCL_COMPILE_STATS flag, it initializes the
   537  *	array that counts the executions of each instruction and it
   538  *	creates the "evalstats" command. It also establishes the link 
   539  *      between the Tcl "tcl_traceExec" and C "tclTraceExec" variables.
   540  *
   541  *----------------------------------------------------------------------
   542  */
   543 
   544 static void
   545 InitByteCodeExecution(interp)
   546     Tcl_Interp *interp;		/* Interpreter for which the Tcl variable
   547 				 * "tcl_traceExec" is linked to control
   548 				 * instruction tracing. */
   549 {
   550 #ifdef TCL_COMPILE_DEBUG
   551     if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec,
   552 		    TCL_LINK_INT) != TCL_OK) {
   553 	panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
   554     }
   555 #endif
   556 #ifdef TCL_COMPILE_STATS    
   557     Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd,
   558 	    (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
   559 #endif /* TCL_COMPILE_STATS */
   560 }
   561 
   562 /*
   563  *----------------------------------------------------------------------
   564  *
   565  * TclCreateExecEnv --
   566  *
   567  *	This procedure creates a new execution environment for Tcl bytecode
   568  *	execution. An ExecEnv points to a Tcl evaluation stack. An ExecEnv
   569  *	is typically created once for each Tcl interpreter (Interp
   570  *	structure) and recursively passed to TclExecuteByteCode to execute
   571  *	ByteCode sequences for nested commands.
   572  *
   573  * Results:
   574  *	A newly allocated ExecEnv is returned. This points to an empty
   575  *	evaluation stack of the standard initial size.
   576  *
   577  * Side effects:
   578  *	The bytecode interpreter is also initialized here, as this
   579  *	procedure will be called before any call to TclExecuteByteCode.
   580  *
   581  *----------------------------------------------------------------------
   582  */
   583 
   584 #define TCL_STACK_INITIAL_SIZE 2000
   585 
   586 ExecEnv *
   587 TclCreateExecEnv(interp)
   588     Tcl_Interp *interp;		/* Interpreter for which the execution
   589 				 * environment is being created. */
   590 {
   591     ExecEnv *eePtr = (ExecEnv *) ckalloc(sizeof(ExecEnv));
   592     Tcl_Obj **stackPtr;
   593 
   594     stackPtr = (Tcl_Obj **)
   595 	ckalloc((size_t) (TCL_STACK_INITIAL_SIZE * sizeof(Tcl_Obj *)));
   596 
   597     /*
   598      * Use the bottom pointer to keep a reference count; the 
   599      * execution environment holds a reference.
   600      */
   601 
   602     stackPtr++;
   603     eePtr->stackPtr = stackPtr;
   604     stackPtr[-1] = (Tcl_Obj *) ((char *) 1);
   605 
   606     eePtr->stackTop = -1;
   607     eePtr->stackEnd = (TCL_STACK_INITIAL_SIZE - 2);
   608 
   609     eePtr->errorInfo = Tcl_NewStringObj("::errorInfo", -1);
   610     Tcl_IncrRefCount(eePtr->errorInfo);
   611 
   612     eePtr->errorCode = Tcl_NewStringObj("::errorCode", -1);
   613     Tcl_IncrRefCount(eePtr->errorCode);
   614 
   615     Tcl_MutexLock(&execMutex);
   616     if (!execInitialized) {
   617 	TclInitAuxDataTypeTable();
   618 	InitByteCodeExecution(interp);
   619 	execInitialized = 1;
   620     }
   621     Tcl_MutexUnlock(&execMutex);
   622 
   623     return eePtr;
   624 }
   625 #undef TCL_STACK_INITIAL_SIZE
   626 
   627 /*
   628  *----------------------------------------------------------------------
   629  *
   630  * TclDeleteExecEnv --
   631  *
   632  *	Frees the storage for an ExecEnv.
   633  *
   634  * Results:
   635  *	None.
   636  *
   637  * Side effects:
   638  *	Storage for an ExecEnv and its contained storage (e.g. the
   639  *	evaluation stack) is freed.
   640  *
   641  *----------------------------------------------------------------------
   642  */
   643 
   644 void
   645 TclDeleteExecEnv(eePtr)
   646     ExecEnv *eePtr;		/* Execution environment to free. */
   647 {
   648     if (eePtr->stackPtr[-1] == (Tcl_Obj *) ((char *) 1)) {
   649 	ckfree((char *) (eePtr->stackPtr-1));
   650     } else {
   651 	panic("ERROR: freeing an execEnv whose stack is still in use.\n");
   652     }
   653     TclDecrRefCount(eePtr->errorInfo);
   654     TclDecrRefCount(eePtr->errorCode);
   655     ckfree((char *) eePtr);
   656 }
   657 
   658 /*
   659  *----------------------------------------------------------------------
   660  *
   661  * TclFinalizeExecution --
   662  *
   663  *	Finalizes the execution environment setup so that it can be
   664  *	later reinitialized.
   665  *
   666  * Results:
   667  *	None.
   668  *
   669  * Side effects:
   670  *	After this call, the next time TclCreateExecEnv will be called
   671  *	it will call InitByteCodeExecution.
   672  *
   673  *----------------------------------------------------------------------
   674  */
   675 
   676 void
   677 TclFinalizeExecution()
   678 {
   679     Tcl_MutexLock(&execMutex);
   680     execInitialized = 0;
   681     Tcl_MutexUnlock(&execMutex);
   682     TclFinalizeAuxDataTypeTable();
   683 }
   684 
   685 /*
   686  *----------------------------------------------------------------------
   687  *
   688  * GrowEvaluationStack --
   689  *
   690  *	This procedure grows a Tcl evaluation stack stored in an ExecEnv.
   691  *
   692  * Results:
   693  *	None.
   694  *
   695  * Side effects:
   696  *	The size of the evaluation stack is doubled.
   697  *
   698  *----------------------------------------------------------------------
   699  */
   700 
   701 static void
   702 GrowEvaluationStack(eePtr)
   703     register ExecEnv *eePtr; /* Points to the ExecEnv with an evaluation
   704 			      * stack to enlarge. */
   705 {
   706     /*
   707      * The current Tcl stack elements are stored from eePtr->stackPtr[0]
   708      * to eePtr->stackPtr[eePtr->stackEnd] (inclusive).
   709      */
   710 
   711     int currElems = (eePtr->stackEnd + 1);
   712     int newElems  = 2*currElems;
   713     int currBytes = currElems * sizeof(Tcl_Obj *);
   714     int newBytes  = 2*currBytes;
   715     Tcl_Obj **newStackPtr = (Tcl_Obj **) ckalloc((unsigned) newBytes);
   716     Tcl_Obj **oldStackPtr = eePtr->stackPtr;
   717 
   718     /*
   719      * We keep the stack reference count as a (char *), as that
   720      * works nicely as a portable pointer-sized counter.
   721      */
   722 
   723     char *refCount = (char *) oldStackPtr[-1];
   724 
   725     /*
   726      * Copy the existing stack items to the new stack space, free the old
   727      * storage if appropriate, and record the refCount of the new stack
   728      * held by the environment.
   729      */
   730  
   731     newStackPtr++;
   732     memcpy((VOID *) newStackPtr, (VOID *) oldStackPtr,
   733 	   (size_t) currBytes);
   734 
   735     if (refCount == (char *) 1) {
   736 	ckfree((VOID *) (oldStackPtr-1));
   737     } else {
   738 	/*
   739 	 * Remove the reference corresponding to the
   740 	 * environment pointer.
   741 	 */
   742 	
   743 	oldStackPtr[-1] = (Tcl_Obj *) (refCount-1);
   744     }
   745 
   746     eePtr->stackPtr = newStackPtr;
   747     eePtr->stackEnd = (newElems - 2); /* index of last usable item */
   748     newStackPtr[-1] = (Tcl_Obj *) ((char *) 1);	
   749 }
   750 
   751 /*
   752  *--------------------------------------------------------------
   753  *
   754  * Tcl_ExprObj --
   755  *
   756  *	Evaluate an expression in a Tcl_Obj.
   757  *
   758  * Results:
   759  *	A standard Tcl object result. If the result is other than TCL_OK,
   760  *	then the interpreter's result contains an error message. If the
   761  *	result is TCL_OK, then a pointer to the expression's result value
   762  *	object is stored in resultPtrPtr. In that case, the object's ref
   763  *	count is incremented to reflect the reference returned to the
   764  *	caller; the caller is then responsible for the resulting object
   765  *	and must, for example, decrement the ref count when it is finished
   766  *	with the object.
   767  *
   768  * Side effects:
   769  *	Any side effects caused by subcommands in the expression, if any.
   770  *	The interpreter result is not modified unless there is an error.
   771  *
   772  *--------------------------------------------------------------
   773  */
   774 
   775 EXPORT_C int
   776 Tcl_ExprObj(interp, objPtr, resultPtrPtr)
   777     Tcl_Interp *interp;		/* Context in which to evaluate the
   778 				 * expression. */
   779     register Tcl_Obj *objPtr;	/* Points to Tcl object containing
   780 				 * expression to evaluate. */
   781     Tcl_Obj **resultPtrPtr;	/* Where the Tcl_Obj* that is the expression
   782 				 * result is stored if no errors occur. */
   783 {
   784     Interp *iPtr = (Interp *) interp;
   785     CompileEnv compEnv;		/* Compilation environment structure
   786 				 * allocated in frame. */
   787     LiteralTable *localTablePtr = &(compEnv.localLitTable);
   788     register ByteCode *codePtr = NULL;
   789     				/* Tcl Internal type of bytecode.
   790 				 * Initialized to avoid compiler warning. */
   791     AuxData *auxDataPtr;
   792     LiteralEntry *entryPtr;
   793     Tcl_Obj *saveObjPtr;
   794     char *string;
   795     int length, i, result;
   796 
   797     /*
   798      * First handle some common expressions specially.
   799      */
   800 
   801     string = Tcl_GetStringFromObj(objPtr, &length);
   802     if (length == 1) {
   803 	if (*string == '0') {
   804 	    *resultPtrPtr = Tcl_NewLongObj(0);
   805 	    Tcl_IncrRefCount(*resultPtrPtr);
   806 	    return TCL_OK;
   807 	} else if (*string == '1') {
   808 	    *resultPtrPtr = Tcl_NewLongObj(1);
   809 	    Tcl_IncrRefCount(*resultPtrPtr);
   810 	    return TCL_OK;
   811 	}
   812     } else if ((length == 2) && (*string == '!')) {
   813 	if (*(string+1) == '0') {
   814 	    *resultPtrPtr = Tcl_NewLongObj(1);
   815 	    Tcl_IncrRefCount(*resultPtrPtr);
   816 	    return TCL_OK;
   817 	} else if (*(string+1) == '1') {
   818 	    *resultPtrPtr = Tcl_NewLongObj(0);
   819 	    Tcl_IncrRefCount(*resultPtrPtr);
   820 	    return TCL_OK;
   821 	}
   822     }
   823 
   824     /*
   825      * Get the ByteCode from the object. If it exists, make sure it hasn't
   826      * been invalidated by, e.g., someone redefining a command with a
   827      * compile procedure (this might make the compiled code wrong). If
   828      * necessary, convert the object to be a ByteCode object and compile it.
   829      * Also, if the code was compiled in/for a different interpreter, we
   830      * recompile it.
   831      *
   832      * Precompiled expressions, however, are immutable and therefore
   833      * they are not recompiled, even if the epoch has changed.
   834      *
   835      */
   836 
   837     if (objPtr->typePtr == &tclByteCodeType) {
   838 	codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
   839 	if (((Interp *) *codePtr->interpHandle != iPtr)
   840 	        || (codePtr->compileEpoch != iPtr->compileEpoch)) {
   841             if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
   842                 if ((Interp *) *codePtr->interpHandle != iPtr) {
   843                     panic("Tcl_ExprObj: compiled expression jumped interps");
   844                 }
   845 	        codePtr->compileEpoch = iPtr->compileEpoch;
   846             } else {
   847                 (*tclByteCodeType.freeIntRepProc)(objPtr);
   848                 objPtr->typePtr = (Tcl_ObjType *) NULL;
   849             }
   850 	}
   851     }
   852     if (objPtr->typePtr != &tclByteCodeType) {
   853 #ifndef TCL_TIP280
   854 	TclInitCompileEnv(interp, &compEnv, string, length);
   855 #else
   856 	/* TIP #280 : No invoker (yet) - Expression compilation */
   857 	TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0);
   858 #endif
   859 	result = TclCompileExpr(interp, string, length, &compEnv);
   860 
   861 	/*
   862 	 * Free the compilation environment's literal table bucket array if
   863 	 * it was dynamically allocated. 
   864 	 */
   865 
   866 	if (localTablePtr->buckets != localTablePtr->staticBuckets) {
   867 	    ckfree((char *) localTablePtr->buckets);
   868 	}
   869     
   870 	if (result != TCL_OK) {
   871 	    /*
   872 	     * Compilation errors. Free storage allocated for compilation.
   873 	     */
   874 
   875 #ifdef TCL_COMPILE_DEBUG
   876 	    TclVerifyLocalLiteralTable(&compEnv);
   877 #endif /*TCL_COMPILE_DEBUG*/
   878 	    entryPtr = compEnv.literalArrayPtr;
   879 	    for (i = 0;  i < compEnv.literalArrayNext;  i++) {
   880 		TclReleaseLiteral(interp, entryPtr->objPtr);
   881 		entryPtr++;
   882 	    }
   883 #ifdef TCL_COMPILE_DEBUG
   884 	    TclVerifyGlobalLiteralTable(iPtr);
   885 #endif /*TCL_COMPILE_DEBUG*/
   886     
   887 	    auxDataPtr = compEnv.auxDataArrayPtr;
   888 	    for (i = 0;  i < compEnv.auxDataArrayNext;  i++) {
   889 		if (auxDataPtr->type->freeProc != NULL) {
   890 		    auxDataPtr->type->freeProc(auxDataPtr->clientData);
   891 		}
   892 		auxDataPtr++;
   893 	    }
   894 	    TclFreeCompileEnv(&compEnv);
   895 	    return result;
   896 	}
   897 
   898 	/*
   899 	 * Successful compilation. If the expression yielded no
   900 	 * instructions, push an zero object as the expression's result.
   901 	 */
   902 	    
   903 	if (compEnv.codeNext == compEnv.codeStart) {
   904 	    TclEmitPush(TclRegisterLiteral(&compEnv, "0", 1, /*onHeap*/ 0),
   905 	            &compEnv);
   906 	}
   907 	    
   908 	/*
   909 	 * Add a "done" instruction as the last instruction and change the
   910 	 * object into a ByteCode object. Ownership of the literal objects
   911 	 * and aux data items is given to the ByteCode object.
   912 	 */
   913 
   914 	compEnv.numSrcBytes = iPtr->termOffset;
   915 	TclEmitOpcode(INST_DONE, &compEnv);
   916 	TclInitByteCodeObj(objPtr, &compEnv);
   917 	TclFreeCompileEnv(&compEnv);
   918 	codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
   919 #ifdef TCL_COMPILE_DEBUG
   920 	if (tclTraceCompile == 2) {
   921 	    TclPrintByteCodeObj(interp, objPtr);
   922 	}
   923 #endif /* TCL_COMPILE_DEBUG */
   924     }
   925 
   926     /*
   927      * Execute the expression after first saving the interpreter's result.
   928      */
   929     
   930     saveObjPtr = Tcl_GetObjResult(interp);
   931     Tcl_IncrRefCount(saveObjPtr);
   932     Tcl_ResetResult(interp);
   933 
   934     /*
   935      * Increment the code's ref count while it is being executed. If
   936      * afterwards no references to it remain, free the code.
   937      */
   938     
   939     codePtr->refCount++;
   940     result = TclExecuteByteCode(interp, codePtr);
   941     codePtr->refCount--;
   942     if (codePtr->refCount <= 0) {
   943 	TclCleanupByteCode(codePtr);
   944 	objPtr->typePtr = NULL;
   945 	objPtr->internalRep.otherValuePtr = NULL;
   946     }
   947     
   948     /*
   949      * If the expression evaluated successfully, store a pointer to its
   950      * value object in resultPtrPtr then restore the old interpreter result.
   951      * We increment the object's ref count to reflect the reference that we
   952      * are returning to the caller. We also decrement the ref count of the
   953      * interpreter's result object after calling Tcl_SetResult since we
   954      * next store into that field directly.
   955      */
   956     
   957     if (result == TCL_OK) {
   958 	*resultPtrPtr = iPtr->objResultPtr;
   959 	Tcl_IncrRefCount(iPtr->objResultPtr);
   960 	
   961 	Tcl_SetObjResult(interp, saveObjPtr);
   962     }
   963     TclDecrRefCount(saveObjPtr);
   964     return result;
   965 }
   966 
   967 /*
   968  *----------------------------------------------------------------------
   969  *
   970  * TclCompEvalObj --
   971  *
   972  *	This procedure evaluates the script contained in a Tcl_Obj by 
   973  *      first compiling it and then passing it to TclExecuteByteCode.
   974  *
   975  * Results:
   976  *	The return value is one of the return codes defined in tcl.h
   977  *	(such as TCL_OK), and interp->objResultPtr refers to a Tcl object
   978  *	that either contains the result of executing the code or an
   979  *	error message.
   980  *
   981  * Side effects:
   982  *	Almost certainly, depending on the ByteCode's instructions.
   983  *
   984  *----------------------------------------------------------------------
   985  */
   986 
   987 int
   988 #ifndef TCL_TIP280
   989 TclCompEvalObj(interp, objPtr)
   990 #else
   991 TclCompEvalObj(interp, objPtr, invoker, word)
   992 #endif
   993     Tcl_Interp *interp;
   994     Tcl_Obj *objPtr;
   995 #ifdef TCL_TIP280
   996     CONST CmdFrame* invoker; /* Frame of the command doing the eval  */
   997     int             word;    /* Index of the word which is in objPtr */
   998 #endif
   999 {
  1000     register Interp *iPtr = (Interp *) interp;
  1001     register ByteCode* codePtr;		/* Tcl Internal type of bytecode. */
  1002     int oldCount = iPtr->cmdCount;	/* Used to tell whether any commands
  1003 					 * at all were executed. */
  1004     char *script;
  1005     int numSrcBytes;
  1006     int result;
  1007     Namespace *namespacePtr;
  1008 
  1009 
  1010     /*
  1011      * Check that the interpreter is ready to execute scripts
  1012      */
  1013 
  1014     iPtr->numLevels++;
  1015     if (TclInterpReady(interp) == TCL_ERROR) {
  1016 	iPtr->numLevels--;
  1017 	return TCL_ERROR;
  1018     }
  1019 
  1020     if (iPtr->varFramePtr != NULL) {
  1021         namespacePtr = iPtr->varFramePtr->nsPtr;
  1022     } else {
  1023         namespacePtr = iPtr->globalNsPtr;
  1024     }
  1025 
  1026     /* 
  1027      * If the object is not already of tclByteCodeType, compile it (and
  1028      * reset the compilation flags in the interpreter; this should be 
  1029      * done after any compilation).
  1030      * Otherwise, check that it is "fresh" enough.
  1031      */
  1032 
  1033     if (objPtr->typePtr != &tclByteCodeType) {
  1034         recompileObj:
  1035 	iPtr->errorLine = 1; 
  1036 
  1037 #ifdef TCL_TIP280
  1038 	/* TIP #280. Remember the invoker for a moment in the interpreter
  1039 	 * structures so that the byte code compiler can pick it up when
  1040 	 * initializing the compilation environment, i.e. the extended
  1041 	 * location information.
  1042 	 */
  1043 
  1044 	iPtr->invokeCmdFramePtr = invoker;
  1045 	iPtr->invokeWord        = word;
  1046 #endif
  1047 	result = tclByteCodeType.setFromAnyProc(interp, objPtr);
  1048 #ifdef TCL_TIP280
  1049 	iPtr->invokeCmdFramePtr = NULL;
  1050 #endif
  1051 
  1052 	if (result != TCL_OK) {
  1053 	    iPtr->numLevels--;
  1054 	    return result;
  1055 	}
  1056 	codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
  1057     } else {
  1058 	/*
  1059 	 * Make sure the Bytecode hasn't been invalidated by, e.g., someone 
  1060 	 * redefining a command with a compile procedure (this might make the 
  1061 	 * compiled code wrong). 
  1062 	 * The object needs to be recompiled if it was compiled in/for a 
  1063 	 * different interpreter, or for a different namespace, or for the 
  1064 	 * same namespace but with different name resolution rules. 
  1065 	 * Precompiled objects, however, are immutable and therefore
  1066 	 * they are not recompiled, even if the epoch has changed.
  1067 	 *
  1068 	 * To be pedantically correct, we should also check that the
  1069 	 * originating procPtr is the same as the current context procPtr
  1070 	 * (assuming one exists at all - none for global level).  This
  1071 	 * code is #def'ed out because [info body] was changed to never
  1072 	 * return a bytecode type object, which should obviate us from
  1073 	 * the extra checks here.
  1074 	 */
  1075 	codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
  1076 	if (((Interp *) *codePtr->interpHandle != iPtr)
  1077 	        || (codePtr->compileEpoch != iPtr->compileEpoch)
  1078 #ifdef CHECK_PROC_ORIGINATION	/* [Bug: 3412 Pedantic] */
  1079 		|| (codePtr->procPtr != NULL && !(iPtr->varFramePtr &&
  1080 			iPtr->varFramePtr->procPtr == codePtr->procPtr))
  1081 #endif
  1082 	        || (codePtr->nsPtr != namespacePtr)
  1083 	        || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {
  1084             if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
  1085                 if ((Interp *) *codePtr->interpHandle != iPtr) {
  1086                     panic("Tcl_EvalObj: compiled script jumped interps");
  1087                 }
  1088 	        codePtr->compileEpoch = iPtr->compileEpoch;
  1089             } else {
  1090 		/*
  1091 		 * This byteCode is invalid: free it and recompile
  1092 		 */
  1093                 tclByteCodeType.freeIntRepProc(objPtr);
  1094 		goto recompileObj;
  1095 	    }
  1096 	}
  1097     }
  1098 
  1099     /*
  1100      * Execute the commands. If the code was compiled from an empty string,
  1101      * don't bother executing the code.
  1102      */
  1103 
  1104     numSrcBytes = codePtr->numSrcBytes;
  1105     if ((numSrcBytes > 0) || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {
  1106 	/*
  1107 	 * Increment the code's ref count while it is being executed. If
  1108 	 * afterwards no references to it remain, free the code.
  1109 	 */
  1110 	
  1111 	codePtr->refCount++;
  1112 	result = TclExecuteByteCode(interp, codePtr);
  1113 	codePtr->refCount--;
  1114 	if (codePtr->refCount <= 0) {
  1115 	    TclCleanupByteCode(codePtr);
  1116 	}
  1117     } else {
  1118 	result = TCL_OK;
  1119     }
  1120     iPtr->numLevels--;
  1121 
  1122 
  1123     /*
  1124      * If no commands at all were executed, check for asynchronous
  1125      * handlers so that they at least get one change to execute.
  1126      * This is needed to handle event loops written in Tcl with
  1127      * empty bodies.
  1128      */
  1129 
  1130     if ((oldCount == iPtr->cmdCount) && Tcl_AsyncReady()) {
  1131 	result = Tcl_AsyncInvoke(interp, result);
  1132     
  1133 
  1134 	/*
  1135 	 * If an error occurred, record information about what was being
  1136 	 * executed when the error occurred.
  1137 	 */
  1138 	
  1139 	if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
  1140 	    script = Tcl_GetStringFromObj(objPtr, &numSrcBytes);
  1141 	    Tcl_LogCommandInfo(interp, script, script, numSrcBytes);
  1142 	}
  1143     }
  1144 
  1145     /*
  1146      * Set the interpreter's termOffset member to the offset of the
  1147      * character just after the last one executed. We approximate the offset
  1148      * of the last character executed by using the number of characters
  1149      * compiled. 
  1150      */
  1151 
  1152     iPtr->termOffset = numSrcBytes;
  1153     iPtr->flags &= ~ERR_ALREADY_LOGGED;
  1154 
  1155     return result;
  1156 }
  1157 
  1158 /*
  1159  *----------------------------------------------------------------------
  1160  *
  1161  * TclExecuteByteCode --
  1162  *
  1163  *	This procedure executes the instructions of a ByteCode structure.
  1164  *	It returns when a "done" instruction is executed or an error occurs.
  1165  *
  1166  * Results:
  1167  *	The return value is one of the return codes defined in tcl.h
  1168  *	(such as TCL_OK), and interp->objResultPtr refers to a Tcl object
  1169  *	that either contains the result of executing the code or an
  1170  *	error message.
  1171  *
  1172  * Side effects:
  1173  *	Almost certainly, depending on the ByteCode's instructions.
  1174  *
  1175  *----------------------------------------------------------------------
  1176  */
  1177  
  1178 static int
  1179 TclExecuteByteCode(interp, codePtr)
  1180     Tcl_Interp *interp;		/* Token for command interpreter. */
  1181     ByteCode *codePtr;		/* The bytecode sequence to interpret. */
  1182 {
  1183     Interp *iPtr = (Interp *) interp;
  1184     ExecEnv *eePtr = iPtr->execEnvPtr;
  1185     				/* Points to the execution environment. */
  1186     register Tcl_Obj **stackPtr = eePtr->stackPtr;
  1187     				/* Cached evaluation stack base pointer. */
  1188     register int stackTop = eePtr->stackTop;
  1189     				/* Cached top index of evaluation stack. */
  1190     register unsigned char *pc = codePtr->codeStart;
  1191 				/* The current program counter. */
  1192     int opnd;			/* Current instruction's operand byte(s). */
  1193     int pcAdjustment;		/* Hold pc adjustment after instruction. */
  1194     int initStackTop = stackTop;/* Stack top at start of execution. */
  1195     ExceptionRange *rangePtr;	/* Points to closest loop or catch exception
  1196 				 * range enclosing the pc. Used by various
  1197 				 * instructions and processCatch to
  1198 				 * process break, continue, and errors. */
  1199     int result = TCL_OK;	/* Return code returned after execution. */
  1200     int storeFlags;
  1201     Tcl_Obj *valuePtr, *value2Ptr, *objPtr;
  1202     char *bytes;
  1203     int length;
  1204     long i = 0;			/* Init. avoids compiler warning. */
  1205     Tcl_WideInt w;
  1206     register int cleanup;
  1207     Tcl_Obj *objResultPtr;
  1208     char *part1, *part2;
  1209     Var *varPtr, *arrayPtr;
  1210     CallFrame *varFramePtr = iPtr->varFramePtr;
  1211 
  1212 #ifdef TCL_TIP280
  1213     /* TIP #280 : Structures for tracking lines */
  1214     CmdFrame bcFrame;
  1215 #endif
  1216 
  1217 #ifdef TCL_COMPILE_DEBUG
  1218     int traceInstructions = (tclTraceExec == 3);
  1219     char cmdNameBuf[21];
  1220 #endif
  1221 
  1222     /*
  1223      * This procedure uses a stack to hold information about catch commands.
  1224      * This information is the current operand stack top when starting to
  1225      * execute the code for each catch command. It starts out with stack-
  1226      * allocated space but uses dynamically-allocated storage if needed.
  1227      */
  1228 
  1229 #define STATIC_CATCH_STACK_SIZE 4
  1230     int (catchStackStorage[STATIC_CATCH_STACK_SIZE]);
  1231     int *catchStackPtr = catchStackStorage;
  1232     int catchTop = -1;
  1233 
  1234 #ifdef TCL_TIP280
  1235     /* TIP #280 : Initialize the frame. Do not push it yet. */
  1236 
  1237     bcFrame.type      = ((codePtr->flags & TCL_BYTECODE_PRECOMPILED)
  1238 			 ? TCL_LOCATION_PREBC
  1239 			 : TCL_LOCATION_BC);
  1240     bcFrame.level     = (iPtr->cmdFramePtr == NULL ?
  1241 			 1 :
  1242 			 iPtr->cmdFramePtr->level + 1);
  1243     bcFrame.framePtr  = iPtr->framePtr;
  1244     bcFrame.nextPtr   = iPtr->cmdFramePtr;
  1245     bcFrame.nline     = 0;
  1246     bcFrame.line      = NULL;
  1247 
  1248     bcFrame.data.tebc.codePtr  = codePtr;
  1249     bcFrame.data.tebc.pc       = NULL;
  1250     bcFrame.cmd.str.cmd        = NULL;
  1251     bcFrame.cmd.str.len        = 0;
  1252 #endif
  1253 
  1254 #ifdef TCL_COMPILE_DEBUG
  1255     if (tclTraceExec >= 2) {
  1256 	PrintByteCodeInfo(codePtr);
  1257 	fprintf(stdout, "  Starting stack top=%d\n", eePtr->stackTop);
  1258 	fflush(stdout);
  1259     }
  1260     opnd = 0;			/* Init. avoids compiler warning. */       
  1261 #endif
  1262     
  1263 #ifdef TCL_COMPILE_STATS
  1264     iPtr->stats.numExecutions++;
  1265 #endif
  1266 
  1267     /*
  1268      * Make sure the catch stack is large enough to hold the maximum number
  1269      * of catch commands that could ever be executing at the same time. This
  1270      * will be no more than the exception range array's depth.
  1271      */
  1272 
  1273     if (codePtr->maxExceptDepth > STATIC_CATCH_STACK_SIZE) {
  1274 	catchStackPtr = (int *)
  1275 	        ckalloc(codePtr->maxExceptDepth * sizeof(int));
  1276     }
  1277 
  1278     /*
  1279      * Make sure the stack has enough room to execute this ByteCode.
  1280      */
  1281 
  1282     while ((stackTop + codePtr->maxStackDepth) > eePtr->stackEnd) {
  1283         GrowEvaluationStack(eePtr); 
  1284         stackPtr = eePtr->stackPtr;
  1285     }
  1286 
  1287     /*
  1288      * Loop executing instructions until a "done" instruction, a 
  1289      * TCL_RETURN, or some error.
  1290      */
  1291 
  1292     goto cleanup0;
  1293 
  1294     
  1295     /*
  1296      * Targets for standard instruction endings; unrolled
  1297      * for speed in the most frequent cases (instructions that 
  1298      * consume up to two stack elements).
  1299      *
  1300      * This used to be a "for(;;)" loop, with each instruction doing
  1301      * its own cleanup.
  1302      */
  1303     
  1304     cleanupV_pushObjResultPtr:
  1305     switch (cleanup) {
  1306         case 0:
  1307 	    stackPtr[++stackTop] = (objResultPtr);
  1308 	    goto cleanup0;
  1309         default:
  1310 	    cleanup -= 2;
  1311 	    while (cleanup--) {
  1312 		valuePtr = POP_OBJECT();
  1313 		TclDecrRefCount(valuePtr);
  1314 	    }
  1315         case 2: 
  1316         cleanup2_pushObjResultPtr:
  1317 	    valuePtr = POP_OBJECT();
  1318 	    TclDecrRefCount(valuePtr);
  1319         case 1: 
  1320         cleanup1_pushObjResultPtr:
  1321 	    valuePtr = stackPtr[stackTop];
  1322 	    TclDecrRefCount(valuePtr);
  1323     }
  1324     stackPtr[stackTop] = objResultPtr;
  1325     goto cleanup0;
  1326     
  1327     cleanupV:
  1328     switch (cleanup) {
  1329         default:
  1330 	    cleanup -= 2;
  1331 	    while (cleanup--) {
  1332 		valuePtr = POP_OBJECT();
  1333 		TclDecrRefCount(valuePtr);
  1334 	    }
  1335         case 2: 
  1336         cleanup2:
  1337 	    valuePtr = POP_OBJECT();
  1338 	    TclDecrRefCount(valuePtr);
  1339         case 1: 
  1340         cleanup1:
  1341 	    valuePtr = POP_OBJECT();
  1342 	    TclDecrRefCount(valuePtr);
  1343         case 0:
  1344 	    /*
  1345 	     * We really want to do nothing now, but this is needed
  1346 	     * for some compilers (SunPro CC)
  1347 	     */
  1348 	    break;
  1349     }
  1350 
  1351     cleanup0:
  1352     
  1353 #ifdef TCL_COMPILE_DEBUG
  1354     ValidatePcAndStackTop(codePtr, pc, stackTop, initStackTop);
  1355     if (traceInstructions) {
  1356 	fprintf(stdout, "%2d: %2d ", iPtr->numLevels, stackTop);
  1357 	TclPrintInstruction(codePtr, pc);
  1358 	fflush(stdout);
  1359     }
  1360 #endif /* TCL_COMPILE_DEBUG */
  1361     
  1362 #ifdef TCL_COMPILE_STATS    
  1363     iPtr->stats.instructionCount[*pc]++;
  1364 #endif
  1365     switch (*pc) {
  1366     case INST_DONE:
  1367 	if (stackTop <= initStackTop) {
  1368 	    stackTop--;
  1369 	    goto abnormalReturn;
  1370 	}
  1371 	
  1372 	/*
  1373 	 * Set the interpreter's object result to point to the 
  1374 	 * topmost object from the stack, and check for a possible
  1375 	 * [catch]. The stackTop's level and refCount will be handled 
  1376 	 * by "processCatch" or "abnormalReturn".
  1377 	 */
  1378 
  1379 	valuePtr = stackPtr[stackTop];
  1380 	Tcl_SetObjResult(interp, valuePtr);
  1381 #ifdef TCL_COMPILE_DEBUG	    
  1382 	TRACE_WITH_OBJ(("=> return code=%d, result=", result),
  1383 	        iPtr->objResultPtr);
  1384 	if (traceInstructions) {
  1385 	    fprintf(stdout, "\n");
  1386 	}
  1387 #endif
  1388 	goto checkForCatch;
  1389 	
  1390     case INST_PUSH1:
  1391 	objResultPtr = codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)];
  1392 	TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), objResultPtr);
  1393 	NEXT_INST_F(2, 0, 1);
  1394 
  1395     case INST_PUSH4:
  1396 	objResultPtr = codePtr->objArrayPtr[TclGetUInt4AtPtr(pc+1)];
  1397 	TRACE_WITH_OBJ(("%u => ", TclGetUInt4AtPtr(pc+1)), objResultPtr);
  1398 	NEXT_INST_F(5, 0, 1);
  1399 
  1400     case INST_POP:
  1401 	TRACE_WITH_OBJ(("=> discarding "), stackPtr[stackTop]);
  1402 	valuePtr = POP_OBJECT();
  1403 	TclDecrRefCount(valuePtr);
  1404 	NEXT_INST_F(1, 0, 0);
  1405 	
  1406     case INST_DUP:
  1407 	objResultPtr = stackPtr[stackTop];
  1408 	TRACE_WITH_OBJ(("=> "), objResultPtr);
  1409 	NEXT_INST_F(1, 0, 1);
  1410 
  1411     case INST_OVER:
  1412 	opnd = TclGetUInt4AtPtr( pc+1 );
  1413 	objResultPtr = stackPtr[ stackTop - opnd ];
  1414 	TRACE_WITH_OBJ(("=> "), objResultPtr);
  1415 	NEXT_INST_F(5, 0, 1);
  1416 
  1417     case INST_CONCAT1:
  1418 	opnd = TclGetUInt1AtPtr(pc+1);
  1419 	{
  1420 	    int totalLen = 0;
  1421 	    
  1422 	    /*
  1423 	     * Peephole optimisation for appending an empty string.
  1424 	     * This enables replacing 'K $x [set x{}]' by '$x[set x{}]'
  1425 	     * for fastest execution. Avoid doing the optimisation for wide
  1426 	     * ints - a case where equal strings may refer to different values
  1427 	     * (see [Bug 1251791]).
  1428 	     */
  1429 
  1430 	    if ((opnd == 2) && (stackPtr[stackTop-1]->typePtr != &tclWideIntType)) {
  1431 		Tcl_GetStringFromObj(stackPtr[stackTop], &length);
  1432 		if (length == 0) {
  1433 		    /* Just drop the top item from the stack */
  1434 		    NEXT_INST_F(2, 1, 0);
  1435 		}
  1436 	    }
  1437 
  1438 	    /*
  1439 	     * Concatenate strings (with no separators) from the top
  1440 	     * opnd items on the stack starting with the deepest item.
  1441 	     * First, determine how many characters are needed.
  1442 	     */
  1443 
  1444 	    for (i = (stackTop - (opnd-1));  i <= stackTop;  i++) {
  1445 		bytes = Tcl_GetStringFromObj(stackPtr[i], &length);
  1446 		if (bytes != NULL) {
  1447 		    totalLen += length;
  1448 		}
  1449 	    }
  1450 
  1451 	    /*
  1452 	     * Initialize the new append string object by appending the
  1453 	     * strings of the opnd stack objects. Also pop the objects. 
  1454 	     */
  1455 
  1456 	    TclNewObj(objResultPtr);
  1457 	    if (totalLen > 0) {
  1458 		char *p = (char *) ckalloc((unsigned) (totalLen + 1));
  1459 		objResultPtr->bytes = p;
  1460 		objResultPtr->length = totalLen;
  1461 		for (i = (stackTop - (opnd-1));  i <= stackTop;  i++) {
  1462 		    valuePtr = stackPtr[i];
  1463 		    bytes = Tcl_GetStringFromObj(valuePtr, &length);
  1464 		    if (bytes != NULL) {
  1465 			memcpy((VOID *) p, (VOID *) bytes,
  1466 			       (size_t) length);
  1467 			p += length;
  1468 		    }
  1469 		}
  1470 		*p = '\0';
  1471 	    }
  1472 		
  1473 	    TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
  1474 	    NEXT_INST_V(2, opnd, 1);
  1475 	}
  1476 	    
  1477     case INST_INVOKE_STK4:
  1478 	opnd = TclGetUInt4AtPtr(pc+1);
  1479 	pcAdjustment = 5;
  1480 	goto doInvocation;
  1481 
  1482     case INST_INVOKE_STK1:
  1483 	opnd = TclGetUInt1AtPtr(pc+1);
  1484 	pcAdjustment = 2;
  1485 	    
  1486     doInvocation:
  1487 	{
  1488 	    int objc = opnd; /* The number of arguments. */
  1489 	    Tcl_Obj **objv;	 /* The array of argument objects. */
  1490 
  1491 	    /*
  1492 	     * We keep the stack reference count as a (char *), as that
  1493 	     * works nicely as a portable pointer-sized counter.
  1494 	     */
  1495 
  1496 	    char **preservedStackRefCountPtr;
  1497 	    
  1498 	    /* 
  1499 	     * Reference to memory block containing
  1500 	     * objv array (must be kept live throughout
  1501 	     * trace and command invokations.) 
  1502 	     */
  1503 
  1504 	    objv = &(stackPtr[stackTop - (objc-1)]);
  1505 
  1506 #ifdef TCL_COMPILE_DEBUG
  1507 	    if (tclTraceExec >= 2) {
  1508 		if (traceInstructions) {
  1509 		    strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
  1510 		    TRACE(("%u => call ", objc));
  1511 		} else {
  1512 		    fprintf(stdout, "%d: (%u) invoking ",
  1513 			    iPtr->numLevels,
  1514 			    (unsigned int)(pc - codePtr->codeStart));
  1515 		}
  1516 		for (i = 0;  i < objc;  i++) {
  1517 		    TclPrintObject(stdout, objv[i], 15);
  1518 		    fprintf(stdout, " ");
  1519 		}
  1520 		fprintf(stdout, "\n");
  1521 		fflush(stdout);
  1522 	    }
  1523 #endif /*TCL_COMPILE_DEBUG*/
  1524 
  1525 	    /* 
  1526 	     * If trace procedures will be called, we need a
  1527 	     * command string to pass to TclEvalObjvInternal; note 
  1528 	     * that a copy of the string will be made there to 
  1529 	     * include the ending \0.
  1530 	     */
  1531 
  1532 	    bytes = NULL;
  1533 	    length = 0;
  1534 	    if (iPtr->tracePtr != NULL) {
  1535 		Trace *tracePtr, *nextTracePtr;
  1536 		    
  1537 		for (tracePtr = iPtr->tracePtr;  tracePtr != NULL;
  1538 		     tracePtr = nextTracePtr) {
  1539 		    nextTracePtr = tracePtr->nextPtr;
  1540 		    if (tracePtr->level == 0 ||
  1541 			iPtr->numLevels <= tracePtr->level) {
  1542 			/*
  1543 			 * Traces will be called: get command string
  1544 			 */
  1545 
  1546 			bytes = GetSrcInfoForPc(pc, codePtr, &length);
  1547 			break;
  1548 		    }
  1549 		}
  1550 	    } else {		
  1551 		Command *cmdPtr;
  1552 		cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[0]);
  1553 		if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_HAS_EXEC_TRACES)) {
  1554 		    bytes = GetSrcInfoForPc(pc, codePtr, &length);
  1555 		}
  1556 	    }		
  1557 
  1558 	    /*
  1559 	     * A reference to part of the stack vector itself
  1560 	     * escapes our control: increase its refCount
  1561 	     * to stop it from being deallocated by a recursive
  1562 	     * call to ourselves.  The extra variable is needed
  1563 	     * because all others are liable to change due to the
  1564 	     * trace procedures.
  1565 	     */
  1566 
  1567 	    preservedStackRefCountPtr = (char **) (stackPtr-1);
  1568 	    ++*preservedStackRefCountPtr;
  1569 
  1570 	    /*
  1571 	     * Finally, let TclEvalObjvInternal handle the command.
  1572 	     *
  1573 	     * TIP #280 : Record the last piece of info needed by
  1574 	     * 'TclGetSrcInfoForPc', and push the frame.
  1575 	     */
  1576 
  1577 #ifdef TCL_TIP280
  1578 	    bcFrame.data.tebc.pc = pc;
  1579 	    iPtr->cmdFramePtr = &bcFrame;
  1580 #endif
  1581 	    DECACHE_STACK_INFO();
  1582 	    Tcl_ResetResult(interp);
  1583 	    result = TclEvalObjvInternal(interp, objc, objv, bytes, length, 0);
  1584 	    CACHE_STACK_INFO();
  1585 #ifdef TCL_TIP280
  1586 	    iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;
  1587 #endif
  1588 
  1589 	    /*
  1590 	     * If the old stack is going to be released, it is
  1591 	     * safe to do so now, since no references to objv are
  1592 	     * going to be used from now on.
  1593 	     */
  1594 
  1595 	    --*preservedStackRefCountPtr;
  1596 	    if (*preservedStackRefCountPtr == (char *) 0) {
  1597 		ckfree((VOID *) preservedStackRefCountPtr);
  1598 	    }	    
  1599 
  1600 	    if (result == TCL_OK) {
  1601 		/*
  1602 		 * Push the call's object result and continue execution
  1603 		 * with the next instruction.
  1604 		 */
  1605 
  1606 		TRACE_WITH_OBJ(("%u => ... after \"%.20s\": TCL_OK, result=",
  1607 		        objc, cmdNameBuf), Tcl_GetObjResult(interp));
  1608 
  1609 		objResultPtr = Tcl_GetObjResult(interp);
  1610 
  1611 		/*
  1612 		 * Reset the interp's result to avoid possible duplications
  1613 		 * of large objects [Bug 781585]. We do not call
  1614 		 * Tcl_ResetResult() to avoid any side effects caused by
  1615 		 * the resetting of errorInfo and errorCode [Bug 804681], 
  1616 		 * which are not needed here. We chose instead to manipulate
  1617 		 * the interp's object result directly.
  1618 		 *
  1619 		 * Note that the result object is now in objResultPtr, it
  1620 		 * keeps the refCount it had in its role of iPtr->objResultPtr.
  1621 		 */
  1622 		{
  1623 		    Tcl_Obj *newObjResultPtr;
  1624 		    TclNewObj(newObjResultPtr);
  1625 		    Tcl_IncrRefCount(newObjResultPtr);
  1626 		    iPtr->objResultPtr = newObjResultPtr;
  1627 		}
  1628 
  1629 		NEXT_INST_V(pcAdjustment, opnd, -1);
  1630 	    } else {
  1631 		cleanup = opnd;
  1632 		goto processExceptionReturn;
  1633 	    }
  1634 	}
  1635 
  1636     case INST_EVAL_STK:
  1637 	/*
  1638 	 * Note to maintainers: it is important that INST_EVAL_STK
  1639 	 * pop its argument from the stack before jumping to
  1640 	 * checkForCatch! DO NOT OPTIMISE!
  1641 	 */
  1642 
  1643 	objPtr = stackPtr[stackTop];
  1644 	DECACHE_STACK_INFO();
  1645 #ifndef TCL_TIP280
  1646 	result = TclCompEvalObj(interp, objPtr);
  1647 #else
  1648 	/* TIP #280: The invoking context is left NULL for a dynamically
  1649 	 * constructed command. We cannot match its lines to the outer
  1650 	 * context.
  1651 	 */
  1652 
  1653 	result = TclCompEvalObj(interp, objPtr, NULL,0);
  1654 #endif
  1655 	CACHE_STACK_INFO();
  1656 	if (result == TCL_OK) {
  1657 	    /*
  1658 	     * Normal return; push the eval's object result.
  1659 	     */
  1660 
  1661 	    objResultPtr = Tcl_GetObjResult(interp);
  1662 	    TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)),
  1663 			   Tcl_GetObjResult(interp));
  1664 
  1665 	    /*
  1666 	     * Reset the interp's result to avoid possible duplications
  1667 	     * of large objects [Bug 781585]. We do not call
  1668 	     * Tcl_ResetResult() to avoid any side effects caused by
  1669 	     * the resetting of errorInfo and errorCode [Bug 804681], 
  1670 	     * which are not needed here. We chose instead to manipulate
  1671 	     * the interp's object result directly.
  1672 	     *
  1673 	     * Note that the result object is now in objResultPtr, it
  1674 	     * keeps the refCount it had in its role of iPtr->objResultPtr.
  1675 	     */
  1676 	    {
  1677 	        Tcl_Obj *newObjResultPtr;
  1678 		TclNewObj(newObjResultPtr);
  1679 		Tcl_IncrRefCount(newObjResultPtr);
  1680 		iPtr->objResultPtr = newObjResultPtr;
  1681 	    }
  1682 
  1683 	    NEXT_INST_F(1, 1, -1);
  1684 	} else {
  1685 	    cleanup = 1;
  1686 	    goto processExceptionReturn;
  1687 	}
  1688 
  1689     case INST_EXPR_STK:
  1690 	objPtr = stackPtr[stackTop];
  1691 	DECACHE_STACK_INFO();
  1692 	Tcl_ResetResult(interp);
  1693 	result = Tcl_ExprObj(interp, objPtr, &valuePtr);
  1694 	CACHE_STACK_INFO();
  1695 	if (result != TCL_OK) {
  1696 	    TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", 
  1697 	        O2S(objPtr)), Tcl_GetObjResult(interp));
  1698 	    goto checkForCatch;
  1699 	}
  1700 	objResultPtr = valuePtr;
  1701 	TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)), valuePtr);
  1702 	NEXT_INST_F(1, 1, -1); /* already has right refct */
  1703 
  1704     /*
  1705      * ---------------------------------------------------------
  1706      *     Start of INST_LOAD instructions.
  1707      *
  1708      * WARNING: more 'goto' here than your doctor recommended!
  1709      * The different instructions set the value of some variables
  1710      * and then jump to somme common execution code.
  1711      */
  1712 
  1713     case INST_LOAD_SCALAR1:
  1714 	opnd = TclGetUInt1AtPtr(pc+1);
  1715 	varPtr = &(varFramePtr->compiledLocals[opnd]);
  1716 	part1 = varPtr->name;
  1717 	while (TclIsVarLink(varPtr)) {
  1718 	    varPtr = varPtr->value.linkPtr;
  1719 	}
  1720 	TRACE(("%u => ", opnd));
  1721 	if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) 
  1722 	        && (varPtr->tracePtr == NULL)) {
  1723 	    /*
  1724 	     * No errors, no traces: just get the value.
  1725 	     */
  1726 	    objResultPtr = varPtr->value.objPtr;
  1727 	    TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  1728 	    NEXT_INST_F(2, 0, 1);
  1729 	}
  1730 	pcAdjustment = 2;
  1731 	cleanup = 0;
  1732 	arrayPtr = NULL;
  1733 	part2 = NULL;
  1734 	goto doCallPtrGetVar;
  1735 
  1736     case INST_LOAD_SCALAR4:
  1737 	opnd = TclGetUInt4AtPtr(pc+1);
  1738 	varPtr = &(varFramePtr->compiledLocals[opnd]);
  1739 	part1 = varPtr->name;
  1740 	while (TclIsVarLink(varPtr)) {
  1741 	    varPtr = varPtr->value.linkPtr;
  1742 	}
  1743 	TRACE(("%u => ", opnd));
  1744 	if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) 
  1745 	        && (varPtr->tracePtr == NULL)) {
  1746 	    /*
  1747 	     * No errors, no traces: just get the value.
  1748 	     */
  1749 	    objResultPtr = varPtr->value.objPtr;
  1750 	    TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  1751 	    NEXT_INST_F(5, 0, 1);
  1752 	}
  1753 	pcAdjustment = 5;
  1754 	cleanup = 0;
  1755 	arrayPtr = NULL;
  1756 	part2 = NULL;
  1757 	goto doCallPtrGetVar;
  1758 
  1759     case INST_LOAD_ARRAY_STK:
  1760 	cleanup = 2;
  1761 	part2 = Tcl_GetString(stackPtr[stackTop]);  /* element name */
  1762 	objPtr = stackPtr[stackTop-1]; /* array name */
  1763 	TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), part2));
  1764 	goto doLoadStk;
  1765 
  1766     case INST_LOAD_STK:
  1767     case INST_LOAD_SCALAR_STK:
  1768 	cleanup = 1;
  1769 	part2 = NULL;
  1770 	objPtr = stackPtr[stackTop]; /* variable name */
  1771 	TRACE(("\"%.30s\" => ", O2S(objPtr)));
  1772 
  1773     doLoadStk:
  1774 	part1 = TclGetString(objPtr);
  1775 	varPtr = TclObjLookupVar(interp, objPtr, part2, 
  1776 	         TCL_LEAVE_ERR_MSG, "read",
  1777                  /*createPart1*/ 0,
  1778 	         /*createPart2*/ 1, &arrayPtr);
  1779 	if (varPtr == NULL) {
  1780 	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  1781 	    result = TCL_ERROR;
  1782 	    goto checkForCatch;
  1783 	}
  1784 	if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) 
  1785 	        && (varPtr->tracePtr == NULL)
  1786 	        && ((arrayPtr == NULL) 
  1787 		        || (arrayPtr->tracePtr == NULL))) {
  1788 	    /*
  1789 	     * No errors, no traces: just get the value.
  1790 	     */
  1791 	    objResultPtr = varPtr->value.objPtr;
  1792 	    TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  1793 	    NEXT_INST_V(1, cleanup, 1);
  1794 	}
  1795 	pcAdjustment = 1;
  1796 	goto doCallPtrGetVar;
  1797 
  1798     case INST_LOAD_ARRAY4:
  1799 	opnd = TclGetUInt4AtPtr(pc+1);
  1800 	pcAdjustment = 5;
  1801 	goto doLoadArray;
  1802 
  1803     case INST_LOAD_ARRAY1:
  1804 	opnd = TclGetUInt1AtPtr(pc+1);
  1805 	pcAdjustment = 2;
  1806     
  1807     doLoadArray:
  1808 	part2 = TclGetString(stackPtr[stackTop]);
  1809 	arrayPtr = &(varFramePtr->compiledLocals[opnd]);
  1810 	part1 = arrayPtr->name;
  1811 	while (TclIsVarLink(arrayPtr)) {
  1812 	    arrayPtr = arrayPtr->value.linkPtr;
  1813 	}
  1814 	TRACE(("%u \"%.30s\" => ", opnd, part2));
  1815 	varPtr = TclLookupArrayElement(interp, part1, part2, 
  1816 	        TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr);
  1817 	if (varPtr == NULL) {
  1818 	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  1819 	    result = TCL_ERROR;
  1820 	    goto checkForCatch;
  1821 	}
  1822 	if (TclIsVarScalar(varPtr) && !TclIsVarUndefined(varPtr) 
  1823 	        && (varPtr->tracePtr == NULL)
  1824 	        && ((arrayPtr == NULL) 
  1825 		        || (arrayPtr->tracePtr == NULL))) {
  1826 	    /*
  1827 	     * No errors, no traces: just get the value.
  1828 	     */
  1829 	    objResultPtr = varPtr->value.objPtr;
  1830 	    TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  1831 	    NEXT_INST_F(pcAdjustment, 1, 1);
  1832 	}
  1833 	cleanup = 1;
  1834 	goto doCallPtrGetVar;
  1835 
  1836     doCallPtrGetVar:
  1837 	/*
  1838 	 * There are either errors or the variable is traced:
  1839 	 * call TclPtrGetVar to process fully.
  1840 	 */
  1841 
  1842 	DECACHE_STACK_INFO();
  1843 	objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1, 
  1844 	        part2, TCL_LEAVE_ERR_MSG);
  1845 	CACHE_STACK_INFO();
  1846 	if (objResultPtr == NULL) {
  1847 	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  1848 	    result = TCL_ERROR;
  1849 	    goto checkForCatch;
  1850 	}
  1851 	TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  1852 	NEXT_INST_V(pcAdjustment, cleanup, 1);
  1853 
  1854     /*
  1855      *     End of INST_LOAD instructions.
  1856      * ---------------------------------------------------------
  1857      */
  1858 
  1859     /*
  1860      * ---------------------------------------------------------
  1861      *     Start of INST_STORE and related instructions.
  1862      *
  1863      * WARNING: more 'goto' here than your doctor recommended!
  1864      * The different instructions set the value of some variables
  1865      * and then jump to somme common execution code.
  1866      */
  1867 
  1868     case INST_LAPPEND_STK:
  1869 	valuePtr = stackPtr[stackTop]; /* value to append */
  1870 	part2 = NULL;
  1871 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE 
  1872 		      | TCL_LIST_ELEMENT | TCL_TRACE_READS);
  1873 	goto doStoreStk;
  1874 
  1875     case INST_LAPPEND_ARRAY_STK:
  1876 	valuePtr = stackPtr[stackTop]; /* value to append */
  1877 	part2 = TclGetString(stackPtr[stackTop - 1]);
  1878 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE 
  1879 		      | TCL_LIST_ELEMENT | TCL_TRACE_READS);
  1880 	goto doStoreStk;
  1881 
  1882     case INST_APPEND_STK:
  1883 	valuePtr = stackPtr[stackTop]; /* value to append */
  1884 	part2 = NULL;
  1885 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
  1886 	goto doStoreStk;
  1887 
  1888     case INST_APPEND_ARRAY_STK:
  1889 	valuePtr = stackPtr[stackTop]; /* value to append */
  1890 	part2 = TclGetString(stackPtr[stackTop - 1]);
  1891 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
  1892 	goto doStoreStk;
  1893 
  1894     case INST_STORE_ARRAY_STK:
  1895 	valuePtr = stackPtr[stackTop];
  1896 	part2 = TclGetString(stackPtr[stackTop - 1]);
  1897 	storeFlags = TCL_LEAVE_ERR_MSG;
  1898 	goto doStoreStk;
  1899 
  1900     case INST_STORE_STK:
  1901     case INST_STORE_SCALAR_STK:
  1902 	valuePtr = stackPtr[stackTop];
  1903 	part2 = NULL;
  1904 	storeFlags = TCL_LEAVE_ERR_MSG;
  1905 
  1906     doStoreStk:
  1907 	objPtr = stackPtr[stackTop - 1 - (part2 != NULL)]; /* variable name */
  1908 	part1 = TclGetString(objPtr);
  1909 #ifdef TCL_COMPILE_DEBUG
  1910 	if (part2 == NULL) {
  1911 	    TRACE(("\"%.30s\" <- \"%.30s\" =>", 
  1912 	            part1, O2S(valuePtr)));
  1913 	} else {
  1914 	    TRACE(("\"%.30s(%.30s)\" <- \"%.30s\" => ",
  1915 		    part1, part2, O2S(valuePtr)));
  1916 	}
  1917 #endif
  1918 	varPtr = TclObjLookupVar(interp, objPtr, part2, 
  1919 	         TCL_LEAVE_ERR_MSG, "set",
  1920                  /*createPart1*/ 1,
  1921 	         /*createPart2*/ 1, &arrayPtr);
  1922 	if (varPtr == NULL) {
  1923 	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  1924 	    result = TCL_ERROR;
  1925 	    goto checkForCatch;
  1926 	}
  1927 	cleanup = ((part2 == NULL)? 2 : 3);
  1928 	pcAdjustment = 1;
  1929 	goto doCallPtrSetVar;
  1930 
  1931     case INST_LAPPEND_ARRAY4:
  1932 	opnd = TclGetUInt4AtPtr(pc+1);
  1933 	pcAdjustment = 5;
  1934 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE 
  1935 		      | TCL_LIST_ELEMENT | TCL_TRACE_READS);
  1936 	goto doStoreArray;
  1937 
  1938     case INST_LAPPEND_ARRAY1:
  1939 	opnd = TclGetUInt1AtPtr(pc+1);
  1940 	pcAdjustment = 2;
  1941 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE 
  1942 		      | TCL_LIST_ELEMENT | TCL_TRACE_READS);
  1943 	goto doStoreArray;
  1944 
  1945     case INST_APPEND_ARRAY4:
  1946 	opnd = TclGetUInt4AtPtr(pc+1);
  1947 	pcAdjustment = 5;
  1948 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
  1949 	goto doStoreArray;
  1950 
  1951     case INST_APPEND_ARRAY1:
  1952 	opnd = TclGetUInt1AtPtr(pc+1);
  1953 	pcAdjustment = 2;
  1954 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
  1955 	goto doStoreArray;
  1956 
  1957     case INST_STORE_ARRAY4:
  1958 	opnd = TclGetUInt4AtPtr(pc+1);
  1959 	pcAdjustment = 5;
  1960 	storeFlags = TCL_LEAVE_ERR_MSG;
  1961 	goto doStoreArray;
  1962 
  1963     case INST_STORE_ARRAY1:
  1964 	opnd = TclGetUInt1AtPtr(pc+1);
  1965 	pcAdjustment = 2;
  1966 	storeFlags = TCL_LEAVE_ERR_MSG;
  1967 	    
  1968     doStoreArray:
  1969 	valuePtr = stackPtr[stackTop];
  1970 	part2 = TclGetString(stackPtr[stackTop - 1]);
  1971 	arrayPtr = &(varFramePtr->compiledLocals[opnd]);
  1972 	part1 = arrayPtr->name;
  1973 	TRACE(("%u \"%.30s\" <- \"%.30s\" => ",
  1974 		    opnd, part2, O2S(valuePtr)));
  1975 	while (TclIsVarLink(arrayPtr)) {
  1976 	    arrayPtr = arrayPtr->value.linkPtr;
  1977 	}
  1978 	varPtr = TclLookupArrayElement(interp, part1, part2, 
  1979 	        TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr);
  1980 	if (varPtr == NULL) {
  1981 	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  1982 	    result = TCL_ERROR;
  1983 	    goto checkForCatch;
  1984 	}
  1985 	cleanup = 2;
  1986 	goto doCallPtrSetVar;
  1987 
  1988     case INST_LAPPEND_SCALAR4:
  1989 	opnd = TclGetUInt4AtPtr(pc+1);
  1990 	pcAdjustment = 5;
  1991 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE 
  1992 		      | TCL_LIST_ELEMENT | TCL_TRACE_READS);
  1993 	goto doStoreScalar;
  1994 
  1995     case INST_LAPPEND_SCALAR1:
  1996 	opnd = TclGetUInt1AtPtr(pc+1);
  1997 	pcAdjustment = 2;	    
  1998 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE 
  1999 		      | TCL_LIST_ELEMENT | TCL_TRACE_READS);
  2000 	goto doStoreScalar;
  2001 
  2002     case INST_APPEND_SCALAR4:
  2003 	opnd = TclGetUInt4AtPtr(pc+1);
  2004 	pcAdjustment = 5;
  2005 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
  2006 	goto doStoreScalar;
  2007 
  2008     case INST_APPEND_SCALAR1:
  2009 	opnd = TclGetUInt1AtPtr(pc+1);
  2010 	pcAdjustment = 2;	    
  2011 	storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
  2012 	goto doStoreScalar;
  2013 
  2014     case INST_STORE_SCALAR4:
  2015 	opnd = TclGetUInt4AtPtr(pc+1);
  2016 	pcAdjustment = 5;
  2017 	storeFlags = TCL_LEAVE_ERR_MSG;
  2018 	goto doStoreScalar;
  2019 
  2020     case INST_STORE_SCALAR1:
  2021 	opnd = TclGetUInt1AtPtr(pc+1);
  2022 	pcAdjustment = 2;
  2023 	storeFlags = TCL_LEAVE_ERR_MSG;
  2024 
  2025     doStoreScalar:
  2026 	valuePtr = stackPtr[stackTop];
  2027 	varPtr = &(varFramePtr->compiledLocals[opnd]);
  2028 	part1 = varPtr->name;
  2029 	TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
  2030 	while (TclIsVarLink(varPtr)) {
  2031 	    varPtr = varPtr->value.linkPtr;
  2032 	}
  2033 	cleanup = 1;
  2034 	arrayPtr = NULL;
  2035 	part2 = NULL;
  2036 
  2037     doCallPtrSetVar:
  2038 	if ((storeFlags == TCL_LEAVE_ERR_MSG)
  2039 	        && !((varPtr->flags & VAR_IN_HASHTABLE) 
  2040 		        && (varPtr->hPtr == NULL))
  2041 	        && (varPtr->tracePtr == NULL)
  2042 	        && (TclIsVarScalar(varPtr) 
  2043 		        || TclIsVarUndefined(varPtr))
  2044 	        && ((arrayPtr == NULL) 
  2045 		        || (arrayPtr->tracePtr == NULL))) {
  2046 	    /*
  2047 	     * No traces, no errors, plain 'set': we can safely inline.
  2048 	     * The value *will* be set to what's requested, so that 
  2049 	     * the stack top remains pointing to the same Tcl_Obj.
  2050 	     */
  2051 	    valuePtr = varPtr->value.objPtr;
  2052 	    objResultPtr = stackPtr[stackTop];
  2053 	    if (valuePtr != objResultPtr) {
  2054 		if (valuePtr != NULL) {
  2055 		    TclDecrRefCount(valuePtr);
  2056 		} else {
  2057 		    TclSetVarScalar(varPtr);
  2058 		    TclClearVarUndefined(varPtr);
  2059 		}
  2060 		varPtr->value.objPtr = objResultPtr;
  2061 		Tcl_IncrRefCount(objResultPtr);
  2062 	    }
  2063 #ifndef TCL_COMPILE_DEBUG
  2064 	    if (*(pc+pcAdjustment) == INST_POP) {
  2065 		NEXT_INST_V((pcAdjustment+1), cleanup, 0);
  2066 	    }
  2067 #else
  2068 	TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  2069 #endif
  2070 	    NEXT_INST_V(pcAdjustment, cleanup, 1);
  2071 	} else {
  2072 	    DECACHE_STACK_INFO();
  2073 	    objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr, 
  2074 	            part1, part2, valuePtr, storeFlags);
  2075 	    CACHE_STACK_INFO();
  2076 	    if (objResultPtr == NULL) {
  2077 		TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  2078 		result = TCL_ERROR;
  2079 		goto checkForCatch;
  2080 	    }
  2081 	}
  2082 #ifndef TCL_COMPILE_DEBUG
  2083 	if (*(pc+pcAdjustment) == INST_POP) {
  2084 	    NEXT_INST_V((pcAdjustment+1), cleanup, 0);
  2085 	}
  2086 #endif
  2087 	TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  2088 	NEXT_INST_V(pcAdjustment, cleanup, 1);
  2089 
  2090 
  2091     /*
  2092      *     End of INST_STORE and related instructions.
  2093      * ---------------------------------------------------------
  2094      */
  2095 
  2096     /*
  2097      * ---------------------------------------------------------
  2098      *     Start of INST_INCR instructions.
  2099      *
  2100      * WARNING: more 'goto' here than your doctor recommended!
  2101      * The different instructions set the value of some variables
  2102      * and then jump to somme common execution code.
  2103      */
  2104 
  2105     case INST_INCR_SCALAR1:
  2106     case INST_INCR_ARRAY1:
  2107     case INST_INCR_ARRAY_STK:
  2108     case INST_INCR_SCALAR_STK:
  2109     case INST_INCR_STK:
  2110 	opnd = TclGetUInt1AtPtr(pc+1);
  2111 	valuePtr = stackPtr[stackTop];
  2112 	if (valuePtr->typePtr == &tclIntType) {
  2113 	    i = valuePtr->internalRep.longValue;
  2114 	} else if (valuePtr->typePtr == &tclWideIntType) {
  2115 	    TclGetLongFromWide(i,valuePtr);
  2116 	} else {
  2117 	    REQUIRE_WIDE_OR_INT(result, valuePtr, i, w);
  2118 	    if (result != TCL_OK) {
  2119 		TRACE_WITH_OBJ(("%u (by %s) => ERROR converting increment amount to int: ",
  2120 		        opnd, O2S(valuePtr)), Tcl_GetObjResult(interp));
  2121 		DECACHE_STACK_INFO();
  2122 		Tcl_AddErrorInfo(interp, "\n    (reading increment)");
  2123 		CACHE_STACK_INFO();
  2124 		goto checkForCatch;
  2125 	    }
  2126 	    FORCE_LONG(valuePtr, i, w);
  2127 	}
  2128 	stackTop--;
  2129 	TclDecrRefCount(valuePtr);
  2130 	switch (*pc) {
  2131 	    case INST_INCR_SCALAR1:
  2132 		pcAdjustment = 2;
  2133 		goto doIncrScalar;
  2134 	    case INST_INCR_ARRAY1:
  2135 		pcAdjustment = 2;
  2136 		goto doIncrArray;
  2137 	    default:
  2138 		pcAdjustment = 1;
  2139 		goto doIncrStk;
  2140 	}
  2141 
  2142     case INST_INCR_ARRAY_STK_IMM:
  2143     case INST_INCR_SCALAR_STK_IMM:
  2144     case INST_INCR_STK_IMM:
  2145 	i = TclGetInt1AtPtr(pc+1);
  2146 	pcAdjustment = 2;
  2147 	    
  2148     doIncrStk:
  2149 	if ((*pc == INST_INCR_ARRAY_STK_IMM) 
  2150 	        || (*pc == INST_INCR_ARRAY_STK)) {
  2151 	    part2 = TclGetString(stackPtr[stackTop]);
  2152 	    objPtr = stackPtr[stackTop - 1];
  2153 	    TRACE(("\"%.30s(%.30s)\" (by %ld) => ",
  2154 		    O2S(objPtr), part2, i));
  2155 	} else {
  2156 	    part2 = NULL;
  2157 	    objPtr = stackPtr[stackTop];
  2158 	    TRACE(("\"%.30s\" (by %ld) => ", O2S(objPtr), i));
  2159 	}
  2160 	part1 = TclGetString(objPtr);
  2161 
  2162 	varPtr = TclObjLookupVar(interp, objPtr, part2, 
  2163 	        TCL_LEAVE_ERR_MSG, "read", 0, 1, &arrayPtr);
  2164 	if (varPtr == NULL) {
  2165 	    DECACHE_STACK_INFO();
  2166 	    Tcl_AddObjErrorInfo(interp,
  2167 	            "\n    (reading value of variable to increment)", -1);
  2168 	    CACHE_STACK_INFO();
  2169 	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  2170 	    result = TCL_ERROR;
  2171 	    goto checkForCatch;
  2172 	}
  2173 	cleanup = ((part2 == NULL)? 1 : 2);
  2174 	goto doIncrVar;
  2175 
  2176     case INST_INCR_ARRAY1_IMM:
  2177 	opnd = TclGetUInt1AtPtr(pc+1);
  2178 	i = TclGetInt1AtPtr(pc+2);
  2179 	pcAdjustment = 3;
  2180 
  2181     doIncrArray:
  2182 	part2 = TclGetString(stackPtr[stackTop]);
  2183 	arrayPtr = &(varFramePtr->compiledLocals[opnd]);
  2184 	part1 = arrayPtr->name;
  2185 	while (TclIsVarLink(arrayPtr)) {
  2186 	    arrayPtr = arrayPtr->value.linkPtr;
  2187 	}
  2188 	TRACE(("%u \"%.30s\" (by %ld) => ",
  2189 		    opnd, part2, i));
  2190 	varPtr = TclLookupArrayElement(interp, part1, part2, 
  2191 	        TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr);
  2192 	if (varPtr == NULL) {
  2193 	    TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  2194 	    result = TCL_ERROR;
  2195 	    goto checkForCatch;
  2196 	}
  2197 	cleanup = 1;
  2198 	goto doIncrVar;
  2199 
  2200     case INST_INCR_SCALAR1_IMM:
  2201 	opnd = TclGetUInt1AtPtr(pc+1);
  2202 	i = TclGetInt1AtPtr(pc+2);
  2203 	pcAdjustment = 3;
  2204 
  2205     doIncrScalar:
  2206 	varPtr = &(varFramePtr->compiledLocals[opnd]);
  2207 	part1 = varPtr->name;
  2208 	while (TclIsVarLink(varPtr)) {
  2209 	    varPtr = varPtr->value.linkPtr;
  2210 	}
  2211 	arrayPtr = NULL;
  2212 	part2 = NULL;
  2213 	cleanup = 0;
  2214 	TRACE(("%u %ld => ", opnd, i));
  2215 
  2216 
  2217     doIncrVar:
  2218 	objPtr = varPtr->value.objPtr;
  2219 	if (TclIsVarScalar(varPtr)
  2220 	        && !TclIsVarUndefined(varPtr) 
  2221 	        && (varPtr->tracePtr == NULL)
  2222 	        && ((arrayPtr == NULL) 
  2223 		        || (arrayPtr->tracePtr == NULL))
  2224 	        && (objPtr->typePtr == &tclIntType)) {
  2225 	    /*
  2226 	     * No errors, no traces, the variable already has an
  2227 	     * integer value: inline processing.
  2228 	     */
  2229 
  2230 	    i += objPtr->internalRep.longValue;
  2231 	    if (Tcl_IsShared(objPtr)) {
  2232 		objResultPtr = Tcl_NewLongObj(i);
  2233 		TclDecrRefCount(objPtr);
  2234 		Tcl_IncrRefCount(objResultPtr);
  2235 		varPtr->value.objPtr = objResultPtr;
  2236 	    } else {
  2237 		Tcl_SetLongObj(objPtr, i);
  2238 		objResultPtr = objPtr;
  2239 	    }
  2240 	    TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  2241 	} else {
  2242 	    DECACHE_STACK_INFO();
  2243 	    objResultPtr = TclPtrIncrVar(interp, varPtr, arrayPtr, part1, 
  2244                     part2, i, TCL_LEAVE_ERR_MSG);
  2245 	    CACHE_STACK_INFO();
  2246 	    if (objResultPtr == NULL) {
  2247 		TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
  2248 		result = TCL_ERROR;
  2249 		goto checkForCatch;
  2250 	    }
  2251 	}
  2252 	TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
  2253 #ifndef TCL_COMPILE_DEBUG
  2254 	if (*(pc+pcAdjustment) == INST_POP) {
  2255 	    NEXT_INST_V((pcAdjustment+1), cleanup, 0);
  2256 	}
  2257 #endif
  2258 	NEXT_INST_V(pcAdjustment, cleanup, 1);
  2259 	    	    
  2260     /*
  2261      *     End of INST_INCR instructions.
  2262      * ---------------------------------------------------------
  2263      */
  2264 
  2265 
  2266     case INST_JUMP1:
  2267 	opnd = TclGetInt1AtPtr(pc+1);
  2268 	TRACE(("%d => new pc %u\n", opnd,
  2269 	        (unsigned int)(pc + opnd - codePtr->codeStart)));
  2270 	NEXT_INST_F(opnd, 0, 0);
  2271 
  2272     case INST_JUMP4:
  2273 	opnd = TclGetInt4AtPtr(pc+1);
  2274 	TRACE(("%d => new pc %u\n", opnd,
  2275 	        (unsigned int)(pc + opnd - codePtr->codeStart)));
  2276 	NEXT_INST_F(opnd, 0, 0);
  2277 
  2278     case INST_JUMP_FALSE4:
  2279 	opnd = 5;                             /* TRUE */
  2280 	pcAdjustment = TclGetInt4AtPtr(pc+1); /* FALSE */
  2281 	goto doJumpTrue;
  2282 
  2283     case INST_JUMP_TRUE4:
  2284 	opnd = TclGetInt4AtPtr(pc+1);         /* TRUE */
  2285 	pcAdjustment = 5;                     /* FALSE */
  2286 	goto doJumpTrue;
  2287 
  2288     case INST_JUMP_FALSE1:
  2289 	opnd = 2;                             /* TRUE */
  2290 	pcAdjustment = TclGetInt1AtPtr(pc+1); /* FALSE */
  2291 	goto doJumpTrue;
  2292 
  2293     case INST_JUMP_TRUE1:
  2294 	opnd = TclGetInt1AtPtr(pc+1);          /* TRUE */
  2295 	pcAdjustment = 2;                      /* FALSE */
  2296 	    
  2297     doJumpTrue:
  2298 	{
  2299 	    int b;
  2300 		
  2301 	    valuePtr = stackPtr[stackTop];
  2302 	    if (valuePtr->typePtr == &tclIntType) {
  2303 		b = (valuePtr->internalRep.longValue != 0);
  2304 	    } else if (valuePtr->typePtr == &tclDoubleType) {
  2305 		b = (valuePtr->internalRep.doubleValue != 0.0);
  2306 	    } else if (valuePtr->typePtr == &tclWideIntType) {
  2307 		TclGetWide(w,valuePtr);
  2308 		b = (w != W0);
  2309 	    } else {
  2310 		result = Tcl_GetBooleanFromObj(interp, valuePtr, &b);
  2311 		if (result != TCL_OK) {
  2312 		    TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
  2313 		    goto checkForCatch;
  2314 		}
  2315 	    }
  2316 #ifndef TCL_COMPILE_DEBUG
  2317 	    NEXT_INST_F((b? opnd : pcAdjustment), 1, 0);
  2318 #else
  2319 	    if (b) {
  2320 		if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE1)) {
  2321 		    TRACE(("%d => %.20s true, new pc %u\n", opnd, O2S(valuePtr),
  2322 		            (unsigned int)(pc+opnd - codePtr->codeStart)));
  2323 		} else {
  2324 		    TRACE(("%d => %.20s true\n", pcAdjustment, O2S(valuePtr)));
  2325 		}
  2326 		NEXT_INST_F(opnd, 1, 0);
  2327 	    } else {
  2328 		if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE1)) {
  2329 		    TRACE(("%d => %.20s false\n", opnd, O2S(valuePtr)));
  2330 		} else {
  2331 		    opnd = pcAdjustment;
  2332 		    TRACE(("%d => %.20s false, new pc %u\n", opnd, O2S(valuePtr),
  2333 		            (unsigned int)(pc + opnd - codePtr->codeStart)));
  2334 		}
  2335 		NEXT_INST_F(pcAdjustment, 1, 0);
  2336 	    }
  2337 #endif
  2338 	}
  2339 	    	    
  2340     case INST_LOR:
  2341     case INST_LAND:
  2342     {
  2343 	/*
  2344 	 * Operands must be boolean or numeric. No int->double
  2345 	 * conversions are performed.
  2346 	 */
  2347 		
  2348 	int i1, i2;
  2349 	int iResult;
  2350 	char *s;
  2351 	Tcl_ObjType *t1Ptr, *t2Ptr;
  2352 
  2353 	value2Ptr = stackPtr[stackTop];
  2354 	valuePtr  = stackPtr[stackTop - 1];;
  2355 	t1Ptr = valuePtr->typePtr;
  2356 	t2Ptr = value2Ptr->typePtr;
  2357 
  2358 	if ((t1Ptr == &tclIntType) || (t1Ptr == &tclBooleanType)) {
  2359 	    i1 = (valuePtr->internalRep.longValue != 0);
  2360 	} else if (t1Ptr == &tclWideIntType) {
  2361 	    TclGetWide(w,valuePtr);
  2362 	    i1 = (w != W0);
  2363 	} else if (t1Ptr == &tclDoubleType) {
  2364 	    i1 = (valuePtr->internalRep.doubleValue != 0.0);
  2365 	} else {
  2366 	    s = Tcl_GetStringFromObj(valuePtr, &length);
  2367 	    if (TclLooksLikeInt(s, length)) {
  2368 		GET_WIDE_OR_INT(result, valuePtr, i, w);
  2369 		if (valuePtr->typePtr == &tclIntType) {
  2370 		    i1 = (i != 0);
  2371 		} else {
  2372 		    i1 = (w != W0);
  2373 		}
  2374 	    } else {
  2375 		result = Tcl_GetBooleanFromObj((Tcl_Interp *) NULL,
  2376 					       valuePtr, &i1);
  2377 		i1 = (i1 != 0);
  2378 	    }
  2379 	    if (result != TCL_OK) {
  2380 		TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
  2381 		        (t1Ptr? t1Ptr->name : "null")));
  2382 		DECACHE_STACK_INFO();
  2383 		IllegalExprOperandType(interp, pc, valuePtr);
  2384 		CACHE_STACK_INFO();
  2385 		goto checkForCatch;
  2386 	    }
  2387 	}
  2388 		
  2389 	if ((t2Ptr == &tclIntType) || (t2Ptr == &tclBooleanType)) {
  2390 	    i2 = (value2Ptr->internalRep.longValue != 0);
  2391 	} else if (t2Ptr == &tclWideIntType) {
  2392 	    TclGetWide(w,value2Ptr);
  2393 	    i2 = (w != W0);
  2394 	} else if (t2Ptr == &tclDoubleType) {
  2395 	    i2 = (value2Ptr->internalRep.doubleValue != 0.0);
  2396 	} else {
  2397 	    s = Tcl_GetStringFromObj(value2Ptr, &length);
  2398 	    if (TclLooksLikeInt(s, length)) {
  2399 		GET_WIDE_OR_INT(result, value2Ptr, i, w);
  2400 		if (value2Ptr->typePtr == &tclIntType) {
  2401 		    i2 = (i != 0);
  2402 		} else {
  2403 		    i2 = (w != W0);
  2404 		}
  2405 	    } else {
  2406 		result = Tcl_GetBooleanFromObj((Tcl_Interp *) NULL, value2Ptr, &i2);
  2407 	    }
  2408 	    if (result != TCL_OK) {
  2409 		TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(value2Ptr),
  2410 		        (t2Ptr? t2Ptr->name : "null")));
  2411 		DECACHE_STACK_INFO();
  2412 		IllegalExprOperandType(interp, pc, value2Ptr);
  2413 		CACHE_STACK_INFO();
  2414 		goto checkForCatch;
  2415 	    }
  2416 	}
  2417 
  2418 	/*
  2419 	 * Reuse the valuePtr object already on stack if possible.
  2420 	 */
  2421 	
  2422 	if (*pc == INST_LOR) {
  2423 	    iResult = (i1 || i2);
  2424 	} else {
  2425 	    iResult = (i1 && i2);
  2426 	}
  2427 	if (Tcl_IsShared(valuePtr)) {
  2428 	    objResultPtr = Tcl_NewLongObj(iResult);
  2429 	    TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult));
  2430 	    NEXT_INST_F(1, 2, 1);
  2431 	} else {	/* reuse the valuePtr object */
  2432 	    TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult));
  2433 	    Tcl_SetLongObj(valuePtr, iResult);
  2434 	    NEXT_INST_F(1, 1, 0);
  2435 	}
  2436     }
  2437 
  2438     /*
  2439      * ---------------------------------------------------------
  2440      *     Start of INST_LIST and related instructions.
  2441      */
  2442 
  2443     case INST_LIST:
  2444 	/*
  2445 	 * Pop the opnd (objc) top stack elements into a new list obj
  2446 	 * and then decrement their ref counts. 
  2447 	 */
  2448 
  2449 	opnd = TclGetUInt4AtPtr(pc+1);
  2450 	objResultPtr = Tcl_NewListObj(opnd, &(stackPtr[stackTop - (opnd-1)]));
  2451 	TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
  2452 	NEXT_INST_V(5, opnd, 1);
  2453 
  2454     case INST_LIST_LENGTH:
  2455 	valuePtr = stackPtr[stackTop];
  2456 
  2457 	result = Tcl_ListObjLength(interp, valuePtr, &length);
  2458 	if (result != TCL_OK) {
  2459 	    TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
  2460 	            Tcl_GetObjResult(interp));
  2461 	    goto checkForCatch;
  2462 	}
  2463 	objResultPtr = Tcl_NewIntObj(length);
  2464 	TRACE(("%.20s => %d\n", O2S(valuePtr), length));
  2465 	NEXT_INST_F(1, 1, 1);
  2466 	    
  2467     case INST_LIST_INDEX:
  2468 	/*** lindex with objc == 3 ***/
  2469 		
  2470 	/*
  2471 	 * Pop the two operands
  2472 	 */
  2473 	value2Ptr = stackPtr[stackTop];
  2474 	valuePtr  = stackPtr[stackTop- 1];
  2475 
  2476 	/*
  2477 	 * Extract the desired list element
  2478 	 */
  2479 	objResultPtr = TclLindexList(interp, valuePtr, value2Ptr);
  2480 	if (objResultPtr == NULL) {
  2481 	    TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ", O2S(valuePtr), O2S(value2Ptr)),
  2482 	            Tcl_GetObjResult(interp));
  2483 	    result = TCL_ERROR;
  2484 	    goto checkForCatch;
  2485 	}
  2486 
  2487 	/*
  2488 	 * Stash the list element on the stack
  2489 	 */
  2490 	TRACE(("%.20s %.20s => %s\n",
  2491 	        O2S(valuePtr), O2S(value2Ptr), O2S(objResultPtr)));
  2492 	NEXT_INST_F(1, 2, -1); /* already has the correct refCount */
  2493 
  2494     case INST_LIST_INDEX_MULTI:
  2495     {
  2496 	/*
  2497 	 * 'lindex' with multiple index args:
  2498 	 *
  2499 	 * Determine the count of index args.
  2500 	 */
  2501 
  2502 	int numIdx;
  2503 
  2504 	opnd = TclGetUInt4AtPtr(pc+1);
  2505 	numIdx = opnd-1;
  2506 
  2507 	/*
  2508 	 * Do the 'lindex' operation.
  2509 	 */
  2510 	objResultPtr = TclLindexFlat(interp, stackPtr[stackTop - numIdx],
  2511 	        numIdx, stackPtr + stackTop - numIdx + 1);
  2512 
  2513 	/*
  2514 	 * Check for errors
  2515 	 */
  2516 	if (objResultPtr == NULL) {
  2517 	    TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
  2518 	    result = TCL_ERROR;
  2519 	    goto checkForCatch;
  2520 	}
  2521 
  2522 	/*
  2523 	 * Set result
  2524 	 */
  2525 	TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
  2526 	NEXT_INST_V(5, opnd, -1);
  2527     }
  2528 
  2529     case INST_LSET_FLAT:
  2530     {
  2531 	/*
  2532 	 * Lset with 3, 5, or more args.  Get the number
  2533 	 * of index args.
  2534 	 */
  2535 	int numIdx;
  2536 
  2537 	opnd = TclGetUInt4AtPtr( pc + 1 );
  2538 	numIdx = opnd - 2;
  2539 
  2540 	/*
  2541 	 * Get the old value of variable, and remove the stack ref.
  2542 	 * This is safe because the variable still references the
  2543 	 * object; the ref count will never go zero here.
  2544 	 */
  2545 	value2Ptr = POP_OBJECT();
  2546 	TclDecrRefCount(value2Ptr); /* This one should be done here */
  2547 
  2548 	/*
  2549 	 * Get the new element value.
  2550 	 */
  2551 	valuePtr = stackPtr[stackTop];
  2552 
  2553 	/*
  2554 	 * Compute the new variable value
  2555 	 */
  2556 	objResultPtr = TclLsetFlat(interp, value2Ptr, numIdx,
  2557 	        stackPtr + stackTop - numIdx, valuePtr);
  2558 
  2559 
  2560 	/*
  2561 	 * Check for errors
  2562 	 */
  2563 	if (objResultPtr == NULL) {
  2564 	    TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
  2565 	    result = TCL_ERROR;
  2566 	    goto checkForCatch;
  2567 	}
  2568 
  2569 	/*
  2570 	 * Set result
  2571 	 */
  2572 	TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
  2573 	NEXT_INST_V(5, (numIdx+1), -1);
  2574     }
  2575 
  2576     case INST_LSET_LIST:
  2577 	/*
  2578 	 * 'lset' with 4 args.
  2579 	 *
  2580 	 * Get the old value of variable, and remove the stack ref.
  2581 	 * This is safe because the variable still references the
  2582 	 * object; the ref count will never go zero here.
  2583 	 */
  2584 	objPtr = POP_OBJECT(); 
  2585 	TclDecrRefCount(objPtr); /* This one should be done here */
  2586 	
  2587 	/*
  2588 	 * Get the new element value, and the index list
  2589 	 */
  2590 	valuePtr = stackPtr[stackTop];
  2591 	value2Ptr = stackPtr[stackTop - 1];
  2592 	
  2593 	/*
  2594 	 * Compute the new variable value
  2595 	 */
  2596 	objResultPtr = TclLsetList(interp, objPtr, value2Ptr, valuePtr);
  2597 
  2598 	/*
  2599 	 * Check for errors
  2600 	 */
  2601 	if (objResultPtr == NULL) {
  2602 	    TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(value2Ptr)),
  2603 	            Tcl_GetObjResult(interp));
  2604 	    result = TCL_ERROR;
  2605 	    goto checkForCatch;
  2606 	}
  2607 
  2608 	/*
  2609 	 * Set result
  2610 	 */
  2611 	TRACE(("=> %s\n", O2S(objResultPtr)));
  2612 	NEXT_INST_F(1, 2, -1);
  2613 
  2614     /*
  2615      *     End of INST_LIST and related instructions.
  2616      * ---------------------------------------------------------
  2617      */
  2618 
  2619     case INST_STR_EQ:
  2620     case INST_STR_NEQ:
  2621     {
  2622 	/*
  2623 	 * String (in)equality check
  2624 	 */
  2625 	int iResult;
  2626 
  2627 	value2Ptr = stackPtr[stackTop];
  2628 	valuePtr = stackPtr[stackTop - 1];
  2629 
  2630 	if (valuePtr == value2Ptr) {
  2631 	    /*
  2632 	     * On the off-chance that the objects are the same,
  2633 	     * we don't really have to think hard about equality.
  2634 	     */
  2635 	    iResult = (*pc == INST_STR_EQ);
  2636 	} else {
  2637 	    char *s1, *s2;
  2638 	    int s1len, s2len;
  2639 
  2640 	    s1 = Tcl_GetStringFromObj(valuePtr, &s1len);
  2641 	    s2 = Tcl_GetStringFromObj(value2Ptr, &s2len);
  2642 	    if (s1len == s2len) {
  2643 		/*
  2644 		 * We only need to check (in)equality when
  2645 		 * we have equal length strings.
  2646 		 */
  2647 		if (*pc == INST_STR_NEQ) {
  2648 		    iResult = (strcmp(s1, s2) != 0);
  2649 		} else {
  2650 		    /* INST_STR_EQ */
  2651 		    iResult = (strcmp(s1, s2) == 0);
  2652 		}
  2653 	    } else {
  2654 		iResult = (*pc == INST_STR_NEQ);
  2655 	    }
  2656 	}
  2657 
  2658 	TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult));
  2659 
  2660 	/*
  2661 	 * Peep-hole optimisation: if you're about to jump, do jump
  2662 	 * from here.
  2663 	 */
  2664 
  2665 	pc++;
  2666 #ifndef TCL_COMPILE_DEBUG
  2667 	switch (*pc) {
  2668 	    case INST_JUMP_FALSE1:
  2669 		NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
  2670 	    case INST_JUMP_TRUE1:
  2671 		NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
  2672 	    case INST_JUMP_FALSE4:
  2673 		NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
  2674 	    case INST_JUMP_TRUE4:
  2675 		NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
  2676 	}
  2677 #endif
  2678 	objResultPtr = Tcl_NewIntObj(iResult);
  2679 	NEXT_INST_F(0, 2, 1);
  2680     }
  2681 
  2682     case INST_STR_CMP:
  2683     {
  2684 	/*
  2685 	 * String compare
  2686 	 */
  2687 	CONST char *s1, *s2;
  2688 	int s1len, s2len, iResult;
  2689 
  2690 	value2Ptr = stackPtr[stackTop];
  2691 	valuePtr = stackPtr[stackTop - 1];
  2692 
  2693 	/*
  2694 	 * The comparison function should compare up to the
  2695 	 * minimum byte length only.
  2696 	 */
  2697 	if (valuePtr == value2Ptr) {
  2698 	    /*
  2699 	     * In the pure equality case, set lengths too for
  2700 	     * the checks below (or we could goto beyond it).
  2701 	     */
  2702 	    iResult = s1len = s2len = 0;
  2703 	} else if ((valuePtr->typePtr == &tclByteArrayType)
  2704 	        && (value2Ptr->typePtr == &tclByteArrayType)) {
  2705 	    s1 = (char *) Tcl_GetByteArrayFromObj(valuePtr, &s1len);
  2706 	    s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
  2707 	    iResult = memcmp(s1, s2, 
  2708 	            (size_t) ((s1len < s2len) ? s1len : s2len));
  2709 	} else if (((valuePtr->typePtr == &tclStringType)
  2710 	        && (value2Ptr->typePtr == &tclStringType))) {
  2711 	    /*
  2712 	     * Do a unicode-specific comparison if both of the args are of
  2713 	     * String type.  If the char length == byte length, we can do a
  2714 	     * memcmp.  In benchmark testing this proved the most efficient
  2715 	     * check between the unicode and string comparison operations.
  2716 	     */
  2717 
  2718 	    s1len = Tcl_GetCharLength(valuePtr);
  2719 	    s2len = Tcl_GetCharLength(value2Ptr);
  2720 	    if ((s1len == valuePtr->length) && (s2len == value2Ptr->length)) {
  2721 		iResult = memcmp(valuePtr->bytes, value2Ptr->bytes,
  2722 			(unsigned) ((s1len < s2len) ? s1len : s2len));
  2723 	    } else {
  2724 		iResult = TclUniCharNcmp(Tcl_GetUnicode(valuePtr),
  2725 			Tcl_GetUnicode(value2Ptr),
  2726 			(unsigned) ((s1len < s2len) ? s1len : s2len));
  2727 	    }
  2728 	} else {
  2729 	    /*
  2730 	     * We can't do a simple memcmp in order to handle the
  2731 	     * special Tcl \xC0\x80 null encoding for utf-8.
  2732 	     */
  2733 	    s1 = Tcl_GetStringFromObj(valuePtr, &s1len);
  2734 	    s2 = Tcl_GetStringFromObj(value2Ptr, &s2len);
  2735 	    iResult = TclpUtfNcmp2(s1, s2,
  2736 	            (size_t) ((s1len < s2len) ? s1len : s2len));
  2737 	}
  2738 
  2739 	/*
  2740 	 * Make sure only -1,0,1 is returned
  2741 	 */
  2742 	if (iResult == 0) {
  2743 	    iResult = s1len - s2len;
  2744 	}
  2745 	if (iResult < 0) {
  2746 	    iResult = -1;
  2747 	} else if (iResult > 0) {
  2748 	    iResult = 1;
  2749 	}
  2750 
  2751 	objResultPtr = Tcl_NewIntObj(iResult);
  2752 	TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), iResult));
  2753 	NEXT_INST_F(1, 2, 1);
  2754     }
  2755 
  2756     case INST_STR_LEN:
  2757     {
  2758 	int length1;
  2759 		 
  2760 	valuePtr = stackPtr[stackTop];
  2761 
  2762 	if (valuePtr->typePtr == &tclByteArrayType) {
  2763 	    (void) Tcl_GetByteArrayFromObj(valuePtr, &length1);
  2764 	} else {
  2765 	    length1 = Tcl_GetCharLength(valuePtr);
  2766 	}
  2767 	objResultPtr = Tcl_NewIntObj(length1);
  2768 	TRACE(("%.20s => %d\n", O2S(valuePtr), length1));
  2769 	NEXT_INST_F(1, 1, 1);
  2770     }
  2771 	    
  2772     case INST_STR_INDEX:
  2773     {
  2774 	/*
  2775 	 * String compare
  2776 	 */
  2777 	int index;
  2778 	bytes = NULL; /* lint */
  2779 
  2780 	value2Ptr = stackPtr[stackTop];
  2781 	valuePtr = stackPtr[stackTop - 1];
  2782 
  2783 	/*
  2784 	 * If we have a ByteArray object, avoid indexing in the
  2785 	 * Utf string since the byte array contains one byte per
  2786 	 * character.  Otherwise, use the Unicode string rep to
  2787 	 * get the index'th char.
  2788 	 */
  2789 
  2790 	if (valuePtr->typePtr == &tclByteArrayType) {
  2791 	    bytes = (char *)Tcl_GetByteArrayFromObj(valuePtr, &length);
  2792 	} else {
  2793 	    /*
  2794 	     * Get Unicode char length to calulate what 'end' means.
  2795 	     */
  2796 	    length = Tcl_GetCharLength(valuePtr);
  2797 	}
  2798 
  2799 	result = TclGetIntForIndex(interp, value2Ptr, length - 1, &index);
  2800 	if (result != TCL_OK) {
  2801 	    goto checkForCatch;
  2802 	}
  2803 
  2804 	if ((index >= 0) && (index < length)) {
  2805 	    if (valuePtr->typePtr == &tclByteArrayType) {
  2806 		objResultPtr = Tcl_NewByteArrayObj((unsigned char *)
  2807 		        (&bytes[index]), 1);
  2808 	    } else if (valuePtr->bytes && length == valuePtr->length) {
  2809 		objResultPtr = Tcl_NewStringObj((CONST char *)
  2810 		        (&valuePtr->bytes[index]), 1);
  2811 	    } else {
  2812 		char buf[TCL_UTF_MAX];
  2813 		Tcl_UniChar ch;
  2814 
  2815 		ch = Tcl_GetUniChar(valuePtr, index);
  2816 		/*
  2817 		 * This could be:
  2818 		 * Tcl_NewUnicodeObj((CONST Tcl_UniChar *)&ch, 1)
  2819 		 * but creating the object as a string seems to be
  2820 		 * faster in practical use.
  2821 		 */
  2822 		length = Tcl_UniCharToUtf(ch, buf);
  2823 		objResultPtr = Tcl_NewStringObj(buf, length);
  2824 	    }
  2825 	} else {
  2826 	    TclNewObj(objResultPtr);
  2827 	}
  2828 
  2829 	TRACE(("%.20s %.20s => %s\n", O2S(valuePtr), O2S(value2Ptr), 
  2830 	        O2S(objResultPtr)));
  2831 	NEXT_INST_F(1, 2, 1);
  2832     }
  2833 
  2834     case INST_STR_MATCH:
  2835     {
  2836 	int nocase, match;
  2837 
  2838 	nocase    = TclGetInt1AtPtr(pc+1);
  2839 	valuePtr  = stackPtr[stackTop];	        /* String */
  2840 	value2Ptr = stackPtr[stackTop - 1];	/* Pattern */
  2841 
  2842 	/*
  2843 	 * Check that at least one of the objects is Unicode before
  2844 	 * promoting both.
  2845 	 */
  2846 
  2847 	if ((valuePtr->typePtr == &tclStringType)
  2848 	        || (value2Ptr->typePtr == &tclStringType)) {
  2849 	    Tcl_UniChar *ustring1, *ustring2;
  2850 	    int length1, length2;
  2851 
  2852 	    ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length1);
  2853 	    ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2);
  2854 	    match = TclUniCharMatch(ustring1, length1, ustring2, length2,
  2855 		    nocase);
  2856 	} else {
  2857 	    match = Tcl_StringCaseMatch(TclGetString(valuePtr),
  2858 		    TclGetString(value2Ptr), nocase);
  2859 	}
  2860 
  2861 	/*
  2862 	 * Reuse value2Ptr object already on stack if possible.
  2863 	 * Adjustment is 2 due to the nocase byte
  2864 	 */
  2865 
  2866 	TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), match));
  2867 	if (Tcl_IsShared(value2Ptr)) {
  2868 	    objResultPtr = Tcl_NewIntObj(match);
  2869 	    NEXT_INST_F(2, 2, 1);
  2870 	} else {	/* reuse the valuePtr object */
  2871 	    Tcl_SetIntObj(value2Ptr, match);
  2872 	    NEXT_INST_F(2, 1, 0);
  2873 	}
  2874     }
  2875 
  2876     case INST_EQ:
  2877     case INST_NEQ:
  2878     case INST_LT:
  2879     case INST_GT:
  2880     case INST_LE:
  2881     case INST_GE:
  2882     {
  2883 	/*
  2884 	 * Any type is allowed but the two operands must have the
  2885 	 * same type. We will compute value op value2.
  2886 	 */
  2887 
  2888 	Tcl_ObjType *t1Ptr, *t2Ptr;
  2889 	char *s1 = NULL;	/* Init. avoids compiler warning. */
  2890 	char *s2 = NULL;	/* Init. avoids compiler warning. */
  2891 	long i2 = 0;		/* Init. avoids compiler warning. */
  2892 	double d1 = 0.0;	/* Init. avoids compiler warning. */
  2893 	double d2 = 0.0;	/* Init. avoids compiler warning. */
  2894 	long iResult = 0;	/* Init. avoids compiler warning. */
  2895 
  2896 	value2Ptr = stackPtr[stackTop];
  2897 	valuePtr  = stackPtr[stackTop - 1];
  2898 
  2899 	/*
  2900 	 * Be careful in the equal-object case; 'NaN' isn't supposed
  2901 	 * to be equal to even itself. [Bug 761471]
  2902 	 */
  2903 
  2904 	t1Ptr = valuePtr->typePtr;
  2905 	if (valuePtr == value2Ptr) {
  2906 	    /*
  2907 	     * If we are numeric already, we can proceed to the main
  2908 	     * equality check right now.  Otherwise, we need to try to
  2909 	     * coerce to a numeric type so we can see if we've got a
  2910 	     * NaN but haven't parsed it as numeric.
  2911 	     */
  2912 	    if (!IS_NUMERIC_TYPE(t1Ptr)) {
  2913 		if (t1Ptr == &tclListType) {
  2914 		    int length;
  2915 		    /*
  2916 		     * Only a list of length 1 can be NaN or such
  2917 		     * things.
  2918 		     */
  2919 		    (void) Tcl_ListObjLength(NULL, valuePtr, &length);
  2920 		    if (length == 1) {
  2921 			goto mustConvertForNaNCheck;
  2922 		    }
  2923 		} else {
  2924 		    /*
  2925 		     * Too bad, we'll have to compute the string and
  2926 		     * try the conversion
  2927 		     */
  2928 
  2929 		  mustConvertForNaNCheck:
  2930 		    s1 = Tcl_GetStringFromObj(valuePtr, &length);
  2931 		    if (TclLooksLikeInt(s1, length)) {
  2932 			GET_WIDE_OR_INT(iResult, valuePtr, i, w);
  2933 		    } else {
  2934 			(void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  2935 				valuePtr, &d1);
  2936 		    }
  2937 		    t1Ptr = valuePtr->typePtr;
  2938 		}
  2939 	    }
  2940 
  2941 	    switch (*pc) {
  2942 	    case INST_EQ:
  2943 	    case INST_LE:
  2944 	    case INST_GE:
  2945 		iResult = !((t1Ptr == &tclDoubleType)
  2946 			&& IS_NAN(valuePtr->internalRep.doubleValue));
  2947 		break;
  2948 	    case INST_LT:
  2949 	    case INST_GT:
  2950 		iResult = 0;
  2951 		break;
  2952 	    case INST_NEQ:
  2953 		iResult = ((t1Ptr == &tclDoubleType)
  2954 			&& IS_NAN(valuePtr->internalRep.doubleValue));
  2955 		break;
  2956 	    }
  2957 	    goto foundResult;
  2958 	}
  2959 
  2960 	t2Ptr = value2Ptr->typePtr;
  2961 
  2962 	/*
  2963 	 * We only want to coerce numeric validation if neither type
  2964 	 * is NULL.  A NULL type means the arg is essentially an empty
  2965 	 * object ("", {} or [list]).
  2966 	 */
  2967 	if (!(     (!t1Ptr && !valuePtr->bytes)
  2968 	        || (valuePtr->bytes && !valuePtr->length)
  2969 		   || (!t2Ptr && !value2Ptr->bytes)
  2970 		   || (value2Ptr->bytes && !value2Ptr->length))) {
  2971 	    if (!IS_NUMERIC_TYPE(t1Ptr)) {
  2972 		s1 = Tcl_GetStringFromObj(valuePtr, &length);
  2973 		if (TclLooksLikeInt(s1, length)) {
  2974 		    GET_WIDE_OR_INT(iResult, valuePtr, i, w);
  2975 		} else {
  2976 		    (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, 
  2977 		            valuePtr, &d1);
  2978 		}
  2979 		t1Ptr = valuePtr->typePtr;
  2980 	    }
  2981 	    if (!IS_NUMERIC_TYPE(t2Ptr)) {
  2982 		s2 = Tcl_GetStringFromObj(value2Ptr, &length);
  2983 		if (TclLooksLikeInt(s2, length)) {
  2984 		    GET_WIDE_OR_INT(iResult, value2Ptr, i2, w);
  2985 		} else {
  2986 		    (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  2987 		            value2Ptr, &d2);
  2988 		}
  2989 		t2Ptr = value2Ptr->typePtr;
  2990 	    }
  2991 	}
  2992 	if (!IS_NUMERIC_TYPE(t1Ptr) || !IS_NUMERIC_TYPE(t2Ptr)) {
  2993 	    /*
  2994 	     * One operand is not numeric. Compare as strings.  NOTE:
  2995 	     * strcmp is not correct for \x00 < \x01, but that is
  2996 	     * unlikely to occur here.  We could use the TclUtfNCmp2
  2997 	     * to handle this.
  2998 	     */
  2999 	    int s1len, s2len;
  3000 	    s1 = Tcl_GetStringFromObj(valuePtr, &s1len);
  3001 	    s2 = Tcl_GetStringFromObj(value2Ptr, &s2len);
  3002 	    switch (*pc) {
  3003 	        case INST_EQ:
  3004 		    if (s1len == s2len) {
  3005 			iResult = (strcmp(s1, s2) == 0);
  3006 		    } else {
  3007 			iResult = 0;
  3008 		    }
  3009 		    break;
  3010 	        case INST_NEQ:
  3011 		    if (s1len == s2len) {
  3012 			iResult = (strcmp(s1, s2) != 0);
  3013 		    } else {
  3014 			iResult = 1;
  3015 		    }
  3016 		    break;
  3017 	        case INST_LT:
  3018 		    iResult = (strcmp(s1, s2) < 0);
  3019 		    break;
  3020 	        case INST_GT:
  3021 		    iResult = (strcmp(s1, s2) > 0);
  3022 		    break;
  3023 	        case INST_LE:
  3024 		    iResult = (strcmp(s1, s2) <= 0);
  3025 		    break;
  3026 	        case INST_GE:
  3027 		    iResult = (strcmp(s1, s2) >= 0);
  3028 		    break;
  3029 	    }
  3030 	} else if ((t1Ptr == &tclDoubleType)
  3031 		   || (t2Ptr == &tclDoubleType)) {
  3032 	    /*
  3033 	     * Compare as doubles.
  3034 	     */
  3035 	    if (t1Ptr == &tclDoubleType) {
  3036 		d1 = valuePtr->internalRep.doubleValue;
  3037 		GET_DOUBLE_VALUE(d2, value2Ptr, t2Ptr);
  3038 	    } else {	/* t1Ptr is integer, t2Ptr is double */
  3039 		GET_DOUBLE_VALUE(d1, valuePtr, t1Ptr);
  3040 		d2 = value2Ptr->internalRep.doubleValue;
  3041 	    }
  3042 	    switch (*pc) {
  3043 	        case INST_EQ:
  3044 		    iResult = d1 == d2;
  3045 		    break;
  3046 	        case INST_NEQ:
  3047 		    iResult = d1 != d2;
  3048 		    break;
  3049 	        case INST_LT:
  3050 		    iResult = d1 < d2;
  3051 		    break;
  3052 	        case INST_GT:
  3053 		    iResult = d1 > d2;
  3054 		    break;
  3055 	        case INST_LE:
  3056 		    iResult = d1 <= d2;
  3057 		    break;
  3058 	        case INST_GE:
  3059 		    iResult = d1 >= d2;
  3060 		    break;
  3061 	    }
  3062 	} else if ((t1Ptr == &tclWideIntType)
  3063 	        || (t2Ptr == &tclWideIntType)) {
  3064 	    Tcl_WideInt w2;
  3065 	    /*
  3066 	     * Compare as wide ints (neither are doubles)
  3067 	     */
  3068 	    if (t1Ptr == &tclIntType) {
  3069 		w  = Tcl_LongAsWide(valuePtr->internalRep.longValue);
  3070 		TclGetWide(w2,value2Ptr);
  3071 	    } else if (t2Ptr == &tclIntType) {
  3072 		TclGetWide(w,valuePtr);
  3073 		w2 = Tcl_LongAsWide(value2Ptr->internalRep.longValue);
  3074 	    } else {
  3075 		TclGetWide(w,valuePtr);
  3076 		TclGetWide(w2,value2Ptr);
  3077 	    }
  3078 	    switch (*pc) {
  3079 	        case INST_EQ:
  3080 		    iResult = w == w2;
  3081 		    break;
  3082 	        case INST_NEQ:
  3083 		    iResult = w != w2;
  3084 		    break;
  3085 	        case INST_LT:
  3086 		    iResult = w < w2;
  3087 		    break;
  3088 	        case INST_GT:
  3089 		    iResult = w > w2;
  3090 		    break;
  3091 	        case INST_LE:
  3092 		    iResult = w <= w2;
  3093 		    break;
  3094 	        case INST_GE:
  3095 		    iResult = w >= w2;
  3096 		    break;
  3097 	    }
  3098 	} else {
  3099 	    /*
  3100 	     * Compare as ints.
  3101 	     */
  3102 	    i  = valuePtr->internalRep.longValue;
  3103 	    i2 = value2Ptr->internalRep.longValue;
  3104 	    switch (*pc) {
  3105 	        case INST_EQ:
  3106 		    iResult = i == i2;
  3107 		    break;
  3108 	        case INST_NEQ:
  3109 		    iResult = i != i2;
  3110 		    break;
  3111 	        case INST_LT:
  3112 		    iResult = i < i2;
  3113 		    break;
  3114 	        case INST_GT:
  3115 		    iResult = i > i2;
  3116 		    break;
  3117 	        case INST_LE:
  3118 		    iResult = i <= i2;
  3119 		    break;
  3120 	        case INST_GE:
  3121 		    iResult = i >= i2;
  3122 		    break;
  3123 	    }
  3124 	}
  3125 
  3126     foundResult:
  3127 	TRACE(("%.20s %.20s => %ld\n", O2S(valuePtr), O2S(value2Ptr), iResult));
  3128 
  3129 	/*
  3130 	 * Peep-hole optimisation: if you're about to jump, do jump
  3131 	 * from here.
  3132 	 */
  3133 
  3134 	pc++;
  3135 #ifndef TCL_COMPILE_DEBUG
  3136 	switch (*pc) {
  3137 	    case INST_JUMP_FALSE1:
  3138 		NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
  3139 	    case INST_JUMP_TRUE1:
  3140 		NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
  3141 	    case INST_JUMP_FALSE4:
  3142 		NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
  3143 	    case INST_JUMP_TRUE4:
  3144 		NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
  3145 	}
  3146 #endif
  3147 	objResultPtr = Tcl_NewIntObj(iResult);
  3148 	NEXT_INST_F(0, 2, 1);
  3149     }
  3150 
  3151     case INST_MOD:
  3152     case INST_LSHIFT:
  3153     case INST_RSHIFT:
  3154     case INST_BITOR:
  3155     case INST_BITXOR:
  3156     case INST_BITAND:
  3157     {
  3158 	/*
  3159 	 * Only integers are allowed. We compute value op value2.
  3160 	 */
  3161 
  3162 	long i2 = 0, rem, negative;
  3163 	long iResult = 0; /* Init. avoids compiler warning. */
  3164 	Tcl_WideInt w2, wResult = W0;
  3165 	int doWide = 0;
  3166 
  3167 	value2Ptr = stackPtr[stackTop];
  3168 	valuePtr  = stackPtr[stackTop - 1]; 
  3169 	if (valuePtr->typePtr == &tclIntType) {
  3170 	    i = valuePtr->internalRep.longValue;
  3171 	} else if (valuePtr->typePtr == &tclWideIntType) {
  3172 	    TclGetWide(w,valuePtr);
  3173 	} else {	/* try to convert to int */
  3174 	    REQUIRE_WIDE_OR_INT(result, valuePtr, i, w);
  3175 	    if (result != TCL_OK) {
  3176 		TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n",
  3177 		        O2S(valuePtr), O2S(value2Ptr), 
  3178 		        (valuePtr->typePtr? 
  3179 			     valuePtr->typePtr->name : "null")));
  3180 		DECACHE_STACK_INFO();
  3181 		IllegalExprOperandType(interp, pc, valuePtr);
  3182 		CACHE_STACK_INFO();
  3183 		goto checkForCatch;
  3184 	    }
  3185 	}
  3186 	if (value2Ptr->typePtr == &tclIntType) {
  3187 	    i2 = value2Ptr->internalRep.longValue;
  3188 	} else if (value2Ptr->typePtr == &tclWideIntType) {
  3189 	    TclGetWide(w2,value2Ptr);
  3190 	} else {
  3191 	    REQUIRE_WIDE_OR_INT(result, value2Ptr, i2, w2);
  3192 	    if (result != TCL_OK) {
  3193 		TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n",
  3194 		        O2S(valuePtr), O2S(value2Ptr),
  3195 		        (value2Ptr->typePtr?
  3196 			    value2Ptr->typePtr->name : "null")));
  3197 		DECACHE_STACK_INFO();
  3198 		IllegalExprOperandType(interp, pc, value2Ptr);
  3199 		CACHE_STACK_INFO();
  3200 		goto checkForCatch;
  3201 	    }
  3202 	}
  3203 
  3204 	switch (*pc) {
  3205 	case INST_MOD:
  3206 	    /*
  3207 	     * This code is tricky: C doesn't guarantee much about
  3208 	     * the quotient or remainder, but Tcl does. The
  3209 	     * remainder always has the same sign as the divisor and
  3210 	     * a smaller absolute value.
  3211 	     */
  3212 	    if (value2Ptr->typePtr == &tclWideIntType && w2 == W0) {
  3213 		if (valuePtr->typePtr == &tclIntType) {
  3214 		    TRACE(("%ld "LLD" => DIVIDE BY ZERO\n", i, w2));
  3215 		} else {
  3216 		    TRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2));
  3217 		}
  3218 		goto divideByZero;
  3219 	    }
  3220 	    if (value2Ptr->typePtr == &tclIntType && i2 == 0) {
  3221 		if (valuePtr->typePtr == &tclIntType) {
  3222 		    TRACE(("%ld %ld => DIVIDE BY ZERO\n", i, i2));
  3223 		} else {
  3224 		    TRACE((LLD" %ld => DIVIDE BY ZERO\n", w, i2));
  3225 		}
  3226 		goto divideByZero;
  3227 	    }
  3228 	    negative = 0;
  3229 	    if (valuePtr->typePtr == &tclWideIntType
  3230 		|| value2Ptr->typePtr == &tclWideIntType) {
  3231 		Tcl_WideInt wRemainder;
  3232 		/*
  3233 		 * Promote to wide
  3234 		 */
  3235 		if (valuePtr->typePtr == &tclIntType) {
  3236 		    w = Tcl_LongAsWide(i);
  3237 		} else if (value2Ptr->typePtr == &tclIntType) {
  3238 		    w2 = Tcl_LongAsWide(i2);
  3239 		}
  3240 		if (w2 < 0) {
  3241 		    w2 = -w2;
  3242 		    w = -w;
  3243 		    negative = 1;
  3244 		}
  3245 		wRemainder  = w % w2;
  3246 		if (wRemainder < 0) {
  3247 		    wRemainder += w2;
  3248 		}
  3249 		if (negative) {
  3250 		    wRemainder = -wRemainder;
  3251 		}
  3252 		wResult = wRemainder;
  3253 		doWide = 1;
  3254 		break;
  3255 	    }
  3256 	    if (i2 < 0) {
  3257 		i2 = -i2;
  3258 		i = -i;
  3259 		negative = 1;
  3260 	    }
  3261 	    rem  = i % i2;
  3262 	    if (rem < 0) {
  3263 		rem += i2;
  3264 	    }
  3265 	    if (negative) {
  3266 		rem = -rem;
  3267 	    }
  3268 	    iResult = rem;
  3269 	    break;
  3270 	case INST_LSHIFT:
  3271 	    /*
  3272 	     * Shifts are never usefully 64-bits wide!
  3273 	     */
  3274 	    FORCE_LONG(value2Ptr, i2, w2);
  3275 	    if (valuePtr->typePtr == &tclWideIntType) {
  3276 #ifdef TCL_COMPILE_DEBUG
  3277 		w2 = Tcl_LongAsWide(i2);
  3278 #endif /* TCL_COMPILE_DEBUG */
  3279 		wResult = w;
  3280 		/*
  3281 		 * Shift in steps when the shift gets large to prevent
  3282 		 * annoying compiler/processor bugs. [Bug 868467]
  3283 		 */
  3284 		if (i2 >= 64) {
  3285 		    wResult = Tcl_LongAsWide(0);
  3286 		} else if (i2 > 60) {
  3287 		    wResult = w << 30;
  3288 		    wResult <<= 30;
  3289 		    wResult <<= i2-60;
  3290 		} else if (i2 > 30) {
  3291 		    wResult = w << 30;
  3292 		    wResult <<= i2-30;
  3293 		} else {
  3294 		    wResult = w << i2;
  3295 		}
  3296 		doWide = 1;
  3297 		break;
  3298 	    }
  3299 	    /*
  3300 	     * Shift in steps when the shift gets large to prevent
  3301 	     * annoying compiler/processor bugs. [Bug 868467]
  3302 	     */
  3303 	    if (i2 >= 64) {
  3304 		iResult = 0;
  3305 	    } else if (i2 > 60) {
  3306 		iResult = i << 30;
  3307 		iResult <<= 30;
  3308 		iResult <<= i2-60;
  3309 	    } else if (i2 > 30) {
  3310 		iResult = i << 30;
  3311 		iResult <<= i2-30;
  3312 	    } else {
  3313 		iResult = i << i2;
  3314 	    }
  3315 	    break;
  3316 	case INST_RSHIFT:
  3317 	    /*
  3318 	     * The following code is a bit tricky: it ensures that
  3319 	     * right shifts propagate the sign bit even on machines
  3320 	     * where ">>" won't do it by default.
  3321 	     */
  3322 	    /*
  3323 	     * Shifts are never usefully 64-bits wide!
  3324 	     */
  3325 	    FORCE_LONG(value2Ptr, i2, w2);
  3326 	    if (valuePtr->typePtr == &tclWideIntType) {
  3327 #ifdef TCL_COMPILE_DEBUG
  3328 		w2 = Tcl_LongAsWide(i2);
  3329 #endif /* TCL_COMPILE_DEBUG */
  3330 		if (w < 0) {
  3331 		    wResult = ~w;
  3332 		} else {
  3333 		    wResult = w;
  3334 		}
  3335 		/*
  3336 		 * Shift in steps when the shift gets large to prevent
  3337 		 * annoying compiler/processor bugs. [Bug 868467]
  3338 		 */
  3339 		if (i2 >= 64) {
  3340 		    wResult = Tcl_LongAsWide(0);
  3341 		} else if (i2 > 60) {
  3342 		    wResult >>= 30;
  3343 		    wResult >>= 30;
  3344 		    wResult >>= i2-60;
  3345 		} else if (i2 > 30) {
  3346 		    wResult >>= 30;
  3347 		    wResult >>= i2-30;
  3348 		} else {
  3349 		    wResult >>= i2;
  3350 		}
  3351 		if (w < 0) {
  3352 		    wResult = ~wResult;
  3353 		}
  3354 		doWide = 1;
  3355 		break;
  3356 	    }
  3357 	    if (i < 0) {
  3358 		iResult = ~i;
  3359 	    } else {
  3360 		iResult = i;
  3361 	    }
  3362 	    /*
  3363 	     * Shift in steps when the shift gets large to prevent
  3364 	     * annoying compiler/processor bugs. [Bug 868467]
  3365 	     */
  3366 	    if (i2 >= 64) {
  3367 		iResult = 0;
  3368 	    } else if (i2 > 60) {
  3369 		iResult >>= 30;
  3370 		iResult >>= 30;
  3371 		iResult >>= i2-60;
  3372 	    } else if (i2 > 30) {
  3373 		iResult >>= 30;
  3374 		iResult >>= i2-30;
  3375 	    } else {
  3376 		iResult >>= i2;
  3377 	    }
  3378 	    if (i < 0) {
  3379 		iResult = ~iResult;
  3380 	    }
  3381 	    break;
  3382 	case INST_BITOR:
  3383 	    if (valuePtr->typePtr == &tclWideIntType
  3384 		|| value2Ptr->typePtr == &tclWideIntType) {
  3385 		/*
  3386 		 * Promote to wide
  3387 		 */
  3388 		if (valuePtr->typePtr == &tclIntType) {
  3389 		    w = Tcl_LongAsWide(i);
  3390 		} else if (value2Ptr->typePtr == &tclIntType) {
  3391 		    w2 = Tcl_LongAsWide(i2);
  3392 		}
  3393 		wResult = w | w2;
  3394 		doWide = 1;
  3395 		break;
  3396 	    }
  3397 	    iResult = i | i2;
  3398 	    break;
  3399 	case INST_BITXOR:
  3400 	    if (valuePtr->typePtr == &tclWideIntType
  3401 		|| value2Ptr->typePtr == &tclWideIntType) {
  3402 		/*
  3403 		 * Promote to wide
  3404 		 */
  3405 		if (valuePtr->typePtr == &tclIntType) {
  3406 		    w = Tcl_LongAsWide(i);
  3407 		} else if (value2Ptr->typePtr == &tclIntType) {
  3408 		    w2 = Tcl_LongAsWide(i2);
  3409 		}
  3410 		wResult = w ^ w2;
  3411 		doWide = 1;
  3412 		break;
  3413 	    }
  3414 	    iResult = i ^ i2;
  3415 	    break;
  3416 	case INST_BITAND:
  3417 	    if (valuePtr->typePtr == &tclWideIntType
  3418 		|| value2Ptr->typePtr == &tclWideIntType) {
  3419 		/*
  3420 		 * Promote to wide
  3421 		 */
  3422 		if (valuePtr->typePtr == &tclIntType) {
  3423 		    w = Tcl_LongAsWide(i);
  3424 		} else if (value2Ptr->typePtr == &tclIntType) {
  3425 		    w2 = Tcl_LongAsWide(i2);
  3426 		}
  3427 		wResult = w & w2;
  3428 		doWide = 1;
  3429 		break;
  3430 	    }
  3431 	    iResult = i & i2;
  3432 	    break;
  3433 	}
  3434 
  3435 	/*
  3436 	 * Reuse the valuePtr object already on stack if possible.
  3437 	 */
  3438 		
  3439 	if (Tcl_IsShared(valuePtr)) {
  3440 	    if (doWide) {
  3441 		objResultPtr = Tcl_NewWideIntObj(wResult);
  3442 		TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult));
  3443 	    } else {
  3444 		objResultPtr = Tcl_NewLongObj(iResult);
  3445 		TRACE(("%ld %ld => %ld\n", i, i2, iResult));
  3446 	    }
  3447 	    NEXT_INST_F(1, 2, 1);
  3448 	} else {	/* reuse the valuePtr object */
  3449 	    if (doWide) {
  3450 		TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult));
  3451 		Tcl_SetWideIntObj(valuePtr, wResult);
  3452 	    } else {
  3453 		TRACE(("%ld %ld => %ld\n", i, i2, iResult));
  3454 		Tcl_SetLongObj(valuePtr, iResult);
  3455 	    }
  3456 	    NEXT_INST_F(1, 1, 0);
  3457 	}
  3458     }
  3459 
  3460     case INST_ADD:
  3461     case INST_SUB:
  3462     case INST_MULT:
  3463     case INST_DIV:
  3464     {
  3465 	/*
  3466 	 * Operands must be numeric and ints get converted to floats
  3467 	 * if necessary. We compute value op value2.
  3468 	 */
  3469 
  3470 	Tcl_ObjType *t1Ptr, *t2Ptr;
  3471 	long i2 = 0, quot, rem;	/* Init. avoids compiler warning. */
  3472 	double d1, d2;
  3473 	long iResult = 0;	/* Init. avoids compiler warning. */
  3474 	double dResult = 0.0;	/* Init. avoids compiler warning. */
  3475 	int doDouble = 0;	/* 1 if doing floating arithmetic */
  3476 	Tcl_WideInt w2, wquot, wrem;
  3477 	Tcl_WideInt wResult = W0; /* Init. avoids compiler warning. */
  3478 	int doWide = 0;		/* 1 if doing wide arithmetic. */
  3479 
  3480 	value2Ptr = stackPtr[stackTop];
  3481 	valuePtr  = stackPtr[stackTop - 1];
  3482 	t1Ptr = valuePtr->typePtr;
  3483 	t2Ptr = value2Ptr->typePtr;
  3484 		
  3485 	if (t1Ptr == &tclIntType) {
  3486 	    i = valuePtr->internalRep.longValue;
  3487 	} else if (t1Ptr == &tclWideIntType) {
  3488 	    TclGetWide(w,valuePtr);
  3489 	} else if ((t1Ptr == &tclDoubleType)
  3490 		   && (valuePtr->bytes == NULL)) {
  3491 	    /*
  3492 	     * We can only use the internal rep directly if there is
  3493 	     * no string rep.  Otherwise the string rep might actually
  3494 	     * look like an integer, which is preferred.
  3495 	     */
  3496 
  3497 	    d1 = valuePtr->internalRep.doubleValue;
  3498 	} else {
  3499 	    char *s = Tcl_GetStringFromObj(valuePtr, &length);
  3500 	    if (TclLooksLikeInt(s, length)) {
  3501 		GET_WIDE_OR_INT(result, valuePtr, i, w);
  3502 	    } else {
  3503 		result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  3504 					      valuePtr, &d1);
  3505 	    }
  3506 	    if (result != TCL_OK) {
  3507 		TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n",
  3508 		        s, O2S(valuePtr),
  3509 		        (valuePtr->typePtr?
  3510 			    valuePtr->typePtr->name : "null")));
  3511 		DECACHE_STACK_INFO();
  3512 		IllegalExprOperandType(interp, pc, valuePtr);
  3513 		CACHE_STACK_INFO();
  3514 		goto checkForCatch;
  3515 	    }
  3516 	    t1Ptr = valuePtr->typePtr;
  3517 	}
  3518 
  3519 	if (t2Ptr == &tclIntType) {
  3520 	    i2 = value2Ptr->internalRep.longValue;
  3521 	} else if (t2Ptr == &tclWideIntType) {
  3522 	    TclGetWide(w2,value2Ptr);
  3523 	} else if ((t2Ptr == &tclDoubleType)
  3524 		   && (value2Ptr->bytes == NULL)) {
  3525 	    /*
  3526 	     * We can only use the internal rep directly if there is
  3527 	     * no string rep.  Otherwise the string rep might actually
  3528 	     * look like an integer, which is preferred.
  3529 	     */
  3530 
  3531 	    d2 = value2Ptr->internalRep.doubleValue;
  3532 	} else {
  3533 	    char *s = Tcl_GetStringFromObj(value2Ptr, &length);
  3534 	    if (TclLooksLikeInt(s, length)) {
  3535 		GET_WIDE_OR_INT(result, value2Ptr, i2, w2);
  3536 	    } else {
  3537 		result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  3538 		        value2Ptr, &d2);
  3539 	    }
  3540 	    if (result != TCL_OK) {
  3541 		TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n",
  3542 		        O2S(value2Ptr), s,
  3543 		        (value2Ptr->typePtr?
  3544 			    value2Ptr->typePtr->name : "null")));
  3545 		DECACHE_STACK_INFO();
  3546 		IllegalExprOperandType(interp, pc, value2Ptr);
  3547 		CACHE_STACK_INFO();
  3548 		goto checkForCatch;
  3549 	    }
  3550 	    t2Ptr = value2Ptr->typePtr;
  3551 	}
  3552 
  3553 	if ((t1Ptr == &tclDoubleType) || (t2Ptr == &tclDoubleType)) {
  3554 	    /*
  3555 	     * Do double arithmetic.
  3556 	     */
  3557 	    doDouble = 1;
  3558 	    if (t1Ptr == &tclIntType) {
  3559 		d1 = i;       /* promote value 1 to double */
  3560 	    } else if (t2Ptr == &tclIntType) {
  3561 		d2 = i2;      /* promote value 2 to double */
  3562 	    } else if (t1Ptr == &tclWideIntType) {
  3563 		d1 = Tcl_WideAsDouble(w);
  3564 	    } else if (t2Ptr == &tclWideIntType) {
  3565 		d2 = Tcl_WideAsDouble(w2);
  3566 	    }
  3567 	    switch (*pc) {
  3568 	        case INST_ADD:
  3569 		    dResult = d1 + d2;
  3570 		    break;
  3571 	        case INST_SUB:
  3572 		    dResult = d1 - d2;
  3573 		    break;
  3574 	        case INST_MULT:
  3575 		    dResult = d1 * d2;
  3576 		    break;
  3577 	        case INST_DIV:
  3578 		    if (d2 == 0.0) {
  3579 			TRACE(("%.6g %.6g => DIVIDE BY ZERO\n", d1, d2));
  3580 			goto divideByZero;
  3581 		    }
  3582 		    dResult = d1 / d2;
  3583 		    break;
  3584 	    }
  3585 		    
  3586 	    /*
  3587 	     * Check now for IEEE floating-point error.
  3588 	     */
  3589 		    
  3590 	    if (IS_NAN(dResult) || IS_INF(dResult)) {
  3591 		TRACE(("%.20s %.20s => IEEE FLOATING PT ERROR\n",
  3592 		        O2S(valuePtr), O2S(value2Ptr)));
  3593 		DECACHE_STACK_INFO();
  3594 		TclExprFloatError(interp, dResult);
  3595 		CACHE_STACK_INFO();
  3596 		result = TCL_ERROR;
  3597 		goto checkForCatch;
  3598 	    }
  3599 	} else if ((t1Ptr == &tclWideIntType) 
  3600 		   || (t2Ptr == &tclWideIntType)) {
  3601 	    /*
  3602 	     * Do wide integer arithmetic.
  3603 	     */
  3604 	    doWide = 1;
  3605 	    if (t1Ptr == &tclIntType) {
  3606 		w = Tcl_LongAsWide(i);
  3607 	    } else if (t2Ptr == &tclIntType) {
  3608 		w2 = Tcl_LongAsWide(i2);
  3609 	    }
  3610 	    switch (*pc) {
  3611 	        case INST_ADD:
  3612 		    wResult = w + w2;
  3613 		    break;
  3614 	        case INST_SUB:
  3615 		    wResult = w - w2;
  3616 		    break;
  3617 	        case INST_MULT:
  3618 		    wResult = w * w2;
  3619 		    break;
  3620 	        case INST_DIV:
  3621 		    /*
  3622 		     * This code is tricky: C doesn't guarantee much
  3623 		     * about the quotient or remainder, but Tcl does.
  3624 		     * The remainder always has the same sign as the
  3625 		     * divisor and a smaller absolute value.
  3626 		     */
  3627 		    if (w2 == W0) {
  3628 			TRACE((LLD" "LLD" => DIVIDE BY ZERO\n", w, w2));
  3629 			goto divideByZero;
  3630 		    }
  3631 		    if (w2 < 0) {
  3632 			w2 = -w2;
  3633 			w = -w;
  3634 		    }
  3635 		    wquot = w / w2;
  3636 		    wrem  = w % w2;
  3637 		    if (wrem < W0) {
  3638 			wquot -= 1;
  3639 		    }
  3640 		    wResult = wquot;
  3641 		    break;
  3642 	    }
  3643 	} else {
  3644 	    /*
  3645 		     * Do integer arithmetic.
  3646 		     */
  3647 	    switch (*pc) {
  3648 	        case INST_ADD:
  3649 		    iResult = i + i2;
  3650 		    break;
  3651 	        case INST_SUB:
  3652 		    iResult = i - i2;
  3653 		    break;
  3654 	        case INST_MULT:
  3655 		    iResult = i * i2;
  3656 		    break;
  3657 	        case INST_DIV:
  3658 		    /*
  3659 		     * This code is tricky: C doesn't guarantee much
  3660 		     * about the quotient or remainder, but Tcl does.
  3661 		     * The remainder always has the same sign as the
  3662 		     * divisor and a smaller absolute value.
  3663 		     */
  3664 		    if (i2 == 0) {
  3665 			TRACE(("%ld %ld => DIVIDE BY ZERO\n", i, i2));
  3666 			goto divideByZero;
  3667 		    }
  3668 		    if (i2 < 0) {
  3669 			i2 = -i2;
  3670 			i = -i;
  3671 		    }
  3672 		    quot = i / i2;
  3673 		    rem  = i % i2;
  3674 		    if (rem < 0) {
  3675 			quot -= 1;
  3676 		    }
  3677 		    iResult = quot;
  3678 		    break;
  3679 	    }
  3680 	}
  3681 
  3682 	/*
  3683 	 * Reuse the valuePtr object already on stack if possible.
  3684 	 */
  3685 		
  3686 	if (Tcl_IsShared(valuePtr)) {
  3687 	    if (doDouble) {
  3688 		objResultPtr = Tcl_NewDoubleObj(dResult);
  3689 		TRACE(("%.6g %.6g => %.6g\n", d1, d2, dResult));
  3690 	    } else if (doWide) {
  3691 		objResultPtr = Tcl_NewWideIntObj(wResult);
  3692 		TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult));
  3693 	    } else {
  3694 		objResultPtr = Tcl_NewLongObj(iResult);
  3695 		TRACE(("%ld %ld => %ld\n", i, i2, iResult));
  3696 	    } 
  3697 	    NEXT_INST_F(1, 2, 1);
  3698 	} else {	    /* reuse the valuePtr object */
  3699 	    if (doDouble) { /* NB: stack top is off by 1 */
  3700 		TRACE(("%.6g %.6g => %.6g\n", d1, d2, dResult));
  3701 		Tcl_SetDoubleObj(valuePtr, dResult);
  3702 	    } else if (doWide) {
  3703 		TRACE((LLD" "LLD" => "LLD"\n", w, w2, wResult));
  3704 		Tcl_SetWideIntObj(valuePtr, wResult);
  3705 	    } else {
  3706 		TRACE(("%ld %ld => %ld\n", i, i2, iResult));
  3707 		Tcl_SetLongObj(valuePtr, iResult);
  3708 	    }
  3709 	    NEXT_INST_F(1, 1, 0);
  3710 	}
  3711     }
  3712 
  3713     case INST_UPLUS:
  3714     {
  3715 	/*
  3716 	 * Operand must be numeric.
  3717 	 */
  3718 
  3719 	double d;
  3720 	Tcl_ObjType *tPtr;
  3721 		
  3722 	valuePtr = stackPtr[stackTop];
  3723 	tPtr = valuePtr->typePtr;
  3724 	if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType) 
  3725                 || (valuePtr->bytes != NULL))) {
  3726 	    char *s = Tcl_GetStringFromObj(valuePtr, &length);
  3727 	    if (TclLooksLikeInt(s, length)) {
  3728 		GET_WIDE_OR_INT(result, valuePtr, i, w);
  3729 	    } else {
  3730 		result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d);
  3731 	    }
  3732 	    if (result != TCL_OK) { 
  3733 		TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n",
  3734 		        s, (tPtr? tPtr->name : "null")));
  3735 		DECACHE_STACK_INFO();
  3736 		IllegalExprOperandType(interp, pc, valuePtr);
  3737 		CACHE_STACK_INFO();
  3738 		goto checkForCatch;
  3739 	    }
  3740 	    tPtr = valuePtr->typePtr;
  3741 	}
  3742 
  3743 	/*
  3744 	 * Ensure that the operand's string rep is the same as the
  3745 	 * formatted version of its internal rep. This makes sure
  3746 	 * that "expr +000123" yields "83", not "000123". We
  3747 	 * implement this by _discarding_ the string rep since we
  3748 	 * know it will be regenerated, if needed later, by
  3749 	 * formatting the internal rep's value.
  3750 	 */
  3751 
  3752 	if (Tcl_IsShared(valuePtr)) {
  3753 	    if (tPtr == &tclIntType) {
  3754 		i = valuePtr->internalRep.longValue;
  3755 		objResultPtr = Tcl_NewLongObj(i);
  3756 	    } else if (tPtr == &tclWideIntType) {
  3757 		TclGetWide(w,valuePtr);
  3758 		objResultPtr = Tcl_NewWideIntObj(w);
  3759 	    } else {
  3760 		d = valuePtr->internalRep.doubleValue;
  3761 		objResultPtr = Tcl_NewDoubleObj(d);
  3762 	    }
  3763 	    TRACE_WITH_OBJ(("%s => ", O2S(objResultPtr)), objResultPtr);
  3764 	    NEXT_INST_F(1, 1, 1);
  3765 	} else {
  3766 	    Tcl_InvalidateStringRep(valuePtr);
  3767 	    TRACE_WITH_OBJ(("%s => ", O2S(valuePtr)), valuePtr);
  3768 	    NEXT_INST_F(1, 0, 0);
  3769 	}
  3770     }
  3771 	    
  3772     case INST_UMINUS:
  3773     case INST_LNOT:
  3774     {
  3775 	/*
  3776 	 * The operand must be numeric or a boolean string as
  3777 	 * accepted by Tcl_GetBooleanFromObj(). If the operand
  3778 	 * object is unshared modify it directly, otherwise
  3779 	 * create a copy to modify: this is "copy on write".
  3780 	 * Free any old string representation since it is now
  3781 	 * invalid.
  3782 	 */
  3783 
  3784 	double d;
  3785 	int boolvar;
  3786 	Tcl_ObjType *tPtr;
  3787 
  3788 	valuePtr = stackPtr[stackTop];
  3789 	tPtr = valuePtr->typePtr;
  3790 	if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType)
  3791 	        || (valuePtr->bytes != NULL))) {
  3792 	    if ((tPtr == &tclBooleanType) && (valuePtr->bytes == NULL)) {
  3793 		valuePtr->typePtr = &tclIntType;
  3794 	    } else {
  3795 		char *s = Tcl_GetStringFromObj(valuePtr, &length);
  3796 		if (TclLooksLikeInt(s, length)) {
  3797 		    GET_WIDE_OR_INT(result, valuePtr, i, w);
  3798 		} else {
  3799 		    result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  3800 		            valuePtr, &d);
  3801 		}
  3802 		if (result == TCL_ERROR && *pc == INST_LNOT) {
  3803 		    result = Tcl_GetBooleanFromObj((Tcl_Interp *)NULL,
  3804 		            valuePtr, &boolvar);
  3805 		    i = (long)boolvar; /* i is long, not int! */
  3806 		}
  3807 		if (result != TCL_OK) {
  3808 		    TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n",
  3809 		            s, (tPtr? tPtr->name : "null")));
  3810 		    DECACHE_STACK_INFO();
  3811 		    IllegalExprOperandType(interp, pc, valuePtr);
  3812 		    CACHE_STACK_INFO();
  3813 		    goto checkForCatch;
  3814 		}
  3815 	    }
  3816 	    tPtr = valuePtr->typePtr;
  3817 	}
  3818 
  3819 	if (Tcl_IsShared(valuePtr)) {
  3820 	    /*
  3821 	     * Create a new object.
  3822 	     */
  3823 	    if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) {
  3824 		i = valuePtr->internalRep.longValue;
  3825 		objResultPtr = Tcl_NewLongObj(
  3826 		    (*pc == INST_UMINUS)? -i : !i);
  3827 		TRACE_WITH_OBJ(("%ld => ", i), objResultPtr);
  3828 	    } else if (tPtr == &tclWideIntType) {
  3829 		TclGetWide(w,valuePtr);
  3830 		if (*pc == INST_UMINUS) {
  3831 		    objResultPtr = Tcl_NewWideIntObj(-w);
  3832 		} else {
  3833 		    objResultPtr = Tcl_NewLongObj(w == W0);
  3834 		}
  3835 		TRACE_WITH_OBJ((LLD" => ", w), objResultPtr);
  3836 	    } else {
  3837 		d = valuePtr->internalRep.doubleValue;
  3838 		if (*pc == INST_UMINUS) {
  3839 		    objResultPtr = Tcl_NewDoubleObj(-d);
  3840 		} else {
  3841 		    /*
  3842 		     * Should be able to use "!d", but apparently
  3843 		     * some compilers can't handle it.
  3844 		     */
  3845 		    objResultPtr = Tcl_NewLongObj((d==0.0)? 1 : 0);
  3846 		}
  3847 		TRACE_WITH_OBJ(("%.6g => ", d), objResultPtr);
  3848 	    }
  3849 	    NEXT_INST_F(1, 1, 1);
  3850 	} else {
  3851 	    /*
  3852 	     * valuePtr is unshared. Modify it directly.
  3853 	     */
  3854 	    if ((tPtr == &tclIntType) || (tPtr == &tclBooleanType)) {
  3855 		i = valuePtr->internalRep.longValue;
  3856 		Tcl_SetLongObj(valuePtr,
  3857 	                (*pc == INST_UMINUS)? -i : !i);
  3858 		TRACE_WITH_OBJ(("%ld => ", i), valuePtr);
  3859 	    } else if (tPtr == &tclWideIntType) {
  3860 		TclGetWide(w,valuePtr);
  3861 		if (*pc == INST_UMINUS) {
  3862 		    Tcl_SetWideIntObj(valuePtr, -w);
  3863 		} else {
  3864 		    Tcl_SetLongObj(valuePtr, w == W0);
  3865 		}
  3866 		TRACE_WITH_OBJ((LLD" => ", w), valuePtr);
  3867 	    } else {
  3868 		d = valuePtr->internalRep.doubleValue;
  3869 		if (*pc == INST_UMINUS) {
  3870 		    Tcl_SetDoubleObj(valuePtr, -d);
  3871 		} else {
  3872 		    /*
  3873 		     * Should be able to use "!d", but apparently
  3874 		     * some compilers can't handle it.
  3875 		     */
  3876 		    Tcl_SetLongObj(valuePtr, (d==0.0)? 1 : 0);
  3877 		}
  3878 		TRACE_WITH_OBJ(("%.6g => ", d), valuePtr);
  3879 	    }
  3880 	    NEXT_INST_F(1, 0, 0);
  3881 	}
  3882     }
  3883 
  3884     case INST_BITNOT:
  3885     {
  3886 	/*
  3887 	 * The operand must be an integer. If the operand object is
  3888 	 * unshared modify it directly, otherwise modify a copy. 
  3889 	 * Free any old string representation since it is now
  3890 	 * invalid.
  3891 	 */
  3892 		
  3893 	Tcl_ObjType *tPtr;
  3894 		
  3895 	valuePtr = stackPtr[stackTop];
  3896 	tPtr = valuePtr->typePtr;
  3897 	if (!IS_INTEGER_TYPE(tPtr)) {
  3898 	    REQUIRE_WIDE_OR_INT(result, valuePtr, i, w);
  3899 	    if (result != TCL_OK) {   /* try to convert to double */
  3900 		TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n",
  3901 		        O2S(valuePtr), (tPtr? tPtr->name : "null")));
  3902 		DECACHE_STACK_INFO();
  3903 		IllegalExprOperandType(interp, pc, valuePtr);
  3904 		CACHE_STACK_INFO();
  3905 		goto checkForCatch;
  3906 	    }
  3907 	}
  3908 		
  3909 	if (valuePtr->typePtr == &tclWideIntType) {
  3910 	    TclGetWide(w,valuePtr);
  3911 	    if (Tcl_IsShared(valuePtr)) {
  3912 		objResultPtr = Tcl_NewWideIntObj(~w);
  3913 		TRACE(("0x%llx => (%llu)\n", w, ~w));
  3914 		NEXT_INST_F(1, 1, 1);
  3915 	    } else {
  3916 		/*
  3917 		 * valuePtr is unshared. Modify it directly.
  3918 		 */
  3919 		Tcl_SetWideIntObj(valuePtr, ~w);
  3920 		TRACE(("0x%llx => (%llu)\n", w, ~w));
  3921 		NEXT_INST_F(1, 0, 0);
  3922 	    }
  3923 	} else {
  3924 	    i = valuePtr->internalRep.longValue;
  3925 	    if (Tcl_IsShared(valuePtr)) {
  3926 		objResultPtr = Tcl_NewLongObj(~i);
  3927 		TRACE(("0x%lx => (%lu)\n", i, ~i));
  3928 		NEXT_INST_F(1, 1, 1);
  3929 	    } else {
  3930 		/*
  3931 		 * valuePtr is unshared. Modify it directly.
  3932 		 */
  3933 		Tcl_SetLongObj(valuePtr, ~i);
  3934 		TRACE(("0x%lx => (%lu)\n", i, ~i));
  3935 		NEXT_INST_F(1, 0, 0);
  3936 	    }
  3937 	}
  3938     }
  3939 
  3940     case INST_CALL_BUILTIN_FUNC1:
  3941 	opnd = TclGetUInt1AtPtr(pc+1);
  3942 	{
  3943 	    /*
  3944 	     * Call one of the built-in Tcl math functions.
  3945 	     */
  3946 
  3947 	    BuiltinFunc *mathFuncPtr;
  3948 
  3949 	    if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) {
  3950 		TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %d\n", opnd));
  3951 		panic("TclExecuteByteCode: unrecognized builtin function code %d", opnd);
  3952 	    }
  3953 	    mathFuncPtr = &(tclBuiltinFuncTable[opnd]);
  3954 	    DECACHE_STACK_INFO();
  3955 	    result = (*mathFuncPtr->proc)(interp, eePtr,
  3956 	            mathFuncPtr->clientData);
  3957 	    CACHE_STACK_INFO();
  3958 	    if (result != TCL_OK) {
  3959 		goto checkForCatch;
  3960 	    }
  3961 	    TRACE_WITH_OBJ(("%d => ", opnd), stackPtr[stackTop]);
  3962 	}
  3963 	NEXT_INST_F(2, 0, 0);
  3964 		    
  3965     case INST_CALL_FUNC1:
  3966 	opnd = TclGetUInt1AtPtr(pc+1);
  3967 	{
  3968 	    /*
  3969 	     * Call a non-builtin Tcl math function previously
  3970 	     * registered by a call to Tcl_CreateMathFunc.
  3971 	     */
  3972 		
  3973 	    int objc = opnd;   /* Number of arguments. The function name
  3974 				* is the 0-th argument. */
  3975 	    Tcl_Obj **objv;    /* The array of arguments. The function
  3976 				* name is objv[0]. */
  3977 
  3978 	    objv = &(stackPtr[stackTop - (objc-1)]); /* "objv[0]" */
  3979 	    DECACHE_STACK_INFO();
  3980 	    result = ExprCallMathFunc(interp, eePtr, objc, objv);
  3981 	    CACHE_STACK_INFO();
  3982 	    if (result != TCL_OK) {
  3983 		goto checkForCatch;
  3984 	    }
  3985 	    TRACE_WITH_OBJ(("%d => ", objc), stackPtr[stackTop]);
  3986 	}
  3987 	NEXT_INST_F(2, 0, 0);
  3988 
  3989     case INST_TRY_CVT_TO_NUMERIC:
  3990     {
  3991 	/*
  3992 	 * Try to convert the topmost stack object to an int or
  3993 	 * double object. This is done in order to support Tcl's
  3994 	 * policy of interpreting operands if at all possible as
  3995 	 * first integers, else floating-point numbers.
  3996 	 */
  3997 		
  3998 	double d;
  3999 	char *s;
  4000 	Tcl_ObjType *tPtr;
  4001 	int converted, needNew;
  4002 
  4003 	valuePtr = stackPtr[stackTop];
  4004 	tPtr = valuePtr->typePtr;
  4005 	converted = 0;
  4006 	if (!IS_INTEGER_TYPE(tPtr) && ((tPtr != &tclDoubleType)
  4007 	        || (valuePtr->bytes != NULL))) {
  4008 	    if ((tPtr == &tclBooleanType) && (valuePtr->bytes == NULL)) {
  4009 		valuePtr->typePtr = &tclIntType;
  4010 		converted = 1;
  4011 	    } else {
  4012 		s = Tcl_GetStringFromObj(valuePtr, &length);
  4013 		if (TclLooksLikeInt(s, length)) {
  4014 		    GET_WIDE_OR_INT(result, valuePtr, i, w);
  4015 		} else {
  4016 		    result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
  4017 		            valuePtr, &d);
  4018 		}
  4019 		if (result == TCL_OK) {
  4020 		    converted = 1;
  4021 		}
  4022 		result = TCL_OK; /* reset the result variable */
  4023 	    }
  4024 	    tPtr = valuePtr->typePtr;
  4025 	}
  4026 
  4027 	/*
  4028 	 * Ensure that the topmost stack object, if numeric, has a
  4029 	 * string rep the same as the formatted version of its
  4030 	 * internal rep. This is used, e.g., to make sure that "expr
  4031 	 * {0001}" yields "1", not "0001". We implement this by
  4032 	 * _discarding_ the string rep since we know it will be
  4033 	 * regenerated, if needed later, by formatting the internal
  4034 	 * rep's value. Also check if there has been an IEEE
  4035 	 * floating point error.
  4036 	 */
  4037 	
  4038 	objResultPtr = valuePtr;
  4039 	needNew = 0;
  4040 	if (IS_NUMERIC_TYPE(tPtr)) {
  4041 	    if (Tcl_IsShared(valuePtr)) {
  4042 		if (valuePtr->bytes != NULL) {
  4043 		    /*
  4044 		     * We only need to make a copy of the object
  4045 		     * when it already had a string rep
  4046 		     */
  4047 		    needNew = 1;
  4048 		    if (tPtr == &tclIntType) {
  4049 			i = valuePtr->internalRep.longValue;
  4050 			objResultPtr = Tcl_NewLongObj(i);
  4051 		    } else if (tPtr == &tclWideIntType) {
  4052 			TclGetWide(w,valuePtr);
  4053 			objResultPtr = Tcl_NewWideIntObj(w);
  4054 		    } else {
  4055 			d = valuePtr->internalRep.doubleValue;
  4056 			objResultPtr = Tcl_NewDoubleObj(d);
  4057 		    }
  4058 		    tPtr = objResultPtr->typePtr;
  4059 		}
  4060 	    } else {
  4061 		Tcl_InvalidateStringRep(valuePtr);
  4062 	    }
  4063 		
  4064 	    if (tPtr == &tclDoubleType) {
  4065 		d = objResultPtr->internalRep.doubleValue;
  4066 		if (IS_NAN(d) || IS_INF(d)) {
  4067 		    TRACE(("\"%.20s\" => IEEE FLOATING PT ERROR\n",
  4068 		            O2S(objResultPtr)));
  4069 		    DECACHE_STACK_INFO();
  4070 		    TclExprFloatError(interp, d);
  4071 		    CACHE_STACK_INFO();
  4072 		    result = TCL_ERROR;
  4073 		    goto checkForCatch;
  4074 		}
  4075 	    }
  4076 	    converted = converted;  /* lint, converted not used. */
  4077 	    TRACE(("\"%.20s\" => numeric, %s, %s\n", O2S(valuePtr),
  4078 	            (converted? "converted" : "not converted"),
  4079 		    (needNew? "new Tcl_Obj" : "same Tcl_Obj")));
  4080 	} else {
  4081 	    TRACE(("\"%.20s\" => not numeric\n", O2S(valuePtr)));
  4082 	}
  4083 	if (needNew) {
  4084 	    NEXT_INST_F(1, 1, 1);
  4085 	} else {
  4086 	    NEXT_INST_F(1, 0, 0);
  4087 	}
  4088     }
  4089 	
  4090     case INST_BREAK:
  4091 	DECACHE_STACK_INFO();
  4092 	Tcl_ResetResult(interp);
  4093 	CACHE_STACK_INFO();
  4094 	result = TCL_BREAK;
  4095 	cleanup = 0;
  4096 	goto processExceptionReturn;
  4097 
  4098     case INST_CONTINUE:
  4099 	DECACHE_STACK_INFO();
  4100 	Tcl_ResetResult(interp);
  4101 	CACHE_STACK_INFO();
  4102 	result = TCL_CONTINUE;
  4103 	cleanup = 0;
  4104 	goto processExceptionReturn;
  4105 
  4106     case INST_FOREACH_START4:
  4107 	opnd = TclGetUInt4AtPtr(pc+1);
  4108 	{
  4109 	    /*
  4110 	     * Initialize the temporary local var that holds the count
  4111 	     * of the number of iterations of the loop body to -1.
  4112 	     */
  4113 
  4114 	    ForeachInfo *infoPtr = (ForeachInfo *)
  4115 	            codePtr->auxDataArrayPtr[opnd].clientData;
  4116 	    int iterTmpIndex = infoPtr->loopCtTemp;
  4117 	    Var *compiledLocals = iPtr->varFramePtr->compiledLocals;
  4118 	    Var *iterVarPtr = &(compiledLocals[iterTmpIndex]);
  4119 	    Tcl_Obj *oldValuePtr = iterVarPtr->value.objPtr;
  4120 
  4121 	    if (oldValuePtr == NULL) {
  4122 		iterVarPtr->value.objPtr = Tcl_NewLongObj(-1);
  4123 		Tcl_IncrRefCount(iterVarPtr->value.objPtr);
  4124 	    } else {
  4125 		Tcl_SetLongObj(oldValuePtr, -1);
  4126 	    }
  4127 	    TclSetVarScalar(iterVarPtr);
  4128 	    TclClearVarUndefined(iterVarPtr);
  4129 	    TRACE(("%u => loop iter count temp %d\n", 
  4130 		   opnd, iterTmpIndex));
  4131 	}
  4132 	    
  4133 #ifndef TCL_COMPILE_DEBUG
  4134 	/* 
  4135 	 * Remark that the compiler ALWAYS sets INST_FOREACH_STEP4
  4136 	 * immediately after INST_FOREACH_START4 - let us just fall
  4137 	 * through instead of jumping back to the top.
  4138 	 */
  4139 
  4140 	pc += 5;
  4141 #else
  4142 	NEXT_INST_F(5, 0, 0);
  4143 #endif	
  4144     case INST_FOREACH_STEP4:
  4145 	opnd = TclGetUInt4AtPtr(pc+1);
  4146 	{
  4147 	    /*
  4148 	     * "Step" a foreach loop (i.e., begin its next iteration) by
  4149 	     * assigning the next value list element to each loop var.
  4150 	     */
  4151 
  4152 	    ForeachInfo *infoPtr = (ForeachInfo *)
  4153 	            codePtr->auxDataArrayPtr[opnd].clientData;
  4154 	    ForeachVarList *varListPtr;
  4155 	    int numLists = infoPtr->numLists;
  4156 	    Var *compiledLocals = iPtr->varFramePtr->compiledLocals;
  4157 	    Tcl_Obj *listPtr;
  4158 	    Var *iterVarPtr, *listVarPtr;
  4159 	    int iterNum, listTmpIndex, listLen, numVars;
  4160 	    int varIndex, valIndex, continueLoop, j;
  4161 
  4162 	    /*
  4163 	     * Increment the temp holding the loop iteration number.
  4164 	     */
  4165 
  4166 	    iterVarPtr = &(compiledLocals[infoPtr->loopCtTemp]);
  4167 	    valuePtr = iterVarPtr->value.objPtr;
  4168 	    iterNum = (valuePtr->internalRep.longValue + 1);
  4169 	    Tcl_SetLongObj(valuePtr, iterNum);
  4170 		
  4171 	    /*
  4172 	     * Check whether all value lists are exhausted and we should
  4173 	     * stop the loop.
  4174 	     */
  4175 
  4176 	    continueLoop = 0;
  4177 	    listTmpIndex = infoPtr->firstValueTemp;
  4178 	    for (i = 0;  i < numLists;  i++) {
  4179 		varListPtr = infoPtr->varLists[i];
  4180 		numVars = varListPtr->numVars;
  4181 		    
  4182 		listVarPtr = &(compiledLocals[listTmpIndex]);
  4183 		listPtr = listVarPtr->value.objPtr;
  4184 		result = Tcl_ListObjLength(interp, listPtr, &listLen);
  4185 		if (result != TCL_OK) {
  4186 		    TRACE_WITH_OBJ(("%u => ERROR converting list %ld, \"%s\": ",
  4187 		            opnd, i, O2S(listPtr)), Tcl_GetObjResult(interp));
  4188 		    goto checkForCatch;
  4189 		}
  4190 		if (listLen > (iterNum * numVars)) {
  4191 		    continueLoop = 1;
  4192 		}
  4193 		listTmpIndex++;
  4194 	    }
  4195 
  4196 	    /*
  4197 	     * If some var in some var list still has a remaining list
  4198 	     * element iterate one more time. Assign to var the next
  4199 	     * element from its value list. We already checked above
  4200 	     * that each list temp holds a valid list object.
  4201 	     */
  4202 		
  4203 	    if (continueLoop) {
  4204 		listTmpIndex = infoPtr->firstValueTemp;
  4205 		for (i = 0;  i < numLists;  i++) {
  4206 		    varListPtr = infoPtr->varLists[i];
  4207 		    numVars = varListPtr->numVars;
  4208 
  4209 		    listVarPtr = &(compiledLocals[listTmpIndex]);
  4210 		    listPtr = listVarPtr->value.objPtr;
  4211 
  4212 		    valIndex = (iterNum * numVars);
  4213 		    for (j = 0;  j < numVars;  j++) {
  4214 			Tcl_Obj **elements;
  4215 
  4216 			/*
  4217 			 * The call to TclPtrSetVar might shimmer listPtr,
  4218 			 * so re-fetch pointers every iteration for safety.
  4219 			 * See test foreach-10.1.
  4220 			 */
  4221 
  4222 			Tcl_ListObjGetElements(NULL, listPtr,
  4223 				&listLen, &elements);
  4224 			if (valIndex >= listLen) {
  4225 			    TclNewObj(valuePtr);
  4226 			} else {
  4227 			    valuePtr = elements[valIndex];
  4228 			}
  4229 			    
  4230 			varIndex = varListPtr->varIndexes[j];
  4231 			varPtr = &(varFramePtr->compiledLocals[varIndex]);
  4232 			part1 = varPtr->name;
  4233 			while (TclIsVarLink(varPtr)) {
  4234 			    varPtr = varPtr->value.linkPtr;
  4235 			}
  4236 			if (!((varPtr->flags & VAR_IN_HASHTABLE) && (varPtr->hPtr == NULL))
  4237 			        && (varPtr->tracePtr == NULL)
  4238 			        && (TclIsVarScalar(varPtr) || TclIsVarUndefined(varPtr))) {
  4239 			    value2Ptr = varPtr->value.objPtr;
  4240 			    if (valuePtr != value2Ptr) {
  4241 				if (value2Ptr != NULL) {
  4242 				    TclDecrRefCount(value2Ptr);
  4243 				} else {
  4244 				    TclSetVarScalar(varPtr);
  4245 				    TclClearVarUndefined(varPtr);
  4246 				}
  4247 				varPtr->value.objPtr = valuePtr;
  4248 				Tcl_IncrRefCount(valuePtr);
  4249 			    }
  4250 			} else {
  4251 			    DECACHE_STACK_INFO();
  4252 			    Tcl_IncrRefCount(valuePtr);
  4253 			    value2Ptr = TclPtrSetVar(interp, varPtr, NULL, part1, 
  4254 						     NULL, valuePtr, TCL_LEAVE_ERR_MSG);
  4255 			    TclDecrRefCount(valuePtr);
  4256 			    CACHE_STACK_INFO();
  4257 			    if (value2Ptr == NULL) {
  4258 				TRACE_WITH_OBJ(("%u => ERROR init. index temp %d: ",
  4259 						opnd, varIndex),
  4260 					       Tcl_GetObjResult(interp));
  4261 				result = TCL_ERROR;
  4262 				goto checkForCatch;
  4263 			    }
  4264 			}
  4265 			valIndex++;
  4266 		    }
  4267 		    listTmpIndex++;
  4268 		}
  4269 	    }
  4270 	    TRACE(("%u => %d lists, iter %d, %s loop\n", opnd, numLists, 
  4271 	            iterNum, (continueLoop? "continue" : "exit")));
  4272 
  4273 	    /* 
  4274 	     * Run-time peep-hole optimisation: the compiler ALWAYS follows
  4275 	     * INST_FOREACH_STEP4 with an INST_JUMP_FALSE. We just skip that
  4276 	     * instruction and jump direct from here.
  4277 	     */
  4278 
  4279 	    pc += 5;
  4280 	    if (*pc == INST_JUMP_FALSE1) {
  4281 		NEXT_INST_F((continueLoop? 2 : TclGetInt1AtPtr(pc+1)), 0, 0);
  4282 	    } else {
  4283 		NEXT_INST_F((continueLoop? 5 : TclGetInt4AtPtr(pc+1)), 0, 0);
  4284 	    }
  4285 	}
  4286 
  4287     case INST_BEGIN_CATCH4:
  4288 	/*
  4289 	 * Record start of the catch command with exception range index
  4290 	 * equal to the operand. Push the current stack depth onto the
  4291 	 * special catch stack.
  4292 	 */
  4293 	catchStackPtr[++catchTop] = stackTop;
  4294 	TRACE(("%u => catchTop=%d, stackTop=%d\n",
  4295 	       TclGetUInt4AtPtr(pc+1), catchTop, stackTop));
  4296 	NEXT_INST_F(5, 0, 0);
  4297 
  4298     case INST_END_CATCH:
  4299 	catchTop--;
  4300 	result = TCL_OK;
  4301 	TRACE(("=> catchTop=%d\n", catchTop));
  4302 	NEXT_INST_F(1, 0, 0);
  4303 	    
  4304     case INST_PUSH_RESULT:
  4305 	objResultPtr = Tcl_GetObjResult(interp);
  4306 	TRACE_WITH_OBJ(("=> "), Tcl_GetObjResult(interp));
  4307 
  4308 	/*
  4309 	 * See the comments at INST_INVOKE_STK
  4310 	 */
  4311 	{
  4312 	    Tcl_Obj *newObjResultPtr;
  4313 	    TclNewObj(newObjResultPtr);
  4314 	    Tcl_IncrRefCount(newObjResultPtr);
  4315 	    iPtr->objResultPtr = newObjResultPtr;
  4316 	}
  4317 
  4318 	NEXT_INST_F(1, 0, -1);
  4319 
  4320     case INST_PUSH_RETURN_CODE:
  4321 	objResultPtr = Tcl_NewLongObj(result);
  4322 	TRACE(("=> %u\n", result));
  4323 	NEXT_INST_F(1, 0, 1);
  4324 
  4325     default:
  4326 	panic("TclExecuteByteCode: unrecognized opCode %u", *pc);
  4327     } /* end of switch on opCode */
  4328 
  4329     /*
  4330      * Division by zero in an expression. Control only reaches this
  4331      * point by "goto divideByZero".
  4332      */
  4333 	
  4334  divideByZero:
  4335     DECACHE_STACK_INFO();
  4336     Tcl_ResetResult(interp);
  4337     Tcl_AppendToObj(Tcl_GetObjResult(interp), "divide by zero", -1);
  4338     Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero",
  4339             (char *) NULL);
  4340     CACHE_STACK_INFO();
  4341 
  4342     result = TCL_ERROR;
  4343     goto checkForCatch;
  4344 	
  4345     /*
  4346      * An external evaluation (INST_INVOKE or INST_EVAL) returned 
  4347      * something different from TCL_OK, or else INST_BREAK or 
  4348      * INST_CONTINUE were called.
  4349      */
  4350 
  4351  processExceptionReturn:
  4352 #if TCL_COMPILE_DEBUG    
  4353     switch (*pc) {
  4354         case INST_INVOKE_STK1:
  4355         case INST_INVOKE_STK4:
  4356 	    TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
  4357 	    break;
  4358         case INST_EVAL_STK:
  4359 	    /*
  4360 	     * Note that the object at stacktop has to be used
  4361 	     * before doing the cleanup.
  4362 	     */
  4363 
  4364 	    TRACE(("\"%.30s\" => ", O2S(stackPtr[stackTop])));
  4365 	    break;
  4366         default:
  4367 	    TRACE(("=> "));
  4368     }		    
  4369 #endif	   
  4370     if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
  4371 	rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 0, codePtr);
  4372 	if (rangePtr == NULL) {
  4373 	    TRACE_APPEND(("no encl. loop or catch, returning %s\n",
  4374 	            StringForResultCode(result)));
  4375 	    goto abnormalReturn;
  4376 	} 
  4377 	if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
  4378 	    TRACE_APPEND(("%s ...\n", StringForResultCode(result)));
  4379 	    goto processCatch;
  4380 	}
  4381 	while (cleanup--) {
  4382 	    valuePtr = POP_OBJECT();
  4383 	    TclDecrRefCount(valuePtr);
  4384 	}
  4385 	if (result == TCL_BREAK) {
  4386 	    result = TCL_OK;
  4387 	    pc = (codePtr->codeStart + rangePtr->breakOffset);
  4388 	    TRACE_APPEND(("%s, range at %d, new pc %d\n",
  4389 		   StringForResultCode(result),
  4390 		   rangePtr->codeOffset, rangePtr->breakOffset));
  4391 	    NEXT_INST_F(0, 0, 0);
  4392 	} else {
  4393 	    if (rangePtr->continueOffset == -1) {
  4394 		TRACE_APPEND(("%s, loop w/o continue, checking for catch\n",
  4395 		        StringForResultCode(result)));
  4396 		goto checkForCatch;
  4397 	    } 
  4398 	    result = TCL_OK;
  4399 	    pc = (codePtr->codeStart + rangePtr->continueOffset);
  4400 	    TRACE_APPEND(("%s, range at %d, new pc %d\n",
  4401 		   StringForResultCode(result),
  4402 		   rangePtr->codeOffset, rangePtr->continueOffset));
  4403 	    NEXT_INST_F(0, 0, 0);
  4404 	}
  4405 #if TCL_COMPILE_DEBUG    
  4406     } else if (traceInstructions) {
  4407 	if ((result != TCL_ERROR) && (result != TCL_RETURN))  {
  4408 	    objPtr = Tcl_GetObjResult(interp);
  4409 	    TRACE_APPEND(("OTHER RETURN CODE %d, result= \"%s\"\n ", 
  4410 		    result, O2S(objPtr)));
  4411 	} else {
  4412 	    objPtr = Tcl_GetObjResult(interp);
  4413 	    TRACE_APPEND(("%s, result= \"%s\"\n", 
  4414 	            StringForResultCode(result), O2S(objPtr)));
  4415 	}
  4416 #endif
  4417     }
  4418 	    	
  4419     /*
  4420      * Execution has generated an "exception" such as TCL_ERROR. If the
  4421      * exception is an error, record information about what was being
  4422      * executed when the error occurred. Find the closest enclosing
  4423      * catch range, if any. If no enclosing catch range is found, stop
  4424      * execution and return the "exception" code.
  4425      */
  4426 	
  4427  checkForCatch:
  4428     if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
  4429 	bytes = GetSrcInfoForPc(pc, codePtr, &length);
  4430 	if (bytes != NULL) {
  4431 	    DECACHE_STACK_INFO();
  4432 	    Tcl_LogCommandInfo(interp, codePtr->source, bytes, length);
  4433             CACHE_STACK_INFO();
  4434 	    iPtr->flags |= ERR_ALREADY_LOGGED;
  4435 	}
  4436     }
  4437     if (catchTop == -1) {
  4438 #ifdef TCL_COMPILE_DEBUG
  4439 	if (traceInstructions) {
  4440 	    fprintf(stdout, "   ... no enclosing catch, returning %s\n",
  4441 	            StringForResultCode(result));
  4442 	}
  4443 #endif
  4444 	goto abnormalReturn;
  4445     }
  4446     rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 1, codePtr);
  4447     if (rangePtr == NULL) {
  4448 	/*
  4449 	 * This is only possible when compiling a [catch] that sends its
  4450 	 * script to INST_EVAL. Cannot correct the compiler without 
  4451 	 * breakingcompat with previous .tbc compiled scripts.
  4452 	 */
  4453 #ifdef TCL_COMPILE_DEBUG
  4454 	if (traceInstructions) {
  4455 	    fprintf(stdout, "   ... no enclosing catch, returning %s\n",
  4456 	            StringForResultCode(result));
  4457 	}
  4458 #endif
  4459 	goto abnormalReturn;
  4460     }
  4461 
  4462     /*
  4463      * A catch exception range (rangePtr) was found to handle an
  4464      * "exception". It was found either by checkForCatch just above or
  4465      * by an instruction during break, continue, or error processing.
  4466      * Jump to its catchOffset after unwinding the operand stack to
  4467      * the depth it had when starting to execute the range's catch
  4468      * command.
  4469      */
  4470 
  4471  processCatch:
  4472     while (stackTop > catchStackPtr[catchTop]) {
  4473 	valuePtr = POP_OBJECT();
  4474 	TclDecrRefCount(valuePtr);
  4475     }
  4476 #ifdef TCL_COMPILE_DEBUG
  4477     if (traceInstructions) {
  4478 	fprintf(stdout, "  ... found catch at %d, catchTop=%d, unwound to %d, new pc %u\n",
  4479 	        rangePtr->codeOffset, catchTop, catchStackPtr[catchTop],
  4480 	        (unsigned int)(rangePtr->catchOffset));
  4481     }
  4482 #endif	
  4483     pc = (codePtr->codeStart + rangePtr->catchOffset);
  4484     NEXT_INST_F(0, 0, 0); /* restart the execution loop at pc */
  4485 
  4486     /* 
  4487      * end of infinite loop dispatching on instructions.
  4488      */
  4489 
  4490     /*
  4491      * Abnormal return code. Restore the stack to state it had when starting
  4492      * to execute the ByteCode. Panic if the stack is below the initial level.
  4493      */
  4494 
  4495  abnormalReturn:
  4496     while (stackTop > initStackTop) {
  4497 	valuePtr = POP_OBJECT();
  4498 	TclDecrRefCount(valuePtr);
  4499     }
  4500     if (stackTop < initStackTop) {
  4501 	fprintf(stderr, "\nTclExecuteByteCode: abnormal return at pc %u: stack top %d < entry stack top %d\n",
  4502 	        (unsigned int)(pc - codePtr->codeStart),
  4503 		(unsigned int) stackTop,
  4504 		(unsigned int) initStackTop);
  4505 	panic("TclExecuteByteCode execution failure: end stack top < start stack top");
  4506     }
  4507 	
  4508     /*
  4509      * Free the catch stack array if malloc'ed storage was used.
  4510      */
  4511 
  4512     if (catchStackPtr != catchStackStorage) {
  4513 	ckfree((char *) catchStackPtr);
  4514     }
  4515     eePtr->stackTop = initStackTop;
  4516     return result;
  4517 #undef STATIC_CATCH_STACK_SIZE
  4518 }
  4519 
  4520 #ifdef TCL_COMPILE_DEBUG
  4521 /*
  4522  *----------------------------------------------------------------------
  4523  *
  4524  * PrintByteCodeInfo --
  4525  *
  4526  *	This procedure prints a summary about a bytecode object to stdout.
  4527  *	It is called by TclExecuteByteCode when starting to execute the
  4528  *	bytecode object if tclTraceExec has the value 2 or more.
  4529  *
  4530  * Results:
  4531  *	None.
  4532  *
  4533  * Side effects:
  4534  *	None.
  4535  *
  4536  *----------------------------------------------------------------------
  4537  */
  4538 
  4539 static void
  4540 PrintByteCodeInfo(codePtr)
  4541     register ByteCode *codePtr;	/* The bytecode whose summary is printed
  4542 				 * to stdout. */
  4543 {
  4544     Proc *procPtr = codePtr->procPtr;
  4545     Interp *iPtr = (Interp *) *codePtr->interpHandle;
  4546 
  4547     fprintf(stdout, "\nExecuting ByteCode 0x%x, refCt %u, epoch %u, interp 0x%x (epoch %u)\n",
  4548 	    (unsigned int) codePtr, codePtr->refCount,
  4549 	    codePtr->compileEpoch, (unsigned int) iPtr,
  4550 	    iPtr->compileEpoch);
  4551     
  4552     fprintf(stdout, "  Source: ");
  4553     TclPrintSource(stdout, codePtr->source, 60);
  4554 
  4555     fprintf(stdout, "\n  Cmds %d, src %d, inst %u, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n",
  4556             codePtr->numCommands, codePtr->numSrcBytes,
  4557 	    codePtr->numCodeBytes, codePtr->numLitObjects,
  4558 	    codePtr->numAuxDataItems, codePtr->maxStackDepth,
  4559 #ifdef TCL_COMPILE_STATS
  4560 	    (codePtr->numSrcBytes?
  4561 	            ((float)codePtr->structureSize)/((float)codePtr->numSrcBytes) : 0.0));
  4562 #else
  4563 	    0.0);
  4564 #endif
  4565 #ifdef TCL_COMPILE_STATS
  4566     fprintf(stdout, "  Code %d = header %d+inst %d+litObj %d+exc %d+aux %d+cmdMap %d\n",
  4567 	    codePtr->structureSize,
  4568 	    (sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time))),
  4569 	    codePtr->numCodeBytes,
  4570 	    (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
  4571 	    (codePtr->numExceptRanges * sizeof(ExceptionRange)),
  4572 	    (codePtr->numAuxDataItems * sizeof(AuxData)),
  4573 	    codePtr->numCmdLocBytes);
  4574 #endif /* TCL_COMPILE_STATS */
  4575     if (procPtr != NULL) {
  4576 	fprintf(stdout,
  4577 		"  Proc 0x%x, refCt %d, args %d, compiled locals %d\n",
  4578 		(unsigned int) procPtr, procPtr->refCount,
  4579 		procPtr->numArgs, procPtr->numCompiledLocals);
  4580     }
  4581 }
  4582 #endif /* TCL_COMPILE_DEBUG */
  4583 
  4584 /*
  4585  *----------------------------------------------------------------------
  4586  *
  4587  * ValidatePcAndStackTop --
  4588  *
  4589  *	This procedure is called by TclExecuteByteCode when debugging to
  4590  *	verify that the program counter and stack top are valid during
  4591  *	execution.
  4592  *
  4593  * Results:
  4594  *	None.
  4595  *
  4596  * Side effects:
  4597  *	Prints a message to stderr and panics if either the pc or stack
  4598  *	top are invalid.
  4599  *
  4600  *----------------------------------------------------------------------
  4601  */
  4602 
  4603 #ifdef TCL_COMPILE_DEBUG
  4604 static void
  4605 ValidatePcAndStackTop(codePtr, pc, stackTop, stackLowerBound)
  4606     register ByteCode *codePtr; /* The bytecode whose summary is printed
  4607 				 * to stdout. */
  4608     unsigned char *pc;		/* Points to first byte of a bytecode
  4609 				 * instruction. The program counter. */
  4610     int stackTop;		/* Current stack top. Must be between
  4611 				 * stackLowerBound and stackUpperBound
  4612 				 * (inclusive). */
  4613     int stackLowerBound;	/* Smallest legal value for stackTop. */
  4614 {
  4615     int stackUpperBound = stackLowerBound +  codePtr->maxStackDepth;	
  4616                                 /* Greatest legal value for stackTop. */
  4617     unsigned int relativePc = (unsigned int) (pc - codePtr->codeStart);
  4618     unsigned int codeStart = (unsigned int) codePtr->codeStart;
  4619     unsigned int codeEnd = (unsigned int)
  4620 	    (codePtr->codeStart + codePtr->numCodeBytes);
  4621     unsigned char opCode = *pc;
  4622 
  4623     if (((unsigned int) pc < codeStart) || ((unsigned int) pc > codeEnd)) {
  4624 	fprintf(stderr, "\nBad instruction pc 0x%x in TclExecuteByteCode\n",
  4625 		(unsigned int) pc);
  4626 	panic("TclExecuteByteCode execution failure: bad pc");
  4627     }
  4628     if ((unsigned int) opCode > LAST_INST_OPCODE) {
  4629 	fprintf(stderr, "\nBad opcode %d at pc %u in TclExecuteByteCode\n",
  4630 		(unsigned int) opCode, relativePc);
  4631         panic("TclExecuteByteCode execution failure: bad opcode");
  4632     }
  4633     if ((stackTop < stackLowerBound) || (stackTop > stackUpperBound)) {
  4634 	int numChars;
  4635 	char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars);
  4636 	char *ellipsis = "";
  4637 	
  4638 	fprintf(stderr, "\nBad stack top %d at pc %u in TclExecuteByteCode (min %i, max %i)",
  4639 		stackTop, relativePc, stackLowerBound, stackUpperBound);
  4640 	if (cmd != NULL) {
  4641 	    if (numChars > 100) {
  4642 		numChars = 100;
  4643 		ellipsis = "...";
  4644 	    }
  4645 	    fprintf(stderr, "\n executing %.*s%s\n", numChars, cmd,
  4646 		    ellipsis);
  4647 	} else {
  4648 	    fprintf(stderr, "\n");
  4649 	}
  4650 	panic("TclExecuteByteCode execution failure: bad stack top");
  4651     }
  4652 }
  4653 #endif /* TCL_COMPILE_DEBUG */
  4654 
  4655 /*
  4656  *----------------------------------------------------------------------
  4657  *
  4658  * IllegalExprOperandType --
  4659  *
  4660  *	Used by TclExecuteByteCode to add an error message to errorInfo
  4661  *	when an illegal operand type is detected by an expression
  4662  *	instruction. The argument opndPtr holds the operand object in error.
  4663  *
  4664  * Results:
  4665  *	None.
  4666  *
  4667  * Side effects:
  4668  *	An error message is appended to errorInfo.
  4669  *
  4670  *----------------------------------------------------------------------
  4671  */
  4672 
  4673 static void
  4674 IllegalExprOperandType(interp, pc, opndPtr)
  4675     Tcl_Interp *interp;		/* Interpreter to which error information
  4676 				 * pertains. */
  4677     unsigned char *pc;		/* Points to the instruction being executed
  4678 				 * when the illegal type was found. */
  4679     Tcl_Obj *opndPtr;		/* Points to the operand holding the value
  4680 				 * with the illegal type. */
  4681 {
  4682     unsigned char opCode = *pc;
  4683     
  4684     Tcl_ResetResult(interp);
  4685     if ((opndPtr->bytes == NULL) || (opndPtr->length == 0)) {
  4686 	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  4687 		"can't use empty string as operand of \"",
  4688 		operatorStrings[opCode - INST_LOR], "\"", (char *) NULL);
  4689     } else {
  4690 	char *msg = "non-numeric string";
  4691 	char *s, *p;
  4692 	int length;
  4693 	int looksLikeInt = 0;
  4694 
  4695 	s = Tcl_GetStringFromObj(opndPtr, &length);
  4696 	p = s;
  4697 	/*
  4698 	 * strtod() isn't at all consistent about detecting Inf and
  4699 	 * NaN between platforms.
  4700 	 */
  4701 	if (length == 3) {
  4702 	    if ((s[0]=='n' || s[0]=='N') && (s[1]=='a' || s[1]=='A') &&
  4703 		    (s[2]=='n' || s[2]=='N')) {
  4704 		msg = "non-numeric floating-point value";
  4705 		goto makeErrorMessage;
  4706 	    }
  4707 	    if ((s[0]=='i' || s[0]=='I') && (s[1]=='n' || s[1]=='N') &&
  4708 		    (s[2]=='f' || s[2]=='F')) {
  4709 		msg = "infinite floating-point value";
  4710 		goto makeErrorMessage;
  4711 	    }
  4712 	}
  4713 
  4714 	/*
  4715 	 * We cannot use TclLooksLikeInt here because it passes strings
  4716 	 * like "10;" [Bug 587140]. We'll accept as "looking like ints"
  4717 	 * for the present purposes any string that looks formally like
  4718 	 * a (decimal|octal|hex) integer.
  4719 	 */
  4720 
  4721 	while (length && isspace(UCHAR(*p))) {
  4722 	    length--;
  4723 	    p++;
  4724 	}
  4725 	if (length && ((*p == '+') || (*p == '-'))) {
  4726 	    length--;
  4727 	    p++;
  4728 	}
  4729 	if (length) {
  4730 	    if ((*p == '0') && ((*(p+1) == 'x') || (*(p+1) == 'X'))) {
  4731 		p += 2;
  4732 		length -= 2;
  4733 		looksLikeInt = ((length > 0) && isxdigit(UCHAR(*p)));
  4734 		if (looksLikeInt) {
  4735 		    length--;
  4736 		    p++;
  4737 		    while (length && isxdigit(UCHAR(*p))) {
  4738 			length--;
  4739 			p++;
  4740 		    }
  4741 		}
  4742 	    } else {
  4743 		looksLikeInt = (length && isdigit(UCHAR(*p)));
  4744 		if (looksLikeInt) {
  4745 		    length--;
  4746 		    p++;
  4747 		    while (length && isdigit(UCHAR(*p))) {
  4748 			length--;
  4749 			p++;
  4750 		    }
  4751 		}
  4752 	    }
  4753 	    while (length && isspace(UCHAR(*p))) {
  4754 		length--;
  4755 		p++;
  4756 	    }
  4757 	    looksLikeInt = !length;
  4758 	}
  4759 	if (looksLikeInt) {
  4760 	    /*
  4761 	     * If something that looks like an integer could not be
  4762 	     * converted, then it *must* be a bad octal or too large
  4763 	     * to represent [Bug 542588].
  4764 	     */
  4765 
  4766 	    if (TclCheckBadOctal(NULL, s)) {
  4767 		msg = "invalid octal number";
  4768 	    } else {
  4769 		msg = "integer value too large to represent";
  4770 		Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  4771 		    "integer value too large to represent", (char *) NULL);
  4772 	    }
  4773 	} else {
  4774 	    /*
  4775 	     * See if the operand can be interpreted as a double in
  4776 	     * order to improve the error message.
  4777 	     */
  4778 
  4779 	    double d;
  4780 
  4781 	    if (Tcl_GetDouble((Tcl_Interp *) NULL, s, &d) == TCL_OK) {
  4782 		msg = "floating-point value";
  4783 	    }
  4784 	}
  4785       makeErrorMessage:
  4786 	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't use ",
  4787 		msg, " as operand of \"", operatorStrings[opCode - INST_LOR],
  4788 		"\"", (char *) NULL);
  4789     }
  4790 }
  4791 
  4792 /*
  4793  *----------------------------------------------------------------------
  4794  *
  4795  * TclGetSrcInfoForPc, GetSrcInfoForPc --
  4796  *
  4797  *	Given a program counter value, finds the closest command in the
  4798  *	bytecode code unit's CmdLocation array and returns information about
  4799  *	that command's source: a pointer to its first byte and the number of
  4800  *	characters.
  4801  *
  4802  * Results:
  4803  *	If a command is found that encloses the program counter value, a
  4804  *	pointer to the command's source is returned and the length of the
  4805  *	source is stored at *lengthPtr. If multiple commands resulted in
  4806  *	code at pc, information about the closest enclosing command is
  4807  *	returned. If no matching command is found, NULL is returned and
  4808  *	*lengthPtr is unchanged.
  4809  *
  4810  * Side effects:
  4811  *	None.
  4812  *
  4813  *----------------------------------------------------------------------
  4814  */
  4815 
  4816 #ifdef TCL_TIP280
  4817 void
  4818 TclGetSrcInfoForPc (cfPtr)
  4819      CmdFrame* cfPtr;
  4820 {
  4821     ByteCode* codePtr = (ByteCode*) cfPtr->data.tebc.codePtr;
  4822 
  4823     if (cfPtr->cmd.str.cmd == NULL) {
  4824         cfPtr->cmd.str.cmd = GetSrcInfoForPc((char*) cfPtr->data.tebc.pc,
  4825 					     codePtr,
  4826 					     &cfPtr->cmd.str.len);
  4827     }
  4828 
  4829     if (cfPtr->cmd.str.cmd != NULL) {
  4830         /* We now have the command. We can get the srcOffset back and
  4831 	 * from there find the list of word locations for this command
  4832 	 */
  4833 
  4834 	ExtCmdLoc*     eclPtr;
  4835 	ECL*           locPtr = NULL;
  4836 	int            srcOffset;
  4837 
  4838         Interp*        iPtr  = (Interp*) *codePtr->interpHandle;
  4839 	Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr);
  4840 
  4841 	if (!hePtr) return;
  4842 
  4843 	srcOffset = cfPtr->cmd.str.cmd - codePtr->source;
  4844 	eclPtr    = (ExtCmdLoc*) Tcl_GetHashValue (hePtr);
  4845 
  4846 	{
  4847 	    int i;
  4848 	    for (i=0; i < eclPtr->nuloc; i++) {
  4849 		if (eclPtr->loc [i].srcOffset == srcOffset) {
  4850 		    locPtr = &(eclPtr->loc [i]);
  4851 		    break;
  4852 		}
  4853 	    }
  4854 	}
  4855 
  4856 	if (locPtr == NULL) {Tcl_Panic ("LocSearch failure");}
  4857 
  4858 	cfPtr->line           = locPtr->line;
  4859 	cfPtr->nline          = locPtr->nline;
  4860 	cfPtr->type           = eclPtr->type;
  4861 
  4862 	if (eclPtr->type == TCL_LOCATION_SOURCE) {
  4863 	    cfPtr->data.eval.path = eclPtr->path;
  4864 	    Tcl_IncrRefCount (cfPtr->data.eval.path);
  4865 	}
  4866 	/* Do not set cfPtr->data.eval.path NULL for non-SOURCE
  4867 	 * Needed for cfPtr->data.tebc.codePtr.
  4868 	 */
  4869     }
  4870 }
  4871 #endif
  4872 
  4873 static char *
  4874 GetSrcInfoForPc(pc, codePtr, lengthPtr)
  4875     unsigned char *pc;		/* The program counter value for which to
  4876 				 * return the closest command's source info.
  4877 				 * This points to a bytecode instruction
  4878 				 * in codePtr's code. */
  4879     ByteCode *codePtr;		/* The bytecode sequence in which to look
  4880 				 * up the command source for the pc. */
  4881     int *lengthPtr;		/* If non-NULL, the location where the
  4882 				 * length of the command's source should be
  4883 				 * stored. If NULL, no length is stored. */
  4884 {
  4885     register int pcOffset = (pc - codePtr->codeStart);
  4886     int numCmds = codePtr->numCommands;
  4887     unsigned char *codeDeltaNext, *codeLengthNext;
  4888     unsigned char *srcDeltaNext, *srcLengthNext;
  4889     int codeOffset, codeLen, codeEnd, srcOffset, srcLen, delta, i;
  4890     int bestDist = INT_MAX;	/* Distance of pc to best cmd's start pc. */
  4891     int bestSrcOffset = -1;	/* Initialized to avoid compiler warning. */
  4892     int bestSrcLength = -1;	/* Initialized to avoid compiler warning. */
  4893 
  4894     if ((pcOffset < 0) || (pcOffset >= codePtr->numCodeBytes)) {
  4895 	return NULL;
  4896     }
  4897 
  4898     /*
  4899      * Decode the code and source offset and length for each command. The
  4900      * closest enclosing command is the last one whose code started before
  4901      * pcOffset.
  4902      */
  4903 
  4904     codeDeltaNext = codePtr->codeDeltaStart;
  4905     codeLengthNext = codePtr->codeLengthStart;
  4906     srcDeltaNext  = codePtr->srcDeltaStart;
  4907     srcLengthNext = codePtr->srcLengthStart;
  4908     codeOffset = srcOffset = 0;
  4909     for (i = 0;  i < numCmds;  i++) {
  4910 	if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
  4911 	    codeDeltaNext++;
  4912 	    delta = TclGetInt4AtPtr(codeDeltaNext);
  4913 	    codeDeltaNext += 4;
  4914 	} else {
  4915 	    delta = TclGetInt1AtPtr(codeDeltaNext);
  4916 	    codeDeltaNext++;
  4917 	}
  4918 	codeOffset += delta;
  4919 
  4920 	if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) {
  4921 	    codeLengthNext++;
  4922 	    codeLen = TclGetInt4AtPtr(codeLengthNext);
  4923 	    codeLengthNext += 4;
  4924 	} else {
  4925 	    codeLen = TclGetInt1AtPtr(codeLengthNext);
  4926 	    codeLengthNext++;
  4927 	}
  4928 	codeEnd = (codeOffset + codeLen - 1);
  4929 
  4930 	if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
  4931 	    srcDeltaNext++;
  4932 	    delta = TclGetInt4AtPtr(srcDeltaNext);
  4933 	    srcDeltaNext += 4;
  4934 	} else {
  4935 	    delta = TclGetInt1AtPtr(srcDeltaNext);
  4936 	    srcDeltaNext++;
  4937 	}
  4938 	srcOffset += delta;
  4939 
  4940 	if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
  4941 	    srcLengthNext++;
  4942 	    srcLen = TclGetInt4AtPtr(srcLengthNext);
  4943 	    srcLengthNext += 4;
  4944 	} else {
  4945 	    srcLen = TclGetInt1AtPtr(srcLengthNext);
  4946 	    srcLengthNext++;
  4947 	}
  4948 	
  4949 	if (codeOffset > pcOffset) {      /* best cmd already found */
  4950 	    break;
  4951 	} else if (pcOffset <= codeEnd) { /* this cmd's code encloses pc */
  4952 	    int dist = (pcOffset - codeOffset);
  4953 	    if (dist <= bestDist) {
  4954 		bestDist = dist;
  4955 		bestSrcOffset = srcOffset;
  4956 		bestSrcLength = srcLen;
  4957 	    }
  4958 	}
  4959     }
  4960 
  4961     if (bestDist == INT_MAX) {
  4962 	return NULL;
  4963     }
  4964     
  4965     if (lengthPtr != NULL) {
  4966 	*lengthPtr = bestSrcLength;
  4967     }
  4968     return (codePtr->source + bestSrcOffset);
  4969 }
  4970 
  4971 /*
  4972  *----------------------------------------------------------------------
  4973  *
  4974  * GetExceptRangeForPc --
  4975  *
  4976  *	Given a program counter value, return the closest enclosing
  4977  *	ExceptionRange.
  4978  *
  4979  * Results:
  4980  *	In the normal case, catchOnly is 0 (false) and this procedure
  4981  *	returns a pointer to the most closely enclosing ExceptionRange
  4982  *	structure regardless of whether it is a loop or catch exception
  4983  *	range. This is appropriate when processing a TCL_BREAK or
  4984  *	TCL_CONTINUE, which will be "handled" either by a loop exception
  4985  *	range or a closer catch range. If catchOnly is nonzero, this
  4986  *	procedure ignores loop exception ranges and returns a pointer to the
  4987  *	closest catch range. If no matching ExceptionRange is found that
  4988  *	encloses pc, a NULL is returned.
  4989  *
  4990  * Side effects:
  4991  *	None.
  4992  *
  4993  *----------------------------------------------------------------------
  4994  */
  4995 
  4996 static ExceptionRange *
  4997 GetExceptRangeForPc(pc, catchOnly, codePtr)
  4998     unsigned char *pc;		/* The program counter value for which to
  4999 				 * search for a closest enclosing exception
  5000 				 * range. This points to a bytecode
  5001 				 * instruction in codePtr's code. */
  5002     int catchOnly;		/* If 0, consider either loop or catch
  5003 				 * ExceptionRanges in search. If nonzero
  5004 				 * consider only catch ranges (and ignore
  5005 				 * any closer loop ranges). */
  5006     ByteCode* codePtr;		/* Points to the ByteCode in which to search
  5007 				 * for the enclosing ExceptionRange. */
  5008 {
  5009     ExceptionRange *rangeArrayPtr;
  5010     int numRanges = codePtr->numExceptRanges;
  5011     register ExceptionRange *rangePtr;
  5012     int pcOffset = (pc - codePtr->codeStart);
  5013     register int start;
  5014 
  5015     if (numRanges == 0) {
  5016 	return NULL;
  5017     }
  5018 
  5019     /* 
  5020      * This exploits peculiarities of our compiler: nested ranges
  5021      * are always *after* their containing ranges, so that by scanning
  5022      * backwards we are sure that the first matching range is indeed
  5023      * the deepest.
  5024      */
  5025 
  5026     rangeArrayPtr = codePtr->exceptArrayPtr;
  5027     rangePtr = rangeArrayPtr + numRanges;
  5028     while (--rangePtr >= rangeArrayPtr) {
  5029 	start = rangePtr->codeOffset;
  5030 	if ((start <= pcOffset) &&
  5031 	        (pcOffset < (start + rangePtr->numCodeBytes))) {
  5032 	    if ((!catchOnly)
  5033 		    || (rangePtr->type == CATCH_EXCEPTION_RANGE)) {
  5034 		return rangePtr;
  5035 	    }
  5036 	}
  5037     }
  5038     return NULL;
  5039 }
  5040 
  5041 /*
  5042  *----------------------------------------------------------------------
  5043  *
  5044  * GetOpcodeName --
  5045  *
  5046  *	This procedure is called by the TRACE and TRACE_WITH_OBJ macros
  5047  *	used in TclExecuteByteCode when debugging. It returns the name of
  5048  *	the bytecode instruction at a specified instruction pc.
  5049  *
  5050  * Results:
  5051  *	A character string for the instruction.
  5052  *
  5053  * Side effects:
  5054  *	None.
  5055  *
  5056  *----------------------------------------------------------------------
  5057  */
  5058 
  5059 #ifdef TCL_COMPILE_DEBUG
  5060 static char *
  5061 GetOpcodeName(pc)
  5062     unsigned char *pc;		/* Points to the instruction whose name
  5063 				 * should be returned. */
  5064 {
  5065     unsigned char opCode = *pc;
  5066     
  5067     return tclInstructionTable[opCode].name;
  5068 }
  5069 #endif /* TCL_COMPILE_DEBUG */
  5070 
  5071 /*
  5072  *----------------------------------------------------------------------
  5073  *
  5074  * VerifyExprObjType --
  5075  *
  5076  *	This procedure is called by the math functions to verify that
  5077  *	the object is either an int or double, coercing it if necessary.
  5078  *	If an error occurs during conversion, an error message is left
  5079  *	in the interpreter's result unless "interp" is NULL.
  5080  *
  5081  * Results:
  5082  *	TCL_OK if it was int or double, TCL_ERROR otherwise
  5083  *
  5084  * Side effects:
  5085  *	objPtr is ensured to be of tclIntType, tclWideIntType or
  5086  *	tclDoubleType.
  5087  *
  5088  *----------------------------------------------------------------------
  5089  */
  5090 
  5091 static int
  5092 VerifyExprObjType(interp, objPtr)
  5093     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5094 				 * function. */
  5095     Tcl_Obj *objPtr;		/* Points to the object to type check. */
  5096 {
  5097     if (IS_NUMERIC_TYPE(objPtr->typePtr)) {
  5098 	return TCL_OK;
  5099     } else {
  5100 	int length, result = TCL_OK;
  5101 	char *s = Tcl_GetStringFromObj(objPtr, &length);
  5102 	
  5103 	if (TclLooksLikeInt(s, length)) {
  5104 	    long i;
  5105 	    Tcl_WideInt w;
  5106 	    GET_WIDE_OR_INT(result, objPtr, i, w);
  5107 	} else {
  5108 	    double d;
  5109 	    result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, objPtr, &d);
  5110 	}
  5111 	if ((result != TCL_OK) && (interp != NULL)) {
  5112 	    Tcl_ResetResult(interp);
  5113 	    if (TclCheckBadOctal((Tcl_Interp *) NULL, s)) {
  5114 		Tcl_AppendToObj(Tcl_GetObjResult(interp),
  5115 			"argument to math function was an invalid octal number",
  5116 			-1);
  5117 	    } else {
  5118 		Tcl_AppendToObj(Tcl_GetObjResult(interp),
  5119 			"argument to math function didn't have numeric value",
  5120 			-1);
  5121 	    }
  5122 	}
  5123 	return result;
  5124     }
  5125 }
  5126 
  5127 /*
  5128  *----------------------------------------------------------------------
  5129  *
  5130  * Math Functions --
  5131  *
  5132  *	This page contains the procedures that implement all of the
  5133  *	built-in math functions for expressions.
  5134  *
  5135  * Results:
  5136  *	Each procedure returns TCL_OK if it succeeds and pushes an
  5137  *	Tcl object holding the result. If it fails it returns TCL_ERROR
  5138  *	and leaves an error message in the interpreter's result.
  5139  *
  5140  * Side effects:
  5141  *	None.
  5142  *
  5143  *----------------------------------------------------------------------
  5144  */
  5145 
  5146 static int
  5147 ExprUnaryFunc(interp, eePtr, clientData)
  5148     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5149 				 * function. */
  5150     ExecEnv *eePtr;		/* Points to the environment for executing
  5151 				 * the function. */
  5152     ClientData clientData;	/* Contains the address of a procedure that
  5153 				 * takes one double argument and returns a
  5154 				 * double result. */
  5155 {
  5156     Tcl_Obj **stackPtr;		/* Cached evaluation stack base pointer. */
  5157     register int stackTop;	/* Cached top index of evaluation stack. */
  5158     register Tcl_Obj *valuePtr;
  5159     double d, dResult;
  5160     int result;
  5161     
  5162     double (*func) _ANSI_ARGS_((double)) =
  5163 	(double (*)_ANSI_ARGS_((double))) clientData;
  5164 
  5165     /*
  5166      * Set stackPtr and stackTop from eePtr.
  5167      */
  5168 
  5169     result = TCL_OK;
  5170     CACHE_STACK_INFO();
  5171 
  5172     /*
  5173      * Pop the function's argument from the evaluation stack. Convert it
  5174      * to a double if necessary.
  5175      */
  5176 
  5177     valuePtr = POP_OBJECT();
  5178 
  5179     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  5180 	result = TCL_ERROR;
  5181 	goto done;
  5182     }
  5183 
  5184     GET_DOUBLE_VALUE(d, valuePtr, valuePtr->typePtr);
  5185 
  5186     errno = 0;
  5187     dResult = (*func)(d);
  5188     if ((errno != 0) || IS_NAN(dResult) || IS_INF(dResult)) {
  5189 	TclExprFloatError(interp, dResult);
  5190 	result = TCL_ERROR;
  5191 	goto done;
  5192     }
  5193     
  5194     /*
  5195      * Push a Tcl object holding the result.
  5196      */
  5197 
  5198     PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  5199     
  5200     /*
  5201      * Reflect the change to stackTop back in eePtr.
  5202      */
  5203 
  5204     done:
  5205     TclDecrRefCount(valuePtr);
  5206     DECACHE_STACK_INFO();
  5207     return result;
  5208 }
  5209 
  5210 static int
  5211 ExprBinaryFunc(interp, eePtr, clientData)
  5212     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5213 				 * function. */
  5214     ExecEnv *eePtr;		/* Points to the environment for executing
  5215 				 * the function. */
  5216     ClientData clientData;	/* Contains the address of a procedure that
  5217 				 * takes two double arguments and
  5218 				 * returns a double result. */
  5219 {
  5220     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  5221     register int stackTop;	/* Cached top index of evaluation stack. */
  5222     register Tcl_Obj *valuePtr, *value2Ptr;
  5223     double d1, d2, dResult;
  5224     int result;
  5225     
  5226     double (*func) _ANSI_ARGS_((double, double))
  5227 	= (double (*)_ANSI_ARGS_((double, double))) clientData;
  5228 
  5229     /*
  5230      * Set stackPtr and stackTop from eePtr.
  5231      */
  5232 
  5233     result = TCL_OK;
  5234     CACHE_STACK_INFO();
  5235 
  5236     /*
  5237      * Pop the function's two arguments from the evaluation stack. Convert
  5238      * them to doubles if necessary.
  5239      */
  5240 
  5241     value2Ptr = POP_OBJECT();
  5242     valuePtr  = POP_OBJECT();
  5243 
  5244     if ((VerifyExprObjType(interp, valuePtr) != TCL_OK) ||
  5245 	    (VerifyExprObjType(interp, value2Ptr) != TCL_OK)) {
  5246 	result = TCL_ERROR;
  5247 	goto done;
  5248     }
  5249 
  5250     GET_DOUBLE_VALUE(d1, valuePtr, valuePtr->typePtr);
  5251     GET_DOUBLE_VALUE(d2, value2Ptr, value2Ptr->typePtr);
  5252 
  5253     errno = 0;
  5254     dResult = (*func)(d1, d2);
  5255     if ((errno != 0) || IS_NAN(dResult) || IS_INF(dResult)) {
  5256 	TclExprFloatError(interp, dResult);
  5257 	result = TCL_ERROR;
  5258 	goto done;
  5259     }
  5260 
  5261     /*
  5262      * Push a Tcl object holding the result.
  5263      */
  5264 
  5265     PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  5266     
  5267     /*
  5268      * Reflect the change to stackTop back in eePtr.
  5269      */
  5270 
  5271     done:
  5272     TclDecrRefCount(valuePtr);
  5273     TclDecrRefCount(value2Ptr);
  5274     DECACHE_STACK_INFO();
  5275     return result;
  5276 }
  5277 
  5278 static int
  5279 ExprAbsFunc(interp, eePtr, clientData)
  5280     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5281 				 * function. */
  5282     ExecEnv *eePtr;		/* Points to the environment for executing
  5283 				 * the function. */
  5284     ClientData clientData;	/* Ignored. */
  5285 {
  5286     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  5287     register int stackTop;	/* Cached top index of evaluation stack. */
  5288     register Tcl_Obj *valuePtr;
  5289     long i, iResult;
  5290     double d, dResult;
  5291     int result;
  5292 
  5293     /*
  5294      * Set stackPtr and stackTop from eePtr.
  5295      */
  5296 
  5297     result = TCL_OK;
  5298     CACHE_STACK_INFO();
  5299 
  5300     /*
  5301      * Pop the argument from the evaluation stack.
  5302      */
  5303 
  5304     valuePtr = POP_OBJECT();
  5305 
  5306     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  5307 	result = TCL_ERROR;
  5308 	goto done;
  5309     }
  5310 
  5311     /*
  5312      * Push a Tcl object with the result.
  5313      */
  5314     if (valuePtr->typePtr == &tclIntType) {
  5315 	i = valuePtr->internalRep.longValue;
  5316 	if (i < 0) {
  5317 	    if (i == LONG_MIN) {
  5318 #ifdef TCL_WIDE_INT_IS_LONG
  5319 		Tcl_SetObjResult(interp, Tcl_NewStringObj(
  5320 			"integer value too large to represent", -1));
  5321 		Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  5322 			"integer value too large to represent", (char *) NULL);
  5323 		result = TCL_ERROR;
  5324 		goto done;
  5325 #else 
  5326 		/*
  5327 		 * Special case: abs(MIN_INT) must promote to wide.
  5328 		 */
  5329 
  5330 		PUSH_OBJECT( Tcl_NewWideIntObj(-(Tcl_WideInt) i) );
  5331 		result = TCL_OK;
  5332 		goto done;
  5333 #endif
  5334 
  5335 	    }
  5336 	    iResult = -i;
  5337 	} else {
  5338 	    iResult = i;
  5339 	}	    
  5340 	PUSH_OBJECT(Tcl_NewLongObj(iResult));
  5341     } else if (valuePtr->typePtr == &tclWideIntType) {
  5342 	Tcl_WideInt wResult, w;
  5343 	TclGetWide(w,valuePtr);
  5344 	if (w < W0) {
  5345 	    wResult = -w;
  5346 	    if (wResult < 0) {
  5347 		Tcl_ResetResult(interp);
  5348 		Tcl_AppendToObj(Tcl_GetObjResult(interp),
  5349 		        "integer value too large to represent", -1);
  5350 		Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  5351 			"integer value too large to represent", (char *) NULL);
  5352 		result = TCL_ERROR;
  5353 		goto done;
  5354 	    }
  5355 	} else {
  5356 	    wResult = w;
  5357 	}	    
  5358 	PUSH_OBJECT(Tcl_NewWideIntObj(wResult));
  5359     } else {
  5360 	d = valuePtr->internalRep.doubleValue;
  5361 	if (d < 0.0) {
  5362 	    dResult = -d;
  5363 	} else {
  5364 	    dResult = d;
  5365 	}
  5366 	if (IS_NAN(dResult) || IS_INF(dResult)) {
  5367 	    TclExprFloatError(interp, dResult);
  5368 	    result = TCL_ERROR;
  5369 	    goto done;
  5370 	}
  5371 	PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  5372     }
  5373 
  5374     /*
  5375      * Reflect the change to stackTop back in eePtr.
  5376      */
  5377 
  5378     done:
  5379     TclDecrRefCount(valuePtr);
  5380     DECACHE_STACK_INFO();
  5381     return result;
  5382 }
  5383 
  5384 static int
  5385 ExprDoubleFunc(interp, eePtr, clientData)
  5386     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5387 				 * function. */
  5388     ExecEnv *eePtr;		/* Points to the environment for executing
  5389 				 * the function. */
  5390     ClientData clientData;	/* Ignored. */
  5391 {
  5392     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  5393     register int stackTop;	/* Cached top index of evaluation stack. */
  5394     register Tcl_Obj *valuePtr;
  5395     double dResult;
  5396     int result;
  5397 
  5398     /*
  5399      * Set stackPtr and stackTop from eePtr.
  5400      */
  5401 
  5402     result = TCL_OK;
  5403     CACHE_STACK_INFO();
  5404 
  5405     /*
  5406      * Pop the argument from the evaluation stack.
  5407      */
  5408 
  5409     valuePtr = POP_OBJECT();
  5410 
  5411     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  5412 	result = TCL_ERROR;
  5413 	goto done;
  5414     }
  5415 
  5416     GET_DOUBLE_VALUE(dResult, valuePtr, valuePtr->typePtr);
  5417 
  5418     /*
  5419      * Push a Tcl object with the result.
  5420      */
  5421 
  5422     PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  5423 
  5424     /*
  5425      * Reflect the change to stackTop back in eePtr.
  5426      */
  5427 
  5428     done:
  5429     TclDecrRefCount(valuePtr);
  5430     DECACHE_STACK_INFO();
  5431     return result;
  5432 }
  5433 
  5434 static int
  5435 ExprIntFunc(interp, eePtr, clientData)
  5436     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5437 				 * function. */
  5438     ExecEnv *eePtr;		/* Points to the environment for executing
  5439 				 * the function. */
  5440     ClientData clientData;	/* Ignored. */
  5441 {
  5442     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  5443     register int stackTop;	/* Cached top index of evaluation stack. */
  5444     register Tcl_Obj *valuePtr;
  5445     long iResult;
  5446     double d;
  5447     int result;
  5448 
  5449     /*
  5450      * Set stackPtr and stackTop from eePtr.
  5451      */
  5452 
  5453     result = TCL_OK;
  5454     CACHE_STACK_INFO();
  5455 
  5456     /*
  5457      * Pop the argument from the evaluation stack.
  5458      */
  5459 
  5460     valuePtr = POP_OBJECT();
  5461     
  5462     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  5463 	result = TCL_ERROR;
  5464 	goto done;
  5465     }
  5466     
  5467     if (valuePtr->typePtr == &tclIntType) {
  5468 	iResult = valuePtr->internalRep.longValue;
  5469     } else if (valuePtr->typePtr == &tclWideIntType) {
  5470 	TclGetLongFromWide(iResult,valuePtr);
  5471     } else {
  5472 	d = valuePtr->internalRep.doubleValue;
  5473 	if (d < 0.0) {
  5474 	    if (d < (double) (long) LONG_MIN) {
  5475 		tooLarge:
  5476 		Tcl_ResetResult(interp);
  5477 		Tcl_AppendToObj(Tcl_GetObjResult(interp),
  5478 		        "integer value too large to represent", -1);
  5479 		Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  5480 			"integer value too large to represent", (char *) NULL);
  5481 		result = TCL_ERROR;
  5482 		goto done;
  5483 	    }
  5484 	} else {
  5485 	    if (d > (double) LONG_MAX) {
  5486 		goto tooLarge;
  5487 	    }
  5488 	}
  5489 	if (IS_NAN(d) || IS_INF(d)) {
  5490 	    TclExprFloatError(interp, d);
  5491 	    result = TCL_ERROR;
  5492 	    goto done;
  5493 	}
  5494 	iResult = (long) d;
  5495     }
  5496 
  5497     /*
  5498      * Push a Tcl object with the result.
  5499      */
  5500     
  5501     PUSH_OBJECT(Tcl_NewLongObj(iResult));
  5502 
  5503     /*
  5504      * Reflect the change to stackTop back in eePtr.
  5505      */
  5506 
  5507     done:
  5508     TclDecrRefCount(valuePtr);
  5509     DECACHE_STACK_INFO();
  5510     return result;
  5511 }
  5512 
  5513 static int
  5514 ExprWideFunc(interp, eePtr, clientData)
  5515     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5516 				 * function. */
  5517     ExecEnv *eePtr;		/* Points to the environment for executing
  5518 				 * the function. */
  5519     ClientData clientData;	/* Ignored. */
  5520 {
  5521     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  5522     register int stackTop;	/* Cached top index of evaluation stack. */
  5523     register Tcl_Obj *valuePtr;
  5524     Tcl_WideInt wResult;
  5525     double d;
  5526     int result;
  5527 
  5528     /*
  5529      * Set stackPtr and stackTop from eePtr.
  5530      */
  5531 
  5532     result = TCL_OK;
  5533     CACHE_STACK_INFO();
  5534 
  5535     /*
  5536      * Pop the argument from the evaluation stack.
  5537      */
  5538 
  5539     valuePtr = POP_OBJECT();
  5540     
  5541     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  5542 	result = TCL_ERROR;
  5543 	goto done;
  5544     }
  5545     
  5546     if (valuePtr->typePtr == &tclWideIntType) {
  5547 	TclGetWide(wResult,valuePtr);
  5548     } else if (valuePtr->typePtr == &tclIntType) {
  5549 	wResult = Tcl_LongAsWide(valuePtr->internalRep.longValue);
  5550     } else {
  5551 	d = valuePtr->internalRep.doubleValue;
  5552 	if (d < 0.0) {
  5553 	    if (d < Tcl_WideAsDouble(LLONG_MIN)) {
  5554 		tooLarge:
  5555 		Tcl_ResetResult(interp);
  5556 		Tcl_AppendToObj(Tcl_GetObjResult(interp),
  5557 		        "integer value too large to represent", -1);
  5558 		Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  5559 			"integer value too large to represent", (char *) NULL);
  5560 		result = TCL_ERROR;
  5561 		goto done;
  5562 	    }
  5563 	} else {
  5564 	    if (d > Tcl_WideAsDouble(LLONG_MAX)) {
  5565 		goto tooLarge;
  5566 	    }
  5567 	}
  5568 	if (IS_NAN(d) || IS_INF(d)) {
  5569 	    TclExprFloatError(interp, d);
  5570 	    result = TCL_ERROR;
  5571 	    goto done;
  5572 	}
  5573 	wResult = Tcl_DoubleAsWide(d);
  5574     }
  5575 
  5576     /*
  5577      * Push a Tcl object with the result.
  5578      */
  5579     
  5580     PUSH_OBJECT(Tcl_NewWideIntObj(wResult));
  5581 
  5582     /*
  5583      * Reflect the change to stackTop back in eePtr.
  5584      */
  5585 
  5586     done:
  5587     TclDecrRefCount(valuePtr);
  5588     DECACHE_STACK_INFO();
  5589     return result;
  5590 }
  5591 
  5592 static int
  5593 ExprRandFunc(interp, eePtr, clientData)
  5594     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5595 				 * function. */
  5596     ExecEnv *eePtr;		/* Points to the environment for executing
  5597 				 * the function. */
  5598     ClientData clientData;	/* Ignored. */
  5599 {
  5600     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  5601     register int stackTop;	/* Cached top index of evaluation stack. */
  5602     Interp *iPtr = (Interp *) interp;
  5603     double dResult;
  5604     long tmp;			/* Algorithm assumes at least 32 bits.
  5605 				 * Only long guarantees that.  See below. */
  5606 
  5607     if (!(iPtr->flags & RAND_SEED_INITIALIZED)) {
  5608 	iPtr->flags |= RAND_SEED_INITIALIZED;
  5609         
  5610         /* 
  5611 	 * Take into consideration the thread this interp is running in order
  5612 	 * to insure different seeds in different threads (bug #416643)
  5613 	 */
  5614 
  5615 	iPtr->randSeed = TclpGetClicks() + ((long)Tcl_GetCurrentThread()<<12);
  5616 
  5617 	/*
  5618 	 * Make sure 1 <= randSeed <= (2^31) - 2.  See below.
  5619 	 */
  5620 
  5621         iPtr->randSeed &= (unsigned long) 0x7fffffff;
  5622 	if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
  5623 	    iPtr->randSeed ^= 123459876;
  5624 	}
  5625     }
  5626     
  5627     /*
  5628      * Set stackPtr and stackTop from eePtr.
  5629      */
  5630     
  5631     CACHE_STACK_INFO();
  5632 
  5633     /*
  5634      * Generate the random number using the linear congruential
  5635      * generator defined by the following recurrence:
  5636      *		seed = ( IA * seed ) mod IM
  5637      * where IA is 16807 and IM is (2^31) - 1.  The recurrence maps
  5638      * a seed in the range [1, IM - 1] to a new seed in that same range.
  5639      * The recurrence maps IM to 0, and maps 0 back to 0, so those two
  5640      * values must not be allowed as initial values of seed.
  5641      *
  5642      * In order to avoid potential problems with integer overflow, the
  5643      * recurrence is implemented in terms of additional constants
  5644      * IQ and IR such that
  5645      *		IM = IA*IQ + IR
  5646      * None of the operations in the implementation overflows a 32-bit
  5647      * signed integer, and the C type long is guaranteed to be at least
  5648      * 32 bits wide.
  5649      *
  5650      * For more details on how this algorithm works, refer to the following
  5651      * papers: 
  5652      *
  5653      *	S.K. Park & K.W. Miller, "Random number generators: good ones
  5654      *	are hard to find," Comm ACM 31(10):1192-1201, Oct 1988
  5655      *
  5656      *	W.H. Press & S.A. Teukolsky, "Portable random number
  5657      *	generators," Computers in Physics 6(5):522-524, Sep/Oct 1992.
  5658      */
  5659 
  5660 #define RAND_IA		16807
  5661 #define RAND_IM		2147483647
  5662 #define RAND_IQ		127773
  5663 #define RAND_IR		2836
  5664 #define RAND_MASK	123459876
  5665 
  5666     tmp = iPtr->randSeed/RAND_IQ;
  5667     iPtr->randSeed = RAND_IA*(iPtr->randSeed - tmp*RAND_IQ) - RAND_IR*tmp;
  5668     if (iPtr->randSeed < 0) {
  5669 	iPtr->randSeed += RAND_IM;
  5670     }
  5671 
  5672     /*
  5673      * Since the recurrence keeps seed values in the range [1, RAND_IM - 1],
  5674      * dividing by RAND_IM yields a double in the range (0, 1).
  5675      */
  5676 
  5677     dResult = iPtr->randSeed * (1.0/RAND_IM);
  5678 
  5679     /*
  5680      * Push a Tcl object with the result.
  5681      */
  5682 
  5683     PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
  5684     
  5685     /*
  5686      * Reflect the change to stackTop back in eePtr.
  5687      */
  5688 
  5689     DECACHE_STACK_INFO();
  5690     return TCL_OK;
  5691 }
  5692 
  5693 static int
  5694 ExprRoundFunc(interp, eePtr, clientData)
  5695     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5696 				 * function. */
  5697     ExecEnv *eePtr;		/* Points to the environment for executing
  5698 				 * the function. */
  5699     ClientData clientData;	/* Ignored. */
  5700 {
  5701     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  5702     register int stackTop;	/* Cached top index of evaluation stack. */
  5703     Tcl_Obj *valuePtr, *resPtr;
  5704     double d, f, i;
  5705     int result;
  5706 
  5707     /*
  5708      * Set stackPtr and stackTop from eePtr.
  5709      */
  5710 
  5711     result = TCL_OK;
  5712     CACHE_STACK_INFO();
  5713 
  5714     /*
  5715      * Pop the argument from the evaluation stack.
  5716      */
  5717 
  5718     valuePtr = POP_OBJECT();
  5719 
  5720     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  5721 	result = TCL_ERROR;
  5722 	goto done;
  5723     }
  5724 
  5725     if ((valuePtr->typePtr == &tclIntType) ||
  5726 	    (valuePtr->typePtr == &tclWideIntType)) {
  5727 	result = TCL_OK;
  5728 	resPtr = valuePtr;
  5729     } else {
  5730 
  5731 	/* 
  5732 	 * Round the number to the nearest integer.  I'd like to use round(),
  5733 	 * but it's C99 (or BSD), and not yet universal.
  5734 	 */
  5735 	
  5736 	d = valuePtr->internalRep.doubleValue;
  5737 	f = modf(d, &i);
  5738 	if (d < 0.0) {
  5739 	    if (f <= -0.5) {
  5740 		i += -1.0;
  5741 	    }
  5742 	    if (i <= Tcl_WideAsDouble(LLONG_MIN)) {
  5743 		goto tooLarge;
  5744 	    } else if (i <= (double) LONG_MIN) {
  5745 		resPtr = Tcl_NewWideIntObj(Tcl_DoubleAsWide(i));
  5746 	    } else {
  5747 		resPtr = Tcl_NewLongObj((long) i);
  5748 	    }			    
  5749 	} else {
  5750 	    if (f >= 0.5) {
  5751 		i += 1.0;
  5752 	    }
  5753 	    if (i >= Tcl_WideAsDouble(LLONG_MAX)) {
  5754 		goto tooLarge;
  5755 	    } else if (i >= (double) LONG_MAX) {
  5756 		resPtr = Tcl_NewWideIntObj(Tcl_DoubleAsWide(i));
  5757 	    } else {
  5758 		resPtr = Tcl_NewLongObj((long) i);
  5759 	    }
  5760 	}
  5761     }
  5762 
  5763     /*
  5764      * Push the result object and free the argument Tcl_Obj.
  5765      */
  5766 
  5767     PUSH_OBJECT(resPtr);
  5768     
  5769     done:
  5770     TclDecrRefCount(valuePtr);
  5771     DECACHE_STACK_INFO();
  5772     return result;
  5773 
  5774     /*
  5775      * Error return: result cannot be represented as an integer.
  5776      */
  5777     
  5778     tooLarge:
  5779     Tcl_ResetResult(interp);
  5780     Tcl_AppendToObj(Tcl_GetObjResult(interp),
  5781 	    "integer value too large to represent", -1);
  5782     Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
  5783 	    "integer value too large to represent",
  5784 	    (char *) NULL);
  5785     result = TCL_ERROR;
  5786     goto done;
  5787 }
  5788 
  5789 static int
  5790 ExprSrandFunc(interp, eePtr, clientData)
  5791     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5792 				 * function. */
  5793     ExecEnv *eePtr;		/* Points to the environment for executing
  5794 				 * the function. */
  5795     ClientData clientData;	/* Ignored. */
  5796 {
  5797     Tcl_Obj **stackPtr;        /* Cached evaluation stack base pointer. */
  5798     register int stackTop;	/* Cached top index of evaluation stack. */
  5799     Interp *iPtr = (Interp *) interp;
  5800     Tcl_Obj *valuePtr;
  5801     long i = 0;			/* Initialized to avoid compiler warning. */
  5802 
  5803     /*
  5804      * Set stackPtr and stackTop from eePtr.
  5805      */
  5806     
  5807     CACHE_STACK_INFO();
  5808 
  5809     /*
  5810      * Pop the argument from the evaluation stack.  Use the value
  5811      * to reset the random number seed.
  5812      */
  5813 
  5814     valuePtr = POP_OBJECT();
  5815 
  5816     if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  5817 	goto badValue;
  5818     }
  5819 
  5820     if (Tcl_GetLongFromObj(NULL, valuePtr, &i) != TCL_OK) {
  5821 	Tcl_WideInt w;
  5822 
  5823 	if (Tcl_GetWideIntFromObj(interp, valuePtr, &w) != TCL_OK) {
  5824 	badValue:
  5825 	    Tcl_AddErrorInfo(interp, "\n    (argument to \"srand()\")");
  5826 	    TclDecrRefCount(valuePtr);
  5827 	    DECACHE_STACK_INFO();
  5828 	    return TCL_ERROR;
  5829 	}
  5830 
  5831 	i = Tcl_WideAsLong(w);
  5832     }
  5833     
  5834     /*
  5835      * Reset the seed.  Make sure 1 <= randSeed <= 2^31 - 2.
  5836      * See comments in ExprRandFunc() for more details.
  5837      */
  5838 
  5839     iPtr->flags |= RAND_SEED_INITIALIZED;
  5840     iPtr->randSeed = i;
  5841     iPtr->randSeed &= (unsigned long) 0x7fffffff;
  5842     if ((iPtr->randSeed == 0) || (iPtr->randSeed == 0x7fffffff)) {
  5843 	iPtr->randSeed ^= 123459876;
  5844     }
  5845 
  5846     /*
  5847      * To avoid duplicating the random number generation code we simply
  5848      * clean up our state and call the real random number function. That
  5849      * function will always succeed.
  5850      */
  5851     
  5852     TclDecrRefCount(valuePtr);
  5853     DECACHE_STACK_INFO();
  5854 
  5855     ExprRandFunc(interp, eePtr, clientData);
  5856     return TCL_OK;
  5857 }
  5858 
  5859 /*
  5860  *----------------------------------------------------------------------
  5861  *
  5862  * ExprCallMathFunc --
  5863  *
  5864  *	This procedure is invoked to call a non-builtin math function
  5865  *	during the execution of an expression. 
  5866  *
  5867  * Results:
  5868  *	TCL_OK is returned if all went well and the function's value
  5869  *	was computed successfully. If an error occurred, TCL_ERROR
  5870  *	is returned and an error message is left in the interpreter's
  5871  *	result.	After a successful return this procedure pushes a Tcl object
  5872  *	holding the result. 
  5873  *
  5874  * Side effects:
  5875  *	None, unless the called math function has side effects.
  5876  *
  5877  *----------------------------------------------------------------------
  5878  */
  5879 
  5880 static int
  5881 ExprCallMathFunc(interp, eePtr, objc, objv)
  5882     Tcl_Interp *interp;		/* The interpreter in which to execute the
  5883 				 * function. */
  5884     ExecEnv *eePtr;		/* Points to the environment for executing
  5885 				 * the function. */
  5886     int objc;			/* Number of arguments. The function name is
  5887 				 * the 0-th argument. */
  5888     Tcl_Obj **objv;		/* The array of arguments. The function name
  5889 				 * is objv[0]. */
  5890 {
  5891     Interp *iPtr = (Interp *) interp;
  5892     Tcl_Obj **stackPtr;		/* Cached evaluation stack base pointer. */
  5893     register int stackTop;	/* Cached top index of evaluation stack. */
  5894     char *funcName;
  5895     Tcl_HashEntry *hPtr;
  5896     MathFunc *mathFuncPtr;	/* Information about math function. */
  5897     Tcl_Value args[MAX_MATH_ARGS]; /* Arguments for function call. */
  5898     Tcl_Value funcResult;	/* Result of function call as Tcl_Value. */
  5899     register Tcl_Obj *valuePtr;
  5900     long i;
  5901     double d;
  5902     int j, k, result;
  5903 
  5904     Tcl_ResetResult(interp);
  5905 
  5906     /*
  5907      * Set stackPtr and stackTop from eePtr.
  5908      */
  5909     
  5910     CACHE_STACK_INFO();
  5911 
  5912     /*
  5913      * Look up the MathFunc record for the function.
  5914      */
  5915 
  5916     funcName = TclGetString(objv[0]);
  5917     hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName);
  5918     if (hPtr == NULL) {
  5919 	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  5920 		"unknown math function \"", funcName, "\"", (char *) NULL);
  5921 	result = TCL_ERROR;
  5922 	goto done;
  5923     }
  5924     mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
  5925     if (mathFuncPtr->numArgs != (objc-1)) {
  5926 	panic("ExprCallMathFunc: expected number of args %d != actual number %d",
  5927 	        mathFuncPtr->numArgs, objc);
  5928 	result = TCL_ERROR;
  5929 	goto done;
  5930     }
  5931 
  5932     /*
  5933      * Collect the arguments for the function, if there are any, into the
  5934      * array "args". Note that args[0] will have the Tcl_Value that
  5935      * corresponds to objv[1].
  5936      */
  5937 
  5938     for (j = 1, k = 0;  j < objc;  j++, k++) {
  5939 	valuePtr = objv[j];
  5940 
  5941 	if (VerifyExprObjType(interp, valuePtr) != TCL_OK) {
  5942 	    result = TCL_ERROR;
  5943 	    goto done;
  5944 	}
  5945 
  5946 	/*
  5947 	 * Copy the object's numeric value to the argument record,
  5948 	 * converting it if necessary. 
  5949 	 */
  5950 
  5951 	if (valuePtr->typePtr == &tclIntType) {
  5952 	    i = valuePtr->internalRep.longValue;
  5953 	    if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) {
  5954 		args[k].type = TCL_DOUBLE;
  5955 		args[k].doubleValue = i;
  5956 	    } else if (mathFuncPtr->argTypes[k] == TCL_WIDE_INT) {
  5957 		args[k].type = TCL_WIDE_INT;
  5958 		args[k].wideValue = Tcl_LongAsWide(i);
  5959 	    } else {
  5960 		args[k].type = TCL_INT;
  5961 		args[k].intValue = i;
  5962 	    }
  5963 	} else if (valuePtr->typePtr == &tclWideIntType) {
  5964 	    Tcl_WideInt w;
  5965 	    TclGetWide(w,valuePtr);
  5966 	    if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) {
  5967 		args[k].type = TCL_DOUBLE;
  5968 		args[k].doubleValue = Tcl_WideAsDouble(w);
  5969 	    } else if (mathFuncPtr->argTypes[k] == TCL_INT) {
  5970 		args[k].type = TCL_INT;
  5971 		args[k].intValue = Tcl_WideAsLong(w);
  5972 	    } else {
  5973 		args[k].type = TCL_WIDE_INT;
  5974 		args[k].wideValue = w;
  5975 	    }
  5976 	} else {
  5977 	    d = valuePtr->internalRep.doubleValue;
  5978 	    if (mathFuncPtr->argTypes[k] == TCL_INT) {
  5979 		args[k].type = TCL_INT;
  5980 		args[k].intValue = (long) d;
  5981 	    } else if (mathFuncPtr->argTypes[k] == TCL_WIDE_INT) {
  5982 		args[k].type = TCL_WIDE_INT;
  5983 		args[k].wideValue = Tcl_DoubleAsWide(d);
  5984 	    } else {
  5985 		args[k].type = TCL_DOUBLE;
  5986 		args[k].doubleValue = d;
  5987 	    }
  5988 	}
  5989     }
  5990 
  5991     /*
  5992      * Invoke the function and copy its result back into valuePtr.
  5993      */
  5994 
  5995     result = (*mathFuncPtr->proc)(mathFuncPtr->clientData, interp, args,
  5996 	    &funcResult);
  5997     if (result != TCL_OK) {
  5998 	goto done;
  5999     }
  6000 
  6001     /*
  6002      * Pop the objc top stack elements and decrement their ref counts.
  6003      */
  6004 
  6005     k = (stackTop - (objc-1));
  6006     while (stackTop >= k) {
  6007 	valuePtr = POP_OBJECT();
  6008 	TclDecrRefCount(valuePtr);
  6009     }
  6010     
  6011     /*
  6012      * Push the call's object result.
  6013      */
  6014     
  6015     if (funcResult.type == TCL_INT) {
  6016 	PUSH_OBJECT(Tcl_NewLongObj(funcResult.intValue));
  6017     } else if (funcResult.type == TCL_WIDE_INT) {
  6018 	PUSH_OBJECT(Tcl_NewWideIntObj(funcResult.wideValue));
  6019     } else {
  6020 	d = funcResult.doubleValue;
  6021 	if (IS_NAN(d) || IS_INF(d)) {
  6022 	    TclExprFloatError(interp, d);
  6023 	    result = TCL_ERROR;
  6024 	    goto done;
  6025 	}
  6026 	PUSH_OBJECT(Tcl_NewDoubleObj(d));
  6027     }
  6028 
  6029     /*
  6030      * Reflect the change to stackTop back in eePtr.
  6031      */
  6032 
  6033     done:
  6034     DECACHE_STACK_INFO();
  6035     return result;
  6036 }
  6037 
  6038 /*
  6039  *----------------------------------------------------------------------
  6040  *
  6041  * TclExprFloatError --
  6042  *
  6043  *	This procedure is called when an error occurs during a
  6044  *	floating-point operation. It reads errno and sets
  6045  *	interp->objResultPtr accordingly.
  6046  *
  6047  * Results:
  6048  *	interp->objResultPtr is set to hold an error message.
  6049  *
  6050  * Side effects:
  6051  *	None.
  6052  *
  6053  *----------------------------------------------------------------------
  6054  */
  6055 
  6056 void
  6057 TclExprFloatError(interp, value)
  6058     Tcl_Interp *interp;		/* Where to store error message. */
  6059     double value;		/* Value returned after error;  used to
  6060 				 * distinguish underflows from overflows. */
  6061 {
  6062     char *s;
  6063 
  6064     Tcl_ResetResult(interp);
  6065     if ((errno == EDOM) || IS_NAN(value)) {
  6066 	s = "domain error: argument not in valid range";
  6067 	Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
  6068 	Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", s, (char *) NULL);
  6069     } else if ((errno == ERANGE) || IS_INF(value)) {
  6070 	if (value == 0.0) {
  6071 	    s = "floating-point value too small to represent";
  6072 	    Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
  6073 	    Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", s, (char *) NULL);
  6074 	} else {
  6075 	    s = "floating-point value too large to represent";
  6076 	    Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
  6077 	    Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", s, (char *) NULL);
  6078 	}
  6079     } else {
  6080 	char msg[64 + TCL_INTEGER_SPACE];
  6081 	
  6082 	sprintf(msg, "unknown floating-point error, errno = %d", errno);
  6083 	Tcl_AppendToObj(Tcl_GetObjResult(interp), msg, -1);
  6084 	Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN", msg, (char *) NULL);
  6085     }
  6086 }
  6087 
  6088 #ifdef TCL_COMPILE_STATS
  6089 /*
  6090  *----------------------------------------------------------------------
  6091  *
  6092  * TclLog2 --
  6093  *
  6094  *	Procedure used while collecting compilation statistics to determine
  6095  *	the log base 2 of an integer.
  6096  *
  6097  * Results:
  6098  *	Returns the log base 2 of the operand. If the argument is less
  6099  *	than or equal to zero, a zero is returned.
  6100  *
  6101  * Side effects:
  6102  *	None.
  6103  *
  6104  *----------------------------------------------------------------------
  6105  */
  6106 
  6107 int
  6108 TclLog2(value)
  6109     register int value;		/* The integer for which to compute the
  6110 				 * log base 2. */
  6111 {
  6112     register int n = value;
  6113     register int result = 0;
  6114 
  6115     while (n > 1) {
  6116 	n = n >> 1;
  6117 	result++;
  6118     }
  6119     return result;
  6120 }
  6121 
  6122 /*
  6123  *----------------------------------------------------------------------
  6124  *
  6125  * EvalStatsCmd --
  6126  *
  6127  *	Implements the "evalstats" command that prints instruction execution
  6128  *	counts to stdout.
  6129  *
  6130  * Results:
  6131  *	Standard Tcl results.
  6132  *
  6133  * Side effects:
  6134  *	None.
  6135  *
  6136  *----------------------------------------------------------------------
  6137  */
  6138 
  6139 static int
  6140 EvalStatsCmd(unused, interp, objc, objv)
  6141     ClientData unused;		/* Unused. */
  6142     Tcl_Interp *interp;		/* The current interpreter. */
  6143     int objc;			/* The number of arguments. */
  6144     Tcl_Obj *CONST objv[];	/* The argument strings. */
  6145 {
  6146     Interp *iPtr = (Interp *) interp;
  6147     LiteralTable *globalTablePtr = &(iPtr->literalTable);
  6148     ByteCodeStats *statsPtr = &(iPtr->stats);
  6149     double totalCodeBytes, currentCodeBytes;
  6150     double totalLiteralBytes, currentLiteralBytes;
  6151     double objBytesIfUnshared, strBytesIfUnshared, sharingBytesSaved;
  6152     double strBytesSharedMultX, strBytesSharedOnce;
  6153     double numInstructions, currentHeaderBytes;
  6154     long numCurrentByteCodes, numByteCodeLits;
  6155     long refCountSum, literalMgmtBytes, sum;
  6156     int numSharedMultX, numSharedOnce;
  6157     int decadeHigh, minSizeDecade, maxSizeDecade, length, i;
  6158     char *litTableStats;
  6159     LiteralEntry *entryPtr;
  6160 
  6161     numInstructions = 0.0;
  6162     for (i = 0;  i < 256;  i++) {
  6163         if (statsPtr->instructionCount[i] != 0) {
  6164             numInstructions += statsPtr->instructionCount[i];
  6165         }
  6166     }
  6167 
  6168     totalLiteralBytes = sizeof(LiteralTable)
  6169 	    + iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)
  6170 	    + (statsPtr->numLiteralsCreated * sizeof(LiteralEntry))
  6171 	    + (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj))
  6172 	    + statsPtr->totalLitStringBytes;
  6173     totalCodeBytes = statsPtr->totalByteCodeBytes + totalLiteralBytes;
  6174 
  6175     numCurrentByteCodes =
  6176 	    statsPtr->numCompilations - statsPtr->numByteCodesFreed;
  6177     currentHeaderBytes = numCurrentByteCodes
  6178 	    * (sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time)));
  6179     literalMgmtBytes = sizeof(LiteralTable)
  6180 	    + (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *))
  6181 	    + (iPtr->literalTable.numEntries * sizeof(LiteralEntry));
  6182     currentLiteralBytes = literalMgmtBytes
  6183 	    + iPtr->literalTable.numEntries * sizeof(Tcl_Obj)
  6184 	    + statsPtr->currentLitStringBytes;
  6185     currentCodeBytes = statsPtr->currentByteCodeBytes + currentLiteralBytes;
  6186     
  6187     /*
  6188      * Summary statistics, total and current source and ByteCode sizes.
  6189      */
  6190 
  6191     fprintf(stdout, "\n----------------------------------------------------------------\n");
  6192     fprintf(stdout,
  6193 	    "Compilation and execution statistics for interpreter 0x%x\n",
  6194 	    (unsigned int) iPtr);
  6195 
  6196     fprintf(stdout, "\nNumber ByteCodes executed	%ld\n",
  6197 	    statsPtr->numExecutions);
  6198     fprintf(stdout, "Number ByteCodes compiled	%ld\n",
  6199 	    statsPtr->numCompilations);
  6200     fprintf(stdout, "  Mean executions/compile	%.1f\n",
  6201 	    ((float)statsPtr->numExecutions) / ((float)statsPtr->numCompilations));
  6202     
  6203     fprintf(stdout, "\nInstructions executed		%.0f\n",
  6204 	    numInstructions);
  6205     fprintf(stdout, "  Mean inst/compile		%.0f\n",
  6206 	    numInstructions / statsPtr->numCompilations);
  6207     fprintf(stdout, "  Mean inst/execution		%.0f\n",
  6208 	    numInstructions / statsPtr->numExecutions);
  6209 
  6210     fprintf(stdout, "\nTotal ByteCodes			%ld\n",
  6211 	    statsPtr->numCompilations);
  6212     fprintf(stdout, "  Source bytes			%.6g\n",
  6213 	    statsPtr->totalSrcBytes);
  6214     fprintf(stdout, "  Code bytes			%.6g\n",
  6215 	    totalCodeBytes);
  6216     fprintf(stdout, "    ByteCode bytes		%.6g\n",
  6217 	    statsPtr->totalByteCodeBytes);
  6218     fprintf(stdout, "    Literal bytes		%.6g\n",
  6219 	    totalLiteralBytes);
  6220     fprintf(stdout, "      table %d + bkts %d + entries %ld + objects %ld + strings %.6g\n",
  6221 	    sizeof(LiteralTable),
  6222 	    iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
  6223 	    statsPtr->numLiteralsCreated * sizeof(LiteralEntry),
  6224 	    statsPtr->numLiteralsCreated * sizeof(Tcl_Obj),
  6225 	    statsPtr->totalLitStringBytes);
  6226     fprintf(stdout, "  Mean code/compile		%.1f\n",
  6227 	    totalCodeBytes / statsPtr->numCompilations);
  6228     fprintf(stdout, "  Mean code/source		%.1f\n",
  6229 	    totalCodeBytes / statsPtr->totalSrcBytes);
  6230 
  6231     fprintf(stdout, "\nCurrent (active) ByteCodes	%ld\n",
  6232 	    numCurrentByteCodes);
  6233     fprintf(stdout, "  Source bytes			%.6g\n",
  6234 	    statsPtr->currentSrcBytes);
  6235     fprintf(stdout, "  Code bytes			%.6g\n",
  6236 	    currentCodeBytes);
  6237     fprintf(stdout, "    ByteCode bytes		%.6g\n",
  6238 	    statsPtr->currentByteCodeBytes);
  6239     fprintf(stdout, "    Literal bytes		%.6g\n",
  6240 	    currentLiteralBytes);
  6241     fprintf(stdout, "      table %d + bkts %d + entries %d + objects %d + strings %.6g\n",
  6242 	    sizeof(LiteralTable),
  6243 	    iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
  6244 	    iPtr->literalTable.numEntries * sizeof(LiteralEntry),
  6245 	    iPtr->literalTable.numEntries * sizeof(Tcl_Obj),
  6246 	    statsPtr->currentLitStringBytes);
  6247     fprintf(stdout, "  Mean code/source		%.1f\n",
  6248 	    currentCodeBytes / statsPtr->currentSrcBytes);
  6249     fprintf(stdout, "  Code + source bytes		%.6g (%0.1f mean code/src)\n",
  6250 	    (currentCodeBytes + statsPtr->currentSrcBytes),
  6251 	    (currentCodeBytes / statsPtr->currentSrcBytes) + 1.0);
  6252 
  6253     /*
  6254      * Tcl_IsShared statistics check
  6255      *
  6256      * This gives the refcount of each obj as Tcl_IsShared was called
  6257      * for it.  Shared objects must be duplicated before they can be
  6258      * modified.
  6259      */
  6260 
  6261     numSharedMultX = 0;
  6262     fprintf(stdout, "\nTcl_IsShared object check (all objects):\n");
  6263     fprintf(stdout, "  Object had refcount <=1 (not shared)	%ld\n",
  6264 	    tclObjsShared[1]);
  6265     for (i = 2;  i < TCL_MAX_SHARED_OBJ_STATS;  i++) {
  6266 	fprintf(stdout, "  refcount ==%d		%ld\n",
  6267 		i, tclObjsShared[i]);
  6268 	numSharedMultX += tclObjsShared[i];
  6269     }
  6270     fprintf(stdout, "  refcount >=%d		%ld\n",
  6271 	    i, tclObjsShared[0]);
  6272     numSharedMultX += tclObjsShared[0];
  6273     fprintf(stdout, "  Total shared objects			%d\n",
  6274 	    numSharedMultX);
  6275 
  6276     /*
  6277      * Literal table statistics.
  6278      */
  6279 
  6280     numByteCodeLits = 0;
  6281     refCountSum = 0;
  6282     numSharedMultX = 0;
  6283     numSharedOnce  = 0;
  6284     objBytesIfUnshared  = 0.0;
  6285     strBytesIfUnshared  = 0.0;
  6286     strBytesSharedMultX = 0.0;
  6287     strBytesSharedOnce  = 0.0;
  6288     for (i = 0;  i < globalTablePtr->numBuckets;  i++) {
  6289 	for (entryPtr = globalTablePtr->buckets[i];  entryPtr != NULL;
  6290 	        entryPtr = entryPtr->nextPtr) {
  6291 	    if (entryPtr->objPtr->typePtr == &tclByteCodeType) {
  6292 		numByteCodeLits++;
  6293 	    }
  6294 	    (void) Tcl_GetStringFromObj(entryPtr->objPtr, &length);
  6295 	    refCountSum += entryPtr->refCount;
  6296 	    objBytesIfUnshared += (entryPtr->refCount * sizeof(Tcl_Obj));
  6297 	    strBytesIfUnshared += (entryPtr->refCount * (length+1));
  6298 	    if (entryPtr->refCount > 1) {
  6299 		numSharedMultX++;
  6300 		strBytesSharedMultX += (length+1);
  6301 	    } else {
  6302 		numSharedOnce++;
  6303 		strBytesSharedOnce += (length+1);
  6304 	    }
  6305 	}
  6306     }
  6307     sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared)
  6308 	    - currentLiteralBytes;
  6309 
  6310     fprintf(stdout, "\nTotal objects (all interps)	%ld\n",
  6311 	    tclObjsAlloced);
  6312     fprintf(stdout, "Current objects			%ld\n",
  6313 	    (tclObjsAlloced - tclObjsFreed));
  6314     fprintf(stdout, "Total literal objects		%ld\n",
  6315 	    statsPtr->numLiteralsCreated);
  6316 
  6317     fprintf(stdout, "\nCurrent literal objects		%d (%0.1f%% of current objects)\n",
  6318 	    globalTablePtr->numEntries,
  6319 	    (globalTablePtr->numEntries * 100.0) / (tclObjsAlloced-tclObjsFreed));
  6320     fprintf(stdout, "  ByteCode literals	 	%ld (%0.1f%% of current literals)\n",
  6321 	    numByteCodeLits,
  6322 	    (numByteCodeLits * 100.0) / globalTablePtr->numEntries);
  6323     fprintf(stdout, "  Literals reused > 1x	 	%d\n",
  6324 	    numSharedMultX);
  6325     fprintf(stdout, "  Mean reference count	 	%.2f\n",
  6326 	    ((double) refCountSum) / globalTablePtr->numEntries);
  6327     fprintf(stdout, "  Mean len, str reused >1x 	%.2f\n",
  6328 	    (numSharedMultX? (strBytesSharedMultX/numSharedMultX) : 0.0));
  6329     fprintf(stdout, "  Mean len, str used 1x	 	%.2f\n",
  6330 	    (numSharedOnce? (strBytesSharedOnce/numSharedOnce) : 0.0));
  6331     fprintf(stdout, "  Total sharing savings	 	%.6g (%0.1f%% of bytes if no sharing)\n",
  6332 	    sharingBytesSaved,
  6333 	    (sharingBytesSaved * 100.0) / (objBytesIfUnshared + strBytesIfUnshared));
  6334     fprintf(stdout, "    Bytes with sharing		%.6g\n",
  6335 	    currentLiteralBytes);
  6336     fprintf(stdout, "      table %d + bkts %d + entries %d + objects %d + strings %.6g\n",
  6337 	    sizeof(LiteralTable),
  6338 	    iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
  6339 	    iPtr->literalTable.numEntries * sizeof(LiteralEntry),
  6340 	    iPtr->literalTable.numEntries * sizeof(Tcl_Obj),
  6341 	    statsPtr->currentLitStringBytes);
  6342     fprintf(stdout, "    Bytes if no sharing		%.6g = objects %.6g + strings %.6g\n",
  6343 	    (objBytesIfUnshared + strBytesIfUnshared),
  6344 	    objBytesIfUnshared, strBytesIfUnshared);
  6345     fprintf(stdout, "  String sharing savings 	%.6g = unshared %.6g - shared %.6g\n",
  6346 	    (strBytesIfUnshared - statsPtr->currentLitStringBytes),
  6347 	    strBytesIfUnshared, statsPtr->currentLitStringBytes);
  6348     fprintf(stdout, "  Literal mgmt overhead	 	%ld (%0.1f%% of bytes with sharing)\n",
  6349 	    literalMgmtBytes,
  6350 	    (literalMgmtBytes * 100.0) / currentLiteralBytes);
  6351     fprintf(stdout, "    table %d + buckets %d + entries %d\n",
  6352 	    sizeof(LiteralTable),
  6353 	    iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
  6354 	    iPtr->literalTable.numEntries * sizeof(LiteralEntry));
  6355 
  6356     /*
  6357      * Breakdown of current ByteCode space requirements.
  6358      */
  6359     
  6360     fprintf(stdout, "\nBreakdown of current ByteCode requirements:\n");
  6361     fprintf(stdout, "                         Bytes      Pct of    Avg per\n");
  6362     fprintf(stdout, "                                     total    ByteCode\n");
  6363     fprintf(stdout, "Total             %12.6g     100.00%%   %8.1f\n",
  6364 	    statsPtr->currentByteCodeBytes,
  6365 	    statsPtr->currentByteCodeBytes / numCurrentByteCodes);
  6366     fprintf(stdout, "Header            %12.6g   %8.1f%%   %8.1f\n",
  6367 	    currentHeaderBytes,
  6368 	    ((currentHeaderBytes * 100.0) / statsPtr->currentByteCodeBytes),
  6369 	    currentHeaderBytes / numCurrentByteCodes);
  6370     fprintf(stdout, "Instructions      %12.6g   %8.1f%%   %8.1f\n",
  6371 	    statsPtr->currentInstBytes,
  6372 	    ((statsPtr->currentInstBytes * 100.0) / statsPtr->currentByteCodeBytes),
  6373 	    statsPtr->currentInstBytes / numCurrentByteCodes);
  6374     fprintf(stdout, "Literal ptr array %12.6g   %8.1f%%   %8.1f\n",
  6375 	    statsPtr->currentLitBytes,
  6376 	    ((statsPtr->currentLitBytes * 100.0) / statsPtr->currentByteCodeBytes),
  6377 	    statsPtr->currentLitBytes / numCurrentByteCodes);
  6378     fprintf(stdout, "Exception table   %12.6g   %8.1f%%   %8.1f\n",
  6379 	    statsPtr->currentExceptBytes,
  6380 	    ((statsPtr->currentExceptBytes * 100.0) / statsPtr->currentByteCodeBytes),
  6381 	    statsPtr->currentExceptBytes / numCurrentByteCodes);
  6382     fprintf(stdout, "Auxiliary data    %12.6g   %8.1f%%   %8.1f\n",
  6383 	    statsPtr->currentAuxBytes,
  6384 	    ((statsPtr->currentAuxBytes * 100.0) / statsPtr->currentByteCodeBytes),
  6385 	    statsPtr->currentAuxBytes / numCurrentByteCodes);
  6386     fprintf(stdout, "Command map       %12.6g   %8.1f%%   %8.1f\n",
  6387 	    statsPtr->currentCmdMapBytes,
  6388 	    ((statsPtr->currentCmdMapBytes * 100.0) / statsPtr->currentByteCodeBytes),
  6389 	    statsPtr->currentCmdMapBytes / numCurrentByteCodes);
  6390 
  6391     /*
  6392      * Detailed literal statistics.
  6393      */
  6394     
  6395     fprintf(stdout, "\nLiteral string sizes:\n");
  6396     fprintf(stdout, "	 Up to length		Percentage\n");
  6397     maxSizeDecade = 0;
  6398     for (i = 31;  i >= 0;  i--) {
  6399         if (statsPtr->literalCount[i] > 0) {
  6400             maxSizeDecade = i;
  6401 	    break;
  6402         }
  6403     }
  6404     sum = 0;
  6405     for (i = 0;  i <= maxSizeDecade;  i++) {
  6406 	decadeHigh = (1 << (i+1)) - 1;
  6407 	sum += statsPtr->literalCount[i];
  6408         fprintf(stdout,	"	%10d		%8.0f%%\n",
  6409 		decadeHigh, (sum * 100.0) / statsPtr->numLiteralsCreated);
  6410     }
  6411 
  6412     litTableStats = TclLiteralStats(globalTablePtr);
  6413     fprintf(stdout, "\nCurrent literal table statistics:\n%s\n",
  6414             litTableStats);
  6415     ckfree((char *) litTableStats);
  6416 
  6417     /*
  6418      * Source and ByteCode size distributions.
  6419      */
  6420 
  6421     fprintf(stdout, "\nSource sizes:\n");
  6422     fprintf(stdout, "	 Up to size		Percentage\n");
  6423     minSizeDecade = maxSizeDecade = 0;
  6424     for (i = 0;  i < 31;  i++) {
  6425         if (statsPtr->srcCount[i] > 0) {
  6426 	    minSizeDecade = i;
  6427 	    break;
  6428         }
  6429     }
  6430     for (i = 31;  i >= 0;  i--) {
  6431         if (statsPtr->srcCount[i] > 0) {
  6432             maxSizeDecade = i;
  6433 	    break;
  6434         }
  6435     }
  6436     sum = 0;
  6437     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
  6438 	decadeHigh = (1 << (i+1)) - 1;
  6439 	sum += statsPtr->srcCount[i];
  6440         fprintf(stdout,	"	%10d		%8.0f%%\n",
  6441 		decadeHigh, (sum * 100.0) / statsPtr->numCompilations);
  6442     }
  6443 
  6444     fprintf(stdout, "\nByteCode sizes:\n");
  6445     fprintf(stdout, "	 Up to size		Percentage\n");
  6446     minSizeDecade = maxSizeDecade = 0;
  6447     for (i = 0;  i < 31;  i++) {
  6448         if (statsPtr->byteCodeCount[i] > 0) {
  6449 	    minSizeDecade = i;
  6450 	    break;
  6451         }
  6452     }
  6453     for (i = 31;  i >= 0;  i--) {
  6454         if (statsPtr->byteCodeCount[i] > 0) {
  6455             maxSizeDecade = i;
  6456 	    break;
  6457         }
  6458     }
  6459     sum = 0;
  6460     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
  6461 	decadeHigh = (1 << (i+1)) - 1;
  6462 	sum += statsPtr->byteCodeCount[i];
  6463         fprintf(stdout,	"	%10d		%8.0f%%\n",
  6464 		decadeHigh, (sum * 100.0) / statsPtr->numCompilations);
  6465     }
  6466 
  6467     fprintf(stdout, "\nByteCode longevity (excludes Current ByteCodes):\n");
  6468     fprintf(stdout, "	       Up to ms		Percentage\n");
  6469     minSizeDecade = maxSizeDecade = 0;
  6470     for (i = 0;  i < 31;  i++) {
  6471         if (statsPtr->lifetimeCount[i] > 0) {
  6472 	    minSizeDecade = i;
  6473 	    break;
  6474         }
  6475     }
  6476     for (i = 31;  i >= 0;  i--) {
  6477         if (statsPtr->lifetimeCount[i] > 0) {
  6478             maxSizeDecade = i;
  6479 	    break;
  6480         }
  6481     }
  6482     sum = 0;
  6483     for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
  6484 	decadeHigh = (1 << (i+1)) - 1;
  6485 	sum += statsPtr->lifetimeCount[i];
  6486         fprintf(stdout,	"	%12.3f		%8.0f%%\n",
  6487 		decadeHigh / 1000.0,
  6488 		(sum * 100.0) / statsPtr->numByteCodesFreed);
  6489     }
  6490 
  6491     /*
  6492      * Instruction counts.
  6493      */
  6494 
  6495     fprintf(stdout, "\nInstruction counts:\n");
  6496     for (i = 0;  i <= LAST_INST_OPCODE;  i++) {
  6497         if (statsPtr->instructionCount[i]) {
  6498             fprintf(stdout, "%20s %8ld %6.1f%%\n",
  6499 		    tclInstructionTable[i].name,
  6500 		    statsPtr->instructionCount[i],
  6501 		    (statsPtr->instructionCount[i]*100.0) / numInstructions);
  6502         }
  6503     }
  6504 
  6505     fprintf(stdout, "\nInstructions NEVER executed:\n");
  6506     for (i = 0;  i <= LAST_INST_OPCODE;  i++) {
  6507         if (statsPtr->instructionCount[i] == 0) {
  6508             fprintf(stdout, "%20s\n", tclInstructionTable[i].name);
  6509         }
  6510     }
  6511 
  6512 #ifdef TCL_MEM_DEBUG
  6513     fprintf(stdout, "\nHeap Statistics:\n");
  6514     TclDumpMemoryInfo(stdout);
  6515 #endif
  6516     fprintf(stdout, "\n----------------------------------------------------------------\n");
  6517     return TCL_OK;
  6518 }
  6519 #endif /* TCL_COMPILE_STATS */
  6520 
  6521 #ifdef TCL_COMPILE_DEBUG
  6522 /*
  6523  *----------------------------------------------------------------------
  6524  *
  6525  * StringForResultCode --
  6526  *
  6527  *	Procedure that returns a human-readable string representing a
  6528  *	Tcl result code such as TCL_ERROR. 
  6529  *
  6530  * Results:
  6531  *	If the result code is one of the standard Tcl return codes, the
  6532  *	result is a string representing that code such as "TCL_ERROR".
  6533  *	Otherwise, the result string is that code formatted as a
  6534  *	sequence of decimal digit characters. Note that the resulting
  6535  *	string must not be modified by the caller.
  6536  *
  6537  * Side effects:
  6538  *	None.
  6539  *
  6540  *----------------------------------------------------------------------
  6541  */
  6542 
  6543 static char *
  6544 StringForResultCode(result)
  6545     int result;			/* The Tcl result code for which to
  6546 				 * generate a string. */
  6547 {
  6548     static char buf[TCL_INTEGER_SPACE];
  6549     
  6550     if ((result >= TCL_OK) && (result <= TCL_CONTINUE)) {
  6551 	return resultStrings[result];
  6552     }
  6553     TclFormatInt(buf, result);
  6554     return buf;
  6555 }
  6556 #endif /* TCL_COMPILE_DEBUG */
  6557 
  6558 /*
  6559  * Local Variables:
  6560  * mode: c
  6561  * c-basic-offset: 4
  6562  * fill-column: 78
  6563  * End:
  6564  */
  6565