OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [generic/] [tclExecute.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclExecute.c --
3
 *
4
 *      This file contains procedures that execute byte-compiled Tcl
5
 *      commands.
6
 *
7
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
8
 *
9
 * See the file "license.terms" for information on usage and redistribution
10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
 *
12
 * RCS: @(#) $Id: tclExecute.c,v 1.1.1.1 2002-01-16 10:25:27 markom Exp $
13
 */
14
 
15
#include "tclInt.h"
16
#include "tclCompile.h"
17
 
18
#ifdef NO_FLOAT_H
19
#   include "../compat/float.h"
20
#else
21
#   include <float.h>
22
#endif
23
#ifndef TCL_NO_MATH
24
#include "tclMath.h"
25
#endif
26
 
27
/*
28
 * The stuff below is a bit of a hack so that this file can be used
29
 * in environments that include no UNIX, i.e. no errno.  Just define
30
 * errno here.
31
 */
32
 
33
#ifndef TCL_GENERIC_ONLY
34
#include "tclPort.h"
35
#else
36
#define NO_ERRNO_H
37
#endif
38
 
39
#ifdef NO_ERRNO_H
40
int errno;
41
#define EDOM 33
42
#define ERANGE 34
43
#endif
44
 
45
/*
46
 * Boolean flag indicating whether the Tcl bytecode interpreter has been
47
 * initialized.
48
 */
49
 
50
static int execInitialized = 0;
51
 
52
/*
53
 * Variable that controls whether execution tracing is enabled and, if so,
54
 * what level of tracing is desired:
55
 *    0: no execution tracing
56
 *    1: trace invocations of Tcl procs only
57
 *    2: trace invocations of all (not compiled away) commands
58
 *    3: display each instruction executed
59
 * This variable is linked to the Tcl variable "tcl_traceExec".
60
 */
61
 
62
int tclTraceExec = 0;
63
 
64
/*
65
 * The following global variable is use to signal matherr that Tcl
66
 * is responsible for the arithmetic, so errors can be handled in a
67
 * fashion appropriate for Tcl.  Zero means no Tcl math is in
68
 * progress;  non-zero means Tcl is doing math.
69
 */
70
 
71
int tcl_MathInProgress = 0;
72
 
73
/*
74
 * The variable below serves no useful purpose except to generate
75
 * a reference to matherr, so that the Tcl version of matherr is
76
 * linked in rather than the system version. Without this reference
77
 * the need for matherr won't be discovered during linking until after
78
 * libtcl.a has been processed, so Tcl's version won't be used.
79
 */
80
 
81
#ifdef NEED_MATHERR
82
extern int matherr();
83
int (*tclMatherrPtr)() = matherr;
84
#endif
85
 
86
/*
87
 * Array of instruction names.
88
 */
89
 
90
static char *opName[256];
91
 
92
/*
93
 * Mapping from expression instruction opcodes to strings; used for error
94
 * messages. Note that these entries must match the order and number of the
95
 * expression opcodes (e.g., INST_LOR) in tclCompile.h.
96
 */
97
 
98
static char *operatorStrings[] = {
99
    "||", "&&", "|", "^", "&", "==", "!=", "<", ">", "<=", ">=", "<<", ">>",
100
    "+", "-", "*", "/", "%", "+", "-", "~", "!",
101
    "BUILTIN FUNCTION", "FUNCTION"
102
};
103
 
104
/*
105
 * Mapping from Tcl result codes to strings; used for error and debugging
106
 * messages.
107
 */
108
 
109
#ifdef TCL_COMPILE_DEBUG
110
static char *resultStrings[] = {
111
    "TCL_OK", "TCL_ERROR", "TCL_RETURN", "TCL_BREAK", "TCL_CONTINUE"
112
};
113
#endif /* TCL_COMPILE_DEBUG */
114
 
115
/*
116
 * The following are statistics-related variables that record information
117
 * about the bytecode compiler and interpreter's operation. This includes
118
 * an array that records for each instruction how often it is executed.
119
 */
120
 
121
#ifdef TCL_COMPILE_STATS
122
static long numExecutions = 0;
123
static int instructionCount[256];
124
#endif /* TCL_COMPILE_STATS */
125
 
126
/*
127
 * Macros for testing floating-point values for certain special cases. Test
128
 * for not-a-number by comparing a value against itself; test for infinity
129
 * by comparing against the largest floating-point value.
130
 */
131
 
132
#define IS_NAN(v) ((v) != (v))
133
#ifdef DBL_MAX
134
#   define IS_INF(v) (((v) > DBL_MAX) || ((v) < -DBL_MAX))
135
#else
136
#   define IS_INF(v) 0
137
#endif
138
 
139
/*
140
 * Macro to adjust the program counter and restart the instruction execution
141
 * loop after each instruction is executed.
142
 */
143
 
144
#define ADJUST_PC(instBytes) \
145
    pc += instBytes;  continue
146
 
147
/*
148
 * Macros used to cache often-referenced Tcl evaluation stack information
149
 * in local variables. Note that a DECACHE_STACK_INFO()-CACHE_STACK_INFO()
150
 * pair must surround any call inside TclExecuteByteCode (and a few other
151
 * procedures that use this scheme) that could result in a recursive call
152
 * to TclExecuteByteCode.
153
 */
154
 
155
#define CACHE_STACK_INFO() \
156
    stackPtr = eePtr->stackPtr; \
157
    stackTop = eePtr->stackTop
158
 
159
#define DECACHE_STACK_INFO() \
160
    eePtr->stackTop = stackTop
161
 
162
/*
163
 * Macros used to access items on the Tcl evaluation stack. PUSH_OBJECT
164
 * increments the object's ref count since it makes the stack have another
165
 * reference pointing to the object. However, POP_OBJECT does not decrement
166
 * the ref count. This is because the stack may hold the only reference to
167
 * the object, so the object would be destroyed if its ref count were
168
 * decremented before the caller had a chance to, e.g., store it in a
169
 * variable. It is the caller's responsibility to decrement the ref count
170
 * when it is finished with an object.
171
 */
172
 
173
#define STK_ITEM(offset)    (stackPtr[stackTop + (offset)])
174
#define STK_OBJECT(offset)  (STK_ITEM(offset).o)
175
#define STK_INT(offset)     (STK_ITEM(offset).i)
176
#define STK_POINTER(offset) (STK_ITEM(offset).p)
177
 
178
/*
179
 * WARNING! It is essential that objPtr only appear once in the PUSH_OBJECT
180
 * macro. The actual parameter might be an expression with side effects,
181
 * and this ensures that it will be executed only once.
182
 */
183
 
184
#define PUSH_OBJECT(objPtr) \
185
    Tcl_IncrRefCount(stackPtr[++stackTop].o = (objPtr))
186
 
187
#define POP_OBJECT() \
188
    (stackPtr[stackTop--].o)
189
 
190
/*
191
 * Macros used to trace instruction execution. The macros TRACE,
192
 * TRACE_WITH_OBJ, and O2S are only used inside TclExecuteByteCode.
193
 * O2S is only used in TRACE* calls to get a string from an object.
194
 *
195
 * NOTE THAT CLIENTS OF O2S ARE LIKELY TO FAIL IF THE OBJECT'S
196
 * STRING REP CONTAINS NULLS.
197
 */
198
 
199
#ifdef TCL_COMPILE_DEBUG
200
 
201
#define O2S(objPtr) \
202
    Tcl_GetStringFromObj((objPtr), &length)
203
 
204
#ifdef TCL_COMPILE_STATS
205
#define TRACE(a) \
206
    if (traceInstructions) { \
207
        fprintf(stdout, "%d: %d,%ld (%u) ", iPtr->numLevels, \
208
               stackTop, (tclObjsAlloced - tclObjsFreed), \
209
               (unsigned int)(pc - codePtr->codeStart)); \
210
        printf a; \
211
        fflush(stdout); \
212
    }
213
#define TRACE_WITH_OBJ(a, objPtr) \
214
    if (traceInstructions) { \
215
        fprintf(stdout, "%d: %d,%ld (%u) ", iPtr->numLevels, \
216
               stackTop, (tclObjsAlloced - tclObjsFreed), \
217
               (unsigned int)(pc - codePtr->codeStart)); \
218
        printf a; \
219
        bytes = Tcl_GetStringFromObj((objPtr), &length); \
220
        TclPrintSource(stdout, bytes, TclMin(length, 30)); \
221
        fprintf(stdout, "\n"); \
222
        fflush(stdout); \
223
    }
224
#else  /* not TCL_COMPILE_STATS */
225
#define TRACE(a) \
226
    if (traceInstructions) { \
227
        fprintf(stdout, "%d: %d (%u) ", iPtr->numLevels, stackTop, \
228
               (unsigned int)(pc - codePtr->codeStart)); \
229
        printf a; \
230
        fflush(stdout); \
231
    }
232
#define TRACE_WITH_OBJ(a, objPtr) \
233
    if (traceInstructions) { \
234
        fprintf(stdout, "%d: %d (%u) ", iPtr->numLevels, stackTop, \
235
               (unsigned int)(pc - codePtr->codeStart)); \
236
        printf a; \
237
        bytes = Tcl_GetStringFromObj((objPtr), &length); \
238
        TclPrintSource(stdout, bytes, TclMin(length, 30)); \
239
        fprintf(stdout, "\n"); \
240
        fflush(stdout); \
241
    }
242
#endif /* TCL_COMPILE_STATS */
243
 
244
#else  /* not TCL_COMPILE_DEBUG */
245
 
246
#define TRACE(a)
247
#define TRACE_WITH_OBJ(a, objPtr)
248
#define O2S(objPtr)
249
 
250
#endif /* TCL_COMPILE_DEBUG */
251
 
252
/*
253
 * Declarations for local procedures to this file:
254
 */
255
 
256
static void             CallTraceProcedure _ANSI_ARGS_((Tcl_Interp *interp,
257
                            Trace *tracePtr, Command *cmdPtr,
258
                            char *command, int numChars,
259
                            int objc, Tcl_Obj *objv[]));
260
static void             DupCmdNameInternalRep _ANSI_ARGS_((Tcl_Obj *objPtr,
261
                            Tcl_Obj *copyPtr));
262
static int              ExprAbsFunc _ANSI_ARGS_((Tcl_Interp *interp,
263
                            ExecEnv *eePtr, ClientData clientData));
264
static int              ExprBinaryFunc _ANSI_ARGS_((Tcl_Interp *interp,
265
                            ExecEnv *eePtr, ClientData clientData));
266
static int              ExprCallMathFunc _ANSI_ARGS_((Tcl_Interp *interp,
267
                            ExecEnv *eePtr, int objc, Tcl_Obj **objv));
268
static int              ExprDoubleFunc _ANSI_ARGS_((Tcl_Interp *interp,
269
                            ExecEnv *eePtr, ClientData clientData));
270
static int              ExprIntFunc _ANSI_ARGS_((Tcl_Interp *interp,
271
                            ExecEnv *eePtr, ClientData clientData));
272
static int              ExprRandFunc _ANSI_ARGS_((Tcl_Interp *interp,
273
                            ExecEnv *eePtr, ClientData clientData));
274
static int              ExprRoundFunc _ANSI_ARGS_((Tcl_Interp *interp,
275
                            ExecEnv *eePtr, ClientData clientData));
276
static int              ExprSrandFunc _ANSI_ARGS_((Tcl_Interp *interp,
277
                            ExecEnv *eePtr, ClientData clientData));
278
static int              ExprUnaryFunc _ANSI_ARGS_((Tcl_Interp *interp,
279
                            ExecEnv *eePtr, ClientData clientData));
280
#ifdef TCL_COMPILE_STATS
281
static int              EvalStatsCmd _ANSI_ARGS_((ClientData clientData,
282
                            Tcl_Interp *interp, int argc, char **argv));
283
#endif /* TCL_COMPILE_STATS */
284
static void             FreeCmdNameInternalRep _ANSI_ARGS_((
285
                            Tcl_Obj *objPtr));
286
static char *           GetSrcInfoForPc _ANSI_ARGS_((unsigned char *pc,
287
                            ByteCode* codePtr, int *lengthPtr));
288
static void             GrowEvaluationStack _ANSI_ARGS_((ExecEnv *eePtr));
289
static void             IllegalExprOperandType _ANSI_ARGS_((
290
                            Tcl_Interp *interp, unsigned int opCode,
291
                            Tcl_Obj *opndPtr));
292
static void             InitByteCodeExecution _ANSI_ARGS_((
293
                            Tcl_Interp *interp));
294
static void             PrintByteCodeInfo _ANSI_ARGS_((ByteCode *codePtr));
295
static void             RecordTracebackInfo _ANSI_ARGS_((Tcl_Interp *interp,
296
                            unsigned char *pc, ByteCode *codePtr));
297
static int              SetCmdNameFromAny _ANSI_ARGS_((Tcl_Interp *interp,
298
                            Tcl_Obj *objPtr));
299
#ifdef TCL_COMPILE_DEBUG
300
static char *           StringForResultCode _ANSI_ARGS_((int result));
301
#endif /* TCL_COMPILE_DEBUG */
302
static void             UpdateStringOfCmdName _ANSI_ARGS_((Tcl_Obj *objPtr));
303
#ifdef TCL_COMPILE_DEBUG
304
static void             ValidatePcAndStackTop _ANSI_ARGS_((
305
                            ByteCode *codePtr, unsigned char *pc,
306
                            int stackTop, int stackLowerBound,
307
                            int stackUpperBound));
308
#endif /* TCL_COMPILE_DEBUG */
309
 
310
/*
311
 * Table describing the built-in math functions. Entries in this table are
312
 * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's
313
 * operand byte.
314
 */
315
 
316
BuiltinFunc builtinFuncTable[] = {
317
#ifndef TCL_NO_MATH
318
    {"acos", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) acos},
319
    {"asin", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) asin},
320
    {"atan", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) atan},
321
    {"atan2", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) atan2},
322
    {"ceil", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) ceil},
323
    {"cos", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) cos},
324
    {"cosh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) cosh},
325
    {"exp", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) exp},
326
    {"floor", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) floor},
327
    {"fmod", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) fmod},
328
    {"hypot", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) hypot},
329
    {"log", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) log},
330
    {"log10", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) log10},
331
    {"pow", 2, {TCL_DOUBLE, TCL_DOUBLE}, ExprBinaryFunc, (ClientData) pow},
332
    {"sin", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sin},
333
    {"sinh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sinh},
334
    {"sqrt", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) sqrt},
335
    {"tan", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) tan},
336
    {"tanh", 1, {TCL_DOUBLE}, ExprUnaryFunc, (ClientData) tanh},
337
#endif
338
    {"abs", 1, {TCL_EITHER}, ExprAbsFunc, 0},
339
    {"double", 1, {TCL_EITHER}, ExprDoubleFunc, 0},
340
    {"int", 1, {TCL_EITHER}, ExprIntFunc, 0},
341
    {"rand", 0, {TCL_EITHER}, ExprRandFunc, 0},   /* NOTE: rand takes no args. */
342
    {"round", 1, {TCL_EITHER}, ExprRoundFunc, 0},
343
    {"srand", 1, {TCL_INT}, ExprSrandFunc, 0},
344
    {0},
345
};
346
 
347
/*
348
 * The structure below defines the command name Tcl object type by means of
349
 * procedures that can be invoked by generic object code. Objects of this
350
 * type cache the Command pointer that results from looking up command names
351
 * in the command hashtable. Such objects appear as the zeroth ("command
352
 * name") argument in a Tcl command.
353
 */
354
 
355
Tcl_ObjType tclCmdNameType = {
356
    "cmdName",                          /* name */
357
    FreeCmdNameInternalRep,             /* freeIntRepProc */
358
    DupCmdNameInternalRep,              /* dupIntRepProc */
359
    UpdateStringOfCmdName,              /* updateStringProc */
360
    SetCmdNameFromAny                   /* setFromAnyProc */
361
};
362
 
363
/*
364
 *----------------------------------------------------------------------
365
 *
366
 * InitByteCodeExecution --
367
 *
368
 *      This procedure is called once to initialize the Tcl bytecode
369
 *      interpreter.
370
 *
371
 * Results:
372
 *      None.
373
 *
374
 * Side effects:
375
 *      This procedure initializes the array of instruction names. If
376
 *      compiling with the TCL_COMPILE_STATS flag, it initializes the
377
 *      array that counts the executions of each instruction and it
378
 *      creates the "evalstats" command. It also registers the command name
379
 *      Tcl_ObjType. It also establishes the link between the Tcl
380
 *      "tcl_traceExec" and C "tclTraceExec" variables.
381
 *
382
 *----------------------------------------------------------------------
383
 */
384
 
385
static void
386
InitByteCodeExecution(interp)
387
    Tcl_Interp *interp;         /* Interpreter for which the Tcl variable
388
                                 * "tcl_traceExec" is linked to control
389
                                 * instruction tracing. */
390
{
391
    int i;
392
 
393
    Tcl_RegisterObjType(&tclCmdNameType);
394
 
395
    (VOID *) memset(opName, 0, sizeof(opName));
396
    for (i = 0;  instructionTable[i].name != NULL;  i++) {
397
        opName[i] = instructionTable[i].name;
398
    }
399
 
400
#ifdef TCL_COMPILE_STATS    
401
    (VOID *) memset(instructionCount, 0, sizeof(instructionCount));
402
    (VOID *) memset(tclByteCodeCount, 0, sizeof(tclByteCodeCount));
403
    (VOID *) memset(tclSourceCount, 0, sizeof(tclSourceCount));
404
 
405
    Tcl_CreateCommand(interp, "evalstats", EvalStatsCmd,
406
                      (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
407
#endif /* TCL_COMPILE_STATS */
408
 
409
    if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec,
410
                    TCL_LINK_INT) != TCL_OK) {
411
        panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
412
    }
413
}
414
 
415
/*
416
 *----------------------------------------------------------------------
417
 *
418
 * TclCreateExecEnv --
419
 *
420
 *      This procedure creates a new execution environment for Tcl bytecode
421
 *      execution. An ExecEnv points to a Tcl evaluation stack. An ExecEnv
422
 *      is typically created once for each Tcl interpreter (Interp
423
 *      structure) and recursively passed to TclExecuteByteCode to execute
424
 *      ByteCode sequences for nested commands.
425
 *
426
 * Results:
427
 *      A newly allocated ExecEnv is returned. This points to an empty
428
 *      evaluation stack of the standard initial size.
429
 *
430
 * Side effects:
431
 *      The bytecode interpreter is also initialized here, as this
432
 *      procedure will be called before any call to TclExecuteByteCode.
433
 *
434
 *----------------------------------------------------------------------
435
 */
436
 
437
#define TCL_STACK_INITIAL_SIZE 2000
438
 
439
ExecEnv *
440
TclCreateExecEnv(interp)
441
    Tcl_Interp *interp;         /* Interpreter for which the execution
442
                                 * environment is being created. */
443
{
444
    ExecEnv *eePtr = (ExecEnv *) ckalloc(sizeof(ExecEnv));
445
 
446
    eePtr->stackPtr = (StackItem *)
447
        ckalloc((unsigned) (TCL_STACK_INITIAL_SIZE * sizeof(StackItem)));
448
    eePtr->stackTop = -1;
449
    eePtr->stackEnd = (TCL_STACK_INITIAL_SIZE - 1);
450
 
451
    if (!execInitialized) {
452
        TclInitAuxDataTypeTable();
453
        InitByteCodeExecution(interp);
454
        execInitialized = 1;
455
    }
456
 
457
    return eePtr;
458
}
459
#undef TCL_STACK_INITIAL_SIZE
460
 
461
/*
462
 *----------------------------------------------------------------------
463
 *
464
 * TclDeleteExecEnv --
465
 *
466
 *      Frees the storage for an ExecEnv.
467
 *
468
 * Results:
469
 *      None.
470
 *
471
 * Side effects:
472
 *      Storage for an ExecEnv and its contained storage (e.g. the
473
 *      evaluation stack) is freed.
474
 *
475
 *----------------------------------------------------------------------
476
 */
477
 
478
void
479
TclDeleteExecEnv(eePtr)
480
    ExecEnv *eePtr;             /* Execution environment to free. */
481
{
482
    ckfree((char *) eePtr->stackPtr);
483
    ckfree((char *) eePtr);
484
}
485
 
486
/*
487
 *----------------------------------------------------------------------
488
 *
489
 * TclFinalizeExecEnv --
490
 *
491
 *      Finalizes the execution environment setup so that it can be
492
 *      later reinitialized.
493
 *
494
 * Results:
495
 *      None.
496
 *
497
 * Side effects:
498
 *      After this call, the next time TclCreateExecEnv will be called
499
 *      it will call InitByteCodeExecution.
500
 *
501
 *----------------------------------------------------------------------
502
 */
503
 
504
void
505
TclFinalizeExecEnv()
506
{
507
    execInitialized = 0;
508
    TclFinalizeAuxDataTypeTable();
509
}
510
 
511
/*
512
 *----------------------------------------------------------------------
513
 *
514
 * GrowEvaluationStack --
515
 *
516
 *      This procedure grows a Tcl evaluation stack stored in an ExecEnv.
517
 *
518
 * Results:
519
 *      None.
520
 *
521
 * Side effects:
522
 *      The size of the evaluation stack is doubled.
523
 *
524
 *----------------------------------------------------------------------
525
 */
526
 
527
static void
528
GrowEvaluationStack(eePtr)
529
    register ExecEnv *eePtr; /* Points to the ExecEnv with an evaluation
530
                              * stack to enlarge. */
531
{
532
    /*
533
     * The current Tcl stack elements are stored from eePtr->stackPtr[0]
534
     * to eePtr->stackPtr[eePtr->stackEnd] (inclusive).
535
     */
536
 
537
    int currElems = (eePtr->stackEnd + 1);
538
    int newElems  = 2*currElems;
539
    int currBytes = currElems * sizeof(StackItem);
540
    int newBytes  = 2*currBytes;
541
    StackItem *newStackPtr = (StackItem *) ckalloc((unsigned) newBytes);
542
 
543
    /*
544
     * Copy the existing stack items to the new stack space, free the old
545
     * storage if appropriate, and mark new space as malloc'ed.
546
     */
547
 
548
    memcpy((VOID *) newStackPtr, (VOID *) eePtr->stackPtr,
549
           (size_t) currBytes);
550
    ckfree((char *) eePtr->stackPtr);
551
    eePtr->stackPtr = newStackPtr;
552
    eePtr->stackEnd = (newElems - 1); /* i.e. index of last usable item */
553
}
554
 
555
/*
556
 *----------------------------------------------------------------------
557
 *
558
 * TclExecuteByteCode --
559
 *
560
 *      This procedure executes the instructions of a ByteCode structure.
561
 *      It returns when a "done" instruction is executed or an error occurs.
562
 *
563
 * Results:
564
 *      The return value is one of the return codes defined in tcl.h
565
 *      (such as TCL_OK), and interp->objResultPtr refers to a Tcl object
566
 *      that either contains the result of executing the code or an
567
 *      error message.
568
 *
569
 * Side effects:
570
 *      Almost certainly, depending on the ByteCode's instructions.
571
 *
572
 *----------------------------------------------------------------------
573
 */
574
 
575
int
576
TclExecuteByteCode(interp, codePtr)
577
    Tcl_Interp *interp;         /* Token for command interpreter. */
578
    ByteCode *codePtr;          /* The bytecode sequence to interpret. */
