Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/generic/tclExecute.c @ 25

Last change on this file since 25 was 25, checked in by landauf, 16 years ago

added tcl to libs

File size: 222.8 KB
Line 
1/*
2 * tclExecute.c --
3 *
4 *      This file contains procedures that execute byte-compiled Tcl commands.
5 *
6 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
7 * Copyright (c) 1998-2000 by Scriptics Corporation.
8 * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
9 * Copyright (c) 2002-2005 by Miguel Sofer.
10 * Copyright (c) 2005-2007 by Donal K. Fellows.
11 * Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net>
12 *
13 * See the file "license.terms" for information on usage and redistribution of
14 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 *
16 * RCS: @(#) $Id: tclExecute.c,v 1.369 2008/03/18 18:52:07 msofer Exp $
17 */
18
19#include "tclInt.h"
20#include "tclCompile.h"
21#include "tommath.h"
22
23#include <math.h>
24#include <float.h>
25
26/*
27 * Hack to determine whether we may expect IEEE floating point. The hack is
28 * formally incorrect in that non-IEEE platforms might have the same precision
29 * and range, but VAX, IBM, and Cray do not; are there any other floating
30 * point units that we might care about?
31 */
32
33#if (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_MAX_EXP == 1024)
34#define IEEE_FLOATING_POINT
35#endif
36
37/*
38 * A mask (should be 2**n-1) that is used to work out when the bytecode engine
39 * should call Tcl_AsyncReady() to see whether there is a signal that needs
40 * handling.
41 */
42
43#ifndef ASYNC_CHECK_COUNT_MASK
44#   define ASYNC_CHECK_COUNT_MASK       63
45#endif /* !ASYNC_CHECK_COUNT_MASK */
46
47/*
48 * Boolean flag indicating whether the Tcl bytecode interpreter has been
49 * initialized.
50 */
51
52static int execInitialized = 0;
53TCL_DECLARE_MUTEX(execMutex)
54
55#ifdef TCL_COMPILE_DEBUG
56/*
57 * Variable that controls whether execution tracing is enabled and, if so,
58 * what level of tracing is desired:
59 *    0: no execution tracing
60 *    1: trace invocations of Tcl procs only
61 *    2: trace invocations of all (not compiled away) commands
62 *    3: display each instruction executed
63 * This variable is linked to the Tcl variable "tcl_traceExec".
64 */
65
66int tclTraceExec = 0;
67#endif
68
69/*
70 * Mapping from expression instruction opcodes to strings; used for error
71 * messages. Note that these entries must match the order and number of the
72 * expression opcodes (e.g., INST_LOR) in tclCompile.h.
73 *
74 * Does not include the string for INST_EXPON (and beyond), as that is
75 * disjoint for backward-compatability reasons.
76 */
77
78static const char *operatorStrings[] = {
79    "||", "&&", "|", "^", "&", "==", "!=", "<", ">", "<=", ">=", "<<", ">>",
80    "+", "-", "*", "/", "%", "+", "-", "~", "!",
81    "BUILTIN FUNCTION", "FUNCTION",
82    "", "", "", "", "", "", "", "", "eq", "ne"
83};
84
85/*
86 * Mapping from Tcl result codes to strings; used for error and debugging
87 * messages.
88 */
89
90#ifdef TCL_COMPILE_DEBUG
91static const char *resultStrings[] = {
92    "TCL_OK", "TCL_ERROR", "TCL_RETURN", "TCL_BREAK", "TCL_CONTINUE"
93};
94#endif
95
96/*
97 * These are used by evalstats to monitor object usage in Tcl.
98 */
99
100#ifdef TCL_COMPILE_STATS
101long            tclObjsAlloced = 0;
102long            tclObjsFreed = 0;
103long            tclObjsShared[TCL_MAX_SHARED_OBJ_STATS] = { 0, 0, 0, 0, 0 };
104#endif /* TCL_COMPILE_STATS */
105
106/*
107 * Support pre-8.5 bytecodes unless specifically requested otherwise.
108 */
109
110#ifndef TCL_SUPPORT_84_BYTECODE
111#define TCL_SUPPORT_84_BYTECODE 1
112#endif
113
114#if TCL_SUPPORT_84_BYTECODE
115/*
116 * We need to know the tclBuiltinFuncTable to support translation of pre-8.5
117 * math functions to the namespace-based ::tcl::mathfunc::op in 8.5+.
118 */
119
120typedef struct {
121    char *name;         /* Name of function. */
122    int numArgs;        /* Number of arguments for function. */
123} BuiltinFunc;
124
125/*
126 * Table describing the built-in math functions. Entries in this table are
127 * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's
128 * operand byte.
129 */
130
131static BuiltinFunc tclBuiltinFuncTable[] = {
132    {"acos", 1},
133    {"asin", 1},
134    {"atan", 1},
135    {"atan2", 2},
136    {"ceil", 1},
137    {"cos", 1},
138    {"cosh", 1},
139    {"exp", 1},
140    {"floor", 1},
141    {"fmod", 2},
142    {"hypot", 2},
143    {"log", 1},
144    {"log10", 1},
145    {"pow", 2},
146    {"sin", 1},
147    {"sinh", 1},
148    {"sqrt", 1},
149    {"tan", 1},
150    {"tanh", 1},
151    {"abs", 1},
152    {"double", 1},
153    {"int", 1},
154    {"rand", 0},
155    {"round", 1},
156    {"srand", 1},
157    {"wide", 1},
158    {0},
159};
160
161#define LAST_BUILTIN_FUNC       25
162#endif
163
164/*
165 * These variable-access macros have to coincide with those in tclVar.c
166 */
167
168#define VarHashGetValue(hPtr) \
169    ((Var *) ((char *)hPtr - TclOffset(VarInHash, entry)))
170
171static inline Var *
172VarHashCreateVar(
173    TclVarHashTable *tablePtr,
174    Tcl_Obj *key,
175    int *newPtr)
176{
177    Tcl_HashEntry *hPtr = Tcl_CreateHashEntry((Tcl_HashTable *) tablePtr,
178            (char *) key, newPtr);
179
180    if (!hPtr) {
181        return NULL;
182    }
183    return VarHashGetValue(hPtr);
184}
185
186#define VarHashFindVar(tablePtr, key) \
187    VarHashCreateVar((tablePtr), (key), NULL)
188
189/*
190 * The new macro for ending an instruction; note that a reasonable C-optimiser
191 * will resolve all branches at compile time. (result) is always a constant;
192 * the macro NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is resolved
193 * at runtime for variable (nCleanup).
194 *
195 * ARGUMENTS:
196 *    pcAdjustment: how much to increment pc
197 *    nCleanup: how many objects to remove from the stack
198 *    resultHandling: 0 indicates no object should be pushed on the stack;
199 *      otherwise, push objResultPtr. If (result < 0), objResultPtr already
200 *      has the correct reference count.
201 */
202
203#define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \
204    if (nCleanup == 0) {\
205        if (resultHandling != 0) {\
206            if ((resultHandling) > 0) {\
207                PUSH_OBJECT(objResultPtr);\
208            } else {\
209                *(++tosPtr) = objResultPtr;\
210            }\
211        } \
212        pc += (pcAdjustment);\
213        goto cleanup0;\
214    } else if (resultHandling != 0) {\
215        if ((resultHandling) > 0) {\
216            Tcl_IncrRefCount(objResultPtr);\
217        }\
218        pc += (pcAdjustment);\
219        switch (nCleanup) {\
220            case 1: goto cleanup1_pushObjResultPtr;\
221            case 2: goto cleanup2_pushObjResultPtr;\
222            default: Tcl_Panic("bad usage of macro NEXT_INST_F");\
223        }\
224    } else {\
225        pc += (pcAdjustment);\
226        switch (nCleanup) {\
227            case 1: goto cleanup1;\
228            case 2: goto cleanup2;\
229            default: Tcl_Panic("bad usage of macro NEXT_INST_F");\
230        }\
231    }
232
233#define NEXT_INST_V(pcAdjustment, nCleanup, resultHandling) \
234    pc += (pcAdjustment);\
235    cleanup = (nCleanup);\
236    if (resultHandling) {\
237        if ((resultHandling) > 0) {\
238            Tcl_IncrRefCount(objResultPtr);\
239        }\
240        goto cleanupV_pushObjResultPtr;\
241    } else {\
242        goto cleanupV;\
243    }
244
245/*
246 * Macros used to cache often-referenced Tcl evaluation stack information
247 * in local variables. Note that a DECACHE_STACK_INFO()-CACHE_STACK_INFO()
248 * pair must surround any call inside TclExecuteByteCode (and a few other
249 * procedures that use this scheme) that could result in a recursive call
250 * to TclExecuteByteCode.
251 */
252
253#define CACHE_STACK_INFO() \
254    checkInterp = 1
255
256#define DECACHE_STACK_INFO() \
257    esPtr->tosPtr = tosPtr
258
259/*
260 * Macros used to access items on the Tcl evaluation stack. PUSH_OBJECT
261 * increments the object's ref count since it makes the stack have another
262 * reference pointing to the object. However, POP_OBJECT does not decrement
263 * the ref count. This is because the stack may hold the only reference to the
264 * object, so the object would be destroyed if its ref count were decremented
265 * before the caller had a chance to, e.g., store it in a variable. It is the
266 * caller's responsibility to decrement the ref count when it is finished with
267 * an object.
268 *
269 * WARNING! It is essential that objPtr only appear once in the PUSH_OBJECT
270 * macro. The actual parameter might be an expression with side effects, and
271 * this ensures that it will be executed only once.
272 */
273
274#define PUSH_OBJECT(objPtr) \
275    Tcl_IncrRefCount(*(++tosPtr) = (objPtr))
276
277#define POP_OBJECT()    *(tosPtr--)
278
279#define OBJ_AT_TOS      *tosPtr
280
281#define OBJ_UNDER_TOS   *(tosPtr-1)
282
283#define OBJ_AT_DEPTH(n) *(tosPtr-(n))
284
285#define CURR_DEPTH      (tosPtr - initTosPtr)
286
287/*
288 * Macros used to trace instruction execution. The macros TRACE,
289 * TRACE_WITH_OBJ, and O2S are only used inside TclExecuteByteCode. O2S is
290 * only used in TRACE* calls to get a string from an object.
291 */
292
293#ifdef TCL_COMPILE_DEBUG
294#   define TRACE(a) \
295    if (traceInstructions) { \
296        fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, \
297                (int) CURR_DEPTH, \
298                (unsigned)(pc - codePtr->codeStart), \
299                GetOpcodeName(pc)); \
300        printf a; \
301    }
302#   define TRACE_APPEND(a) \
303    if (traceInstructions) { \
304        printf a; \
305    }
306#   define TRACE_WITH_OBJ(a, objPtr) \
307    if (traceInstructions) { \
308        fprintf(stdout, "%2d: %2d (%u) %s ", iPtr->numLevels, \
309                (int) CURR_DEPTH, \
310                (unsigned)(pc - codePtr->codeStart), \
311                GetOpcodeName(pc)); \
312        printf a; \
313        TclPrintObject(stdout, objPtr, 30); \
314        fprintf(stdout, "\n"); \
315    }
316#   define O2S(objPtr) \
317    (objPtr ? TclGetString(objPtr) : "")
318#else /* !TCL_COMPILE_DEBUG */
319#   define TRACE(a)
320#   define TRACE_APPEND(a)
321#   define TRACE_WITH_OBJ(a, objPtr)
322#   define O2S(objPtr)
323#endif /* TCL_COMPILE_DEBUG */
324
325/*
326 * DTrace instruction probe macros.
327 */
328
329#define TCL_DTRACE_INST_NEXT() \
330    if (TCL_DTRACE_INST_DONE_ENABLED()) {\
331        if (curInstName) {\
332            TCL_DTRACE_INST_DONE(curInstName, (int) CURR_DEPTH, tosPtr);\
333        }\
334        curInstName = tclInstructionTable[*pc].name;\
335        if (TCL_DTRACE_INST_START_ENABLED()) {\
336            TCL_DTRACE_INST_START(curInstName, (int) CURR_DEPTH, tosPtr);\
337        }\
338    } else if (TCL_DTRACE_INST_START_ENABLED()) {\
339        TCL_DTRACE_INST_START(tclInstructionTable[*pc].name, (int) CURR_DEPTH,\
340                tosPtr);\
341    }
342#define TCL_DTRACE_INST_LAST() \
343    if (TCL_DTRACE_INST_DONE_ENABLED() && curInstName) {\
344        TCL_DTRACE_INST_DONE(curInstName, (int) CURR_DEPTH, tosPtr);\
345    }
346
347/*
348 * Macro used in this file to save a function call for common uses of
349 * TclGetNumberFromObj(). The ANSI C "prototype" is:
350 *
351 * MODULE_SCOPE int GetNumberFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
352 *                      ClientData *ptrPtr, int *tPtr);
353 */
354
355#ifdef NO_WIDE_TYPE
356
357#define GetNumberFromObj(interp, objPtr, ptrPtr, tPtr)                  \
358    (((objPtr)->typePtr == &tclIntType)                                 \
359        ?       (*(tPtr) = TCL_NUMBER_LONG,                             \
360                *(ptrPtr) = (ClientData)                                \
361                    (&((objPtr)->internalRep.longValue)), TCL_OK) :     \
362    ((objPtr)->typePtr == &tclDoubleType)                               \
363        ?       (((TclIsNaN((objPtr)->internalRep.doubleValue))         \
364                    ?   (*(tPtr) = TCL_NUMBER_NAN)                      \
365                    :   (*(tPtr) = TCL_NUMBER_DOUBLE)),                 \
366                *(ptrPtr) = (ClientData)                                \
367                    (&((objPtr)->internalRep.doubleValue)), TCL_OK) :   \
368    ((((objPtr)->typePtr == NULL) && ((objPtr)->bytes == NULL)) ||      \
369    (((objPtr)->bytes != NULL) && ((objPtr)->length == 0)))             \
370        ? TCL_ERROR :                                                   \
371    TclGetNumberFromObj((interp), (objPtr), (ptrPtr), (tPtr)))
372
373#else
374
375#define GetNumberFromObj(interp, objPtr, ptrPtr, tPtr)                  \
376    (((objPtr)->typePtr == &tclIntType)                                 \
377        ?       (*(tPtr) = TCL_NUMBER_LONG,                             \
378                *(ptrPtr) = (ClientData)                                \
379                    (&((objPtr)->internalRep.longValue)), TCL_OK) :     \
380    ((objPtr)->typePtr == &tclWideIntType)                              \
381        ?       (*(tPtr) = TCL_NUMBER_WIDE,                             \
382                *(ptrPtr) = (ClientData)                                \
383                    (&((objPtr)->internalRep.wideValue)), TCL_OK) :     \
384    ((objPtr)->typePtr == &tclDoubleType)                               \
385        ?       (((TclIsNaN((objPtr)->internalRep.doubleValue))         \
386                    ?   (*(tPtr) = TCL_NUMBER_NAN)                      \
387                    :   (*(tPtr) = TCL_NUMBER_DOUBLE)),                 \
388                *(ptrPtr) = (ClientData)                                \
389                    (&((objPtr)->internalRep.doubleValue)), TCL_OK) :   \
390    ((((objPtr)->typePtr == NULL) && ((objPtr)->bytes == NULL)) ||      \
391    (((objPtr)->bytes != NULL) && ((objPtr)->length == 0)))             \
392        ? TCL_ERROR :                                                   \
393    TclGetNumberFromObj((interp), (objPtr), (ptrPtr), (tPtr)))
394
395#endif
396
397/*
398 * Macro used in this file to save a function call for common uses of
399 * Tcl_GetBooleanFromObj(). The ANSI C "prototype" is:
400 *
401 * MODULE_SCOPE int TclGetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
402 *                      int *boolPtr);
403 */
404
405#define TclGetBooleanFromObj(interp, objPtr, boolPtr)                   \
406    ((((objPtr)->typePtr == &tclIntType)                                \
407        || ((objPtr)->typePtr == &tclBooleanType))                      \
408        ? (*(boolPtr) = ((objPtr)->internalRep.longValue!=0), TCL_OK)   \
409        : Tcl_GetBooleanFromObj((interp), (objPtr), (boolPtr)))
410
411/*
412 * Macro used in this file to save a function call for common uses of
413 * Tcl_GetWideIntFromObj(). The ANSI C "prototype" is:
414 *
415 * MODULE_SCOPE int TclGetWideIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
416 *                      Tcl_WideInt *wideIntPtr);
417 */
418
419#ifdef NO_WIDE_TYPE
420#define TclGetWideIntFromObj(interp, objPtr, wideIntPtr)                \
421    (((objPtr)->typePtr == &tclIntType)                                 \
422        ? (*(wideIntPtr) = (Tcl_WideInt)                                \
423                ((objPtr)->internalRep.longValue), TCL_OK) :            \
424        Tcl_GetWideIntFromObj((interp), (objPtr), (wideIntPtr)))
425#else
426#define TclGetWideIntFromObj(interp, objPtr, wideIntPtr)                \
427    (((objPtr)->typePtr == &tclWideIntType)                             \
428        ? (*(wideIntPtr) = (objPtr)->internalRep.wideValue, TCL_OK) :   \
429    ((objPtr)->typePtr == &tclIntType)                                  \
430        ? (*(wideIntPtr) = (Tcl_WideInt)                                \
431                ((objPtr)->internalRep.longValue), TCL_OK) :            \
432        Tcl_GetWideIntFromObj((interp), (objPtr), (wideIntPtr)))
433#endif
434
435/*
436 * Macro used to make the check for type overflow more mnemonic. This works by
437 * comparing sign bits; the rest of the word is irrelevant. The ANSI C
438 * "prototype" (where inttype_t is any integer type) is:
439 *
440 * MODULE_SCOPE int Overflowing(inttype_t a, inttype_t b, inttype_t sum);
441 *
442 * Check first the condition most likely to fail in usual code (at least for
443 * usage in [incr]: do the first summand and the sum have != signs?
444 */
445
446#define Overflowing(a,b,sum) ((((a)^(sum)) < 0) && (((a)^(b)) >= 0))
447
448/*
449 * Custom object type only used in this file; values of its type should never
450 * be seen by user scripts.
451 */
452
453static Tcl_ObjType dictIteratorType = {
454    "dictIterator",
455    NULL, NULL, NULL, NULL
456};
457
458/*
459 * Auxiliary tables used to compute powers of small integers
460 */
461
462#if (LONG_MAX == 0x7fffffff)
463
464/*
465 * Maximum base that, when raised to powers 2, 3, ... 8, fits in a 32-bit
466 * signed integer
467 */
468
469static const long MaxBase32[7] = {46340, 1290, 215, 73, 35, 21, 14};
470
471/*
472 * Table giving 3, 4, ..., 11, raised to the powers 9, 10, ..., as far as they
473 * fit in a 32-bit signed integer. Exp32Index[i] gives the starting index of
474 * powers of i+3; Exp32Value[i] gives the corresponding powers.
475 */
476
477static const unsigned short Exp32Index[] = {
478    0, 11, 18, 23, 26, 29, 31, 32, 33
479};
480static const long Exp32Value[] = {
481    19683, 59049, 177147, 531441, 1594323, 4782969, 14348907, 43046721,
482    129140163, 387420489, 1162261467, 262144, 1048576, 4194304,
483    16777216, 67108864, 268435456, 1073741824, 1953125, 9765625,
484    48828125, 244140625, 1220703125, 10077696, 60466176, 362797056,
485    40353607, 282475249, 1977326743, 134217728, 1073741824, 387420489,
486    1000000000
487};
488
489#endif /* LONG_MAX == 0x7fffffff -- 32 bit machine */
490
491#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
492
493/*
494 * Maximum base that, when raised to powers 2, 3, ..., 16, fits in a
495 * Tcl_WideInt.
496 */
497
498static Tcl_WideInt MaxBaseWide[15];
499
500/*
501 *Table giving 3, 4, ..., 13 raised to powers greater than 16 when the
502 * results fit in a 64-bit signed integer.
503 */
504
505static const unsigned short Exp64Index[] = {
506    0, 23, 38, 49, 57, 63, 67, 70, 72, 74, 75, 76
507};
508static const Tcl_WideInt Exp64Value[] = {
509    (Tcl_WideInt)243*243*243*3*3,
510    (Tcl_WideInt)243*243*243*3*3*3,
511    (Tcl_WideInt)243*243*243*3*3*3*3,
512    (Tcl_WideInt)243*243*243*243,
513    (Tcl_WideInt)243*243*243*243*3,
514    (Tcl_WideInt)243*243*243*243*3*3,
515    (Tcl_WideInt)243*243*243*243*3*3*3,
516    (Tcl_WideInt)243*243*243*243*3*3*3*3,
517    (Tcl_WideInt)243*243*243*243*243,
518    (Tcl_WideInt)243*243*243*243*243*3,
519    (Tcl_WideInt)243*243*243*243*243*3*3,
520    (Tcl_WideInt)243*243*243*243*243*3*3*3,
521    (Tcl_WideInt)243*243*243*243*243*3*3*3*3,
522    (Tcl_WideInt)243*243*243*243*243*243,
523    (Tcl_WideInt)243*243*243*243*243*243*3,
524    (Tcl_WideInt)243*243*243*243*243*243*3*3,
525    (Tcl_WideInt)243*243*243*243*243*243*3*3*3,
526    (Tcl_WideInt)243*243*243*243*243*243*3*3*3*3,
527    (Tcl_WideInt)243*243*243*243*243*243*243,
528    (Tcl_WideInt)243*243*243*243*243*243*243*3,
529    (Tcl_WideInt)243*243*243*243*243*243*243*3*3,
530    (Tcl_WideInt)243*243*243*243*243*243*243*3*3*3,
531    (Tcl_WideInt)243*243*243*243*243*243*243*3*3*3*3,
532    (Tcl_WideInt)1024*1024*1024*4*4,
533    (Tcl_WideInt)1024*1024*1024*4*4*4,
534    (Tcl_WideInt)1024*1024*1024*4*4*4*4,
535    (Tcl_WideInt)1024*1024*1024*1024,
536    (Tcl_WideInt)1024*1024*1024*1024*4,
537    (Tcl_WideInt)1024*1024*1024*1024*4*4,
538    (Tcl_WideInt)1024*1024*1024*1024*4*4*4,
539    (Tcl_WideInt)1024*1024*1024*1024*4*4*4*4,
540    (Tcl_WideInt)1024*1024*1024*1024*1024,
541    (Tcl_WideInt)1024*1024*1024*1024*1024*4,
542    (Tcl_WideInt)1024*1024*1024*1024*1024*4*4,
543    (Tcl_WideInt)1024*1024*1024*1024*1024*4*4*4,
544    (Tcl_WideInt)1024*1024*1024*1024*1024*4*4*4*4,
545    (Tcl_WideInt)1024*1024*1024*1024*1024*1024,
546    (Tcl_WideInt)1024*1024*1024*1024*1024*1024*4,
547    (Tcl_WideInt)3125*3125*3125*5*5,
548    (Tcl_WideInt)3125*3125*3125*5*5*5,
549    (Tcl_WideInt)3125*3125*3125*5*5*5*5,
550    (Tcl_WideInt)3125*3125*3125*3125,
551    (Tcl_WideInt)3125*3125*3125*3125*5,
552    (Tcl_WideInt)3125*3125*3125*3125*5*5,
553    (Tcl_WideInt)3125*3125*3125*3125*5*5*5,
554    (Tcl_WideInt)3125*3125*3125*3125*5*5*5*5,
555    (Tcl_WideInt)3125*3125*3125*3125*3125,
556    (Tcl_WideInt)3125*3125*3125*3125*3125*5,
557    (Tcl_WideInt)3125*3125*3125*3125*3125*5*5,
558    (Tcl_WideInt)7776*7776*7776*6*6,
559    (Tcl_WideInt)7776*7776*7776*6*6*6,
560    (Tcl_WideInt)7776*7776*7776*6*6*6*6,
561    (Tcl_WideInt)7776*7776*7776*7776,
562    (Tcl_WideInt)7776*7776*7776*7776*6,
563    (Tcl_WideInt)7776*7776*7776*7776*6*6,
564    (Tcl_WideInt)7776*7776*7776*7776*6*6*6,
565    (Tcl_WideInt)7776*7776*7776*7776*6*6*6*6,
566    (Tcl_WideInt)16807*16807*16807*7*7,
567    (Tcl_WideInt)16807*16807*16807*7*7*7,
568    (Tcl_WideInt)16807*16807*16807*7*7*7*7,
569    (Tcl_WideInt)16807*16807*16807*16807,
570    (Tcl_WideInt)16807*16807*16807*16807*7,
571    (Tcl_WideInt)16807*16807*16807*16807*7*7,
572    (Tcl_WideInt)32768*32768*32768*8*8,
573    (Tcl_WideInt)32768*32768*32768*8*8*8,
574    (Tcl_WideInt)32768*32768*32768*8*8*8*8,
575    (Tcl_WideInt)32768*32768*32768*32768,
576    (Tcl_WideInt)59049*59049*59049*9*9,
577    (Tcl_WideInt)59049*59049*59049*9*9*9,
578    (Tcl_WideInt)59049*59049*59049*9*9*9*9,
579    (Tcl_WideInt)100000*100000*100000*10*10,
580    (Tcl_WideInt)100000*100000*100000*10*10*10,
581    (Tcl_WideInt)161051*161051*161051*11*11,
582    (Tcl_WideInt)161051*161051*161051*11*11*11,
583    (Tcl_WideInt)248832*248832*248832*12*12,
584    (Tcl_WideInt)371293*371293*371293*13*13
585};
586
587#endif
588
589/*
590 * Declarations for local procedures to this file:
591 */
592
593#ifdef TCL_COMPILE_STATS
594static int              EvalStatsCmd(ClientData clientData,
595                            Tcl_Interp *interp, int objc,
596                            Tcl_Obj *const objv[]);
597#endif /* TCL_COMPILE_STATS */
598#ifdef TCL_COMPILE_DEBUG
599static char *           GetOpcodeName(unsigned char *pc);
600static void             PrintByteCodeInfo(ByteCode *codePtr);
601static const char *     StringForResultCode(int result);
602static void             ValidatePcAndStackTop(ByteCode *codePtr,
603                            unsigned char *pc, int stackTop,
604                            int stackLowerBound, int checkStack);
605#endif /* TCL_COMPILE_DEBUG */
606static void             DeleteExecStack(ExecStack *esPtr);
607static void             DupExprCodeInternalRep(Tcl_Obj *srcPtr,
608                            Tcl_Obj *copyPtr);
609static void             FreeExprCodeInternalRep(Tcl_Obj *objPtr);
610static ExceptionRange * GetExceptRangeForPc(unsigned char *pc, int catchOnly,
611                            ByteCode *codePtr);
612static const char *     GetSrcInfoForPc(unsigned char *pc, ByteCode *codePtr,
613                            int *lengthPtr);
614static Tcl_Obj **       GrowEvaluationStack(ExecEnv *eePtr, int growth,
615                            int move);
616static void             IllegalExprOperandType(Tcl_Interp *interp,
617                            unsigned char *pc, Tcl_Obj *opndPtr);
618static void             InitByteCodeExecution(Tcl_Interp *interp);
619/* Useful elsewhere, make available in tclInt.h or stubs? */
620static Tcl_Obj **       StackAllocWords(Tcl_Interp *interp, int numWords);
621static Tcl_Obj **       StackReallocWords(Tcl_Interp *interp, int numWords);
622
623/*
624 * The structure below defines a bytecode Tcl object type to hold the
625 * compiled bytecode for Tcl expressions.
626 */
627
628static Tcl_ObjType exprCodeType = {
629    "exprcode",
630    FreeExprCodeInternalRep,    /* freeIntRepProc */
631    DupExprCodeInternalRep,     /* dupIntRepProc */
632    NULL,                       /* updateStringProc */
633    NULL                        /* setFromAnyProc */
634};
635
636/*
637 *----------------------------------------------------------------------
638 *
639 * InitByteCodeExecution --
640 *
641 *      This procedure is called once to initialize the Tcl bytecode
642 *      interpreter.
643 *
644 * Results:
645 *      None.
646 *
647 * Side effects:
648 *      This procedure initializes the array of instruction names. If
649 *      compiling with the TCL_COMPILE_STATS flag, it initializes the array
650 *      that counts the executions of each instruction and it creates the
651 *      "evalstats" command. It also establishes the link between the Tcl
652 *      "tcl_traceExec" and C "tclTraceExec" variables.
653 *
654 *----------------------------------------------------------------------
655 */
656
657static void
658InitByteCodeExecution(
659    Tcl_Interp *interp)         /* Interpreter for which the Tcl variable
660                                 * "tcl_traceExec" is linked to control
661                                 * instruction tracing. */
662{
663#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
664    int i, j;
665    Tcl_WideInt w, x;
666#endif
667#ifdef TCL_COMPILE_DEBUG
668    if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec,
669            TCL_LINK_INT) != TCL_OK) {
670        Tcl_Panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
671    }
672#endif
673#ifdef TCL_COMPILE_STATS
674    Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd, NULL, NULL);
675#endif /* TCL_COMPILE_STATS */
676#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
677
678    /*
679     * Fill in a table of what base can be raised to powers 2, 3, ... 16
680     * without overflowing a Tcl_WideInt
681     */
682
683    for (i = 2; i <= 16; ++i) {
684        /*
685         * Compute an initial guess in floating point.
686         */
687
688        w = (Tcl_WideInt) pow((double) LLONG_MAX, 1.0 / i) + 1;
689
690        /*
691         * Correct the guess if it's too high.
692         */
693
694        for (;;) {
695            x = LLONG_MAX;
696            for (j = 0; j < i; ++j) {
697                x /= w;
698            }
699            if (x == 1) {
700                break;
701            }
702            --w;
703        }
704
705        MaxBaseWide[i-2] = w;
706    }
707#endif
708}
709
710/*
711 *----------------------------------------------------------------------
712 *
713 * TclCreateExecEnv --
714 *
715 *      This procedure creates a new execution environment for Tcl bytecode
716 *      execution. An ExecEnv points to a Tcl evaluation stack. An ExecEnv is
717 *      typically created once for each Tcl interpreter (Interp structure) and
718 *      recursively passed to TclExecuteByteCode to execute ByteCode sequences
719 *      for nested commands.
720 *
721 * Results:
722 *      A newly allocated ExecEnv is returned. This points to an empty
723 *      evaluation stack of the standard initial size.
724 *
725 * Side effects:
726 *      The bytecode interpreter is also initialized here, as this procedure
727 *      will be called before any call to TclExecuteByteCode.
728 *
729 *----------------------------------------------------------------------
730 */
731
732#define TCL_STACK_INITIAL_SIZE 2000
733
734ExecEnv *
735TclCreateExecEnv(
736    Tcl_Interp *interp)         /* Interpreter for which the execution
737                                 * environment is being created. */
738{
739    ExecEnv *eePtr = (ExecEnv *) ckalloc(sizeof(ExecEnv));
740    ExecStack *esPtr = (ExecStack *) ckalloc(sizeof(ExecStack)
741            + (size_t) (TCL_STACK_INITIAL_SIZE-1) * sizeof(Tcl_Obj *));
742
743    eePtr->execStackPtr = esPtr;
744    TclNewBooleanObj(eePtr->constants[0], 0);
745    Tcl_IncrRefCount(eePtr->constants[0]);
746    TclNewBooleanObj(eePtr->constants[1], 1);
747    Tcl_IncrRefCount(eePtr->constants[1]);
748
749    esPtr->prevPtr = NULL;
750    esPtr->nextPtr = NULL;
751    esPtr->markerPtr = NULL;
752    esPtr->endPtr = &esPtr->stackWords[TCL_STACK_INITIAL_SIZE-1];
753    esPtr->tosPtr = &esPtr->stackWords[-1];
754
755    Tcl_MutexLock(&execMutex);
756    if (!execInitialized) {
757        TclInitAuxDataTypeTable();
758        InitByteCodeExecution(interp);
759        execInitialized = 1;
760    }
761    Tcl_MutexUnlock(&execMutex);
762
763    return eePtr;
764}
765#undef TCL_STACK_INITIAL_SIZE
766
767/*
768 *----------------------------------------------------------------------
769 *
770 * TclDeleteExecEnv --
771 *
772 *      Frees the storage for an ExecEnv.
773 *
774 * Results:
775 *      None.
776 *
777 * Side effects:
778 *      Storage for an ExecEnv and its contained storage (e.g. the evaluation
779 *      stack) is freed.
780 *
781 *----------------------------------------------------------------------
782 */
783
784static void
785DeleteExecStack(
786    ExecStack *esPtr)
787{
788    if (esPtr->markerPtr) {
789        Tcl_Panic("freeing an execStack which is still in use");
790    }
791
792    if (esPtr->prevPtr) {
793        esPtr->prevPtr->nextPtr = esPtr->nextPtr;
794    }
795    if (esPtr->nextPtr) {
796        esPtr->nextPtr->prevPtr = esPtr->prevPtr;
797    }
798    ckfree((char *) esPtr);
799}
800
801void
802TclDeleteExecEnv(
803    ExecEnv *eePtr)             /* Execution environment to free. */
804{
805    ExecStack *esPtr = eePtr->execStackPtr, *tmpPtr;
806
807    /*
808     * Delete all stacks in this exec env.
809     */
810
811    while (esPtr->nextPtr) {
812        esPtr = esPtr->nextPtr;
813    }
814    while (esPtr) {
815        tmpPtr = esPtr;
816        esPtr = tmpPtr->prevPtr;
817        DeleteExecStack(tmpPtr);
818    }
819
820    TclDecrRefCount(eePtr->constants[0]);
821    TclDecrRefCount(eePtr->constants[1]);
822    ckfree((char *) eePtr);
823}
824
825/*
826 *----------------------------------------------------------------------
827 *
828 * TclFinalizeExecution --
829 *
830 *      Finalizes the execution environment setup so that it can be later
831 *      reinitialized.
832 *
833 * Results:
834 *      None.
835 *
836 * Side effects:
837 *      After this call, the next time TclCreateExecEnv will be called it will
838 *      call InitByteCodeExecution.
839 *
840 *----------------------------------------------------------------------
841 */
842
843void
844TclFinalizeExecution(void)
845{
846    Tcl_MutexLock(&execMutex);
847    execInitialized = 0;
848    Tcl_MutexUnlock(&execMutex);
849    TclFinalizeAuxDataTypeTable();
850}
851
852/*
853 * Auxiliary code to insure that GrowEvaluationStack always returns correctly
854 * aligned memory. This assumes that TCL_ALLOCALIGN is a multiple of the
855 * wordsize 'sizeof(Tcl_Obj *)'.
856 */
857
858#define WALLOCALIGN \
859    (TCL_ALLOCALIGN/sizeof(Tcl_Obj *))
860
861static inline int
862OFFSET(
863    void *ptr)
864{
865    int mask = TCL_ALLOCALIGN-1;
866    int base = PTR2INT(ptr) & mask;
867    return (TCL_ALLOCALIGN - base)/sizeof(Tcl_Obj**);
868}
869
870#define MEMSTART(markerPtr) \
871    ((markerPtr) + OFFSET(markerPtr))
872
873
874/*
875 *----------------------------------------------------------------------
876 *
877 * GrowEvaluationStack --
878 *
879 *      This procedure grows a Tcl evaluation stack stored in an ExecEnv,
880 *      copying over the words since the last mark if so requested. A mark is
881 *      set at the beginning of the new area when no copying is requested.
882 *
883 * Results:
884 *      Returns a pointer to the first usable word in the (possibly) grown
885 *      stack.
886 *
887 * Side effects:
888 *      The size of the evaluation stack may be grown, a marker is set
889 *
890 *----------------------------------------------------------------------
891 */
892
893static Tcl_Obj **
894GrowEvaluationStack(
895    ExecEnv *eePtr,             /* Points to the ExecEnv with an evaluation
896                                 * stack to enlarge. */
897    int growth,                 /* How much larger than the current used
898                                 * size. */
899    int move)                   /* 1 if move words since last marker. */
900{
901    ExecStack *esPtr = eePtr->execStackPtr, *oldPtr = NULL;
902    int newBytes, newElems, currElems;
903    int needed = growth - (esPtr->endPtr - esPtr->tosPtr);
904    Tcl_Obj **markerPtr = esPtr->markerPtr, **memStart;
905
906    if (move) {
907        if (!markerPtr) {
908            Tcl_Panic("STACK: Reallocating with no previous alloc");
909        }
910        if (needed <= 0) {
911            return MEMSTART(markerPtr);
912        }
913    } else {
914        Tcl_Obj **tmpMarkerPtr = esPtr->tosPtr + 1;
915        int offset = OFFSET(tmpMarkerPtr);
916
917        if (needed + offset < 0) {
918            /*
919             * Put a marker pointing to the previous marker in this stack, and
920             * store it in esPtr as the current marker. Return a pointer to
921             * the start of aligned memory.
922             */
923
924            esPtr->markerPtr = tmpMarkerPtr;
925            memStart = tmpMarkerPtr + offset; 
926            esPtr->tosPtr = memStart - 1;
927            *esPtr->markerPtr = (Tcl_Obj *) markerPtr;
928            return memStart;
929        }
930    }
931
932    /*
933     * Reset move to hold the number of words to be moved to new stack (if
934     * any) and growth to hold the complete stack requirements: add the marker
935     * and maximal possible offset.
936     */
937
938    if (move) {
939        move = esPtr->tosPtr - MEMSTART(markerPtr) + 1;
940    }
941    needed = growth + move + WALLOCALIGN - 1;
942
943    /*
944     * Check if there is enough room in the next stack (if there is one, it
945     * should be both empty and the last one!)
946     */
947
948    if (esPtr->nextPtr) {
949        oldPtr = esPtr;
950        esPtr = oldPtr->nextPtr;
951        currElems = esPtr->endPtr - &esPtr->stackWords[-1];
952        if (esPtr->markerPtr || (esPtr->tosPtr != &esPtr->stackWords[-1])) {
953            Tcl_Panic("STACK: Stack after current is in use");
954        }
955        if (esPtr->nextPtr) {
956            Tcl_Panic("STACK: Stack after current is not last");
957        }
958        if (needed <= currElems) {
959            goto newStackReady;
960        }
961        DeleteExecStack(esPtr);
962        esPtr = oldPtr;
963    } else {
964        currElems = esPtr->endPtr - &esPtr->stackWords[-1];
965    }
966
967    /*
968     * We need to allocate a new stack! It needs to store 'growth' words,
969     * including the elements to be copied over and the new marker.
970     */
971
972    newElems = 2*currElems;
973    while (needed > newElems) {
974        newElems *= 2;
975    }
976    newBytes = sizeof (ExecStack) + (newElems-1) * sizeof(Tcl_Obj *);
977
978    oldPtr = esPtr;
979    esPtr = (ExecStack *) ckalloc(newBytes);
980
981    oldPtr->nextPtr = esPtr;
982    esPtr->prevPtr = oldPtr;
983    esPtr->nextPtr = NULL;
984    esPtr->endPtr = &esPtr->stackWords[newElems-1];
985
986  newStackReady:
987    eePtr->execStackPtr = esPtr;
988
989    /*
990     * Store a NULL marker at the beginning of the stack, to indicate that
991     * this is the first marker in this stack and that rewinding to here
992     * should actually be a return to the previous stack.
993     */
994
995    esPtr->stackWords[0] = NULL;
996    esPtr->markerPtr = &esPtr->stackWords[0];
997    memStart = MEMSTART(esPtr->markerPtr);
998    esPtr->tosPtr = memStart - 1;
999   
1000    if (move) {
1001        memcpy(memStart, MEMSTART(markerPtr), move*sizeof(Tcl_Obj *));
1002        esPtr->tosPtr += move;
1003        oldPtr->markerPtr = (Tcl_Obj **) *markerPtr;
1004        oldPtr->tosPtr = markerPtr-1;
1005    }
1006
1007    /*
1008     * Free the old stack if it is now unused.
1009     */
1010
1011    if (!oldPtr->markerPtr) {
1012        DeleteExecStack(oldPtr);
1013    }
1014
1015    return memStart;
1016}
1017
1018/*
1019 *--------------------------------------------------------------
1020 *
1021 * TclStackAlloc, TclStackRealloc, TclStackFree --
1022 *
1023 *      Allocate memory from the execution stack; it has to be returned later
1024 *      with a call to TclStackFree.
1025 *
1026 * Results:
1027 *      A pointer to the first byte allocated, or panics if the allocation did
1028 *      not succeed.
1029 *
1030 * Side effects:
1031 *      The execution stack may be grown.
1032 *
1033 *--------------------------------------------------------------
1034 */
1035
1036static Tcl_Obj **
1037StackAllocWords(
1038    Tcl_Interp *interp,
1039    int numWords)
1040{
1041    /*
1042     * Note that GrowEvaluationStack sets a marker in the stack. This marker
1043     * is read when rewinding, e.g., by TclStackFree.
1044     */
1045
1046    Interp *iPtr = (Interp *) interp;
1047    ExecEnv *eePtr = iPtr->execEnvPtr;
1048    Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 0);
1049
1050    eePtr->execStackPtr->tosPtr += numWords;
1051    return resPtr;
1052}
1053
1054static Tcl_Obj **
1055StackReallocWords(
1056    Tcl_Interp *interp,
1057    int numWords)
1058{
1059    Interp *iPtr = (Interp *) interp;
1060    ExecEnv *eePtr = iPtr->execEnvPtr;
1061    Tcl_Obj **resPtr = GrowEvaluationStack(eePtr, numWords, 1);
1062
1063    eePtr->execStackPtr->tosPtr += numWords;
1064    return resPtr;
1065}
1066
1067void
1068TclStackFree(
1069    Tcl_Interp *interp,
1070    void *freePtr)
1071{
1072    Interp *iPtr = (Interp *) interp;
1073    ExecEnv *eePtr;
1074    ExecStack *esPtr;
1075    Tcl_Obj **markerPtr;
1076
1077    if (iPtr == NULL || iPtr->execEnvPtr == NULL) {
1078        Tcl_Free((char *) freePtr);
1079        return;
1080    }
1081
1082    /*
1083     * Rewind the stack to the previous marker position. The current marker,
1084     * as set in the last call to GrowEvaluationStack, contains a pointer to
1085     * the previous marker.
1086     */
1087
1088    eePtr = iPtr->execEnvPtr;
1089    esPtr = eePtr->execStackPtr;
1090    markerPtr = esPtr->markerPtr;
1091
1092    if (MEMSTART(markerPtr) != (Tcl_Obj **)freePtr) {
1093        Tcl_Panic("TclStackFree: incorrect freePtr. Call out of sequence?");
1094    }
1095
1096    esPtr->tosPtr = markerPtr-1;
1097    esPtr->markerPtr = (Tcl_Obj **) *markerPtr;
1098    if (*markerPtr) {
1099        return;
1100    }
1101
1102    /*
1103     * Return to previous stack.
1104     */
1105
1106    esPtr->tosPtr = &esPtr->stackWords[-1];
1107    if (esPtr->prevPtr) {
1108        eePtr->execStackPtr = esPtr->prevPtr;
1109    }
1110    if (esPtr->nextPtr) {
1111        if (!esPtr->prevPtr) {
1112            eePtr->execStackPtr = esPtr->nextPtr;
1113        }
1114        DeleteExecStack(esPtr);
1115    }
1116}
1117
1118void *
1119TclStackAlloc(
1120    Tcl_Interp *interp,
1121    int numBytes)
1122{
1123    Interp *iPtr = (Interp *) interp;
1124    int numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
1125
1126    if (iPtr == NULL || iPtr->execEnvPtr == NULL) {
1127        return (void *) Tcl_Alloc(numBytes);
1128    }
1129
1130    return (void *) StackAllocWords(interp, numWords);
1131}
1132
1133void *
1134TclStackRealloc(
1135    Tcl_Interp *interp,
1136    void *ptr,
1137    int numBytes)
1138{
1139    Interp *iPtr = (Interp *) interp;
1140    ExecEnv *eePtr;
1141    ExecStack *esPtr;
1142    Tcl_Obj **markerPtr;
1143    int numWords;
1144
1145    if (iPtr == NULL || iPtr->execEnvPtr == NULL) {
1146        return (void *) Tcl_Realloc((char *) ptr, numBytes);
1147    }
1148
1149    eePtr = iPtr->execEnvPtr;
1150    esPtr = eePtr->execStackPtr;
1151    markerPtr = esPtr->markerPtr;
1152
1153    if (MEMSTART(markerPtr) != (Tcl_Obj **)ptr) {
1154        Tcl_Panic("TclStackRealloc: incorrect ptr. Call out of sequence?");
1155    }
1156
1157    numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
1158    return (void *) StackReallocWords(interp, numWords);
1159}
1160
1161/*
1162 *--------------------------------------------------------------
1163 *
1164 * Tcl_ExprObj --
1165 *
1166 *      Evaluate an expression in a Tcl_Obj.
1167 *
1168 * Results:
1169 *      A standard Tcl object result. If the result is other than TCL_OK, then
1170 *      the interpreter's result contains an error message. If the result is
1171 *      TCL_OK, then a pointer to the expression's result value object is
1172 *      stored in resultPtrPtr. In that case, the object's ref count is
1173 *      incremented to reflect the reference returned to the caller; the
1174 *      caller is then responsible for the resulting object and must, for
1175 *      example, decrement the ref count when it is finished with the object.
1176 *
1177 * Side effects:
1178 *      Any side effects caused by subcommands in the expression, if any. The
1179 *      interpreter result is not modified unless there is an error.
1180 *
1181 *--------------------------------------------------------------
1182 */
1183
1184int
1185Tcl_ExprObj(
1186    Tcl_Interp *interp,         /* Context in which to evaluate the
1187                                 * expression. */
1188    register Tcl_Obj *objPtr,   /* Points to Tcl object containing expression
1189                                 * to evaluate. */
1190    Tcl_Obj **resultPtrPtr)     /* Where the Tcl_Obj* that is the expression
1191                                 * result is stored if no errors occur. */
1192{
1193    Interp *iPtr = (Interp *) interp;
1194    CompileEnv compEnv;         /* Compilation environment structure allocated
1195                                 * in frame. */
1196    register ByteCode *codePtr = NULL;
1197                                /* Tcl Internal type of bytecode. Initialized
1198                                 * to avoid compiler warning. */
1199    int result;
1200
1201    /*
1202     * Execute the expression after first saving the interpreter's result.
1203     */
1204
1205    Tcl_Obj *saveObjPtr = Tcl_GetObjResult(interp);
1206    Tcl_IncrRefCount(saveObjPtr);
1207
1208    /*
1209     * Get the expression ByteCode from the object. If it exists, make sure it
1210     * is valid in the current context.
1211     */
1212    if (objPtr->typePtr == &exprCodeType) {
1213        Namespace *namespacePtr = iPtr->varFramePtr->nsPtr;
1214
1215        codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
1216        if (((Interp *) *codePtr->interpHandle != iPtr)
1217                || (codePtr->compileEpoch != iPtr->compileEpoch)
1218                || (codePtr->nsPtr != namespacePtr)
1219                || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {
1220            objPtr->typePtr->freeIntRepProc(objPtr);
1221            objPtr->typePtr = (Tcl_ObjType *) NULL;
1222        }
1223    }
1224    if (objPtr->typePtr != &exprCodeType) {
1225        /*
1226         * TIP #280: No invoker (yet) - Expression compilation.
1227         */
1228
1229        int length;
1230        const char *string = TclGetStringFromObj(objPtr, &length);
1231
1232        TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0);
1233        TclCompileExpr(interp, string, length, &compEnv, 0);
1234
1235        /*
1236         * Successful compilation. If the expression yielded no instructions,
1237         * push an zero object as the expression's result.
1238         */
1239
1240        if (compEnv.codeNext == compEnv.codeStart) {
1241            TclEmitPush(TclRegisterNewLiteral(&compEnv, "0", 1),
1242                    &compEnv);
1243        }
1244
1245        /*
1246         * Add a "done" instruction as the last instruction and change the
1247         * object into a ByteCode object. Ownership of the literal objects and
1248         * aux data items is given to the ByteCode object.
1249         */
1250
1251        TclEmitOpcode(INST_DONE, &compEnv);
1252        TclInitByteCodeObj(objPtr, &compEnv);
1253        objPtr->typePtr = &exprCodeType;
1254        TclFreeCompileEnv(&compEnv);
1255        codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
1256#ifdef TCL_COMPILE_DEBUG
1257        if (tclTraceCompile == 2) {
1258            TclPrintByteCodeObj(interp, objPtr);
1259            fflush(stdout);
1260        }
1261#endif /* TCL_COMPILE_DEBUG */
1262    }
1263
1264    Tcl_ResetResult(interp);
1265
1266    /*
1267     * Increment the code's ref count while it is being executed. If
1268     * afterwards no references to it remain, free the code.
1269     */
1270
1271    codePtr->refCount++;
1272    result = TclExecuteByteCode(interp, codePtr);
1273    codePtr->refCount--;
1274    if (codePtr->refCount <= 0) {
1275        TclCleanupByteCode(codePtr);
1276    }
1277
1278    /*
1279     * If the expression evaluated successfully, store a pointer to its value
1280     * object in resultPtrPtr then restore the old interpreter result. We
1281     * increment the object's ref count to reflect the reference that we are
1282     * returning to the caller. We also decrement the ref count of the
1283     * interpreter's result object after calling Tcl_SetResult since we next
1284     * store into that field directly.
1285     */
1286
1287    if (result == TCL_OK) {
1288        *resultPtrPtr = iPtr->objResultPtr;
1289        Tcl_IncrRefCount(iPtr->objResultPtr);
1290
1291        Tcl_SetObjResult(interp, saveObjPtr);
1292    }
1293    TclDecrRefCount(saveObjPtr);
1294    return result;
1295}
1296
1297/*
1298 *----------------------------------------------------------------------
1299 *
1300 * DupExprCodeInternalRep --
1301 *
1302 *      Part of the Tcl object type implementation for Tcl expression
1303 *      bytecode.  We do not copy the bytecode intrep.  Instead, we
1304 *      return without setting copyPtr->typePtr, so the copy is a plain
1305 *      string copy of the expression value, and if it is to be used
1306 *      as a compiled expression, it will just need a recompile.
1307 *
1308 *      This makes sense, because with Tcl's copy-on-write practices,
1309 *      the usual (only?) time Tcl_DuplicateObj() will be called is
1310 *      when the copy is about to be modified, which would invalidate
1311 *      any copied bytecode anyway.  The only reason it might make sense
1312 *      to copy the bytecode is if we had some modifying routines that
1313 *      operated directly on the intrep, like we do for lists and dicts.
1314 *
1315 * Results:
1316 *      None.
1317 *
1318 * Side effects:
1319 *      None.
1320 *
1321 *----------------------------------------------------------------------
1322 */
1323
1324static void
1325DupExprCodeInternalRep(
1326    Tcl_Obj *srcPtr,
1327    Tcl_Obj *copyPtr)
1328{
1329    return;
1330}
1331
1332/*
1333 *----------------------------------------------------------------------
1334 *
1335 * FreeExprCodeInternalRep --
1336 *
1337 *      Part of the Tcl object type implementation for Tcl expression
1338 *      bytecode.  Frees the storage allocated to hold the internal rep,
1339 *      unless ref counts indicate bytecode execution is still in progress.
1340 *
1341 * Results:
1342 *      None.
1343 *
1344 * Side effects:
1345 *      May free allocated memory.  Leaves objPtr untyped.
1346 *----------------------------------------------------------------------
1347 */
1348
1349static void
1350FreeExprCodeInternalRep(
1351    Tcl_Obj *objPtr)
1352{
1353    ByteCode *codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
1354
1355    codePtr->refCount--;
1356    if (codePtr->refCount <= 0) {
1357        TclCleanupByteCode(codePtr);
1358    }
1359    objPtr->typePtr = NULL;
1360    objPtr->internalRep.otherValuePtr = NULL;
1361}
1362
1363/*
1364 *----------------------------------------------------------------------
1365 *
1366 * TclCompEvalObj --
1367 *
1368 *      This procedure evaluates the script contained in a Tcl_Obj by first
1369 *      compiling it and then passing it to TclExecuteByteCode.
1370 *
1371 * Results:
1372 *      The return value is one of the return codes defined in tcl.h (such as
1373 *      TCL_OK), and interp->objResultPtr refers to a Tcl object that either
1374 *      contains the result of executing the code or an error message.
1375 *
1376 * Side effects:
1377 *      Almost certainly, depending on the ByteCode's instructions.
1378 *
1379 *----------------------------------------------------------------------
1380 */
1381
1382int
1383TclCompEvalObj(
1384    Tcl_Interp *interp,
1385    Tcl_Obj *objPtr,
1386    const CmdFrame *invoker,
1387    int word)
1388{
1389    register Interp *iPtr = (Interp *) interp;
1390    register ByteCode *codePtr; /* Tcl Internal type of bytecode. */
1391    int result;
1392    Namespace *namespacePtr;
1393
1394    /*
1395     * Check that the interpreter is ready to execute scripts. Note that we
1396     * manage the interp's runlevel here: it is a small white lie (maybe), but
1397     * saves a ++/-- pair at each invocation. Amazingly enough, the impact on
1398     * performance is noticeable.
1399     */
1400
1401    iPtr->numLevels++;
1402    if (TclInterpReady(interp) == TCL_ERROR) {
1403        result = TCL_ERROR;
1404        goto done;
1405    }
1406
1407    namespacePtr = iPtr->varFramePtr->nsPtr;
1408
1409    /*
1410     * If the object is not already of tclByteCodeType, compile it (and reset
1411     * the compilation flags in the interpreter; this should be done after any
1412     * compilation). Otherwise, check that it is "fresh" enough.
1413     */
1414
1415    if (objPtr->typePtr == &tclByteCodeType) {
1416        /*
1417         * Make sure the Bytecode hasn't been invalidated by, e.g., someone
1418         * redefining a command with a compile procedure (this might make the
1419         * compiled code wrong). The object needs to be recompiled if it was
1420         * compiled in/for a different interpreter, or for a different
1421         * namespace, or for the same namespace but with different name
1422         * resolution rules. Precompiled objects, however, are immutable and
1423         * therefore they are not recompiled, even if the epoch has changed.
1424         *
1425         * To be pedantically correct, we should also check that the
1426         * originating procPtr is the same as the current context procPtr
1427         * (assuming one exists at all - none for global level). This code is
1428         * #def'ed out because [info body] was changed to never return a
1429         * bytecode type object, which should obviate us from the extra checks
1430         * here.
1431         */
1432
1433        codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
1434        if (((Interp *) *codePtr->interpHandle != iPtr)
1435                || (codePtr->compileEpoch != iPtr->compileEpoch)
1436                || (codePtr->nsPtr != namespacePtr)
1437                || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {
1438            if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
1439                if ((Interp *) *codePtr->interpHandle != iPtr) {
1440                    Tcl_Panic("Tcl_EvalObj: compiled script jumped interps");
1441                }
1442                codePtr->compileEpoch = iPtr->compileEpoch;
1443            } else {
1444                /*
1445                 * This byteCode is invalid: free it and recompile.
1446                 */
1447
1448                objPtr->typePtr->freeIntRepProc(objPtr);
1449                goto recompileObj;
1450            }
1451        }
1452
1453        /*
1454         * Increment the code's ref count while it is being executed. If
1455         * afterwards no references to it remain, free the code.
1456         */
1457
1458    runCompiledObj:
1459        codePtr->refCount++;
1460        result = TclExecuteByteCode(interp, codePtr);
1461        codePtr->refCount--;
1462        if (codePtr->refCount <= 0) {
1463            TclCleanupByteCode(codePtr);
1464        }
1465        goto done;
1466    }
1467
1468    recompileObj:
1469    iPtr->errorLine = 1;
1470
1471    /*
1472     * TIP #280. Remember the invoker for a moment in the interpreter
1473     * structures so that the byte code compiler can pick it up when
1474     * initializing the compilation environment, i.e. the extended location
1475     * information.
1476     */
1477
1478    iPtr->invokeCmdFramePtr = invoker;
1479    iPtr->invokeWord = word;
1480    tclByteCodeType.setFromAnyProc(interp, objPtr);
1481    iPtr->invokeCmdFramePtr = NULL;
1482    codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
1483    goto runCompiledObj;
1484
1485    done:
1486    iPtr->numLevels--;
1487    return result;
1488}
1489
1490/*
1491 *----------------------------------------------------------------------
1492 *
1493 * TclIncrObj --
1494 *
1495 *      Increment an integeral value in a Tcl_Obj by an integeral value held
1496 *      in another Tcl_Obj. Caller is responsible for making sure we can
1497 *      update the first object.
1498 *
1499 * Results:
1500 *      TCL_ERROR if either object is non-integer, and TCL_OK otherwise. On
1501 *      error, an error message is left in the interpreter (if it is not NULL,
1502 *      of course).
1503 *
1504 * Side effects:
1505 *      valuePtr gets the new incrmented value.
1506 *
1507 *----------------------------------------------------------------------
1508 */
1509
1510int
1511TclIncrObj(
1512    Tcl_Interp *interp,
1513    Tcl_Obj *valuePtr,
1514    Tcl_Obj *incrPtr)
1515{
1516    ClientData ptr1, ptr2;
1517    int type1, type2;
1518    mp_int value, incr;
1519
1520    if (Tcl_IsShared(valuePtr)) {
1521        Tcl_Panic("%s called with shared object", "TclIncrObj");
1522    }
1523
1524    if (GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK) {
1525        /*
1526         * Produce error message (reparse?!)
1527         */
1528
1529        return TclGetIntFromObj(interp, valuePtr, &type1);
1530    }
1531    if (GetNumberFromObj(NULL, incrPtr, &ptr2, &type2) != TCL_OK) {
1532        /*
1533         * Produce error message (reparse?!)
1534         */
1535
1536        TclGetIntFromObj(interp, incrPtr, &type1);
1537        Tcl_AddErrorInfo(interp, "\n    (reading increment)");
1538        return TCL_ERROR;
1539    }
1540
1541    if ((type1 == TCL_NUMBER_LONG) && (type2 == TCL_NUMBER_LONG)) {
1542        long augend = *((const long *) ptr1);
1543        long addend = *((const long *) ptr2);
1544        long sum = augend + addend;
1545
1546        /*
1547         * Overflow when (augend and sum have different sign) and (augend and
1548         * addend have the same sign). This is encapsulated in the Overflowing
1549         * macro.
1550         */
1551
1552        if (!Overflowing(augend, addend, sum)) {
1553            TclSetLongObj(valuePtr, sum);
1554            return TCL_OK;
1555        }
1556#ifndef NO_WIDE_TYPE
1557        {
1558            Tcl_WideInt w1 = (Tcl_WideInt) augend;
1559            Tcl_WideInt w2 = (Tcl_WideInt) addend;
1560
1561            /*
1562             * We know the sum value is outside the long range, so we use the
1563             * macro form that doesn't range test again.
1564             */
1565
1566            TclSetWideIntObj(valuePtr, w1 + w2);
1567            return TCL_OK;
1568        }
1569#endif
1570    }
1571
1572    if ((type1 == TCL_NUMBER_DOUBLE) || (type1 == TCL_NUMBER_NAN)) {
1573        /*
1574         * Produce error message (reparse?!)
1575         */
1576
1577        return TclGetIntFromObj(interp, valuePtr, &type1);
1578    }
1579    if ((type2 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_NAN)) {
1580        /*
1581         * Produce error message (reparse?!)
1582         */
1583
1584        TclGetIntFromObj(interp, incrPtr, &type1);
1585        Tcl_AddErrorInfo(interp, "\n    (reading increment)");
1586        return TCL_ERROR;
1587    }
1588
1589#ifndef NO_WIDE_TYPE
1590    if ((type1 != TCL_NUMBER_BIG) && (type2 != TCL_NUMBER_BIG)) {
1591        Tcl_WideInt w1, w2, sum;
1592
1593        TclGetWideIntFromObj(NULL, valuePtr, &w1);
1594        TclGetWideIntFromObj(NULL, incrPtr, &w2);
1595        sum = w1 + w2;
1596
1597        /*
1598         * Check for overflow.
1599         */
1600
1601        if (!Overflowing(w1, w2, sum)) {
1602            Tcl_SetWideIntObj(valuePtr, sum);
1603            return TCL_OK;
1604        }
1605    }
1606#endif
1607
1608    Tcl_TakeBignumFromObj(interp, valuePtr, &value);
1609    Tcl_GetBignumFromObj(interp, incrPtr, &incr);
1610    mp_add(&value, &incr, &value);
1611    mp_clear(&incr);
1612    Tcl_SetBignumObj(valuePtr, &value);
1613    return TCL_OK;
1614}
1615
1616/*
1617 *----------------------------------------------------------------------
1618 *
1619 * TclExecuteByteCode --
1620 *
1621 *      This procedure executes the instructions of a ByteCode structure. It
1622 *      returns when a "done" instruction is executed or an error occurs.
1623 *
1624 * Results:
1625 *      The return value is one of the return codes defined in tcl.h (such as
1626 *      TCL_OK), and interp->objResultPtr refers to a Tcl object that either
1627 *      contains the result of executing the code or an error message.
1628 *
1629 * Side effects:
1630 *      Almost certainly, depending on the ByteCode's instructions.
1631 *
1632 *----------------------------------------------------------------------
1633 */
1634
1635int
1636TclExecuteByteCode(
1637    Tcl_Interp *interp,         /* Token for command interpreter. */
1638    ByteCode *codePtr)          /* The bytecode sequence to interpret. */
1639{
1640    /*
1641     * Compiler cast directive - not a real variable.
1642     *     Interp *iPtr = (Interp *) interp;
1643     */
1644#define iPtr ((Interp *) interp)
1645
1646    /*
1647     * Check just the read-traced/write-traced bit of a variable.
1648     */
1649
1650#define ReadTraced(varPtr) ((varPtr)->flags & VAR_TRACED_READ)
1651#define WriteTraced(varPtr) ((varPtr)->flags & VAR_TRACED_WRITE)
1652
1653    /*
1654     * Constants: variables that do not change during the execution, used
1655     * sporadically.
1656     */
1657
1658    ExecStack *esPtr;
1659    Tcl_Obj **initTosPtr;       /* Stack top at start of execution. */
1660    ptrdiff_t *initCatchTop;    /* Catch stack top at start of execution. */
1661    Var *compiledLocals;
1662    Namespace *namespacePtr;
1663    CmdFrame *bcFramePtr;       /* TIP #280: Structure for tracking lines. */
1664    Tcl_Obj **constants = &iPtr->execEnvPtr->constants[0];
1665
1666    /*
1667     * Globals: variables that store state, must remain valid at all times.
1668     */
1669
1670    ptrdiff_t *catchTop;
1671    register Tcl_Obj **tosPtr;  /* Cached pointer to top of evaluation
1672                                 * stack. */
1673    register unsigned char *pc = codePtr->codeStart;
1674                                /* The current program counter. */
1675    int instructionCount = 0;   /* Counter that is used to work out when to
1676                                 * call Tcl_AsyncReady() */
1677    Tcl_Obj *expandNestList = NULL;
1678    int checkInterp = 0;        /* Indicates when a check of interp readyness
1679                                 * is necessary. Set by CACHE_STACK_INFO() */
1680
1681    /*
1682     * Transfer variables - needed only between opcodes, but not while
1683     * executing an instruction.
1684     */
1685
1686    register int cleanup;
1687    Tcl_Obj *objResultPtr;
1688
1689    /*
1690     * Result variable - needed only when going to checkForcatch or other
1691     * error handlers; also used as local in some opcodes.
1692     */
1693
1694    int result = TCL_OK;        /* Return code returned after execution. */
1695
1696    /*
1697     * Locals - variables that are used within opcodes or bounded sections of
1698     * the file (jumps between opcodes within a family).
1699     * NOTE: These are now defined locally where needed.
1700     */
1701
1702#ifdef TCL_COMPILE_DEBUG
1703    int traceInstructions = (tclTraceExec == 3);
1704    char cmdNameBuf[21];
1705#endif
1706    char *curInstName = NULL;
1707
1708    /*
1709     * The execution uses a unified stack: first the catch stack, immediately
1710     * above it a CmdFrame, then the execution stack.
1711     *
1712     * Make sure the catch stack is large enough to hold the maximum number of
1713     * catch commands that could ever be executing at the same time (this will
1714     * be no more than the exception range array's depth). Make sure the
1715     * execution stack is large enough to execute this ByteCode.
1716     */
1717
1718    catchTop = initCatchTop = (ptrdiff_t *) (
1719        GrowEvaluationStack(iPtr->execEnvPtr,
1720                codePtr->maxExceptDepth + sizeof(CmdFrame) +
1721                    codePtr->maxStackDepth, 0) - 1);
1722    bcFramePtr = (CmdFrame *) (initCatchTop + codePtr->maxExceptDepth + 1);
1723    tosPtr = initTosPtr = ((Tcl_Obj **) (bcFramePtr + 1)) - 1;
1724    esPtr = iPtr->execEnvPtr->execStackPtr;
1725
1726    /*
1727     * TIP #280: Initialize the frame. Do not push it yet.
1728     */
1729
1730    bcFramePtr->type = ((codePtr->flags & TCL_BYTECODE_PRECOMPILED)
1731            ? TCL_LOCATION_PREBC : TCL_LOCATION_BC);
1732    bcFramePtr->level = (iPtr->cmdFramePtr ? iPtr->cmdFramePtr->level+1 : 1);
1733    bcFramePtr->framePtr = iPtr->framePtr;
1734    bcFramePtr->nextPtr = iPtr->cmdFramePtr;
1735    bcFramePtr->nline = 0;
1736    bcFramePtr->line = NULL;
1737
1738    bcFramePtr->data.tebc.codePtr = codePtr;
1739    bcFramePtr->data.tebc.pc = NULL;
1740    bcFramePtr->cmd.str.cmd = NULL;
1741    bcFramePtr->cmd.str.len = 0;
1742
1743#ifdef TCL_COMPILE_DEBUG
1744    if (tclTraceExec >= 2) {
1745        PrintByteCodeInfo(codePtr);
1746        fprintf(stdout, "  Starting stack top=%d\n", CURR_DEPTH);
1747        fflush(stdout);
1748    }
1749#endif
1750
1751#ifdef TCL_COMPILE_STATS
1752    iPtr->stats.numExecutions++;
1753#endif
1754
1755    namespacePtr = iPtr->varFramePtr->nsPtr;
1756    compiledLocals = iPtr->varFramePtr->compiledLocals;
1757
1758    /*
1759     * Loop executing instructions until a "done" instruction, a TCL_RETURN,
1760     * or some error.
1761     */
1762
1763    goto cleanup0;
1764
1765    /*
1766     * Targets for standard instruction endings; unrolled for speed in the
1767     * most frequent cases (instructions that consume up to two stack
1768     * elements).
1769     *
1770     * This used to be a "for(;;)" loop, with each instruction doing its own
1771     * cleanup.
1772     */
1773
1774    {
1775        Tcl_Obj *valuePtr;
1776
1777    cleanupV_pushObjResultPtr:
1778        switch (cleanup) {
1779        case 0:
1780            *(++tosPtr) = (objResultPtr);
1781            goto cleanup0;
1782        default:
1783            cleanup -= 2;
1784            while (cleanup--) {
1785                valuePtr = POP_OBJECT();
1786                TclDecrRefCount(valuePtr);
1787            }
1788        case 2:
1789        cleanup2_pushObjResultPtr:
1790            valuePtr = POP_OBJECT();
1791            TclDecrRefCount(valuePtr);
1792        case 1:
1793        cleanup1_pushObjResultPtr:
1794            valuePtr = OBJ_AT_TOS;
1795            TclDecrRefCount(valuePtr);
1796        }
1797        OBJ_AT_TOS = objResultPtr;
1798        goto cleanup0;
1799
1800    cleanupV:
1801        switch (cleanup) {
1802        default:
1803            cleanup -= 2;
1804            while (cleanup--) {
1805                valuePtr = POP_OBJECT();
1806                TclDecrRefCount(valuePtr);
1807            }
1808        case 2:
1809        cleanup2:
1810            valuePtr = POP_OBJECT();
1811            TclDecrRefCount(valuePtr);
1812        case 1:
1813        cleanup1:
1814            valuePtr = POP_OBJECT();
1815            TclDecrRefCount(valuePtr);
1816        case 0:
1817            /*
1818             * We really want to do nothing now, but this is needed for some
1819             * compilers (SunPro CC).
1820             */
1821
1822            break;
1823        }
1824    }
1825 cleanup0:
1826
1827#ifdef TCL_COMPILE_DEBUG
1828    /*
1829     * Skip the stack depth check if an expansion is in progress.
1830     */
1831
1832    ValidatePcAndStackTop(codePtr, pc, CURR_DEPTH, 0,
1833            /*checkStack*/ expandNestList == NULL);
1834    if (traceInstructions) {
1835        fprintf(stdout, "%2d: %2d ", iPtr->numLevels, (int) CURR_DEPTH);
1836        TclPrintInstruction(codePtr, pc);
1837        fflush(stdout);
1838    }
1839#endif /* TCL_COMPILE_DEBUG */
1840
1841#ifdef TCL_COMPILE_STATS
1842    iPtr->stats.instructionCount[*pc]++;
1843#endif
1844
1845    /*
1846     * Check for asynchronous handlers [Bug 746722]; we do the check every
1847     * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-1).
1848     */
1849
1850    if ((instructionCount++ & ASYNC_CHECK_COUNT_MASK) == 0) {
1851        /*
1852         * Check for asynchronous handlers [Bug 746722]; we do the check every
1853         * ASYNC_CHECK_COUNT_MASK instruction, of the form (2**n-<1).
1854         */
1855
1856        if (TclAsyncReady(iPtr)) {
1857            int localResult;
1858
1859            DECACHE_STACK_INFO();
1860            localResult = Tcl_AsyncInvoke(interp, result);
1861            CACHE_STACK_INFO();
1862            if (localResult == TCL_ERROR) {
1863                result = localResult;
1864                goto checkForCatch;
1865            }
1866        }
1867        if (TclLimitReady(iPtr->limit)) {
1868            int localResult;
1869
1870            DECACHE_STACK_INFO();
1871            localResult = Tcl_LimitCheck(interp);
1872            CACHE_STACK_INFO();
1873            if (localResult == TCL_ERROR) {
1874                result = localResult;
1875                goto checkForCatch;
1876            }
1877        }
1878    }
1879
1880     TCL_DTRACE_INST_NEXT();
1881
1882    /*
1883     * These two instructions account for 26% of all instructions (according
1884     * to measurements on tclbench by Ben Vitale
1885     * [http://www.cs.toronto.edu/syslab/pubs/tcl2005-vitale-zaleski.pdf]
1886     * Resolving them before the switch reduces the cost of branch
1887     * mispredictions, seems to improve runtime by 5% to 15%, and (amazingly!)
1888     * reduces total obj size.
1889     */
1890
1891    if (*pc == INST_LOAD_SCALAR1) {
1892        goto instLoadScalar1;
1893    } else if (*pc == INST_PUSH1) {
1894        goto instPush1Peephole;
1895    }
1896
1897    switch (*pc) {
1898    case INST_SYNTAX:
1899    case INST_RETURN_IMM: {
1900        int code = TclGetInt4AtPtr(pc+1);
1901        int level = TclGetUInt4AtPtr(pc+5);
1902
1903        /*
1904         * OBJ_AT_TOS is returnOpts, OBJ_UNDER_TOS is resultObjPtr.
1905         */
1906
1907        TRACE(("%u %u => ", code, level));
1908        result = TclProcessReturn(interp, code, level, OBJ_AT_TOS);
1909        if (result == TCL_OK) {
1910            TRACE_APPEND(("continuing to next instruction (result=\"%.30s\")",
1911                    O2S(objResultPtr)));
1912            NEXT_INST_F(9, 1, 0);
1913        } else {
1914            Tcl_SetObjResult(interp, OBJ_UNDER_TOS);
1915            if (*pc == INST_SYNTAX) {
1916                iPtr->flags &= ~ERR_ALREADY_LOGGED;
1917            }
1918            cleanup = 2;
1919            goto processExceptionReturn;
1920        }
1921    }
1922
1923    case INST_RETURN_STK:
1924        TRACE(("=> "));
1925        objResultPtr = POP_OBJECT();
1926        result = Tcl_SetReturnOptions(interp, OBJ_AT_TOS);
1927        Tcl_DecrRefCount(OBJ_AT_TOS);
1928        OBJ_AT_TOS = objResultPtr;
1929        if (result == TCL_OK) {
1930            TRACE_APPEND(("continuing to next instruction (result=\"%.30s\")",
1931                    O2S(objResultPtr)));
1932            NEXT_INST_F(1, 0, 0);
1933        } else {
1934            Tcl_SetObjResult(interp, objResultPtr);
1935            cleanup = 1;
1936            goto processExceptionReturn;
1937        }
1938
1939    case INST_DONE:
1940        if (tosPtr > initTosPtr) {
1941            /*
1942             * Set the interpreter's object result to point to the topmost
1943             * object from the stack, and check for a possible [catch]. The
1944             * stackTop's level and refCount will be handled by "processCatch"
1945             * or "abnormalReturn".
1946             */
1947
1948            Tcl_SetObjResult(interp, OBJ_AT_TOS);
1949#ifdef TCL_COMPILE_DEBUG
1950            TRACE_WITH_OBJ(("=> return code=%d, result=", result),
1951                    iPtr->objResultPtr);
1952            if (traceInstructions) {
1953                fprintf(stdout, "\n");
1954            }
1955#endif
1956            goto checkForCatch;
1957        } else {
1958            (void) POP_OBJECT();
1959            goto abnormalReturn;
1960        }
1961
1962    case INST_PUSH1:
1963    instPush1Peephole:
1964        PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc+1)]);
1965        TRACE_WITH_OBJ(("%u => ", TclGetInt1AtPtr(pc+1)), OBJ_AT_TOS);
1966        pc += 2;
1967#if !TCL_COMPILE_DEBUG
1968        /*
1969         * Runtime peephole optimisation: check if we are pushing again.
1970         */
1971
1972        if (*pc == INST_PUSH1) {
1973            TCL_DTRACE_INST_NEXT();
1974            goto instPush1Peephole;
1975        }
1976#endif
1977        NEXT_INST_F(0, 0, 0);
1978
1979    case INST_PUSH4:
1980        objResultPtr = codePtr->objArrayPtr[TclGetUInt4AtPtr(pc+1)];
1981        TRACE_WITH_OBJ(("%u => ", TclGetUInt4AtPtr(pc+1)), objResultPtr);
1982        NEXT_INST_F(5, 0, 1);
1983
1984    case INST_POP: {
1985        Tcl_Obj *valuePtr;
1986
1987        TRACE_WITH_OBJ(("=> discarding "), OBJ_AT_TOS);
1988        valuePtr = POP_OBJECT();
1989        TclDecrRefCount(valuePtr);
1990
1991        /*
1992         * Runtime peephole optimisation: an INST_POP is scheduled at the end
1993         * of most commands. If the next instruction is an INST_START_CMD,
1994         * fall through to it.
1995         */
1996
1997        pc++;
1998#if !TCL_COMPILE_DEBUG
1999        if (*pc == INST_START_CMD) {
2000            TCL_DTRACE_INST_NEXT();
2001            goto instStartCmdPeephole;
2002        }
2003#endif
2004        NEXT_INST_F(0, 0, 0);
2005    }
2006
2007    case INST_START_CMD:
2008#if !TCL_COMPILE_DEBUG
2009    instStartCmdPeephole:
2010#endif
2011        /*
2012         * Remark that if the interpreter is marked for deletion its
2013         * compileEpoch is modified, so that the epoch check also verifies
2014         * that the interp is not deleted. If no outside call has been made
2015         * since the last check, it is safe to omit the check.
2016         */
2017
2018        iPtr->cmdCount += TclGetUInt4AtPtr(pc+5);
2019        if (!checkInterp) {
2020        instStartCmdOK:
2021            NEXT_INST_F(9, 0, 0);
2022        } else if (((codePtr->compileEpoch == iPtr->compileEpoch)
2023                && (codePtr->nsEpoch == namespacePtr->resolverEpoch))
2024                || (codePtr->flags & TCL_BYTECODE_PRECOMPILED)) {
2025            checkInterp = 0;
2026            goto instStartCmdOK;
2027        } else {
2028            const char *bytes;
2029            int length, opnd;
2030            Tcl_Obj *newObjResultPtr;
2031
2032            bytes = GetSrcInfoForPc(pc, codePtr, &length);
2033            DECACHE_STACK_INFO();
2034            result = Tcl_EvalEx(interp, bytes, length, 0);
2035            CACHE_STACK_INFO();
2036            if (result != TCL_OK) {
2037                cleanup = 0;
2038                goto processExceptionReturn;
2039            }
2040            opnd = TclGetUInt4AtPtr(pc+1);
2041            objResultPtr = Tcl_GetObjResult(interp);
2042            TclNewObj(newObjResultPtr);
2043            Tcl_IncrRefCount(newObjResultPtr);
2044            iPtr->objResultPtr = newObjResultPtr;
2045            NEXT_INST_V(opnd, 0, -1);
2046        }
2047
2048    case INST_DUP:
2049        objResultPtr = OBJ_AT_TOS;
2050        TRACE_WITH_OBJ(("=> "), objResultPtr);
2051        NEXT_INST_F(1, 0, 1);
2052
2053    case INST_OVER: {
2054        int opnd;
2055
2056        opnd = TclGetUInt4AtPtr(pc+1);
2057        objResultPtr = OBJ_AT_DEPTH(opnd);
2058        TRACE_WITH_OBJ(("=> "), objResultPtr);
2059        NEXT_INST_F(5, 0, 1);
2060    }
2061
2062    case INST_REVERSE: {
2063        int opnd;
2064        Tcl_Obj **a, **b;
2065
2066        opnd = TclGetUInt4AtPtr(pc+1);
2067        a = tosPtr-(opnd-1);
2068        b = tosPtr;
2069        while (a<b) {
2070            Tcl_Obj *temp = *a;
2071            *a = *b;
2072            *b = temp;
2073            a++; b--;
2074        }
2075        NEXT_INST_F(5, 0, 0);
2076    }
2077
2078    case INST_CONCAT1: {
2079        int opnd, length, appendLen = 0;
2080        char *bytes, *p;
2081        Tcl_Obj **currPtr;
2082
2083        opnd = TclGetUInt1AtPtr(pc+1);
2084
2085        /*
2086         * Compute the length to be appended.
2087         */
2088
2089        for (currPtr=&OBJ_AT_DEPTH(opnd-2); currPtr<=&OBJ_AT_TOS; currPtr++) {
2090            bytes = TclGetStringFromObj(*currPtr, &length);
2091            if (bytes != NULL) {
2092                appendLen += length;
2093            }
2094        }
2095
2096        /*
2097         * If nothing is to be appended, just return the first object by
2098         * dropping all the others from the stack; this saves both the
2099         * computation and copy of the string rep of the first object,
2100         * enabling the fast '$x[set x {}]' idiom for 'K $x [set x {}]'.
2101         */
2102
2103        if (appendLen == 0) {
2104            TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
2105            NEXT_INST_V(2, (opnd-1), 0);
2106        }
2107
2108        /*
2109         * If the first object is shared, we need a new obj for the result;
2110         * otherwise, we can reuse the first object. In any case, make sure it
2111         * has enough room to accomodate all the concatenated bytes. Note that
2112         * if it is unshared its bytes are copied by ckrealloc, so that we set
2113         * the loop parameters to avoid copying them again: p points to the
2114         * end of the already copied bytes, currPtr to the second object.
2115         */
2116
2117        objResultPtr = OBJ_AT_DEPTH(opnd-1);
2118        bytes = TclGetStringFromObj(objResultPtr, &length);
2119#if !TCL_COMPILE_DEBUG
2120        if (bytes != tclEmptyStringRep && !Tcl_IsShared(objResultPtr)) {
2121            TclFreeIntRep(objResultPtr);
2122            objResultPtr->typePtr = NULL;
2123            objResultPtr->bytes = ckrealloc(bytes, (length + appendLen + 1));
2124            objResultPtr->length = length + appendLen;
2125            p = TclGetString(objResultPtr) + length;
2126            currPtr = &OBJ_AT_DEPTH(opnd - 2);
2127        } else {
2128#endif
2129            p = (char *) ckalloc((unsigned) (length + appendLen + 1));
2130            TclNewObj(objResultPtr);
2131            objResultPtr->bytes = p;
2132            objResultPtr->length = length + appendLen;
2133            currPtr = &OBJ_AT_DEPTH(opnd - 1);
2134#if !TCL_COMPILE_DEBUG
2135        }
2136#endif
2137
2138        /*
2139         * Append the remaining characters.
2140         */
2141
2142        for (; currPtr <= &OBJ_AT_TOS; currPtr++) {
2143            bytes = TclGetStringFromObj(*currPtr, &length);
2144            if (bytes != NULL) {
2145                memcpy(p, bytes, (size_t) length);
2146                p += length;
2147            }
2148        }
2149        *p = '\0';
2150
2151        TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
2152        NEXT_INST_V(2, opnd, 1);
2153    }
2154
2155    case INST_EXPAND_START: {
2156        /*
2157         * Push an element to the expandNestList. This records the current
2158         * stack depth - i.e., the point in the stack where the expanded
2159         * command starts.
2160         *
2161         * Use a Tcl_Obj as linked list element; slight mem waste, but faster
2162         * allocation than ckalloc. This also abuses the Tcl_Obj structure, as
2163         * we do not define a special tclObjType for it. It is not dangerous
2164         * as the obj is never passed anywhere, so that all manipulations are
2165         * performed here and in INST_INVOKE_EXPANDED (in case of an expansion
2166         * error, also in INST_EXPAND_STKTOP).
2167         */
2168
2169        Tcl_Obj *objPtr;
2170
2171        TclNewObj(objPtr);
2172        objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) CURR_DEPTH;
2173        objPtr->internalRep.twoPtrValue.ptr2 = (VOID *) expandNestList;
2174        expandNestList = objPtr;
2175        NEXT_INST_F(1, 0, 0);
2176    }
2177
2178    case INST_EXPAND_STKTOP: {
2179        int objc, length, i;
2180        Tcl_Obj **objv, *valuePtr;
2181        ptrdiff_t moved;
2182
2183        /*
2184         * Make sure that the element at stackTop is a list; if not, just
2185         * leave with an error. Note that the element from the expand list
2186         * will be removed at checkForCatch.
2187         */
2188
2189        valuePtr = OBJ_AT_TOS;
2190        if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK){
2191            TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
2192                    Tcl_GetObjResult(interp));
2193            result = TCL_ERROR;
2194            goto checkForCatch;
2195        }
2196        (void) POP_OBJECT();
2197
2198        /*
2199         * Make sure there is enough room in the stack to expand this list
2200         * *and* process the rest of the command (at least up to the next
2201         * argument expansion or command end). The operand is the current
2202         * stack depth, as seen by the compiler.
2203         */
2204
2205        length = objc + (codePtr->maxStackDepth - TclGetInt4AtPtr(pc+1));
2206        DECACHE_STACK_INFO();
2207        moved = (GrowEvaluationStack(iPtr->execEnvPtr, length, 1) - 1)
2208                - (Tcl_Obj **) initCatchTop;
2209
2210        if (moved) {
2211            /*
2212             * Change the global data to point to the new stack.
2213             */
2214
2215            initCatchTop += moved;
2216            catchTop += moved;
2217            initTosPtr += moved;
2218            tosPtr += moved;
2219            esPtr = iPtr->execEnvPtr->execStackPtr;
2220        }
2221
2222        /*
2223         * Expand the list at stacktop onto the stack; free the list. Knowing
2224         * that it has a freeIntRepProc we use Tcl_DecrRefCount().
2225         */
2226
2227        for (i = 0; i < objc; i++) {
2228            PUSH_OBJECT(objv[i]);
2229        }
2230
2231        Tcl_DecrRefCount(valuePtr);
2232        NEXT_INST_F(5, 0, 0);
2233    }
2234
2235    {
2236        /*
2237         * INVOCATION BLOCK
2238         */
2239
2240        int objc, pcAdjustment;
2241
2242    case INST_INVOKE_EXPANDED:
2243        {
2244            Tcl_Obj *objPtr = expandNestList;
2245
2246            expandNestList = (Tcl_Obj *) objPtr->internalRep.twoPtrValue.ptr2;
2247            objc = CURR_DEPTH
2248                    - (ptrdiff_t) objPtr->internalRep.twoPtrValue.ptr1;
2249            TclDecrRefCount(objPtr);
2250        }
2251
2252        if (objc) {
2253            pcAdjustment = 1;
2254            goto doInvocation;
2255        } else {
2256            /*
2257             * Nothing was expanded, return {}.
2258             */
2259
2260            TclNewObj(objResultPtr);
2261            NEXT_INST_F(1, 0, 1);
2262        }
2263
2264    case INST_INVOKE_STK4:
2265        objc = TclGetUInt4AtPtr(pc+1);
2266        pcAdjustment = 5;
2267        goto doInvocation;
2268
2269    case INST_INVOKE_STK1:
2270        objc = TclGetUInt1AtPtr(pc+1);
2271        pcAdjustment = 2;
2272
2273    doInvocation:
2274        {
2275            Tcl_Obj **objv = &OBJ_AT_DEPTH(objc-1);
2276
2277#ifdef TCL_COMPILE_DEBUG
2278            if (tclTraceExec >= 2) {
2279                int i;
2280
2281                if (traceInstructions) {
2282                    strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
2283                    TRACE(("%u => call ", objc));
2284                } else {
2285                    fprintf(stdout, "%d: (%u) invoking ", iPtr->numLevels,
2286                            (unsigned)(pc - codePtr->codeStart));
2287                }
2288                for (i = 0;  i < objc;  i++) {
2289                    TclPrintObject(stdout, objv[i], 15);
2290                    fprintf(stdout, " ");
2291                }
2292                fprintf(stdout, "\n");
2293                fflush(stdout);
2294            }
2295#endif /*TCL_COMPILE_DEBUG*/
2296
2297            /*
2298             * Reset the instructionCount variable, since we're about to check
2299             * for async stuff anyway while processing TclEvalObjvInternal.
2300             */
2301
2302            instructionCount = 1;
2303
2304            /*
2305             * Finally, let TclEvalObjvInternal handle the command.
2306             *
2307             * TIP #280: Record the last piece of info needed by
2308             * 'TclGetSrcInfoForPc', and push the frame.
2309             */
2310
2311            bcFramePtr->data.tebc.pc = (char *) pc;
2312            iPtr->cmdFramePtr = bcFramePtr;
2313            DECACHE_STACK_INFO();
2314            result = TclEvalObjvInternal(interp, objc, objv,
2315                    /* call from TEBC */(char *) -1, -1, 0);
2316            CACHE_STACK_INFO();
2317            iPtr->cmdFramePtr = iPtr->cmdFramePtr->nextPtr;
2318
2319            if (result == TCL_OK) {
2320                Tcl_Obj *objPtr;
2321
2322#ifndef TCL_COMPILE_DEBUG
2323                if (*(pc+pcAdjustment) == INST_POP) {
2324                    NEXT_INST_V((pcAdjustment+1), objc, 0);
2325                }
2326#endif
2327                /*
2328                 * Push the call's object result and continue execution with
2329                 * the next instruction.
2330                 */
2331
2332                TRACE_WITH_OBJ(("%u => ... after \"%.20s\": TCL_OK, result=",
2333                        objc, cmdNameBuf), Tcl_GetObjResult(interp));
2334
2335                objResultPtr = Tcl_GetObjResult(interp);
2336
2337                /*
2338                 * Reset the interp's result to avoid possible duplications of
2339                 * large objects [Bug 781585]. We do not call Tcl_ResetResult
2340                 * to avoid any side effects caused by the resetting of
2341                 * errorInfo and errorCode [Bug 804681], which are not needed
2342                 * here. We chose instead to manipulate the interp's object
2343                 * result directly.
2344                 *
2345                 * Note that the result object is now in objResultPtr, it
2346                 * keeps the refCount it had in its role of
2347                 * iPtr->objResultPtr.
2348                 */
2349
2350                TclNewObj(objPtr);
2351                Tcl_IncrRefCount(objPtr);
2352                iPtr->objResultPtr = objPtr;
2353                NEXT_INST_V(pcAdjustment, objc, -1);
2354            } else {
2355                cleanup = objc;
2356                goto processExceptionReturn;
2357            }
2358        }
2359
2360#if TCL_SUPPORT_84_BYTECODE
2361    case INST_CALL_BUILTIN_FUNC1: {
2362        /*
2363         * Call one of the built-in pre-8.5 Tcl math functions. This
2364         * translates to INST_INVOKE_STK1 with the first argument of
2365         * ::tcl::mathfunc::$objv[0]. We need to insert the named math
2366         * function into the stack.
2367         */
2368
2369        int opnd, numArgs;
2370        Tcl_Obj *objPtr;
2371
2372        opnd = TclGetUInt1AtPtr(pc+1);
2373        if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) {
2374            TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %d\n", opnd));
2375            Tcl_Panic("TclExecuteByteCode: unrecognized builtin function code %d", opnd);
2376        }
2377
2378        objPtr = Tcl_NewStringObj("::tcl::mathfunc::", 17);
2379        Tcl_AppendToObj(objPtr, tclBuiltinFuncTable[opnd].name, -1);
2380
2381        /*
2382         * Only 0, 1 or 2 args.
2383         */
2384
2385        numArgs = tclBuiltinFuncTable[opnd].numArgs;
2386        if (numArgs == 0) {
2387            PUSH_OBJECT(objPtr);
2388        } else if (numArgs == 1) {
2389            Tcl_Obj *tmpPtr1 = POP_OBJECT();
2390            PUSH_OBJECT(objPtr);
2391            PUSH_OBJECT(tmpPtr1);
2392            Tcl_DecrRefCount(tmpPtr1);
2393        } else {
2394            Tcl_Obj *tmpPtr1, *tmpPtr2;
2395            tmpPtr2 = POP_OBJECT();
2396            tmpPtr1 = POP_OBJECT();
2397            PUSH_OBJECT(objPtr);
2398            PUSH_OBJECT(tmpPtr1);
2399            PUSH_OBJECT(tmpPtr2);
2400            Tcl_DecrRefCount(tmpPtr1);
2401            Tcl_DecrRefCount(tmpPtr2);
2402        }
2403
2404        objc = numArgs + 1;
2405        pcAdjustment = 2;
2406        goto doInvocation;
2407    }
2408
2409    case INST_CALL_FUNC1: {
2410        /*
2411         * Call a non-builtin Tcl math function previously registered by a
2412         * call to Tcl_CreateMathFunc pre-8.5. This is essentially
2413         * INST_INVOKE_STK1 converting the first arg to
2414         * ::tcl::mathfunc::$objv[0].
2415         */
2416
2417        Tcl_Obj *tmpPtr, *objPtr;
2418
2419        /*
2420         * Number of arguments. The function name is the 0-th argument.
2421         */
2422
2423        objc = TclGetUInt1AtPtr(pc+1);
2424
2425        objPtr = OBJ_AT_DEPTH(objc-1);
2426        tmpPtr = Tcl_NewStringObj("::tcl::mathfunc::", 17);
2427        Tcl_AppendObjToObj(tmpPtr, objPtr);
2428        Tcl_DecrRefCount(objPtr);
2429
2430        /*
2431         * Variation of PUSH_OBJECT.
2432         */
2433
2434        OBJ_AT_DEPTH(objc-1) = tmpPtr;
2435        Tcl_IncrRefCount(tmpPtr);
2436
2437        pcAdjustment = 2;
2438        goto doInvocation;
2439    }
2440#else
2441    /*
2442     * INST_CALL_BUILTIN_FUNC1 and INST_CALL_FUNC1 were made obsolete by the
2443     * changes to add a ::tcl::mathfunc namespace in 8.5. Optional support
2444     * remains for existing bytecode precompiled files.
2445     */
2446
2447    case INST_CALL_BUILTIN_FUNC1:
2448        Tcl_Panic("TclExecuteByteCode: obsolete INST_CALL_BUILTIN_FUNC1 found");
2449    case INST_CALL_FUNC1:
2450        Tcl_Panic("TclExecuteByteCode: obsolete INST_CALL_FUNC1 found");
2451#endif
2452    }
2453
2454    case INST_EVAL_STK: {
2455        /*
2456         * Note to maintainers: it is important that INST_EVAL_STK pop its
2457         * argument from the stack before jumping to checkForCatch! DO NOT
2458         * OPTIMISE!
2459         */
2460
2461        Tcl_Obj *objPtr = OBJ_AT_TOS;
2462
2463        DECACHE_STACK_INFO();
2464
2465        /*
2466         * TIP #280: The invoking context is left NULL for a dynamically
2467         * constructed command. We cannot match its lines to the outer
2468         * context.
2469         */
2470
2471        result = TclCompEvalObj(interp, objPtr, NULL, 0);
2472        CACHE_STACK_INFO();
2473        if (result == TCL_OK) {
2474            /*
2475             * Normal return; push the eval's object result.
2476             */
2477
2478            objResultPtr = Tcl_GetObjResult(interp);
2479            TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)),
2480                    Tcl_GetObjResult(interp));
2481
2482            /*
2483             * Reset the interp's result to avoid possible duplications of
2484             * large objects [Bug 781585]. We do not call Tcl_ResetResult to
2485             * avoid any side effects caused by the resetting of errorInfo and
2486             * errorCode [Bug 804681], which are not needed here. We chose
2487             * instead to manipulate the interp's object result directly.
2488             *
2489             * Note that the result object is now in objResultPtr, it keeps
2490             * the refCount it had in its role of iPtr->objResultPtr.
2491             */
2492
2493            TclNewObj(objPtr);
2494            Tcl_IncrRefCount(objPtr);
2495            iPtr->objResultPtr = objPtr;
2496            NEXT_INST_F(1, 1, -1);
2497        } else {
2498            cleanup = 1;
2499            goto processExceptionReturn;
2500        }
2501    }
2502
2503    case INST_EXPR_STK: {
2504        Tcl_Obj *objPtr, *valuePtr;
2505
2506        objPtr = OBJ_AT_TOS;
2507        DECACHE_STACK_INFO();
2508        /*Tcl_ResetResult(interp);*/
2509        result = Tcl_ExprObj(interp, objPtr, &valuePtr);
2510        CACHE_STACK_INFO();
2511        if (result == TCL_OK) {
2512            objResultPtr = valuePtr;
2513            TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(objPtr)), valuePtr);
2514            NEXT_INST_F(1, 1, -1);      /* Already has right refct. */
2515        } else {
2516            TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(objPtr)),
2517                    Tcl_GetObjResult(interp));
2518            goto checkForCatch;
2519        }
2520    }
2521
2522    /*
2523     * ---------------------------------------------------------
2524     *     Start of INST_LOAD instructions.
2525     *
2526     * WARNING: more 'goto' here than your doctor recommended! The different
2527     * instructions set the value of some variables and then jump to some
2528     * common execution code.
2529     */
2530    {
2531        int opnd, pcAdjustment;
2532        Tcl_Obj *part1Ptr, *part2Ptr;
2533        Var *varPtr, *arrayPtr;
2534        Tcl_Obj *objPtr;
2535
2536    case INST_LOAD_SCALAR1:
2537    instLoadScalar1:
2538        opnd = TclGetUInt1AtPtr(pc+1);
2539        varPtr = &(compiledLocals[opnd]);
2540        while (TclIsVarLink(varPtr)) {
2541            varPtr = varPtr->value.linkPtr;
2542        }
2543        TRACE(("%u => ", opnd));
2544        if (TclIsVarDirectReadable(varPtr)) {
2545            /*
2546             * No errors, no traces: just get the value.
2547             */
2548
2549            objResultPtr = varPtr->value.objPtr;
2550            TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
2551            NEXT_INST_F(2, 0, 1);
2552        }
2553        pcAdjustment = 2;
2554        cleanup = 0;
2555        arrayPtr = NULL;
2556        part1Ptr = part2Ptr = NULL;
2557        goto doCallPtrGetVar;
2558
2559    case INST_LOAD_SCALAR4:
2560        opnd = TclGetUInt4AtPtr(pc+1);
2561        varPtr = &(compiledLocals[opnd]);
2562        while (TclIsVarLink(varPtr)) {
2563            varPtr = varPtr->value.linkPtr;
2564        }
2565        TRACE(("%u => ", opnd));
2566        if (TclIsVarDirectReadable(varPtr)) {
2567            /*
2568             * No errors, no traces: just get the value.
2569             */
2570
2571            objResultPtr = varPtr->value.objPtr;
2572            TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
2573            NEXT_INST_F(5, 0, 1);
2574        }
2575        pcAdjustment = 5;
2576        cleanup = 0;
2577        arrayPtr = NULL;
2578        part1Ptr = part2Ptr = NULL;
2579        goto doCallPtrGetVar;
2580
2581    case INST_LOAD_ARRAY4:
2582        opnd = TclGetUInt4AtPtr(pc+1);
2583        pcAdjustment = 5;
2584        goto doLoadArray;
2585
2586    case INST_LOAD_ARRAY1:
2587        opnd = TclGetUInt1AtPtr(pc+1);
2588        pcAdjustment = 2;
2589
2590    doLoadArray:
2591        part1Ptr = NULL;
2592        part2Ptr = OBJ_AT_TOS;
2593        arrayPtr = &(compiledLocals[opnd]);
2594        while (TclIsVarLink(arrayPtr)) {
2595            arrayPtr = arrayPtr->value.linkPtr;
2596        }
2597        TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
2598        if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) {
2599            varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
2600            if (varPtr && TclIsVarDirectReadable(varPtr)) {
2601                /*
2602                 * No errors, no traces: just get the value.
2603                 */
2604
2605                objResultPtr = varPtr->value.objPtr;
2606                TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
2607                NEXT_INST_F(pcAdjustment, 1, 1);
2608            }
2609        }
2610        varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
2611                TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr, opnd);
2612        if (varPtr == NULL) {
2613            TRACE_APPEND(("ERROR: %.30s\n",
2614                                 O2S(Tcl_GetObjResult(interp))));
2615            result = TCL_ERROR;
2616            goto checkForCatch;
2617        }
2618        cleanup = 1;
2619        goto doCallPtrGetVar;
2620
2621    case INST_LOAD_ARRAY_STK:
2622        cleanup = 2;
2623        part2Ptr = OBJ_AT_TOS;          /* element name */
2624        objPtr = OBJ_UNDER_TOS;         /* array name */
2625        TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), O2S(part2Ptr)));
2626        goto doLoadStk;
2627
2628    case INST_LOAD_STK:
2629    case INST_LOAD_SCALAR_STK:
2630        cleanup = 1;
2631        part2Ptr = NULL;
2632        objPtr = OBJ_AT_TOS;            /* variable name */
2633        TRACE(("\"%.30s\" => ", O2S(objPtr)));
2634
2635    doLoadStk:
2636        part1Ptr = objPtr;
2637        varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr,
2638                TCL_LEAVE_ERR_MSG, "read", /*createPart1*/0, /*createPart2*/1,
2639                &arrayPtr);
2640        if (varPtr) {
2641            if (TclIsVarDirectReadable2(varPtr, arrayPtr)) {
2642                /*
2643                 * No errors, no traces: just get the value.
2644                 */
2645
2646                objResultPtr = varPtr->value.objPtr;
2647                TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
2648                NEXT_INST_V(1, cleanup, 1);
2649            }
2650            pcAdjustment = 1;
2651            opnd = -1;
2652            goto doCallPtrGetVar;
2653        } else {
2654            TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
2655            result = TCL_ERROR;
2656            goto checkForCatch;
2657        }
2658
2659    doCallPtrGetVar:
2660        /*
2661         * There are either errors or the variable is traced: call
2662         * TclPtrGetVar to process fully.
2663         */
2664
2665        DECACHE_STACK_INFO();
2666        objResultPtr = TclPtrGetVar(interp, varPtr, arrayPtr,
2667                part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, opnd);
2668        CACHE_STACK_INFO();
2669        if (objResultPtr) {
2670            TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
2671            NEXT_INST_V(pcAdjustment, cleanup, 1);
2672        } else {
2673            TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
2674            result = TCL_ERROR;
2675            goto checkForCatch;
2676        }
2677    }
2678
2679    /*
2680     *     End of INST_LOAD instructions.
2681     * ---------------------------------------------------------
2682     */
2683
2684    /*
2685     * ---------------------------------------------------------
2686     *     Start of INST_STORE and related instructions.
2687     *
2688     * WARNING: more 'goto' here than your doctor recommended! The different
2689     * instructions set the value of some variables and then jump to somme
2690     * common execution code.
2691     */
2692
2693    {
2694        int opnd, pcAdjustment, storeFlags;
2695        Tcl_Obj *part1Ptr, *part2Ptr;
2696        Var *varPtr, *arrayPtr;
2697        Tcl_Obj *objPtr, *valuePtr;
2698
2699    case INST_STORE_ARRAY4:
2700        opnd = TclGetUInt4AtPtr(pc+1);
2701        pcAdjustment = 5;
2702        goto doStoreArrayDirect;
2703
2704    case INST_STORE_ARRAY1:
2705        opnd = TclGetUInt1AtPtr(pc+1);
2706        pcAdjustment = 2;
2707
2708    doStoreArrayDirect:
2709        valuePtr = OBJ_AT_TOS;
2710        part2Ptr = OBJ_UNDER_TOS;
2711        arrayPtr = &(compiledLocals[opnd]);
2712        TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
2713                O2S(valuePtr)));
2714        while (TclIsVarLink(arrayPtr)) {
2715            arrayPtr = arrayPtr->value.linkPtr;
2716        }
2717        if (TclIsVarArray(arrayPtr) && !WriteTraced(arrayPtr)) {
2718            varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
2719            if (varPtr && TclIsVarDirectWritable(varPtr)) {
2720                tosPtr--;
2721                Tcl_DecrRefCount(OBJ_AT_TOS);
2722                OBJ_AT_TOS = valuePtr;
2723                goto doStoreVarDirect;
2724            }
2725        }
2726        cleanup = 2;
2727        storeFlags = TCL_LEAVE_ERR_MSG;
2728        part1Ptr = NULL;
2729        goto doStoreArrayDirectFailed;
2730
2731    case INST_STORE_SCALAR4:
2732        opnd = TclGetUInt4AtPtr(pc+1);
2733        pcAdjustment = 5;
2734        goto doStoreScalarDirect;
2735
2736    case INST_STORE_SCALAR1:
2737        opnd = TclGetUInt1AtPtr(pc+1);
2738        pcAdjustment = 2;
2739
2740    doStoreScalarDirect:
2741        valuePtr = OBJ_AT_TOS;
2742        varPtr = &(compiledLocals[opnd]);
2743        TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
2744        while (TclIsVarLink(varPtr)) {
2745            varPtr = varPtr->value.linkPtr;
2746        }
2747        if (TclIsVarDirectWritable(varPtr)) {
2748    doStoreVarDirect:
2749            /*
2750             * No traces, no errors, plain 'set': we can safely inline. The
2751             * value *will* be set to what's requested, so that the stack top
2752             * remains pointing to the same Tcl_Obj.
2753             */
2754
2755            valuePtr = varPtr->value.objPtr;
2756            if (valuePtr != NULL) {
2757                TclDecrRefCount(valuePtr);
2758            }
2759            objResultPtr = OBJ_AT_TOS;
2760            varPtr->value.objPtr = objResultPtr;
2761#ifndef TCL_COMPILE_DEBUG
2762            if (*(pc+pcAdjustment) == INST_POP) {
2763                tosPtr--;
2764                NEXT_INST_F((pcAdjustment+1), 0, 0);
2765            }
2766#else
2767            TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
2768#endif
2769            Tcl_IncrRefCount(objResultPtr);
2770            NEXT_INST_F(pcAdjustment, 0, 0);
2771        }
2772        storeFlags = TCL_LEAVE_ERR_MSG;
2773        part1Ptr = NULL;
2774        goto doStoreScalar;
2775
2776    case INST_LAPPEND_STK:
2777        valuePtr = OBJ_AT_TOS; /* value to append */
2778        part2Ptr = NULL;
2779        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
2780                | TCL_LIST_ELEMENT | TCL_TRACE_READS);
2781        goto doStoreStk;
2782
2783    case INST_LAPPEND_ARRAY_STK:
2784        valuePtr = OBJ_AT_TOS; /* value to append */
2785        part2Ptr = OBJ_UNDER_TOS;
2786        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
2787                | TCL_LIST_ELEMENT | TCL_TRACE_READS);
2788        goto doStoreStk;
2789
2790    case INST_APPEND_STK:
2791        valuePtr = OBJ_AT_TOS; /* value to append */
2792        part2Ptr = NULL;
2793        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
2794        goto doStoreStk;
2795
2796    case INST_APPEND_ARRAY_STK:
2797        valuePtr = OBJ_AT_TOS; /* value to append */
2798        part2Ptr = OBJ_UNDER_TOS;
2799        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
2800        goto doStoreStk;
2801
2802    case INST_STORE_ARRAY_STK:
2803        valuePtr = OBJ_AT_TOS;
2804        part2Ptr = OBJ_UNDER_TOS;
2805        storeFlags = TCL_LEAVE_ERR_MSG;
2806        goto doStoreStk;
2807
2808    case INST_STORE_STK:
2809    case INST_STORE_SCALAR_STK:
2810        valuePtr = OBJ_AT_TOS;
2811        part2Ptr = NULL;
2812        storeFlags = TCL_LEAVE_ERR_MSG;
2813
2814    doStoreStk:
2815        objPtr = OBJ_AT_DEPTH(1 + (part2Ptr != NULL)); /* variable name */
2816        part1Ptr = objPtr;
2817#ifdef TCL_COMPILE_DEBUG
2818        if (part2Ptr == NULL) {
2819            TRACE(("\"%.30s\" <- \"%.30s\" =>", O2S(part1Ptr),O2S(valuePtr)));
2820        } else {
2821            TRACE(("\"%.30s(%.30s)\" <- \"%.30s\" => ",
2822                    O2S(part1Ptr), O2S(part2Ptr), O2S(valuePtr)));
2823        }
2824#endif
2825        varPtr = TclObjLookupVarEx(interp, objPtr,part2Ptr, TCL_LEAVE_ERR_MSG,
2826                "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
2827        if (varPtr) {
2828            cleanup = ((part2Ptr == NULL)? 2 : 3);
2829            pcAdjustment = 1;
2830            opnd = -1;
2831            goto doCallPtrSetVar;
2832        } else {
2833            TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
2834            result = TCL_ERROR;
2835            goto checkForCatch;
2836        }
2837
2838    case INST_LAPPEND_ARRAY4:
2839        opnd = TclGetUInt4AtPtr(pc+1);
2840        pcAdjustment = 5;
2841        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
2842                | TCL_LIST_ELEMENT | TCL_TRACE_READS);
2843        goto doStoreArray;
2844
2845    case INST_LAPPEND_ARRAY1:
2846        opnd = TclGetUInt1AtPtr(pc+1);
2847        pcAdjustment = 2;
2848        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
2849                | TCL_LIST_ELEMENT | TCL_TRACE_READS);
2850        goto doStoreArray;
2851
2852    case INST_APPEND_ARRAY4:
2853        opnd = TclGetUInt4AtPtr(pc+1);
2854        pcAdjustment = 5;
2855        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
2856        goto doStoreArray;
2857
2858    case INST_APPEND_ARRAY1:
2859        opnd = TclGetUInt1AtPtr(pc+1);
2860        pcAdjustment = 2;
2861        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
2862        goto doStoreArray;
2863
2864    doStoreArray:
2865        valuePtr = OBJ_AT_TOS;
2866        part2Ptr = OBJ_UNDER_TOS;
2867        arrayPtr = &(compiledLocals[opnd]);
2868        TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
2869                O2S(valuePtr)));
2870        while (TclIsVarLink(arrayPtr)) {
2871            arrayPtr = arrayPtr->value.linkPtr;
2872        }
2873        cleanup = 2;
2874        part1Ptr = NULL;
2875
2876    doStoreArrayDirectFailed:
2877        varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
2878                TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr, opnd);
2879        if (varPtr) {
2880            goto doCallPtrSetVar;
2881        } else {
2882            TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
2883            result = TCL_ERROR;
2884            goto checkForCatch;
2885        }
2886
2887    case INST_LAPPEND_SCALAR4:
2888        opnd = TclGetUInt4AtPtr(pc+1);
2889        pcAdjustment = 5;
2890        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
2891                | TCL_LIST_ELEMENT | TCL_TRACE_READS);
2892        goto doStoreScalar;
2893
2894    case INST_LAPPEND_SCALAR1:
2895        opnd = TclGetUInt1AtPtr(pc+1);
2896        pcAdjustment = 2;
2897        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
2898                | TCL_LIST_ELEMENT | TCL_TRACE_READS);
2899        goto doStoreScalar;
2900
2901    case INST_APPEND_SCALAR4:
2902        opnd = TclGetUInt4AtPtr(pc+1);
2903        pcAdjustment = 5;
2904        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
2905        goto doStoreScalar;
2906
2907    case INST_APPEND_SCALAR1:
2908        opnd = TclGetUInt1AtPtr(pc+1);
2909        pcAdjustment = 2;
2910        storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
2911        goto doStoreScalar;
2912
2913    doStoreScalar:
2914        valuePtr = OBJ_AT_TOS;
2915        varPtr = &(compiledLocals[opnd]);
2916        TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
2917        while (TclIsVarLink(varPtr)) {
2918            varPtr = varPtr->value.linkPtr;
2919        }
2920        cleanup = 1;
2921        arrayPtr = NULL;
2922        part1Ptr = part2Ptr = NULL;
2923
2924    doCallPtrSetVar:
2925        DECACHE_STACK_INFO();
2926        objResultPtr = TclPtrSetVar(interp, varPtr, arrayPtr,
2927                part1Ptr, part2Ptr, valuePtr, storeFlags, opnd);
2928        CACHE_STACK_INFO();
2929        if (objResultPtr) {
2930#ifndef TCL_COMPILE_DEBUG
2931            if (*(pc+pcAdjustment) == INST_POP) {
2932                NEXT_INST_V((pcAdjustment+1), cleanup, 0);
2933            }
2934#endif
2935            TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
2936            NEXT_INST_V(pcAdjustment, cleanup, 1);
2937        } else {
2938            TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
2939            result = TCL_ERROR;
2940            goto checkForCatch;
2941        }
2942    }
2943
2944    /*
2945     *     End of INST_STORE and related instructions.
2946     * ---------------------------------------------------------
2947     */
2948
2949    /*
2950     * ---------------------------------------------------------
2951     *     Start of INST_INCR instructions.
2952     *
2953     * WARNING: more 'goto' here than your doctor recommended! The different
2954     * instructions set the value of some variables and then jump to somme
2955     * common execution code.
2956     */
2957
2958/*TODO: Consider more untangling here; merge with LOAD and STORE ? */
2959
2960    {
2961        Tcl_Obj *objPtr, *incrPtr;
2962        int opnd, pcAdjustment;
2963#ifndef NO_WIDE_TYPE
2964        Tcl_WideInt w;
2965#endif
2966        long i;
2967        Tcl_Obj *part1Ptr, *part2Ptr;
2968        Var *varPtr, *arrayPtr;
2969
2970    case INST_INCR_SCALAR1:
2971    case INST_INCR_ARRAY1:
2972    case INST_INCR_ARRAY_STK:
2973    case INST_INCR_SCALAR_STK:
2974    case INST_INCR_STK:
2975        opnd = TclGetUInt1AtPtr(pc+1);
2976        incrPtr = POP_OBJECT();
2977        switch (*pc) {
2978        case INST_INCR_SCALAR1:
2979            pcAdjustment = 2;
2980            goto doIncrScalar;
2981        case INST_INCR_ARRAY1:
2982            pcAdjustment = 2;
2983            goto doIncrArray;
2984        default:
2985            pcAdjustment = 1;
2986            goto doIncrStk;
2987        }
2988
2989    case INST_INCR_ARRAY_STK_IMM:
2990    case INST_INCR_SCALAR_STK_IMM:
2991    case INST_INCR_STK_IMM:
2992        i = TclGetInt1AtPtr(pc+1);
2993        incrPtr = Tcl_NewIntObj(i);
2994        Tcl_IncrRefCount(incrPtr);
2995        pcAdjustment = 2;
2996
2997    doIncrStk:
2998        if ((*pc == INST_INCR_ARRAY_STK_IMM)
2999                || (*pc == INST_INCR_ARRAY_STK)) {
3000            part2Ptr = OBJ_AT_TOS;
3001            objPtr = OBJ_UNDER_TOS;
3002            TRACE(("\"%.30s(%.30s)\" (by %ld) => ",
3003                    O2S(objPtr), O2S(part2Ptr), i));
3004        } else {
3005            part2Ptr = NULL;
3006            objPtr = OBJ_AT_TOS;
3007            TRACE(("\"%.30s\" (by %ld) => ", O2S(objPtr), i));
3008        }
3009        part1Ptr = objPtr;
3010        opnd = -1;
3011        varPtr = TclObjLookupVarEx(interp, objPtr, part2Ptr,
3012                TCL_LEAVE_ERR_MSG, "read", 1, 1, &arrayPtr);
3013        if (varPtr) {
3014            cleanup = ((part2Ptr == NULL)? 1 : 2);
3015            goto doIncrVar;
3016        } else {
3017            Tcl_AddObjErrorInfo(interp,
3018                    "\n    (reading value of variable to increment)", -1);
3019            TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
3020            result = TCL_ERROR;
3021            Tcl_DecrRefCount(incrPtr);
3022            goto checkForCatch;
3023        }
3024
3025    case INST_INCR_ARRAY1_IMM:
3026        opnd = TclGetUInt1AtPtr(pc+1);
3027        i = TclGetInt1AtPtr(pc+2);
3028        incrPtr = Tcl_NewIntObj(i);
3029        Tcl_IncrRefCount(incrPtr);
3030        pcAdjustment = 3;
3031
3032    doIncrArray:
3033        part1Ptr = NULL;
3034        part2Ptr = OBJ_AT_TOS;
3035        arrayPtr = &(compiledLocals[opnd]);
3036        cleanup = 1;
3037        while (TclIsVarLink(arrayPtr)) {
3038            arrayPtr = arrayPtr->value.linkPtr;
3039        }
3040        TRACE(("%u \"%.30s\" (by %ld) => ", opnd, O2S(part2Ptr), i));
3041        varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
3042                TCL_LEAVE_ERR_MSG, "read", 1, 1, arrayPtr, opnd);
3043        if (varPtr) {
3044            goto doIncrVar;
3045        } else {
3046            TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
3047            result = TCL_ERROR;
3048            Tcl_DecrRefCount(incrPtr);
3049            goto checkForCatch;
3050        }
3051
3052    case INST_INCR_SCALAR1_IMM:
3053        opnd = TclGetUInt1AtPtr(pc+1);
3054        i = TclGetInt1AtPtr(pc+2);
3055        pcAdjustment = 3;
3056        cleanup = 0;
3057        varPtr = &(compiledLocals[opnd]);
3058        while (TclIsVarLink(varPtr)) {
3059            varPtr = varPtr->value.linkPtr;
3060        }
3061
3062        if (TclIsVarDirectModifyable(varPtr)) {
3063            ClientData ptr;
3064            int type;
3065
3066            objPtr = varPtr->value.objPtr;
3067            if (GetNumberFromObj(NULL, objPtr, &ptr, &type) == TCL_OK) {
3068                if (type == TCL_NUMBER_LONG) {
3069                    long augend = *((const long *)ptr);
3070                    long sum = augend + i;
3071
3072                    /*
3073                     * Overflow when (augend and sum have different sign) and
3074                     * (augend and i have the same sign). This is encapsulated
3075                     * in the Overflowing macro.
3076                     */
3077
3078                    if (!Overflowing(augend, i, sum)) {
3079                        TRACE(("%u %ld => ", opnd, i));
3080                        if (Tcl_IsShared(objPtr)) {
3081                            objPtr->refCount--; /* We know it's shared. */
3082                            TclNewLongObj(objResultPtr, sum);
3083                            Tcl_IncrRefCount(objResultPtr);
3084                            varPtr->value.objPtr = objResultPtr;
3085                        } else {
3086                            objResultPtr = objPtr;
3087                            TclSetLongObj(objPtr, sum);
3088                        }
3089                        goto doneIncr;
3090                    }
3091#ifndef NO_WIDE_TYPE
3092                    {
3093                        w = (Tcl_WideInt)augend;
3094
3095                        TRACE(("%u %ld => ", opnd, i));
3096                        if (Tcl_IsShared(objPtr)) {
3097                            objPtr->refCount--; /* We know it's shared. */
3098                            objResultPtr = Tcl_NewWideIntObj(w+i);
3099                            Tcl_IncrRefCount(objResultPtr);
3100                            varPtr->value.objPtr = objResultPtr;
3101                        } else {
3102                            objResultPtr = objPtr;
3103
3104                            /*
3105                             * We know the sum value is outside the long
3106                             * range; use macro form that doesn't range test
3107                             * again.
3108                             */
3109
3110                            TclSetWideIntObj(objPtr, w+i);
3111                        }
3112                        goto doneIncr;
3113                    }
3114#endif
3115                }       /* end if (type == TCL_NUMBER_LONG) */
3116#ifndef NO_WIDE_TYPE
3117                if (type == TCL_NUMBER_WIDE) {
3118                    Tcl_WideInt sum;
3119                    w = *((const Tcl_WideInt *)ptr);
3120                    sum = w + i;
3121
3122                    /*
3123                     * Check for overflow.
3124                     */
3125
3126                    if (!Overflowing(w, i, sum)) {
3127                        TRACE(("%u %ld => ", opnd, i));
3128                        if (Tcl_IsShared(objPtr)) {
3129                            objPtr->refCount--; /* We know it's shared. */
3130                            objResultPtr = Tcl_NewWideIntObj(sum);
3131                            Tcl_IncrRefCount(objResultPtr);
3132                            varPtr->value.objPtr = objResultPtr;
3133                        } else {
3134                            objResultPtr = objPtr;
3135
3136                            /*
3137                             * We *do not* know the sum value is outside the
3138                             * long range (wide + long can yield long); use
3139                             * the function call that checks range.
3140                             */
3141
3142                            Tcl_SetWideIntObj(objPtr, sum);
3143                        }
3144                        goto doneIncr;
3145                    }
3146                }
3147#endif
3148            }
3149            if (Tcl_IsShared(objPtr)) {
3150                objPtr->refCount--;     /* We know it's shared */
3151                objResultPtr = Tcl_DuplicateObj(objPtr);
3152                Tcl_IncrRefCount(objResultPtr);
3153                varPtr->value.objPtr = objResultPtr;
3154            } else {
3155                objResultPtr = objPtr;
3156            }
3157            TclNewLongObj(incrPtr, i);
3158            result = TclIncrObj(interp, objResultPtr, incrPtr);
3159            Tcl_DecrRefCount(incrPtr);
3160            if (result == TCL_OK) {
3161                goto doneIncr;
3162            } else {
3163                TRACE_APPEND(("ERROR: %.30s\n",
3164                        O2S(Tcl_GetObjResult(interp))));
3165                goto checkForCatch;
3166            }
3167        }
3168
3169        /*
3170         * All other cases, flow through to generic handling.
3171         */
3172
3173        TclNewLongObj(incrPtr, i);
3174        Tcl_IncrRefCount(incrPtr);
3175
3176    doIncrScalar:
3177        varPtr = &(compiledLocals[opnd]);
3178        while (TclIsVarLink(varPtr)) {
3179            varPtr = varPtr->value.linkPtr;
3180        }
3181        arrayPtr = NULL;
3182        part1Ptr = part2Ptr = NULL;
3183        cleanup = 0;
3184        TRACE(("%u %ld => ", opnd, i));
3185
3186    doIncrVar:
3187        if (TclIsVarDirectModifyable2(varPtr, arrayPtr)) {
3188            objPtr = varPtr->value.objPtr;
3189            if (Tcl_IsShared(objPtr)) {
3190                objPtr->refCount--;     /* We know it's shared */
3191                objResultPtr = Tcl_DuplicateObj(objPtr);
3192                Tcl_IncrRefCount(objResultPtr);
3193                varPtr->value.objPtr = objResultPtr;
3194            } else {
3195                objResultPtr = objPtr;
3196            }
3197            result = TclIncrObj(interp, objResultPtr, incrPtr);
3198            Tcl_DecrRefCount(incrPtr);
3199            if (result == TCL_OK) {
3200                goto doneIncr;
3201            } else {
3202                TRACE_APPEND(("ERROR: %.30s\n",
3203                        O2S(Tcl_GetObjResult(interp))));
3204                goto checkForCatch;
3205            }
3206        } else {
3207            DECACHE_STACK_INFO();
3208            objResultPtr = TclPtrIncrObjVar(interp, varPtr, arrayPtr,
3209                    part1Ptr, part2Ptr, incrPtr, TCL_LEAVE_ERR_MSG, opnd);
3210            CACHE_STACK_INFO();
3211            Tcl_DecrRefCount(incrPtr);
3212            if (objResultPtr == NULL) {
3213                TRACE_APPEND(("ERROR: %.30s\n",
3214                        O2S(Tcl_GetObjResult(interp))));
3215                result = TCL_ERROR;
3216                goto checkForCatch;
3217            }
3218        }
3219    doneIncr:
3220        TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
3221#ifndef TCL_COMPILE_DEBUG
3222        if (*(pc+pcAdjustment) == INST_POP) {
3223            NEXT_INST_V((pcAdjustment+1), cleanup, 0);
3224        }
3225#endif
3226        NEXT_INST_V(pcAdjustment, cleanup, 1);
3227    }
3228
3229    /*
3230     *     End of INST_INCR instructions.
3231     * ---------------------------------------------------------
3232     */
3233
3234    /*
3235     * ---------------------------------------------------------
3236     *     Start of INST_EXIST instructions.
3237     */
3238    {
3239        Tcl_Obj *part1Ptr, *part2Ptr;
3240        Var *varPtr, *arrayPtr;
3241
3242    case INST_EXIST_SCALAR: {
3243        int opnd = TclGetUInt4AtPtr(pc+1);
3244
3245        varPtr = &(compiledLocals[opnd]);
3246        while (TclIsVarLink(varPtr)) {
3247            varPtr = varPtr->value.linkPtr;
3248        }
3249        TRACE(("%u => ", opnd));
3250        if (ReadTraced(varPtr)) {
3251            DECACHE_STACK_INFO();
3252            TclObjCallVarTraces(iPtr, NULL, varPtr, NULL, NULL,
3253                    TCL_TRACE_READS, 0, opnd);
3254            CACHE_STACK_INFO();
3255            if (TclIsVarUndefined(varPtr)) {
3256                TclCleanupVar(varPtr, NULL);
3257                varPtr = NULL;
3258            }
3259        }
3260
3261        /*
3262         * Tricky! Arrays always exist.
3263         */
3264
3265        objResultPtr = constants[!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1];
3266        TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
3267        NEXT_INST_F(5, 0, 1);
3268    }
3269
3270    case INST_EXIST_ARRAY: {
3271        int opnd = TclGetUInt4AtPtr(pc+1);
3272
3273        part2Ptr = OBJ_AT_TOS;
3274        arrayPtr = &(compiledLocals[opnd]);
3275        while (TclIsVarLink(arrayPtr)) {
3276            arrayPtr = arrayPtr->value.linkPtr;
3277        }
3278        TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
3279        if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) {
3280            varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
3281            if (!varPtr || !ReadTraced(varPtr)) {
3282                goto doneExistArray;
3283            }
3284        }
3285        varPtr = TclLookupArrayElement(interp, NULL, part2Ptr, 0, "access",
3286                0, 1, arrayPtr, opnd);
3287        if (varPtr) {
3288            if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) {
3289                DECACHE_STACK_INFO();
3290                TclObjCallVarTraces(iPtr, arrayPtr, varPtr, NULL, part2Ptr,
3291                        TCL_TRACE_READS, 0, opnd);
3292                CACHE_STACK_INFO();
3293            }
3294            if (TclIsVarUndefined(varPtr)) {
3295                TclCleanupVar(varPtr, arrayPtr);
3296                varPtr = NULL;
3297            }
3298        }
3299    doneExistArray:
3300        objResultPtr = constants[!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1];
3301        TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
3302        NEXT_INST_F(5, 1, 1);
3303    }
3304
3305    case INST_EXIST_ARRAY_STK:
3306        cleanup = 2;
3307        part2Ptr = OBJ_AT_TOS;          /* element name */
3308        part1Ptr = OBJ_UNDER_TOS;       /* array name */
3309        TRACE(("\"%.30s(%.30s)\" => ", O2S(part1Ptr), O2S(part2Ptr)));
3310        goto doExistStk;
3311
3312    case INST_EXIST_STK:
3313        cleanup = 1;
3314        part2Ptr = NULL;
3315        part1Ptr = OBJ_AT_TOS;          /* variable name */
3316        TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
3317
3318    doExistStk:
3319        varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, 0, "access",
3320                /*createPart1*/0, /*createPart2*/1, &arrayPtr);
3321        if (varPtr) {
3322            if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) {
3323                DECACHE_STACK_INFO();
3324                TclObjCallVarTraces(iPtr, arrayPtr, varPtr, part1Ptr,part2Ptr,
3325                        TCL_TRACE_READS, 0, -1);
3326                CACHE_STACK_INFO();
3327            }
3328            if (TclIsVarUndefined(varPtr)) {
3329                TclCleanupVar(varPtr, arrayPtr);
3330                varPtr = NULL;
3331            }
3332        }
3333        objResultPtr = constants[!varPtr || TclIsVarUndefined(varPtr) ? 0 : 1];
3334        TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
3335        NEXT_INST_V(1, cleanup, 1);
3336    }
3337
3338    /*
3339     *     End of INST_EXIST instructions.
3340     * ---------------------------------------------------------
3341     */
3342
3343    case INST_UPVAR: {
3344        int opnd;
3345        Var *varPtr, *otherPtr;
3346
3347        TRACE_WITH_OBJ(("upvar "), OBJ_UNDER_TOS);
3348
3349        {
3350            CallFrame *framePtr, *savedFramePtr;
3351
3352            result = TclObjGetFrame(interp, OBJ_UNDER_TOS, &framePtr);
3353            if (result != -1) {
3354                /*
3355                 * Locate the other variable.
3356                 */
3357
3358                savedFramePtr = iPtr->varFramePtr;
3359                iPtr->varFramePtr = framePtr;
3360                otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
3361                        (TCL_LEAVE_ERR_MSG), "access",
3362                        /*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
3363                iPtr->varFramePtr = savedFramePtr;
3364                if (otherPtr) {
3365                    result = TCL_OK;
3366                    goto doLinkVars;
3367                }
3368            }
3369            result = TCL_ERROR;
3370            goto checkForCatch;
3371        }
3372
3373    case INST_VARIABLE:
3374        TRACE(("variable "));
3375        otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
3376                (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
3377                /*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
3378        if (otherPtr) {
3379            /*
3380             * Do the [variable] magic.
3381             */
3382
3383            TclSetVarNamespaceVar(otherPtr);
3384            result = TCL_OK;
3385            goto doLinkVars;
3386        }
3387        result = TCL_ERROR;
3388        goto checkForCatch;
3389
3390    case INST_NSUPVAR:
3391        TRACE_WITH_OBJ(("nsupvar "), OBJ_UNDER_TOS);
3392
3393        {
3394            Tcl_Namespace *nsPtr, *savedNsPtr;
3395
3396            result = TclGetNamespaceFromObj(interp, OBJ_UNDER_TOS, &nsPtr);
3397            if (result == TCL_OK) {
3398                /*
3399                 * Locate the other variable.
3400                 */
3401
3402                savedNsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
3403                iPtr->varFramePtr->nsPtr = (Namespace *) nsPtr;
3404                otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
3405                        (TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
3406                        /*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
3407                iPtr->varFramePtr->nsPtr = (Namespace *) savedNsPtr;
3408                if (otherPtr) {
3409                    goto doLinkVars;
3410                }
3411            }
3412            result = TCL_ERROR;
3413            goto checkForCatch;
3414        }
3415
3416    doLinkVars:
3417
3418        /*
3419         * If we are here, the local variable has already been created: do the
3420         * little work of TclPtrMakeUpvar that remains to be done right here
3421         * if there are no errors; otherwise, let it handle the case.
3422         */
3423
3424        opnd = TclGetInt4AtPtr(pc+1);;
3425        varPtr = &(compiledLocals[opnd]);
3426        if ((varPtr != otherPtr) && !TclIsVarTraced(varPtr)
3427                && (TclIsVarUndefined(varPtr) || TclIsVarLink(varPtr))) {
3428            if (!TclIsVarUndefined(varPtr)) {
3429                /*
3430                 * Then it is a defined link.
3431                 */
3432
3433                Var *linkPtr = varPtr->value.linkPtr;
3434
3435                if (linkPtr == otherPtr) {
3436                    goto doLinkVarsDone;
3437                }
3438                if (TclIsVarInHash(linkPtr)) {
3439                    VarHashRefCount(linkPtr)--;
3440                    if (TclIsVarUndefined(linkPtr)) {
3441                        TclCleanupVar(linkPtr, NULL);
3442                    }
3443                }
3444            }
3445            TclSetVarLink(varPtr);
3446            varPtr->value.linkPtr = otherPtr;
3447            if (TclIsVarInHash(otherPtr)) {
3448                VarHashRefCount(otherPtr)++;
3449            }
3450        } else {
3451            result = TclPtrObjMakeUpvar(interp, otherPtr, NULL, 0, opnd);
3452            if (result != TCL_OK) {
3453                goto checkForCatch;
3454            }
3455        }
3456
3457        /*
3458         * Do not pop the namespace or frame index, it may be needed for other
3459         * variables - and [variable] did not push it at all.
3460         */
3461
3462    doLinkVarsDone:
3463        NEXT_INST_F(5, 1, 0);
3464    }
3465
3466    case INST_JUMP1: {
3467        int opnd = TclGetInt1AtPtr(pc+1);
3468
3469        TRACE(("%d => new pc %u\n", opnd,
3470                (unsigned)(pc + opnd - codePtr->codeStart)));
3471        NEXT_INST_F(opnd, 0, 0);
3472    }
3473
3474    case INST_JUMP4: {
3475        int opnd = TclGetInt4AtPtr(pc+1);
3476
3477        TRACE(("%d => new pc %u\n", opnd,
3478                (unsigned)(pc + opnd - codePtr->codeStart)));
3479        NEXT_INST_F(opnd, 0, 0);
3480    }
3481
3482    {
3483        int jmpOffset[2], b;
3484        Tcl_Obj *valuePtr;
3485
3486        /* TODO: consider rewrite so we don't compute the offset we're not
3487         * going to take. */
3488    case INST_JUMP_FALSE4:
3489        jmpOffset[0] = TclGetInt4AtPtr(pc+1);   /* FALSE offset */
3490        jmpOffset[1] = 5;                       /* TRUE offset*/
3491        goto doCondJump;
3492
3493    case INST_JUMP_TRUE4:
3494        jmpOffset[0] = 5;
3495        jmpOffset[1] = TclGetInt4AtPtr(pc+1);
3496        goto doCondJump;
3497
3498    case INST_JUMP_FALSE1:
3499        jmpOffset[0] = TclGetInt1AtPtr(pc+1);
3500        jmpOffset[1] = 2;
3501        goto doCondJump;
3502
3503    case INST_JUMP_TRUE1:
3504        jmpOffset[0] = 2;
3505        jmpOffset[1] = TclGetInt1AtPtr(pc+1);
3506
3507    doCondJump:
3508        valuePtr = OBJ_AT_TOS;
3509
3510        /* TODO - check claim that taking address of b harms performance */
3511        /* TODO - consider optimization search for constants */
3512        result = TclGetBooleanFromObj(interp, valuePtr, &b);
3513        if (result != TCL_OK) {
3514            TRACE_WITH_OBJ(("%d => ERROR: ", jmpOffset[
3515                    ((*pc == INST_JUMP_FALSE1) || (*pc == INST_JUMP_FALSE4))
3516                    ? 0 : 1]), Tcl_GetObjResult(interp));
3517            goto checkForCatch;
3518        }
3519
3520#ifdef TCL_COMPILE_DEBUG
3521        if (b) {
3522            if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
3523                TRACE(("%d => %.20s true, new pc %u\n", jmpOffset[1],
3524                        O2S(valuePtr),
3525                        (unsigned)(pc + jmpOffset[1] - codePtr->codeStart)));
3526            } else {
3527                TRACE(("%d => %.20s true\n", jmpOffset[0], O2S(valuePtr)));
3528            }
3529        } else {
3530            if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
3531                TRACE(("%d => %.20s false\n", jmpOffset[0], O2S(valuePtr)));
3532            } else {
3533                TRACE(("%d => %.20s false, new pc %u\n", jmpOffset[0],
3534                        O2S(valuePtr),
3535                        (unsigned)(pc + jmpOffset[1] - codePtr->codeStart)));
3536            }
3537        }
3538#endif
3539        NEXT_INST_F(jmpOffset[b], 1, 0);
3540    }
3541
3542    case INST_JUMP_TABLE: {
3543        Tcl_HashEntry *hPtr;
3544        JumptableInfo *jtPtr;
3545        int opnd;
3546
3547        /*
3548         * Jump to location looked up in a hashtable; fall through to next
3549         * instr if lookup fails.
3550         */
3551
3552        opnd = TclGetInt4AtPtr(pc+1);
3553        jtPtr = (JumptableInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
3554        TRACE(("%d => %.20s ", opnd, O2S(OBJ_AT_TOS)));
3555        hPtr = Tcl_FindHashEntry(&jtPtr->hashTable, TclGetString(OBJ_AT_TOS));
3556        if (hPtr != NULL) {
3557            int jumpOffset = PTR2INT(Tcl_GetHashValue(hPtr));
3558
3559            TRACE_APPEND(("found in table, new pc %u\n",
3560                    (unsigned)(pc - codePtr->codeStart + jumpOffset)));
3561            NEXT_INST_F(jumpOffset, 1, 0);
3562        } else {
3563            TRACE_APPEND(("not found in table\n"));
3564            NEXT_INST_F(5, 1, 0);
3565        }
3566    }
3567
3568    /*
3569     * These two instructions are now redundant: the complete logic of the LOR
3570     * and LAND is now handled by the expression compiler.
3571     */
3572
3573    case INST_LOR:
3574    case INST_LAND: {
3575        /*
3576         * Operands must be boolean or numeric. No int->double conversions are
3577         * performed.
3578         */
3579
3580        int i1, i2, iResult;
3581        Tcl_Obj *value2Ptr = OBJ_AT_TOS;
3582        Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
3583
3584        result = TclGetBooleanFromObj(NULL, valuePtr, &i1);
3585        if (result != TCL_OK) {
3586            TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
3587                    (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
3588            IllegalExprOperandType(interp, pc, valuePtr);
3589            goto checkForCatch;
3590        }
3591
3592        result = TclGetBooleanFromObj(NULL, value2Ptr, &i2);
3593        if (result != TCL_OK) {
3594            TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(value2Ptr),
3595                    (value2Ptr->typePtr? value2Ptr->typePtr->name : "null")));
3596            IllegalExprOperandType(interp, pc, value2Ptr);
3597            goto checkForCatch;
3598        }
3599
3600        if (*pc == INST_LOR) {
3601            iResult = (i1 || i2);
3602        } else {
3603            iResult = (i1 && i2);
3604        }
3605        objResultPtr = constants[iResult];
3606        TRACE(("%.20s %.20s => %d\n", O2S(valuePtr),O2S(value2Ptr),iResult));
3607        NEXT_INST_F(1, 2, 1);
3608    }
3609
3610    /*
3611     * ---------------------------------------------------------
3612     *     Start of INST_LIST and related instructions.
3613     */
3614
3615    case INST_LIST: {
3616        /*
3617         * Pop the opnd (objc) top stack elements into a new list obj and then
3618         * decrement their ref counts.
3619         */
3620
3621        int opnd;
3622
3623        opnd = TclGetUInt4AtPtr(pc+1);
3624        objResultPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1));
3625        TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
3626        NEXT_INST_V(5, opnd, 1);
3627    }
3628
3629    case INST_LIST_LENGTH: {
3630        Tcl_Obj *valuePtr;
3631        int length;
3632
3633        valuePtr = OBJ_AT_TOS;
3634
3635        result = TclListObjLength(interp, valuePtr, &length);
3636        if (result == TCL_OK) {
3637            TclNewIntObj(objResultPtr, length);
3638            TRACE(("%.20s => %d\n", O2S(valuePtr), length));
3639            NEXT_INST_F(1, 1, 1);
3640        } else {
3641            TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
3642                    Tcl_GetObjResult(interp));
3643            goto checkForCatch;
3644        }
3645    }
3646
3647    case INST_LIST_INDEX: {
3648        /*** lindex with objc == 3 ***/
3649
3650        /* Variables also for INST_LIST_INDEX_IMM */
3651
3652        int listc, idx, opnd, pcAdjustment;
3653        Tcl_Obj **listv;
3654        Tcl_Obj *valuePtr, *value2Ptr;
3655
3656        /*
3657         * Pop the two operands.
3658         */
3659
3660        value2Ptr = OBJ_AT_TOS;
3661        valuePtr = OBJ_UNDER_TOS;
3662
3663        /*
3664         * Extract the desired list element.
3665         */
3666
3667        result = TclListObjGetElements(interp, valuePtr, &listc, &listv);
3668        if ((result == TCL_OK) && (value2Ptr->typePtr != &tclListType)
3669                && (TclGetIntForIndexM(NULL , value2Ptr, listc-1,
3670                        &idx) == TCL_OK)) {
3671            TclDecrRefCount(value2Ptr);
3672            tosPtr--;
3673            pcAdjustment = 1;
3674            goto lindexFastPath;
3675        }
3676
3677        objResultPtr = TclLindexList(interp, valuePtr, value2Ptr);
3678        if (objResultPtr) {
3679            /*
3680             * Stash the list element on the stack.
3681             */
3682
3683            TRACE(("%.20s %.20s => %s\n",
3684                    O2S(valuePtr), O2S(value2Ptr), O2S(objResultPtr)));
3685            NEXT_INST_F(1, 2, -1);      /* Already has the correct refCount */
3686        } else {
3687            TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ", O2S(valuePtr),
3688                    O2S(value2Ptr)), Tcl_GetObjResult(interp));
3689            result = TCL_ERROR;
3690            goto checkForCatch;
3691        }
3692
3693    case INST_LIST_INDEX_IMM:
3694        /*** lindex with objc==3 and index in bytecode stream ***/
3695
3696        pcAdjustment = 5;
3697
3698        /*
3699         * Pop the list and get the index.
3700         */
3701
3702        valuePtr = OBJ_AT_TOS;
3703        opnd = TclGetInt4AtPtr(pc+1);
3704
3705        /*
3706         * Get the contents of the list, making sure that it really is a list
3707         * in the process.
3708         */
3709
3710        result = TclListObjGetElements(interp, valuePtr, &listc, &listv);
3711
3712        if (result == TCL_OK) {
3713            /*
3714             * Select the list item based on the index. Negative operand means
3715             * end-based indexing.
3716             */
3717
3718            if (opnd < -1) {
3719                idx = opnd+1 + listc;
3720            } else {
3721                idx = opnd;
3722            }
3723
3724        lindexFastPath:
3725            if (idx >= 0 && idx < listc) {
3726                objResultPtr = listv[idx];
3727            } else {
3728                TclNewObj(objResultPtr);
3729            }
3730
3731            TRACE_WITH_OBJ(("\"%.30s\" %d => ", O2S(valuePtr), opnd),
3732                    objResultPtr);
3733            NEXT_INST_F(pcAdjustment, 1, 1);
3734        } else {
3735            TRACE_WITH_OBJ(("\"%.30s\" %d => ERROR: ", O2S(valuePtr), opnd),
3736                    Tcl_GetObjResult(interp));
3737            goto checkForCatch;
3738        }
3739    }
3740
3741    case INST_LIST_INDEX_MULTI: {
3742        /*
3743         * 'lindex' with multiple index args:
3744         *
3745         * Determine the count of index args.
3746         */
3747
3748        int numIdx, opnd;
3749
3750        opnd = TclGetUInt4AtPtr(pc+1);
3751        numIdx = opnd-1;
3752
3753        /*
3754         * Do the 'lindex' operation.
3755         */
3756
3757        objResultPtr = TclLindexFlat(interp, OBJ_AT_DEPTH(numIdx),
3758                numIdx, &OBJ_AT_DEPTH(numIdx - 1));
3759
3760        /*
3761         * Check for errors.
3762         */
3763
3764        if (objResultPtr) {
3765            /*
3766             * Set result.
3767             */
3768
3769            TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
3770            NEXT_INST_V(5, opnd, -1);
3771        } else {
3772            TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
3773            result = TCL_ERROR;
3774            goto checkForCatch;
3775        }
3776    }
3777
3778    case INST_LSET_FLAT: {
3779        /*
3780         * Lset with 3, 5, or more args. Get the number of index args.
3781         */
3782
3783        int numIdx,opnd;
3784        Tcl_Obj *valuePtr, *value2Ptr;
3785
3786        opnd = TclGetUInt4AtPtr(pc + 1);
3787        numIdx = opnd - 2;
3788
3789        /*
3790         * Get the old value of variable, and remove the stack ref. This is
3791         * safe because the variable still references the object; the ref
3792         * count will never go zero here - we can use the smaller macro
3793         * Tcl_DecrRefCount.
3794         */
3795
3796        value2Ptr = POP_OBJECT();
3797        Tcl_DecrRefCount(value2Ptr); /* This one should be done here */
3798
3799        /*
3800         * Get the new element value.
3801         */
3802
3803        valuePtr = OBJ_AT_TOS;
3804
3805        /*
3806         * Compute the new variable value.
3807         */
3808
3809        objResultPtr = TclLsetFlat(interp, value2Ptr, numIdx,
3810                &OBJ_AT_DEPTH(numIdx), valuePtr);
3811
3812        /*
3813         * Check for errors.
3814         */
3815
3816        if (objResultPtr) {
3817            /*
3818             * Set result.
3819             */
3820
3821            TRACE(("%d => %s\n", opnd, O2S(objResultPtr)));
3822            NEXT_INST_V(5, (numIdx+1), -1);
3823        } else {
3824            TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
3825            result = TCL_ERROR;
3826            goto checkForCatch;
3827        }
3828    }
3829
3830    case INST_LSET_LIST: {
3831        /*
3832         * 'lset' with 4 args.
3833         */
3834
3835        Tcl_Obj *objPtr, *valuePtr, *value2Ptr;
3836
3837        /*
3838         * Get the old value of variable, and remove the stack ref. This is
3839         * safe because the variable still references the object; the ref
3840         * count will never go zero here - we can use the smaller macro
3841         * Tcl_DecrRefCount.
3842         */
3843
3844        objPtr = POP_OBJECT();
3845        Tcl_DecrRefCount(objPtr);       /* This one should be done here. */
3846
3847        /*
3848         * Get the new element value, and the index list.
3849         */
3850
3851        valuePtr = OBJ_AT_TOS;
3852        value2Ptr = OBJ_UNDER_TOS;
3853
3854        /*
3855         * Compute the new variable value.
3856         */
3857
3858        objResultPtr = TclLsetList(interp, objPtr, value2Ptr, valuePtr);
3859
3860        /*
3861         * Check for errors.
3862         */
3863
3864        if (objResultPtr) {
3865            /*
3866             * Set result.
3867             */
3868
3869            TRACE(("=> %s\n", O2S(objResultPtr)));
3870            NEXT_INST_F(1, 2, -1);
3871        } else {
3872            TRACE_WITH_OBJ(("\"%.30s\" => ERROR: ", O2S(value2Ptr)),
3873                    Tcl_GetObjResult(interp));
3874            result = TCL_ERROR;
3875            goto checkForCatch;
3876        }
3877    }
3878
3879    case INST_LIST_RANGE_IMM: {
3880        /*** lrange with objc==4 and both indices in bytecode stream ***/
3881
3882        int listc, fromIdx, toIdx;
3883        Tcl_Obj **listv, *valuePtr;
3884
3885        /*
3886         * Pop the list and get the indices.
3887         */
3888
3889        valuePtr = OBJ_AT_TOS;
3890        fromIdx = TclGetInt4AtPtr(pc+1);
3891        toIdx = TclGetInt4AtPtr(pc+5);
3892
3893        /*
3894         * Get the contents of the list, making sure that it really is a list
3895         * in the process.
3896         */
3897        result = TclListObjGetElements(interp, valuePtr, &listc, &listv);
3898
3899        /*
3900         * Skip a lot of work if we're about to throw the result away (common
3901         * with uses of [lassign]).
3902         */
3903
3904        if (result == TCL_OK) {
3905#ifndef TCL_COMPILE_DEBUG
3906            if (*(pc+9) == INST_POP) {
3907                NEXT_INST_F(10, 1, 0);
3908            }
3909#endif
3910        } else {
3911            TRACE_WITH_OBJ(("\"%.30s\" %d %d => ERROR: ", O2S(valuePtr),
3912                    fromIdx, toIdx), Tcl_GetObjResult(interp));
3913            goto checkForCatch;
3914        }
3915
3916        /*
3917         * Adjust the indices for end-based handling.
3918         */
3919
3920        if (fromIdx < -1) {
3921            fromIdx += 1+listc;
3922            if (fromIdx < -1) {
3923                fromIdx = -1;
3924            }
3925        } else if (fromIdx > listc) {
3926            fromIdx = listc;
3927        }
3928        if (toIdx < -1) {
3929            toIdx += 1+listc;
3930            if (toIdx < -1) {
3931                toIdx = -1;
3932            }
3933        } else if (toIdx > listc) {
3934            toIdx = listc;
3935        }
3936
3937        /*
3938         * Check if we are referring to a valid, non-empty list range, and if
3939         * so, build the list of elements in that range.
3940         */
3941
3942        if (fromIdx<=toIdx && fromIdx<listc && toIdx>=0) {
3943            if (fromIdx<0) {
3944                fromIdx = 0;
3945            }
3946            if (toIdx >= listc) {
3947                toIdx = listc-1;
3948            }
3949            objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, listv+fromIdx);
3950        } else {
3951            TclNewObj(objResultPtr);
3952        }
3953
3954        TRACE_WITH_OBJ(("\"%.30s\" %d %d => ", O2S(valuePtr),
3955                TclGetInt4AtPtr(pc+1), TclGetInt4AtPtr(pc+5)), objResultPtr);
3956        NEXT_INST_F(9, 1, 1);
3957    }
3958
3959    case INST_LIST_IN:
3960    case INST_LIST_NOT_IN: {
3961        /*
3962         * Basic list containment operators.
3963         */
3964
3965        int found, s1len, s2len, llen, i;
3966        Tcl_Obj *valuePtr, *value2Ptr, *o;
3967        char *s1;
3968        const char *s2;
3969
3970        value2Ptr = OBJ_AT_TOS;
3971        valuePtr = OBJ_UNDER_TOS;
3972
3973        /* TODO: Consider more efficient tests than strcmp() */
3974        s1 = TclGetStringFromObj(valuePtr, &s1len);
3975        result = TclListObjLength(interp, value2Ptr, &llen);
3976        if (result != TCL_OK) {
3977            TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ERROR: ", O2S(valuePtr),
3978                    O2S(value2Ptr)), Tcl_GetObjResult(interp));
3979            goto checkForCatch;
3980        }
3981        found = 0;
3982        if (llen > 0) {
3983            /*
3984             * An empty list doesn't match anything.
3985             */
3986
3987            i = 0;
3988            do {
3989                Tcl_ListObjIndex(NULL, value2Ptr, i, &o);
3990                if (o != NULL) {
3991                    s2 = TclGetStringFromObj(o, &s2len);
3992                } else {
3993                    s2 = "";
3994                }
3995                if (s1len == s2len) {
3996                    found = (strcmp(s1, s2) == 0);
3997                }
3998                i++;
3999            } while (i < llen && found == 0);
4000        }
4001
4002        if (*pc == INST_LIST_NOT_IN) {
4003            found = !found;
4004        }
4005
4006        TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), found));
4007
4008        /*
4009         * Peep-hole optimisation: if you're about to jump, do jump from here.
4010         * We're saving the effort of pushing a boolean value only to pop it
4011         * for branching.
4012         */
4013
4014        pc++;
4015#ifndef TCL_COMPILE_DEBUG
4016        switch (*pc) {
4017        case INST_JUMP_FALSE1:
4018            NEXT_INST_F((found ? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
4019        case INST_JUMP_TRUE1:
4020            NEXT_INST_F((found ? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
4021        case INST_JUMP_FALSE4:
4022            NEXT_INST_F((found ? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
4023        case INST_JUMP_TRUE4:
4024            NEXT_INST_F((found ? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
4025        }
4026#endif
4027        objResultPtr = constants[found];
4028        NEXT_INST_F(0, 2, 1);
4029    }
4030
4031    /*
4032     *     End of INST_LIST and related instructions.
4033     * ---------------------------------------------------------
4034     */
4035
4036    case INST_STR_EQ:
4037    case INST_STR_NEQ: {
4038        /*
4039         * String (in)equality check
4040         * TODO: Consider merging into INST_STR_CMP
4041         */
4042
4043        int iResult;
4044        Tcl_Obj *valuePtr, *value2Ptr;
4045
4046        value2Ptr = OBJ_AT_TOS;
4047        valuePtr = OBJ_UNDER_TOS;
4048
4049        if (valuePtr == value2Ptr) {
4050            /*
4051             * On the off-chance that the objects are the same, we don't
4052             * really have to think hard about equality.
4053             */
4054
4055            iResult = (*pc == INST_STR_EQ);
4056        } else {
4057            char *s1, *s2;
4058            int s1len, s2len;
4059
4060            s1 = TclGetStringFromObj(valuePtr, &s1len);
4061            s2 = TclGetStringFromObj(value2Ptr, &s2len);
4062            if (s1len == s2len) {
4063                /*
4064                 * We only need to check (in)equality when we have equal
4065                 * length strings.
4066                 */
4067
4068                if (*pc == INST_STR_NEQ) {
4069                    iResult = (strcmp(s1, s2) != 0);
4070                } else {
4071                    /* INST_STR_EQ */
4072                    iResult = (strcmp(s1, s2) == 0);
4073                }
4074            } else {
4075                iResult = (*pc == INST_STR_NEQ);
4076            }
4077        }
4078
4079        TRACE(("%.20s %.20s => %d\n", O2S(valuePtr),O2S(value2Ptr),iResult));
4080
4081        /*
4082         * Peep-hole optimisation: if you're about to jump, do jump from here.
4083         */
4084
4085        pc++;
4086#ifndef TCL_COMPILE_DEBUG
4087        switch (*pc) {
4088        case INST_JUMP_FALSE1:
4089            NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
4090        case INST_JUMP_TRUE1:
4091            NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
4092        case INST_JUMP_FALSE4:
4093            NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
4094        case INST_JUMP_TRUE4:
4095            NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
4096        }
4097#endif
4098        objResultPtr = constants[iResult];
4099        NEXT_INST_F(0, 2, 1);
4100    }
4101
4102    case INST_STR_CMP: {
4103        /*
4104         * String compare.
4105         */
4106
4107        const char *s1, *s2;
4108        int s1len, s2len, iResult;
4109        Tcl_Obj *valuePtr, *value2Ptr;
4110
4111    stringCompare:
4112        value2Ptr = OBJ_AT_TOS;
4113        valuePtr = OBJ_UNDER_TOS;
4114
4115        /*
4116         * The comparison function should compare up to the minimum byte
4117         * length only.
4118         */
4119
4120        if (valuePtr == value2Ptr) {
4121            /*
4122             * In the pure equality case, set lengths too for the checks below
4123             * (or we could goto beyond it).
4124             */
4125
4126            iResult = s1len = s2len = 0;
4127        } else if ((valuePtr->typePtr == &tclByteArrayType)
4128                && (value2Ptr->typePtr == &tclByteArrayType)) {
4129            s1 = (char *) Tcl_GetByteArrayFromObj(valuePtr, &s1len);
4130            s2 = (char *) Tcl_GetByteArrayFromObj(value2Ptr, &s2len);
4131            iResult = memcmp(s1, s2,
4132                    (size_t) ((s1len < s2len) ? s1len : s2len));
4133        } else if (((valuePtr->typePtr == &tclStringType)
4134                && (value2Ptr->typePtr == &tclStringType))) {
4135            /*
4136             * Do a unicode-specific comparison if both of the args are of
4137             * String type. If the char length == byte length, we can do a
4138             * memcmp. In benchmark testing this proved the most efficient
4139             * check between the unicode and string comparison operations.
4140             */
4141
4142            s1len = Tcl_GetCharLength(valuePtr);
4143            s2len = Tcl_GetCharLength(value2Ptr);
4144            if ((s1len == valuePtr->length) && (s2len == value2Ptr->length)) {
4145                iResult = memcmp(valuePtr->bytes, value2Ptr->bytes,
4146                        (unsigned) ((s1len < s2len) ? s1len : s2len));
4147            } else {
4148                iResult = TclUniCharNcmp(Tcl_GetUnicode(valuePtr),
4149                        Tcl_GetUnicode(value2Ptr),
4150                        (unsigned) ((s1len < s2len) ? s1len : s2len));
4151            }
4152        } else {
4153            /*
4154             * We can't do a simple memcmp in order to handle the special Tcl
4155             * \xC0\x80 null encoding for utf-8.
4156             */
4157
4158            s1 = TclGetStringFromObj(valuePtr, &s1len);
4159            s2 = TclGetStringFromObj(value2Ptr, &s2len);
4160            iResult = TclpUtfNcmp2(s1, s2,
4161                    (size_t) ((s1len < s2len) ? s1len : s2len));
4162        }
4163
4164        /*
4165         * Make sure only -1,0,1 is returned
4166         * TODO: consider peephole opt.
4167         */
4168
4169        if (iResult == 0) {
4170            iResult = s1len - s2len;
4171        }
4172
4173        if (*pc != INST_STR_CMP) {
4174            /*
4175             * Take care of the opcodes that goto'ed into here.
4176             */
4177
4178            switch (*pc) {
4179            case INST_EQ:
4180                iResult = (iResult == 0);
4181                break;
4182            case INST_NEQ:
4183                iResult = (iResult != 0);
4184                break;
4185            case INST_LT:
4186                iResult = (iResult < 0);
4187                break;
4188            case INST_GT:
4189                iResult = (iResult > 0);
4190                break;
4191            case INST_LE:
4192                iResult = (iResult <= 0);
4193                break;
4194            case INST_GE:
4195                iResult = (iResult >= 0);
4196                break;
4197            }
4198        }
4199        if (iResult < 0) {
4200            TclNewIntObj(objResultPtr, -1);
4201            TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), -1));
4202        } else {
4203            objResultPtr = constants[(iResult>0)];
4204            TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr),
4205                (iResult > 0)));
4206        }
4207
4208        NEXT_INST_F(1, 2, 1);
4209    }
4210
4211    case INST_STR_LEN: {
4212        int length;
4213        Tcl_Obj *valuePtr;
4214
4215        valuePtr = OBJ_AT_TOS;
4216
4217        if (valuePtr->typePtr == &tclByteArrayType) {
4218            (void) Tcl_GetByteArrayFromObj(valuePtr, &length);
4219        } else {
4220            length = Tcl_GetCharLength(valuePtr);
4221        }
4222        TclNewIntObj(objResultPtr, length);
4223        TRACE(("%.20s => %d\n", O2S(valuePtr), length));
4224        NEXT_INST_F(1, 1, 1);
4225    }
4226
4227    case INST_STR_INDEX: {
4228        /*
4229         * String compare.
4230         */
4231
4232        int index, length;
4233        char *bytes;
4234        Tcl_Obj *valuePtr, *value2Ptr;
4235
4236        bytes = NULL; /* lint */
4237        value2Ptr = OBJ_AT_TOS;
4238        valuePtr = OBJ_UNDER_TOS;
4239
4240        /*
4241         * If we have a ByteArray object, avoid indexing in the Utf string
4242         * since the byte array contains one byte per character. Otherwise,
4243         * use the Unicode string rep to get the index'th char.
4244         */
4245
4246        if (valuePtr->typePtr == &tclByteArrayType) {
4247            bytes = (char *)Tcl_GetByteArrayFromObj(valuePtr, &length);
4248        } else {
4249            /*
4250             * Get Unicode char length to calulate what 'end' means.
4251             */
4252
4253            length = Tcl_GetCharLength(valuePtr);
4254        }
4255
4256        result = TclGetIntForIndexM(interp, value2Ptr, length - 1, &index);
4257        if (result != TCL_OK) {
4258            goto checkForCatch;
4259        }
4260
4261        if ((index >= 0) && (index < length)) {
4262            if (valuePtr->typePtr == &tclByteArrayType) {
4263                objResultPtr = Tcl_NewByteArrayObj((unsigned char *)
4264                        (&bytes[index]), 1);
4265            } else if (valuePtr->bytes && length == valuePtr->length) {
4266                objResultPtr = Tcl_NewStringObj((const char *)
4267                        (&valuePtr->bytes[index]), 1);
4268            } else {
4269                char buf[TCL_UTF_MAX];
4270                Tcl_UniChar ch;
4271
4272                ch = Tcl_GetUniChar(valuePtr, index);
4273
4274                /*
4275                 * This could be: Tcl_NewUnicodeObj((const Tcl_UniChar *)&ch,
4276                 * 1) but creating the object as a string seems to be faster
4277                 * in practical use.
4278                 */
4279
4280                length = Tcl_UniCharToUtf(ch, buf);
4281                objResultPtr = Tcl_NewStringObj(buf, length);
4282            }
4283        } else {
4284            TclNewObj(objResultPtr);
4285        }
4286
4287        TRACE(("%.20s %.20s => %s\n", O2S(valuePtr), O2S(value2Ptr),
4288                O2S(objResultPtr)));
4289        NEXT_INST_F(1, 2, 1);
4290    }
4291
4292    case INST_STR_MATCH: {
4293        int nocase, match;
4294        Tcl_Obj *valuePtr, *value2Ptr;
4295
4296        nocase = TclGetInt1AtPtr(pc+1);
4297        valuePtr = OBJ_AT_TOS;          /* String */
4298        value2Ptr = OBJ_UNDER_TOS;      /* Pattern */
4299
4300        /*
4301         * Check that at least one of the objects is Unicode before promoting
4302         * both.
4303         */
4304
4305        if ((valuePtr->typePtr == &tclStringType)
4306                || (value2Ptr->typePtr == &tclStringType)) {
4307            Tcl_UniChar *ustring1, *ustring2;
4308            int length1, length2;
4309
4310            ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length1);
4311            ustring2 = Tcl_GetUnicodeFromObj(value2Ptr, &length2);
4312            match = TclUniCharMatch(ustring1, length1, ustring2, length2,
4313                    nocase);
4314        } else if ((valuePtr->typePtr == &tclByteArrayType) && !nocase) {
4315            unsigned char *string1, *string2;
4316            int length1, length2;
4317
4318            string1 = Tcl_GetByteArrayFromObj(valuePtr, &length1);
4319            string2 = Tcl_GetByteArrayFromObj(value2Ptr, &length2);
4320            match = TclByteArrayMatch(string1, length1, string2, length2, 0);
4321        } else {
4322            match = Tcl_StringCaseMatch(TclGetString(valuePtr),
4323                    TclGetString(value2Ptr), nocase);
4324        }
4325
4326        /*
4327         * Reuse value2Ptr object already on stack if possible. Adjustment is
4328         * 2 due to the nocase byte
4329         * TODO: consider peephole opt.
4330         */
4331
4332        TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), match));
4333        objResultPtr = constants[match];
4334        NEXT_INST_F(2, 2, 1);
4335    }
4336
4337    case INST_REGEXP: {
4338        int cflags, match;
4339        Tcl_Obj *valuePtr, *value2Ptr;
4340        Tcl_RegExp regExpr;
4341
4342        cflags = TclGetInt1AtPtr(pc+1); /* RE compile flages like NOCASE */
4343        valuePtr = OBJ_AT_TOS;          /* String */
4344        value2Ptr = OBJ_UNDER_TOS;      /* Pattern */
4345
4346        regExpr = Tcl_GetRegExpFromObj(interp, value2Ptr, cflags);
4347        if (regExpr == NULL) {
4348            match = -1;
4349        } else {
4350            match = Tcl_RegExpExecObj(interp, regExpr, valuePtr, 0, 0, 0);
4351        }
4352
4353        /*
4354         * Adjustment is 2 due to the nocase byte
4355         */
4356
4357        if (match < 0) {
4358            objResultPtr = Tcl_GetObjResult(interp);
4359            TRACE_WITH_OBJ(("%.20s %.20s => ERROR: ",
4360                    O2S(valuePtr), O2S(value2Ptr)), objResultPtr);
4361            result = TCL_ERROR;
4362            goto checkForCatch;
4363        } else {
4364            TRACE(("%.20s %.20s => %d\n",
4365                    O2S(valuePtr), O2S(value2Ptr), match));
4366            objResultPtr = constants[match];
4367            NEXT_INST_F(2, 2, 1);
4368        }
4369    }
4370
4371    case INST_EQ:
4372    case INST_NEQ:
4373    case INST_LT:
4374    case INST_GT:
4375    case INST_LE:
4376    case INST_GE: {
4377        Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
4378        Tcl_Obj *value2Ptr = OBJ_AT_TOS;
4379        ClientData ptr1, ptr2;
4380        int iResult = 0, compare = 0, type1, type2;
4381        double d1, d2, tmp;
4382        long l1, l2;
4383        mp_int big1, big2;
4384#ifndef NO_WIDE_TYPE
4385        Tcl_WideInt w1, w2;
4386#endif
4387
4388        if (GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK) {
4389            /*
4390             * At least one non-numeric argument - compare as strings.
4391             */
4392
4393            goto stringCompare;
4394        }
4395        if (type1 == TCL_NUMBER_NAN) {
4396            /*
4397             * NaN first arg: NaN != to everything, other compares are false.
4398             */
4399
4400            iResult = (*pc == INST_NEQ);
4401            goto foundResult;
4402        }
4403        if (valuePtr == value2Ptr) {
4404            compare = MP_EQ;
4405            goto convertComparison;
4406        }
4407        if (GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK) {
4408            /*
4409             * At least one non-numeric argument - compare as strings.
4410             */
4411
4412            goto stringCompare;
4413        }
4414        if (type2 == TCL_NUMBER_NAN) {
4415            /*
4416             * NaN 2nd arg: NaN != to everything, other compares are false.
4417             */
4418
4419            iResult = (*pc == INST_NEQ);
4420            goto foundResult;
4421        }
4422        switch (type1) {
4423        case TCL_NUMBER_LONG:
4424            l1 = *((const long *)ptr1);
4425            switch (type2) {
4426            case TCL_NUMBER_LONG:
4427                l2 = *((const long *)ptr2);
4428            longCompare:
4429                compare = (l1 < l2) ? MP_LT : ((l1 > l2) ? MP_GT : MP_EQ);
4430                break;
4431#ifndef NO_WIDE_TYPE
4432            case TCL_NUMBER_WIDE:
4433                w2 = *((const Tcl_WideInt *)ptr2);
4434                w1 = (Tcl_WideInt)l1;
4435                goto wideCompare;
4436#endif
4437            case TCL_NUMBER_DOUBLE:
4438                d2 = *((const double *)ptr2);
4439                d1 = (double) l1;
4440
4441                /*
4442                 * If the double has a fractional part, or if the long can be
4443                 * converted to double without loss of precision, then compare
4444                 * as doubles.
4445                 */
4446
4447                if (DBL_MANT_DIG > CHAR_BIT*sizeof(long)
4448                        || l1 == (long) d1
4449                        || modf(d2, &tmp) != 0.0) {
4450                    goto doubleCompare;
4451                }
4452
4453                /*
4454                 * Otherwise, to make comparision based on full precision,
4455                 * need to convert the double to a suitably sized integer.
4456                 *
4457                 * Need this to get comparsions like
4458                 *      expr 20000000000000003 < 20000000000000004.0
4459                 * right. Converting the first argument to double will yield
4460                 * two double values that are equivalent within double
4461                 * precision. Converting the double to an integer gets done
4462                 * exactly, then integer comparison can tell the difference.
4463                 */
4464
4465                if (d2 < (double)LONG_MIN) {
4466                    compare = MP_GT;
4467                    break;
4468                }
4469                if (d2 > (double)LONG_MAX) {
4470                    compare = MP_LT;
4471                    break;
4472                }
4473                l2 = (long) d2;
4474                goto longCompare;
4475            case TCL_NUMBER_BIG:
4476                Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
4477                if (mp_cmp_d(&big2, 0) == MP_LT) {
4478                    compare = MP_GT;
4479                } else {
4480                    compare = MP_LT;
4481                }
4482                mp_clear(&big2);
4483            }
4484            break;
4485
4486#ifndef NO_WIDE_TYPE
4487        case TCL_NUMBER_WIDE:
4488            w1 = *((const Tcl_WideInt *)ptr1);
4489            switch (type2) {
4490            case TCL_NUMBER_WIDE:
4491                w2 = *((const Tcl_WideInt *)ptr2);
4492            wideCompare:
4493                compare = (w1 < w2) ? MP_LT : ((w1 > w2) ? MP_GT : MP_EQ);
4494                break;
4495            case TCL_NUMBER_LONG:
4496                l2 = *((const long *)ptr2);
4497                w2 = (Tcl_WideInt)l2;
4498                goto wideCompare;
4499            case TCL_NUMBER_DOUBLE:
4500                d2 = *((const double *)ptr2);
4501                d1 = (double) w1;
4502                if (DBL_MANT_DIG > CHAR_BIT*sizeof(Tcl_WideInt)
4503                        || w1 == (Tcl_WideInt) d1
4504                        || modf(d2, &tmp) != 0.0) {
4505                    goto doubleCompare;
4506                }
4507                if (d2 < (double)LLONG_MIN) {
4508                    compare = MP_GT;
4509                    break;
4510                }
4511                if (d2 > (double)LLONG_MAX) {
4512                    compare = MP_LT;
4513                    break;
4514                }
4515                w2 = (Tcl_WideInt) d2;
4516                goto wideCompare;
4517            case TCL_NUMBER_BIG:
4518                Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
4519                if (mp_cmp_d(&big2, 0) == MP_LT) {
4520                    compare = MP_GT;
4521                } else {
4522                    compare = MP_LT;
4523                }
4524                mp_clear(&big2);
4525            }
4526            break;
4527#endif
4528
4529        case TCL_NUMBER_DOUBLE:
4530            d1 = *((const double *)ptr1);
4531            switch (type2) {
4532            case TCL_NUMBER_DOUBLE:
4533                d2 = *((const double *)ptr2);
4534            doubleCompare:
4535                compare = (d1 < d2) ? MP_LT : ((d1 > d2) ? MP_GT : MP_EQ);
4536                break;
4537            case TCL_NUMBER_LONG:
4538                l2 = *((const long *)ptr2);
4539                d2 = (double) l2;
4540                if (DBL_MANT_DIG > CHAR_BIT*sizeof(long)
4541                        || l2 == (long) d2
4542                        || modf(d1, &tmp) != 0.0) {
4543                    goto doubleCompare;
4544                }
4545                if (d1 < (double)LONG_MIN) {
4546                    compare = MP_LT;
4547                    break;
4548                }
4549                if (d1 > (double)LONG_MAX) {
4550                    compare = MP_GT;
4551                    break;
4552                }
4553                l1 = (long) d1;
4554                goto longCompare;
4555#ifndef NO_WIDE_TYPE
4556            case TCL_NUMBER_WIDE:
4557                w2 = *((const Tcl_WideInt *)ptr2);
4558                d2 = (double) w2;
4559                if (DBL_MANT_DIG > CHAR_BIT*sizeof(Tcl_WideInt)
4560                        || w2 == (Tcl_WideInt) d2
4561                        || modf(d1, &tmp) != 0.0) {
4562                    goto doubleCompare;
4563                }
4564                if (d1 < (double)LLONG_MIN) {
4565                    compare = MP_LT;
4566                    break;
4567                }
4568                if (d1 > (double)LLONG_MAX) {
4569                    compare = MP_GT;
4570                    break;
4571                }
4572                w1 = (Tcl_WideInt) d1;
4573                goto wideCompare;
4574#endif
4575            case TCL_NUMBER_BIG:
4576                if (TclIsInfinite(d1)) {
4577                    compare = (d1 > 0.0) ? MP_GT : MP_LT;
4578                    break;
4579                }
4580                Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
4581                if ((d1 < (double)LONG_MAX) && (d1 > (double)LONG_MIN)) {
4582                    if (mp_cmp_d(&big2, 0) == MP_LT) {
4583                        compare = MP_GT;
4584                    } else {
4585                        compare = MP_LT;
4586                    }
4587                    mp_clear(&big2);
4588                    break;
4589                }
4590                if (DBL_MANT_DIG > CHAR_BIT*sizeof(long)
4591                        && modf(d1, &tmp) != 0.0) {
4592                    d2 = TclBignumToDouble(&big2);
4593                    mp_clear(&big2);
4594                    goto doubleCompare;
4595                }
4596                Tcl_InitBignumFromDouble(NULL, d1, &big1);
4597                goto bigCompare;
4598            }
4599            break;
4600
4601        case TCL_NUMBER_BIG:
4602            Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
4603            switch (type2) {
4604#ifndef NO_WIDE_TYPE
4605            case TCL_NUMBER_WIDE:
4606#endif
4607            case TCL_NUMBER_LONG:
4608                compare = mp_cmp_d(&big1, 0);
4609                mp_clear(&big1);
4610                break;
4611            case TCL_NUMBER_DOUBLE:
4612                d2 = *((const double *)ptr2);
4613                if (TclIsInfinite(d2)) {
4614                    compare = (d2 > 0.0) ? MP_LT : MP_GT;
4615                    mp_clear(&big1);
4616                    break;
4617                }
4618                if ((d2 < (double)LONG_MAX) && (d2 > (double)LONG_MIN)) {
4619                    compare = mp_cmp_d(&big1, 0);
4620                    mp_clear(&big1);
4621                    break;
4622                }
4623                if (DBL_MANT_DIG > CHAR_BIT*sizeof(long)
4624                        && modf(d2, &tmp) != 0.0) {
4625                    d1 = TclBignumToDouble(&big1);
4626                    mp_clear(&big1);
4627                    goto doubleCompare;
4628                }
4629                Tcl_InitBignumFromDouble(NULL, d2, &big2);
4630                goto bigCompare;
4631            case TCL_NUMBER_BIG:
4632                Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
4633            bigCompare:
4634                compare = mp_cmp(&big1, &big2);
4635                mp_clear(&big1);
4636                mp_clear(&big2);
4637            }
4638        }
4639
4640        /*
4641         * Turn comparison outcome into appropriate result for opcode.
4642         */
4643
4644    convertComparison:
4645        switch (*pc) {
4646        case INST_EQ:
4647            iResult = (compare == MP_EQ);
4648            break;
4649        case INST_NEQ:
4650            iResult = (compare != MP_EQ);
4651            break;
4652        case INST_LT:
4653            iResult = (compare == MP_LT);
4654            break;
4655        case INST_GT:
4656            iResult = (compare == MP_GT);
4657            break;
4658        case INST_LE:
4659            iResult = (compare != MP_GT);
4660            break;
4661        case INST_GE:
4662            iResult = (compare != MP_LT);
4663            break;
4664        }
4665
4666        /*
4667         * Peep-hole optimisation: if you're about to jump, do jump from here.
4668         */
4669
4670    foundResult:
4671        pc++;
4672#ifndef TCL_COMPILE_DEBUG
4673        switch (*pc) {
4674        case INST_JUMP_FALSE1:
4675            NEXT_INST_F((iResult? 2 : TclGetInt1AtPtr(pc+1)), 2, 0);
4676        case INST_JUMP_TRUE1:
4677            NEXT_INST_F((iResult? TclGetInt1AtPtr(pc+1) : 2), 2, 0);
4678        case INST_JUMP_FALSE4:
4679            NEXT_INST_F((iResult? 5 : TclGetInt4AtPtr(pc+1)), 2, 0);
4680        case INST_JUMP_TRUE4:
4681            NEXT_INST_F((iResult? TclGetInt4AtPtr(pc+1) : 5), 2, 0);
4682        }
4683#endif
4684        objResultPtr = constants[iResult];
4685        NEXT_INST_F(0, 2, 1);
4686    }
4687
4688    case INST_MOD:
4689    case INST_LSHIFT:
4690    case INST_RSHIFT: {
4691        Tcl_Obj *value2Ptr = OBJ_AT_TOS;
4692        Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
4693        ClientData ptr1, ptr2;
4694        int invalid, shift, type1, type2;
4695        long l1 = 0;
4696
4697        result = GetNumberFromObj(NULL, valuePtr, &ptr1, &type1);
4698        if ((result != TCL_OK) || (type1 == TCL_NUMBER_DOUBLE)
4699                || (type1 == TCL_NUMBER_NAN)) {
4700            result = TCL_ERROR;
4701            TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr),
4702                    O2S(value2Ptr), (valuePtr->typePtr?
4703                    valuePtr->typePtr->name : "null")));
4704            IllegalExprOperandType(interp, pc, valuePtr);
4705            goto checkForCatch;
4706        }
4707
4708        result = GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2);
4709        if ((result != TCL_OK) || (type2 == TCL_NUMBER_DOUBLE)
4710                || (type2 == TCL_NUMBER_NAN)) {
4711            result = TCL_ERROR;
4712            TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr),
4713                    O2S(value2Ptr), (value2Ptr->typePtr?
4714                    value2Ptr->typePtr->name : "null")));
4715            IllegalExprOperandType(interp, pc, value2Ptr);
4716            goto checkForCatch;
4717        }
4718
4719        if (*pc == INST_MOD) {
4720            /* TODO: Attempts to re-use unshared operands on stack */
4721
4722            long l2 = 0;        /* silence gcc warning */
4723
4724            if (type2 == TCL_NUMBER_LONG) {
4725                l2 = *((const long *)ptr2);
4726                if (l2 == 0) {
4727                    TRACE(("%s %s => DIVIDE BY ZERO\n", O2S(valuePtr),
4728                            O2S(value2Ptr)));
4729                    goto divideByZero;
4730                }
4731                if ((l2 == 1) || (l2 == -1)) {
4732                    /*
4733                     * Div. by |1| always yields remainder of 0.
4734                     */
4735
4736                    objResultPtr = constants[0];
4737                    TRACE(("%s\n", O2S(objResultPtr)));
4738                    NEXT_INST_F(1, 2, 1);
4739                }
4740            }
4741            if (type1 == TCL_NUMBER_LONG) {
4742                l1 = *((const long *)ptr1);
4743                if (l1 == 0) {
4744                    /*
4745                     * 0 % (non-zero) always yields remainder of 0.
4746                     */
4747
4748                    objResultPtr = constants[0];
4749                    TRACE(("%s\n", O2S(objResultPtr)));
4750                    NEXT_INST_F(1, 2, 1);
4751                }
4752                if (type2 == TCL_NUMBER_LONG) {
4753                    /*
4754                     * Both operands are long; do native calculation.
4755                     */
4756
4757                    long lRemainder, lQuotient = l1 / l2;
4758
4759                    /*
4760                     * Force Tcl's integer division rules.
4761                     * TODO: examine for logic simplification
4762                     */
4763
4764                    if ((lQuotient < 0 || (lQuotient == 0 &&
4765                            ((l1 < 0 && l2 > 0) || (l1 > 0 && l2 < 0)))) &&
4766                            (lQuotient * l2 != l1)) {
4767                        lQuotient -= 1;
4768                    }
4769                    lRemainder = l1 - l2*lQuotient;
4770                    TclNewLongObj(objResultPtr, lRemainder);
4771                    TRACE(("%s\n", O2S(objResultPtr)));
4772                    NEXT_INST_F(1, 2, 1);
4773                }
4774
4775                /*
4776                 * First operand fits in long; second does not, so the second
4777                 * has greater magnitude than first. No need to divide to
4778                 * determine the remainder.
4779                 */
4780
4781#ifndef NO_WIDE_TYPE
4782                if (type2 == TCL_NUMBER_WIDE) {
4783                    Tcl_WideInt w2 = *((const Tcl_WideInt *)ptr2);
4784
4785                    if ((l1 > 0) ^ (w2 > (Tcl_WideInt)0)) {
4786                        /*
4787                         * Arguments are opposite sign; remainder is sum.
4788                         */
4789
4790                        objResultPtr = Tcl_NewWideIntObj(w2+(Tcl_WideInt)l1);
4791                        TRACE(("%s\n", O2S(objResultPtr)));
4792                        NEXT_INST_F(1, 2, 1);
4793                    }
4794
4795                    /*
4796                     * Arguments are same sign; remainder is first operand.
4797                     */
4798
4799                    TRACE(("%s\n", O2S(valuePtr)));
4800                    NEXT_INST_F(1, 1, 0);
4801                }
4802#endif
4803                {
4804                    mp_int big2;
4805
4806                    Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
4807
4808                    /* TODO: internals intrusion */
4809                    if ((l1 > 0) ^ (big2.sign == MP_ZPOS)) {
4810                        /*
4811                         * Arguments are opposite sign; remainder is sum.
4812                         */
4813
4814                        mp_int big1;
4815
4816                        TclBNInitBignumFromLong(&big1, l1);
4817                        mp_add(&big2, &big1, &big2);
4818                        mp_clear(&big1);
4819                        objResultPtr = Tcl_NewBignumObj(&big2);
4820                        TRACE(("%s\n", O2S(objResultPtr)));
4821                        NEXT_INST_F(1, 2, 1);
4822                    }
4823
4824                    /*
4825                     * Arguments are same sign; remainder is first operand.
4826                     */
4827
4828                    mp_clear(&big2);
4829                    TRACE(("%s\n", O2S(valuePtr)));
4830                    NEXT_INST_F(1, 1, 0);
4831                }
4832            }
4833#ifndef NO_WIDE_TYPE
4834            if (type1 == TCL_NUMBER_WIDE) {
4835                Tcl_WideInt w1 = *((const Tcl_WideInt *)ptr1);
4836
4837                if (type2 != TCL_NUMBER_BIG) {
4838                    Tcl_WideInt w2, wQuotient, wRemainder;
4839
4840                    Tcl_GetWideIntFromObj(NULL, value2Ptr, &w2);
4841                    wQuotient = w1 / w2;
4842
4843                    /*
4844                     * Force Tcl's integer division rules.
4845                     * TODO: examine for logic simplification
4846                     */
4847
4848                    if (((wQuotient < (Tcl_WideInt) 0)
4849                            || ((wQuotient == (Tcl_WideInt) 0)
4850                            && ((w1 < (Tcl_WideInt)0 && w2 > (Tcl_WideInt)0)
4851                            || (w1 > (Tcl_WideInt)0 && w2 < (Tcl_WideInt)0))))
4852                            && (wQuotient * w2 != w1)) {
4853                        wQuotient -= (Tcl_WideInt) 1;
4854                    }
4855                    wRemainder = w1 - w2*wQuotient;
4856                    objResultPtr = Tcl_NewWideIntObj(wRemainder);
4857                    TRACE(("%s\n", O2S(objResultPtr)));
4858                    NEXT_INST_F(1, 2, 1);
4859                }
4860                {
4861                    mp_int big2;
4862                    Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
4863
4864                    /* TODO: internals intrusion */
4865                    if ((w1 > ((Tcl_WideInt) 0)) ^ (big2.sign == MP_ZPOS)) {
4866                        /*
4867                         * Arguments are opposite sign; remainder is sum.
4868                         */
4869
4870                        mp_int big1;
4871
4872                        TclBNInitBignumFromWideInt(&big1, w1);
4873                        mp_add(&big2, &big1, &big2);
4874                        mp_clear(&big1);
4875                        objResultPtr = Tcl_NewBignumObj(&big2);
4876                        TRACE(("%s\n", O2S(objResultPtr)));
4877                        NEXT_INST_F(1, 2, 1);
4878                    }
4879
4880                    /*
4881                     * Arguments are same sign; remainder is first operand.
4882                     */
4883
4884                    mp_clear(&big2);
4885                    TRACE(("%s\n", O2S(valuePtr)));
4886                    NEXT_INST_F(1, 1, 0);
4887                }
4888            }
4889#endif
4890            {
4891                mp_int big1, big2, bigResult, bigRemainder;
4892
4893                Tcl_GetBignumFromObj(NULL, valuePtr, &big1);
4894                Tcl_GetBignumFromObj(NULL, value2Ptr, &big2);
4895                mp_init(&bigResult);
4896                mp_init(&bigRemainder);
4897                mp_div(&big1, &big2, &bigResult, &bigRemainder);
4898                if (!mp_iszero(&bigRemainder)
4899                        && (bigRemainder.sign != big2.sign)) {
4900                    /*
4901                     * Convert to Tcl's integer division rules.
4902                     */
4903
4904                    mp_sub_d(&bigResult, 1, &bigResult);
4905                    mp_add(&bigRemainder, &big2, &bigRemainder);
4906                }
4907                mp_copy(&bigRemainder, &bigResult);
4908                mp_clear(&bigRemainder);
4909                mp_clear(&big1);
4910                mp_clear(&big2);
4911                TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
4912                if (Tcl_IsShared(valuePtr)) {
4913                    objResultPtr = Tcl_NewBignumObj(&bigResult);
4914                    TRACE(("%s\n", O2S(objResultPtr)));
4915                    NEXT_INST_F(1, 2, 1);
4916                }
4917                Tcl_SetBignumObj(valuePtr, &bigResult);
4918                TRACE(("%s\n", O2S(valuePtr)));
4919                NEXT_INST_F(1, 1, 0);
4920            }
4921        }
4922
4923        /*
4924         * Reject negative shift argument.
4925         */
4926
4927        switch (type2) {
4928        case TCL_NUMBER_LONG:
4929            invalid = (*((const long *)ptr2) < (long)0);
4930            break;
4931#ifndef NO_WIDE_TYPE
4932        case TCL_NUMBER_WIDE:
4933            invalid = (*((const Tcl_WideInt *)ptr2) < (Tcl_WideInt)0);
4934            break;
4935#endif
4936        case TCL_NUMBER_BIG: {
4937            mp_int big2;
4938
4939            Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
4940            invalid = (mp_cmp_d(&big2, 0) == MP_LT);
4941            mp_clear(&big2);
4942            break;
4943        }
4944        default:
4945            /* Unused, here to silence compiler warning */
4946            invalid = 0;
4947        }
4948        if (invalid) {
4949            Tcl_SetObjResult(interp,
4950                    Tcl_NewStringObj("negative shift argument", -1));
4951            result = TCL_ERROR;
4952            goto checkForCatch;
4953        }
4954
4955        /*
4956         * Zero shifted any number of bits is still zero.
4957         */
4958
4959        if ((type1==TCL_NUMBER_LONG) && (*((const long *)ptr1) == (long)0)) {
4960            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
4961            objResultPtr = constants[0];
4962            TRACE(("%s\n", O2S(objResultPtr)));
4963            NEXT_INST_F(1, 2, 1);
4964        }
4965
4966        if (*pc == INST_LSHIFT) {
4967            /*
4968             * Large left shifts create integer overflow.
4969             *
4970             * BEWARE! Can't use Tcl_GetIntFromObj() here because that
4971             * converts values in the (unsigned) range to their signed int
4972             * counterparts, leading to incorrect results.
4973             */
4974
4975            if ((type2 != TCL_NUMBER_LONG)
4976                    || (*((const long *)ptr2) > (long) INT_MAX)) {
4977                /*
4978                 * Technically, we could hold the value (1 << (INT_MAX+1)) in
4979                 * an mp_int, but since we're using mp_mul_2d() to do the
4980                 * work, and it takes only an int argument, that's a good
4981                 * place to draw the line.
4982                 */
4983
4984                Tcl_SetObjResult(interp, Tcl_NewStringObj(
4985                        "integer value too large to represent", -1));
4986                result = TCL_ERROR;
4987                goto checkForCatch;
4988            }
4989            shift = (int)(*((const long *)ptr2));
4990
4991            /*
4992             * Handle shifts within the native long range.
4993             */
4994
4995            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
4996            if ((type1 == TCL_NUMBER_LONG)
4997                    && (size_t) shift < CHAR_BIT*sizeof(long)
4998                    && ((l1 = *(const long *)ptr1) != 0)
4999                    && !((l1>0 ? l1 : ~l1)
5000                            & -(1L<<(CHAR_BIT*sizeof(long) - 1 - shift)))) {
5001                TclNewLongObj(objResultPtr, (l1<<shift));
5002                TRACE(("%s\n", O2S(objResultPtr)));
5003                NEXT_INST_F(1, 2, 1);
5004            }
5005
5006            /*
5007             * Handle shifts within the native wide range.
5008             */
5009
5010            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5011            if ((type1 != TCL_NUMBER_BIG)
5012                    && ((size_t)shift < CHAR_BIT*sizeof(Tcl_WideInt))) {
5013                Tcl_WideInt w;
5014
5015                TclGetWideIntFromObj(NULL, valuePtr, &w);
5016                if (!((w>0 ? w : ~w)
5017                        & -(((Tcl_WideInt)1)
5018                        << (CHAR_BIT*sizeof(Tcl_WideInt) - 1 - shift)))) {
5019                    objResultPtr = Tcl_NewWideIntObj(w<<shift);
5020                    TRACE(("%s\n", O2S(objResultPtr)));
5021                    NEXT_INST_F(1, 2, 1);
5022                }
5023            }
5024        } else {
5025            /*
5026             * Quickly force large right shifts to 0 or -1.
5027             */
5028
5029            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5030            if ((type2 != TCL_NUMBER_LONG)
5031                    || (*(const long *)ptr2 > INT_MAX)) {
5032                /*
5033                 * Again, technically, the value to be shifted could be an
5034                 * mp_int so huge that a right shift by (INT_MAX+1) bits could
5035                 * not take us to the result of 0 or -1, but since we're using
5036                 * mp_div_2d to do the work, and it takes only an int
5037                 * argument, we draw the line there.
5038                 */
5039
5040                int zero;
5041
5042                switch (type1) {
5043                case TCL_NUMBER_LONG:
5044                    zero = (*(const long *)ptr1 > 0L);
5045                    break;
5046#ifndef NO_WIDE_TYPE
5047                case TCL_NUMBER_WIDE:
5048                    zero = (*(const Tcl_WideInt *)ptr1 > (Tcl_WideInt)0);
5049                    break;
5050#endif
5051                case TCL_NUMBER_BIG: {
5052                    mp_int big1;
5053                    Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
5054                    zero = (mp_cmp_d(&big1, 0) == MP_GT);
5055                    mp_clear(&big1);
5056                    break;
5057                }
5058                default:
5059                    /* Unused, here to silence compiler warning. */
5060                    zero = 0;
5061                }
5062                if (zero) {
5063                    objResultPtr = constants[0];
5064                } else {
5065                    TclNewIntObj(objResultPtr, -1);
5066                }
5067                TRACE(("%s\n", O2S(objResultPtr)));
5068                NEXT_INST_F(1, 2, 1);
5069            }
5070            shift = (int)(*(const long *)ptr2);
5071
5072            /*
5073             * Handle shifts within the native long range.
5074             */
5075
5076            if (type1 == TCL_NUMBER_LONG) {
5077                l1 = *((const long *)ptr1);
5078                if ((size_t)shift >= CHAR_BIT*sizeof(long)) {
5079                    if (l1 >= (long)0) {
5080                        objResultPtr = constants[0];
5081                    } else {
5082                        TclNewIntObj(objResultPtr, -1);
5083                    }
5084                } else {
5085                    TclNewLongObj(objResultPtr, (l1 >> shift));
5086                }
5087                TRACE(("%s\n", O2S(objResultPtr)));
5088                NEXT_INST_F(1, 2, 1);
5089            }
5090
5091#ifndef NO_WIDE_TYPE
5092            /*
5093             * Handle shifts within the native wide range.
5094             */
5095
5096            if (type1 == TCL_NUMBER_WIDE) {
5097                Tcl_WideInt w = *(const Tcl_WideInt *)ptr1;
5098
5099                if ((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideInt)) {
5100                    if (w >= (Tcl_WideInt)0) {
5101                        objResultPtr = constants[0];
5102                    } else {
5103                        TclNewIntObj(objResultPtr, -1);
5104                    }
5105                } else {
5106                    objResultPtr = Tcl_NewWideIntObj(w >> shift);
5107                }
5108                TRACE(("%s\n", O2S(objResultPtr)));
5109                NEXT_INST_F(1, 2, 1);
5110            }
5111#endif
5112        }
5113
5114        {
5115            mp_int big, bigResult, bigRemainder;
5116
5117            Tcl_TakeBignumFromObj(NULL, valuePtr, &big);
5118
5119            mp_init(&bigResult);
5120            if (*pc == INST_LSHIFT) {
5121                mp_mul_2d(&big, shift, &bigResult);
5122            } else {
5123                mp_init(&bigRemainder);
5124                mp_div_2d(&big, shift, &bigResult, &bigRemainder);
5125                if (mp_cmp_d(&bigRemainder, 0) == MP_LT) {
5126                    /*
5127                     * Convert to Tcl's integer division rules.
5128                     */
5129
5130                    mp_sub_d(&bigResult, 1, &bigResult);
5131                }
5132                mp_clear(&bigRemainder);
5133            }
5134            mp_clear(&big);
5135
5136            if (!Tcl_IsShared(valuePtr)) {
5137                Tcl_SetBignumObj(valuePtr, &bigResult);
5138                TRACE(("%s\n", O2S(valuePtr)));
5139                NEXT_INST_F(1, 1, 0);
5140            }
5141            objResultPtr = Tcl_NewBignumObj(&bigResult);
5142        }
5143        TRACE(("%s\n", O2S(objResultPtr)));
5144        NEXT_INST_F(1, 2, 1);
5145    }
5146
5147    case INST_BITOR:
5148    case INST_BITXOR:
5149    case INST_BITAND: {
5150        ClientData ptr1, ptr2;
5151        int type1, type2;
5152        Tcl_Obj *value2Ptr = OBJ_AT_TOS;
5153        Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
5154
5155        result = GetNumberFromObj(NULL, valuePtr, &ptr1, &type1);
5156        if ((result != TCL_OK)
5157                || (type1 == TCL_NUMBER_NAN)
5158                || (type1 == TCL_NUMBER_DOUBLE)) {
5159            result = TCL_ERROR;
5160            TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr),
5161                    O2S(value2Ptr), (valuePtr->typePtr?
5162                    valuePtr->typePtr->name : "null")));
5163            IllegalExprOperandType(interp, pc, valuePtr);
5164            goto checkForCatch;
5165        }
5166        result = GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2);
5167        if ((result != TCL_OK) || (type2 == TCL_NUMBER_NAN)
5168                || (type2 == TCL_NUMBER_DOUBLE)) {
5169            result = TCL_ERROR;
5170            TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr),
5171                    O2S(value2Ptr), (value2Ptr->typePtr?
5172                    value2Ptr->typePtr->name : "null")));
5173            IllegalExprOperandType(interp, pc, value2Ptr);
5174            goto checkForCatch;
5175        }
5176
5177        if ((type1 == TCL_NUMBER_BIG) || (type2 == TCL_NUMBER_BIG)) {
5178            mp_int big1, big2, bigResult, *First, *Second;
5179            int numPos;
5180
5181            Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
5182            Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
5183
5184            /*
5185             * Count how many positive arguments we have. If only one of the
5186             * arguments is negative, store it in 'Second'.
5187             */
5188
5189            if (mp_cmp_d(&big1, 0) != MP_LT) {
5190                numPos = 1 + (mp_cmp_d(&big2, 0) != MP_LT);
5191                First = &big1;
5192                Second = &big2;
5193            } else {
5194                First = &big2;
5195                Second = &big1;
5196                numPos = (mp_cmp_d(First, 0) != MP_LT);
5197            }
5198            mp_init(&bigResult);
5199
5200            switch (*pc) {
5201            case INST_BITAND:
5202                switch (numPos) {
5203                case 2:
5204                    /*
5205                     * Both arguments positive, base case.
5206                     */
5207
5208                    mp_and(First, Second, &bigResult);
5209                    break;
5210                case 1:
5211                    /*
5212                     * First is positive; second negative:
5213                     * P & N = P & ~~N = P&~(-N-1) = P & (P ^ (-N-1))
5214                     */
5215
5216                    mp_neg(Second, Second);
5217                    mp_sub_d(Second, 1, Second);
5218                    mp_xor(First, Second, &bigResult);
5219                    mp_and(First, &bigResult, &bigResult);
5220                    break;
5221                case 0:
5222                    /*
5223                     * Both arguments negative:
5224                     * a & b = ~ (~a | ~b) = -(-a-1|-b-1)-1
5225                     */
5226
5227                    mp_neg(First, First);
5228                    mp_sub_d(First, 1, First);
5229                    mp_neg(Second, Second);
5230                    mp_sub_d(Second, 1, Second);
5231                    mp_or(First, Second, &bigResult);
5232                    mp_neg(&bigResult, &bigResult);
5233                    mp_sub_d(&bigResult, 1, &bigResult);
5234                    break;
5235                }
5236                break;
5237
5238            case INST_BITOR:
5239                switch (numPos) {
5240                case 2:
5241                    /*
5242                     * Both arguments positive, base case.
5243                     */
5244
5245                    mp_or(First, Second, &bigResult);
5246                    break;
5247                case 1:
5248                    /*
5249                     * First is positive; second negative:
5250                     * N|P = ~(~N&~P) = ~((-N-1)&~P) = -((-N-1)&((-N-1)^P))-1
5251                     */
5252
5253                    mp_neg(Second, Second);
5254                    mp_sub_d(Second, 1, Second);
5255                    mp_xor(First, Second, &bigResult);
5256                    mp_and(Second, &bigResult, &bigResult);
5257                    mp_neg(&bigResult, &bigResult);
5258                    mp_sub_d(&bigResult, 1, &bigResult);
5259                    break;
5260                case 0:
5261                    /*
5262                     * Both arguments negative:
5263                     * a | b = ~ (~a & ~b) = -(-a-1&-b-1)-1
5264                     */
5265
5266                    mp_neg(First, First);
5267                    mp_sub_d(First, 1, First);
5268                    mp_neg(Second, Second);
5269                    mp_sub_d(Second, 1, Second);
5270                    mp_and(First, Second, &bigResult);
5271                    mp_neg(&bigResult, &bigResult);
5272                    mp_sub_d(&bigResult, 1, &bigResult);
5273                    break;
5274                }
5275                break;
5276
5277            case INST_BITXOR:
5278                switch (numPos) {
5279                case 2:
5280                    /*
5281                     * Both arguments positive, base case.
5282                     */
5283
5284                    mp_xor(First, Second, &bigResult);
5285                    break;
5286                case 1:
5287                    /*
5288                     * First is positive; second negative:
5289                     * P^N = ~(P^~N) = -(P^(-N-1))-1
5290                     */
5291
5292                    mp_neg(Second, Second);
5293                    mp_sub_d(Second, 1, Second);
5294                    mp_xor(First, Second, &bigResult);
5295                    mp_neg(&bigResult, &bigResult);
5296                    mp_sub_d(&bigResult, 1, &bigResult);
5297                    break;
5298                case 0:
5299                    /*
5300                     * Both arguments negative:
5301                     * a ^ b = (~a ^ ~b) = (-a-1^-b-1)
5302                     */
5303
5304                    mp_neg(First, First);
5305                    mp_sub_d(First, 1, First);
5306                    mp_neg(Second, Second);
5307                    mp_sub_d(Second, 1, Second);
5308                    mp_xor(First, Second, &bigResult);
5309                    break;
5310                }
5311                break;
5312            }
5313
5314            mp_clear(&big1);
5315            mp_clear(&big2);
5316            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5317            if (Tcl_IsShared(valuePtr)) {
5318                objResultPtr = Tcl_NewBignumObj(&bigResult);
5319                TRACE(("%s\n", O2S(objResultPtr)));
5320                NEXT_INST_F(1, 2, 1);
5321            }
5322            Tcl_SetBignumObj(valuePtr, &bigResult);
5323            TRACE(("%s\n", O2S(valuePtr)));
5324            NEXT_INST_F(1, 1, 0);
5325        }
5326
5327#ifndef NO_WIDE_TYPE
5328        if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE)) {
5329            Tcl_WideInt wResult, w1, w2;
5330
5331            TclGetWideIntFromObj(NULL, valuePtr, &w1);
5332            TclGetWideIntFromObj(NULL, value2Ptr, &w2);
5333
5334            switch (*pc) {
5335            case INST_BITAND:
5336                wResult = w1 & w2;
5337                break;
5338            case INST_BITOR:
5339                wResult = w1 | w2;
5340                break;
5341            case INST_BITXOR:
5342                wResult = w1 ^ w2;
5343                break;
5344            default:
5345                /* Unused, here to silence compiler warning. */
5346                wResult = 0;
5347            }
5348
5349            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5350            if (Tcl_IsShared(valuePtr)) {
5351                objResultPtr = Tcl_NewWideIntObj(wResult);
5352                TRACE(("%s\n", O2S(objResultPtr)));
5353                NEXT_INST_F(1, 2, 1);
5354            }
5355            Tcl_SetWideIntObj(valuePtr, wResult);
5356            TRACE(("%s\n", O2S(valuePtr)));
5357            NEXT_INST_F(1, 1, 0);
5358        }
5359#endif
5360        {
5361            long lResult, l1 = *((const long *)ptr1);
5362            long l2 = *((const long *)ptr2);
5363
5364            switch (*pc) {
5365            case INST_BITAND:
5366                lResult = l1 & l2;
5367                break;
5368            case INST_BITOR:
5369                lResult = l1 | l2;
5370                break;
5371            case INST_BITXOR:
5372                lResult = l1 ^ l2;
5373                break;
5374            default:
5375                /* Unused, here to silence compiler warning. */
5376                lResult = 0;
5377            }
5378
5379            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5380            if (Tcl_IsShared(valuePtr)) {
5381                TclNewLongObj(objResultPtr, lResult);
5382                TRACE(("%s\n", O2S(objResultPtr)));
5383                NEXT_INST_F(1, 2, 1);
5384            }
5385            TclSetLongObj(valuePtr, lResult);
5386            TRACE(("%s\n", O2S(valuePtr)));
5387            NEXT_INST_F(1, 1, 0);
5388        }
5389    }
5390
5391    case INST_EXPON:
5392    case INST_ADD:
5393    case INST_SUB:
5394    case INST_DIV:
5395    case INST_MULT: {
5396        ClientData ptr1, ptr2;
5397        int type1, type2;
5398        Tcl_Obj *value2Ptr = OBJ_AT_TOS;
5399        Tcl_Obj *valuePtr = OBJ_UNDER_TOS;
5400
5401        result = GetNumberFromObj(NULL, valuePtr, &ptr1, &type1);
5402        if ((result != TCL_OK)
5403#ifndef ACCEPT_NAN
5404                || (type1 == TCL_NUMBER_NAN)
5405#endif
5406                ) {
5407            result = TCL_ERROR;
5408            TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n",
5409                    O2S(value2Ptr), O2S(valuePtr),
5410                    (valuePtr->typePtr? valuePtr->typePtr->name: "null")));
5411            IllegalExprOperandType(interp, pc, valuePtr);
5412            goto checkForCatch;
5413        }
5414
5415#ifdef ACCEPT_NAN
5416        if (type1 == TCL_NUMBER_NAN) {
5417            /*
5418             * NaN first argument -> result is also NaN.
5419             */
5420
5421            NEXT_INST_F(1, 1, 0);
5422        }
5423#endif
5424
5425        result = GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2);
5426        if ((result != TCL_OK)
5427#ifndef ACCEPT_NAN
5428                || (type2 == TCL_NUMBER_NAN)
5429#endif
5430                ) {
5431            result = TCL_ERROR;
5432            TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n",
5433                    O2S(value2Ptr), O2S(valuePtr),
5434                    (value2Ptr->typePtr? value2Ptr->typePtr->name: "null")));
5435            IllegalExprOperandType(interp, pc, value2Ptr);
5436            goto checkForCatch;
5437        }
5438
5439#ifdef ACCEPT_NAN
5440        if (type2 == TCL_NUMBER_NAN) {
5441            /*
5442             * NaN second argument -> result is also NaN.
5443             */
5444
5445            objResultPtr = value2Ptr;
5446            NEXT_INST_F(1, 2, 1);
5447        }
5448#endif
5449
5450        if ((type1 == TCL_NUMBER_DOUBLE) || (type2 == TCL_NUMBER_DOUBLE)) {
5451            /*
5452             * At least one of the values is floating-point, so perform
5453             * floating point calculations.
5454             */
5455
5456            double d1, d2, dResult;
5457
5458            Tcl_GetDoubleFromObj(NULL, valuePtr, &d1);
5459            Tcl_GetDoubleFromObj(NULL, value2Ptr, &d2);
5460
5461            switch (*pc) {
5462            case INST_ADD:
5463                dResult = d1 + d2;
5464                break;
5465            case INST_SUB:
5466                dResult = d1 - d2;
5467                break;
5468            case INST_MULT:
5469                dResult = d1 * d2;
5470                break;
5471            case INST_DIV:
5472#ifndef IEEE_FLOATING_POINT
5473                if (d2 == 0.0) {
5474                    TRACE(("%.6g %.6g => DIVIDE BY ZERO\n", d1, d2));
5475                    goto divideByZero;
5476                }
5477#endif
5478                /*
5479                 * We presume that we are running with zero-divide unmasked if
5480                 * we're on an IEEE box. Otherwise, this statement might cause
5481                 * demons to fly out our noses.
5482                 */
5483
5484                dResult = d1 / d2;
5485                break;
5486            case INST_EXPON:
5487                if (d1==0.0 && d2<0.0) {
5488                    TRACE(("%.6g %.6g => EXPONENT OF ZERO\n", d1, d2));
5489                    goto exponOfZero;
5490                }
5491                dResult = pow(d1, d2);
5492                break;
5493            default:
5494                /* Unused, here to silence compiler warning. */
5495                dResult = 0;
5496            }
5497
5498#ifndef ACCEPT_NAN
5499            /*
5500             * Check now for IEEE floating-point error.
5501             */
5502
5503            if (TclIsNaN(dResult)) {
5504                TRACE(("%.20s %.20s => IEEE FLOATING PT ERROR\n",
5505                        O2S(valuePtr), O2S(value2Ptr)));
5506                TclExprFloatError(interp, dResult);
5507                result = TCL_ERROR;
5508                goto checkForCatch;
5509            }
5510#endif
5511            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5512            if (Tcl_IsShared(valuePtr)) {
5513                TclNewDoubleObj(objResultPtr, dResult);
5514                TRACE(("%s\n", O2S(objResultPtr)));
5515                NEXT_INST_F(1, 2, 1);
5516            }
5517            TclSetDoubleObj(valuePtr, dResult);
5518            TRACE(("%s\n", O2S(valuePtr)));
5519            NEXT_INST_F(1, 1, 0);
5520        }
5521
5522        if ((sizeof(long) >= 2*sizeof(int)) && (*pc == INST_MULT)
5523                && (type1 == TCL_NUMBER_LONG) && (type2 == TCL_NUMBER_LONG)) {
5524            long l1 = *((const long *)ptr1);
5525            long l2 = *((const long *)ptr2);
5526
5527            if ((l1 <= INT_MAX) && (l1 >= INT_MIN)
5528                    && (l2 <= INT_MAX) && (l2 >= INT_MIN)) {
5529                long lResult = l1 * l2;
5530
5531                TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5532                if (Tcl_IsShared(valuePtr)) {
5533                    TclNewLongObj(objResultPtr,lResult);
5534                    TRACE(("%s\n", O2S(objResultPtr)));
5535                    NEXT_INST_F(1, 2, 1);
5536                }
5537                TclSetLongObj(valuePtr, lResult);
5538                TRACE(("%s\n", O2S(valuePtr)));
5539                NEXT_INST_F(1, 1, 0);
5540            }
5541        }
5542
5543        if ((sizeof(Tcl_WideInt) >= 2*sizeof(long)) && (*pc == INST_MULT)
5544                && (type1 == TCL_NUMBER_LONG) && (type2 == TCL_NUMBER_LONG)) {
5545            Tcl_WideInt w1, w2, wResult;
5546            TclGetWideIntFromObj(NULL, valuePtr, &w1);
5547            TclGetWideIntFromObj(NULL, value2Ptr, &w2);
5548
5549            wResult = w1 * w2;
5550
5551            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5552            if (Tcl_IsShared(valuePtr)) {
5553                objResultPtr = Tcl_NewWideIntObj(wResult);
5554                TRACE(("%s\n", O2S(objResultPtr)));
5555                NEXT_INST_F(1, 2, 1);
5556            }
5557            Tcl_SetWideIntObj(valuePtr, wResult);
5558            TRACE(("%s\n", O2S(valuePtr)));
5559            NEXT_INST_F(1, 1, 0);
5560        }
5561
5562        /* TODO: Attempts to re-use unshared operands on stack. */
5563        if (*pc == INST_EXPON) {
5564            long l1 = 0, l2 = 0;
5565            Tcl_WideInt w1;
5566            int oddExponent = 0, negativeExponent = 0;
5567
5568            if (type2 == TCL_NUMBER_LONG) {
5569                l2 = *((const long *) ptr2);
5570                if (l2 == 0) {
5571                    /*
5572                     * Anything to the zero power is 1.
5573                     */
5574
5575                    objResultPtr = constants[1];
5576                    NEXT_INST_F(1, 2, 1);
5577                } else if (l2 == 1) {
5578                    /*
5579                     * Anything to the first power is itself
5580                     */
5581                    NEXT_INST_F(1, 1, 0);
5582                }
5583            }
5584
5585            switch (type2) {
5586            case TCL_NUMBER_LONG: {
5587                negativeExponent = (l2 < 0);
5588                oddExponent = (int) (l2 & 1);
5589                break;
5590            }
5591#ifndef NO_WIDE_TYPE
5592            case TCL_NUMBER_WIDE: {
5593                Tcl_WideInt w2 = *((const Tcl_WideInt *)ptr2);
5594
5595                negativeExponent = (w2 < 0);
5596                oddExponent = (int) (w2 & (Tcl_WideInt)1);
5597                break;
5598            }
5599#endif
5600            case TCL_NUMBER_BIG: {
5601                mp_int big2;
5602
5603                Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
5604                negativeExponent = (mp_cmp_d(&big2, 0) == MP_LT);
5605                mp_mod_2d(&big2, 1, &big2);
5606                oddExponent = !mp_iszero(&big2);
5607                mp_clear(&big2);
5608                break;
5609            }
5610            }
5611
5612            if (negativeExponent) {
5613                if (type1 == TCL_NUMBER_LONG) {
5614                    l1 = *((const long *)ptr1);
5615                    switch (l1) {
5616                    case 0:
5617                        /*
5618                         * Zero to a negative power is div by zero error.
5619                         */
5620
5621                        TRACE(("%s %s => EXPONENT OF ZERO\n", O2S(valuePtr),
5622                                O2S(value2Ptr)));
5623                        goto exponOfZero;
5624                    case -1:
5625                        if (oddExponent) {
5626                            TclNewIntObj(objResultPtr, -1);
5627                        } else {
5628                            objResultPtr = constants[1];
5629                        }
5630                        NEXT_INST_F(1, 2, 1);
5631                    case 1:
5632                        /*
5633                         * 1 to any power is 1.
5634                         */
5635
5636                        objResultPtr = constants[1];
5637                        NEXT_INST_F(1, 2, 1);
5638                    }
5639                }
5640
5641                /*
5642                 * Integers with magnitude greater than 1 raise to a negative
5643                 * power yield the answer zero (see TIP 123).
5644                 */
5645
5646                objResultPtr = constants[0];
5647                NEXT_INST_F(1, 2, 1);
5648            }
5649
5650            if (type1 == TCL_NUMBER_LONG) {
5651                l1 = *((const long *)ptr1);
5652                switch (l1) {
5653                case 0:
5654                    /*
5655                     * Zero to a positive power is zero.
5656                     */
5657
5658                    objResultPtr = constants[0];
5659                    NEXT_INST_F(1, 2, 1);
5660                case 1:
5661                    /*
5662                     * 1 to any power is 1.
5663                     */
5664
5665                    objResultPtr = constants[1];
5666                    NEXT_INST_F(1, 2, 1);
5667                case -1:
5668                    if (oddExponent) {
5669                        TclNewIntObj(objResultPtr, -1);
5670                    } else {
5671                        objResultPtr = constants[1];
5672                    }
5673                    NEXT_INST_F(1, 2, 1);
5674                }
5675            }
5676            if (type2 == TCL_NUMBER_BIG) {
5677                Tcl_SetObjResult(interp,
5678                        Tcl_NewStringObj("exponent too large", -1));
5679                result = TCL_ERROR;
5680                goto checkForCatch;
5681            }
5682
5683            if (type1 == TCL_NUMBER_LONG && type2 == TCL_NUMBER_LONG) {
5684                if (l1 == 2) {
5685                    /*
5686                     * Reduce small powers of 2 to shifts.
5687                     */
5688
5689                    if ((unsigned long) l2 < CHAR_BIT * sizeof(long) - 1) {
5690                        TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5691                        TclNewLongObj(objResultPtr, (1L << l2));
5692                        TRACE(("%s\n", O2S(objResultPtr)));
5693                        NEXT_INST_F(1, 2, 1);
5694                    }
5695#if !defined(TCL_WIDE_INT_IS_LONG)
5696                    if ((unsigned long)l2 < CHAR_BIT*sizeof(Tcl_WideInt) - 1){
5697                        TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5698                        objResultPtr =
5699                                Tcl_NewWideIntObj(((Tcl_WideInt) 1) << l2);
5700                        TRACE(("%s\n", O2S(objResultPtr)));
5701                        NEXT_INST_F(1, 2, 1);
5702                    }
5703#endif
5704                }
5705                if (l1 == -2) {
5706                    int signum = oddExponent ? -1 : 1;
5707
5708                    /*
5709                     * Reduce small powers of 2 to shifts.
5710                     */
5711
5712                    if ((unsigned long) l2 < CHAR_BIT * sizeof(long) - 1) {
5713                        TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5714                        TclNewLongObj(objResultPtr, signum * (1L << l2));
5715                        TRACE(("%s\n", O2S(objResultPtr)));
5716                        NEXT_INST_F(1, 2, 1);
5717                    }
5718#if !defined(TCL_WIDE_INT_IS_LONG)
5719                    if ((unsigned long)l2 < CHAR_BIT*sizeof(Tcl_WideInt) - 1){
5720                        TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5721                        objResultPtr = Tcl_NewWideIntObj(
5722                                signum * (((Tcl_WideInt) 1) << l2));
5723                        TRACE(("%s\n", O2S(objResultPtr)));
5724                        NEXT_INST_F(1, 2, 1);
5725                    }
5726#endif
5727                }
5728#if (LONG_MAX == 0x7fffffff)
5729                if (l2 <= 8 &&
5730                        l1 <= MaxBase32[l2-2] && l1 >= -MaxBase32[l2-2]) {
5731                    /*
5732                     * Small powers of 32-bit integers.
5733                     */
5734
5735                    long lResult = l1 * l1;     /* b**2 */
5736                    switch (l2) {
5737                    case 2:
5738                        break;
5739                    case 3:
5740                        lResult *= l1;          /* b**3 */
5741                        break;
5742                    case 4:
5743                        lResult *= lResult;     /* b**4 */
5744                        break;
5745                    case 5:
5746                        lResult *= lResult;     /* b**4 */
5747                        lResult *= l1;          /* b**5 */
5748                        break;
5749                    case 6:
5750                        lResult *= l1;          /* b**3 */
5751                        lResult *= lResult;     /* b**6 */
5752                        break;
5753                    case 7:
5754                        lResult *= l1;          /* b**3 */
5755                        lResult *= lResult;     /* b**6 */
5756                        lResult *= l1;          /* b**7 */
5757                        break;
5758                    case 8:
5759                        lResult *= lResult;     /* b**4 */
5760                        lResult *= lResult;     /* b**8 */
5761                        break;
5762                    }
5763                    TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5764                    if (Tcl_IsShared(valuePtr)) {
5765                        TclNewLongObj(objResultPtr, lResult);
5766                        TRACE(("%s\n", O2S(objResultPtr)));
5767                        NEXT_INST_F(1, 2, 1);
5768                    }
5769                    Tcl_SetLongObj(valuePtr, lResult);
5770                    TRACE(("%s\n", O2S(valuePtr)));
5771                    NEXT_INST_F(1, 1, 0);
5772                }
5773                if (l1 >= 3 &&
5774                        ((unsigned long) l1 < (sizeof(Exp32Index)
5775                                / sizeof(unsigned short)) - 1)) {
5776                    unsigned short base = Exp32Index[l1-3]
5777                            + (unsigned short) l2 - 9;
5778                    if (base < Exp32Index[l1-2]) {
5779                        /*
5780                         * 32-bit number raised to intermediate power, done by
5781                         * table lookup.
5782                         */
5783
5784                        TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5785                        if (Tcl_IsShared(valuePtr)) {
5786                            TclNewLongObj(objResultPtr, Exp32Value[base]);
5787                            TRACE(("%s\n", O2S(objResultPtr)));
5788                            NEXT_INST_F(1, 2, 1);
5789                        }
5790                        Tcl_SetLongObj(valuePtr, Exp32Value[base]);
5791                        TRACE(("%s\n", O2S(valuePtr)));
5792                        NEXT_INST_F(1, 1, 0);
5793                    }
5794                }
5795                if (-l1 >= 3
5796                    && (unsigned long)(-l1) < (sizeof(Exp32Index)
5797                             / sizeof(unsigned short)) - 1) {
5798                    unsigned short base
5799                        = Exp32Index[-l1-3] + (unsigned short) l2 - 9;
5800                    if (base < Exp32Index[-l1-2]) {
5801                        long lResult = (oddExponent) ?
5802                            -Exp32Value[base] : Exp32Value[base];
5803
5804                        /*
5805                         * 32-bit number raised to intermediate power, done by
5806                         * table lookup.
5807                         */
5808
5809                        TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5810                        if (Tcl_IsShared(valuePtr)) {
5811                            TclNewLongObj(objResultPtr, lResult);
5812                            TRACE(("%s\n", O2S(objResultPtr)));
5813                            NEXT_INST_F(1, 2, 1);
5814                        }
5815                        Tcl_SetLongObj(valuePtr, lResult);
5816                        TRACE(("%s\n", O2S(valuePtr)));
5817                        NEXT_INST_F(1, 1, 0);
5818                    }
5819                }
5820#endif
5821            }
5822            if (type1 == TCL_NUMBER_LONG) {
5823                w1 = l1;
5824#ifndef NO_WIDE_TYPE
5825            } else if (type1 == TCL_NUMBER_WIDE) {
5826                w1 = *((const Tcl_WideInt*) ptr1);
5827#endif
5828            } else {
5829                w1 = 0;
5830            }
5831#if (LONG_MAX > 0x7fffffff) || !defined(TCL_WIDE_INT_IS_LONG)
5832            if (w1 != 0 && type2 == TCL_NUMBER_LONG && l2 <= 16
5833                    && w1 <= MaxBaseWide[l2-2] && w1 >= -MaxBaseWide[l2-2]) {
5834                /*
5835                 * Small powers of integers whose result is wide.
5836                 */
5837
5838                Tcl_WideInt wResult = w1 * w1; /* b**2 */
5839
5840                switch (l2) {
5841                case 2:
5842                    break;
5843                case 3:
5844                    wResult *= l1;      /* b**3 */
5845                    break;
5846                case 4:
5847                    wResult *= wResult; /* b**4 */
5848                    break;
5849                case 5:
5850                    wResult *= wResult; /* b**4 */
5851                    wResult *= w1;      /* b**5 */
5852                    break;
5853                case 6:
5854                    wResult *= w1;      /* b**3 */
5855                    wResult *= wResult; /* b**6 */
5856                    break;
5857                case 7:
5858                    wResult *= w1;      /* b**3 */
5859                    wResult *= wResult; /* b**6 */
5860                    wResult *= w1;      /* b**7 */
5861                    break;
5862                case 8:
5863                    wResult *= wResult; /* b**4 */
5864                    wResult *= wResult; /* b**8 */
5865                    break;
5866                case 9:
5867                    wResult *= wResult; /* b**4 */
5868                    wResult *= wResult; /* b**8 */
5869                    wResult *= w1;      /* b**9 */
5870                    break;
5871                case 10:
5872                    wResult *= wResult; /* b**4 */
5873                    wResult *= w1;      /* b**5 */
5874                    wResult *= wResult; /* b**10 */
5875                    break;
5876                case 11:
5877                    wResult *= wResult; /* b**4 */
5878                    wResult *= w1;      /* b**5 */
5879                    wResult *= wResult; /* b**10 */
5880                    wResult *= w1;      /* b**11 */
5881                    break;
5882                case 12:
5883                    wResult *= w1;      /* b**3 */
5884                    wResult *= wResult; /* b**6 */
5885                    wResult *= wResult; /* b**12 */
5886                    break;
5887                case 13:
5888                    wResult *= w1;      /* b**3 */
5889                    wResult *= wResult; /* b**6 */
5890                    wResult *= wResult; /* b**12 */
5891                    wResult *= w1;      /* b**13 */
5892                    break;
5893                case 14:
5894                    wResult *= w1;      /* b**3 */
5895                    wResult *= wResult; /* b**6 */
5896                    wResult *= w1;      /* b**7 */
5897                    wResult *= wResult; /* b**14 */
5898                    break;
5899                case 15:
5900                    wResult *= w1;      /* b**3 */
5901                    wResult *= wResult; /* b**6 */
5902                    wResult *= w1;      /* b**7 */
5903                    wResult *= wResult; /* b**14 */
5904                    wResult *= w1;      /* b**15 */
5905                    break;
5906                case 16:
5907                    wResult *= wResult; /* b**4 */
5908                    wResult *= wResult; /* b**8 */
5909                    wResult *= wResult; /* b**16 */
5910                    break;
5911
5912                }
5913                TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5914                objResultPtr = Tcl_NewWideIntObj(wResult);
5915                TRACE(("%s\n", O2S(objResultPtr)));
5916                NEXT_INST_F(1, 2, 1);
5917            }
5918
5919            /*
5920             * Handle cases of powers > 16 that still fit in a 64-bit word by
5921             * doing table lookup.
5922             */
5923
5924            if (w1 >= 3 &&
5925                    (Tcl_WideUInt) w1 < (sizeof(Exp64Index)
5926                            / sizeof(unsigned short)) - 1) {
5927                unsigned short base =
5928                        Exp64Index[w1-3] + (unsigned short) l2 - 17;
5929
5930                if (base < Exp64Index[w1-2]) {
5931                    /*
5932                     * 64-bit number raised to intermediate power, done by
5933                     * table lookup.
5934                     */
5935
5936                    TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5937                    if (Tcl_IsShared(valuePtr)) {
5938                        objResultPtr = Tcl_NewWideIntObj(Exp64Value[base]);
5939                        TRACE(("%s\n", O2S(objResultPtr)));
5940                        NEXT_INST_F(1, 2, 1);
5941                    }
5942                    Tcl_SetWideIntObj(valuePtr, Exp64Value[base]);
5943                    TRACE(("%s\n", O2S(valuePtr)));
5944                    NEXT_INST_F(1, 1, 0);
5945                }
5946            }
5947            if (-w1 >= 3 &&
5948                    (Tcl_WideUInt) (-w1) < (sizeof(Exp64Index)
5949                            / sizeof(unsigned short)) - 1) {
5950                unsigned short base =
5951                        Exp64Index[-w1-3] + (unsigned short) l2 - 17;
5952
5953                if (base < Exp64Index[-w1-2]) {
5954                    Tcl_WideInt wResult = (oddExponent) ?
5955                            -Exp64Value[base] : Exp64Value[base];
5956                    /*
5957                     * 64-bit number raised to intermediate power, done by
5958                     * table lookup.
5959                     */
5960
5961                    TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
5962                    if (Tcl_IsShared(valuePtr)) {
5963                        objResultPtr = Tcl_NewWideIntObj(wResult);
5964                        TRACE(("%s\n", O2S(objResultPtr)));
5965                        NEXT_INST_F(1, 2, 1);
5966                    }
5967                    Tcl_SetWideIntObj(valuePtr, wResult);
5968                    TRACE(("%s\n", O2S(valuePtr)));
5969                    NEXT_INST_F(1, 1, 0);
5970                }
5971            }
5972#endif
5973
5974            goto overflow;
5975        }
5976
5977        if ((*pc != INST_MULT)
5978                && (type1 != TCL_NUMBER_BIG) && (type2 != TCL_NUMBER_BIG)) {
5979            Tcl_WideInt w1, w2, wResult;
5980
5981            TclGetWideIntFromObj(NULL, valuePtr, &w1);
5982            TclGetWideIntFromObj(NULL, value2Ptr, &w2);
5983
5984            switch (*pc) {
5985            case INST_ADD:
5986                wResult = w1 + w2;
5987#ifndef NO_WIDE_TYPE
5988                if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE))
5989#endif
5990                {
5991                    /*
5992                     * Check for overflow.
5993                     */
5994
5995                    if (Overflowing(w1, w2, wResult)) {
5996                        goto overflow;
5997                    }
5998                }
5999                break;
6000
6001            case INST_SUB:
6002                wResult = w1 - w2;
6003#ifndef NO_WIDE_TYPE
6004                if ((type1 == TCL_NUMBER_WIDE) || (type2 == TCL_NUMBER_WIDE))
6005#endif
6006                {
6007                    /*
6008                     * Must check for overflow. The macro tests for overflows
6009                     * in sums by looking at the sign bits. As we have a
6010                     * subtraction here, we are adding -w2. As -w2 could in
6011                     * turn overflow, we test with ~w2 instead: it has the
6012                     * opposite sign bit to w2 so it does the job. Note that
6013                     * the only "bad" case (w2==0) is irrelevant for this
6014                     * macro, as in that case w1 and wResult have the same
6015                     * sign and there is no overflow anyway.
6016                     */
6017
6018                    if (Overflowing(w1, ~w2, wResult)) {
6019                        goto overflow;
6020                    }
6021                }
6022                break;
6023
6024            case INST_DIV:
6025                if (w2 == 0) {
6026                    TRACE(("%s %s => DIVIDE BY ZERO\n",
6027                            O2S(valuePtr), O2S(value2Ptr)));
6028                    goto divideByZero;
6029                }
6030
6031                /*
6032                 * Need a bignum to represent (LLONG_MIN / -1)
6033                 */
6034
6035                if ((w1 == LLONG_MIN) && (w2 == -1)) {
6036                    goto overflow;
6037                }
6038                wResult = w1 / w2;
6039
6040                /*
6041                 * Force Tcl's integer division rules.
6042                 * TODO: examine for logic simplification
6043                 */
6044
6045                if (((wResult < 0) || ((wResult == 0) &&
6046                        ((w1 < 0 && w2 > 0) || (w1 > 0 && w2 < 0)))) &&
6047                        ((wResult * w2) != w1)) {
6048                    wResult -= 1;
6049                }
6050                break;
6051            default:
6052                /*
6053                 * Unused, here to silence compiler warning.
6054                 */
6055
6056                wResult = 0;
6057            }
6058
6059            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
6060            if (Tcl_IsShared(valuePtr)) {
6061                objResultPtr = Tcl_NewWideIntObj(wResult);
6062                TRACE(("%s\n", O2S(objResultPtr)));
6063                NEXT_INST_F(1, 2, 1);
6064            }
6065            Tcl_SetWideIntObj(valuePtr, wResult);
6066            TRACE(("%s\n", O2S(valuePtr)));
6067            NEXT_INST_F(1, 1, 0);
6068        }
6069
6070    overflow:
6071        {
6072            mp_int big1, big2, bigResult, bigRemainder;
6073
6074            TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
6075            Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
6076            Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
6077            mp_init(&bigResult);
6078            switch (*pc) {
6079            case INST_ADD:
6080                mp_add(&big1, &big2, &bigResult);
6081                break;
6082            case INST_SUB:
6083                mp_sub(&big1, &big2, &bigResult);
6084                break;
6085            case INST_MULT:
6086                mp_mul(&big1, &big2, &bigResult);
6087                break;
6088            case INST_DIV:
6089                if (mp_iszero(&big2)) {
6090                    TRACE(("%s %s => DIVIDE BY ZERO\n", O2S(valuePtr),
6091                            O2S(value2Ptr)));
6092                    mp_clear(&big1);
6093                    mp_clear(&big2);
6094                    mp_clear(&bigResult);
6095                    goto divideByZero;
6096                }
6097                mp_init(&bigRemainder);
6098                mp_div(&big1, &big2, &bigResult, &bigRemainder);
6099                /* TODO: internals intrusion */
6100                if (!mp_iszero(&bigRemainder)
6101                        && (bigRemainder.sign != big2.sign)) {
6102                    /*
6103                     * Convert to Tcl's integer division rules.
6104                     */
6105
6106                    mp_sub_d(&bigResult, 1, &bigResult);
6107                    mp_add(&bigRemainder, &big2, &bigRemainder);
6108                }
6109                mp_clear(&bigRemainder);
6110                break;
6111            case INST_EXPON:
6112                if (big2.used > 1) {
6113                    Tcl_SetObjResult(interp,
6114                            Tcl_NewStringObj("exponent too large", -1));
6115                    mp_clear(&big1);
6116                    mp_clear(&big2);
6117                    mp_clear(&bigResult);
6118                    result = TCL_ERROR;
6119                    goto checkForCatch;
6120                }
6121                mp_expt_d(&big1, big2.dp[0], &bigResult);
6122                break;
6123            }
6124            mp_clear(&big1);
6125            mp_clear(&big2);
6126            if (Tcl_IsShared(valuePtr)) {
6127                objResultPtr = Tcl_NewBignumObj(&bigResult);
6128                TRACE(("%s\n", O2S(objResultPtr)));
6129                NEXT_INST_F(1, 2, 1);
6130            }
6131            Tcl_SetBignumObj(valuePtr, &bigResult);
6132            TRACE(("%s\n", O2S(valuePtr)));
6133            NEXT_INST_F(1, 1, 0);
6134        }
6135    }
6136
6137    case INST_LNOT: {
6138        int b;
6139        Tcl_Obj *valuePtr = OBJ_AT_TOS;
6140
6141        /* TODO - check claim that taking address of b harms performance */
6142        /* TODO - consider optimization search for constants */
6143        result = TclGetBooleanFromObj(NULL, valuePtr, &b);
6144        if (result != TCL_OK) {
6145            TRACE(("\"%.20s\" => ILLEGAL TYPE %s\n", O2S(valuePtr),
6146                    (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
6147            IllegalExprOperandType(interp, pc, valuePtr);
6148            goto checkForCatch;
6149        }
6150        /* TODO: Consider peephole opt. */
6151        objResultPtr = constants[!b];
6152        NEXT_INST_F(1, 1, 1);
6153    }
6154
6155    case INST_BITNOT: {
6156        mp_int big;
6157        ClientData ptr;
6158        int type;
6159        Tcl_Obj *valuePtr = OBJ_AT_TOS;
6160
6161        result = GetNumberFromObj(NULL, valuePtr, &ptr, &type);
6162        if ((result != TCL_OK)
6163                || (type == TCL_NUMBER_NAN) || (type == TCL_NUMBER_DOUBLE)) {
6164            /*
6165             * ... ~$NonInteger => raise an error.
6166             */
6167
6168            result = TCL_ERROR;
6169            TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
6170                    (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
6171            IllegalExprOperandType(interp, pc, valuePtr);
6172            goto checkForCatch;
6173        }
6174        if (type == TCL_NUMBER_LONG) {
6175            long l = *((const long *)ptr);
6176
6177            if (Tcl_IsShared(valuePtr)) {
6178                TclNewLongObj(objResultPtr, ~l);
6179                NEXT_INST_F(1, 1, 1);
6180            }
6181            TclSetLongObj(valuePtr, ~l);
6182            NEXT_INST_F(1, 0, 0);
6183        }
6184#ifndef NO_WIDE_TYPE
6185        if (type == TCL_NUMBER_WIDE) {
6186            Tcl_WideInt w = *((const Tcl_WideInt *)ptr);
6187
6188            if (Tcl_IsShared(valuePtr)) {
6189                objResultPtr = Tcl_NewWideIntObj(~w);
6190                NEXT_INST_F(1, 1, 1);
6191            }
6192            Tcl_SetWideIntObj(valuePtr, ~w);
6193            NEXT_INST_F(1, 0, 0);
6194        }
6195#endif
6196        Tcl_TakeBignumFromObj(NULL, valuePtr, &big);
6197        /* ~a = - a - 1 */
6198        mp_neg(&big, &big);
6199        mp_sub_d(&big, 1, &big);
6200        if (Tcl_IsShared(valuePtr)) {
6201            objResultPtr = Tcl_NewBignumObj(&big);
6202            NEXT_INST_F(1, 1, 1);
6203        }
6204        Tcl_SetBignumObj(valuePtr, &big);
6205        NEXT_INST_F(1, 0, 0);
6206    }
6207
6208    case INST_UMINUS: {
6209        ClientData ptr;
6210        int type;
6211        Tcl_Obj *valuePtr = OBJ_AT_TOS;
6212
6213        result = GetNumberFromObj(NULL, valuePtr, &ptr, &type);
6214        if ((result != TCL_OK)
6215#ifndef ACCEPT_NAN
6216                || (type == TCL_NUMBER_NAN)
6217#endif
6218                ) {
6219            result = TCL_ERROR;
6220            TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
6221                    (valuePtr->typePtr? valuePtr->typePtr->name : "null")));
6222            IllegalExprOperandType(interp, pc, valuePtr);
6223            goto checkForCatch;
6224        }
6225        switch (type) {
6226        case TCL_NUMBER_DOUBLE: {
6227            double d;
6228
6229            if (Tcl_IsShared(valuePtr)) {
6230                TclNewDoubleObj(objResultPtr, -(*((const double *)ptr)));
6231                NEXT_INST_F(1, 1, 1);
6232            }
6233            d = *((const double *)ptr);
6234            TclSetDoubleObj(valuePtr, -d);
6235            NEXT_INST_F(1, 0, 0);
6236        }
6237        case TCL_NUMBER_LONG: {
6238            long l = *((const long *)ptr);
6239
6240            if (l != LONG_MIN) {
6241                if (Tcl_IsShared(valuePtr)) {
6242                    TclNewLongObj(objResultPtr, -l);
6243                    NEXT_INST_F(1, 1, 1);
6244                }
6245                TclSetLongObj(valuePtr, -l);
6246                NEXT_INST_F(1, 0, 0);
6247            }
6248            /* FALLTHROUGH */
6249        }
6250#ifndef NO_WIDE_TYPE
6251        case TCL_NUMBER_WIDE: {
6252            Tcl_WideInt w;
6253
6254            if (type == TCL_NUMBER_LONG) {
6255                w = (Tcl_WideInt)(*((const long *)ptr));
6256            } else {
6257                w = *((const Tcl_WideInt *)ptr);
6258            }
6259            if (w != LLONG_MIN) {
6260                if (Tcl_IsShared(valuePtr)) {
6261                    objResultPtr = Tcl_NewWideIntObj(-w);
6262                    NEXT_INST_F(1, 1, 1);
6263                }
6264                Tcl_SetWideIntObj(valuePtr, -w);
6265                NEXT_INST_F(1, 0, 0);
6266            }
6267            /* FALLTHROUGH */
6268        }
6269#endif
6270        case TCL_NUMBER_BIG: {
6271            mp_int big;
6272
6273            switch (type) {
6274#ifdef NO_WIDE_TYPE
6275            case TCL_NUMBER_LONG:
6276                TclBNInitBignumFromLong(&big, *(const long *) ptr);
6277                break;
6278#else
6279            case TCL_NUMBER_WIDE:
6280                TclBNInitBignumFromWideInt(&big, *(const Tcl_WideInt *) ptr);
6281                break;
6282#endif
6283            case TCL_NUMBER_BIG:
6284                Tcl_TakeBignumFromObj(NULL, valuePtr, &big);
6285            }
6286            mp_neg(&big, &big);
6287            if (Tcl_IsShared(valuePtr)) {
6288                objResultPtr = Tcl_NewBignumObj(&big);
6289                NEXT_INST_F(1, 1, 1);
6290            }
6291            Tcl_SetBignumObj(valuePtr, &big);
6292            NEXT_INST_F(1, 0, 0);
6293        }
6294        case TCL_NUMBER_NAN:
6295            /* -NaN => NaN */
6296            NEXT_INST_F(1, 0, 0);
6297        }
6298    }
6299
6300    case INST_UPLUS:
6301    case INST_TRY_CVT_TO_NUMERIC: {
6302        /*
6303         * Try to convert the topmost stack object to numeric object. This is
6304         * done in order to support [expr]'s policy of interpreting operands
6305         * if at all possible as numbers first, then strings.
6306         */
6307
6308        ClientData ptr;
6309        int type;
6310        Tcl_Obj *valuePtr = OBJ_AT_TOS;
6311
6312        if (GetNumberFromObj(NULL, valuePtr, &ptr, &type) != TCL_OK) {
6313            if (*pc == INST_UPLUS) {
6314                /*
6315                 * ... +$NonNumeric => raise an error.
6316                 */
6317
6318                result = TCL_ERROR;
6319                TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
6320                        (valuePtr->typePtr? valuePtr->typePtr->name:"null")));
6321                IllegalExprOperandType(interp, pc, valuePtr);
6322                goto checkForCatch;
6323            } else {
6324                /* ... TryConvertToNumeric($NonNumeric) is acceptable */
6325                TRACE(("\"%.20s\" => not numeric\n", O2S(valuePtr)));
6326                NEXT_INST_F(1, 0, 0);
6327            }
6328        }
6329#ifndef ACCEPT_NAN
6330        if (type == TCL_NUMBER_NAN) {
6331            result = TCL_ERROR;
6332            if (*pc == INST_UPLUS) {
6333                /*
6334                 * ... +$NonNumeric => raise an error.
6335                 */
6336
6337                TRACE(("\"%.20s\" => ILLEGAL TYPE %s \n", O2S(valuePtr),
6338                        (valuePtr->typePtr? valuePtr->typePtr->name:"null")));
6339                IllegalExprOperandType(interp, pc, valuePtr);
6340            } else {
6341                /*
6342                 * Numeric conversion of NaN -> error.
6343                 */
6344
6345                TRACE(("\"%.20s\" => IEEE FLOATING PT ERROR\n",
6346                        O2S(objResultPtr)));
6347                TclExprFloatError(interp, *((const double *)ptr));
6348            }
6349            goto checkForCatch;
6350        }
6351#endif
6352
6353        /*
6354         * Ensure that the numeric value has a string rep the same as the
6355         * formatted version of its internal rep. This is used, e.g., to make
6356         * sure that "expr {0001}" yields "1", not "0001". We implement this
6357         * by _discarding_ the string rep since we know it will be
6358         * regenerated, if needed later, by formatting the internal rep's
6359         * value.
6360         */
6361
6362        if (valuePtr->bytes == NULL) {
6363            TRACE(("\"%.20s\" => numeric, same Tcl_Obj\n", O2S(valuePtr)));
6364            NEXT_INST_F(1, 0, 0);
6365        }
6366        if (Tcl_IsShared(valuePtr)) {
6367            /*
6368             * Here we do some surgery within the Tcl_Obj internals. We want
6369             * to copy the intrep, but not the string, so we temporarily hide
6370             * the string so we do not copy it.
6371             */
6372
6373            char *savedString = valuePtr->bytes;
6374
6375            valuePtr->bytes = NULL;
6376            objResultPtr = Tcl_DuplicateObj(valuePtr);
6377            valuePtr->bytes = savedString;
6378            TRACE(("\"%.20s\" => numeric, new Tcl_Obj\n", O2S(valuePtr)));
6379            NEXT_INST_F(1, 1, 1);
6380        }
6381        TclInvalidateStringRep(valuePtr);
6382        TRACE(("\"%.20s\" => numeric, same Tcl_Obj\n", O2S(valuePtr)));
6383        NEXT_INST_F(1, 0, 0);
6384    }
6385
6386    case INST_BREAK:
6387        /*
6388        DECACHE_STACK_INFO();
6389        Tcl_ResetResult(interp);
6390        CACHE_STACK_INFO();
6391        */
6392        result = TCL_BREAK;
6393        cleanup = 0;
6394        goto processExceptionReturn;
6395
6396    case INST_CONTINUE:
6397        /*
6398        DECACHE_STACK_INFO();
6399        Tcl_ResetResult(interp);
6400        CACHE_STACK_INFO();
6401        */
6402        result = TCL_CONTINUE;
6403        cleanup = 0;
6404        goto processExceptionReturn;
6405
6406    case INST_FOREACH_START4: {
6407        /*
6408         * Initialize the temporary local var that holds the count of the
6409         * number of iterations of the loop body to -1.
6410         */
6411
6412        int opnd, iterTmpIndex;
6413        ForeachInfo *infoPtr;
6414        Var *iterVarPtr;
6415        Tcl_Obj *oldValuePtr;
6416
6417        opnd = TclGetUInt4AtPtr(pc+1);
6418        infoPtr = (ForeachInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
6419        iterTmpIndex = infoPtr->loopCtTemp;
6420        iterVarPtr = &(compiledLocals[iterTmpIndex]);
6421        oldValuePtr = iterVarPtr->value.objPtr;
6422
6423        if (oldValuePtr == NULL) {
6424            TclNewLongObj(iterVarPtr->value.objPtr, -1);
6425            Tcl_IncrRefCount(iterVarPtr->value.objPtr);
6426        } else {
6427            TclSetLongObj(oldValuePtr, -1);
6428        }
6429        TRACE(("%u => loop iter count temp %d\n", opnd, iterTmpIndex));
6430
6431#ifndef TCL_COMPILE_DEBUG
6432        /*
6433         * Remark that the compiler ALWAYS sets INST_FOREACH_STEP4 immediately
6434         * after INST_FOREACH_START4 - let us just fall through instead of
6435         * jumping back to the top.
6436         */
6437
6438        pc += 5;
6439        TCL_DTRACE_INST_NEXT();
6440#else
6441        NEXT_INST_F(5, 0, 0);
6442#endif
6443    }
6444
6445    case INST_FOREACH_STEP4: {
6446        /*
6447         * "Step" a foreach loop (i.e., begin its next iteration) by assigning
6448         * the next value list element to each loop var.
6449         */
6450
6451        ForeachInfo *infoPtr;
6452        ForeachVarList *varListPtr;
6453        Tcl_Obj *listPtr,*valuePtr, *value2Ptr, **elements;
6454        Var *iterVarPtr, *listVarPtr, *varPtr;
6455        int opnd, numLists, iterNum, listTmpIndex, listLen, numVars;
6456        int varIndex, valIndex, continueLoop, j;
6457        long i;
6458
6459        opnd = TclGetUInt4AtPtr(pc+1);
6460        infoPtr = (ForeachInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
6461        numLists = infoPtr->numLists;
6462
6463        /*
6464         * Increment the temp holding the loop iteration number.
6465         */
6466
6467        iterVarPtr = &(compiledLocals[infoPtr->loopCtTemp]);
6468        valuePtr = iterVarPtr->value.objPtr;
6469        iterNum = (valuePtr->internalRep.longValue + 1);
6470        TclSetLongObj(valuePtr, iterNum);
6471
6472        /*
6473         * Check whether all value lists are exhausted and we should stop the
6474         * loop.
6475         */
6476
6477        continueLoop = 0;
6478        listTmpIndex = infoPtr->firstValueTemp;
6479        for (i = 0;  i < numLists;  i++) {
6480            varListPtr = infoPtr->varLists[i];
6481            numVars = varListPtr->numVars;
6482
6483            listVarPtr = &(compiledLocals[listTmpIndex]);
6484            listPtr = listVarPtr->value.objPtr;
6485            result = TclListObjLength(interp, listPtr, &listLen);
6486            if (result == TCL_OK) {
6487                if (listLen > (iterNum * numVars)) {
6488                    continueLoop = 1;
6489                }
6490                listTmpIndex++;
6491            } else {
6492                TRACE_WITH_OBJ(("%u => ERROR converting list %ld, \"%s\": ",
6493                        opnd, i, O2S(listPtr)), Tcl_GetObjResult(interp));
6494                goto checkForCatch;
6495            }
6496        }
6497
6498        /*
6499         * If some var in some var list still has a remaining list element
6500         * iterate one more time. Assign to var the next element from its
6501         * value list. We already checked above that each list temp holds a
6502         * valid list object (by calling Tcl_ListObjLength), but cannot rely
6503         * on that check remaining valid: one list could have been shimmered
6504         * as a side effect of setting a traced variable.
6505         */
6506
6507        if (continueLoop) {
6508            listTmpIndex = infoPtr->firstValueTemp;
6509            for (i = 0;  i < numLists;  i++) {
6510                varListPtr = infoPtr->varLists[i];
6511                numVars = varListPtr->numVars;
6512
6513                listVarPtr = &(compiledLocals[listTmpIndex]);
6514                listPtr = TclListObjCopy(NULL, listVarPtr->value.objPtr);
6515                TclListObjGetElements(interp, listPtr, &listLen, &elements);
6516
6517                valIndex = (iterNum * numVars);
6518                for (j = 0;  j < numVars;  j++) {
6519                    if (valIndex >= listLen) {
6520                        TclNewObj(valuePtr);
6521                    } else {
6522                        valuePtr = elements[valIndex];
6523                    }
6524
6525                    varIndex = varListPtr->varIndexes[j];
6526                    varPtr = &(compiledLocals[varIndex]);
6527                    while (TclIsVarLink(varPtr)) {
6528                        varPtr = varPtr->value.linkPtr;
6529                    }
6530                    if (TclIsVarDirectWritable(varPtr)) {
6531                        value2Ptr = varPtr->value.objPtr;
6532                        if (valuePtr != value2Ptr) {
6533                            if (value2Ptr != NULL) {
6534                                TclDecrRefCount(value2Ptr);
6535                            }
6536                            varPtr->value.objPtr = valuePtr;
6537                            Tcl_IncrRefCount(valuePtr);
6538                        }
6539                    } else {
6540                        DECACHE_STACK_INFO();
6541                        value2Ptr = TclPtrSetVar(interp, varPtr, NULL, NULL,
6542                                NULL, valuePtr, TCL_LEAVE_ERR_MSG, varIndex);
6543                        CACHE_STACK_INFO();
6544                        if (value2Ptr == NULL) {
6545                            TRACE_WITH_OBJ((
6546                                    "%u => ERROR init. index temp %d: ",
6547                                    opnd,varIndex), Tcl_GetObjResult(interp));
6548                            result = TCL_ERROR;
6549                            TclDecrRefCount(listPtr);
6550                            goto checkForCatch;
6551                        }
6552                    }
6553                    valIndex++;
6554                }
6555                TclDecrRefCount(listPtr);
6556                listTmpIndex++;
6557            }
6558        }
6559        TRACE(("%u => %d lists, iter %d, %s loop\n", opnd, numLists,
6560                iterNum, (continueLoop? "continue" : "exit")));
6561
6562        /*
6563         * Run-time peep-hole optimisation: the compiler ALWAYS follows
6564         * INST_FOREACH_STEP4 with an INST_JUMP_FALSE. We just skip that
6565         * instruction and jump direct from here.
6566         */
6567
6568        pc += 5;
6569        if (*pc == INST_JUMP_FALSE1) {
6570            NEXT_INST_F((continueLoop? 2 : TclGetInt1AtPtr(pc+1)), 0, 0);
6571        } else {
6572            NEXT_INST_F((continueLoop? 5 : TclGetInt4AtPtr(pc+1)), 0, 0);
6573        }
6574    }
6575
6576    case INST_BEGIN_CATCH4:
6577        /*
6578         * Record start of the catch command with exception range index equal
6579         * to the operand. Push the current stack depth onto the special catch
6580         * stack.
6581         */
6582
6583        *(++catchTop) = CURR_DEPTH;
6584        TRACE(("%u => catchTop=%d, stackTop=%d\n",
6585                TclGetUInt4AtPtr(pc+1), (catchTop - initCatchTop - 1),
6586                (int) CURR_DEPTH));
6587        NEXT_INST_F(5, 0, 0);
6588
6589    case INST_END_CATCH:
6590        catchTop--;
6591        Tcl_ResetResult(interp);
6592        result = TCL_OK;
6593        TRACE(("=> catchTop=%d\n", (catchTop - initCatchTop - 1)));
6594        NEXT_INST_F(1, 0, 0);
6595
6596    case INST_PUSH_RESULT:
6597        objResultPtr = Tcl_GetObjResult(interp);
6598        TRACE_WITH_OBJ(("=> "), objResultPtr);
6599
6600        /*
6601         * See the comments at INST_INVOKE_STK
6602         */
6603        {
6604            Tcl_Obj *newObjResultPtr;
6605
6606            TclNewObj(newObjResultPtr);
6607            Tcl_IncrRefCount(newObjResultPtr);
6608            iPtr->objResultPtr = newObjResultPtr;
6609        }
6610
6611        NEXT_INST_F(1, 0, -1);
6612
6613    case INST_PUSH_RETURN_CODE:
6614        TclNewIntObj(objResultPtr, result);
6615        TRACE(("=> %u\n", result));
6616        NEXT_INST_F(1, 0, 1);
6617
6618    case INST_PUSH_RETURN_OPTIONS:
6619        objResultPtr = Tcl_GetReturnOptions(interp, result);
6620        TRACE_WITH_OBJ(("=> "), objResultPtr);
6621        NEXT_INST_F(1, 0, 1);
6622
6623/* TODO: normalize "valPtr" to "valuePtr" */
6624    {
6625        int opnd, opnd2, allocateDict;
6626        Tcl_Obj *dictPtr, *valPtr;
6627        Var *varPtr;
6628
6629    case INST_DICT_GET:
6630        opnd = TclGetUInt4AtPtr(pc+1);
6631        TRACE(("%u => ", opnd));
6632        dictPtr = OBJ_AT_DEPTH(opnd);
6633        if (opnd > 1) {
6634            dictPtr = TclTraceDictPath(interp, dictPtr, opnd-1,
6635                    &OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ);
6636            if (dictPtr == NULL) {
6637                TRACE_WITH_OBJ((
6638                        "%u => ERROR tracing dictionary path into \"%s\": ",
6639                        opnd, O2S(OBJ_AT_DEPTH(opnd))),
6640                        Tcl_GetObjResult(interp));
6641                result = TCL_ERROR;
6642                goto checkForCatch;
6643            }
6644        }
6645        result = Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, &objResultPtr);
6646        if ((result == TCL_OK) && objResultPtr) {
6647            TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
6648            NEXT_INST_V(5, opnd+1, 1);
6649        }
6650        if (result != TCL_OK) {
6651            TRACE_WITH_OBJ((
6652                    "%u => ERROR reading leaf dictionary key \"%s\": ",
6653                    opnd, O2S(dictPtr)), Tcl_GetObjResult(interp));
6654        } else {
6655            /*Tcl_ResetResult(interp);*/
6656            Tcl_AppendResult(interp, "key \"", TclGetString(OBJ_AT_TOS),
6657                    "\" not known in dictionary", NULL);
6658            TRACE_WITH_OBJ(("%u => ERROR ", opnd), Tcl_GetObjResult(interp));
6659            result = TCL_ERROR;
6660        }
6661        goto checkForCatch;
6662
6663    case INST_DICT_SET:
6664    case INST_DICT_UNSET:
6665    case INST_DICT_INCR_IMM:
6666        opnd = TclGetUInt4AtPtr(pc+1);
6667        opnd2 = TclGetUInt4AtPtr(pc+5);
6668
6669        varPtr = &(compiledLocals[opnd2]);
6670        while (TclIsVarLink(varPtr)) {
6671            varPtr = varPtr->value.linkPtr;
6672        }
6673        TRACE(("%u %u => ", opnd, opnd2));
6674        if (TclIsVarDirectReadable(varPtr)) {
6675            dictPtr = varPtr->value.objPtr;
6676        } else {
6677            DECACHE_STACK_INFO();
6678            dictPtr = TclPtrGetVar(interp, varPtr, NULL,NULL,NULL, 0, opnd2);
6679            CACHE_STACK_INFO();
6680        }
6681        if (dictPtr == NULL) {
6682            TclNewObj(dictPtr);
6683            allocateDict = 1;
6684        } else {
6685            allocateDict = Tcl_IsShared(dictPtr);
6686            if (allocateDict) {
6687                dictPtr = Tcl_DuplicateObj(dictPtr);
6688            }
6689        }
6690
6691        switch (*pc) {
6692        case INST_DICT_SET:
6693            cleanup = opnd + 1;
6694            result = Tcl_DictObjPutKeyList(interp, dictPtr, opnd,
6695                    &OBJ_AT_DEPTH(opnd), OBJ_AT_TOS);
6696            break;
6697        case INST_DICT_INCR_IMM:
6698            cleanup = 1;
6699            opnd = TclGetInt4AtPtr(pc+1);
6700            result = Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, &valPtr);
6701            if (result != TCL_OK) {
6702                break;
6703            }
6704            if (valPtr == NULL) {
6705                Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS,Tcl_NewIntObj(opnd));
6706            } else {
6707                Tcl_Obj *incrPtr = Tcl_NewIntObj(opnd);
6708
6709                Tcl_IncrRefCount(incrPtr);
6710                if (Tcl_IsShared(valPtr)) {
6711                    valPtr = Tcl_DuplicateObj(valPtr);
6712                    Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS, valPtr);
6713                }
6714                result = TclIncrObj(interp, valPtr, incrPtr);
6715                if (result == TCL_OK) {
6716                    Tcl_InvalidateStringRep(dictPtr);
6717                }
6718                TclDecrRefCount(incrPtr);
6719            }
6720            break;
6721        case INST_DICT_UNSET:
6722            cleanup = opnd;
6723            result = Tcl_DictObjRemoveKeyList(interp, dictPtr, opnd,
6724                    &OBJ_AT_DEPTH(opnd-1));
6725            break;
6726        default:
6727            cleanup = 0; /* stop compiler warning */
6728            Tcl_Panic("Should not happen!");
6729        }
6730
6731        if (result != TCL_OK) {
6732            if (allocateDict) {
6733                TclDecrRefCount(dictPtr);
6734            }
6735            TRACE_WITH_OBJ(("%u %u => ERROR updating dictionary: ",
6736                    opnd, opnd2), Tcl_GetObjResult(interp));
6737            goto checkForCatch;
6738        }
6739
6740        if (TclIsVarDirectWritable(varPtr)) {
6741            if (allocateDict) {
6742                Tcl_Obj *oldValuePtr = varPtr->value.objPtr;
6743
6744                Tcl_IncrRefCount(dictPtr);
6745                if (oldValuePtr != NULL) {
6746                    TclDecrRefCount(oldValuePtr);
6747                }
6748                varPtr->value.objPtr = dictPtr;
6749            }
6750            objResultPtr = dictPtr;
6751        } else {
6752            Tcl_IncrRefCount(dictPtr);
6753            DECACHE_STACK_INFO();
6754            objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
6755                    dictPtr, TCL_LEAVE_ERR_MSG, opnd2);
6756            CACHE_STACK_INFO();
6757            TclDecrRefCount(dictPtr);
6758            if (objResultPtr == NULL) {
6759                TRACE_APPEND(("ERROR: %.30s\n",
6760                        O2S(Tcl_GetObjResult(interp))));
6761                result = TCL_ERROR;
6762                goto checkForCatch;
6763            }
6764        }
6765#ifndef TCL_COMPILE_DEBUG
6766        if (*(pc+9) == INST_POP) {
6767            NEXT_INST_V(10, cleanup, 0);
6768        }
6769#endif
6770        TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
6771        NEXT_INST_V(9, cleanup, 1);
6772
6773    case INST_DICT_APPEND:
6774    case INST_DICT_LAPPEND:
6775        opnd = TclGetUInt4AtPtr(pc+1);
6776
6777        varPtr = &(compiledLocals[opnd]);
6778        while (TclIsVarLink(varPtr)) {
6779            varPtr = varPtr->value.linkPtr;
6780        }
6781        TRACE(("%u => ", opnd));
6782        if (TclIsVarDirectReadable(varPtr)) {
6783            dictPtr = varPtr->value.objPtr;
6784        } else {
6785            DECACHE_STACK_INFO();
6786            dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
6787            CACHE_STACK_INFO();
6788        }
6789        if (dictPtr == NULL) {
6790            TclNewObj(dictPtr);
6791            allocateDict = 1;
6792        } else {
6793            allocateDict = Tcl_IsShared(dictPtr);
6794            if (allocateDict) {
6795                dictPtr = Tcl_DuplicateObj(dictPtr);
6796            }
6797        }
6798
6799        result = Tcl_DictObjGet(interp, dictPtr, OBJ_UNDER_TOS, &valPtr);
6800        if (result != TCL_OK) {
6801            if (allocateDict) {
6802                TclDecrRefCount(dictPtr);
6803            }
6804            goto checkForCatch;
6805        }
6806
6807        /*
6808         * Note that a non-existent key results in a NULL valPtr, which is a
6809         * case handled separately below. What we *can* say at this point is
6810         * that the write-back will always succeed.
6811         */
6812
6813        switch (*pc) {
6814        case INST_DICT_APPEND:
6815            if (valPtr == NULL) {
6816                valPtr = OBJ_AT_TOS;
6817            } else {
6818                if (Tcl_IsShared(valPtr)) {
6819                    valPtr = Tcl_DuplicateObj(valPtr);
6820                }
6821                Tcl_AppendObjToObj(valPtr, OBJ_AT_TOS);
6822            }
6823            break;
6824        case INST_DICT_LAPPEND:
6825            /*
6826             * More complex because list-append can fail.
6827             */
6828
6829            if (valPtr == NULL) {
6830                valPtr = Tcl_NewListObj(1, &OBJ_AT_TOS);
6831            } else if (Tcl_IsShared(valPtr)) {
6832                valPtr = Tcl_DuplicateObj(valPtr);
6833                result = Tcl_ListObjAppendElement(interp, valPtr, OBJ_AT_TOS);
6834                if (result != TCL_OK) {
6835                    TclDecrRefCount(valPtr);
6836                    if (allocateDict) {
6837                        TclDecrRefCount(dictPtr);
6838                    }
6839                    goto checkForCatch;
6840                }
6841            } else {
6842                result = Tcl_ListObjAppendElement(interp, valPtr, OBJ_AT_TOS);
6843                if (result != TCL_OK) {
6844                    if (allocateDict) {
6845                        TclDecrRefCount(dictPtr);
6846                    }
6847                    goto checkForCatch;
6848                }
6849            }
6850            break;
6851        default:
6852            Tcl_Panic("Should not happen!");
6853        }
6854
6855        Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS, valPtr);
6856
6857        if (TclIsVarDirectWritable(varPtr)) {
6858            if (allocateDict) {
6859                Tcl_Obj *oldValuePtr = varPtr->value.objPtr;
6860
6861                Tcl_IncrRefCount(dictPtr);
6862                if (oldValuePtr != NULL) {
6863                    TclDecrRefCount(oldValuePtr);
6864                }
6865                varPtr->value.objPtr = dictPtr;
6866            }
6867            objResultPtr = dictPtr;
6868        } else {
6869            Tcl_IncrRefCount(dictPtr);
6870            DECACHE_STACK_INFO();
6871            objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
6872                    dictPtr, TCL_LEAVE_ERR_MSG, opnd);
6873            CACHE_STACK_INFO();
6874            TclDecrRefCount(dictPtr);
6875            if (objResultPtr == NULL) {
6876                TRACE_APPEND(("ERROR: %.30s\n",
6877                        O2S(Tcl_GetObjResult(interp))));
6878                result = TCL_ERROR;
6879                goto checkForCatch;
6880            }
6881        }
6882#ifndef TCL_COMPILE_DEBUG
6883        if (*(pc+5) == INST_POP) {
6884            NEXT_INST_F(6, 2, 0);
6885        }
6886#endif
6887        TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
6888        NEXT_INST_F(5, 2, 1);
6889    }
6890
6891    {
6892        int opnd, done;
6893        Tcl_Obj *statePtr, *dictPtr, *keyPtr, *valuePtr, *emptyPtr;
6894        Var *varPtr;
6895        Tcl_DictSearch *searchPtr;
6896
6897    case INST_DICT_FIRST:
6898        opnd = TclGetUInt4AtPtr(pc+1);
6899        TRACE(("%u => ", opnd));
6900        dictPtr = POP_OBJECT();
6901        searchPtr = (Tcl_DictSearch *) ckalloc(sizeof(Tcl_DictSearch));
6902        result = Tcl_DictObjFirst(interp, dictPtr, searchPtr, &keyPtr,
6903                &valuePtr, &done);
6904        if (result != TCL_OK) {
6905            ckfree((char *) searchPtr);
6906            goto checkForCatch;
6907        }
6908        TclNewObj(statePtr);
6909        statePtr->typePtr = &dictIteratorType;
6910        statePtr->internalRep.twoPtrValue.ptr1 = (void *) searchPtr;
6911        statePtr->internalRep.twoPtrValue.ptr2 = (void *) dictPtr;
6912        varPtr = (compiledLocals + opnd);
6913        if (varPtr->value.objPtr) {
6914            if (varPtr->value.objPtr->typePtr != &dictIteratorType) {
6915                TclDecrRefCount(varPtr->value.objPtr);
6916            } else {
6917                Tcl_Panic("mis-issued dictFirst!");
6918            }
6919        }
6920        varPtr->value.objPtr = statePtr;
6921        Tcl_IncrRefCount(statePtr);
6922        goto pushDictIteratorResult;
6923
6924    case INST_DICT_NEXT:
6925        opnd = TclGetUInt4AtPtr(pc+1);
6926        TRACE(("%u => ", opnd));
6927        statePtr = compiledLocals[opnd].value.objPtr;
6928        if (statePtr == NULL || statePtr->typePtr != &dictIteratorType) {
6929            Tcl_Panic("mis-issued dictNext!");
6930        }
6931        searchPtr = (Tcl_DictSearch *) statePtr->internalRep.twoPtrValue.ptr1;
6932        Tcl_DictObjNext(searchPtr, &keyPtr, &valuePtr, &done);
6933    pushDictIteratorResult:
6934        if (done) {
6935            TclNewObj(emptyPtr);
6936            PUSH_OBJECT(emptyPtr);
6937            PUSH_OBJECT(emptyPtr);
6938        } else {
6939            PUSH_OBJECT(valuePtr);
6940            PUSH_OBJECT(keyPtr);
6941        }
6942        TRACE_APPEND(("\"%.30s\" \"%.30s\" %d",
6943                O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), done));
6944        objResultPtr = constants[done];
6945        /* TODO: consider opt like INST_FOREACH_STEP4 */
6946        NEXT_INST_F(5, 0, 1);
6947
6948    case INST_DICT_DONE:
6949        opnd = TclGetUInt4AtPtr(pc+1);
6950        TRACE(("%u => ", opnd));
6951        statePtr = compiledLocals[opnd].value.objPtr;
6952        if (statePtr == NULL) {
6953            Tcl_Panic("mis-issued dictDone!");
6954        }
6955
6956        if (statePtr->typePtr == &dictIteratorType) {
6957            /*
6958             * First kill the search, and then release the reference to the
6959             * dictionary that we were holding.
6960             */
6961
6962            searchPtr = (Tcl_DictSearch *)
6963                    statePtr->internalRep.twoPtrValue.ptr1;
6964            Tcl_DictObjDone(searchPtr);
6965            ckfree((char *) searchPtr);
6966
6967            dictPtr = (Tcl_Obj *) statePtr->internalRep.twoPtrValue.ptr2;
6968            TclDecrRefCount(dictPtr);
6969
6970            /*
6971             * Set the internal variable to an empty object to signify that we
6972             * don't hold an iterator.
6973             */
6974
6975            TclDecrRefCount(statePtr);
6976            TclNewObj(emptyPtr);
6977            compiledLocals[opnd].value.objPtr = emptyPtr;
6978            Tcl_IncrRefCount(emptyPtr);
6979        }
6980        NEXT_INST_F(5, 0, 0);
6981    }
6982
6983    {
6984        int opnd, opnd2, i, length, allocdict;
6985        Tcl_Obj **keyPtrPtr, *dictPtr;
6986        DictUpdateInfo *duiPtr;
6987        Var *varPtr;
6988
6989    case INST_DICT_UPDATE_START:
6990        opnd = TclGetUInt4AtPtr(pc+1);
6991        opnd2 = TclGetUInt4AtPtr(pc+5);
6992        varPtr = &(compiledLocals[opnd]);
6993        duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
6994        while (TclIsVarLink(varPtr)) {
6995            varPtr = varPtr->value.linkPtr;
6996        }
6997        TRACE(("%u => ", opnd));
6998        if (TclIsVarDirectReadable(varPtr)) {
6999            dictPtr = varPtr->value.objPtr;
7000        } else {
7001            DECACHE_STACK_INFO();
7002            dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL,
7003                    TCL_LEAVE_ERR_MSG, opnd);
7004            CACHE_STACK_INFO();
7005            if (dictPtr == NULL) {
7006                goto dictUpdateStartFailed;
7007            }
7008        }
7009        if (TclListObjGetElements(interp, OBJ_AT_TOS, &length,
7010                &keyPtrPtr) != TCL_OK) {
7011            goto dictUpdateStartFailed;
7012        }
7013        if (length != duiPtr->length) {
7014            Tcl_Panic("dictUpdateStart argument length mismatch");
7015        }
7016        for (i=0 ; i<length ; i++) {
7017            Tcl_Obj *valPtr;
7018
7019            if (Tcl_DictObjGet(interp, dictPtr, keyPtrPtr[i],
7020                    &valPtr) != TCL_OK) {
7021                goto dictUpdateStartFailed;
7022            }
7023            varPtr = &(compiledLocals[duiPtr->varIndices[i]]);
7024            while (TclIsVarLink(varPtr)) {
7025                varPtr = varPtr->value.linkPtr;
7026            }
7027            DECACHE_STACK_INFO();
7028            if (valPtr == NULL) {
7029                TclObjUnsetVar2(interp,
7030                        localName(iPtr->varFramePtr, duiPtr->varIndices[i]),
7031                        NULL, 0);
7032            } else if (TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
7033                    valPtr, TCL_LEAVE_ERR_MSG,
7034                    duiPtr->varIndices[i]) == NULL) {
7035                CACHE_STACK_INFO();
7036            dictUpdateStartFailed:
7037                result = TCL_ERROR;
7038                goto checkForCatch;
7039            }
7040            CACHE_STACK_INFO();
7041        }
7042        NEXT_INST_F(9, 0, 0);
7043
7044    case INST_DICT_UPDATE_END:
7045        opnd = TclGetUInt4AtPtr(pc+1);
7046        opnd2 = TclGetUInt4AtPtr(pc+5);
7047        varPtr = &(compiledLocals[opnd]);
7048        duiPtr = codePtr->auxDataArrayPtr[opnd2].clientData;
7049        while (TclIsVarLink(varPtr)) {
7050            varPtr = varPtr->value.linkPtr;
7051        }
7052        TRACE(("%u => ", opnd));
7053        if (TclIsVarDirectReadable(varPtr)) {
7054            dictPtr = varPtr->value.objPtr;
7055        } else {
7056            DECACHE_STACK_INFO();
7057            dictPtr = TclPtrGetVar(interp, varPtr, NULL, NULL, NULL, 0, opnd);
7058            CACHE_STACK_INFO();
7059        }
7060        if (dictPtr == NULL) {
7061            NEXT_INST_F(9, 1, 0);
7062        }
7063        if (Tcl_DictObjSize(interp, dictPtr, &length) != TCL_OK
7064                || TclListObjGetElements(interp, OBJ_AT_TOS, &length,
7065                        &keyPtrPtr) != TCL_OK) {
7066            result = TCL_ERROR;
7067            goto checkForCatch;
7068        }
7069        allocdict = Tcl_IsShared(dictPtr);
7070        if (allocdict) {
7071            dictPtr = Tcl_DuplicateObj(dictPtr);
7072        }
7073        for (i=0 ; i<length ; i++) {
7074            Tcl_Obj *valPtr;
7075            Var *var2Ptr;
7076
7077            var2Ptr = &(compiledLocals[duiPtr->varIndices[i]]);
7078            while (TclIsVarLink(var2Ptr)) {
7079                var2Ptr = var2Ptr->value.linkPtr;
7080            }
7081            if (TclIsVarDirectReadable(var2Ptr)) {
7082                valPtr = var2Ptr->value.objPtr;
7083            } else {
7084                DECACHE_STACK_INFO();
7085                valPtr = TclPtrGetVar(interp, var2Ptr, NULL, NULL, NULL, 0,
7086                        duiPtr->varIndices[i]);
7087                CACHE_STACK_INFO();
7088            }
7089            if (valPtr == NULL) {
7090                Tcl_DictObjRemove(interp, dictPtr, keyPtrPtr[i]);
7091            } else if (dictPtr == valPtr) {
7092                Tcl_DictObjPut(interp, dictPtr, keyPtrPtr[i],
7093                        Tcl_DuplicateObj(valPtr));
7094            } else {
7095                Tcl_DictObjPut(interp, dictPtr, keyPtrPtr[i], valPtr);
7096            }
7097        }
7098        if (TclIsVarDirectWritable(varPtr)) {
7099            Tcl_IncrRefCount(dictPtr);
7100            TclDecrRefCount(varPtr->value.objPtr);
7101            varPtr->value.objPtr = dictPtr;
7102        } else {
7103            DECACHE_STACK_INFO();
7104            objResultPtr = TclPtrSetVar(interp, varPtr, NULL, NULL, NULL,
7105                    dictPtr, TCL_LEAVE_ERR_MSG, opnd);
7106            CACHE_STACK_INFO();
7107            if (objResultPtr == NULL) {
7108                if (allocdict) {
7109                    TclDecrRefCount(dictPtr);
7110                }
7111                result = TCL_ERROR;
7112                goto checkForCatch;
7113            }
7114        }
7115        NEXT_INST_F(9, 1, 0);
7116    }
7117
7118    default:
7119        Tcl_Panic("TclExecuteByteCode: unrecognized opCode %u", *pc);
7120    } /* end of switch on opCode */
7121
7122    /*
7123     * Division by zero in an expression. Control only reaches this point by
7124     * "goto divideByZero".
7125     */
7126
7127 divideByZero:
7128    Tcl_SetObjResult(interp, Tcl_NewStringObj("divide by zero", -1));
7129    Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", NULL);
7130
7131    result = TCL_ERROR;
7132    goto checkForCatch;
7133
7134    /*
7135     * Exponentiation of zero by negative number in an expression. Control
7136     * only reaches this point by "goto exponOfZero".
7137     */
7138
7139 exponOfZero:
7140    Tcl_SetObjResult(interp, Tcl_NewStringObj(
7141            "exponentiation of zero by negative power", -1));
7142    Tcl_SetErrorCode(interp, "ARITH", "DOMAIN",
7143            "exponentiation of zero by negative power", NULL);
7144    result = TCL_ERROR;
7145    goto checkForCatch;
7146
7147    /*
7148     * Block for variables needed to process exception returns.
7149     */
7150
7151    {
7152        ExceptionRange *rangePtr;
7153                                /* Points to closest loop or catch exception
7154                                 * range enclosing the pc. Used by various
7155                                 * instructions and processCatch to process
7156                                 * break, continue, and errors. */
7157        Tcl_Obj *valuePtr;
7158        const char *bytes;
7159        int length;
7160#if TCL_COMPILE_DEBUG
7161        int opnd;
7162#endif
7163
7164        /*
7165         * An external evaluation (INST_INVOKE or INST_EVAL) returned
7166         * something different from TCL_OK, or else INST_BREAK or
7167         * INST_CONTINUE were called.
7168         */
7169
7170    processExceptionReturn:
7171#if TCL_COMPILE_DEBUG
7172        switch (*pc) {
7173        case INST_INVOKE_STK1:
7174            opnd = TclGetUInt1AtPtr(pc+1);
7175            TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
7176            break;
7177        case INST_INVOKE_STK4:
7178            opnd = TclGetUInt4AtPtr(pc+1);
7179            TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
7180            break;
7181        case INST_EVAL_STK:
7182            /*
7183             * Note that the object at stacktop has to be used before doing
7184             * the cleanup.
7185             */
7186
7187            TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
7188            break;
7189        default:
7190            TRACE(("=> "));
7191        }
7192#endif
7193        if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
7194            rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 0, codePtr);
7195            if (rangePtr == NULL) {
7196                TRACE_APPEND(("no encl. loop or catch, returning %s\n",
7197                        StringForResultCode(result)));
7198                goto abnormalReturn;
7199            }
7200            if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
7201                TRACE_APPEND(("%s ...\n", StringForResultCode(result)));
7202                goto processCatch;
7203            }
7204            while (cleanup--) {
7205                valuePtr = POP_OBJECT();
7206                TclDecrRefCount(valuePtr);
7207            }
7208            if (result == TCL_BREAK) {
7209                result = TCL_OK;
7210                pc = (codePtr->codeStart + rangePtr->breakOffset);
7211                TRACE_APPEND(("%s, range at %d, new pc %d\n",
7212                        StringForResultCode(result),
7213                        rangePtr->codeOffset, rangePtr->breakOffset));
7214                NEXT_INST_F(0, 0, 0);
7215            } else {
7216                if (rangePtr->continueOffset == -1) {
7217                    TRACE_APPEND((
7218                            "%s, loop w/o continue, checking for catch\n",
7219                            StringForResultCode(result)));
7220                    goto checkForCatch;
7221                }
7222                result = TCL_OK;
7223                pc = (codePtr->codeStart + rangePtr->continueOffset);
7224                TRACE_APPEND(("%s, range at %d, new pc %d\n",
7225                        StringForResultCode(result),
7226                        rangePtr->codeOffset, rangePtr->continueOffset));
7227                NEXT_INST_F(0, 0, 0);
7228            }
7229#if TCL_COMPILE_DEBUG
7230        } else if (traceInstructions) {
7231            if ((result != TCL_ERROR) && (result != TCL_RETURN)) {
7232                Tcl_Obj *objPtr = Tcl_GetObjResult(interp);
7233                TRACE_APPEND(("OTHER RETURN CODE %d, result= \"%s\"\n ",
7234                        result, O2S(objPtr)));
7235            } else {
7236                Tcl_Obj *objPtr = Tcl_GetObjResult(interp);
7237                TRACE_APPEND(("%s, result= \"%s\"\n",
7238                        StringForResultCode(result), O2S(objPtr)));
7239            }
7240#endif
7241        }
7242
7243        /*
7244         * Execution has generated an "exception" such as TCL_ERROR. If the
7245         * exception is an error, record information about what was being
7246         * executed when the error occurred. Find the closest enclosing catch
7247         * range, if any. If no enclosing catch range is found, stop execution
7248         * and return the "exception" code.
7249         */
7250
7251        checkForCatch:
7252        if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
7253            bytes = GetSrcInfoForPc(pc, codePtr, &length);
7254            if (bytes != NULL) {
7255                DECACHE_STACK_INFO();
7256                Tcl_LogCommandInfo(interp, codePtr->source, bytes, length);
7257                CACHE_STACK_INFO();
7258            }
7259        }
7260        iPtr->flags &= ~ERR_ALREADY_LOGGED;
7261
7262        /*
7263         * Clear all expansions that may have started after the last
7264         * INST_BEGIN_CATCH.
7265         */
7266
7267        while ((expandNestList != NULL) && ((catchTop == initCatchTop) ||
7268                (*catchTop <=
7269                (ptrdiff_t) expandNestList->internalRep.twoPtrValue.ptr1))) {
7270            Tcl_Obj *objPtr = expandNestList->internalRep.twoPtrValue.ptr2;
7271
7272            TclDecrRefCount(expandNestList);
7273            expandNestList = objPtr;
7274        }
7275
7276        /*
7277         * We must not catch an exceeded limit. Instead, it blows outwards
7278         * until we either hit another interpreter (presumably where the limit
7279         * is not exceeded) or we get to the top-level.
7280         */
7281
7282        if (TclLimitExceeded(iPtr->limit)) {
7283#ifdef TCL_COMPILE_DEBUG
7284            if (traceInstructions) {
7285                fprintf(stdout, "   ... limit exceeded, returning %s\n",
7286                        StringForResultCode(result));
7287            }
7288#endif
7289            goto abnormalReturn;
7290        }
7291        if (catchTop == initCatchTop) {
7292#ifdef TCL_COMPILE_DEBUG
7293            if (traceInstructions) {
7294                fprintf(stdout, "   ... no enclosing catch, returning %s\n",
7295                        StringForResultCode(result));
7296            }
7297#endif
7298            goto abnormalReturn;
7299        }
7300        rangePtr = GetExceptRangeForPc(pc, /*catchOnly*/ 1, codePtr);
7301        if (rangePtr == NULL) {
7302            /*
7303             * This is only possible when compiling a [catch] that sends its
7304             * script to INST_EVAL. Cannot correct the compiler without
7305             * breakingcompat with previous .tbc compiled scripts.
7306             */
7307
7308#ifdef TCL_COMPILE_DEBUG
7309            if (traceInstructions) {
7310                fprintf(stdout, "   ... no enclosing catch, returning %s\n",
7311                        StringForResultCode(result));
7312            }
7313#endif
7314            goto abnormalReturn;
7315        }
7316
7317        /*
7318         * A catch exception range (rangePtr) was found to handle an
7319         * "exception". It was found either by checkForCatch just above or by
7320         * an instruction during break, continue, or error processing. Jump to
7321         * its catchOffset after unwinding the operand stack to the depth it
7322         * had when starting to execute the range's catch command.
7323         */
7324
7325    processCatch:
7326        while (CURR_DEPTH > *catchTop) {
7327            valuePtr = POP_OBJECT();
7328            TclDecrRefCount(valuePtr);
7329        }
7330#ifdef TCL_COMPILE_DEBUG
7331        if (traceInstructions) {
7332            fprintf(stdout, "  ... found catch at %d, catchTop=%d, "
7333                    "unwound to %ld, new pc %u\n",
7334                    rangePtr->codeOffset, catchTop - initCatchTop - 1,
7335                    (long) *catchTop, (unsigned) rangePtr->catchOffset);
7336        }
7337#endif
7338        pc = (codePtr->codeStart + rangePtr->catchOffset);
7339        NEXT_INST_F(0, 0, 0);   /* Restart the execution loop at pc. */
7340
7341        /*
7342         * end of infinite loop dispatching on instructions.
7343         */
7344
7345        /*
7346         * Abnormal return code. Restore the stack to state it had when
7347         * starting to execute the ByteCode. Panic if the stack is below the
7348         * initial level.
7349         */
7350
7351    abnormalReturn:
7352        TCL_DTRACE_INST_LAST();
7353        while (tosPtr > initTosPtr) {
7354            Tcl_Obj *objPtr = POP_OBJECT();
7355
7356            Tcl_DecrRefCount(objPtr);
7357        }
7358
7359        /*
7360         * Clear all expansions.
7361         */
7362
7363        while (expandNestList) {
7364            Tcl_Obj *objPtr = expandNestList->internalRep.twoPtrValue.ptr2;
7365
7366            TclDecrRefCount(expandNestList);
7367            expandNestList = objPtr;
7368        }
7369        if (tosPtr < initTosPtr) {
7370            fprintf(stderr,
7371                    "\nTclExecuteByteCode: abnormal return at pc %u: "
7372                    "stack top %d < entry stack top %d\n",
7373                    (unsigned)(pc - codePtr->codeStart),
7374                    (unsigned) CURR_DEPTH, (unsigned) 0);
7375            Tcl_Panic("TclExecuteByteCode execution failure: end stack top < start stack top");
7376        }
7377    }
7378
7379    /*
7380     * Restore the stack to the state it had previous to this bytecode.
7381     */
7382
7383    TclStackFree(interp, initCatchTop+1);
7384    return result;
7385#undef iPtr
7386}
7387
7388#ifdef TCL_COMPILE_DEBUG
7389/*
7390 *----------------------------------------------------------------------
7391 *
7392 * PrintByteCodeInfo --
7393 *
7394 *      This procedure prints a summary about a bytecode object to stdout. It
7395 *      is called by TclExecuteByteCode when starting to execute the bytecode
7396 *      object if tclTraceExec has the value 2 or more.
7397 *
7398 * Results:
7399 *      None.
7400 *
7401 * Side effects:
7402 *      None.
7403 *
7404 *----------------------------------------------------------------------
7405 */
7406
7407static void
7408PrintByteCodeInfo(
7409    register ByteCode *codePtr) /* The bytecode whose summary is printed to
7410                                 * stdout. */
7411{
7412    Proc *procPtr = codePtr->procPtr;
7413    Interp *iPtr = (Interp *) *codePtr->interpHandle;
7414
7415    fprintf(stdout, "\nExecuting ByteCode 0x%p, refCt %u, epoch %u, interp 0x%p (epoch %u)\n",
7416            codePtr, codePtr->refCount, codePtr->compileEpoch, iPtr,
7417            iPtr->compileEpoch);
7418
7419    fprintf(stdout, "  Source: ");
7420    TclPrintSource(stdout, codePtr->source, 60);
7421
7422    fprintf(stdout, "\n  Cmds %d, src %d, inst %u, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n",
7423            codePtr->numCommands, codePtr->numSrcBytes,
7424            codePtr->numCodeBytes, codePtr->numLitObjects,
7425            codePtr->numAuxDataItems, codePtr->maxStackDepth,
7426#ifdef TCL_COMPILE_STATS
7427            codePtr->numSrcBytes?
7428                    ((float)codePtr->structureSize)/codePtr->numSrcBytes :
7429#endif
7430            0.0);
7431
7432#ifdef TCL_COMPILE_STATS
7433    fprintf(stdout, "  Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n",
7434            (unsigned long) codePtr->structureSize,
7435            (unsigned long) (sizeof(ByteCode)-sizeof(size_t)-sizeof(Tcl_Time)),
7436            codePtr->numCodeBytes,
7437            (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
7438            (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)),
7439            (unsigned long) (codePtr->numAuxDataItems * sizeof(AuxData)),
7440            codePtr->numCmdLocBytes);
7441#endif /* TCL_COMPILE_STATS */
7442    if (procPtr != NULL) {
7443        fprintf(stdout,
7444                "  Proc 0x%p, refCt %d, args %d, compiled locals %d\n",
7445                procPtr, procPtr->refCount, procPtr->numArgs,
7446                procPtr->numCompiledLocals);
7447    }
7448}
7449#endif /* TCL_COMPILE_DEBUG */
7450
7451/*
7452 *----------------------------------------------------------------------
7453 *
7454 * ValidatePcAndStackTop --
7455 *
7456 *      This procedure is called by TclExecuteByteCode when debugging to
7457 *      verify that the program counter and stack top are valid during
7458 *      execution.
7459 *
7460 * Results:
7461 *      None.
7462 *
7463 * Side effects:
7464 *      Prints a message to stderr and panics if either the pc or stack top
7465 *      are invalid.
7466 *
7467 *----------------------------------------------------------------------
7468 */
7469
7470#ifdef TCL_COMPILE_DEBUG
7471static void
7472ValidatePcAndStackTop(
7473    register ByteCode *codePtr, /* The bytecode whose summary is printed to
7474                                 * stdout. */
7475    unsigned char *pc,          /* Points to first byte of a bytecode
7476                                 * instruction. The program counter. */
7477    int stackTop,               /* Current stack top. Must be between
7478                                 * stackLowerBound and stackUpperBound
7479                                 * (inclusive). */
7480    int stackLowerBound,        /* Smallest legal value for stackTop. */
7481    int checkStack)             /* 0 if the stack depth check should be
7482                                 * skipped. */
7483{
7484    int stackUpperBound = stackLowerBound + codePtr->maxStackDepth;
7485                                /* Greatest legal value for stackTop. */
7486    unsigned relativePc = (unsigned) (pc - codePtr->codeStart);
7487    unsigned long codeStart = (unsigned long) codePtr->codeStart;
7488    unsigned long codeEnd = (unsigned long)
7489            (codePtr->codeStart + codePtr->numCodeBytes);
7490    unsigned char opCode = *pc;
7491
7492    if (((unsigned long) pc < codeStart) || ((unsigned long) pc > codeEnd)) {
7493        fprintf(stderr, "\nBad instruction pc 0x%p in TclExecuteByteCode\n",
7494                pc);
7495        Tcl_Panic("TclExecuteByteCode execution failure: bad pc");
7496    }
7497    if ((unsigned) opCode > LAST_INST_OPCODE) {
7498        fprintf(stderr, "\nBad opcode %d at pc %u in TclExecuteByteCode\n",
7499                (unsigned) opCode, relativePc);
7500        Tcl_Panic("TclExecuteByteCode execution failure: bad opcode");
7501    }
7502    if (checkStack &&
7503            ((stackTop < stackLowerBound) || (stackTop > stackUpperBound))) {
7504        int numChars;
7505        const char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars);
7506
7507        fprintf(stderr, "\nBad stack top %d at pc %u in TclExecuteByteCode (min %i, max %i)",
7508                stackTop, relativePc, stackLowerBound, stackUpperBound);
7509        if (cmd != NULL) {
7510            Tcl_Obj *message;
7511
7512            TclNewLiteralStringObj(message, "\n executing ");
7513            Tcl_IncrRefCount(message);
7514            Tcl_AppendLimitedToObj(message, cmd, numChars, 100, NULL);
7515            fprintf(stderr,"%s\n", Tcl_GetString(message));
7516            Tcl_DecrRefCount(message);
7517        } else {
7518            fprintf(stderr, "\n");
7519        }
7520        Tcl_Panic("TclExecuteByteCode execution failure: bad stack top");
7521    }
7522}
7523#endif /* TCL_COMPILE_DEBUG */
7524
7525/*
7526 *----------------------------------------------------------------------
7527 *
7528 * IllegalExprOperandType --
7529 *
7530 *      Used by TclExecuteByteCode to append an error message to the interp
7531 *      result when an illegal operand type is detected by an expression
7532 *      instruction. The argument opndPtr holds the operand object in error.
7533 *
7534 * Results:
7535 *      None.
7536 *
7537 * Side effects:
7538 *      An error message is appended to the interp result.
7539 *
7540 *----------------------------------------------------------------------
7541 */
7542
7543static void
7544IllegalExprOperandType(
7545    Tcl_Interp *interp,         /* Interpreter to which error information
7546                                 * pertains. */
7547    unsigned char *pc,          /* Points to the instruction being executed
7548                                 * when the illegal type was found. */
7549    Tcl_Obj *opndPtr)           /* Points to the operand holding the value
7550                                 * with the illegal type. */
7551{
7552    ClientData ptr;
7553    int type;
7554    unsigned char opcode = *pc;
7555    const char *description, *operator = operatorStrings[opcode - INST_LOR];
7556
7557    if (opcode == INST_EXPON) {
7558        operator = "**";
7559    }
7560
7561    if (GetNumberFromObj(NULL, opndPtr, &ptr, &type) != TCL_OK) {
7562        int numBytes;
7563        const char *bytes = Tcl_GetStringFromObj(opndPtr, &numBytes);
7564
7565        if (numBytes == 0) {
7566            description = "empty string";
7567        } else if (TclCheckBadOctal(NULL, bytes)) {
7568            description = "invalid octal number";
7569        } else {
7570            description = "non-numeric string";
7571        }
7572    } else if (type == TCL_NUMBER_NAN) {
7573        description = "non-numeric floating-point value";
7574    } else if (type == TCL_NUMBER_DOUBLE) {
7575        description = "floating-point value";
7576    } else {
7577        /* TODO: No caller needs this. Eliminate? */
7578        description = "(big) integer";
7579    }
7580
7581    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
7582            "can't use %s as operand of \"%s\"", description, operator));
7583}
7584
7585/*
7586 *----------------------------------------------------------------------
7587 *
7588 * TclGetSrcInfoForPc, GetSrcInfoForPc, TclGetSrcInfoForCmd --
7589 *
7590 *      Given a program counter value, finds the closest command in the
7591 *      bytecode code unit's CmdLocation array and returns information about
7592 *      that command's source: a pointer to its first byte and the number of
7593 *      characters.
7594 *
7595 * Results:
7596 *      If a command is found that encloses the program counter value, a
7597 *      pointer to the command's source is returned and the length of the
7598 *      source is stored at *lengthPtr. If multiple commands resulted in code
7599 *      at pc, information about the closest enclosing command is returned. If
7600 *      no matching command is found, NULL is returned and *lengthPtr is
7601 *      unchanged.
7602 *
7603 * Side effects:
7604 *      The CmdFrame at *cfPtr is updated.
7605 *
7606 *----------------------------------------------------------------------
7607 */
7608
7609const char *
7610TclGetSrcInfoForCmd(
7611    Interp *iPtr,
7612    int *lenPtr)
7613{
7614    CmdFrame *cfPtr = iPtr->cmdFramePtr;
7615    ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr;
7616
7617    return GetSrcInfoForPc((unsigned char *) cfPtr->data.tebc.pc,
7618            codePtr, lenPtr);
7619}
7620
7621void
7622TclGetSrcInfoForPc(
7623    CmdFrame *cfPtr)
7624{
7625    ByteCode *codePtr = (ByteCode *) cfPtr->data.tebc.codePtr;
7626
7627    if (cfPtr->cmd.str.cmd == NULL) {
7628        cfPtr->cmd.str.cmd = GetSrcInfoForPc(
7629                (unsigned char *) cfPtr->data.tebc.pc, codePtr,
7630                &cfPtr->cmd.str.len);
7631    }
7632
7633    if (cfPtr->cmd.str.cmd != NULL) {
7634        /*
7635         * We now have the command. We can get the srcOffset back and from
7636         * there find the list of word locations for this command.
7637         */
7638
7639        ExtCmdLoc *eclPtr;
7640        ECL *locPtr = NULL;
7641        int srcOffset, i;
7642        Interp *iPtr = (Interp *) *codePtr->interpHandle;
7643        Tcl_HashEntry *hePtr =
7644                Tcl_FindHashEntry(iPtr->lineBCPtr, (char *) codePtr);
7645
7646        if (!hePtr) {
7647            return;
7648        }
7649
7650        srcOffset = cfPtr->cmd.str.cmd - codePtr->source;
7651        eclPtr = (ExtCmdLoc *) Tcl_GetHashValue (hePtr);
7652
7653        for (i=0; i < eclPtr->nuloc; i++) {
7654            if (eclPtr->loc[i].srcOffset == srcOffset) {
7655                locPtr = eclPtr->loc+i;
7656                break;
7657            }
7658        }
7659        if (locPtr == NULL) {
7660            Tcl_Panic("LocSearch failure");
7661        }
7662
7663        cfPtr->line = locPtr->line;
7664        cfPtr->nline = locPtr->nline;
7665        cfPtr->type = eclPtr->type;
7666
7667        if (eclPtr->type == TCL_LOCATION_SOURCE) {
7668            cfPtr->data.eval.path = eclPtr->path;
7669            Tcl_IncrRefCount(cfPtr->data.eval.path);
7670        }
7671
7672        /*
7673         * Do not set cfPtr->data.eval.path NULL for non-SOURCE. Needed for
7674         * cfPtr->data.tebc.codePtr.
7675         */
7676    }
7677}
7678
7679static const char *
7680GetSrcInfoForPc(
7681    unsigned char *pc,          /* The program counter value for which to
7682                                 * return the closest command's source info.
7683                                 * This points to a bytecode instruction in
7684                                 * codePtr's code. */
7685    ByteCode *codePtr,          /* The bytecode sequence in which to look up
7686                                 * the command source for the pc. */
7687    int *lengthPtr)             /* If non-NULL, the location where the length
7688                                 * of the command's source should be stored.
7689                                 * If NULL, no length is stored. */
7690{
7691    register int pcOffset = (pc - codePtr->codeStart);
7692    int numCmds = codePtr->numCommands;
7693    unsigned char *codeDeltaNext, *codeLengthNext;
7694    unsigned char *srcDeltaNext, *srcLengthNext;
7695    int codeOffset, codeLen, codeEnd, srcOffset, srcLen, delta, i;
7696    int bestDist = INT_MAX;     /* Distance of pc to best cmd's start pc. */
7697    int bestSrcOffset = -1;     /* Initialized to avoid compiler warning. */
7698    int bestSrcLength = -1;     /* Initialized to avoid compiler warning. */
7699
7700    if ((pcOffset < 0) || (pcOffset >= codePtr->numCodeBytes)) {
7701        return NULL;
7702    }
7703
7704    /*
7705     * Decode the code and source offset and length for each command. The
7706     * closest enclosing command is the last one whose code started before
7707     * pcOffset.
7708     */
7709
7710    codeDeltaNext = codePtr->codeDeltaStart;
7711    codeLengthNext = codePtr->codeLengthStart;
7712    srcDeltaNext = codePtr->srcDeltaStart;
7713    srcLengthNext = codePtr->srcLengthStart;
7714    codeOffset = srcOffset = 0;
7715    for (i = 0;  i < numCmds;  i++) {
7716        if ((unsigned) *codeDeltaNext == (unsigned) 0xFF) {
7717            codeDeltaNext++;
7718            delta = TclGetInt4AtPtr(codeDeltaNext);
7719            codeDeltaNext += 4;
7720        } else {
7721            delta = TclGetInt1AtPtr(codeDeltaNext);
7722            codeDeltaNext++;
7723        }
7724        codeOffset += delta;
7725
7726        if ((unsigned) *codeLengthNext == (unsigned) 0xFF) {
7727            codeLengthNext++;
7728            codeLen = TclGetInt4AtPtr(codeLengthNext);
7729            codeLengthNext += 4;
7730        } else {
7731            codeLen = TclGetInt1AtPtr(codeLengthNext);
7732            codeLengthNext++;
7733        }
7734        codeEnd = (codeOffset + codeLen - 1);
7735
7736        if ((unsigned) *srcDeltaNext == (unsigned) 0xFF) {
7737            srcDeltaNext++;
7738            delta = TclGetInt4AtPtr(srcDeltaNext);
7739            srcDeltaNext += 4;
7740        } else {
7741            delta = TclGetInt1AtPtr(srcDeltaNext);
7742            srcDeltaNext++;
7743        }
7744        srcOffset += delta;
7745
7746        if ((unsigned) *srcLengthNext == (unsigned) 0xFF) {
7747            srcLengthNext++;
7748            srcLen = TclGetInt4AtPtr(srcLengthNext);
7749            srcLengthNext += 4;
7750        } else {
7751            srcLen = TclGetInt1AtPtr(srcLengthNext);
7752            srcLengthNext++;
7753        }
7754
7755        if (codeOffset > pcOffset) {    /* Best cmd already found */
7756            break;
7757        }
7758        if (pcOffset <= codeEnd) {      /* This cmd's code encloses pc */
7759            int dist = (pcOffset - codeOffset);
7760
7761            if (dist <= bestDist) {
7762                bestDist = dist;
7763                bestSrcOffset = srcOffset;
7764                bestSrcLength = srcLen;
7765            }
7766        }
7767    }
7768
7769    if (bestDist == INT_MAX) {
7770        return NULL;
7771    }
7772
7773    if (lengthPtr != NULL) {
7774        *lengthPtr = bestSrcLength;
7775    }
7776    return (codePtr->source + bestSrcOffset);
7777}
7778
7779/*
7780 *----------------------------------------------------------------------
7781 *
7782 * GetExceptRangeForPc --
7783 *
7784 *      Given a program counter value, return the closest enclosing
7785 *      ExceptionRange.
7786 *
7787 * Results:
7788 *      In the normal case, catchOnly is 0 (false) and this procedure returns
7789 *      a pointer to the most closely enclosing ExceptionRange structure
7790 *      regardless of whether it is a loop or catch exception range. This is
7791 *      appropriate when processing a TCL_BREAK or TCL_CONTINUE, which will be
7792 *      "handled" either by a loop exception range or a closer catch range. If
7793 *      catchOnly is nonzero, this procedure ignores loop exception ranges and
7794 *      returns a pointer to the closest catch range. If no matching
7795 *      ExceptionRange is found that encloses pc, a NULL is returned.
7796 *
7797 * Side effects:
7798 *      None.
7799 *
7800 *----------------------------------------------------------------------
7801 */
7802
7803static ExceptionRange *
7804GetExceptRangeForPc(
7805    unsigned char *pc,          /* The program counter value for which to
7806                                 * search for a closest enclosing exception
7807                                 * range. This points to a bytecode
7808                                 * instruction in codePtr's code. */
7809    int catchOnly,              /* If 0, consider either loop or catch
7810                                 * ExceptionRanges in search. If nonzero
7811                                 * consider only catch ranges (and ignore any
7812                                 * closer loop ranges). */
7813    ByteCode *codePtr)          /* Points to the ByteCode in which to search
7814                                 * for the enclosing ExceptionRange. */
7815{
7816    ExceptionRange *rangeArrayPtr;
7817    int numRanges = codePtr->numExceptRanges;
7818    register ExceptionRange *rangePtr;
7819    int pcOffset = pc - codePtr->codeStart;
7820    register int start;
7821
7822    if (numRanges == 0) {
7823        return NULL;
7824    }
7825
7826    /*
7827     * This exploits peculiarities of our compiler: nested ranges are always
7828     * *after* their containing ranges, so that by scanning backwards we are
7829     * sure that the first matching range is indeed the deepest.
7830     */
7831
7832    rangeArrayPtr = codePtr->exceptArrayPtr;
7833    rangePtr = rangeArrayPtr + numRanges;
7834    while (--rangePtr >= rangeArrayPtr) {
7835        start = rangePtr->codeOffset;
7836        if ((start <= pcOffset) &&
7837                (pcOffset < (start + rangePtr->numCodeBytes))) {
7838            if ((!catchOnly)
7839                    || (rangePtr->type == CATCH_EXCEPTION_RANGE)) {
7840                return rangePtr;
7841            }
7842        }
7843    }
7844    return NULL;
7845}
7846
7847/*
7848 *----------------------------------------------------------------------
7849 *
7850 * GetOpcodeName --
7851 *
7852 *      This procedure is called by the TRACE and TRACE_WITH_OBJ macros used
7853 *      in TclExecuteByteCode when debugging. It returns the name of the
7854 *      bytecode instruction at a specified instruction pc.
7855 *
7856 * Results:
7857 *      A character string for the instruction.
7858 *
7859 * Side effects:
7860 *      None.
7861 *
7862 *----------------------------------------------------------------------
7863 */
7864
7865#ifdef TCL_COMPILE_DEBUG
7866static char *
7867GetOpcodeName(
7868    unsigned char *pc)          /* Points to the instruction whose name should
7869                                 * be returned. */
7870{
7871    unsigned char opCode = *pc;
7872
7873    return tclInstructionTable[opCode].name;
7874}
7875#endif /* TCL_COMPILE_DEBUG */
7876
7877/*
7878 *----------------------------------------------------------------------
7879 *
7880 * TclExprFloatError --
7881 *
7882 *      This procedure is called when an error occurs during a floating-point
7883 *      operation. It reads errno and sets interp->objResultPtr accordingly.
7884 *
7885 * Results:
7886 *      interp->objResultPtr is set to hold an error message.
7887 *
7888 * Side effects:
7889 *      None.
7890 *
7891 *----------------------------------------------------------------------
7892 */
7893
7894void
7895TclExprFloatError(
7896    Tcl_Interp *interp,         /* Where to store error message. */
7897    double value)               /* Value returned after error; used to
7898                                 * distinguish underflows from overflows. */
7899{
7900    const char *s;
7901
7902    if ((errno == EDOM) || TclIsNaN(value)) {
7903        s = "domain error: argument not in valid range";
7904        Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1));
7905        Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", s, NULL);
7906    } else if ((errno == ERANGE) || TclIsInfinite(value)) {
7907        if (value == 0.0) {
7908            s = "floating-point value too small to represent";
7909            Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1));
7910            Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", s, NULL);
7911        } else {
7912            s = "floating-point value too large to represent";
7913            Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1));
7914            Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", s, NULL);
7915        }
7916    } else {
7917        Tcl_Obj *objPtr = Tcl_ObjPrintf(
7918                "unknown floating-point error, errno = %d", errno);
7919
7920        Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN",
7921                Tcl_GetString(objPtr), NULL);
7922        Tcl_SetObjResult(interp, objPtr);
7923    }
7924}
7925
7926#ifdef TCL_COMPILE_STATS
7927/*
7928 *----------------------------------------------------------------------
7929 *
7930 * TclLog2 --
7931 *
7932 *      Procedure used while collecting compilation statistics to determine
7933 *      the log base 2 of an integer.
7934 *
7935 * Results:
7936 *      Returns the log base 2 of the operand. If the argument is less than or
7937 *      equal to zero, a zero is returned.
7938 *
7939 * Side effects:
7940 *      None.
7941 *
7942 *----------------------------------------------------------------------
7943 */
7944
7945int
7946TclLog2(
7947    register int value)         /* The integer for which to compute the log
7948                                 * base 2. */
7949{
7950    register int n = value;
7951    register int result = 0;
7952
7953    while (n > 1) {
7954        n = n >> 1;
7955        result++;
7956    }
7957    return result;
7958}
7959
7960/*
7961 *----------------------------------------------------------------------
7962 *
7963 * EvalStatsCmd --
7964 *
7965 *      Implements the "evalstats" command that prints instruction execution
7966 *      counts to stdout.
7967 *
7968 * Results:
7969 *      Standard Tcl results.
7970 *
7971 * Side effects:
7972 *      None.
7973 *
7974 *----------------------------------------------------------------------
7975 */
7976
7977static int
7978EvalStatsCmd(
7979    ClientData unused,          /* Unused. */
7980    Tcl_Interp *interp,         /* The current interpreter. */
7981    int objc,                   /* The number of arguments. */
7982    Tcl_Obj *const objv[])      /* The argument strings. */
7983{
7984    Interp *iPtr = (Interp *) interp;
7985    LiteralTable *globalTablePtr = &iPtr->literalTable;
7986    ByteCodeStats *statsPtr = &iPtr->stats;
7987    double totalCodeBytes, currentCodeBytes;
7988    double totalLiteralBytes, currentLiteralBytes;
7989    double objBytesIfUnshared, strBytesIfUnshared, sharingBytesSaved;
7990    double strBytesSharedMultX, strBytesSharedOnce;
7991    double numInstructions, currentHeaderBytes;
7992    long numCurrentByteCodes, numByteCodeLits;
7993    long refCountSum, literalMgmtBytes, sum;
7994    int numSharedMultX, numSharedOnce;
7995    int decadeHigh, minSizeDecade, maxSizeDecade, length, i;
7996    char *litTableStats;
7997    LiteralEntry *entryPtr;
7998
7999#define Percent(a,b) ((a) * 100.0 / (b))
8000
8001    numInstructions = 0.0;
8002    for (i = 0;  i < 256;  i++) {
8003        if (statsPtr->instructionCount[i] != 0) {
8004            numInstructions += statsPtr->instructionCount[i];
8005        }
8006    }
8007
8008    totalLiteralBytes = sizeof(LiteralTable)
8009            + iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)
8010            + (statsPtr->numLiteralsCreated * sizeof(LiteralEntry))
8011            + (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj))
8012            + statsPtr->totalLitStringBytes;
8013    totalCodeBytes = statsPtr->totalByteCodeBytes + totalLiteralBytes;
8014
8015    numCurrentByteCodes =
8016            statsPtr->numCompilations - statsPtr->numByteCodesFreed;
8017    currentHeaderBytes = numCurrentByteCodes
8018            * (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time));
8019    literalMgmtBytes = sizeof(LiteralTable)
8020            + (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *))
8021            + (iPtr->literalTable.numEntries * sizeof(LiteralEntry));
8022    currentLiteralBytes = literalMgmtBytes
8023            + iPtr->literalTable.numEntries * sizeof(Tcl_Obj)
8024            + statsPtr->currentLitStringBytes;
8025    currentCodeBytes = statsPtr->currentByteCodeBytes + currentLiteralBytes;
8026
8027    /*
8028     * Summary statistics, total and current source and ByteCode sizes.
8029     */
8030
8031    fprintf(stdout, "\n----------------------------------------------------------------\n");
8032    fprintf(stdout,
8033            "Compilation and execution statistics for interpreter 0x%p\n",
8034            iPtr);
8035
8036    fprintf(stdout, "\nNumber ByteCodes executed        %ld\n",
8037            statsPtr->numExecutions);
8038    fprintf(stdout, "Number ByteCodes compiled  %ld\n",
8039            statsPtr->numCompilations);
8040    fprintf(stdout, "  Mean executions/compile  %.1f\n",
8041            statsPtr->numExecutions / (float)statsPtr->numCompilations);
8042
8043    fprintf(stdout, "\nInstructions executed            %.0f\n",
8044            numInstructions);
8045    fprintf(stdout, "  Mean inst/compile                %.0f\n",
8046            numInstructions / statsPtr->numCompilations);
8047    fprintf(stdout, "  Mean inst/execution              %.0f\n",
8048            numInstructions / statsPtr->numExecutions);
8049
8050    fprintf(stdout, "\nTotal ByteCodes                  %ld\n",
8051            statsPtr->numCompilations);
8052    fprintf(stdout, "  Source bytes                     %.6g\n",
8053            statsPtr->totalSrcBytes);
8054    fprintf(stdout, "  Code bytes                       %.6g\n",
8055            totalCodeBytes);
8056    fprintf(stdout, "    ByteCode bytes         %.6g\n",
8057            statsPtr->totalByteCodeBytes);
8058    fprintf(stdout, "    Literal bytes          %.6g\n",
8059            totalLiteralBytes);
8060    fprintf(stdout, "      table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
8061            (unsigned long) sizeof(LiteralTable),
8062            (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
8063            (unsigned long) (statsPtr->numLiteralsCreated * sizeof(LiteralEntry)),
8064            (unsigned long) (statsPtr->numLiteralsCreated * sizeof(Tcl_Obj)),
8065            statsPtr->totalLitStringBytes);
8066    fprintf(stdout, "  Mean code/compile                %.1f\n",
8067            totalCodeBytes / statsPtr->numCompilations);
8068    fprintf(stdout, "  Mean code/source         %.1f\n",
8069            totalCodeBytes / statsPtr->totalSrcBytes);
8070
8071    fprintf(stdout, "\nCurrent (active) ByteCodes       %ld\n",
8072            numCurrentByteCodes);
8073    fprintf(stdout, "  Source bytes                     %.6g\n",
8074            statsPtr->currentSrcBytes);
8075    fprintf(stdout, "  Code bytes                       %.6g\n",
8076            currentCodeBytes);
8077    fprintf(stdout, "    ByteCode bytes         %.6g\n",
8078            statsPtr->currentByteCodeBytes);
8079    fprintf(stdout, "    Literal bytes          %.6g\n",
8080            currentLiteralBytes);
8081    fprintf(stdout, "      table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
8082            (unsigned long) sizeof(LiteralTable),
8083            (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
8084            (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)),
8085            (unsigned long) (iPtr->literalTable.numEntries * sizeof(Tcl_Obj)),
8086            statsPtr->currentLitStringBytes);
8087    fprintf(stdout, "  Mean code/source         %.1f\n",
8088            currentCodeBytes / statsPtr->currentSrcBytes);
8089    fprintf(stdout, "  Code + source bytes              %.6g (%0.1f mean code/src)\n",
8090            (currentCodeBytes + statsPtr->currentSrcBytes),
8091            (currentCodeBytes / statsPtr->currentSrcBytes) + 1.0);
8092
8093    /*
8094     * Tcl_IsShared statistics check
8095     *
8096     * This gives the refcount of each obj as Tcl_IsShared was called for it.
8097     * Shared objects must be duplicated before they can be modified.
8098     */
8099
8100    numSharedMultX = 0;
8101    fprintf(stdout, "\nTcl_IsShared object check (all objects):\n");
8102    fprintf(stdout, "  Object had refcount <=1 (not shared)     %ld\n",
8103            tclObjsShared[1]);
8104    for (i = 2;  i < TCL_MAX_SHARED_OBJ_STATS;  i++) {
8105        fprintf(stdout, "  refcount ==%d                %ld\n",
8106                i, tclObjsShared[i]);
8107        numSharedMultX += tclObjsShared[i];
8108    }
8109    fprintf(stdout, "  refcount >=%d            %ld\n",
8110            i, tclObjsShared[0]);
8111    numSharedMultX += tclObjsShared[0];
8112    fprintf(stdout, "  Total shared objects                     %d\n",
8113            numSharedMultX);
8114
8115    /*
8116     * Literal table statistics.
8117     */
8118
8119    numByteCodeLits = 0;
8120    refCountSum = 0;
8121    numSharedMultX = 0;
8122    numSharedOnce = 0;
8123    objBytesIfUnshared = 0.0;
8124    strBytesIfUnshared = 0.0;
8125    strBytesSharedMultX = 0.0;
8126    strBytesSharedOnce = 0.0;
8127    for (i = 0;  i < globalTablePtr->numBuckets;  i++) {
8128        for (entryPtr = globalTablePtr->buckets[i];  entryPtr != NULL;
8129                entryPtr = entryPtr->nextPtr) {
8130            if (entryPtr->objPtr->typePtr == &tclByteCodeType) {
8131                numByteCodeLits++;
8132            }
8133            (void) Tcl_GetStringFromObj(entryPtr->objPtr, &length);
8134            refCountSum += entryPtr->refCount;
8135            objBytesIfUnshared += (entryPtr->refCount * sizeof(Tcl_Obj));
8136            strBytesIfUnshared += (entryPtr->refCount * (length+1));
8137            if (entryPtr->refCount > 1) {
8138                numSharedMultX++;
8139                strBytesSharedMultX += (length+1);
8140            } else {
8141                numSharedOnce++;
8142                strBytesSharedOnce += (length+1);
8143            }
8144        }
8145    }
8146    sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared)
8147            - currentLiteralBytes;
8148
8149    fprintf(stdout, "\nTotal objects (all interps)      %ld\n",
8150            tclObjsAlloced);
8151    fprintf(stdout, "Current objects                    %ld\n",
8152            (tclObjsAlloced - tclObjsFreed));
8153    fprintf(stdout, "Total literal objects              %ld\n",
8154            statsPtr->numLiteralsCreated);
8155
8156    fprintf(stdout, "\nCurrent literal objects          %d (%0.1f%% of current objects)\n",
8157            globalTablePtr->numEntries,
8158            Percent(globalTablePtr->numEntries, tclObjsAlloced-tclObjsFreed));
8159    fprintf(stdout, "  ByteCode literals                %ld (%0.1f%% of current literals)\n",
8160            numByteCodeLits,
8161            Percent(numByteCodeLits, globalTablePtr->numEntries));
8162    fprintf(stdout, "  Literals reused > 1x             %d\n",
8163            numSharedMultX);
8164    fprintf(stdout, "  Mean reference count             %.2f\n",
8165            ((double) refCountSum) / globalTablePtr->numEntries);
8166    fprintf(stdout, "  Mean len, str reused >1x         %.2f\n",
8167            (numSharedMultX ? strBytesSharedMultX/numSharedMultX : 0.0));
8168    fprintf(stdout, "  Mean len, str used 1x            %.2f\n",
8169            (numSharedOnce ? strBytesSharedOnce/numSharedOnce : 0.0));
8170    fprintf(stdout, "  Total sharing savings            %.6g (%0.1f%% of bytes if no sharing)\n",
8171            sharingBytesSaved,
8172            Percent(sharingBytesSaved, objBytesIfUnshared+strBytesIfUnshared));
8173    fprintf(stdout, "    Bytes with sharing             %.6g\n",
8174            currentLiteralBytes);
8175    fprintf(stdout, "      table %lu + bkts %lu + entries %lu + objects %lu + strings %.6g\n",
8176            (unsigned long) sizeof(LiteralTable),
8177            (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
8178            (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)),
8179            (unsigned long) (iPtr->literalTable.numEntries * sizeof(Tcl_Obj)),
8180            statsPtr->currentLitStringBytes);
8181    fprintf(stdout, "    Bytes if no sharing            %.6g = objects %.6g + strings %.6g\n",
8182            (objBytesIfUnshared + strBytesIfUnshared),
8183            objBytesIfUnshared, strBytesIfUnshared);
8184    fprintf(stdout, "  String sharing savings   %.6g = unshared %.6g - shared %.6g\n",
8185            (strBytesIfUnshared - statsPtr->currentLitStringBytes),
8186            strBytesIfUnshared, statsPtr->currentLitStringBytes);
8187    fprintf(stdout, "  Literal mgmt overhead            %ld (%0.1f%% of bytes with sharing)\n",
8188            literalMgmtBytes,
8189            Percent(literalMgmtBytes, currentLiteralBytes));
8190    fprintf(stdout, "    table %lu + buckets %lu + entries %lu\n",
8191            (unsigned long) sizeof(LiteralTable),
8192            (unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
8193            (unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)));
8194
8195    /*
8196     * Breakdown of current ByteCode space requirements.
8197     */
8198
8199    fprintf(stdout, "\nBreakdown of current ByteCode requirements:\n");
8200    fprintf(stdout, "                         Bytes      Pct of    Avg per\n");
8201    fprintf(stdout, "                                     total    ByteCode\n");
8202    fprintf(stdout, "Total             %12.6g     100.00%%   %8.1f\n",
8203            statsPtr->currentByteCodeBytes,
8204            statsPtr->currentByteCodeBytes / numCurrentByteCodes);
8205    fprintf(stdout, "Header            %12.6g   %8.1f%%   %8.1f\n",
8206            currentHeaderBytes,
8207            Percent(currentHeaderBytes, statsPtr->currentByteCodeBytes),
8208            currentHeaderBytes / numCurrentByteCodes);
8209    fprintf(stdout, "Instructions      %12.6g   %8.1f%%   %8.1f\n",
8210            statsPtr->currentInstBytes,
8211            Percent(statsPtr->currentInstBytes,statsPtr->currentByteCodeBytes),
8212            statsPtr->currentInstBytes / numCurrentByteCodes);
8213    fprintf(stdout, "Literal ptr array %12.6g   %8.1f%%   %8.1f\n",
8214            statsPtr->currentLitBytes,
8215            Percent(statsPtr->currentLitBytes,statsPtr->currentByteCodeBytes),
8216            statsPtr->currentLitBytes / numCurrentByteCodes);
8217    fprintf(stdout, "Exception table   %12.6g   %8.1f%%   %8.1f\n",
8218            statsPtr->currentExceptBytes,
8219            Percent(statsPtr->currentExceptBytes,statsPtr->currentByteCodeBytes),
8220            statsPtr->currentExceptBytes / numCurrentByteCodes);
8221    fprintf(stdout, "Auxiliary data    %12.6g   %8.1f%%   %8.1f\n",
8222            statsPtr->currentAuxBytes,
8223            Percent(statsPtr->currentAuxBytes,statsPtr->currentByteCodeBytes),
8224            statsPtr->currentAuxBytes / numCurrentByteCodes);
8225    fprintf(stdout, "Command map       %12.6g   %8.1f%%   %8.1f\n",
8226            statsPtr->currentCmdMapBytes,
8227            Percent(statsPtr->currentCmdMapBytes,statsPtr->currentByteCodeBytes),
8228            statsPtr->currentCmdMapBytes / numCurrentByteCodes);
8229
8230    /*
8231     * Detailed literal statistics.
8232     */
8233
8234    fprintf(stdout, "\nLiteral string sizes:\n");
8235    fprintf(stdout, "    Up to length           Percentage\n");
8236    maxSizeDecade = 0;
8237    for (i = 31;  i >= 0;  i--) {
8238        if (statsPtr->literalCount[i] > 0) {
8239            maxSizeDecade = i;
8240            break;
8241        }
8242    }
8243    sum = 0;
8244    for (i = 0;  i <= maxSizeDecade;  i++) {
8245        decadeHigh = (1 << (i+1)) - 1;
8246        sum += statsPtr->literalCount[i];
8247        fprintf(stdout, "       %10d            %8.0f%%\n",
8248                decadeHigh, Percent(sum, statsPtr->numLiteralsCreated));
8249    }
8250
8251    litTableStats = TclLiteralStats(globalTablePtr);
8252    fprintf(stdout, "\nCurrent literal table statistics:\n%s\n",
8253            litTableStats);
8254    ckfree((char *) litTableStats);
8255
8256    /*
8257     * Source and ByteCode size distributions.
8258     */
8259
8260    fprintf(stdout, "\nSource sizes:\n");
8261    fprintf(stdout, "    Up to size             Percentage\n");
8262    minSizeDecade = maxSizeDecade = 0;
8263    for (i = 0;  i < 31;  i++) {
8264        if (statsPtr->srcCount[i] > 0) {
8265            minSizeDecade = i;
8266            break;
8267        }
8268    }
8269    for (i = 31;  i >= 0;  i--) {
8270        if (statsPtr->srcCount[i] > 0) {
8271            maxSizeDecade = i;
8272            break;
8273        }
8274    }
8275    sum = 0;
8276    for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
8277        decadeHigh = (1 << (i+1)) - 1;
8278        sum += statsPtr->srcCount[i];
8279        fprintf(stdout, "       %10d            %8.0f%%\n",
8280                decadeHigh, Percent(sum, statsPtr->numCompilations));
8281    }
8282
8283    fprintf(stdout, "\nByteCode sizes:\n");
8284    fprintf(stdout, "    Up to size             Percentage\n");
8285    minSizeDecade = maxSizeDecade = 0;
8286    for (i = 0;  i < 31;  i++) {
8287        if (statsPtr->byteCodeCount[i] > 0) {
8288            minSizeDecade = i;
8289            break;
8290        }
8291    }
8292    for (i = 31;  i >= 0;  i--) {
8293        if (statsPtr->byteCodeCount[i] > 0) {
8294            maxSizeDecade = i;
8295            break;
8296        }
8297    }
8298    sum = 0;
8299    for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
8300        decadeHigh = (1 << (i+1)) - 1;
8301        sum += statsPtr->byteCodeCount[i];
8302        fprintf(stdout, "       %10d            %8.0f%%\n",
8303                decadeHigh, Percent(sum, statsPtr->numCompilations));
8304    }
8305
8306    fprintf(stdout, "\nByteCode longevity (excludes Current ByteCodes):\n");
8307    fprintf(stdout, "          Up to ms         Percentage\n");
8308    minSizeDecade = maxSizeDecade = 0;
8309    for (i = 0;  i < 31;  i++) {
8310        if (statsPtr->lifetimeCount[i] > 0) {
8311            minSizeDecade = i;
8312            break;
8313        }
8314    }
8315    for (i = 31;  i >= 0;  i--) {
8316        if (statsPtr->lifetimeCount[i] > 0) {
8317            maxSizeDecade = i;
8318            break;
8319        }
8320    }
8321    sum = 0;
8322    for (i = minSizeDecade;  i <= maxSizeDecade;  i++) {
8323        decadeHigh = (1 << (i+1)) - 1;
8324        sum += statsPtr->lifetimeCount[i];
8325        fprintf(stdout, "       %12.3f          %8.0f%%\n",
8326                decadeHigh/1000.0, Percent(sum, statsPtr->numByteCodesFreed));
8327    }
8328
8329    /*
8330     * Instruction counts.
8331     */
8332
8333    fprintf(stdout, "\nInstruction counts:\n");
8334    for (i = 0;  i <= LAST_INST_OPCODE;  i++) {
8335        if (statsPtr->instructionCount[i] == 0) {
8336            fprintf(stdout, "%20s %8ld %6.1f%%\n",
8337                    tclInstructionTable[i].name,
8338                    statsPtr->instructionCount[i],
8339                    Percent(statsPtr->instructionCount[i], numInstructions));
8340        }
8341    }
8342
8343    fprintf(stdout, "\nInstructions NEVER executed:\n");
8344    for (i = 0;  i <= LAST_INST_OPCODE;  i++) {
8345        if (statsPtr->instructionCount[i] == 0) {
8346            fprintf(stdout, "%20s\n", tclInstructionTable[i].name);
8347        }
8348    }
8349
8350#ifdef TCL_MEM_DEBUG
8351    fprintf(stdout, "\nHeap Statistics:\n");
8352    TclDumpMemoryInfo(stdout);
8353#endif
8354    fprintf(stdout, "\n----------------------------------------------------------------\n");
8355    return TCL_OK;
8356}
8357#endif /* TCL_COMPILE_STATS */
8358
8359#ifdef TCL_COMPILE_DEBUG
8360/*
8361 *----------------------------------------------------------------------
8362 *
8363 * StringForResultCode --
8364 *
8365 *      Procedure that returns a human-readable string representing a Tcl
8366 *      result code such as TCL_ERROR.
8367 *
8368 * Results:
8369 *      If the result code is one of the standard Tcl return codes, the result
8370 *      is a string representing that code such as "TCL_ERROR". Otherwise, the
8371 *      result string is that code formatted as a sequence of decimal digit
8372 *      characters. Note that the resulting string must not be modified by the
8373 *      caller.
8374 *
8375 * Side effects:
8376 *      None.
8377 *
8378 *----------------------------------------------------------------------
8379 */
8380
8381static const char *
8382StringForResultCode(
8383    int result)                 /* The Tcl result code for which to generate a
8384                                 * string. */
8385{
8386    static char buf[TCL_INTEGER_SPACE];
8387
8388    if ((result >= TCL_OK) && (result <= TCL_CONTINUE)) {
8389        return resultStrings[result];
8390    }
8391    TclFormatInt(buf, result);
8392    return buf;
8393}
8394#endif /* TCL_COMPILE_DEBUG */
8395
8396/*
8397 * Local Variables:
8398 * mode: c
8399 * c-basic-offset: 4
8400 * fill-column: 78
8401 * End:
8402 */
Note: See TracBrowser for help on using the repository browser.