579
{
580
    Interp *iPtr = (Interp *) interp;
581
    ExecEnv *eePtr = iPtr->execEnvPtr;
582
                                /* Points to the execution environment. */
583
    register StackItem *stackPtr = eePtr->stackPtr;
584
                                /* Cached evaluation stack base pointer. */
585
    register int stackTop = eePtr->stackTop;
586
                                /* Cached top index of evaluation stack. */
587
    Tcl_Obj **objArrayPtr = codePtr->objArrayPtr;
588
                                /* Points to the ByteCode's object array. */
589
    unsigned char *pc = codePtr->codeStart;
590
                                /* The current program counter. */
591
    unsigned char opCode;       /* The current instruction code. */
592
    int opnd;                   /* Current instruction's operand byte. */
593
    int pcAdjustment;           /* Hold pc adjustment after instruction. */
594
    int initStackTop = stackTop;/* Stack top at start of execution. */
595
    ExceptionRange *rangePtr;   /* Points to closest loop or catch exception
596
                                 * range enclosing the pc. Used by various
597
                                 * instructions and processCatch to
598
                                 * process break, continue, and errors. */
599
    int result = TCL_OK;        /* Return code returned after execution. */
600
    int traceInstructions = (tclTraceExec == 3);
601
    Tcl_Obj *valuePtr, *value2Ptr, *namePtr, *objPtr;
602
    char *bytes;
603
    int length;
604
    long i;
605
    Tcl_DString command;        /* Used for debugging. If tclTraceExec >= 2
606
                                 * holds a string representing the last
607
                                 * command invoked. */
608
 
609
    /*
610
     * This procedure uses a stack to hold information about catch commands.
611
     * This information is the current operand stack top when starting to
612
     * execute the code for each catch command. It starts out with stack-
613
     * allocated space but uses dynamically-allocated storage if needed.
614
     */
615
 
616
#define STATIC_CATCH_STACK_SIZE 5
617
    int (catchStackStorage[STATIC_CATCH_STACK_SIZE]);
618
    int *catchStackPtr = catchStackStorage;
619
    int catchTop = -1;
620
 
621
    /*
622
     * THIS PROC FAILS IF AN OBJECT'S STRING REP HAS A NULL BYTE.
623
     */
624
 
625
    if (tclTraceExec >= 2) {
626
        PrintByteCodeInfo(codePtr);
627
#ifdef TCL_COMPILE_STATS
628
        fprintf(stdout, "  Starting stack top=%d, system objects=%ld\n",
629
                eePtr->stackTop, (tclObjsAlloced - tclObjsFreed));
630
#else
631
        fprintf(stdout, "  Starting stack top=%d\n", eePtr->stackTop);
632
#endif /* TCL_COMPILE_STATS */
633
        fflush(stdout);
634
    }
635
 
636
#ifdef TCL_COMPILE_STATS
637
    numExecutions++;
638
#endif /* TCL_COMPILE_STATS */
639
 
640
    /*
641
     * Make sure the catch stack is large enough to hold the maximum number
642
     * of catch commands that could ever be executing at the same time. This
643
     * will be no more than the exception range array's depth.
644
     */
645
 
646
    if (codePtr->maxExcRangeDepth > STATIC_CATCH_STACK_SIZE) {
647
        catchStackPtr = (int *)
648
                ckalloc(codePtr->maxExcRangeDepth * sizeof(int));
649
    }
650
 
651
    /*
652
     * Make sure the stack has enough room to execute this ByteCode.
653
     */
654
 
655
    while ((stackTop + codePtr->maxStackDepth) > eePtr->stackEnd) {
656
        GrowEvaluationStack(eePtr);
657
        stackPtr = eePtr->stackPtr;
658
    }
659
 
660
    /*
661
     * Initialize the buffer that holds a string containing the name and
662
     * arguments for the last invoked command.
663
     */
664
 
665
    Tcl_DStringInit(&command);
666
 
667
    /*
668
     * Loop executing instructions until a "done" instruction, a TCL_RETURN,
669
     * or some error.
670
     */
671
 
672
    for (;;) {
673
#ifdef TCL_COMPILE_DEBUG
674
        ValidatePcAndStackTop(codePtr, pc, stackTop, initStackTop,
675
                eePtr->stackEnd);
676
#else /* not TCL_COMPILE_DEBUG */
677
        if (traceInstructions) {
678
#ifdef TCL_COMPILE_STATS
679
            fprintf(stdout, "%d: %d,%ld ", iPtr->numLevels, stackTop,
680
                    (tclObjsAlloced - tclObjsFreed));
681
#else /* TCL_COMPILE_STATS */
682
            fprintf(stdout, "%d: %d ", iPtr->numLevels, stackTop);
683
#endif /* TCL_COMPILE_STATS */
684
            TclPrintInstruction(codePtr, pc);
685
            fflush(stdout);
686
        }
687
#endif /* TCL_COMPILE_DEBUG */
688
 
689
        opCode = *pc;
690
#ifdef TCL_COMPILE_STATS    
691
        instructionCount[opCode]++;
692
#endif /* TCL_COMPILE_STATS */
693
 
694
        switch (opCode) {
695
        case INST_DONE:
696
            /*
697
             * Pop the topmost object from the stack, set the interpreter's
698
             * object result to point to it, and return.
699
             */
700
            valuePtr = POP_OBJECT();
701
            Tcl_SetObjResult(interp, valuePtr);
702
            TclDecrRefCount(valuePtr);
703
            if (stackTop != initStackTop) {
704
                fprintf(stderr, "\nTclExecuteByteCode: done instruction at pc %u: stack top %d != entry stack top %d\n",
705
                        (unsigned int)(pc - codePtr->codeStart),
706
                        (unsigned int) stackTop,
707
                        (unsigned int) initStackTop);
708
                fprintf(stderr, "  Source: ");
709
                TclPrintSource(stderr, codePtr->source, 150);
710
                panic("TclExecuteByteCode execution failure: end stack top != start stack top");
711
            }
712
            TRACE_WITH_OBJ(("done => return code=%d, result is ", result),
713
                    iPtr->objResultPtr);
714
            goto done;
715
 
716
        case INST_PUSH1:
717
            valuePtr = objArrayPtr[TclGetUInt1AtPtr(pc+1)];
718
            PUSH_OBJECT(valuePtr);
719
            TRACE_WITH_OBJ(("push1 %u => ", TclGetUInt1AtPtr(pc+1)),
720
                    valuePtr);
721
            ADJUST_PC(2);
722
 
723
        case INST_PUSH4:
724
            valuePtr = objArrayPtr[TclGetUInt4AtPtr(pc+1)];
725
            PUSH_OBJECT(valuePtr);
726
            TRACE_WITH_OBJ(("push4 %u => ", TclGetUInt4AtPtr(pc+1)),
727
                    valuePtr);
728
            ADJUST_PC(5);
729
 
730
        case INST_POP:
731
            valuePtr = POP_OBJECT();
732
            TRACE_WITH_OBJ(("pop => discarding "), valuePtr);
733
            TclDecrRefCount(valuePtr); /* finished with pop'ed object. */
734
            ADJUST_PC(1);
735
 
736
        case INST_DUP:
737
            valuePtr = stackPtr[stackTop].o;
738
            PUSH_OBJECT(Tcl_DuplicateObj(valuePtr));
739
            TRACE_WITH_OBJ(("dup => "), valuePtr);
740
            ADJUST_PC(1);
741
 
742
        case INST_CONCAT1:
743
            opnd = TclGetUInt1AtPtr(pc+1);
744
            {
745
                Tcl_Obj *concatObjPtr;
746
                int totalLen = 0;
747
 
748
                /*
749
                 * Concatenate strings (with no separators) from the top
750
                 * opnd items on the stack starting with the deepest item.
751
                 * First, determine how many characters are needed.
752
                 */
753
 
754
                for (i = (stackTop - (opnd-1));  i <= stackTop;  i++) {
755
                    valuePtr = stackPtr[i].o;
756
                    bytes = TclGetStringFromObj(valuePtr, &length);
757
                    if (bytes != NULL) {
758
                        totalLen += length;
759
                    }
760
                }
761
 
762
                /*
763
                 * Initialize the new append string object by appending the
764
                 * strings of the opnd stack objects. Also pop the objects.
765
                 */
766
 
767
                TclNewObj(concatObjPtr);
768
                if (totalLen > 0) {
769
                    char *p = (char *) ckalloc((unsigned) (totalLen + 1));
770
                    concatObjPtr->bytes = p;
771
                    concatObjPtr->length = totalLen;
772
                    for (i = (stackTop - (opnd-1));  i <= stackTop;  i++) {
773
                        valuePtr = stackPtr[i].o;
774
                        bytes = TclGetStringFromObj(valuePtr, &length);
775
                        if (bytes != NULL) {
776
                            memcpy((VOID *) p, (VOID *) bytes,
777
                                    (size_t) length);
778
                            p += length;
779
                        }
780
                        TclDecrRefCount(valuePtr);
781
                    }
782
                    *p = '\0';
783
                } else {
784
                    for (i = (stackTop - (opnd-1));  i <= stackTop;  i++) {
785
                        valuePtr = stackPtr[i].o;
786
                        Tcl_DecrRefCount(valuePtr);
787
                    }
788
                }
789
                stackTop -= opnd;
790
 
791
                PUSH_OBJECT(concatObjPtr);
792
                TRACE_WITH_OBJ(("concat %u => ", opnd), concatObjPtr);
793
                ADJUST_PC(2);
794
            }
795
 
796
        case INST_INVOKE_STK4:
797
            opnd = TclGetUInt4AtPtr(pc+1);
798
            pcAdjustment = 5;
799
            goto doInvocation;
800
 
801
        case INST_INVOKE_STK1:
802
            opnd = TclGetUInt1AtPtr(pc+1);
803
            pcAdjustment = 2;
804
 
805
            doInvocation:
806
            {
807
                char *cmdName;
808
                Command *cmdPtr;   /* Points to command's Command struct. */
809
                int objc = opnd;   /* The number of arguments. */
810
                Tcl_Obj **objv;    /* The array of argument objects. */
811
                Tcl_Obj *objv0Ptr; /* Holds objv[0], the command name. */
812
                int newPcOffset = 0;
813
                                   /* Instruction offset computed during
814
                                    * break, continue, error processing.
815
                                    * Init. to avoid compiler warning. */
816
                Tcl_Command cmd;
817
#ifdef TCL_COMPILE_DEBUG
818
                int isUnknownCmd = 0;
819
                char cmdNameBuf[30];
820
#endif /* TCL_COMPILE_DEBUG */
821
 
822
                /*
823
                 * If the interpreter was deleted, return an error.
824
                 */
825
 
826
                if (iPtr->flags & DELETED) {
827
                    Tcl_ResetResult(interp);
828
                    Tcl_AppendToObj(Tcl_GetObjResult(interp),
829
                            "attempt to call eval in deleted interpreter", -1);
830
                    Tcl_SetErrorCode(interp, "CORE", "IDELETE",
831
                            "attempt to call eval in deleted interpreter",
832
                            (char *) NULL);
833
                    result = TCL_ERROR;
834
                    goto checkForCatch;
835
                }
836
 
837
                objv = &(stackPtr[stackTop - (objc-1)].o);
838
                objv0Ptr = objv[0];
839
                cmdName = TclGetStringFromObj(objv0Ptr, (int *) NULL);
840
 
841
                /*
842
                 * Find the procedure to execute this command. If there
843
                 * isn't one, then see if there is a command "unknown". If
844
                 * so, invoke it, passing it the original command words as
845
                 * arguments.
846
                 *
847
                 * We convert the objv[0] object to be a CmdName object.
848
                 * This caches a pointer to the Command structure for the
849
                 * command; this pointer is held in a ResolvedCmdName
850
                 * structure the object's internal rep. points to.
851
                 */
852
 
853
                cmd = Tcl_GetCommandFromObj(interp, objv0Ptr);
854
                cmdPtr = (Command *) cmd;
855
 
856
                /*
857
                 * If the command is still not found, handle it with the
858
                 * "unknown" proc.
859
                 */
860
 
861
                if (cmdPtr == NULL) {
862
                    cmd = Tcl_FindCommand(interp, "unknown",
863
                            (Tcl_Namespace *) NULL, /*flags*/ TCL_GLOBAL_ONLY);
864
                    if (cmd == (Tcl_Command) NULL) {
865
                        Tcl_ResetResult(interp);
866
                        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
867
                                "invalid command name \"", cmdName, "\"",
868
                                (char *) NULL);
869
                        TRACE(("%s %u => unknown proc not found: ",
870
                               opName[opCode], objc));
871
                        result = TCL_ERROR;
872
                        goto checkForCatch;
873
                    }
874
                    cmdPtr = (Command *) cmd;
875
#ifdef TCL_COMPILE_DEBUG
876
                    isUnknownCmd = 1;
877
#endif /*TCL_COMPILE_DEBUG*/                    
878
                    stackTop++; /* need room for new inserted objv[0] */
879
                    for (i = objc;  i >= 0;  i--) {
880
                        objv[i+1] = objv[i];
881
                    }
882
                    objc++;
883
                    objv[0] = Tcl_NewStringObj("unknown", -1);
884
                    Tcl_IncrRefCount(objv[0]);
885
                }
886
 
887
                /*
888
                 * Call any trace procedures.
889
                 */
890
 
891
                if (iPtr->tracePtr != NULL) {
892
                    Trace *tracePtr, *nextTracePtr;
893
 
894
                    for (tracePtr = iPtr->tracePtr;  tracePtr != NULL;
895
                            tracePtr = nextTracePtr) {
896
                        nextTracePtr = tracePtr->nextPtr;
897
                        if (iPtr->numLevels <= tracePtr->level) {
898
                            int numChars;
899
                            char *cmd = GetSrcInfoForPc(pc, codePtr,
900
                                    &numChars);
901
                            if (cmd != NULL) {
902
                                DECACHE_STACK_INFO();
903
                                CallTraceProcedure(interp, tracePtr, cmdPtr,
904
                                        cmd, numChars, objc, objv);
905
                                CACHE_STACK_INFO();
906
                            }
907
                        }
908
                    }
909
                }
910
 
911
                /*
912
                 * Finally, invoke the command's Tcl_ObjCmdProc. First reset
913
                 * the interpreter's string and object results to their
914
                 * default empty values since they could have gotten changed
915
                 * by earlier invocations.
916
                 */
917
 
918
                Tcl_ResetResult(interp);
919
 
920
                if (tclTraceExec >= 2) {
921
                    char buffer[50];
922
 
923
                    sprintf(buffer, "%d: (%u) invoking ", iPtr->numLevels,
924
                            (unsigned int)(pc - codePtr->codeStart));
925
                    Tcl_DStringAppend(&command, buffer, -1);
926
 
927
#ifdef TCL_COMPILE_DEBUG
928
                    if (traceInstructions) { /* tclTraceExec == 3 */
929
                        strncpy(cmdNameBuf, cmdName, 20);
930
                        TRACE(("%s %u => call ", opName[opCode],
931
                               (isUnknownCmd? objc-1 : objc)));
932
                    } else {
933
                        fprintf(stdout, "%s", buffer);
934
                    }
935
#else /* TCL_COMPILE_DEBUG */
936
                    fprintf(stdout, "%s", buffer);
937
#endif /*TCL_COMPILE_DEBUG*/
938
 
939
                    for (i = 0;  i < objc;  i++) {
940
                        bytes = TclGetStringFromObj(objv[i], &length);
941
                        TclPrintSource(stdout, bytes, TclMin(length, 15));
942
                        fprintf(stdout, " ");
943
 
944
                        sprintf(buffer, "\"%.*s\" ", TclMin(length, 15), bytes);
945
                        Tcl_DStringAppend(&command, buffer, -1);
946
                    }
947
                    fprintf(stdout, "\n");
948
                    fflush(stdout);
949
 
950
                    Tcl_DStringFree(&command);
951
                }
952
 
953
                iPtr->cmdCount++;
954
                DECACHE_STACK_INFO();
955
                result = (*cmdPtr->objProc)(cmdPtr->objClientData, interp,
956
                                            objc, objv);
957
                if (Tcl_AsyncReady()) {
958
                    result = Tcl_AsyncInvoke(interp, result);
959
                }
960
                CACHE_STACK_INFO();
961
 
962
                /*
963
                 * If the interpreter has a non-empty string result, the
964
                 * result object is either empty or stale because some
965
                 * procedure set interp->result directly. If so, move the
966
                 * string result to the result object, then reset the
967
                 * string result.
968
                 */
969
 
970
                if (*(iPtr->result) != 0) {
971
                    (void) Tcl_GetObjResult(interp);
972
                }
973
 
974
                /*
975
                 * Pop the objc top stack elements and decrement their ref
976
                 * counts.
977
                 */
978
 
979
                i = (stackTop - (objc-1));
980
                while (i <= stackTop) {
981
                    valuePtr = stackPtr[i].o;
982
                    TclDecrRefCount(valuePtr);
983
                    i++;
984
                }
985
                stackTop -= objc;
986
 
987
                /*
988
                 * Process the result of the Tcl_ObjCmdProc call.
989
                 */
990
 
991
                switch (result) {
992
                case TCL_OK:
993
                    /*
994
                     * Push the call's object result and continue execution
995
                     * with the next instruction.
996
                     */
997
                    PUSH_OBJECT(Tcl_GetObjResult(interp));
998
                    TRACE_WITH_OBJ(("%s %u => ...after \"%.20s\", result=",
999
                            opName[opCode], objc, cmdNameBuf),
1000
                            Tcl_GetObjResult(interp));
1001
                    ADJUST_PC(pcAdjustment);
1002
 
1003
                case TCL_BREAK:
1004
                case TCL_CONTINUE:
1005
                    /*
1006
                     * The invoked command requested a break or continue.
1007
                     * Find the closest enclosing loop or catch exception
1008
                     * range, if any. If a loop is found, terminate its
1009
                     * execution or skip to its next iteration. If the
1010
                     * closest is a catch exception range, jump to its
1011
                     * catchOffset. If no enclosing range is found, stop
1012
                     * execution and return the TCL_BREAK or TCL_CONTINUE.
1013
                     */
1014
                    rangePtr = TclGetExceptionRangeForPc(pc,
1015
                            /*catchOnly*/ 0, codePtr);
1016
                    if (rangePtr == NULL) {
1017
                        TRACE(("%s %u => ... after \"%.20s\", no encl. loop or catch, returning %s\n",
1018
                                opName[opCode], objc, cmdNameBuf,
1019
                                StringForResultCode(result)));
1020
                        goto abnormalReturn; /* no catch exists to check */
1021
                    }
1022
                    switch (rangePtr->type) {
1023
                    case LOOP_EXCEPTION_RANGE:
1024
                        if (result == TCL_BREAK) {
1025
                            newPcOffset = rangePtr->breakOffset;
1026
                        } else if (rangePtr->continueOffset == -1) {
1027
                            TRACE(("%s %u => ... after \"%.20s\", %s, loop w/o continue, checking for catch\n",
1028
                                   opName[opCode], objc, cmdNameBuf,
1029
                                   StringForResultCode(result)));
1030
                            goto checkForCatch;
1031
                        } else {
1032
                            newPcOffset = rangePtr->continueOffset;
1033
                        }
1034
                        TRACE(("%s %u => ... after \"%.20s\", %s, range at %d, new pc %d\n",
1035
                               opName[opCode], objc, cmdNameBuf,
1036
                               StringForResultCode(result),
1037
                               rangePtr->codeOffset, newPcOffset));
1038
                        break;
1039
                    case CATCH_EXCEPTION_RANGE:
1040
                        TRACE(("%s %u => ... after \"%.20s\", %s...\n",
1041
                               opName[opCode], objc, cmdNameBuf,
1042
                               StringForResultCode(result)));
1043
                        goto processCatch; /* it will use rangePtr */
1044
                    default:
1045
                        panic("TclExecuteByteCode: unrecognized ExceptionRange type %d\n", rangePtr->type);
1046
                    }
1047
                    result = TCL_OK;
1048
                    pc = (codePtr->codeStart + newPcOffset);
1049
                    continue;   /* restart outer instruction loop at pc */
1050
 
1051
                case TCL_ERROR:
1052
                    /*
1053
                     * The invoked command returned an error. Look for an
1054
                     * enclosing catch exception range, if any.
1055
                     */
1056
                    TRACE_WITH_OBJ(("%s %u => ... after \"%.20s\", TCL_ERROR ",
1057
                            opName[opCode], objc, cmdNameBuf),
1058
                            Tcl_GetObjResult(interp));
1059
                    goto checkForCatch;
1060
 
1061
                case TCL_RETURN:
1062
                    /*
1063
                     * The invoked command requested that the current
1064
                     * procedure stop execution and return. First check
1065
                     * for an enclosing catch exception range, if any.
1066
                     */
1067
                    TRACE(("%s %u => ... after \"%.20s\", TCL_RETURN\n",
1068
                            opName[opCode], objc, cmdNameBuf));
1069
                    goto checkForCatch;
1070
 
1071
                default:
1072
                    TRACE_WITH_OBJ(("%s %u => ... after \"%.20s\", OTHER RETURN CODE %d ",
1073
                            opName[opCode], objc, cmdNameBuf, result),
1074
                            Tcl_GetObjResult(interp));
1075
                    goto checkForCatch;
1076
                } /* end of switch on result from invoke instruction */
1077
            }
1078
 
1079
        case INST_EVAL_STK:
1080
            objPtr = POP_OBJECT();
1081
            DECACHE_STACK_INFO();
1082
            result = Tcl_EvalObj(interp, objPtr);
1083
            CACHE_STACK_INFO();
1084
            if (result == TCL_OK) {
1085
                /*
1086
                 * Normal return; push the eval's object result.
1087
                 */
1088
 
1089
                PUSH_OBJECT(Tcl_GetObjResult(interp));
1090
                TRACE_WITH_OBJ(("evalStk \"%.30s\" => ", O2S(objPtr)),
1091
                        Tcl_GetObjResult(interp));
1092
                TclDecrRefCount(objPtr);
1093
                ADJUST_PC(1);
1094
            } else if ((result == TCL_BREAK) || (result == TCL_CONTINUE)) {
1095
                /*
1096
                 * Find the closest enclosing loop or catch exception range,
1097
                 * if any. If a loop is found, terminate its execution or
1098
                 * skip to its next iteration. If the closest is a catch
1099
                 * exception range, jump to its catchOffset. If no enclosing
1100
                 * range is found, stop execution and return that same
1101
                 * TCL_BREAK or TCL_CONTINUE.
1102
                 */
1103
 
1104
                int newPcOffset = 0; /* Pc offset computed during break,
1105
                                      * continue, error processing. Init.
1106
                                      * to avoid compiler warning. */
1107
 
1108
                rangePtr = TclGetExceptionRangeForPc(pc, /*catchOnly*/ 0,
1109
                        codePtr);
1110
                if (rangePtr == NULL) {
1111
                    TRACE(("evalStk \"%.30s\" => no encl. loop or catch, returning %s\n",
1112
                            O2S(objPtr), StringForResultCode(result)));
1113
                    Tcl_DecrRefCount(objPtr);
1114
                    goto abnormalReturn;    /* no catch exists to check */
1115
                }
1116
                switch (rangePtr->type) {
1117
                case LOOP_EXCEPTION_RANGE:
1118
                    if (result == TCL_BREAK) {
1119
                        newPcOffset = rangePtr->breakOffset;
1120
                    } else if (rangePtr->continueOffset == -1) {
1121
                        TRACE(("evalStk \"%.30s\" => %s, loop w/o continue, checking for catch\n",
1122
                               O2S(objPtr), StringForResultCode(result)));
1123
                        Tcl_DecrRefCount(objPtr);
1124
                        goto checkForCatch;
1125
                    } else {
1126
                        newPcOffset = rangePtr->continueOffset;
1127
                    }
1128
                    result = TCL_OK;
1129
                    TRACE_WITH_OBJ(("evalStk \"%.30s\" => %s, range at %d, new pc %d ",
1130
                            O2S(objPtr), StringForResultCode(result),
1131
                            rangePtr->codeOffset, newPcOffset), valuePtr);
1132
                    break;
1133
                case CATCH_EXCEPTION_RANGE:
1134
                    TRACE_WITH_OBJ(("evalStk \"%.30s\" => %s ",
1135
                            O2S(objPtr), StringForResultCode(result)),
1136
                            valuePtr);
1137
                    Tcl_DecrRefCount(objPtr);
1138
                    goto processCatch;  /* it will use rangePtr */
1139
                default:
1140
                    panic("TclExecuteByteCode: unrecognized ExceptionRange type %d\n", rangePtr->type);
1141
                }
1142
                Tcl_DecrRefCount(objPtr);
1143
                pc = (codePtr->codeStart + newPcOffset);
1144
                continue;       /* restart outer instruction loop at pc */
1145
            } else { /* eval returned TCL_ERROR, TCL_RETURN, unknown code */
1146
                TRACE_WITH_OBJ(("evalStk \"%.30s\" => ERROR: ", O2S(objPtr)),
1147
                        Tcl_GetObjResult(interp));
1148
                Tcl_DecrRefCount(objPtr);
1149
                goto checkForCatch;
1150
            }
1151
 
1152
        case INST_EXPR_STK:
1153
            objPtr = POP_OBJECT();
1154
            Tcl_ResetResult(interp);
1155
            DECACHE_STACK_INFO();
1156
            result = Tcl_ExprObj(interp, objPtr, &valuePtr);
1157
            CACHE_STACK_INFO();
1158
            if (result != TCL_OK) {
1159
                TRACE_WITH_OBJ(("exprStk \"%.30s\" => ERROR: ",
1160
                        O2S(objPtr)), Tcl_GetObjResult(interp));
1161
                Tcl_DecrRefCount(objPtr);
1162
                goto checkForCatch;
1163
            }
1164
            stackPtr[++stackTop].o = valuePtr; /* already has right refct */
1165
            TRACE_WITH_OBJ(("exprStk \"%.30s\" => ", O2S(objPtr)), valuePtr);
1166
            TclDecrRefCount(objPtr);
1167
            ADJUST_PC(1);
1168
 
1169
        case INST_LOAD_SCALAR4:
1170
            opnd = TclGetInt4AtPtr(pc+1);
1171
            pcAdjustment = 5;
1172
            goto doLoadScalar;
1173
 
1174
        case INST_LOAD_SCALAR1:
1175
            opnd = TclGetUInt1AtPtr(pc+1);
1176
            pcAdjustment = 2;
1177
 
1178
            doLoadScalar:
1179
            DECACHE_STACK_INFO();
1180
            valuePtr = TclGetIndexedScalar(interp, opnd,
1181
                                           /*leaveErrorMsg*/ 1);
1182
            CACHE_STACK_INFO();
1183
            if (valuePtr == NULL) {
1184
                TRACE_WITH_OBJ(("%s %u => ERROR: ", opName[opCode], opnd),
1185
                        Tcl_GetObjResult(interp));
1186
                result = TCL_ERROR;
1187
                goto checkForCatch;
1188
            }
1189
            PUSH_OBJECT(valuePtr);
1190
            TRACE_WITH_OBJ(("%s %u => ", opName[opCode], opnd), valuePtr);
1191
            ADJUST_PC(pcAdjustment);
1192
 
1193
        case INST_LOAD_SCALAR_STK:
1194
            namePtr = POP_OBJECT();
1195
            DECACHE_STACK_INFO();
1196
            valuePtr = Tcl_ObjGetVar2(interp, namePtr, (Tcl_Obj *) NULL,
1197
                                      TCL_LEAVE_ERR_MSG);
1198
            CACHE_STACK_INFO();
1199
            if (valuePtr == NULL) {
1200
                TRACE_WITH_OBJ(("loadScalarStk \"%.30s\" => ERROR: ",
1201
                        O2S(namePtr)), Tcl_GetObjResult(interp));
1202
                Tcl_DecrRefCount(namePtr);
1203
                result = TCL_ERROR;
1204
                goto checkForCatch;
1205
            }
1206
            PUSH_OBJECT(valuePtr);
1207
            TRACE_WITH_OBJ(("loadScalarStk \"%.30s\" => ",
1208
                    O2S(namePtr)), valuePtr);
1209
            TclDecrRefCount(namePtr);
1210
            ADJUST_PC(1);
1211
 
1212
        case INST_LOAD_ARRAY4:
1213
            opnd = TclGetUInt4AtPtr(pc+1);
1214
            pcAdjustment = 5;
1215
            goto doLoadArray;
1216
 
1217
        case INST_LOAD_ARRAY1:
1218
            opnd = TclGetUInt1AtPtr(pc+1);
1219
            pcAdjustment = 2;
1220
 
1221
            doLoadArray:
1222
            {
1223
                Tcl_Obj *elemPtr = POP_OBJECT();
1224
 
1225
                DECACHE_STACK_INFO();
1226
                valuePtr = TclGetElementOfIndexedArray(interp, opnd,
1227
                        elemPtr, /*leaveErrorMsg*/ 1);
1228
                CACHE_STACK_INFO();
1229
                if (valuePtr == NULL) {
1230
                    TRACE_WITH_OBJ(("%s %u \"%.30s\" => ERROR: ",
1231
                            opName[opCode], opnd, O2S(elemPtr)),
1232
                            Tcl_GetObjResult(interp));
1233
                    Tcl_DecrRefCount(elemPtr);
1234
                    result = TCL_ERROR;
1235
                    goto checkForCatch;
1236
                }
1237
                PUSH_OBJECT(valuePtr);
1238
                TRACE_WITH_OBJ(("%s %u \"%.30s\" => ",
1239
                        opName[opCode], opnd, O2S(elemPtr)), valuePtr);
1240
                TclDecrRefCount(elemPtr);
1241
            }
1242
            ADJUST_PC(pcAdjustment);
1243
 
1244
        case INST_LOAD_ARRAY_STK:
1245
            {
1246
                Tcl_Obj *elemPtr = POP_OBJECT();
1247
 
1248
                namePtr = POP_OBJECT();
1249
                DECACHE_STACK_INFO();
1250
                valuePtr = Tcl_ObjGetVar2(interp, namePtr, elemPtr,
1251
                        TCL_LEAVE_ERR_MSG);
1252
                CACHE_STACK_INFO();
1253
                if (valuePtr == NULL) {
1254
                    TRACE_WITH_OBJ(("loadArrayStk \"%.30s(%.30s)\" => ERROR: ",
1255
                            O2S(namePtr), O2S(elemPtr)),
1256
                            Tcl_GetObjResult(interp));
1257
                    Tcl_DecrRefCount(namePtr);
1258
                    Tcl_DecrRefCount(elemPtr);
1259
                    result = TCL_ERROR;
1260
                    goto checkForCatch;
1261
                }
1262
                PUSH_OBJECT(valuePtr);
1263
                TRACE_WITH_OBJ(("loadArrayStk \"%.30s(%.30s)\" => ",
1264
                        O2S(namePtr), O2S(elemPtr)), valuePtr);
1265
                TclDecrRefCount(namePtr);
1266
                TclDecrRefCount(elemPtr);
1267
            }
1268
            ADJUST_PC(1);
1269
 
1270
        case INST_LOAD_STK:
1271
            namePtr = POP_OBJECT();
1272
            DECACHE_STACK_INFO();
1273
            valuePtr = Tcl_ObjGetVar2(interp, namePtr, NULL,
1274
                    TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG);
1275
            CACHE_STACK_INFO();
1276
            if (valuePtr == NULL) {
1277
                TRACE_WITH_OBJ(("loadStk \"%.30s\" => ERROR: ",
1278
                        O2S(namePtr)), Tcl_GetObjResult(interp));
1279
                Tcl_DecrRefCount(namePtr);
1280
                result = TCL_ERROR;
1281
                goto checkForCatch;
1282
            }
1283
            PUSH_OBJECT(valuePtr);
1284
            TRACE_WITH_OBJ(("loadStk \"%.30s\" => ", O2S(namePtr)),
1285
                    valuePtr);
1286
            TclDecrRefCount(namePtr);
1287
            ADJUST_PC(1);
1288
 
1289
        case INST_STORE_SCALAR4:
1290
            opnd = TclGetUInt4AtPtr(pc+1);
1291
            pcAdjustment = 5;
1292
            goto doStoreScalar;
1293
 
1294
        case INST_STORE_SCALAR1:
1295
            opnd = TclGetUInt1AtPtr(pc+1);
1296
            pcAdjustment = 2;
1297
 
1298
          doStoreScalar:
1299
            valuePtr = POP_OBJECT();
1300
            DECACHE_STACK_INFO();
1301
            value2Ptr = TclSetIndexedScalar(interp, opnd, valuePtr,
1302
                                              /*leaveErrorMsg*/ 1);
1303
            CACHE_STACK_INFO();
1304
            if (value2Ptr == NULL) {
1305
                TRACE_WITH_OBJ(("%s %u <- \"%.30s\" => ERROR: ",
1306
                        opName[opCode], opnd, O2S(valuePtr)),
1307
                        Tcl_GetObjResult(interp));
1308
                Tcl_DecrRefCount(valuePtr);
1309
                result = TCL_ERROR;
1310
                goto checkForCatch;
1311
            }
1312
            PUSH_OBJECT(value2Ptr);
1313
            TRACE_WITH_OBJ(("%s %u <- \"%.30s\" => ",
1314
                    opName[opCode], opnd, O2S(valuePtr)), value2Ptr);
1315
            TclDecrRefCount(valuePtr);
1316
            ADJUST_PC(pcAdjustment);
1317
 
1318
        case INST_STORE_SCALAR_STK:
1319
            valuePtr = POP_OBJECT();
1320
            namePtr = POP_OBJECT();
1321
            DECACHE_STACK_INFO();
1322
            value2Ptr = Tcl_ObjSetVar2(interp, namePtr, NULL, valuePtr,
1323
                    TCL_LEAVE_ERR_MSG);
1324
            CACHE_STACK_INFO();
1325
            if (value2Ptr == NULL) {
1326
                TRACE_WITH_OBJ(
1327
                        ("storeScalarStk \"%.30s\" <- \"%.30s\" => ERROR: ",
1328
                        O2S(namePtr), O2S(valuePtr)),
1329
                        Tcl_GetObjResult(interp));
1330
                Tcl_DecrRefCount(namePtr);
1331
                Tcl_DecrRefCount(valuePtr);
1332
                result = TCL_ERROR;
1333
                goto checkForCatch;
1334
            }
1335
            PUSH_OBJECT(value2Ptr);
1336
            TRACE_WITH_OBJ(
1337
                    ("storeScalarStk \"%.30s\" <- \"%.30s\" => ",
1338
                    O2S(namePtr),
1339
                    O2S(valuePtr)),
1340
                    value2Ptr);
1341
            TclDecrRefCount(namePtr);
1342
            TclDecrRefCount(valuePtr);
1343
            ADJUST_PC(1);
1344
 
1345
        case INST_STORE_ARRAY4:
1346
            opnd = TclGetUInt4AtPtr(pc+1);
1347
            pcAdjustment = 5;
1348
            goto doStoreArray;
1349
 
1350
        case INST_STORE_ARRAY1:
1351
            opnd = TclGetUInt1AtPtr(pc+1);
1352
            pcAdjustment = 2;
1353
 
1354
            doStoreArray:
1355
            {
1356
                Tcl_Obj *elemPtr;
1357
 
1358
                valuePtr = POP_OBJECT();
1359
                elemPtr = POP_OBJECT();
1360
                DECACHE_STACK_INFO();
1361
                value2Ptr = TclSetElementOfIndexedArray(interp, opnd,
1362
                        elemPtr, valuePtr, TCL_LEAVE_ERR_MSG);
1363
                CACHE_STACK_INFO();
1364
                if (value2Ptr == NULL) {
1365
                    TRACE_WITH_OBJ(
1366
                            ("%s %u \"%.30s\" <- \"%.30s\" => ERROR: ",
1367
                            opName[opCode], opnd, O2S(elemPtr),
1368
                            O2S(valuePtr)), Tcl_GetObjResult(interp));
1369
                    Tcl_DecrRefCount(elemPtr);
1370
                    Tcl_DecrRefCount(valuePtr);
1371
                    result = TCL_ERROR;
1372
                    goto checkForCatch;
1373
                }
1374
                PUSH_OBJECT(value2Ptr);
1375
                TRACE_WITH_OBJ(("%s %u \"%.30s\" <- \"%.30s\" => ",
1376
                        opName[opCode], opnd, O2S(elemPtr), O2S(valuePtr)),
1377
                        value2Ptr);
1378
                TclDecrRefCount(elemPtr);
1379
                TclDecrRefCount(valuePtr);
1380
            }
1381
            ADJUST_PC(pcAdjustment);
1382
 
1383
        case INST_STORE_ARRAY_STK:
1384
            {
1385
                Tcl_Obj *elemPtr;
1386
 
1387
                valuePtr = POP_OBJECT();
1388
                elemPtr = POP_OBJECT();
1389
                namePtr = POP_OBJECT();
1390
                DECACHE_STACK_INFO();
1391
                value2Ptr = Tcl_ObjSetVar2(interp, namePtr, elemPtr,
1392
                        valuePtr, TCL_LEAVE_ERR_MSG);
1393
                CACHE_STACK_INFO();
1394
                if (value2Ptr == NULL) {
1395
                    TRACE_WITH_OBJ(("storeArrayStk \"%.30s(%.30s)\" <- \"%.30s\" => ERROR: ",
1396
                            O2S(namePtr), O2S(elemPtr), O2S(valuePtr)),
1397
                            Tcl_GetObjResult(interp));
1398
                    Tcl_DecrRefCount(namePtr);
1399
                    Tcl_DecrRefCount(elemPtr);
1400
                    Tcl_DecrRefCount(valuePtr);
1401
                    result = TCL_ERROR;
1402
                    goto checkForCatch;
1403
                }
1404
                PUSH_OBJECT(value2Ptr);
1405
                TRACE_WITH_OBJ(("storeArrayStk \"%.30s(%.30s)\" <- \"%.30s\" => ",
1406
                        O2S(namePtr), O2S(elemPtr), O2S(valuePtr)),
1407
                        value2Ptr);
1408
                TclDecrRefCount(namePtr);
1409
                TclDecrRefCount(elemPtr);
1410
                TclDecrRefCount(valuePtr);
1411
            }
1412
            ADJUST_PC(1);
1413
 
1414
        case INST_STORE_STK:
1415
            valuePtr = POP_OBJECT();
1416
            namePtr = POP_OBJECT();
1417
            DECACHE_STACK_INFO();
1418
            value2Ptr = Tcl_ObjSetVar2(interp, namePtr, NULL, valuePtr,
1419
                    TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG);
1420
            CACHE_STACK_INFO();
1421
            if (value2Ptr == NULL) {
1422
                TRACE_WITH_OBJ(("storeStk \"%.30s\" <- \"%.30s\" => ERROR: ",
1423
                        O2S(namePtr), O2S(valuePtr)),
1424
                        Tcl_GetObjResult(interp));
1425
                Tcl_DecrRefCount(namePtr);
1426
                Tcl_DecrRefCount(valuePtr);
1427
                result = TCL_ERROR;
1428
                goto checkForCatch;
1429
            }
1430
            PUSH_OBJECT(value2Ptr);
1431
            TRACE_WITH_OBJ(("storeStk \"%.30s\" <- \"%.30s\" => ",
1432
                    O2S(namePtr), O2S(valuePtr)), value2Ptr);
1433
            TclDecrRefCount(namePtr);
1434
            TclDecrRefCount(valuePtr);
1435
            ADJUST_PC(1);
1436
 
1437
        case INST_INCR_SCALAR1:
1438
            opnd = TclGetUInt1AtPtr(pc+1);
1439
            valuePtr = POP_OBJECT();
1440
            if (valuePtr->typePtr != &tclIntType) {
1441
                result = tclIntType.setFromAnyProc(interp, valuePtr);
1442
                if (result != TCL_OK) {
1443
                    TRACE_WITH_OBJ(("incrScalar1 %u (by %s) => ERROR converting increment amount to int: ",
1444
                            opnd, O2S(valuePtr)), Tcl_GetObjResult(interp));
1445
                    Tcl_DecrRefCount(valuePtr);
1446
                    goto checkForCatch;
1447
                }
1448
            }
1449
            i = valuePtr->internalRep.longValue;
1450
            DECACHE_STACK_INFO();
1451
            value2Ptr = TclIncrIndexedScalar(interp, opnd, i);
1452
            CACHE_STACK_INFO();
1453
            if (value2Ptr == NULL) {
1454
                TRACE_WITH_OBJ(("incrScalar1 %u (by %ld) => ERROR: ",
1455
                        opnd, i), Tcl_GetObjResult(interp));
1456
                Tcl_DecrRefCount(valuePtr);
1457
                result = TCL_ERROR;
1458
                goto checkForCatch;
1459
            }
1460
            PUSH_OBJECT(value2Ptr);
1461
            TRACE_WITH_OBJ(("incrScalar1 %u (by %ld) => ", opnd, i),
1462
                    value2Ptr);
1463
            TclDecrRefCount(valuePtr);
1464
            ADJUST_PC(2);
1465
 
1466
        case INST_INCR_SCALAR_STK:
1467
        case INST_INCR_STK:
1468
            valuePtr = POP_OBJECT();
1469
            namePtr = POP_OBJECT();
1470
            if (valuePtr->typePtr != &tclIntType) {
1471
                result = tclIntType.setFromAnyProc(interp, valuePtr);
1472
                if (result != TCL_OK) {
1473
                    TRACE_WITH_OBJ(("%s \"%.30s\" (by %s) => ERROR converting increment amount to int: ",
1474
                            opName[opCode], O2S(namePtr), O2S(valuePtr)),
1475
                            Tcl_GetObjResult(interp));
1476
                    Tcl_DecrRefCount(namePtr);
1477
                    Tcl_DecrRefCount(valuePtr);
1478
                    goto checkForCatch;
1479
                }
1480
            }
1481
            i = valuePtr->internalRep.longValue;
1482
            DECACHE_STACK_INFO();
1483
            value2Ptr = TclIncrVar2(interp, namePtr, (Tcl_Obj *) NULL, i,
1484
                /*part1NotParsed*/ (opCode == INST_INCR_STK));
1485
            CACHE_STACK_INFO();
1486
            if (value2Ptr == NULL) {
1487
                TRACE_WITH_OBJ(("%s \"%.30s\" (by %ld) => ERROR: ",
1488
                        opName[opCode], O2S(namePtr), i),
1489
                        Tcl_GetObjResult(interp));
1490
                Tcl_DecrRefCount(namePtr);
1491
                Tcl_DecrRefCount(valuePtr);
1492
                result = TCL_ERROR;
1493
                goto checkForCatch;
1494
            }
1495
            PUSH_OBJECT(value2Ptr);
1496
            TRACE_WITH_OBJ(("%s \"%.30s\" (by %ld) => ",
1497
                    opName[opCode], O2S(namePtr), i), value2Ptr);
1498
            Tcl_DecrRefCount(namePtr);
1499
            Tcl_DecrRefCount(valuePtr);
1500
            ADJUST_PC(1);
1501
 
1502
        case INST_INCR_ARRAY1:
1503
            {
1504
                Tcl_Obj *elemPtr;
1505
 
1506
                opnd = TclGetUInt1AtPtr(pc+1);
1507
                valuePtr = POP_OBJECT();
1508
                elemPtr = POP_OBJECT();
1509
                if (valuePtr->typePtr != &tclIntType) {
1510
                    result = tclIntType.setFromAnyProc(interp, valuePtr);
1511
                    if (result != TCL_OK) {
1512
                        TRACE_WITH_OBJ(("incrArray1 %u \"%.30s\" (by %s) => ERROR converting increment amount to int: ",
1513
                                opnd, O2S(elemPtr), O2S(valuePtr)),
1514
                                Tcl_GetObjResult(interp));
1515
                        Tcl_DecrRefCount(elemPtr);
1516
                        Tcl_DecrRefCount(valuePtr);
1517
                        goto checkForCatch;
1518
                    }
1519
                }
1520
                i = valuePtr->internalRep.longValue;
1521
                DECACHE_STACK_INFO();
1522
                value2Ptr = TclIncrElementOfIndexedArray(interp, opnd,
1523
                        elemPtr, i);
1524
                CACHE_STACK_INFO();
1525
                if (value2Ptr == NULL) {
1526
                    TRACE_WITH_OBJ(("incrArray1 %u \"%.30s\" (by %ld) => ERROR: ",
1527
                            opnd, O2S(elemPtr), i),
1528
                            Tcl_GetObjResult(interp));
1529
                    Tcl_DecrRefCount(elemPtr);
1530
                    Tcl_DecrRefCount(valuePtr);
1531
                    result = TCL_ERROR;
1532
                    goto checkForCatch;
1533
                }
1534
                PUSH_OBJECT(value2Ptr);
1535
                TRACE_WITH_OBJ(("incrArray1 %u \"%.30s\" (by %ld) => ",
1536
                        opnd, O2S(elemPtr), i), value2Ptr);
1537
                Tcl_DecrRefCount(elemPtr);
1538
                Tcl_DecrRefCount(valuePtr);
1539
            }
1540
            ADJUST_PC(2);
1541
 
1542
        case INST_INCR_ARRAY_STK:
1543
            {
1544
                Tcl_Obj *elemPtr;
1545
 
1546
                valuePtr = POP_OBJECT();
1547
                elemPtr = POP_OBJECT();
1548
                namePtr = POP_OBJECT();
1549
                if (valuePtr->typePtr != &tclIntType) {
1550
                    result = tclIntType.setFromAnyProc(interp, valuePtr);
1551
                    if (result != TCL_OK) {
1552
                        TRACE_WITH_OBJ(("incrArrayStk \"%.30s(%.30s)\" (by %s) => ERROR converting increment amount to int: ",
1553
                                O2S(namePtr), O2S(elemPtr), O2S(valuePtr)),
1554
                                Tcl_GetObjResult(interp));
1555
                        Tcl_DecrRefCount(namePtr);
1556
                        Tcl_DecrRefCount(elemPtr);
1557
                        Tcl_DecrRefCount(valuePtr);
1558
                        goto checkForCatch;
1559
                    }
1560
                }
1561
                i = valuePtr->internalRep.longValue;
1562
                DECACHE_STACK_INFO();
1563
                value2Ptr = TclIncrVar2(interp, namePtr, elemPtr, i,
1564
                                        /*part1NotParsed*/ 0);
1565
                CACHE_STACK_INFO();
1566
                if (value2Ptr == NULL) {
1567
                    TRACE_WITH_OBJ(("incrArrayStk \"%.30s(%.30s)\" (by %ld) => ERROR: ",
1568
                            O2S(namePtr), O2S(elemPtr), i),
1569
                            Tcl_GetObjResult(interp));
1570
                    Tcl_DecrRefCount(namePtr);
1571
                    Tcl_DecrRefCount(elemPtr);
1572
                    Tcl_DecrRefCount(valuePtr);
1573
                    result = TCL_ERROR;
1574
                    goto checkForCatch;
1575
                }
1576
                PUSH_OBJECT(value2Ptr);
1577
                TRACE_WITH_OBJ(("incrArrayStk \"%.30s(%.30s)\" (by %ld) => ",
1578
                        O2S(namePtr), O2S(elemPtr), i), value2Ptr);
1579
                Tcl_DecrRefCount(namePtr);
1580
                Tcl_DecrRefCount(elemPtr);
1581
                Tcl_DecrRefCount(valuePtr);
1582
            }
1583
            ADJUST_PC(1);
1584
 
1585
        case INST_INCR_SCALAR1_IMM:
1586
            opnd = TclGetUInt1AtPtr(pc+1);
1587
            i = TclGetInt1AtPtr(pc+2);
1588
            DECACHE_STACK_INFO();
1589
            value2Ptr = TclIncrIndexedScalar(interp, opnd, i);
1590
            CACHE_STACK_INFO();
1591
            if (value2Ptr == NULL) {
1592
                TRACE_WITH_OBJ(("incrScalar1Imm %u %ld => ERROR: ",
1593
                        opnd, i), Tcl_GetObjResult(interp));
1594
                result = TCL_ERROR;
1595
                goto checkForCatch;
1596
            }
1597
            PUSH_OBJECT(value2Ptr);
1598
            TRACE_WITH_OBJ(("incrScalar1Imm %u %ld => ", opnd, i),
1599
                    value2Ptr);
1600
            ADJUST_PC(3);
1601
 
1602
        case INST_INCR_SCALAR_STK_IMM:
1603
        case INST_INCR_STK_IMM:
1604
            namePtr = POP_OBJECT();
1605
            i = TclGetInt1AtPtr(pc+1);
1606
            DECACHE_STACK_INFO();
1607
            value2Ptr = TclIncrVar2(interp, namePtr, (Tcl_Obj *) NULL, i,
1608
                    /*part1NotParsed*/ (opCode == INST_INCR_STK_IMM));
1609
            CACHE_STACK_INFO();
1610
            if (value2Ptr == NULL) {
1611
                TRACE_WITH_OBJ(("%s \"%.30s\" %ld => ERROR: ",
1612
                        opName[opCode], O2S(namePtr), i),
1613
                        Tcl_GetObjResult(interp));
1614
                result = TCL_ERROR;
1615
                Tcl_DecrRefCount(namePtr);
1616
                goto checkForCatch;
1617
            }
1618
            PUSH_OBJECT(value2Ptr);
1619
            TRACE_WITH_OBJ(("%s \"%.30s\" %ld => ",
1620
                    opName[opCode], O2S(namePtr), i), value2Ptr);
1621
            TclDecrRefCount(namePtr);
1622
            ADJUST_PC(2);
1623
 
1624
        case INST_INCR_ARRAY1_IMM:
1625
            {
1626
                Tcl_Obj *elemPtr;
1627
 
1628
                opnd = TclGetUInt1AtPtr(pc+1);
1629
                i = TclGetInt1AtPtr(pc+2);
1630
                elemPtr = POP_OBJECT();
1631
                DECACHE_STACK_INFO();
1632
                value2Ptr = TclIncrElementOfIndexedArray(interp, opnd,
1633
                        elemPtr, i);
1634
                CACHE_STACK_INFO();
1635
                if (value2Ptr == NULL) {
1636
                    TRACE_WITH_OBJ(("incrArray1Imm %u \"%.30s\" (by %ld) => ERROR: ",
1637
                            opnd, O2S(elemPtr), i),
1638
                            Tcl_GetObjResult(interp));
1639
                    Tcl_DecrRefCount(elemPtr);
1640
                    result = TCL_ERROR;
1641
                    goto checkForCatch;
1642
                }
1643
                PUSH_OBJECT(value2Ptr);
1644
                TRACE_WITH_OBJ(("incrArray1Imm %u \"%.30s\" (by %ld) => ",
1645
                        opnd, O2S(elemPtr), i), value2Ptr);
1646
                Tcl_DecrRefCount(elemPtr);
1647
            }
1648
            ADJUST_PC(3);
1649
 
1650
        case INST_INCR_ARRAY_STK_IMM:
1651
            {
1652
                Tcl_Obj *elemPtr;
1653
 
1654
                i = TclGetInt1AtPtr(pc+1);
1655
                elemPtr = POP_OBJECT();
1656
                namePtr = POP_OBJECT();
1657
                DECACHE_STACK_INFO();
1658
                value2Ptr = TclIncrVar2(interp, namePtr, elemPtr, i,
1659
                        /*part1NotParsed*/ 0);
1660
                CACHE_STACK_INFO();
1661
                if (value2Ptr == NULL) {
1662
                    TRACE_WITH_OBJ(("incrArrayStkImm \"%.30s(%.30s)\" (by %ld) => ERROR: ",
1663
                            O2S(namePtr), O2S(elemPtr), i),
1664
                            Tcl_GetObjResult(interp));
1665
                    Tcl_DecrRefCount(namePtr);
1666
                    Tcl_DecrRefCount(elemPtr);
1667
                    result = TCL_ERROR;
1668
                    goto checkForCatch;
1669
                }
1670
                PUSH_OBJECT(value2Ptr);
1671
                TRACE_WITH_OBJ(("incrArrayStkImm \"%.30s(%.30s)\" (by %ld) => ",
1672
                        O2S(namePtr), O2S(elemPtr), i), value2Ptr);
1673
                Tcl_DecrRefCount(namePtr);
1674
                Tcl_DecrRefCount(elemPtr);
1675
            }
1676
            ADJUST_PC(2);
1677
 
1678
        case INST_JUMP1:
1679
            opnd = TclGetInt1AtPtr(pc+1);
1680
            TRACE(("jump1 %d => new pc %u\n", opnd,
1681
                   (unsigned int)(pc + opnd - codePtr->codeStart)));
1682
            ADJUST_PC(opnd);
1683
 
1684
        case INST_JUMP4:
1685
            opnd = TclGetInt4AtPtr(pc+1);
1686
            TRACE(("jump4 %d => new pc %u\n", opnd,
1687
                   (unsigned int)(pc + opnd - codePtr->codeStart)));
1688
            ADJUST_PC(opnd);
1689
 
1690
        case INST_JUMP_TRUE4:
1691
            opnd = TclGetInt4AtPtr(pc+1);
1692
            pcAdjustment = 5;
1693
            goto doJumpTrue;
1694
 
1695
        case INST_JUMP_TRUE1:
1696
            opnd = TclGetInt1AtPtr(pc+1);
1697
            pcAdjustment = 2;
1698
 
1699
            doJumpTrue:
1700
            {
1701
                int b;
1702
 
1703
                valuePtr = POP_OBJECT();
1704
                if (valuePtr->typePtr == &tclIntType) {
1705
                    b = (valuePtr->internalRep.longValue != 0);
1706
                } else if (valuePtr->typePtr == &tclDoubleType) {
1707
                    b = (valuePtr->internalRep.doubleValue != 0.0);
1708
                } else {
1709
                    result = Tcl_GetBooleanFromObj(interp, valuePtr, &b);
1710
                    if (result != TCL_OK) {
1711
                        TRACE_WITH_OBJ(("%s %d => ERROR: ", opName[opCode],
1712
                                opnd), Tcl_GetObjResult(interp));
1713
                        Tcl_DecrRefCount(valuePtr);
1714
                        goto checkForCatch;
1715
                    }
1716
                }
1717
                if (b) {
1718
                    TRACE(("%s %d => %.20s true, new pc %u\n",
1719
                            opName[opCode], opnd, O2S(valuePtr),
1720
                            (unsigned int)(pc+opnd - codePtr->codeStart)));
1721
                    TclDecrRefCount(valuePtr);
1722
                    ADJUST_PC(opnd);
1723
                } else {
1724
                    TRACE(("%s %d => %.20s false\n", opName[opCode], opnd,
1725
                            O2S(valuePtr)));
1726
                    TclDecrRefCount(valuePtr);
1727
                    ADJUST_PC(pcAdjustment);
1728
                }
1729
            }
1730
 
1731
        case INST_JUMP_FALSE4:
1732
            opnd = TclGetInt4AtPtr(pc+1);
1733
            pcAdjustment = 5;
1734
            goto doJumpFalse;
1735
 
1736
        case INST_JUMP_FALSE1:
1737
            opnd = TclGetInt1AtPtr(pc+1);
1738
            pcAdjustment = 2;
1739
 
1740
            doJumpFalse:
1741
            {
1742
                int b;
1743
 
1744
                valuePtr = POP_OBJECT();
1745
                if (valuePtr->typePtr == &tclIntType) {
1746
                    b = (valuePtr->internalRep.longValue != 0);
1747
                } else if (valuePtr->typePtr == &tclDoubleType) {
1748
                    b = (valuePtr->internalRep.doubleValue != 0.0);
1749
                } else {
1750
                    result = Tcl_GetBooleanFromObj(interp, valuePtr, &b);
1751
                    if (result != TCL_OK) {
1752
                        TRACE_WITH_OBJ(("%s %d => ERROR: ", opName[opCode],
1753
                                opnd), Tcl_GetObjResult(interp));
1754
                        Tcl_DecrRefCount(valuePtr);
1755
                        goto checkForCatch;
1756
                    }
1757
                }
1758
                if (b) {
1759
                    TRACE(("%s %d => %.20s true\n", opName[opCode], opnd,
1760
                            O2S(valuePtr)));
1761
                    TclDecrRefCount(valuePtr);
1762
                    ADJUST_PC(pcAdjustment);
1763
                } else {
1764
                    TRACE(("%s %d => %.20s false, new pc %u\n",
1765
                            opName[opCode], opnd, O2S(valuePtr),
1766
                           (unsigned int)(pc + opnd - codePtr->codeStart)));
1767
                    TclDecrRefCount(valuePtr);
1768
                    ADJUST_PC(opnd);
1769
                }
1770
            }
1771
 
1772
        case INST_LOR:
1773
        case INST_LAND:
1774
            {
1775
                /*
1776
                 * Operands must be boolean or numeric. No int->double
1777
                 * conversions are performed.
1778
                 */
1779
 
1780
                int i1, i2;
1781
                int iResult;
1782
                char *s;
1783
                Tcl_ObjType *t1Ptr, *t2Ptr;
1784
 
1785
                value2Ptr = POP_OBJECT();
1786
                valuePtr  = POP_OBJECT();
1787
                t1Ptr = valuePtr->typePtr;
1788
                t2Ptr = value2Ptr->typePtr;
1789
 
1790
                if ((t1Ptr == &tclIntType) || (t1Ptr == &tclBooleanType)) {
1791
                    i1 = (valuePtr->internalRep.longValue != 0);
1792
                } else if (t1Ptr == &tclDoubleType) {
1793
                    i1 = (valuePtr->internalRep.doubleValue != 0.0);
1794
                } else {        /* FAILS IF NULL STRING REP */
1795
                    s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
1796
                    if (TclLooksLikeInt(s)) {
1797
                        result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
1798
                                valuePtr, &i);
1799
                        i1 = (i != 0);
1800
                    } else {
1801
                        result = Tcl_GetBooleanFromObj((Tcl_Interp *) NULL,
1802
                                valuePtr, &i1);
1803
                        i1 = (i1 != 0);
1804
                    }
1805
                    if (result != TCL_OK) {
1806
                        TRACE(("%s \"%.20s\" => ILLEGAL TYPE %s \n",
1807
                                opName[opCode], O2S(valuePtr),
1808
                                (t1Ptr? t1Ptr->name : "null")));
1809
                        IllegalExprOperandType(interp, opCode, valuePtr);
1810
                        Tcl_DecrRefCount(valuePtr);
1811
                        Tcl_DecrRefCount(value2Ptr);
1812
                        goto checkForCatch;
1813
                    }
1814
                }
1815
 
1816
                if ((t2Ptr == &tclIntType) || (t2Ptr == &tclBooleanType)) {
1817
                    i2 = (value2Ptr->internalRep.longValue != 0);
1818
                } else if (t2Ptr == &tclDoubleType) {
1819
                    i2 = (value2Ptr->internalRep.doubleValue != 0.0);
1820
                } else {        /* FAILS IF NULL STRING REP */
1821
                    s = Tcl_GetStringFromObj(value2Ptr, (int *) NULL);
1822
                    if (TclLooksLikeInt(s)) {
1823
                        result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
1824
                                value2Ptr, &i);
1825
                        i2 = (i != 0);
1826
                    } else {
1827
                        result = Tcl_GetBooleanFromObj((Tcl_Interp *) NULL,
1828
                                value2Ptr, &i2);
1829
                        i2 = (i2 != 0);
1830
                    }
1831
                    if (result != TCL_OK) {
1832
                        TRACE(("%s \"%.20s\" => ILLEGAL TYPE %s \n",
1833
                                opName[opCode], O2S(value2Ptr),
1834
                                (t2Ptr? t2Ptr->name : "null")));
1835
                        IllegalExprOperandType(interp, opCode, value2Ptr);
1836
                        Tcl_DecrRefCount(valuePtr);
1837
                        Tcl_DecrRefCount(value2Ptr);
1838
                        goto checkForCatch;
1839
                    }
1840
                }
1841
 
1842
                /*
1843
                 * Reuse the valuePtr object already on stack if possible.
1844
                 */
1845
 
1846
                if (opCode == INST_LOR) {
1847
                    iResult = (i1 || i2);
1848
                } else {
1849
                    iResult = (i1 && i2);
1850
                }
1851
                if (Tcl_IsShared(valuePtr)) {
1852
                    PUSH_OBJECT(Tcl_NewLongObj(iResult));
1853
                    TRACE(("%s %.20s %.20s => %d\n", opName[opCode],
1854
                           O2S(valuePtr), O2S(value2Ptr), iResult));
1855
                    TclDecrRefCount(valuePtr);
1856
                } else {        /* reuse the valuePtr object */
1857
                    TRACE(("%s %.20s %.20s => %d\n",
1858
                           opName[opCode], /* NB: stack top is off by 1 */
1859
                           O2S(valuePtr), O2S(value2Ptr), iResult));
1860
                    Tcl_SetLongObj(valuePtr, iResult);
1861
                    ++stackTop; /* valuePtr now on stk top has right r.c. */
1862
                }
1863
                TclDecrRefCount(value2Ptr);
1864
            }
1865
            ADJUST_PC(1);
1866
 
1867
        case INST_EQ:
1868
        case INST_NEQ:
1869
        case INST_LT:
1870
        case INST_GT:
1871
        case INST_LE:
1872
        case INST_GE:
1873
            {
1874
                /*
1875
                 * Any type is allowed but the two operands must have the
1876
                 * same type. We will compute value op value2.
1877
                 */
1878
 
1879
                Tcl_ObjType *t1Ptr, *t2Ptr;
1880
                char *s1 = NULL;   /* Init. avoids compiler warning. */
1881
                char *s2 = NULL;   /* Init. avoids compiler warning. */
1882
                long i2 = 0;        /* Init. avoids compiler warning. */
1883
                double d1 = 0.0;   /* Init. avoids compiler warning. */
1884
                double d2 = 0.0;   /* Init. avoids compiler warning. */
1885
                long iResult = 0;  /* Init. avoids compiler warning. */
1886
 
1887
                value2Ptr = POP_OBJECT();
1888
                valuePtr  = POP_OBJECT();
1889
                t1Ptr = valuePtr->typePtr;
1890
                t2Ptr = value2Ptr->typePtr;
1891
 
1892
                if ((t1Ptr != &tclIntType) && (t1Ptr != &tclDoubleType)) {
1893
                    s1 = Tcl_GetStringFromObj(valuePtr, &length);
1894
                    if (TclLooksLikeInt(s1)) { /* FAILS IF NULLS */
1895
                        (void) Tcl_GetLongFromObj((Tcl_Interp *) NULL,
1896
                                valuePtr, &i);
1897
                    } else {
1898
                        (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
1899
                                valuePtr, &d1);
1900
                    }
1901
                    t1Ptr = valuePtr->typePtr;
1902
                }
1903
                if ((t2Ptr != &tclIntType) && (t2Ptr != &tclDoubleType)) {
1904
                    s2 = Tcl_GetStringFromObj(value2Ptr, &length);
1905
                    if (TclLooksLikeInt(s2)) { /* FAILS IF NULLS */
1906
                        (void) Tcl_GetLongFromObj((Tcl_Interp *) NULL,
1907
                                value2Ptr, &i2);
1908
                    } else {
1909
                        (void) Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
1910
                                value2Ptr, &d2);
1911
                    }
1912
                    t2Ptr = value2Ptr->typePtr;
1913
                }
1914
 
1915
                if (((t1Ptr != &tclIntType) && (t1Ptr != &tclDoubleType))
1916
                        || ((t2Ptr != &tclIntType) && (t2Ptr != &tclDoubleType))) {
1917
                    /*
1918
                     * One operand is not numeric. Compare as strings.
1919
                     * THIS FAILS IF AN OBJECT'S STRING REP CONTAINS NULLS.
1920
                     */
1921
                    int cmpValue;
1922
                    s1 = TclGetStringFromObj(valuePtr, &length);
1923
                    s2 = TclGetStringFromObj(value2Ptr, &length);
1924
                    cmpValue = strcmp(s1, s2);
1925
                    switch (opCode) {
1926
                    case INST_EQ:
1927
                        iResult = (cmpValue == 0);
1928
                        break;
1929
                    case INST_NEQ:
1930
                        iResult = (cmpValue != 0);
1931
                        break;
1932
                    case INST_LT:
1933
                        iResult = (cmpValue < 0);
1934
                        break;
1935
                    case INST_GT:
1936
                        iResult = (cmpValue > 0);
1937
                        break;
1938
                    case INST_LE:
1939
                        iResult = (cmpValue <= 0);
1940
                        break;
1941
                    case INST_GE:
1942
                        iResult = (cmpValue >= 0);
1943
                        break;
1944
                    }
1945
                } else if ((t1Ptr == &tclDoubleType)
1946
                        || (t2Ptr == &tclDoubleType)) {
1947
                    /*
1948
                     * Compare as doubles.
1949
                     */
1950
                    if (t1Ptr == &tclDoubleType) {
1951
                        d1 = valuePtr->internalRep.doubleValue;
1952
                        if (t2Ptr == &tclIntType) {
1953
                            d2 = value2Ptr->internalRep.longValue;
1954
                        } else {
1955
                            d2 = value2Ptr->internalRep.doubleValue;
1956
                        }
1957
                    } else {    /* t1Ptr is int, t2Ptr is double */
1958
                        d1 = valuePtr->internalRep.longValue;
1959
                        d2 = value2Ptr->internalRep.doubleValue;
1960
                    }
1961
                    switch (opCode) {
1962
                    case INST_EQ:
1963
                        iResult = d1 == d2;
1964
                        break;
1965
                    case INST_NEQ:
1966
                        iResult = d1 != d2;
1967
                        break;
1968
                    case INST_LT:
1969
                        iResult = d1 < d2;
1970
                        break;
1971
                    case INST_GT:
1972
                        iResult = d1 > d2;
1973
                        break;
1974
                    case INST_LE:
1975
                        iResult = d1 <= d2;
1976
                        break;
1977
                    case INST_GE:
1978
                        iResult = d1 >= d2;
1979
                        break;
1980
                    }
1981
                } else {
1982
                    /*
1983
                     * Compare as ints.
1984
                     */
1985
                    i  = valuePtr->internalRep.longValue;
1986
                    i2 = value2Ptr->internalRep.longValue;
1987
                    switch (opCode) {
1988
                    case INST_EQ:
1989
                        iResult = i == i2;
1990
                        break;
1991
                    case INST_NEQ:
1992
                        iResult = i != i2;
1993
                        break;
1994
                    case INST_LT:
1995
                        iResult = i < i2;
1996
                        break;
1997
                    case INST_GT:
1998
                        iResult = i > i2;
1999
                        break;
2000
                    case INST_LE:
2001
                        iResult = i <= i2;
2002
                        break;
2003
                    case INST_GE:
2004
                        iResult = i >= i2;
2005
                        break;
2006
                    }
2007
                }
2008
 
2009
                /*
2010
                 * Reuse the valuePtr object already on stack if possible.
2011
                 */
2012
 
2013
                if (Tcl_IsShared(valuePtr)) {
2014
                    PUSH_OBJECT(Tcl_NewLongObj(iResult));
2015
                    TRACE(("%s %.20s %.20s => %ld\n", opName[opCode],
2016
                        O2S(valuePtr), O2S(value2Ptr), iResult));
2017
                    TclDecrRefCount(valuePtr);
2018
                } else {        /* reuse the valuePtr object */
2019
                    TRACE(("%s %.20s %.20s => %ld\n",
2020
                        opName[opCode], /* NB: stack top is off by 1 */
2021
                        O2S(valuePtr), O2S(value2Ptr), iResult));
2022
                    Tcl_SetLongObj(valuePtr, iResult);
2023
                    ++stackTop; /* valuePtr now on stk top has right r.c. */
2024
                }
2025
                TclDecrRefCount(value2Ptr);
2026
            }
2027
            ADJUST_PC(1);
2028
 
2029
        case INST_MOD:
2030
        case INST_LSHIFT:
2031
        case INST_RSHIFT:
2032
        case INST_BITOR:
2033
        case INST_BITXOR:
2034
        case INST_BITAND:
2035
            {
2036
                /*
2037
                 * Only integers are allowed. We compute value op value2.
2038
                 */
2039
 
2040
                long i2, rem, negative;
2041
                long iResult = 0; /* Init. avoids compiler warning. */
2042
 
2043
                value2Ptr = POP_OBJECT();
2044
                valuePtr  = POP_OBJECT();
2045
                if (valuePtr->typePtr == &tclIntType) {
2046
                    i = valuePtr->internalRep.longValue;
2047
                } else {        /* try to convert to int */
2048
                    result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
2049
                            valuePtr, &i);
2050
                    if (result != TCL_OK) {
2051
                        TRACE(("%s %.20s %.20s => ILLEGAL 1st TYPE %s\n",
2052
                              opName[opCode], O2S(valuePtr), O2S(value2Ptr),
2053
                              (valuePtr->typePtr?
2054
                                   valuePtr->typePtr->name : "null")));
2055
                        IllegalExprOperandType(interp, opCode, valuePtr);
2056
                        Tcl_DecrRefCount(valuePtr);
2057
                        Tcl_DecrRefCount(value2Ptr);
2058
                        goto checkForCatch;
2059
                    }
2060
                }
2061
                if (value2Ptr->typePtr == &tclIntType) {
2062
                    i2 = value2Ptr->internalRep.longValue;
2063
                } else {
2064
                    result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
2065
                            value2Ptr, &i2);
2066
                    if (result != TCL_OK) {
2067
                        TRACE(("%s %.20s %.20s => ILLEGAL 2nd TYPE %s\n",
2068
                              opName[opCode], O2S(valuePtr), O2S(value2Ptr),
2069
                              (value2Ptr->typePtr?
2070
                                   value2Ptr->typePtr->name : "null")));
2071
                        IllegalExprOperandType(interp, opCode, value2Ptr);
2072
                        Tcl_DecrRefCount(valuePtr);
2073
                        Tcl_DecrRefCount(value2Ptr);
2074
                        goto checkForCatch;
2075
                    }
2076
                }
2077
 
2078
                switch (opCode) {
2079
                case INST_MOD:
2080
                    /*
2081
                     * This code is tricky: C doesn't guarantee much about
2082
                     * the quotient or remainder, but Tcl does. The
2083
                     * remainder always has the same sign as the divisor and
2084
                     * a smaller absolute value.
2085
                     */
2086
                    if (i2 == 0) {
2087
                        TRACE(("mod %ld %ld => DIVIDE BY ZERO\n", i, i2));
2088
                        Tcl_DecrRefCount(valuePtr);
2089
                        Tcl_DecrRefCount(value2Ptr);
2090
                        goto divideByZero;
2091
                    }
2092
                    negative = 0;
2093
                    if (i2 < 0) {
2094
                        i2 = -i2;
2095
                        i = -i;
2096
                        negative = 1;
2097
                    }
2098
                    rem  = i % i2;
2099
                    if (rem < 0) {
2100
                        rem += i2;
2101
                    }
2102
                    if (negative) {
2103
                        rem = -rem;
2104
                    }
2105
                    iResult = rem;
2106
                    break;
2107
                case INST_LSHIFT:
2108
                    iResult = i << i2;
2109
                    break;
2110
                case INST_RSHIFT:
2111
                    /*
2112
                     * The following code is a bit tricky: it ensures that
2113
                     * right shifts propagate the sign bit even on machines
2114
                     * where ">>" won't do it by default.
2115
                     */
2116
                    if (i < 0) {
2117
                        iResult = ~((~i) >> i2);
2118
                    } else {
2119
                        iResult = i >> i2;
2120
                    }
2121
                    break;
2122
                case INST_BITOR:
2123
                    iResult = i | i2;
2124
                    break;
2125
                case INST_BITXOR:
2126
                    iResult = i ^ i2;
2127
                    break;
2128
                case INST_BITAND:
2129
                    iResult = i & i2;
2130
                    break;
2131
                }
2132
 
2133
                /*
2134
                 * Reuse the valuePtr object already on stack if possible.
2135
                 */
2136
 
2137
                if (Tcl_IsShared(valuePtr)) {
2138
                    PUSH_OBJECT(Tcl_NewLongObj(iResult));
2139
                    TRACE(("%s %ld %ld => %ld\n", opName[opCode], i, i2,
2140
                           iResult));
2141
                    TclDecrRefCount(valuePtr);
2142
                } else {        /* reuse the valuePtr object */
2143
                    TRACE(("%s %ld %ld => %ld\n", opName[opCode], i, i2,
2144
                        iResult)); /* NB: stack top is off by 1 */
2145
                    Tcl_SetLongObj(valuePtr, iResult);
2146
                    ++stackTop; /* valuePtr now on stk top has right r.c. */
2147
                }
2148
                TclDecrRefCount(value2Ptr);
2149
            }
2150
            ADJUST_PC(1);
2151
 
2152
        case INST_ADD:
2153
        case INST_SUB:
2154
        case INST_MULT:
2155
        case INST_DIV:
2156
            {
2157
                /*
2158
                 * Operands must be numeric and ints get converted to floats
2159
                 * if necessary. We compute value op value2.
2160
                 */
2161
 
2162
                Tcl_ObjType *t1Ptr, *t2Ptr;
2163
                long i2, quot, rem;
2164
                double d1, d2;
2165
                long iResult = 0;     /* Init. avoids compiler warning. */
2166
                double dResult = 0.0; /* Init. avoids compiler warning. */
2167
                int doDouble = 0;     /* 1 if doing floating arithmetic */
2168
 
2169
                value2Ptr = POP_OBJECT();
2170
                valuePtr  = POP_OBJECT();
2171
                t1Ptr = valuePtr->typePtr;
2172
                t2Ptr = value2Ptr->typePtr;
2173
 
2174
                if (t1Ptr == &tclIntType) {
2175
                    i  = valuePtr->internalRep.longValue;
2176
                } else if (t1Ptr == &tclDoubleType) {
2177
                    d1 = valuePtr->internalRep.doubleValue;
2178
                } else {             /* try to convert; FAILS IF NULLS */
2179
                    char *s = Tcl_GetStringFromObj(valuePtr, &length);
2180
                    if (TclLooksLikeInt(s)) {
2181
                        result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
2182
                                valuePtr, &i);
2183
                    } else {
2184
                        result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
2185
                                valuePtr, &d1);
2186
                    }
2187
                    if (result != TCL_OK) {
2188
                        TRACE(("%s %.20s %.20s => ILLEGAL 1st TYPE %s\n",
2189
                               opName[opCode], s, O2S(value2Ptr),
2190
                               (valuePtr->typePtr?
2191
                                    valuePtr->typePtr->name : "null")));
2192
                        IllegalExprOperandType(interp, opCode, valuePtr);
2193
                        Tcl_DecrRefCount(valuePtr);
2194
                        Tcl_DecrRefCount(value2Ptr);
2195
                        goto checkForCatch;
2196
                    }
2197
                    t1Ptr = valuePtr->typePtr;
2198
                }
2199
 
2200
                if (t2Ptr == &tclIntType) {
2201
                    i2 = value2Ptr->internalRep.longValue;
2202
                } else if (t2Ptr == &tclDoubleType) {
2203
                    d2 = value2Ptr->internalRep.doubleValue;
2204
                } else {             /* try to convert; FAILS IF NULLS */
2205
                    char *s = Tcl_GetStringFromObj(value2Ptr, &length);
2206
                    if (TclLooksLikeInt(s)) {
2207
                        result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
2208
                                value2Ptr, &i2);
2209
                    } else {
2210
                        result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
2211
                                value2Ptr, &d2);
2212
                    }
2213
                    if (result != TCL_OK) {
2214
                        TRACE(("%s %.20s %.20s => ILLEGAL 2nd TYPE %s\n",
2215
                               opName[opCode], O2S(valuePtr), s,
2216
                               (value2Ptr->typePtr?
2217
                                    value2Ptr->typePtr->name : "null")));
2218
                        IllegalExprOperandType(interp, opCode, value2Ptr);
2219
                        Tcl_DecrRefCount(valuePtr);
2220
                        Tcl_DecrRefCount(value2Ptr);
2221
                        goto checkForCatch;
2222
                    }
2223
                    t2Ptr = value2Ptr->typePtr;
2224
                }
2225
 
2226
                if ((t1Ptr == &tclDoubleType) || (t2Ptr == &tclDoubleType)) {
2227
                    /*
2228
                     * Do double arithmetic.
2229
                     */
2230
                    doDouble = 1;
2231
                    if (t1Ptr == &tclIntType) {
2232
                        d1 = i;       /* promote value 1 to double */
2233
                    } else if (t2Ptr == &tclIntType) {
2234
                        d2 = i2;      /* promote value 2 to double */
2235
                    }
2236
                    switch (opCode) {
2237
                    case INST_ADD:
2238
                        dResult = d1 + d2;
2239
                        break;
2240
                    case INST_SUB:
2241
                        dResult = d1 - d2;
2242
                        break;
2243
                    case INST_MULT:
2244
                        dResult = d1 * d2;
2245
                        break;
2246
                    case INST_DIV:
2247
                        if (d2 == 0.0) {
2248
                            TRACE(("div %.6g %.6g => DIVIDE BY ZERO\n",
2249
                                   d1, d2));
2250
                            Tcl_DecrRefCount(valuePtr);
2251
                            Tcl_DecrRefCount(value2Ptr);
2252
                            goto divideByZero;
2253
                        }
2254
                        dResult = d1 / d2;
2255
                        break;
2256
                    }
2257
 
2258
                    /*
2259
                     * Check now for IEEE floating-point error.
2260
                     */
2261
 
2262
                    if (IS_NAN(dResult) || IS_INF(dResult)) {
2263
                        TRACE(("%s %.20s %.20s => IEEE FLOATING PT ERROR\n",
2264
                               opName[opCode], O2S(valuePtr), O2S(value2Ptr)));
2265
                        TclExprFloatError(interp, dResult);
2266
                        result = TCL_ERROR;
2267
                        Tcl_DecrRefCount(valuePtr);
2268
                        Tcl_DecrRefCount(value2Ptr);
2269
                        goto checkForCatch;
2270
                    }
2271
                } else {
2272
                    /*
2273
                     * Do integer arithmetic.
2274
                     */
2275
                    switch (opCode) {
2276
                    case INST_ADD:
2277
                        iResult = i + i2;
2278
                        break;
2279
                    case INST_SUB:
2280
                        iResult = i - i2;
2281
                        break;
2282
                    case INST_MULT:
2283
                        iResult = i * i2;
2284
                        break;
2285
                    case INST_DIV:
2286
                        /*
2287
                         * This code is tricky: C doesn't guarantee much
2288
                         * about the quotient or remainder, but Tcl does.
2289
                         * The remainder always has the same sign as the
2290
                         * divisor and a smaller absolute value.
2291
                         */
2292
                        if (i2 == 0) {
2293
                            TRACE(("div %ld %ld => DIVIDE BY ZERO\n",
2294
                                    i, i2));
2295
                            Tcl_DecrRefCount(valuePtr);
2296
                            Tcl_DecrRefCount(value2Ptr);
2297
                            goto divideByZero;
2298
                        }
2299
                        if (i2 < 0) {
2300
                            i2 = -i2;
2301
                            i = -i;
2302
                        }
2303
                        quot = i / i2;
2304
                        rem  = i % i2;
2305
                        if (rem < 0) {
2306
                            quot -= 1;
2307
                        }
2308
                        iResult = quot;
2309
                        break;
2310
                    }
2311
                }
2312
 
2313
                /*
2314
                 * Reuse the valuePtr object already on stack if possible.
2315
                 */
2316
 
2317
                if (Tcl_IsShared(valuePtr)) {
2318
                    if (doDouble) {
2319
                        PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
2320
                        TRACE(("%s %.6g %.6g => %.6g\n", opName[opCode],
2321
                               d1, d2, dResult));
2322
                    } else {
2323
                        PUSH_OBJECT(Tcl_NewLongObj(iResult));
2324
                        TRACE(("%s %ld %ld => %ld\n", opName[opCode],
2325
                               i, i2, iResult));
2326
                    }
2327
                    TclDecrRefCount(valuePtr);
2328
                } else {            /* reuse the valuePtr object */
2329
                    if (doDouble) { /* NB: stack top is off by 1 */
2330
                        TRACE(("%s %.6g %.6g => %.6g\n", opName[opCode],
2331
                               d1, d2, dResult));
2332
                        Tcl_SetDoubleObj(valuePtr, dResult);
2333
                    } else {
2334
                        TRACE(("%s %ld %ld => %ld\n", opName[opCode],
2335
                               i, i2, iResult));
2336
                        Tcl_SetLongObj(valuePtr, iResult);
2337
                    }
2338
                    ++stackTop; /* valuePtr now on stk top has right r.c. */
2339
                }
2340
                TclDecrRefCount(value2Ptr);
2341
            }
2342
            ADJUST_PC(1);
2343
 
2344
        case INST_UPLUS:
2345
            {
2346
                /*
2347
                 * Operand must be numeric.
2348
                 */
2349
 
2350
                double d;
2351
                Tcl_ObjType *tPtr;
2352
 
2353
                valuePtr = stackPtr[stackTop].o;
2354
                tPtr = valuePtr->typePtr;
2355
                if ((tPtr != &tclIntType) && (tPtr != &tclDoubleType)) {
2356
                    char *s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
2357
                    if (TclLooksLikeInt(s)) { /* FAILS IF NULLS */
2358
                        result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
2359
                                valuePtr, &i);
2360
                    } else {
2361
                        result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
2362
                                valuePtr, &d);
2363
                    }
2364
                    if (result != TCL_OK) {
2365
                        TRACE(("%s \"%.20s\" => ILLEGAL TYPE %s \n",
2366
                                opName[opCode], s,
2367
                                (tPtr? tPtr->name : "null")));
2368
                        IllegalExprOperandType(interp, opCode, valuePtr);
2369
                        goto checkForCatch;
2370
                    }
2371
                }
2372
                TRACE_WITH_OBJ(("uplus %s => ", O2S(valuePtr)), valuePtr);
2373
            }
2374
            ADJUST_PC(1);
2375
 
2376
        case INST_UMINUS:
2377
        case INST_LNOT:
2378
            {
2379
                /*
2380
                 * The operand must be numeric. If the operand object is
2381
                 * unshared modify it directly, otherwise create a copy to
2382
                 * modify: this is "copy on write". free any old string
2383
                 * representation since it is now invalid.
2384
                 */
2385
 
2386
                double d;
2387
                Tcl_ObjType *tPtr;
2388
 
2389
                valuePtr = POP_OBJECT();
2390
                tPtr = valuePtr->typePtr;
2391
                if ((tPtr != &tclIntType) && (tPtr != &tclDoubleType)) {
2392
                    char *s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
2393
                    if (TclLooksLikeInt(s)) { /* FAILS IF NULLS */
2394
                        result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
2395
                                valuePtr, &i);
2396
                    } else {
2397
                        result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
2398
                                valuePtr, &d);
2399
                    }
2400
                    if (result != TCL_OK) {
2401
                        TRACE(("%s \"%.20s\" => ILLEGAL TYPE %s\n",
2402
                                opName[opCode], s,
2403
                               (tPtr? tPtr->name : "null")));
2404
                        IllegalExprOperandType(interp, opCode, valuePtr);
2405
                        Tcl_DecrRefCount(valuePtr);
2406
                        goto checkForCatch;
2407
                    }
2408
                    tPtr = valuePtr->typePtr;
2409
                }
2410
 
2411
                if (Tcl_IsShared(valuePtr)) {
2412
                    /*
2413
                     * Create a new object.
2414
                     */
2415
                    if (tPtr == &tclIntType) {
2416
                        i = valuePtr->internalRep.longValue;
2417
                        objPtr = Tcl_NewLongObj(
2418
                                (opCode == INST_UMINUS)? -i : !i);
2419
                        TRACE_WITH_OBJ(("%s %ld => ", opName[opCode], i),
2420
                                objPtr); /* NB: stack top is off by 1 */
2421
                    } else {
2422
                        d = valuePtr->internalRep.doubleValue;
2423
                        if (opCode == INST_UMINUS) {
2424
                            objPtr = Tcl_NewDoubleObj(-d);
2425
                        } else {
2426
                            /*
2427
                             * Should be able to use "!d", but apparently
2428
                             * some compilers can't handle it.
2429
                             */
2430
                            objPtr = Tcl_NewLongObj((d==0.0)? 1 : 0);
2431
                        }
2432
                        TRACE_WITH_OBJ(("%s %.6g => ", opName[opCode], d),
2433
                                objPtr); /* NB: stack top is off by 1 */
2434
                    }
2435
                    PUSH_OBJECT(objPtr);
2436
                    TclDecrRefCount(valuePtr);
2437
                } else {
2438
                    /*
2439
                     * valuePtr is unshared. Modify it directly.
2440
                     */
2441
                    if (tPtr == &tclIntType) {
2442
                        i = valuePtr->internalRep.longValue;
2443
                        Tcl_SetLongObj(valuePtr,
2444
                                (opCode == INST_UMINUS)? -i : !i);
2445
                        TRACE_WITH_OBJ(("%s %ld => ", opName[opCode], i),
2446
                                valuePtr); /* NB: stack top is off by 1 */
2447
                    } else {
2448
                        d = valuePtr->internalRep.doubleValue;
2449
                        if (opCode == INST_UMINUS) {
2450
                            Tcl_SetDoubleObj(valuePtr, -d);
2451
                        } else {
2452
                            /*
2453
                             * Should be able to use "!d", but apparently
2454
                             * some compilers can't handle it.
2455
                             */
2456
                            Tcl_SetLongObj(valuePtr, (d==0.0)? 1 : 0);
2457
                        }
2458
                        TRACE_WITH_OBJ(("%s %.6g => ", opName[opCode], d),
2459
                                valuePtr); /* NB: stack top is off by 1 */
2460
                    }
2461
                    ++stackTop; /* valuePtr now on stk top has right r.c. */
2462
                }
2463
            }
2464
            ADJUST_PC(1);
2465
 
2466
        case INST_BITNOT:
2467
            {
2468
                /*
2469
                 * The operand must be an integer. If the operand object is
2470
                 * unshared modify it directly, otherwise modify a copy.
2471
                 * Free any old string representation since it is now
2472
                 * invalid.
2473
                 */
2474
 
2475
                Tcl_ObjType *tPtr;
2476
 
2477
                valuePtr = POP_OBJECT();
2478
                tPtr = valuePtr->typePtr;
2479
                if (tPtr != &tclIntType) {
2480
                    result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
2481
                            valuePtr, &i);
2482
                    if (result != TCL_OK) {   /* try to convert to double */
2483
                        TRACE(("bitnot \"%.20s\" => ILLEGAL TYPE %s\n",
2484
                               O2S(valuePtr), (tPtr? tPtr->name : "null")));
2485
                        IllegalExprOperandType(interp, opCode, valuePtr);
2486
                        Tcl_DecrRefCount(valuePtr);
2487
                        goto checkForCatch;
2488
                    }
2489
                }
2490
 
2491
                i = valuePtr->internalRep.longValue;
2492
                if (Tcl_IsShared(valuePtr)) {
2493
                    PUSH_OBJECT(Tcl_NewLongObj(~i));
2494
                    TRACE(("bitnot 0x%lx => (%lu)\n", i, ~i));
2495
                    TclDecrRefCount(valuePtr);
2496
                } else {
2497
                    /*
2498
                     * valuePtr is unshared. Modify it directly.
2499
                     */
2500
                    Tcl_SetLongObj(valuePtr, ~i);
2501
                    ++stackTop; /* valuePtr now on stk top has right r.c. */
2502
                    TRACE(("bitnot 0x%lx => (%lu)\n", i, ~i));
2503
                }
2504
            }
2505
            ADJUST_PC(1);
2506
 
2507
        case INST_CALL_BUILTIN_FUNC1:
2508
            opnd = TclGetUInt1AtPtr(pc+1);
2509
            {
2510
                /*
2511
                 * Call one of the built-in Tcl math functions.
2512
                 */
2513
 
2514
                BuiltinFunc *mathFuncPtr;
2515
 
2516
                if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) {
2517
                    TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %d\n", opnd));
2518
                    panic("TclExecuteByteCode: unrecognized builtin function code %d", opnd);
2519
                }
2520
                mathFuncPtr = &(builtinFuncTable[opnd]);
2521
                DECACHE_STACK_INFO();
2522
                tcl_MathInProgress++;
2523
                result = (*mathFuncPtr->proc)(interp, eePtr,
2524
                        mathFuncPtr->clientData);
2525
                tcl_MathInProgress--;
2526
                CACHE_STACK_INFO();
2527
                if (result != TCL_OK) {
2528
                    goto checkForCatch;
2529
                }
2530
                TRACE_WITH_OBJ(("callBuiltinFunc1 %d => ", opnd),
2531
                        stackPtr[stackTop].o);
2532
            }
2533
            ADJUST_PC(2);
2534
 
2535
        case INST_CALL_FUNC1:
2536
            opnd = TclGetUInt1AtPtr(pc+1);
2537
            {
2538
                /*
2539
                 * Call a non-builtin Tcl math function previously
2540
                 * registered by a call to Tcl_CreateMathFunc.
2541
                 */
2542
 
2543
                int objc = opnd;   /* Number of arguments. The function name
2544
                                    * is the 0-th argument. */
2545
                Tcl_Obj **objv;    /* The array of arguments. The function
2546
                                    * name is objv[0]. */
2547
 
2548
                objv = &(stackPtr[stackTop - (objc-1)].o); /* "objv[0]" */
2549
                DECACHE_STACK_INFO();
2550
                tcl_MathInProgress++;
2551
                result = ExprCallMathFunc(interp, eePtr, objc, objv);
2552
                tcl_MathInProgress--;
2553
                CACHE_STACK_INFO();
2554
                if (result != TCL_OK) {
2555
                    goto checkForCatch;
2556
                }
2557
                TRACE_WITH_OBJ(("callFunc1 %d => ", objc),
2558
                        stackPtr[stackTop].o);
2559
                ADJUST_PC(2);
2560
            }
2561
 
2562
        case INST_TRY_CVT_TO_NUMERIC:
2563
            {
2564
                /*
2565
                 * Try to convert the topmost stack object to an int or
2566
                 * double object. This is done in order to support Tcl's
2567
                 * policy of interpreting operands if at all possible as
2568
                 * first integers, else floating-point numbers.
2569
                 */
2570
 
2571
                double d;
2572
                char *s;
2573
                Tcl_ObjType *tPtr;
2574
                int converted, shared;
2575
 
2576
                valuePtr = stackPtr[stackTop].o;
2577
                tPtr = valuePtr->typePtr;
2578
                converted = 0;
2579
                if ((tPtr != &tclIntType) && (tPtr != &tclDoubleType)) {
2580
                    s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
2581
                    if (TclLooksLikeInt(s)) { /* FAILS IF NULLS */
2582
                        result = Tcl_GetLongFromObj((Tcl_Interp *) NULL,
2583
                                valuePtr, &i);
2584
                    } else {
2585
                        result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
2586
                                valuePtr, &d);
2587
                    }
2588
                    if (result == TCL_OK) {
2589
                        converted = 1;
2590
                    }
2591
                    result = TCL_OK; /* reset the result variable */
2592
                    tPtr = valuePtr->typePtr;
2593
                }
2594
 
2595
                /*
2596
                 * Ensure that the topmost stack object, if numeric, has a
2597
                 * string rep the same as the formatted version of its
2598
                 * internal rep. This is used, e.g., to make sure that "expr
2599
                 * {0001}" yields "1", not "0001". We implement this by
2600
                 * _discarding_ the string rep since we know it will be
2601
                 * regenerated, if needed later, by formatting the internal
2602
                 * rep's value. Also check if there has been an IEEE
2603
                 * floating point error.
2604
                 */
2605
 
2606
                if ((tPtr == &tclIntType) || (tPtr == &tclDoubleType)) {
2607
                    shared = 0;
2608
                    if (Tcl_IsShared(valuePtr)) {
2609
                        shared = 1;
2610
                        if (tPtr == &tclIntType) {
2611
                            i = valuePtr->internalRep.longValue;
2612
                            objPtr = Tcl_NewLongObj(i);
2613
                        } else {
2614
                            d = valuePtr->internalRep.doubleValue;
2615
                            objPtr = Tcl_NewDoubleObj(d);
2616
                        }
2617
                        Tcl_IncrRefCount(objPtr);
2618
                        TclDecrRefCount(valuePtr);
2619
                        valuePtr = objPtr;
2620
                        tPtr = valuePtr->typePtr;
2621
                    } else {
2622
                        Tcl_InvalidateStringRep(valuePtr);
2623
                    }
2624
                    stackPtr[stackTop].o = valuePtr;
2625
 
2626
                    if (tPtr == &tclDoubleType) {
2627
                        d = valuePtr->internalRep.doubleValue;
2628
                        if (IS_NAN(d) || IS_INF(d)) {
2629
                            TRACE(("tryCvtToNumeric \"%.20s\" => IEEE FLOATING PT ERROR\n",
2630
                                   O2S(valuePtr)));
2631
                            TclExprFloatError(interp, d);
2632
                            result = TCL_ERROR;
2633
                            goto checkForCatch;
2634
                        }
2635
                    }
2636
                    shared = shared;            /* lint, shared not used. */
2637
                    converted = converted;      /* lint, converted not used. */
2638
                    TRACE(("tryCvtToNumeric \"%.20s\" => numeric, %s, %s\n",
2639
                           O2S(valuePtr),
2640
                           (converted? "converted" : "not converted"),
2641
                           (shared? "shared" : "not shared")));
2642
                } else {
2643
                    TRACE(("tryCvtToNumeric \"%.20s\" => not numeric\n",
2644
                           O2S(valuePtr)));
2645
                }
2646
            }
2647
            ADJUST_PC(1);
2648
 
2649
        case INST_BREAK:
2650
            /*
2651
             * First reset the interpreter's result. Then find the closest
2652
             * enclosing loop or catch exception range, if any. If a loop is
2653
             * found, terminate its execution. If the closest is a catch
2654
             * exception range, jump to its catchOffset. If no enclosing
2655
             * range is found, stop execution and return TCL_BREAK.
2656
             */
2657
 
2658
            Tcl_ResetResult(interp);
2659
            rangePtr = TclGetExceptionRangeForPc(pc, /*catchOnly*/ 0,
2660
                    codePtr);
2661
            if (rangePtr == NULL) {
2662
                TRACE(("break => no encl. loop or catch, returning TCL_BREAK\n"));
2663
                result = TCL_BREAK;
2664
                goto abnormalReturn; /* no catch exists to check */
2665
            }
2666
            switch (rangePtr->type) {
2667
            case LOOP_EXCEPTION_RANGE:
2668
                result = TCL_OK;
2669
                TRACE(("break => range at %d, new pc %d\n",
2670
                       rangePtr->codeOffset, rangePtr->breakOffset));
2671
                break;
2672
            case CATCH_EXCEPTION_RANGE:
2673
                result = TCL_BREAK;
2674
                TRACE(("break => ...\n"));
2675
                goto processCatch; /* it will use rangePtr */
2676
            default:
2677
                panic("TclExecuteByteCode: unrecognized ExceptionRange type %d\n", rangePtr->type);
2678
            }
2679
            pc = (codePtr->codeStart + rangePtr->breakOffset);
2680
            continue;   /* restart outer instruction loop at pc */
2681
 
2682
        case INST_CONTINUE:
2683
            /*
2684
             * Find the closest enclosing loop or catch exception range,
2685
             * if any. If a loop is found, skip to its next iteration.
2686
             * If the closest is a catch exception range, jump to its
2687
             * catchOffset. If no enclosing range is found, stop
2688
             * execution and return TCL_CONTINUE.
2689
             */
2690
 
2691
            Tcl_ResetResult(interp);
2692
            rangePtr = TclGetExceptionRangeForPc(pc, /*catchOnly*/ 0,
2693
                    codePtr);
2694
            if (rangePtr == NULL) {
2695
                TRACE(("continue => no encl. loop or catch, returning TCL_CONTINUE\n"));
2696
                result = TCL_CONTINUE;
2697
                goto abnormalReturn;
2698
            }
2699
            switch (rangePtr->type) {
2700
            case LOOP_EXCEPTION_RANGE:
2701
                if (rangePtr->continueOffset == -1) {
2702
                    TRACE(("continue => loop w/o continue, checking for catch\n"));
2703
                    goto checkForCatch;
2704
                } else {
2705
                    result = TCL_OK;
2706
                    TRACE(("continue => range at %d, new pc %d\n",
2707
                           rangePtr->codeOffset, rangePtr->continueOffset));
2708
                }
2709
                break;
2710
            case CATCH_EXCEPTION_RANGE:
2711
                result = TCL_CONTINUE;
2712
                TRACE(("continue => ...\n"));
2713
                goto processCatch; /* it will use rangePtr */
2714
            default:
2715
                panic("TclExecuteByteCode: unrecognized ExceptionRange type %d\n", rangePtr->type);
2716
            }
2717
            pc = (codePtr->codeStart + rangePtr->continueOffset);
2718
            continue;   /* restart outer instruction loop at pc */
2719
 
2720
        case INST_FOREACH_START4:
2721
            opnd = TclGetUInt4AtPtr(pc+1);
2722
            {
2723
                /*
2724
                 * Initialize the temporary local var that holds the count
2725
                 * of the number of iterations of the loop body to -1.
2726
                 */
2727
 
2728
                ForeachInfo *infoPtr = (ForeachInfo *)
2729
                    codePtr->auxDataArrayPtr[opnd].clientData;
2730
                int iterTmpIndex = infoPtr->loopIterNumTmp;
2731
                CallFrame *varFramePtr = iPtr->varFramePtr;
2732
                Var *compiledLocals = varFramePtr->compiledLocals;
2733
                Var *iterVarPtr;
2734
                Tcl_Obj *oldValuePtr;
2735
 
2736
                iterVarPtr = &(compiledLocals[iterTmpIndex]);
2737
                oldValuePtr = iterVarPtr->value.objPtr;
2738
                if (oldValuePtr == NULL) {
2739
                    iterVarPtr->value.objPtr = Tcl_NewLongObj(-1);
2740
                    Tcl_IncrRefCount(iterVarPtr->value.objPtr);
2741
                } else {
2742
                    Tcl_SetLongObj(oldValuePtr, -1);
2743
                }
2744
                TclSetVarScalar(iterVarPtr);
2745
                TclClearVarUndefined(iterVarPtr);
2746
                TRACE(("foreach_start4 %u => loop iter count temp %d\n",
2747
                        opnd, iterTmpIndex));
2748
            }
2749
            ADJUST_PC(5);
2750
 
2751
        case INST_FOREACH_STEP4:
2752
            opnd = TclGetUInt4AtPtr(pc+1);
2753
            {
2754
                /*
2755
                 * "Step" a foreach loop (i.e., begin its next iteration) by
2756
                 * assigning the next value list element to each loop var.
2757
                 */
2758
 
2759
                ForeachInfo *infoPtr = (ForeachInfo *)
2760
                    codePtr->auxDataArrayPtr[opnd].clientData;
2761
                ForeachVarList *varListPtr;
2762
                int numLists = infoPtr->numLists;
2763
                int iterTmpIndex = infoPtr->loopIterNumTmp;
2764
                CallFrame *varFramePtr = iPtr->varFramePtr;
2765
                Var *compiledLocals = varFramePtr->compiledLocals;
2766
                int iterNum, listTmpIndex, listLen, numVars;
2767
                int varIndex, valIndex, j;
2768
                Tcl_Obj *listPtr, *elemPtr, *oldValuePtr;
2769
                List *listRepPtr;
2770
                Var *iterVarPtr, *listVarPtr;
2771
                int continueLoop = 0;
2772
 
2773
                /*
2774
                 * Increment the temp holding the loop iteration number.
2775
                 */
2776
 
2777
                iterVarPtr = &(compiledLocals[iterTmpIndex]);
2778
                oldValuePtr = iterVarPtr->value.objPtr;
2779
                iterNum = (oldValuePtr->internalRep.longValue + 1);
2780
                Tcl_SetLongObj(oldValuePtr, iterNum);
2781
 
2782
                /*
2783
                 * Check whether all value lists are exhausted and we should
2784
                 * stop the loop.
2785
                 */
2786
 
2787
                listTmpIndex = infoPtr->firstListTmp;
2788
                for (i = 0;  i < numLists;  i++) {
2789
                    varListPtr = infoPtr->varLists[i];
2790
                    numVars = varListPtr->numVars;
2791
 
2792
                    listVarPtr = &(compiledLocals[listTmpIndex]);
2793
                    listPtr = listVarPtr->value.objPtr;
2794
                    result = Tcl_ListObjLength(interp, listPtr, &listLen);
2795
                    if (result != TCL_OK) {
2796
                        TRACE_WITH_OBJ(("foreach_step4 %u => ERROR converting list %ld, \"%s\": ",
2797
                                opnd, i, O2S(listPtr)),
2798
                                Tcl_GetObjResult(interp));
2799
                        goto checkForCatch;
2800
                    }
2801
                    if (listLen > (iterNum * numVars)) {
2802
                        continueLoop = 1;
2803
                    }
2804
                    listTmpIndex++;
2805
                }
2806
 
2807
                /*
2808
                 * If some var in some var list still has a remaining list
2809
                 * element iterate one more time. Assign to var the next
2810
                 * element from its value list. We already checked above
2811
                 * that each list temp holds a valid list object.
2812
                 */
2813
 
2814
                if (continueLoop) {
2815
                    listTmpIndex = infoPtr->firstListTmp;
2816
                    for (i = 0;  i < numLists;  i++) {
2817
                        varListPtr = infoPtr->varLists[i];
2818
                        numVars = varListPtr->numVars;
2819
 
2820
                        listVarPtr = &(compiledLocals[listTmpIndex]);
2821
                        listPtr = listVarPtr->value.objPtr;
2822
                        listRepPtr = (List *)
2823
                                listPtr->internalRep.otherValuePtr;
2824
                        listLen = listRepPtr->elemCount;
2825
 
2826
                        valIndex = (iterNum * numVars);
2827
                        for (j = 0;  j < numVars;  j++) {
2828
                            int setEmptyStr = 0;
2829
                            if (valIndex >= listLen) {
2830
                                setEmptyStr = 1;
2831
                                elemPtr = Tcl_NewObj();
2832
                            } else {
2833
                                elemPtr = listRepPtr->elements[valIndex];
2834
                            }
2835
 
2836
                            varIndex = varListPtr->varIndexes[j];
2837
                            DECACHE_STACK_INFO();
2838
                            value2Ptr = TclSetIndexedScalar(interp,
2839
                                   varIndex, elemPtr, /*leaveErrorMsg*/ 1);
2840
                            CACHE_STACK_INFO();
2841
                            if (value2Ptr == NULL) {
2842
                                TRACE_WITH_OBJ(("foreach_step4 %u => ERROR init. index temp %d: ",
2843
                                       opnd, varIndex),
2844
                                       Tcl_GetObjResult(interp));
2845
                                if (setEmptyStr) {
2846
                                    Tcl_DecrRefCount(elemPtr); /* unneeded */
2847
                                }
2848
                                result = TCL_ERROR;
2849
                                goto checkForCatch;
2850
                            }
2851
                            valIndex++;
2852
                        }
2853
                        listTmpIndex++;
2854
                    }
2855
                }
2856
 
2857
                /*
2858
                 * Now push a "1" object if at least one value list had a
2859
                 * remaining element and the loop should continue.
2860
                 * Otherwise push "0".
2861
                 */
2862
 
2863
                PUSH_OBJECT(Tcl_NewLongObj(continueLoop));
2864
                TRACE(("foreach_step4 %u => %d lists, iter %d, %s loop\n",
2865
                        opnd, numLists, iterNum,
2866
                        (continueLoop? "continue" : "exit")));
2867
            }
2868
            ADJUST_PC(5);
2869
 
2870
        case INST_BEGIN_CATCH4:
2871
            /*
2872
             * Record start of the catch command with exception range index
2873
             * equal to the operand. Push the current stack depth onto the
2874
             * special catch stack.
2875
             */
2876
            catchStackPtr[++catchTop] = stackTop;
2877
            TRACE(("beginCatch4 %u => catchTop=%d, stackTop=%d\n",
2878
                    TclGetUInt4AtPtr(pc+1), catchTop, stackTop));
2879
            ADJUST_PC(5);
2880
 
2881
        case INST_END_CATCH:
2882
            catchTop--;
2883
            result = TCL_OK;
2884
            TRACE(("endCatch => catchTop=%d\n", catchTop));
2885
            ADJUST_PC(1);
2886
 
2887
        case INST_PUSH_RESULT:
2888
            PUSH_OBJECT(Tcl_GetObjResult(interp));
2889
            TRACE_WITH_OBJ(("pushResult => "), Tcl_GetObjResult(interp));
2890
            ADJUST_PC(1);
2891
 
2892
        case INST_PUSH_RETURN_CODE:
2893
            PUSH_OBJECT(Tcl_NewLongObj(result));
2894
            TRACE(("pushReturnCode => %u\n", result));
2895
            ADJUST_PC(1);
2896
 
2897
        default:
2898
            TRACE(("UNRECOGNIZED INSTRUCTION %u\n", opCode));
2899
            panic("TclExecuteByteCode: unrecognized opCode %u", opCode);
2900
        } /* end of switch on opCode */
2901
 
2902
        /*
2903
         * Division by zero in an expression. Control only reaches this
2904
         * point by "goto divideByZero".
2905
         */
2906
 
2907
        divideByZero:
2908
        Tcl_ResetResult(interp);
2909
        Tcl_AppendToObj(Tcl_GetObjResult(interp), "divide by zero", -1);
2910
        Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero",
2911
                         (char *) NULL);
2912
        result = TCL_ERROR;
2913
 
2914
        /*
2915
         * Execution has generated an "exception" such as TCL_ERROR. If the
2916
         * exception is an error, record information about what was being
2917
         * executed when the error occurred. Find the closest enclosing
2918
         * catch range, if any. If no enclosing catch range is found, stop
2919
         * execution and return the "exception" code.
2920
         */
2921
 
2922
        checkForCatch:
2923
        if ((result == TCL_ERROR) && !(iPtr->flags & ERR_ALREADY_LOGGED)) {
2924
            RecordTracebackInfo(interp, pc, codePtr);
2925
        }
2926
        rangePtr = TclGetExceptionRangeForPc(pc, /*catchOnly*/ 1, codePtr);
2927
        if (rangePtr == NULL) {
2928
            TRACE(("   ... no enclosing catch, returning %s\n",
2929
                    StringForResultCode(result)));
2930
            goto abnormalReturn;
2931
        }
2932
 
2933
        /*
2934
         * A catch exception range (rangePtr) was found to handle an
2935
         * "exception". It was found either by checkForCatch just above or
2936
         * by an instruction during break, continue, or error processing.
2937
         * Jump to its catchOffset after unwinding the operand stack to
2938
         * the depth it had when starting to execute the range's catch
2939
         * command.
2940
         */
2941
 
2942
        processCatch:
2943
        while (stackTop > catchStackPtr[catchTop]) {
2944
            valuePtr = POP_OBJECT();
2945
            TclDecrRefCount(valuePtr);
2946
        }
2947
        TRACE(("  ... found catch at %d, catchTop=%d, unwound to %d, new pc %u\n",
2948
                rangePtr->codeOffset, catchTop, catchStackPtr[catchTop],
2949
                (unsigned int)(rangePtr->catchOffset)));
2950
        pc = (codePtr->codeStart + rangePtr->catchOffset);
2951
        continue;               /* restart the execution loop at pc */
2952
    } /* end of infinite loop dispatching on instructions */
2953
 
2954
    /*
2955
     * Abnormal return code. Restore the stack to state it had when starting
2956
     * to execute the ByteCode.
2957
     */
2958
 
2959
    abnormalReturn:
2960
    while (stackTop > initStackTop) {
2961
        valuePtr = POP_OBJECT();
2962
        Tcl_DecrRefCount(valuePtr);
2963
    }
2964
 
2965
    /*
2966
     * Free the catch stack array if malloc'ed storage was used.
2967
     */
2968
 
2969
    done:
2970
    if (catchStackPtr != catchStackStorage) {
2971
        ckfree((char *) catchStackPtr);
2972
    }
2973
    eePtr->stackTop = initStackTop;
2974
    return result;
2975
#undef STATIC_CATCH_STACK_SIZE
2976
}
2977
 
2978
/*
2979
 *----------------------------------------------------------------------
2980
 *
2981
 * PrintByteCodeInfo --
2982
 *
2983
 *      This procedure prints a summary about a bytecode object to stdout.
2984
 *      It is called by TclExecuteByteCode when starting to execute the
2985
 *      bytecode object if tclTraceExec has the value 2 or more.
2986
 *
2987
 * Results:
2988
 *      None.
2989
 *
2990
 * Side effects:
2991
 *      None.
2992
 *
2993
 *----------------------------------------------------------------------
2994
 */
2995
 
2996
static void
2997
PrintByteCodeInfo(codePtr)
2998
    register ByteCode *codePtr; /* The bytecode whose summary is printed
2999
                                 * to stdout. */
3000
{
3001
    Proc *procPtr = codePtr->procPtr;
3002
    int numCmds = codePtr->numCommands;
3003
    int numObjs = codePtr->numObjects;
3004
    int objBytes, i;
3005
 
3006
    objBytes = (numObjs * sizeof(Tcl_Obj));
3007
    for (i = 0;  i < numObjs;  i++) {
3008
        Tcl_Obj *litObjPtr = codePtr->objArrayPtr[i];
3009
        if (litObjPtr->bytes != NULL) {
3010
            objBytes += litObjPtr->length;
3011
        }
3012
    }
3013
 
3014
    fprintf(stdout, "\nExecuting ByteCode 0x%x, ref ct %u, epoch %u, interp 0x%x(epoch %u)\n",
3015
            (unsigned int) codePtr, codePtr->refCount,
3016
            codePtr->compileEpoch, (unsigned int) codePtr->iPtr,
3017
            codePtr->iPtr->compileEpoch);
3018
 
3019
    fprintf(stdout, "  Source: ");
3020
    TclPrintSource(stdout, codePtr->source, 70);
3021
 
3022
    fprintf(stdout, "\n  Cmds %d, chars %d, inst %u, objs %u, aux %d, stk depth %u, code/src %.2fn",
3023
            numCmds, codePtr->numSrcChars, codePtr->numCodeBytes, numObjs,
3024
            codePtr->numAuxDataItems, codePtr->maxStackDepth,
3025
            (codePtr->numSrcChars?
3026
                    ((float)codePtr->totalSize)/((float)codePtr->numSrcChars) : 0.0));
3027
 
3028
    fprintf(stdout, "  Code %d = %d(header)+%d(inst)+%d(objs)+%d(exc)+%d(aux)+%d(cmd map)\n",
3029
            codePtr->totalSize, sizeof(ByteCode), codePtr->numCodeBytes,
3030
            objBytes, (codePtr->numExcRanges * sizeof(ExceptionRange)),
3031
            (codePtr->numAuxDataItems * sizeof(AuxData)),
3032
            codePtr->numCmdLocBytes);
3033
 
3034
    if (procPtr != NULL) {
3035
        fprintf(stdout,
3036
                "  Proc 0x%x, ref ct %d, args %d, compiled locals %d\n",
3037
                (unsigned int) procPtr, procPtr->refCount,
3038
                procPtr->numArgs, procPtr->numCompiledLocals);
3039
    }
3040
}
3041
 
3042
/*
3043
 *----------------------------------------------------------------------
3044
 *
3045
 * ValidatePcAndStackTop --
3046
 *
3047
 *      This procedure is called by TclExecuteByteCode when debugging to
3048
 *      verify that the program counter and stack top are valid during
3049
 *      execution.
3050
 *
3051
 * Results:
3052
 *      None.
3053
 *
3054
 * Side effects:
3055
 *      Prints a message to stderr and panics if either the pc or stack
3056
 *      top are invalid.
3057
 *
3058
 *----------------------------------------------------------------------
3059
 */
3060
 
3061
#ifdef TCL_COMPILE_DEBUG
3062
static void
3063
ValidatePcAndStackTop(codePtr, pc, stackTop, stackLowerBound, stackUpperBound)
3064
    register ByteCode *codePtr; /* The bytecode whose summary is printed
3065
                                 * to stdout. */
3066
    unsigned char *pc;          /* Points to first byte of a bytecode
3067
                                 * instruction. The program counter. */
3068
    int stackTop;               /* Current stack top. Must be between
3069
                                 * stackLowerBound and stackUpperBound
3070
                                 * (inclusive). */
3071
    int stackLowerBound;        /* Smallest legal value for stackTop. */
3072
    int stackUpperBound;        /* Greatest legal value for stackTop. */
3073
{
3074
    unsigned int relativePc = (unsigned int) (pc - codePtr->codeStart);
3075
    unsigned int codeStart = (unsigned int) codePtr->codeStart;
3076
    unsigned int codeEnd = (unsigned int)
3077
            (codePtr->codeStart + codePtr->numCodeBytes);
3078
    unsigned char opCode = *pc;
3079
 
3080
    if (((unsigned int) pc < codeStart) || ((unsigned int) pc > codeEnd)) {
3081
        fprintf(stderr, "\nBad instruction pc 0x%x in TclExecuteByteCode\n",
3082
                (unsigned int) pc);
3083
        panic("TclExecuteByteCode execution failure: bad pc");
3084
    }
3085
    if ((unsigned int) opCode > LAST_INST_OPCODE) {
3086
        fprintf(stderr, "\nBad opcode %d at pc %u in TclExecuteByteCode\n",
3087
                (unsigned int) opCode, relativePc);
3088
        panic("TclExecuteByteCode execution failure: bad opcode");
3089
    }
3090
    if ((stackTop < stackLowerBound) || (stackTop > stackUpperBound)) {
3091
        int numChars;
3092
        char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars);
3093
        char *ellipsis = "";
3094
 
3095
        fprintf(stderr, "\nBad stack top %d at pc %u in TclExecuteByteCode",
3096
                stackTop, relativePc);
3097
        if (cmd != NULL) {
3098
            if (numChars > 100) {
3099
                numChars = 100;
3100
                ellipsis = "...";
3101
            }
3102
            fprintf(stderr, "\n executing %.*s%s\n", numChars, cmd,
3103
                    ellipsis);
3104
        } else {
3105
            fprintf(stderr, "\n");
3106
        }
3107
        panic("TclExecuteByteCode execution failure: bad stack top");
3108
    }
3109
}
3110
#endif /* TCL_COMPILE_DEBUG */
3111
 
3112
/*
3113
 *----------------------------------------------------------------------
3114
 *
3115
 * IllegalExprOperandType --
3116
 *
3117
 *      Used by TclExecuteByteCode to add an error message to errorInfo
3118
 *      when an illegal operand type is detected by an expression
3119
 *      instruction. The argument opCode holds the failing instruction's
3120
 *      opcode and opndPtr holds the operand object in error.
3121
 *
3122
 * Results:
3123
 *      None.
3124
 *
3125
 * Side effects:
3126
 *      An error message is appended to errorInfo.
3127
 *
3128
 *----------------------------------------------------------------------
3129
 */
3130
 
3131
static void
3132
IllegalExprOperandType(interp, opCode, opndPtr)
3133
    Tcl_Interp *interp;         /* Interpreter to which error information
3134
                                 * pertains. */
3135
    unsigned int opCode;        /* The instruction opcode being executed
3136
                                 * when the illegal type was found. */
3137
    Tcl_Obj *opndPtr;           /* Points to the operand holding the value
3138
                                 * with the illegal type. */
3139
{
3140
    Tcl_ResetResult(interp);
3141
    if ((opndPtr->bytes == NULL) || (opndPtr->length == 0)) {
3142
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
3143
                "can't use empty string as operand of \"",
3144
                operatorStrings[opCode - INST_LOR], "\"", (char *) NULL);
3145
    } else {
3146
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't use ",
3147
                ((opndPtr->typePtr == &tclDoubleType) ?
3148
                    "floating-point value" : "non-numeric string"),
3149
                " as operand of \"", operatorStrings[opCode - INST_LOR],
3150
                "\"", (char *) NULL);
3151
    }
3152
}
3153
 
3154
/*
3155
 *----------------------------------------------------------------------
3156
 *
3157
 * CallTraceProcedure --
3158
 *
3159
 *      Invokes a trace procedure registered with an interpreter. These
3160
 *      procedures trace command execution. Currently this trace procedure
3161
 *      is called with the address of the string-based Tcl_CmdProc for the
3162
 *      command, not the Tcl_ObjCmdProc.
3163
 *
3164
 * Results:
3165
 *      None.
3166
 *
3167
 * Side effects:
3168
 *      Those side effects made by the trace procedure.
3169
 *
3170
 *----------------------------------------------------------------------
3171
 */
3172
 
3173
static void
3174
CallTraceProcedure(interp, tracePtr, cmdPtr, command, numChars, objc, objv)
3175
    Tcl_Interp *interp;         /* The current interpreter. */
3176
    register Trace *tracePtr;   /* Describes the trace procedure to call. */
3177
    Command *cmdPtr;            /* Points to command's Command struct. */
3178
    char *command;              /* Points to the first character of the
3179
                                 * command's source before substitutions. */
3180
    int numChars;               /* The number of characters in the
3181
                                 * command's source. */
3182
    register int objc;          /* Number of arguments for the command. */
3183
    Tcl_Obj *objv[];            /* Pointers to Tcl_Obj of each argument. */
3184
{
3185
    Interp *iPtr = (Interp *) interp;
3186
    register char **argv;
3187
    register int i;
3188
    int length;
3189
    char *p;
3190
 
3191
    /*
3192
     * Get the string rep from the objv argument objects and place their
3193
     * pointers in argv. First make sure argv is large enough to hold the
3194
     * objc args plus 1 extra word for the zero end-of-argv word.
3195
     * THIS FAILS IF AN OBJECT'S STRING REP CONTAINS NULLS.
3196
     */
3197
 
3198
    argv = (char **) ckalloc((unsigned)(objc + 1) * sizeof(char *));
3199
    for (i = 0;  i < objc;  i++) {
3200
        argv[i] = Tcl_GetStringFromObj(objv[i], &length);
3201
    }
3202
    argv[objc] = 0;
3203
 
3204
    /*
3205
     * Copy the command characters into a new string.
3206
     */
3207
 
3208
    p = (char *) ckalloc((unsigned) (numChars + 1));
3209
    memcpy((VOID *) p, (VOID *) command, (size_t) numChars);
3210
    p[numChars] = '\0';
3211
 
3212
    /*
3213
     * Call the trace procedure then free allocated storage.
3214
     */
3215
 
3216
    (*tracePtr->proc)(tracePtr->clientData, interp, iPtr->numLevels,
3217
                      p, cmdPtr->proc, cmdPtr->clientData, objc, argv);
3218
 
3219
    ckfree((char *) argv);
3220
    ckfree((char *) p);
3221
}
3222
 
3223
/*
3224
 *----------------------------------------------------------------------
3225
 *
3226
 * RecordTracebackInfo --
3227
 *
3228
 *      Procedure called by TclExecuteByteCode to record information
3229
 *      about what was being executed when the error occurred.
3230
 *
3231
 * Results:
3232
 *      None.
3233
 *
3234
 * Side effects:
3235
 *      Appends information about the command being executed to the
3236
 *      "errorInfo" variable. Sets the errorLine field in the interpreter
3237
 *      to the line number of that command. Sets the ERR_ALREADY_LOGGED
3238
 *      bit in the interpreter's execution flags.
3239
 *
3240
 *----------------------------------------------------------------------
3241
 */
3242
 
3243
static void
3244
RecordTracebackInfo(interp, pc, codePtr)
3245
    Tcl_Interp *interp;         /* The interpreter in which the error
3246
                                 * occurred. */
3247
    unsigned char *pc;          /* The program counter value where the error                                 * occurred. This points to a bytecode
3248
                                 * instruction in codePtr's code. */
3249
    ByteCode *codePtr;          /* The bytecode sequence being executed. */
3250
{
3251
    register Interp *iPtr = (Interp *) interp;
3252
    char *cmd, *ellipsis;
3253
    char buf[200];
3254
    register char *p;
3255
    int numChars;
3256
 
3257
    /*
3258
     * Record the command in errorInfo (up to a certain number of
3259
     * characters, or up to the first newline).
3260
     */
3261
 
3262
    iPtr->errorLine = 1;
3263
    cmd = GetSrcInfoForPc(pc, codePtr, &numChars);
3264
    if (cmd != NULL) {
3265
        for (p = codePtr->source;  p != cmd;  p++) {
3266
            if (*p == '\n') {
3267
                iPtr->errorLine++;
3268
            }
3269
        }
3270
        for ( ;  (isspace(UCHAR(*p)) || (*p == ';'));  p++) {
3271
            if (*p == '\n') {
3272
                iPtr->errorLine++;
3273
            }
3274
        }
3275
 
3276
        ellipsis = "";
3277
        if (numChars > 150) {
3278
            numChars = 150;
3279
            ellipsis = "...";
3280
        }
3281
        if (!(iPtr->flags & ERR_IN_PROGRESS)) {
3282
            sprintf(buf, "\n    while executing\n\"%.*s%s\"",
3283
                    numChars, cmd, ellipsis);
3284
        } else {
3285
            sprintf(buf, "\n    invoked from within\n\"%.*s%s\"",
3286
                    numChars, cmd, ellipsis);
3287
        }
3288
        Tcl_AddObjErrorInfo(interp, buf, -1);
3289
        iPtr->flags |= ERR_ALREADY_LOGGED;
3290
    }
3291
}
3292
 
3293
/*
3294
 *----------------------------------------------------------------------
3295
 *
3296
 * GetSrcInfoForPc --
3297
 *
3298
 *      Given a program counter value, finds the closest command in the
3299
 *      bytecode code unit's CmdLocation array and returns information about
3300
 *      that command's source: a pointer to its first byte and the number of
3301
 *      characters.
3302
 *
3303
 * Results:
3304
 *      If a command is found that encloses the program counter value, a
3305
 *      pointer to the command's source is returned and the length of the
3306
 *      source is stored at *lengthPtr. If multiple commands resulted in
3307
 *      code at pc, information about the closest enclosing command is
3308
 *      returned. If no matching command is found, NULL is returned and
3309
 *      *lengthPtr is unchanged.
3310
 *
3311
 * Side effects:
3312
 *      None.
3313
 *
3314
 *----------------------------------------------------------------------
3315
 */
3316
 
3317
static char *
3318
GetSrcInfoForPc(pc, codePtr, lengthPtr)
3319
    unsigned char *pc;          /* The program counter value for which to
3320
                                 * return the closest command's source info.
3321
                                 * This points to a bytecode instruction
3322
                                 * in codePtr's code. */
3323
    ByteCode *codePtr;          /* The bytecode sequence in which to look
3324
                                 * up the command source for the pc. */
3325
    int *lengthPtr;             /* If non-NULL, the location where the
3326
                                 * length of the command's source should be
3327
                                 * stored. If NULL, no length is stored. */
3328
{
3329
    register int pcOffset = (pc - codePtr->codeStart);
3330
    int numCmds = codePtr->numCommands;
3331
    unsigned char *codeDeltaNext, *codeLengthNext;
3332
    unsigned char *srcDeltaNext, *srcLengthNext;
3333
    int codeOffset, codeLen, codeEnd, srcOffset, srcLen, delta, i;
3334
    int bestDist = INT_MAX;     /* Distance of pc to best cmd's start pc. */
3335
    int bestSrcOffset = -1;     /* Initialized to avoid compiler warning. */
3336
    int bestSrcLength = -1;     /* Initialized to avoid compiler warning. */
3337
 
3338
    if ((pcOffset < 0) || (pcOffset >= codePtr->numCodeBytes)) {
3339
        return NULL;
3340
    }
3341
 
3342
    /*
3343
     * Decode the code and source offset and length for each command. The
3344
     * closest enclosing command is the last one whose code started before
3345
     * pcOffset.
3346
     */
3347
 
3348
    codeDeltaNext = codePtr->codeDeltaStart;
3349
    codeLengthNext = codePtr->codeLengthStart;
3350
    srcDeltaNext  = codePtr->srcDeltaStart;
3351
    srcLengthNext = codePtr->srcLengthStart;
3352
    codeOffset = srcOffset = 0;
3353
    for (i = 0;  i < numCmds;  i++) {
3354
        if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
3355
            codeDeltaNext++;
3356
            delta = TclGetInt4AtPtr(codeDeltaNext);
3357
            codeDeltaNext += 4;
3358
        } else {
3359
            delta = TclGetInt1AtPtr(codeDeltaNext);
3360
            codeDeltaNext++;
3361
        }
3362
        codeOffset += delta;
3363
 
3364
        if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) {
3365
            codeLengthNext++;
3366
            codeLen = TclGetInt4AtPtr(codeLengthNext);
3367
            codeLengthNext += 4;
3368
        } else {
3369
            codeLen = TclGetInt1AtPtr(codeLengthNext);
3370
            codeLengthNext++;
3371
        }
3372
        codeEnd = (codeOffset + codeLen - 1);
3373
 
3374
        if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
3375
            srcDeltaNext++;
3376
            delta = TclGetInt4AtPtr(srcDeltaNext);
3377
            srcDeltaNext += 4;
3378
        } else {
3379
            delta = TclGetInt1AtPtr(srcDeltaNext);
3380
            srcDeltaNext++;
3381
        }
3382
        srcOffset += delta;
3383
 
3384
        if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
3385
            srcLengthNext++;
3386
            srcLen = TclGetInt4AtPtr(srcLengthNext);
3387
            srcLengthNext += 4;
3388
        } else {
3389
            srcLen = TclGetInt1AtPtr(srcLengthNext);
3390
            srcLengthNext++;
3391
        }
3392
 
3393
        if (codeOffset > pcOffset) {      /* best cmd already found */
3394
            break;
3395
        } else if (pcOffset <= codeEnd) { /* this cmd's code encloses pc */
3396
            int dist = (pcOffset - codeOffset);
3397
            if (dist <= bestDist) {
3398
                bestDist = dist;
3399
                bestSrcOffset = srcOffset;
3400
                bestSrcLength = srcLen;
3401
            }
3402
        }
3403
    }
3404
 
3405
    if (bestDist == INT_MAX) {
3406
        return NULL;
3407
    }
3408
 
3409
    if (lengthPtr != NULL) {
3410
        *lengthPtr = bestSrcLength;
3411
    }
3412
    return (codePtr->source + bestSrcOffset);
3413
}
3414
 
3415
/*
3416
 *----------------------------------------------------------------------
3417
 *
3418
 * TclGetExceptionRangeForPc --
3419
 *
3420
 *      Procedure that given a program counter value, returns the closest
3421
 *      enclosing ExceptionRange that matches the kind requested.
3422
 *
3423
 * Results:
3424
 *      In the normal case, catchOnly is 0 (false) and this procedure
3425
 *      returns a pointer to the most closely enclosing ExceptionRange
3426
 *      structure regardless of whether it is a loop or catch exception
3427
 *      range. This is appropriate when processing a TCL_BREAK or
3428
 *      TCL_CONTINUE, which will be "handled" either by a loop exception
3429
 *      range or a closer catch range. If catchOnly is nonzero (true), this
3430
 *      procedure ignores loop exception ranges and returns a pointer to the
3431
 *      closest catch range. If no matching ExceptionRange is found that
3432
 *      encloses pc, a NULL is returned.
3433
 *
3434
 * Side effects:
3435
 *      None.
3436
 *
3437
 *----------------------------------------------------------------------
3438
 */
3439
 
3440
ExceptionRange *
3441
TclGetExceptionRangeForPc(pc, catchOnly, codePtr)
3442
    unsigned char *pc;          /* The program counter value for which to
3443
                                 * search for a closest enclosing exception
3444
                                 * range. This points to a bytecode
3445
                                 * instruction in codePtr's code. */
3446
    int catchOnly;              /* If 0, consider either loop or catch
3447
                                 * ExceptionRanges in search. Otherwise
3448
                                 * consider only catch ranges (and ignore
3449
                                 * any closer loop ranges). */
3450
    ByteCode* codePtr;          /* Points to the ByteCode in which to search
3451
                                 * for the enclosing ExceptionRange. */
3452
{
3453
    ExceptionRange *rangeArrayPtr = codePtr->excRangeArrayPtr;
3454
    int numRanges = codePtr->numExcRanges;
3455
    register ExceptionRange *rangePtr;
3456
    int codeOffset = (pc - codePtr->codeStart);
3457
    register int i, level;
3458
 
3459
    for (level = codePtr->maxExcRangeDepth;  level >= 0;  level--) {
3460
        for (i = 0;  i < numRanges;  i++) {
3461
            rangePtr = &(rangeArrayPtr[i]);
3462
            if (rangePtr->nestingLevel == level) {
3463
                int start = rangePtr->codeOffset;
3464
                int end   = (start + rangePtr->numCodeBytes);
3465
                if ((start <= codeOffset) && (codeOffset < end)) {
3466
                    if ((!catchOnly)
3467
                            || (rangePtr->type == CATCH_EXCEPTION_RANGE)) {
3468
                        return rangePtr;
3469
                    }
3470
                }
3471
            }
3472
        }
3473
    }
3474
    return NULL;
3475
}
3476
 
3477
/*
3478
 *----------------------------------------------------------------------
3479
 *
3480
 * Math Functions --
3481
 *
3482
 *      This page contains the procedures that implement all of the
3483
 *      built-in math functions for expressions.
3484
 *
3485
 * Results:
3486
 *      Each procedure returns TCL_OK if it succeeds and pushes an
3487
 *      Tcl object holding the result. If it fails it returns TCL_ERROR
3488
 *      and leaves an error message in the interpreter's result.
3489
 *
3490
 * Side effects:
3491
 *      None.
3492
 *
3493
 *----------------------------------------------------------------------
3494
 */
3495
 
3496
static int
3497
ExprUnaryFunc(interp, eePtr, clientData)
3498
    Tcl_Interp *interp;         /* The interpreter in which to execute the
3499
                                 * function. */
3500
    ExecEnv *eePtr;             /* Points to the environment for executing
3501
                                 * the function. */
3502
    ClientData clientData;      /* Contains the address of a procedure that
3503
                                 * takes one double argument and returns a
3504
                                 * double result. */
3505
{
3506
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
3507
    register int stackTop;      /* Cached top index of evaluation stack. */
3508
    register Tcl_Obj *valuePtr;
3509
    Tcl_ObjType *tPtr;
3510
    double d, dResult;
3511
    long i;
3512
    int result = TCL_OK;
3513
 
3514
    double (*func) _ANSI_ARGS_((double)) =
3515
        (double (*)_ANSI_ARGS_((double))) clientData;
3516
 
3517
    /*
3518
     * Set stackPtr and stackTop from eePtr.
3519
     */
3520
 
3521
    CACHE_STACK_INFO();
3522
 
3523
    /*
3524
     * Pop the function's argument from the evaluation stack. Convert it
3525
     * to a double if necessary.
3526
     */
3527
 
3528
    valuePtr = POP_OBJECT();
3529
    tPtr = valuePtr->typePtr;
3530
 
3531
    if (tPtr == &tclIntType) {
3532
        d = (double) valuePtr->internalRep.longValue;
3533
    } else if (tPtr == &tclDoubleType) {
3534
        d = valuePtr->internalRep.doubleValue;
3535
    } else {                    /* FAILS IF STRING REP HAS NULLS */
3536
        char *s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
3537
 
3538
        if (TclLooksLikeInt(s)) {
3539
            result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, valuePtr, &i);
3540
            d = (double) valuePtr->internalRep.longValue;
3541
        } else {
3542
            result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d);
3543
        }
3544
        if (result != TCL_OK) {
3545
            Tcl_ResetResult(interp);
3546
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
3547
                    "argument to math function didn't have numeric value", -1);
3548
            goto done;
3549
        }
3550
    }
3551
 
3552
    errno = 0;
3553
    dResult = (*func)(d);
3554
    if ((errno != 0) || IS_NAN(dResult) || IS_INF(dResult)) {
3555
        TclExprFloatError(interp, dResult);
3556
        result = TCL_ERROR;
3557
        goto done;
3558
    }
3559
 
3560
    /*
3561
     * Push a Tcl object holding the result.
3562
     */
3563
 
3564
    PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
3565
 
3566
    /*
3567
     * Reflect the change to stackTop back in eePtr.
3568
     */
3569
 
3570
    done:
3571
    Tcl_DecrRefCount(valuePtr);
3572
    DECACHE_STACK_INFO();
3573
    return result;
3574
}
3575
 
3576
static int
3577
ExprBinaryFunc(interp, eePtr, clientData)
3578
    Tcl_Interp *interp;         /* The interpreter in which to execute the
3579
                                 * function. */
3580
    ExecEnv *eePtr;             /* Points to the environment for executing
3581
                                 * the function. */
3582
    ClientData clientData;      /* Contains the address of a procedure that
3583
                                 * takes two double arguments and
3584
                                 * returns a double result. */
3585
{
3586
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
3587
    register int stackTop;      /* Cached top index of evaluation stack. */
3588
    register Tcl_Obj *valuePtr, *value2Ptr;
3589
    Tcl_ObjType *tPtr;
3590
    double d1, d2, dResult;
3591
    long i;
3592
    char *s;
3593
    int result = TCL_OK;
3594
 
3595
    double (*func) _ANSI_ARGS_((double, double))
3596
        = (double (*)_ANSI_ARGS_((double, double))) clientData;
3597
 
3598
    /*
3599
     * Set stackPtr and stackTop from eePtr.
3600
     */
3601
 
3602
    CACHE_STACK_INFO();
3603
 
3604
    /*
3605
     * Pop the function's two arguments from the evaluation stack. Convert
3606
     * them to doubles if necessary.
3607
     */
3608
 
3609
    value2Ptr = POP_OBJECT();
3610
    valuePtr  = POP_OBJECT();
3611
 
3612
    tPtr = valuePtr->typePtr;
3613
    if (tPtr == &tclIntType) {
3614
        d1 = (double) valuePtr->internalRep.longValue;
3615
    } else if (tPtr == &tclDoubleType) {
3616
        d1 = valuePtr->internalRep.doubleValue;
3617
    } else {                    /* FAILS IF STRING REP HAS NULLS */
3618
        s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
3619
        if (TclLooksLikeInt(s)) {
3620
            result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, valuePtr, &i);
3621
            d1 = (double) valuePtr->internalRep.longValue;
3622
        } else {
3623
            result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d1);
3624
        }
3625
        if (result != TCL_OK) {
3626
            badArg:
3627
            Tcl_ResetResult(interp);
3628
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
3629
                    "argument to math function didn't have numeric value", -1);
3630
            goto done;
3631
        }
3632
    }
3633
 
3634
    tPtr = value2Ptr->typePtr;
3635
    if (tPtr == &tclIntType) {
3636
        d2 = value2Ptr->internalRep.longValue;
3637
    } else if (tPtr == &tclDoubleType) {
3638
        d2 = value2Ptr->internalRep.doubleValue;
3639
    } else {                    /* FAILS IF STRING REP HAS NULLS */
3640
        s = Tcl_GetStringFromObj(value2Ptr, (int *) NULL);
3641
        if (TclLooksLikeInt(s)) {
3642
            result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, value2Ptr, &i);
3643
            d2 = (double) value2Ptr->internalRep.longValue;
3644
        } else {
3645
            result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, value2Ptr, &d2);
3646
        }
3647
        if (result != TCL_OK) {
3648
            goto badArg;
3649
        }
3650
    }
3651
 
3652
    errno = 0;
3653
    dResult = (*func)(d1, d2);
3654
    if ((errno != 0) || IS_NAN(dResult) || IS_INF(dResult)) {
3655
        TclExprFloatError(interp, dResult);
3656
        result = TCL_ERROR;
3657
        goto done;
3658
    }
3659
 
3660
    /*
3661
     * Push a Tcl object holding the result.
3662
     */
3663
 
3664
    PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
3665
 
3666
    /*
3667
     * Reflect the change to stackTop back in eePtr.
3668
     */
3669
 
3670
    done:
3671
    Tcl_DecrRefCount(valuePtr);
3672
    Tcl_DecrRefCount(value2Ptr);
3673
    DECACHE_STACK_INFO();
3674
    return result;
3675
}
3676
 
3677
static int
3678
ExprAbsFunc(interp, eePtr, clientData)
3679
    Tcl_Interp *interp;         /* The interpreter in which to execute the
3680
                                 * function. */
3681
    ExecEnv *eePtr;             /* Points to the environment for executing
3682
                                 * the function. */
3683
    ClientData clientData;      /* Ignored. */
3684
{
3685
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
3686
    register int stackTop;      /* Cached top index of evaluation stack. */
3687
    register Tcl_Obj *valuePtr;
3688
    Tcl_ObjType *tPtr;
3689
    long i, iResult;
3690
    double d, dResult;
3691
    int result = TCL_OK;
3692
 
3693
    /*
3694
     * Set stackPtr and stackTop from eePtr.
3695
     */
3696
 
3697
    CACHE_STACK_INFO();
3698
 
3699
    /*
3700
     * Pop the argument from the evaluation stack.
3701
     */
3702
 
3703
    valuePtr = POP_OBJECT();
3704
    tPtr = valuePtr->typePtr;
3705
 
3706
    if (tPtr == &tclIntType) {
3707
        i = valuePtr->internalRep.longValue;
3708
    } else if (tPtr == &tclDoubleType) {
3709
        d = valuePtr->internalRep.doubleValue;
3710
    } else {                    /* FAILS IF STRING REP HAS NULLS */
3711
        char *s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
3712
 
3713
        if (TclLooksLikeInt(s)) {
3714
            result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, valuePtr, &i);
3715
        } else {
3716
            result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d);
3717
        }
3718
        if (result != TCL_OK) {
3719
            Tcl_ResetResult(interp);
3720
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
3721
                    "argument to math function didn't have numeric value", -1);
3722
            goto done;
3723
        }
3724
        tPtr = valuePtr->typePtr;
3725
    }
3726
 
3727
    /*
3728
     * Push a Tcl object with the result.
3729
     */
3730
 
3731
    if (tPtr == &tclIntType) {
3732
        if (i < 0) {
3733
            iResult = -i;
3734
            if (iResult < 0) {
3735
                Tcl_ResetResult(interp);
3736
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
3737
                        "integer value too large to represent", -1);
3738
                Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
3739
                        "integer value too large to represent", (char *) NULL);
3740
                result = TCL_ERROR;
3741
                goto done;
3742
            }
3743
        } else {
3744
            iResult = i;
3745
        }
3746
        PUSH_OBJECT(Tcl_NewLongObj(iResult));
3747
    } else {
3748
        if (d < 0.0) {
3749
            dResult = -d;
3750
        } else {
3751
            dResult = d;
3752
        }
3753
        if (IS_NAN(dResult) || IS_INF(dResult)) {
3754
            TclExprFloatError(interp, dResult);
3755
            result = TCL_ERROR;
3756
            goto done;
3757
        }
3758
        PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
3759
    }
3760
 
3761
    /*
3762
     * Reflect the change to stackTop back in eePtr.
3763
     */
3764
 
3765
    done:
3766
    Tcl_DecrRefCount(valuePtr);
3767
    DECACHE_STACK_INFO();
3768
    return result;
3769
}
3770
 
3771
static int
3772
ExprDoubleFunc(interp, eePtr, clientData)
3773
    Tcl_Interp *interp;         /* The interpreter in which to execute the
3774
                                 * function. */
3775
    ExecEnv *eePtr;             /* Points to the environment for executing
3776
                                 * the function. */
3777
    ClientData clientData;      /* Ignored. */
3778
{
3779
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
3780
    register int stackTop;      /* Cached top index of evaluation stack. */
3781
    register Tcl_Obj *valuePtr;
3782
    double dResult;
3783
    long i;
3784
    int result = TCL_OK;
3785
 
3786
    /*
3787
     * Set stackPtr and stackTop from eePtr.
3788
     */
3789
 
3790
    CACHE_STACK_INFO();
3791
 
3792
    /*
3793
     * Pop the argument from the evaluation stack.
3794
     */
3795
 
3796
    valuePtr = POP_OBJECT();
3797
    if (valuePtr->typePtr == &tclIntType) {
3798
        dResult = (double) valuePtr->internalRep.longValue;
3799
    } else if (valuePtr->typePtr == &tclDoubleType) {
3800
        dResult = valuePtr->internalRep.doubleValue;
3801
    } else {                    /* FAILS IF STRING REP HAS NULLS */
3802
        char *s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
3803
 
3804
        if (TclLooksLikeInt(s)) {
3805
            result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, valuePtr, &i);
3806
            dResult = (double) valuePtr->internalRep.longValue;
3807
        } else {
3808
            result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr,
3809
                    &dResult);
3810
        }
3811
        if (result != TCL_OK) {
3812
            Tcl_ResetResult(interp);
3813
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
3814
                    "argument to math function didn't have numeric value", -1);
3815
            goto done;
3816
        }
3817
    }
3818
 
3819
    /*
3820
     * Push a Tcl object with the result.
3821
     */
3822
 
3823
    PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
3824
 
3825
    /*
3826
     * Reflect the change to stackTop back in eePtr.
3827
     */
3828
 
3829
    done:
3830
    Tcl_DecrRefCount(valuePtr);
3831
    DECACHE_STACK_INFO();
3832
    return result;
3833
}
3834
 
3835
static int
3836
ExprIntFunc(interp, eePtr, clientData)
3837
    Tcl_Interp *interp;         /* The interpreter in which to execute the
3838
                                 * function. */
3839
    ExecEnv *eePtr;             /* Points to the environment for executing
3840
                                 * the function. */
3841
    ClientData clientData;      /* Ignored. */
3842
{
3843
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
3844
    register int stackTop;      /* Cached top index of evaluation stack. */
3845
    register Tcl_Obj *valuePtr;
3846
    Tcl_ObjType *tPtr;
3847
    long i = 0;                  /* Initialized to avoid compiler warning. */
3848
    long iResult;
3849
    double d;
3850
    int result = TCL_OK;
3851
 
3852
    /*
3853
     * Set stackPtr and stackTop from eePtr.
3854
     */
3855
 
3856
    CACHE_STACK_INFO();
3857
 
3858
    /*
3859
     * Pop the argument from the evaluation stack.
3860
     */
3861
 
3862
    valuePtr = POP_OBJECT();
3863
    tPtr = valuePtr->typePtr;
3864
 
3865
    if (tPtr == &tclIntType) {
3866
        i = valuePtr->internalRep.longValue;
3867
    } else if (tPtr == &tclDoubleType) {
3868
        d = valuePtr->internalRep.doubleValue;
3869
    } else {                    /* FAILS IF STRING REP HAS NULLS */
3870
        char *s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
3871
 
3872
        if (TclLooksLikeInt(s)) {
3873
            result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, valuePtr, &i);
3874
        } else {
3875
            result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d);
3876
        }
3877
        if (result != TCL_OK) {
3878
            Tcl_ResetResult(interp);
3879
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
3880
                    "argument to math function didn't have numeric value", -1);
3881
            goto done;
3882
        }
3883
        tPtr = valuePtr->typePtr;
3884
    }
3885
 
3886
    /*
3887
     * Push a Tcl object with the result.
3888
     */
3889
 
3890
    if (tPtr == &tclIntType) {
3891
        iResult = i;
3892
    } else {
3893
        if (d < 0.0) {
3894
            if (d < (double) (long) LONG_MIN) {
3895
                tooLarge:
3896
                Tcl_ResetResult(interp);
3897
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
3898
                        "integer value too large to represent", -1);
3899
                Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
3900
                        "integer value too large to represent", (char *) NULL);
3901
                result = TCL_ERROR;
3902
                goto done;
3903
            }
3904
        } else {
3905
            if (d > (double) LONG_MAX) {
3906
                goto tooLarge;
3907
            }
3908
        }
3909
        if (IS_NAN(d) || IS_INF(d)) {
3910
            TclExprFloatError(interp, d);
3911
            result = TCL_ERROR;
3912
            goto done;
3913
        }
3914
        iResult = (long) d;
3915
    }
3916
    PUSH_OBJECT(Tcl_NewLongObj(iResult));
3917
 
3918
    /*
3919
     * Reflect the change to stackTop back in eePtr.
3920
     */
3921
 
3922
    done:
3923
    Tcl_DecrRefCount(valuePtr);
3924
    DECACHE_STACK_INFO();
3925
    return result;
3926
}
3927
 
3928
static int
3929
ExprRandFunc(interp, eePtr, clientData)
3930
    Tcl_Interp *interp;         /* The interpreter in which to execute the
3931
                                 * function. */
3932
    ExecEnv *eePtr;             /* Points to the environment for executing
3933
                                 * the function. */
3934
    ClientData clientData;      /* Ignored. */
3935
{
3936
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
3937
    register int stackTop;      /* Cached top index of evaluation stack. */
3938
    Interp *iPtr = (Interp *) interp;
3939
    double dResult;
3940
    int tmp;
3941
 
3942
    if (!(iPtr->flags & RAND_SEED_INITIALIZED)) {
3943
        iPtr->flags |= RAND_SEED_INITIALIZED;
3944
        iPtr->randSeed = TclpGetClicks();
3945
    }
3946
 
3947
    /*
3948
     * Set stackPtr and stackTop from eePtr.
3949
     */
3950
 
3951
    CACHE_STACK_INFO();
3952
 
3953
    /*
3954
     * Generate the random number using the linear congruential
3955
     * generator defined by the following recurrence:
3956
     *          seed = ( IA * seed ) mod IM
3957
     * where IA is 16807 and IM is (2^31) - 1.  In order to avoid
3958
     * potential problems with integer overflow, the  code uses
3959
     * additional constants IQ and IR such that
3960
     *          IM = IA*IQ + IR
3961
     * For details on how this algorithm works, refer to the following
3962
     * papers:
3963
     *
3964
     *  S.K. Park & K.W. Miller, "Random number generators: good ones
3965
     *  are hard to find," Comm ACM 31(10):1192-1201, Oct 1988
3966
     *
3967
     *  W.H. Press & S.A. Teukolsky, "Portable random number
3968
     *  generators," Computers in Physics 6(5):522-524, Sep/Oct 1992.
3969
     */
3970
 
3971
#define RAND_IA         16807
3972
#define RAND_IM         2147483647
3973
#define RAND_IQ         127773
3974
#define RAND_IR         2836
3975
#define RAND_MASK       123459876
3976
 
3977
    if (iPtr->randSeed == 0) {
3978
        /*
3979
         * Don't allow a 0 seed, since it breaks the generator.  Shift
3980
         * it to some other value.
3981
         */
3982
 
3983
        iPtr->randSeed = 123459876;
3984
    }
3985
    tmp = iPtr->randSeed/RAND_IQ;
3986
    iPtr->randSeed = RAND_IA*(iPtr->randSeed - tmp*RAND_IQ) - RAND_IR*tmp;
3987
    if (iPtr->randSeed < 0) {
3988
        iPtr->randSeed += RAND_IM;
3989
    }
3990
 
3991
    /*
3992
     * On 64-bit architectures we need to mask off the upper bits to
3993
     * ensure we only have a 32-bit range.  The constant has the
3994
     * bizarre form below in order to make sure that it doesn't
3995
     * get sign-extended (the rules for sign extension are very
3996
     * concat, particularly on 64-bit machines).
3997
     */
3998
 
3999
    iPtr->randSeed &= ((((unsigned long) 0xfffffff) << 4) | 0xf);
4000
    dResult = iPtr->randSeed * (1.0/RAND_IM);
4001
 
4002
    /*
4003
     * Push a Tcl object with the result.
4004
     */
4005
 
4006
    PUSH_OBJECT(Tcl_NewDoubleObj(dResult));
4007
 
4008
    /*
4009
     * Reflect the change to stackTop back in eePtr.
4010
     */
4011
 
4012
    DECACHE_STACK_INFO();
4013
    return TCL_OK;
4014
}
4015
 
4016
static int
4017
ExprRoundFunc(interp, eePtr, clientData)
4018
    Tcl_Interp *interp;         /* The interpreter in which to execute the
4019
                                 * function. */
4020
    ExecEnv *eePtr;             /* Points to the environment for executing
4021
                                 * the function. */
4022
    ClientData clientData;      /* Ignored. */
4023
{
4024
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
4025
    register int stackTop;      /* Cached top index of evaluation stack. */
4026
    Tcl_Obj *valuePtr;
4027
    Tcl_ObjType *tPtr;
4028
    long i = 0;                  /* Initialized to avoid compiler warning. */
4029
    long iResult;
4030
    double d, temp;
4031
    int result = TCL_OK;
4032
 
4033
    /*
4034
     * Set stackPtr and stackTop from eePtr.
4035
     */
4036
 
4037
    CACHE_STACK_INFO();
4038
 
4039
    /*
4040
     * Pop the argument from the evaluation stack.
4041
     */
4042
 
4043
    valuePtr = POP_OBJECT();
4044
    tPtr = valuePtr->typePtr;
4045
 
4046
    if (tPtr == &tclIntType) {
4047
        i = valuePtr->internalRep.longValue;
4048
    } else if (tPtr == &tclDoubleType) {
4049
        d = valuePtr->internalRep.doubleValue;
4050
    } else {                    /* FAILS IF STRING REP HAS NULLS */
4051
        char *s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
4052
 
4053
        if (TclLooksLikeInt(s)) {
4054
            result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, valuePtr, &i);
4055
        } else {
4056
            result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL, valuePtr, &d);
4057
        }
4058
        if (result != TCL_OK) {
4059
            Tcl_ResetResult(interp);
4060
            Tcl_AppendToObj(Tcl_GetObjResult(interp),
4061
                    "argument to math function didn't have numeric value", -1);
4062
            goto done;
4063
        }
4064
        tPtr = valuePtr->typePtr;
4065
    }
4066
 
4067
    /*
4068
     * Push a Tcl object with the result.
4069
     */
4070
 
4071
    if (tPtr == &tclIntType) {
4072
        iResult = i;
4073
    } else {
4074
        if (d < 0.0) {
4075
            if (d <= (((double) (long) LONG_MIN) - 0.5)) {
4076
                tooLarge:
4077
                Tcl_ResetResult(interp);
4078
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
4079
                        "integer value too large to represent", -1);
4080
                Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
4081
                        "integer value too large to represent",
4082
                        (char *) NULL);
4083
                result = TCL_ERROR;
4084
                goto done;
4085
            }
4086
            temp = (long) (d - 0.5);
4087
        } else {
4088
            if (d >= (((double) LONG_MAX + 0.5))) {
4089
                goto tooLarge;
4090
            }
4091
            temp = (long) (d + 0.5);
4092
        }
4093
        if (IS_NAN(temp) || IS_INF(temp)) {
4094
            TclExprFloatError(interp, temp);
4095
            result = TCL_ERROR;
4096
            goto done;
4097
        }
4098
        iResult = (long) temp;
4099
    }
4100
    PUSH_OBJECT(Tcl_NewLongObj(iResult));
4101
 
4102
    /*
4103
     * Reflect the change to stackTop back in eePtr.
4104
     */
4105
 
4106
    done:
4107
    Tcl_DecrRefCount(valuePtr);
4108
    DECACHE_STACK_INFO();
4109
    return result;
4110
}
4111
 
4112
static int
4113
ExprSrandFunc(interp, eePtr, clientData)
4114
    Tcl_Interp *interp;         /* The interpreter in which to execute the
4115
                                 * function. */
4116
    ExecEnv *eePtr;             /* Points to the environment for executing
4117
                                 * the function. */
4118
    ClientData clientData;      /* Ignored. */
4119
{
4120
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
4121
    register int stackTop;      /* Cached top index of evaluation stack. */
4122
    Interp *iPtr = (Interp *) interp;
4123
    Tcl_Obj *valuePtr;
4124
    Tcl_ObjType *tPtr;
4125
    long i = 0;                  /* Initialized to avoid compiler warning. */
4126
    int result;
4127
 
4128
    /*
4129
     * Set stackPtr and stackTop from eePtr.
4130
     */
4131
 
4132
    CACHE_STACK_INFO();
4133
 
4134
    /*
4135
     * Pop the argument from the evaluation stack.  Use the value
4136
     * to reset the random number seed.
4137
     */
4138
 
4139
    valuePtr = POP_OBJECT();
4140
    tPtr = valuePtr->typePtr;
4141
 
4142
    if (tPtr == &tclIntType) {
4143
        i = valuePtr->internalRep.longValue;
4144
    } else {                    /* FAILS IF STRING REP HAS NULLS */
4145
        result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, valuePtr, &i);
4146
        if (result != TCL_OK) {
4147
            Tcl_ResetResult(interp);
4148
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "can't use ",
4149
                    ((tPtr == &tclDoubleType)? "floating-point value" : "non-numeric string"),
4150
                    " as argument to srand", (char *) NULL);
4151
            Tcl_DecrRefCount(valuePtr);
4152
            DECACHE_STACK_INFO();
4153
            return result;
4154
        }
4155
    }
4156
 
4157
    /*
4158
     * Reset the seed.
4159
     */
4160
 
4161
    iPtr->flags |= RAND_SEED_INITIALIZED;
4162
    iPtr->randSeed = i;
4163
 
4164
    /*
4165
     * To avoid duplicating the random number generation code we simply
4166
     * clean up our state and call the real random number function. That
4167
     * function will always succeed.
4168
     */
4169
 
4170
    Tcl_DecrRefCount(valuePtr);
4171
    DECACHE_STACK_INFO();
4172
 
4173
    ExprRandFunc(interp, eePtr, clientData);
4174
    return TCL_OK;
4175
}
4176
 
4177
/*
4178
 *----------------------------------------------------------------------
4179
 *
4180
 * ExprCallMathFunc --
4181
 *
4182
 *      This procedure is invoked to call a non-builtin math function
4183
 *      during the execution of an expression.
4184
 *
4185
 * Results:
4186
 *      TCL_OK is returned if all went well and the function's value
4187
 *      was computed successfully. If an error occurred, TCL_ERROR
4188
 *      is returned and an error message is left in the interpreter's
4189
 *      result. After a successful return this procedure pushes a Tcl object
4190
 *      holding the result.
4191
 *
4192
 * Side effects:
4193
 *      None, unless the called math function has side effects.
4194
 *
4195
 *----------------------------------------------------------------------
4196
 */
4197
 
4198
static int
4199
ExprCallMathFunc(interp, eePtr, objc, objv)
4200
    Tcl_Interp *interp;         /* The interpreter in which to execute the
4201
                                 * function. */
4202
    ExecEnv *eePtr;             /* Points to the environment for executing
4203
                                 * the function. */
4204
    int objc;                   /* Number of arguments. The function name is
4205
                                 * the 0-th argument. */
4206
    Tcl_Obj **objv;             /* The array of arguments. The function name
4207
                                 * is objv[0]. */
4208
{
4209
    Interp *iPtr = (Interp *) interp;
4210
    StackItem *stackPtr;        /* Cached evaluation stack base pointer. */
4211
    register int stackTop;      /* Cached top index of evaluation stack. */
4212
    char *funcName;
4213
    Tcl_HashEntry *hPtr;
4214
    MathFunc *mathFuncPtr;      /* Information about math function. */
4215
    Tcl_Value args[MAX_MATH_ARGS]; /* Arguments for function call. */
4216
    Tcl_Value funcResult;       /* Result of function call as Tcl_Value. */
4217
    register Tcl_Obj *valuePtr;
4218
    Tcl_ObjType *tPtr;
4219
    long i;
4220
    double d;
4221
    int j, k, result;
4222
 
4223
    Tcl_ResetResult(interp);
4224
 
4225
    /*
4226
     * Set stackPtr and stackTop from eePtr.
4227
     */
4228
 
4229
    CACHE_STACK_INFO();
4230
 
4231
    /*
4232
     * Look up the MathFunc record for the function.
4233
     * THIS FAILS IF THE OBJECT'S STRING REP CONTAINS NULLS.
4234
     */
4235
 
4236
    funcName = Tcl_GetStringFromObj(objv[0], (int *) NULL);
4237
    hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, funcName);
4238
    if (hPtr == NULL) {
4239
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
4240
                "unknown math function \"", funcName, "\"", (char *) NULL);
4241
        result = TCL_ERROR;
4242
        goto done;
4243
    }
4244
    mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
4245
    if (mathFuncPtr->numArgs != (objc-1)) {
4246
        panic("ExprCallMathFunc: expected number of args %d != actual number %d",
4247
                mathFuncPtr->numArgs, objc);
4248
        result = TCL_ERROR;
4249
        goto done;
4250
    }
4251
 
4252
    /*
4253
     * Collect the arguments for the function, if there are any, into the
4254
     * array "args". Note that args[0] will have the Tcl_Value that
4255
     * corresponds to objv[1].
4256
     */
4257
 
4258
    for (j = 1, k = 0;  j < objc;  j++, k++) {
4259
        valuePtr = objv[j];
4260
        tPtr = valuePtr->typePtr;
4261
 
4262
        if (tPtr == &tclIntType) {
4263
            i = valuePtr->internalRep.longValue;
4264
        } else if (tPtr == &tclDoubleType) {
4265
            d = valuePtr->internalRep.doubleValue;
4266
        } else {
4267
            /*
4268
             * Try to convert to int first then double.
4269
             * FAILS IF STRING REP HAS NULLS.
4270
             */
4271
 
4272
            char *s = Tcl_GetStringFromObj(valuePtr, (int *) NULL);
4273
 
4274
            if (TclLooksLikeInt(s)) {
4275
                result = Tcl_GetLongFromObj((Tcl_Interp *) NULL, valuePtr, &i);
4276
            } else {
4277
                result = Tcl_GetDoubleFromObj((Tcl_Interp *) NULL,
4278
                        valuePtr, &d);
4279
            }
4280
            if (result != TCL_OK) {
4281
                Tcl_AppendToObj(Tcl_GetObjResult(interp),
4282
                        "argument to math function didn't have numeric value", -1);
4283
                goto done;
4284
            }
4285
            tPtr = valuePtr->typePtr;
4286
        }
4287
 
4288
        /*
4289
         * Copy the object's numeric value to the argument record,
4290
         * converting it if necessary.
4291
         */
4292
 
4293
        if (tPtr == &tclIntType) {
4294
            if (mathFuncPtr->argTypes[k] == TCL_DOUBLE) {
4295
                args[k].type = TCL_DOUBLE;
4296
                args[k].doubleValue = i;
4297
            } else {
4298
                args[k].type = TCL_INT;
4299
                args[k].intValue = i;
4300
            }
4301
        } else {
4302
            if (mathFuncPtr->argTypes[k] == TCL_INT) {
4303
                args[k].type = TCL_INT;
4304
                args[k].intValue = (long) d;
4305
            } else {
4306
                args[k].type = TCL_DOUBLE;
4307
                args[k].doubleValue = d;
4308
            }
4309
        }
4310
    }
4311
 
4312
    /*
4313
     * Invoke the function and copy its result back into valuePtr.
4314
     */
4315
 
4316
    tcl_MathInProgress++;
4317
    result = (*mathFuncPtr->proc)(mathFuncPtr->clientData, interp, args,
4318
            &funcResult);
4319
    tcl_MathInProgress--;
4320
    if (result != TCL_OK) {
4321
        goto done;
4322
    }
4323
 
4324
    /*
4325
     * Pop the objc top stack elements and decrement their ref counts.
4326
     */
4327
 
4328
    i = (stackTop - (objc-1));
4329
    while (i <= stackTop) {
4330
        valuePtr = stackPtr[i].o;
4331
        Tcl_DecrRefCount(valuePtr);
4332
        i++;
4333
    }
4334
    stackTop -= objc;
4335
 
4336
    /*
4337
     * Push the call's object result.
4338
     */
4339
 
4340
    if (funcResult.type == TCL_INT) {
4341
        PUSH_OBJECT(Tcl_NewLongObj(funcResult.intValue));
4342
    } else {
4343
        d = funcResult.doubleValue;
4344
        if (IS_NAN(d) || IS_INF(d)) {
4345
            TclExprFloatError(interp, d);
4346
            result = TCL_ERROR;
4347
            goto done;
4348
        }
4349
        PUSH_OBJECT(Tcl_NewDoubleObj(d));
4350
    }
4351
 
4352
    /*
4353
     * Reflect the change to stackTop back in eePtr.
4354
     */
4355
 
4356
    done:
4357
    DECACHE_STACK_INFO();
4358
    return result;
4359
}
4360
 
4361
/*
4362
 *----------------------------------------------------------------------
4363
 *
4364
 * TclExprFloatError --
4365
 *
4366
 *      This procedure is called when an error occurs during a
4367
 *      floating-point operation. It reads errno and sets
4368
 *      interp->objResultPtr accordingly.
4369
 *
4370
 * Results:
4371
 *      interp->objResultPtr is set to hold an error message.
4372
 *
4373
 * Side effects:
4374
 *      None.
4375
 *
4376
 *----------------------------------------------------------------------
4377
 */
4378
 
4379
void
4380
TclExprFloatError(interp, value)
4381
    Tcl_Interp *interp;         /* Where to store error message. */
4382
    double value;               /* Value returned after error;  used to
4383
                                 * distinguish underflows from overflows. */
4384
{
4385
    char *s;
4386
 
4387
    Tcl_ResetResult(interp);
4388
    if ((errno == EDOM) || (value != value)) {
4389
        s = "domain error: argument not in valid range";
4390
        Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
4391
        Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", s, (char *) NULL);
4392
    } else if ((errno == ERANGE) || IS_INF(value)) {
4393
        if (value == 0.0) {
4394
            s = "floating-point value too small to represent";
4395
            Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
4396
            Tcl_SetErrorCode(interp, "ARITH", "UNDERFLOW", s, (char *) NULL);
4397
        } else {
4398
            s = "floating-point value too large to represent";
4399
            Tcl_AppendToObj(Tcl_GetObjResult(interp), s, -1);
4400
            Tcl_SetErrorCode(interp, "ARITH", "OVERFLOW", s, (char *) NULL);
4401
        }
4402
    } else {                    /* FAILS IF STRING REP CONTAINS NULLS */
4403
        char msg[100];
4404
 
4405
        sprintf(msg, "unknown floating-point error, errno = %d", errno);
4406
        Tcl_AppendToObj(Tcl_GetObjResult(interp), msg, -1);
4407
        Tcl_SetErrorCode(interp, "ARITH", "UNKNOWN", msg, (char *) NULL);
4408
    }
4409
}
4410
 
4411
#ifdef TCL_COMPILE_STATS
4412
/*
4413
 *----------------------------------------------------------------------
4414
 *
4415
 * TclLog2 --
4416
 *
4417
 *      Procedure used while collecting compilation statistics to determine
4418
 *      the log base 2 of an integer.
4419
 *
4420
 * Results:
4421
 *      Returns the log base 2 of the operand. If the argument is less
4422
 *      than or equal to zero, a zero is returned.
4423
 *
4424
 * Side effects:
4425
 *      None.
4426
 *
4427
 *----------------------------------------------------------------------
4428
 */
4429
 
4430
int
4431
TclLog2(value)
4432
    register int value;         /* The integer for which to compute the
4433
                                 * log base 2. */
4434
{
4435
    register int n = value;
4436
    register int result = 0;
4437
 
4438
    while (n > 1) {
4439
        n = n >> 1;
4440
        result++;
4441
    }
4442
    return result;
4443
}
4444
 
4445
/*
4446
 *----------------------------------------------------------------------
4447
 *
4448
 * EvalStatsCmd --
4449
 *
4450
 *      Implements the "evalstats" command that prints instruction execution
4451
 *      counts to stdout.
4452
 *
4453
 * Results:
4454
 *      Standard Tcl results.
4455
 *
4456
 * Side effects:
4457
 *      None.
4458
 *
4459
 *----------------------------------------------------------------------
4460
 */
4461
 
4462
static int
4463
EvalStatsCmd(unused, interp, argc, argv)
4464
    ClientData unused;          /* Unused. */
4465
    Tcl_Interp *interp;         /* The current interpreter. */
4466
    int argc;                   /* The number of arguments. */
4467
    char **argv;                /* The argument strings. */
4468
{
4469
    register double total = 0.0;
4470
    register int i;
4471
    int maxSizeDecade = 0;
4472
    double totalHeaderBytes = (tclNumCompilations * sizeof(ByteCode));
4473
 
4474
    for (i = 0;  i < 256;  i++) {
4475
        if (instructionCount[i] != 0) {
4476
            total += instructionCount[i];
4477
        }
4478
    }
4479
 
4480
    for (i = 31;  i >= 0;  i--) {
4481
        if ((tclSourceCount[i] > 0) && (tclByteCodeCount[i] > 0)) {
4482
            maxSizeDecade = i;
4483
            break;
4484
        }
4485
    }
4486
 
4487
    fprintf(stdout, "\nNumber of compilations           %ld\n",
4488
            tclNumCompilations);
4489
    fprintf(stdout, "Number of executions               %ld\n",
4490
            numExecutions);
4491
    fprintf(stdout, "Average executions/compilation     %.0f\n",
4492
            ((float) numExecutions/tclNumCompilations));
4493
 
4494
    fprintf(stdout, "\nInstructions executed            %.0f\n",
4495
            total);
4496
    fprintf(stdout, "Average instructions/compile       %.0f\n",
4497
            total/tclNumCompilations);
4498
    fprintf(stdout, "Average instructions/execution     %.0f\n",
4499
            total/numExecutions);
4500
 
4501
    fprintf(stdout, "\nTotal source bytes               %.6g\n",
4502
            tclTotalSourceBytes);
4503
    fprintf(stdout, "Total code bytes           %.6g\n",
4504
            tclTotalCodeBytes);
4505
    fprintf(stdout, "Average code/compilation   %.0f\n",
4506
            tclTotalCodeBytes/tclNumCompilations);
4507
    fprintf(stdout, "Average code/source                %.2f\n",
4508
            tclTotalCodeBytes/tclTotalSourceBytes);
4509
    fprintf(stdout, "Current source bytes               %.6g\n",
4510
            tclCurrentSourceBytes);
4511
    fprintf(stdout, "Current code bytes         %.6g\n",
4512
            tclCurrentCodeBytes);
4513
    fprintf(stdout, "Current code/source                %.2f\n",
4514
            tclCurrentCodeBytes/tclCurrentSourceBytes);
4515
 
4516
    fprintf(stdout, "\nTotal objects allocated          %ld\n",
4517
            tclObjsAlloced);
4518
    fprintf(stdout, "Total objects freed                %ld\n",
4519
            tclObjsFreed);
4520
    fprintf(stdout, "Current objects:           %ld\n",
4521
            (tclObjsAlloced - tclObjsFreed));
4522
 
4523
    fprintf(stdout, "\nBreakdown of code byte requirements:\n");
4524
    fprintf(stdout, "                   Total bytes      Pct of    Avg per\n");
4525
    fprintf(stdout, "                                  all code    compile\n");
4526
    fprintf(stdout, "Total code        %12.6g        100%%   %8.2f\n",
4527
            tclTotalCodeBytes, tclTotalCodeBytes/tclNumCompilations);
4528
    fprintf(stdout, "Header            %12.6g   %8.2f%%   %8.2f\n",
4529
            totalHeaderBytes,
4530
            ((totalHeaderBytes * 100.0) / tclTotalCodeBytes),
4531
            totalHeaderBytes/tclNumCompilations);
4532
    fprintf(stdout, "Instructions      %12.6g   %8.2f%%   %8.2f\n",
4533
            tclTotalInstBytes,
4534
            ((tclTotalInstBytes * 100.0) / tclTotalCodeBytes),
4535
            tclTotalInstBytes/tclNumCompilations);
4536
    fprintf(stdout, "Objects           %12.6g   %8.2f%%   %8.2f\n",
4537
            tclTotalObjBytes,
4538
            ((tclTotalObjBytes * 100.0) / tclTotalCodeBytes),
4539
            tclTotalObjBytes/tclNumCompilations);
4540
    fprintf(stdout, "Exception table   %12.6g   %8.2f%%   %8.2f\n",
4541
            tclTotalExceptBytes,
4542
            ((tclTotalExceptBytes * 100.0) / tclTotalCodeBytes),
4543
            tclTotalExceptBytes/tclNumCompilations);
4544
    fprintf(stdout, "Auxiliary data    %12.6g   %8.2f%%   %8.2f\n",
4545
            tclTotalAuxBytes,
4546
            ((tclTotalAuxBytes * 100.0) / tclTotalCodeBytes),
4547
            tclTotalAuxBytes/tclNumCompilations);
4548
    fprintf(stdout, "Command map       %12.6g   %8.2f%%   %8.2f\n",
4549
            tclTotalCmdMapBytes,
4550
            ((tclTotalCmdMapBytes * 100.0) / tclTotalCodeBytes),
4551
            tclTotalCmdMapBytes/tclNumCompilations);
4552
 
4553
    fprintf(stdout, "\nSource and ByteCode size distributions:\n");
4554
    fprintf(stdout, "    binary decade          source    code\n");
4555
    for (i = 0;  i <= maxSizeDecade;  i++) {
4556
        int decadeLow, decadeHigh;
4557
 
4558
        if (i == 0) {
4559
            decadeLow = 0;
4560
        } else {
4561
            decadeLow = 1 << i;
4562
        }
4563
        decadeHigh = (1 << (i+1)) - 1;
4564
        fprintf(stdout, "       %6d -%6d                %6d     %6d\n",
4565
                decadeLow, decadeHigh,
4566
                tclSourceCount[i], tclByteCodeCount[i]);
4567
    }
4568
 
4569
    fprintf(stdout, "\nInstruction counts:\n");
4570
    for (i = 0;  i < 256;  i++) {
4571
        if (instructionCount[i]) {
4572
            fprintf(stdout, "%20s %8d %6.2f%%\n",
4573
                    opName[i], instructionCount[i],
4574
                    (instructionCount[i] * 100.0)/total);
4575
        }
4576
    }
4577
 
4578
#ifdef TCL_MEM_DEBUG
4579
    fprintf(stdout, "\nHeap Statistics:\n");
4580
    TclDumpMemoryInfo(stdout);
4581
#endif /* TCL_MEM_DEBUG */
4582
 
4583
    return TCL_OK;
4584
}
4585
#endif /* TCL_COMPILE_STATS */
4586
 
4587
/*
4588
 *----------------------------------------------------------------------
4589
 *
4590
 * Tcl_GetCommandFromObj --
4591
 *
4592
 *      Returns the command specified by the name in a Tcl_Obj.
4593
 *
4594
 * Results:
4595
 *      Returns a token for the command if it is found. Otherwise, if it
4596
 *      can't be found or there is an error, returns NULL.
4597
 *
4598
 * Side effects:
4599
 *      May update the internal representation for the object, caching
4600
 *      the command reference so that the next time this procedure is
4601
 *      called with the same object, the command can be found quickly.
4602
 *
4603
 *----------------------------------------------------------------------
4604
 */
4605
 
4606
Tcl_Command
4607
Tcl_GetCommandFromObj(interp, objPtr)
4608
    Tcl_Interp *interp;         /* The interpreter in which to resolve the
4609
                                 * command and to report errors. */
4610
    register Tcl_Obj *objPtr;   /* The object containing the command's
4611
                                 * name. If the name starts with "::", will
4612
                                 * be looked up in global namespace. Else,
4613
                                 * looked up first in the current namespace
4614
                                 * if contextNsPtr is NULL, then in global
4615
                                 * namespace. */
4616
{
4617
    Interp *iPtr = (Interp *) interp;
4618
    register ResolvedCmdName *resPtr;
4619
    register Command *cmdPtr;
4620
    Namespace *currNsPtr;
4621
    int result;
4622
 
4623
    /*
4624
     * Get the internal representation, converting to a command type if
4625
     * needed. The internal representation is a ResolvedCmdName that points
4626
     * to the actual command.
4627
     */
4628
 
4629
    if (objPtr->typePtr != &tclCmdNameType) {
4630
        result = tclCmdNameType.setFromAnyProc(interp, objPtr);
4631
        if (result != TCL_OK) {
4632
            return (Tcl_Command) NULL;
4633
        }
4634
    }
4635
    resPtr = (ResolvedCmdName *) objPtr->internalRep.otherValuePtr;
4636
 
4637
    /*
4638
     * Get the current namespace.
4639
     */
4640
 
4641
    if (iPtr->varFramePtr != NULL) {
4642
        currNsPtr = iPtr->varFramePtr->nsPtr;
4643
    } else {
4644
        currNsPtr = iPtr->globalNsPtr;
4645
    }
4646
 
4647
    /*
4648
     * Check the context namespace and the namespace epoch of the resolved
4649
     * symbol to make sure that it is fresh. If not, then force another
4650
     * conversion to the command type, to discard the old rep and create a
4651
     * new one. Note that we verify that the namespace id of the context
4652
     * namespace is the same as the one we cached; this insures that the
4653
     * namespace wasn't deleted and a new one created at the same address
4654
     * with the same command epoch.
4655
     */
4656
 
4657
    cmdPtr = NULL;
4658
    if ((resPtr != NULL)
4659
            && (resPtr->refNsPtr == currNsPtr)
4660
            && (resPtr->refNsId == currNsPtr->nsId)
4661
            && (resPtr->refNsCmdEpoch == currNsPtr->cmdRefEpoch)) {
4662
        cmdPtr = resPtr->cmdPtr;
4663
        if (cmdPtr->cmdEpoch != resPtr->cmdEpoch) {
4664
            cmdPtr = NULL;
4665
        }
4666
    }
4667
 
4668
    if (cmdPtr == NULL) {
4669
        result = tclCmdNameType.setFromAnyProc(interp, objPtr);
4670
        if (result != TCL_OK) {
4671
            return (Tcl_Command) NULL;
4672
        }
4673
        resPtr = (ResolvedCmdName *) objPtr->internalRep.otherValuePtr;
4674
        if (resPtr != NULL) {
4675
            cmdPtr = resPtr->cmdPtr;
4676
        }
4677
    }
4678
 
4679
    if (cmdPtr == NULL) {
4680
        return (Tcl_Command) NULL;
4681
    }
4682
    return (Tcl_Command) cmdPtr;
4683
}
4684
 
4685
/*
4686
 *----------------------------------------------------------------------
4687
 *
4688
 * FreeCmdNameInternalRep --
4689
 *
4690
 *      Frees the resources associated with a cmdName object's internal
4691
 *      representation.
4692
 *
4693
 * Results:
4694
 *      None.
4695
 *
4696
 * Side effects:
4697
 *      Decrements the ref count of any cached ResolvedCmdName structure
4698
 *      pointed to by the cmdName's internal representation. If this is
4699
 *      the last use of the ResolvedCmdName, it is freed. This in turn
4700
 *      decrements the ref count of the Command structure pointed to by
4701
 *      the ResolvedSymbol, which may free the Command structure.
4702
 *
4703
 *----------------------------------------------------------------------
4704
 */
4705
 
4706
static void
4707
FreeCmdNameInternalRep(objPtr)
4708
    register Tcl_Obj *objPtr;   /* CmdName object with internal
4709
                                 * representation to free. */
4710
{
4711
    register ResolvedCmdName *resPtr =
4712
        (ResolvedCmdName *) objPtr->internalRep.otherValuePtr;
4713
 
4714
    if (resPtr != NULL) {
4715
        /*
4716
         * Decrement the reference count of the ResolvedCmdName structure.
4717
         * If there are no more uses, free the ResolvedCmdName structure.
4718
         */
4719
 
4720
        resPtr->refCount--;
4721
        if (resPtr->refCount == 0) {
4722
            /*
4723
             * Now free the cached command, unless it is still in its
4724
             * hash table or if there are other references to it
4725
             * from other cmdName objects.
4726
             */
4727
 
4728
            Command *cmdPtr = resPtr->cmdPtr;
4729
            TclCleanupCommand(cmdPtr);
4730
            ckfree((char *) resPtr);
4731
        }
4732
    }
4733
}
4734
 
4735
/*
4736
 *----------------------------------------------------------------------
4737
 *
4738
 * DupCmdNameInternalRep --
4739
 *
4740
 *      Initialize the internal representation of an cmdName Tcl_Obj to a
4741
 *      copy of the internal representation of an existing cmdName object.
4742
 *
4743
 * Results:
4744
 *      None.
4745
 *
4746
 * Side effects:
4747
 *      "copyPtr"s internal rep is set to point to the ResolvedCmdName
4748
 *      structure corresponding to "srcPtr"s internal rep. Increments the
4749
 *      ref count of the ResolvedCmdName structure pointed to by the
4750
 *      cmdName's internal representation.
4751
 *
4752
 *----------------------------------------------------------------------
4753
 */
4754
 
4755
static void
4756
DupCmdNameInternalRep(srcPtr, copyPtr)
4757
    Tcl_Obj *srcPtr;            /* Object with internal rep to copy. */
4758
    register Tcl_Obj *copyPtr;  /* Object with internal rep to set. */
4759
{
4760
    register ResolvedCmdName *resPtr =
4761
        (ResolvedCmdName *) srcPtr->internalRep.otherValuePtr;
4762
 
4763
    copyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr;
4764
    copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
4765
    if (resPtr != NULL) {
4766
        resPtr->refCount++;
4767
    }
4768
    copyPtr->typePtr = &tclCmdNameType;
4769
}
4770
 
4771
/*
4772
 *----------------------------------------------------------------------
4773
 *
4774
 * SetCmdNameFromAny --
4775
 *
4776
 *      Generate an cmdName internal form for the Tcl object "objPtr".
4777
 *
4778
 * Results:
4779
 *      The return value is a standard Tcl result. The conversion always
4780
 *      succeeds and TCL_OK is returned.
4781
 *
4782
 * Side effects:
4783
 *      A pointer to a ResolvedCmdName structure that holds a cached pointer
4784
 *      to the command with a name that matches objPtr's string rep is
4785
 *      stored as objPtr's internal representation. This ResolvedCmdName
4786
 *      pointer will be NULL if no matching command was found. The ref count
4787
 *      of the cached Command's structure (if any) is also incremented.
4788
 *
4789
 *----------------------------------------------------------------------
4790
 */
4791
 
4792
static int
4793
SetCmdNameFromAny(interp, objPtr)
4794
    Tcl_Interp *interp;         /* Used for error reporting if not NULL. */
4795
    register Tcl_Obj *objPtr;   /* The object to convert. */
4796
{
4797
    Interp *iPtr = (Interp *) interp;
4798
    char *name;
4799
    Tcl_Command cmd;
4800
    register Command *cmdPtr;
4801
    Namespace *currNsPtr;
4802
    register ResolvedCmdName *resPtr;
4803
 
4804
    /*
4805
     * Get "objPtr"s string representation. Make it up-to-date if necessary.
4806
     */
4807
 
4808
    name = objPtr->bytes;
4809
    if (name == NULL) {
4810
        name = Tcl_GetStringFromObj(objPtr, (int *) NULL);
4811
    }
4812
 
4813
    /*
4814
     * Find the Command structure, if any, that describes the command called
4815
     * "name". Build a ResolvedCmdName that holds a cached pointer to this
4816
     * Command, and bump the reference count in the referenced Command
4817
     * structure. A Command structure will not be deleted as long as it is
4818
     * referenced from a CmdName object.
4819
     */
4820
 
4821
    cmd = Tcl_FindCommand(interp, name, (Tcl_Namespace *) NULL,
4822
            /*flags*/ 0);
4823
    cmdPtr = (Command *) cmd;
4824
    if (cmdPtr != NULL) {
4825
        /*
4826
         * Get the current namespace.
4827
         */
4828
 
4829
        if (iPtr->varFramePtr != NULL) {
4830
            currNsPtr = iPtr->varFramePtr->nsPtr;
4831
        } else {
4832
            currNsPtr = iPtr->globalNsPtr;
4833
        }
4834
 
4835
        cmdPtr->refCount++;
4836
        resPtr = (ResolvedCmdName *) ckalloc(sizeof(ResolvedCmdName));
4837
        resPtr->cmdPtr        = cmdPtr;
4838
        resPtr->refNsPtr      = currNsPtr;
4839
        resPtr->refNsId       = currNsPtr->nsId;
4840
        resPtr->refNsCmdEpoch = currNsPtr->cmdRefEpoch;
4841
        resPtr->cmdEpoch      = cmdPtr->cmdEpoch;
4842
        resPtr->refCount      = 1;
4843
    } else {
4844
        resPtr = NULL;  /* no command named "name" was found */
4845
    }
4846
 
4847
    /*
4848
     * Free the old internalRep before setting the new one. We do this as
4849
     * late as possible to allow the conversion code, in particular
4850
     * GetStringFromObj, to use that old internalRep. If no Command
4851
     * structure was found, leave NULL as the cached value.
4852
     */
4853
 
4854
    if ((objPtr->typePtr != NULL)
4855
            && (objPtr->typePtr->freeIntRepProc != NULL)) {
4856
        objPtr->typePtr->freeIntRepProc(objPtr);
4857
    }
4858
 
4859
    objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr;
4860
    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
4861
    objPtr->typePtr = &tclCmdNameType;
4862
    return TCL_OK;
4863
}
4864
 
4865
/*
4866
 *----------------------------------------------------------------------
4867
 *
4868
 * UpdateStringOfCmdName --
4869
 *
4870
 *      Update the string representation for an cmdName object.
4871
 *
4872
 * Results:
4873
 *      None.
4874
 *
4875
 * Side effects:
4876
 *      Generates a panic.
4877
 *
4878
 *----------------------------------------------------------------------
4879
 */
4880
 
4881
static void
4882
UpdateStringOfCmdName(objPtr)
4883
    Tcl_Obj *objPtr;            /* CmdName obj to update string rep. */
4884
{
4885
    /*
4886
     * This procedure is never invoked since the internal representation of
4887
     * a cmdName object is never modified.
4888
     */
4889
 
4890
    panic("UpdateStringOfCmdName should never be invoked");
4891
}
4892
 
4893
#ifdef TCL_COMPILE_DEBUG
4894
/*
4895
 *----------------------------------------------------------------------
4896
 *
4897
 * StringForResultCode --
4898
 *
4899
 *      Procedure that returns a human-readable string representing a
4900
 *      Tcl result code such as TCL_ERROR.
4901
 *
4902
 * Results:
4903
 *      If the result code is one of the standard Tcl return codes, the
4904
 *      result is a string representing that code such as "TCL_ERROR".
4905
 *      Otherwise, the result string is that code formatted as a
4906
 *      sequence of decimal digit characters. Note that the resulting
4907
 *      string must not be modified by the caller.
4908
 *
4909
 * Side effects:
4910
 *      None.
4911
 *
4912
 *----------------------------------------------------------------------
4913
 */
4914
 
4915
static char *
4916
StringForResultCode(result)
4917
    int result;                 /* The Tcl result code for which to
4918
                                 * generate a string. */
4919
{
4920
    static char buf[20];
4921
 
4922
    if ((result >= TCL_OK) && (result <= TCL_CONTINUE)) {
4923
        return resultStrings[result];
4924
    }
4925
    TclFormatInt(buf, result);
4926
    return buf;
4927
}
4928
#endif /* TCL_COMPILE_DEBUG */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.