/[dtapublic]/projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclcompile.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclcompile.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 64 by dashley, Sun Oct 30 04:21:11 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2  /*  /*
3   * tclCompile.c --   * tclCompile.c --
4   *   *
5   *      This file contains procedures that compile Tcl commands or parts   *      This file contains procedures that compile Tcl commands or parts
6   *      of commands (like quoted strings or nested sub-commands) into a   *      of commands (like quoted strings or nested sub-commands) into a
7   *      sequence of instructions ("bytecodes").   *      sequence of instructions ("bytecodes").
8   *   *
9   * Copyright (c) 1996-1998 Sun Microsystems, Inc.   * Copyright (c) 1996-1998 Sun Microsystems, Inc.
10   *   *
11   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
12   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13   *   *
14   * RCS: @(#) $Id: tclcompile.c,v 1.1.1.1 2001/06/13 04:36:17 dtashley Exp $   * RCS: @(#) $Id: tclcompile.c,v 1.1.1.1 2001/06/13 04:36:17 dtashley Exp $
15   */   */
16    
17  #include "tclInt.h"  #include "tclInt.h"
18  #include "tclCompile.h"  #include "tclCompile.h"
19    
20  /*  /*
21   * Table of all AuxData types.   * Table of all AuxData types.
22   */   */
23    
24  static Tcl_HashTable auxDataTypeTable;  static Tcl_HashTable auxDataTypeTable;
25  static int auxDataTypeTableInitialized; /* 0 means not yet initialized. */  static int auxDataTypeTableInitialized; /* 0 means not yet initialized. */
26    
27  TCL_DECLARE_MUTEX(tableMutex)  TCL_DECLARE_MUTEX(tableMutex)
28    
29  /*  /*
30   * Variable that controls whether compilation tracing is enabled and, if so,   * Variable that controls whether compilation tracing is enabled and, if so,
31   * what level of tracing is desired:   * what level of tracing is desired:
32   *    0: no compilation tracing   *    0: no compilation tracing
33   *    1: summarize compilation of top level cmds and proc bodies   *    1: summarize compilation of top level cmds and proc bodies
34   *    2: display all instructions of each ByteCode compiled   *    2: display all instructions of each ByteCode compiled
35   * This variable is linked to the Tcl variable "tcl_traceCompile".   * This variable is linked to the Tcl variable "tcl_traceCompile".
36   */   */
37    
38  int tclTraceCompile = 0;  int tclTraceCompile = 0;
39  static int traceInitialized = 0;  static int traceInitialized = 0;
40    
41  /*  /*
42   * A table describing the Tcl bytecode instructions. Entries in this table   * A table describing the Tcl bytecode instructions. Entries in this table
43   * must correspond to the instruction opcode definitions in tclCompile.h.   * must correspond to the instruction opcode definitions in tclCompile.h.
44   * The names "op1" and "op4" refer to an instruction's one or four byte   * The names "op1" and "op4" refer to an instruction's one or four byte
45   * first operand. Similarly, "stktop" and "stknext" refer to the topmost   * first operand. Similarly, "stktop" and "stknext" refer to the topmost
46   * and next to topmost stack elements.   * and next to topmost stack elements.
47   *   *
48   * Note that the load, store, and incr instructions do not distinguish local   * Note that the load, store, and incr instructions do not distinguish local
49   * from global variables; the bytecode interpreter at runtime uses the   * from global variables; the bytecode interpreter at runtime uses the
50   * existence of a procedure call frame to distinguish these.   * existence of a procedure call frame to distinguish these.
51   */   */
52    
53  InstructionDesc instructionTable[] = {  InstructionDesc instructionTable[] = {
54     /* Name            Bytes #Opnds Operand types        Stack top, next   */     /* Name            Bytes #Opnds Operand types        Stack top, next   */
55      {"done",              1,   0,   {OPERAND_NONE}},      {"done",              1,   0,   {OPERAND_NONE}},
56          /* Finish ByteCode execution and return stktop (top stack item) */          /* Finish ByteCode execution and return stktop (top stack item) */
57      {"push1",             2,   1,   {OPERAND_UINT1}},      {"push1",             2,   1,   {OPERAND_UINT1}},
58          /* Push object at ByteCode objArray[op1] */          /* Push object at ByteCode objArray[op1] */
59      {"push4",             5,   1,   {OPERAND_UINT4}},      {"push4",             5,   1,   {OPERAND_UINT4}},
60          /* Push object at ByteCode objArray[op4] */          /* Push object at ByteCode objArray[op4] */
61      {"pop",               1,   0,   {OPERAND_NONE}},      {"pop",               1,   0,   {OPERAND_NONE}},
62          /* Pop the topmost stack object */          /* Pop the topmost stack object */
63      {"dup",               1,   0,   {OPERAND_NONE}},      {"dup",               1,   0,   {OPERAND_NONE}},
64          /* Duplicate the topmost stack object and push the result */          /* Duplicate the topmost stack object and push the result */
65      {"concat1",           2,   1,   {OPERAND_UINT1}},      {"concat1",           2,   1,   {OPERAND_UINT1}},
66          /* Concatenate the top op1 items and push result */          /* Concatenate the top op1 items and push result */
67      {"invokeStk1",        2,   1,   {OPERAND_UINT1}},      {"invokeStk1",        2,   1,   {OPERAND_UINT1}},
68          /* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */          /* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
69      {"invokeStk4",        5,   1,   {OPERAND_UINT4}},      {"invokeStk4",        5,   1,   {OPERAND_UINT4}},
70          /* Invoke command named objv[0]; <objc,objv> = <op4,top op4> */          /* Invoke command named objv[0]; <objc,objv> = <op4,top op4> */
71      {"evalStk",           1,   0,   {OPERAND_NONE}},      {"evalStk",           1,   0,   {OPERAND_NONE}},
72          /* Evaluate command in stktop using Tcl_EvalObj. */          /* Evaluate command in stktop using Tcl_EvalObj. */
73      {"exprStk",           1,   0,   {OPERAND_NONE}},      {"exprStk",           1,   0,   {OPERAND_NONE}},
74          /* Execute expression in stktop using Tcl_ExprStringObj. */          /* Execute expression in stktop using Tcl_ExprStringObj. */
75            
76      {"loadScalar1",       2,   1,   {OPERAND_UINT1}},      {"loadScalar1",       2,   1,   {OPERAND_UINT1}},
77          /* Load scalar variable at index op1 <= 255 in call frame */          /* Load scalar variable at index op1 <= 255 in call frame */
78      {"loadScalar4",       5,   1,   {OPERAND_UINT4}},      {"loadScalar4",       5,   1,   {OPERAND_UINT4}},
79          /* Load scalar variable at index op1 >= 256 in call frame */          /* Load scalar variable at index op1 >= 256 in call frame */
80      {"loadScalarStk",     1,   0,   {OPERAND_NONE}},      {"loadScalarStk",     1,   0,   {OPERAND_NONE}},
81          /* Load scalar variable; scalar's name is stktop */          /* Load scalar variable; scalar's name is stktop */
82      {"loadArray1",        2,   1,   {OPERAND_UINT1}},      {"loadArray1",        2,   1,   {OPERAND_UINT1}},
83          /* Load array element; array at slot op1<=255, element is stktop */          /* Load array element; array at slot op1<=255, element is stktop */
84      {"loadArray4",        5,   1,   {OPERAND_UINT4}},      {"loadArray4",        5,   1,   {OPERAND_UINT4}},
85          /* Load array element; array at slot op1 > 255, element is stktop */          /* Load array element; array at slot op1 > 255, element is stktop */
86      {"loadArrayStk",      1,   0,   {OPERAND_NONE}},      {"loadArrayStk",      1,   0,   {OPERAND_NONE}},
87          /* Load array element; element is stktop, array name is stknext */          /* Load array element; element is stktop, array name is stknext */
88      {"loadStk",           1,   0,   {OPERAND_NONE}},      {"loadStk",           1,   0,   {OPERAND_NONE}},
89          /* Load general variable; unparsed variable name is stktop */          /* Load general variable; unparsed variable name is stktop */
90      {"storeScalar1",      2,   1,   {OPERAND_UINT1}},      {"storeScalar1",      2,   1,   {OPERAND_UINT1}},
91          /* Store scalar variable at op1<=255 in frame; value is stktop */          /* Store scalar variable at op1<=255 in frame; value is stktop */
92      {"storeScalar4",      5,   1,   {OPERAND_UINT4}},      {"storeScalar4",      5,   1,   {OPERAND_UINT4}},
93          /* Store scalar variable at op1 > 255 in frame; value is stktop */          /* Store scalar variable at op1 > 255 in frame; value is stktop */
94      {"storeScalarStk",    1,   0,   {OPERAND_NONE}},      {"storeScalarStk",    1,   0,   {OPERAND_NONE}},
95          /* Store scalar; value is stktop, scalar name is stknext */          /* Store scalar; value is stktop, scalar name is stknext */
96      {"storeArray1",       2,   1,   {OPERAND_UINT1}},      {"storeArray1",       2,   1,   {OPERAND_UINT1}},
97          /* Store array element; array at op1<=255, value is top then elem */          /* Store array element; array at op1<=255, value is top then elem */
98      {"storeArray4",       5,   1,   {OPERAND_UINT4}},      {"storeArray4",       5,   1,   {OPERAND_UINT4}},
99          /* Store array element; array at op1>=256, value is top then elem */          /* Store array element; array at op1>=256, value is top then elem */
100      {"storeArrayStk",     1,   0,   {OPERAND_NONE}},      {"storeArrayStk",     1,   0,   {OPERAND_NONE}},
101          /* Store array element; value is stktop, then elem, array names */          /* Store array element; value is stktop, then elem, array names */
102      {"storeStk",          1,   0,   {OPERAND_NONE}},      {"storeStk",          1,   0,   {OPERAND_NONE}},
103          /* Store general variable; value is stktop, then unparsed name */          /* Store general variable; value is stktop, then unparsed name */
104            
105      {"incrScalar1",       2,   1,   {OPERAND_UINT1}},      {"incrScalar1",       2,   1,   {OPERAND_UINT1}},
106          /* Incr scalar at index op1<=255 in frame; incr amount is stktop */          /* Incr scalar at index op1<=255 in frame; incr amount is stktop */
107      {"incrScalarStk",     1,   0,   {OPERAND_NONE}},      {"incrScalarStk",     1,   0,   {OPERAND_NONE}},
108          /* Incr scalar; incr amount is stktop, scalar's name is stknext */          /* Incr scalar; incr amount is stktop, scalar's name is stknext */
109      {"incrArray1",        2,   1,   {OPERAND_UINT1}},      {"incrArray1",        2,   1,   {OPERAND_UINT1}},
110          /* Incr array elem; arr at slot op1<=255, amount is top then elem */          /* Incr array elem; arr at slot op1<=255, amount is top then elem */
111      {"incrArrayStk",      1,   0,   {OPERAND_NONE}},      {"incrArrayStk",      1,   0,   {OPERAND_NONE}},
112          /* Incr array element; amount is top then elem then array names */          /* Incr array element; amount is top then elem then array names */
113      {"incrStk",           1,   0,   {OPERAND_NONE}},      {"incrStk",           1,   0,   {OPERAND_NONE}},
114          /* Incr general variable; amount is stktop then unparsed var name */          /* Incr general variable; amount is stktop then unparsed var name */
115      {"incrScalar1Imm",    3,   2,   {OPERAND_UINT1, OPERAND_INT1}},      {"incrScalar1Imm",    3,   2,   {OPERAND_UINT1, OPERAND_INT1}},
116          /* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */          /* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
117      {"incrScalarStkImm",  2,   1,   {OPERAND_INT1}},      {"incrScalarStkImm",  2,   1,   {OPERAND_INT1}},
118          /* Incr scalar; scalar name is stktop; incr amount is op1 */          /* Incr scalar; scalar name is stktop; incr amount is op1 */
119      {"incrArray1Imm",     3,   2,   {OPERAND_UINT1, OPERAND_INT1}},      {"incrArray1Imm",     3,   2,   {OPERAND_UINT1, OPERAND_INT1}},
120          /* Incr array elem; array at slot op1 <= 255, elem is stktop,          /* Incr array elem; array at slot op1 <= 255, elem is stktop,
121           * amount is 2nd operand byte */           * amount is 2nd operand byte */
122      {"incrArrayStkImm",   2,   1,   {OPERAND_INT1}},      {"incrArrayStkImm",   2,   1,   {OPERAND_INT1}},
123          /* Incr array element; elem is top then array name, amount is op1 */          /* Incr array element; elem is top then array name, amount is op1 */
124      {"incrStkImm",        2,   1,   {OPERAND_INT1}},      {"incrStkImm",        2,   1,   {OPERAND_INT1}},
125          /* Incr general variable; unparsed name is top, amount is op1 */          /* Incr general variable; unparsed name is top, amount is op1 */
126            
127      {"jump1",             2,   1,   {OPERAND_INT1}},      {"jump1",             2,   1,   {OPERAND_INT1}},
128          /* Jump relative to (pc + op1) */          /* Jump relative to (pc + op1) */
129      {"jump4",             5,   1,   {OPERAND_INT4}},      {"jump4",             5,   1,   {OPERAND_INT4}},
130          /* Jump relative to (pc + op4) */          /* Jump relative to (pc + op4) */
131      {"jumpTrue1",         2,   1,   {OPERAND_INT1}},      {"jumpTrue1",         2,   1,   {OPERAND_INT1}},
132          /* Jump relative to (pc + op1) if stktop expr object is true */          /* Jump relative to (pc + op1) if stktop expr object is true */
133      {"jumpTrue4",         5,   1,   {OPERAND_INT4}},      {"jumpTrue4",         5,   1,   {OPERAND_INT4}},
134          /* Jump relative to (pc + op4) if stktop expr object is true */          /* Jump relative to (pc + op4) if stktop expr object is true */
135      {"jumpFalse1",        2,   1,   {OPERAND_INT1}},      {"jumpFalse1",        2,   1,   {OPERAND_INT1}},
136          /* Jump relative to (pc + op1) if stktop expr object is false */          /* Jump relative to (pc + op1) if stktop expr object is false */
137      {"jumpFalse4",        5,   1,   {OPERAND_INT4}},      {"jumpFalse4",        5,   1,   {OPERAND_INT4}},
138          /* Jump relative to (pc + op4) if stktop expr object is false */          /* Jump relative to (pc + op4) if stktop expr object is false */
139    
140      {"lor",               1,   0,   {OPERAND_NONE}},      {"lor",               1,   0,   {OPERAND_NONE}},
141          /* Logical or:  push (stknext || stktop) */          /* Logical or:  push (stknext || stktop) */
142      {"land",              1,   0,   {OPERAND_NONE}},      {"land",              1,   0,   {OPERAND_NONE}},
143          /* Logical and: push (stknext && stktop) */          /* Logical and: push (stknext && stktop) */
144      {"bitor",             1,   0,   {OPERAND_NONE}},      {"bitor",             1,   0,   {OPERAND_NONE}},
145          /* Bitwise or:  push (stknext | stktop) */          /* Bitwise or:  push (stknext | stktop) */
146      {"bitxor",            1,   0,   {OPERAND_NONE}},      {"bitxor",            1,   0,   {OPERAND_NONE}},
147          /* Bitwise xor  push (stknext ^ stktop) */          /* Bitwise xor  push (stknext ^ stktop) */
148      {"bitand",            1,   0,   {OPERAND_NONE}},      {"bitand",            1,   0,   {OPERAND_NONE}},
149          /* Bitwise and: push (stknext & stktop) */          /* Bitwise and: push (stknext & stktop) */
150      {"eq",                1,   0,   {OPERAND_NONE}},      {"eq",                1,   0,   {OPERAND_NONE}},
151          /* Equal:       push (stknext == stktop) */          /* Equal:       push (stknext == stktop) */
152      {"neq",               1,   0,   {OPERAND_NONE}},      {"neq",               1,   0,   {OPERAND_NONE}},
153          /* Not equal:   push (stknext != stktop) */          /* Not equal:   push (stknext != stktop) */
154      {"lt",                1,   0,   {OPERAND_NONE}},      {"lt",                1,   0,   {OPERAND_NONE}},
155          /* Less:        push (stknext < stktop) */          /* Less:        push (stknext < stktop) */
156      {"gt",                1,   0,   {OPERAND_NONE}},      {"gt",                1,   0,   {OPERAND_NONE}},
157          /* Greater:     push (stknext || stktop) */          /* Greater:     push (stknext || stktop) */
158      {"le",                1,   0,   {OPERAND_NONE}},      {"le",                1,   0,   {OPERAND_NONE}},
159          /* Logical or:  push (stknext || stktop) */          /* Logical or:  push (stknext || stktop) */
160      {"ge",                1,   0,   {OPERAND_NONE}},      {"ge",                1,   0,   {OPERAND_NONE}},
161          /* Logical or:  push (stknext || stktop) */          /* Logical or:  push (stknext || stktop) */
162      {"lshift",            1,   0,   {OPERAND_NONE}},      {"lshift",            1,   0,   {OPERAND_NONE}},
163          /* Left shift:  push (stknext << stktop) */          /* Left shift:  push (stknext << stktop) */
164      {"rshift",            1,   0,   {OPERAND_NONE}},      {"rshift",            1,   0,   {OPERAND_NONE}},
165          /* Right shift: push (stknext >> stktop) */          /* Right shift: push (stknext >> stktop) */
166      {"add",               1,   0,   {OPERAND_NONE}},      {"add",               1,   0,   {OPERAND_NONE}},
167          /* Add:         push (stknext + stktop) */          /* Add:         push (stknext + stktop) */
168      {"sub",               1,   0,   {OPERAND_NONE}},      {"sub",               1,   0,   {OPERAND_NONE}},
169          /* Sub:         push (stkext - stktop) */          /* Sub:         push (stkext - stktop) */
170      {"mult",              1,   0,   {OPERAND_NONE}},      {"mult",              1,   0,   {OPERAND_NONE}},
171          /* Multiply:    push (stknext * stktop) */          /* Multiply:    push (stknext * stktop) */
172      {"div",               1,   0,   {OPERAND_NONE}},      {"div",               1,   0,   {OPERAND_NONE}},
173          /* Divide:      push (stknext / stktop) */          /* Divide:      push (stknext / stktop) */
174      {"mod",               1,   0,   {OPERAND_NONE}},      {"mod",               1,   0,   {OPERAND_NONE}},
175          /* Mod:         push (stknext % stktop) */          /* Mod:         push (stknext % stktop) */
176      {"uplus",             1,   0,   {OPERAND_NONE}},      {"uplus",             1,   0,   {OPERAND_NONE}},
177          /* Unary plus:  push +stktop */          /* Unary plus:  push +stktop */
178      {"uminus",            1,   0,   {OPERAND_NONE}},      {"uminus",            1,   0,   {OPERAND_NONE}},
179          /* Unary minus: push -stktop */          /* Unary minus: push -stktop */
180      {"bitnot",            1,   0,   {OPERAND_NONE}},      {"bitnot",            1,   0,   {OPERAND_NONE}},
181          /* Bitwise not: push ~stktop */          /* Bitwise not: push ~stktop */
182      {"not",               1,   0,   {OPERAND_NONE}},      {"not",               1,   0,   {OPERAND_NONE}},
183          /* Logical not: push !stktop */          /* Logical not: push !stktop */
184      {"callBuiltinFunc1",  2,   1,   {OPERAND_UINT1}},      {"callBuiltinFunc1",  2,   1,   {OPERAND_UINT1}},
185          /* Call builtin math function with index op1; any args are on stk */          /* Call builtin math function with index op1; any args are on stk */
186      {"callFunc1",         2,   1,   {OPERAND_UINT1}},      {"callFunc1",         2,   1,   {OPERAND_UINT1}},
187          /* Call non-builtin func objv[0]; <objc,objv>=<op1,top op1>  */          /* Call non-builtin func objv[0]; <objc,objv>=<op1,top op1>  */
188      {"tryCvtToNumeric",   1,   0,   {OPERAND_NONE}},      {"tryCvtToNumeric",   1,   0,   {OPERAND_NONE}},
189          /* Try converting stktop to first int then double if possible. */          /* Try converting stktop to first int then double if possible. */
190    
191      {"break",             1,   0,   {OPERAND_NONE}},      {"break",             1,   0,   {OPERAND_NONE}},
192          /* Abort closest enclosing loop; if none, return TCL_BREAK code. */          /* Abort closest enclosing loop; if none, return TCL_BREAK code. */
193      {"continue",          1,   0,   {OPERAND_NONE}},      {"continue",          1,   0,   {OPERAND_NONE}},
194          /* Skip to next iteration of closest enclosing loop; if none,          /* Skip to next iteration of closest enclosing loop; if none,
195           * return TCL_CONTINUE code. */           * return TCL_CONTINUE code. */
196    
197      {"foreach_start4",    5,   1,   {OPERAND_UINT4}},      {"foreach_start4",    5,   1,   {OPERAND_UINT4}},
198          /* Initialize execution of a foreach loop. Operand is aux data index          /* Initialize execution of a foreach loop. Operand is aux data index
199           * of the ForeachInfo structure for the foreach command. */           * of the ForeachInfo structure for the foreach command. */
200      {"foreach_step4",     5,   1,   {OPERAND_UINT4}},      {"foreach_step4",     5,   1,   {OPERAND_UINT4}},
201          /* "Step" or begin next iteration of foreach loop. Push 0 if to          /* "Step" or begin next iteration of foreach loop. Push 0 if to
202           *  terminate loop, else push 1. */           *  terminate loop, else push 1. */
203    
204      {"beginCatch4",       5,   1,   {OPERAND_UINT4}},      {"beginCatch4",       5,   1,   {OPERAND_UINT4}},
205          /* Record start of catch with the operand's exception index.          /* Record start of catch with the operand's exception index.
206           * Push the current stack depth onto a special catch stack. */           * Push the current stack depth onto a special catch stack. */
207      {"endCatch",          1,   0,   {OPERAND_NONE}},      {"endCatch",          1,   0,   {OPERAND_NONE}},
208          /* End of last catch. Pop the bytecode interpreter's catch stack. */          /* End of last catch. Pop the bytecode interpreter's catch stack. */
209      {"pushResult",        1,   0,   {OPERAND_NONE}},      {"pushResult",        1,   0,   {OPERAND_NONE}},
210          /* Push the interpreter's object result onto the stack. */          /* Push the interpreter's object result onto the stack. */
211      {"pushReturnCode",    1,   0,   {OPERAND_NONE}},      {"pushReturnCode",    1,   0,   {OPERAND_NONE}},
212          /* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as          /* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as
213           * a new object onto the stack. */           * a new object onto the stack. */
214      {0}      {0}
215  };  };
216    
217  /*  /*
218   * Prototypes for procedures defined later in this file:   * Prototypes for procedures defined later in this file:
219   */   */
220    
221  static void             DupByteCodeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,  static void             DupByteCodeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
222                              Tcl_Obj *copyPtr));                              Tcl_Obj *copyPtr));
223  static unsigned char *  EncodeCmdLocMap _ANSI_ARGS_((  static unsigned char *  EncodeCmdLocMap _ANSI_ARGS_((
224                              CompileEnv *envPtr, ByteCode *codePtr,                              CompileEnv *envPtr, ByteCode *codePtr,
225                              unsigned char *startPtr));                              unsigned char *startPtr));
226  static void             EnterCmdExtentData _ANSI_ARGS_((  static void             EnterCmdExtentData _ANSI_ARGS_((
227                              CompileEnv *envPtr, int cmdNumber,                              CompileEnv *envPtr, int cmdNumber,
228                              int numSrcBytes, int numCodeBytes));                              int numSrcBytes, int numCodeBytes));
229  static void             EnterCmdStartData _ANSI_ARGS_((  static void             EnterCmdStartData _ANSI_ARGS_((
230                              CompileEnv *envPtr, int cmdNumber,                              CompileEnv *envPtr, int cmdNumber,
231                              int srcOffset, int codeOffset));                              int srcOffset, int codeOffset));
232  static void             FreeByteCodeInternalRep _ANSI_ARGS_((  static void             FreeByteCodeInternalRep _ANSI_ARGS_((
233                              Tcl_Obj *objPtr));                              Tcl_Obj *objPtr));
234  static int              GetCmdLocEncodingSize _ANSI_ARGS_((  static int              GetCmdLocEncodingSize _ANSI_ARGS_((
235                              CompileEnv *envPtr));                              CompileEnv *envPtr));
236  static void             LogCompilationInfo _ANSI_ARGS_((Tcl_Interp *interp,  static void             LogCompilationInfo _ANSI_ARGS_((Tcl_Interp *interp,
237                              char *script, char *command, int length));                              char *script, char *command, int length));
238  #ifdef TCL_COMPILE_STATS  #ifdef TCL_COMPILE_STATS
239  static void             RecordByteCodeStats _ANSI_ARGS_((  static void             RecordByteCodeStats _ANSI_ARGS_((
240                              ByteCode *codePtr));                              ByteCode *codePtr));
241  #endif /* TCL_COMPILE_STATS */  #endif /* TCL_COMPILE_STATS */
242  static int              SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp,  static int              SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp,
243                              Tcl_Obj *objPtr));                              Tcl_Obj *objPtr));
244    
245  /*  /*
246   * The structure below defines the bytecode Tcl object type by   * The structure below defines the bytecode Tcl object type by
247   * means of procedures that can be invoked by generic object code.   * means of procedures that can be invoked by generic object code.
248   */   */
249    
250  Tcl_ObjType tclByteCodeType = {  Tcl_ObjType tclByteCodeType = {
251      "bytecode",                         /* name */      "bytecode",                         /* name */
252      FreeByteCodeInternalRep,            /* freeIntRepProc */      FreeByteCodeInternalRep,            /* freeIntRepProc */
253      DupByteCodeInternalRep,             /* dupIntRepProc */      DupByteCodeInternalRep,             /* dupIntRepProc */
254      (Tcl_UpdateStringProc *) NULL,      /* updateStringProc */      (Tcl_UpdateStringProc *) NULL,      /* updateStringProc */
255      SetByteCodeFromAny                  /* setFromAnyProc */      SetByteCodeFromAny                  /* setFromAnyProc */
256  };  };
257    
258  /*  /*
259   *----------------------------------------------------------------------   *----------------------------------------------------------------------
260   *   *
261   * TclSetByteCodeFromAny --   * TclSetByteCodeFromAny --
262   *   *
263   *      Part of the bytecode Tcl object type implementation. Attempts to   *      Part of the bytecode Tcl object type implementation. Attempts to
264   *      generate an byte code internal form for the Tcl object "objPtr" by   *      generate an byte code internal form for the Tcl object "objPtr" by
265   *      compiling its string representation.  This function also takes   *      compiling its string representation.  This function also takes
266   *      a hook procedure that will be invoked to perform any needed post   *      a hook procedure that will be invoked to perform any needed post
267   *      processing on the compilation results before generating byte   *      processing on the compilation results before generating byte
268   *      codes.   *      codes.
269   *   *
270   * Results:   * Results:
271   *      The return value is a standard Tcl object result. If an error occurs   *      The return value is a standard Tcl object result. If an error occurs
272   *      during compilation, an error message is left in the interpreter's   *      during compilation, an error message is left in the interpreter's
273   *      result unless "interp" is NULL.   *      result unless "interp" is NULL.
274   *   *
275   * Side effects:   * Side effects:
276   *      Frees the old internal representation. If no error occurs, then the   *      Frees the old internal representation. If no error occurs, then the
277   *      compiled code is stored as "objPtr"s bytecode representation.   *      compiled code is stored as "objPtr"s bytecode representation.
278   *      Also, if debugging, initializes the "tcl_traceCompile" Tcl variable   *      Also, if debugging, initializes the "tcl_traceCompile" Tcl variable
279   *      used to trace compilations.   *      used to trace compilations.
280   *   *
281   *----------------------------------------------------------------------   *----------------------------------------------------------------------
282   */   */
283    
284  int  int
285  TclSetByteCodeFromAny(interp, objPtr, hookProc, clientData)  TclSetByteCodeFromAny(interp, objPtr, hookProc, clientData)
286      Tcl_Interp *interp;         /* The interpreter for which the code is      Tcl_Interp *interp;         /* The interpreter for which the code is
287                                   * being compiled.  Must not be NULL. */                                   * being compiled.  Must not be NULL. */
288      Tcl_Obj *objPtr;            /* The object to make a ByteCode object. */      Tcl_Obj *objPtr;            /* The object to make a ByteCode object. */
289      CompileHookProc *hookProc;  /* Procedure to invoke after compilation. */      CompileHookProc *hookProc;  /* Procedure to invoke after compilation. */
290      ClientData clientData;      /* Hook procedure private data. */      ClientData clientData;      /* Hook procedure private data. */
291  {  {
292      Interp *iPtr = (Interp *) interp;      Interp *iPtr = (Interp *) interp;
293      CompileEnv compEnv;         /* Compilation environment structure      CompileEnv compEnv;         /* Compilation environment structure
294                                   * allocated in frame. */                                   * allocated in frame. */
295      LiteralTable *localTablePtr = &(compEnv.localLitTable);      LiteralTable *localTablePtr = &(compEnv.localLitTable);
296      register AuxData *auxDataPtr;      register AuxData *auxDataPtr;
297      LiteralEntry *entryPtr;      LiteralEntry *entryPtr;
298      register int i;      register int i;
299      int length, nested, result;      int length, nested, result;
300      char *string;      char *string;
301    
302      if (!traceInitialized) {      if (!traceInitialized) {
303          if (Tcl_LinkVar(interp, "tcl_traceCompile",          if (Tcl_LinkVar(interp, "tcl_traceCompile",
304                      (char *) &tclTraceCompile,  TCL_LINK_INT) != TCL_OK) {                      (char *) &tclTraceCompile,  TCL_LINK_INT) != TCL_OK) {
305              panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");              panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
306          }          }
307          traceInitialized = 1;          traceInitialized = 1;
308      }      }
309    
310      if (iPtr->evalFlags & TCL_BRACKET_TERM) {      if (iPtr->evalFlags & TCL_BRACKET_TERM) {
311          nested = 1;          nested = 1;
312      } else {      } else {
313          nested = 0;          nested = 0;
314      }      }
315      string = Tcl_GetStringFromObj(objPtr, &length);      string = Tcl_GetStringFromObj(objPtr, &length);
316      TclInitCompileEnv(interp, &compEnv, string, length);      TclInitCompileEnv(interp, &compEnv, string, length);
317      result = TclCompileScript(interp, string, length, nested, &compEnv);      result = TclCompileScript(interp, string, length, nested, &compEnv);
318    
319      if (result == TCL_OK) {      if (result == TCL_OK) {
320          /*          /*
321           * Successful compilation. Add a "done" instruction at the end.           * Successful compilation. Add a "done" instruction at the end.
322           */           */
323    
324          compEnv.numSrcBytes = iPtr->termOffset;          compEnv.numSrcBytes = iPtr->termOffset;
325          TclEmitOpcode(INST_DONE, &compEnv);          TclEmitOpcode(INST_DONE, &compEnv);
326    
327          /*          /*
328           * Invoke the compilation hook procedure if one exists.           * Invoke the compilation hook procedure if one exists.
329           */           */
330    
331          if (hookProc) {          if (hookProc) {
332              result = (*hookProc)(interp, &compEnv, clientData);              result = (*hookProc)(interp, &compEnv, clientData);
333          }          }
334    
335          /*          /*
336           * Change the object into a ByteCode object. Ownership of the literal           * Change the object into a ByteCode object. Ownership of the literal
337           * objects and aux data items is given to the ByteCode object.           * objects and aux data items is given to the ByteCode object.
338           */           */
339            
340  #ifdef TCL_COMPILE_DEBUG  #ifdef TCL_COMPILE_DEBUG
341          TclVerifyLocalLiteralTable(&compEnv);          TclVerifyLocalLiteralTable(&compEnv);
342  #endif /*TCL_COMPILE_DEBUG*/  #endif /*TCL_COMPILE_DEBUG*/
343    
344          TclInitByteCodeObj(objPtr, &compEnv);          TclInitByteCodeObj(objPtr, &compEnv);
345  #ifdef TCL_COMPILE_DEBUG  #ifdef TCL_COMPILE_DEBUG
346          if (tclTraceCompile == 2) {          if (tclTraceCompile == 2) {
347              TclPrintByteCodeObj(interp, objPtr);              TclPrintByteCodeObj(interp, objPtr);
348          }          }
349  #endif /* TCL_COMPILE_DEBUG */  #endif /* TCL_COMPILE_DEBUG */
350      }      }
351                    
352      if (result != TCL_OK) {      if (result != TCL_OK) {
353          /*          /*
354           * Compilation errors.           * Compilation errors.
355           */           */
356    
357          entryPtr = compEnv.literalArrayPtr;          entryPtr = compEnv.literalArrayPtr;
358          for (i = 0;  i < compEnv.literalArrayNext;  i++) {          for (i = 0;  i < compEnv.literalArrayNext;  i++) {
359              TclReleaseLiteral(interp, entryPtr->objPtr);              TclReleaseLiteral(interp, entryPtr->objPtr);
360              entryPtr++;              entryPtr++;
361          }          }
362  #ifdef TCL_COMPILE_DEBUG  #ifdef TCL_COMPILE_DEBUG
363          TclVerifyGlobalLiteralTable(iPtr);          TclVerifyGlobalLiteralTable(iPtr);
364  #endif /*TCL_COMPILE_DEBUG*/  #endif /*TCL_COMPILE_DEBUG*/
365    
366          auxDataPtr = compEnv.auxDataArrayPtr;          auxDataPtr = compEnv.auxDataArrayPtr;
367          for (i = 0;  i < compEnv.auxDataArrayNext;  i++) {          for (i = 0;  i < compEnv.auxDataArrayNext;  i++) {
368              if (auxDataPtr->type->freeProc != NULL) {              if (auxDataPtr->type->freeProc != NULL) {
369                  auxDataPtr->type->freeProc(auxDataPtr->clientData);                  auxDataPtr->type->freeProc(auxDataPtr->clientData);
370              }              }
371              auxDataPtr++;              auxDataPtr++;
372          }          }
373      }      }
374    
375    
376      /*      /*
377       * Free storage allocated during compilation.       * Free storage allocated during compilation.
378       */       */
379            
380      if (localTablePtr->buckets != localTablePtr->staticBuckets) {      if (localTablePtr->buckets != localTablePtr->staticBuckets) {
381          ckfree((char *) localTablePtr->buckets);          ckfree((char *) localTablePtr->buckets);
382      }      }
383      TclFreeCompileEnv(&compEnv);      TclFreeCompileEnv(&compEnv);
384      return result;      return result;
385  }  }
386    
387  /*  /*
388   *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
389   *   *
390   * SetByteCodeFromAny --   * SetByteCodeFromAny --
391   *   *
392   *      Part of the bytecode Tcl object type implementation. Attempts to   *      Part of the bytecode Tcl object type implementation. Attempts to
393   *      generate an byte code internal form for the Tcl object "objPtr" by   *      generate an byte code internal form for the Tcl object "objPtr" by
394   *      compiling its string representation.   *      compiling its string representation.
395   *   *
396   * Results:   * Results:
397   *      The return value is a standard Tcl object result. If an error occurs   *      The return value is a standard Tcl object result. If an error occurs
398   *      during compilation, an error message is left in the interpreter's   *      during compilation, an error message is left in the interpreter's
399   *      result unless "interp" is NULL.   *      result unless "interp" is NULL.
400   *   *
401   * Side effects:   * Side effects:
402   *      Frees the old internal representation. If no error occurs, then the   *      Frees the old internal representation. If no error occurs, then the
403   *      compiled code is stored as "objPtr"s bytecode representation.   *      compiled code is stored as "objPtr"s bytecode representation.
404   *      Also, if debugging, initializes the "tcl_traceCompile" Tcl variable   *      Also, if debugging, initializes the "tcl_traceCompile" Tcl variable
405   *      used to trace compilations.   *      used to trace compilations.
406   *   *
407   *----------------------------------------------------------------------   *----------------------------------------------------------------------
408   */   */
409    
410  static int  static int
411  SetByteCodeFromAny(interp, objPtr)  SetByteCodeFromAny(interp, objPtr)
412      Tcl_Interp *interp;         /* The interpreter for which the code is      Tcl_Interp *interp;         /* The interpreter for which the code is
413                                   * being compiled.  Must not be NULL. */                                   * being compiled.  Must not be NULL. */
414      Tcl_Obj *objPtr;            /* The object to make a ByteCode object. */      Tcl_Obj *objPtr;            /* The object to make a ByteCode object. */
415  {  {
416      return TclSetByteCodeFromAny(interp, objPtr,      return TclSetByteCodeFromAny(interp, objPtr,
417              (CompileHookProc *) NULL, (ClientData) NULL);              (CompileHookProc *) NULL, (ClientData) NULL);
418  }  }
419    
420  /*  /*
421   *----------------------------------------------------------------------   *----------------------------------------------------------------------
422   *   *
423   * DupByteCodeInternalRep --   * DupByteCodeInternalRep --
424   *   *
425   *      Part of the bytecode Tcl object type implementation. However, it   *      Part of the bytecode Tcl object type implementation. However, it
426   *      does not copy the internal representation of a bytecode Tcl_Obj, but   *      does not copy the internal representation of a bytecode Tcl_Obj, but
427   *      instead leaves the new object untyped (with a NULL type pointer).   *      instead leaves the new object untyped (with a NULL type pointer).
428   *      Code will be compiled for the new object only if necessary.   *      Code will be compiled for the new object only if necessary.
429   *   *
430   * Results:   * Results:
431   *      None.   *      None.
432   *   *
433   * Side effects:   * Side effects:
434   *      None.   *      None.
435   *   *
436   *----------------------------------------------------------------------   *----------------------------------------------------------------------
437   */   */
438    
439  static void  static void
440  DupByteCodeInternalRep(srcPtr, copyPtr)  DupByteCodeInternalRep(srcPtr, copyPtr)
441      Tcl_Obj *srcPtr;            /* Object with internal rep to copy. */      Tcl_Obj *srcPtr;            /* Object with internal rep to copy. */
442      Tcl_Obj *copyPtr;           /* Object with internal rep to set. */      Tcl_Obj *copyPtr;           /* Object with internal rep to set. */
443  {  {
444      return;      return;
445  }  }
446    
447  /*  /*
448   *----------------------------------------------------------------------   *----------------------------------------------------------------------
449   *   *
450   * FreeByteCodeInternalRep --   * FreeByteCodeInternalRep --
451   *   *
452   *      Part of the bytecode Tcl object type implementation. Frees the   *      Part of the bytecode Tcl object type implementation. Frees the
453   *      storage associated with a bytecode object's internal representation   *      storage associated with a bytecode object's internal representation
454   *      unless its code is actively being executed.   *      unless its code is actively being executed.
455   *   *
456   * Results:   * Results:
457   *      None.   *      None.
458   *   *
459   * Side effects:   * Side effects:
460   *      The bytecode object's internal rep is marked invalid and its   *      The bytecode object's internal rep is marked invalid and its
461   *      code gets freed unless the code is actively being executed.   *      code gets freed unless the code is actively being executed.
462   *      In that case the cleanup is delayed until the last execution   *      In that case the cleanup is delayed until the last execution
463   *      of the code completes.   *      of the code completes.
464   *   *
465   *----------------------------------------------------------------------   *----------------------------------------------------------------------
466   */   */
467    
468  static void  static void
469  FreeByteCodeInternalRep(objPtr)  FreeByteCodeInternalRep(objPtr)
470      register Tcl_Obj *objPtr;   /* Object whose internal rep to free. */      register Tcl_Obj *objPtr;   /* Object whose internal rep to free. */
471  {  {
472      register ByteCode *codePtr =      register ByteCode *codePtr =
473              (ByteCode *) objPtr->internalRep.otherValuePtr;              (ByteCode *) objPtr->internalRep.otherValuePtr;
474    
475      codePtr->refCount--;      codePtr->refCount--;
476      if (codePtr->refCount <= 0) {      if (codePtr->refCount <= 0) {
477          TclCleanupByteCode(codePtr);          TclCleanupByteCode(codePtr);
478      }      }
479      objPtr->typePtr = NULL;      objPtr->typePtr = NULL;
480      objPtr->internalRep.otherValuePtr = NULL;      objPtr->internalRep.otherValuePtr = NULL;
481  }  }
482    
483  /*  /*
484   *----------------------------------------------------------------------   *----------------------------------------------------------------------
485   *   *
486   * TclCleanupByteCode --   * TclCleanupByteCode --
487   *   *
488   *      This procedure does all the real work of freeing up a bytecode   *      This procedure does all the real work of freeing up a bytecode
489   *      object's ByteCode structure. It's called only when the structure's   *      object's ByteCode structure. It's called only when the structure's
490   *      reference count becomes zero.   *      reference count becomes zero.
491   *   *
492   * Results:   * Results:
493   *      None.   *      None.
494   *   *
495   * Side effects:   * Side effects:
496   *      Frees objPtr's bytecode internal representation and sets its type   *      Frees objPtr's bytecode internal representation and sets its type
497   *      and objPtr->internalRep.otherValuePtr NULL. Also releases its   *      and objPtr->internalRep.otherValuePtr NULL. Also releases its
498   *      literals and frees its auxiliary data items.   *      literals and frees its auxiliary data items.
499   *   *
500   *----------------------------------------------------------------------   *----------------------------------------------------------------------
501   */   */
502    
503  void  void
504  TclCleanupByteCode(codePtr)  TclCleanupByteCode(codePtr)
505      register ByteCode *codePtr; /* Points to the ByteCode to free. */      register ByteCode *codePtr; /* Points to the ByteCode to free. */
506  {  {
507      Tcl_Interp *interp = (Tcl_Interp *) *codePtr->interpHandle;      Tcl_Interp *interp = (Tcl_Interp *) *codePtr->interpHandle;
508      int numLitObjects = codePtr->numLitObjects;      int numLitObjects = codePtr->numLitObjects;
509      int numAuxDataItems = codePtr->numAuxDataItems;      int numAuxDataItems = codePtr->numAuxDataItems;
510      register Tcl_Obj **objArrayPtr;      register Tcl_Obj **objArrayPtr;
511      register AuxData *auxDataPtr;      register AuxData *auxDataPtr;
512      int i;      int i;
513  #ifdef TCL_COMPILE_STATS  #ifdef TCL_COMPILE_STATS
514    
515      if (interp != NULL) {      if (interp != NULL) {
516          ByteCodeStats *statsPtr;          ByteCodeStats *statsPtr;
517          Tcl_Time destroyTime;          Tcl_Time destroyTime;
518          int lifetimeSec, lifetimeMicroSec, log2;          int lifetimeSec, lifetimeMicroSec, log2;
519    
520          statsPtr = &((Interp *) interp)->stats;          statsPtr = &((Interp *) interp)->stats;
521    
522          statsPtr->numByteCodesFreed++;          statsPtr->numByteCodesFreed++;
523          statsPtr->currentSrcBytes -= (double) codePtr->numSrcBytes;          statsPtr->currentSrcBytes -= (double) codePtr->numSrcBytes;
524          statsPtr->currentByteCodeBytes -= (double) codePtr->structureSize;          statsPtr->currentByteCodeBytes -= (double) codePtr->structureSize;
525    
526          statsPtr->currentInstBytes   -= (double) codePtr->numCodeBytes;          statsPtr->currentInstBytes   -= (double) codePtr->numCodeBytes;
527          statsPtr->currentLitBytes    -=          statsPtr->currentLitBytes    -=
528                  (double) (codePtr->numLitObjects * sizeof(Tcl_Obj *));                  (double) (codePtr->numLitObjects * sizeof(Tcl_Obj *));
529          statsPtr->currentExceptBytes -=          statsPtr->currentExceptBytes -=
530                  (double) (codePtr->numExceptRanges * sizeof(ExceptionRange));                  (double) (codePtr->numExceptRanges * sizeof(ExceptionRange));
531          statsPtr->currentAuxBytes    -=          statsPtr->currentAuxBytes    -=
532                  (double) (codePtr->numAuxDataItems * sizeof(AuxData));                  (double) (codePtr->numAuxDataItems * sizeof(AuxData));
533          statsPtr->currentCmdMapBytes -= (double) codePtr->numCmdLocBytes;          statsPtr->currentCmdMapBytes -= (double) codePtr->numCmdLocBytes;
534    
535          TclpGetTime(&destroyTime);          TclpGetTime(&destroyTime);
536          lifetimeSec = destroyTime.sec - codePtr->createTime.sec;          lifetimeSec = destroyTime.sec - codePtr->createTime.sec;
537          if (lifetimeSec > 2000) {       /* avoid overflow */          if (lifetimeSec > 2000) {       /* avoid overflow */
538              lifetimeSec = 2000;              lifetimeSec = 2000;
539          }          }
540          lifetimeMicroSec =          lifetimeMicroSec =
541              1000000*lifetimeSec + (destroyTime.usec - codePtr->createTime.usec);              1000000*lifetimeSec + (destroyTime.usec - codePtr->createTime.usec);
542                    
543          log2 = TclLog2(lifetimeMicroSec);          log2 = TclLog2(lifetimeMicroSec);
544          if (log2 > 31) {          if (log2 > 31) {
545              log2 = 31;              log2 = 31;
546          }          }
547          statsPtr->lifetimeCount[log2]++;          statsPtr->lifetimeCount[log2]++;
548      }      }
549  #endif /* TCL_COMPILE_STATS */  #endif /* TCL_COMPILE_STATS */
550    
551      /*      /*
552       * A single heap object holds the ByteCode structure and its code,       * A single heap object holds the ByteCode structure and its code,
553       * object, command location, and auxiliary data arrays. This means we       * object, command location, and auxiliary data arrays. This means we
554       * only need to 1) decrement the ref counts of the LiteralEntry's in       * only need to 1) decrement the ref counts of the LiteralEntry's in
555       * its literal array, 2) call the free procs for the auxiliary data       * its literal array, 2) call the free procs for the auxiliary data
556       * items, and 3) free the ByteCode structure's heap object.       * items, and 3) free the ByteCode structure's heap object.
557       *       *
558       * The case for TCL_BYTECODE_PRECOMPILED (precompiled ByteCodes,       * The case for TCL_BYTECODE_PRECOMPILED (precompiled ByteCodes,
559       * like those generated from tbcload) is special, as they doesn't       * like those generated from tbcload) is special, as they doesn't
560       * make use of the global literal table.  They instead maintain       * make use of the global literal table.  They instead maintain
561       * private references to their literals which must be decremented.       * private references to their literals which must be decremented.
562       */       */
563    
564      if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {      if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
565          register Tcl_Obj *objPtr;          register Tcl_Obj *objPtr;
566    
567          objArrayPtr = codePtr->objArrayPtr;          objArrayPtr = codePtr->objArrayPtr;
568          for (i = 0;  i < numLitObjects;  i++) {          for (i = 0;  i < numLitObjects;  i++) {
569              objPtr = *objArrayPtr;              objPtr = *objArrayPtr;
570              if (objPtr) {              if (objPtr) {
571                  Tcl_DecrRefCount(objPtr);                  Tcl_DecrRefCount(objPtr);
572              }              }
573              objArrayPtr++;              objArrayPtr++;
574          }          }
575          codePtr->numLitObjects = 0;          codePtr->numLitObjects = 0;
576      } else if (interp != NULL) {      } else if (interp != NULL) {
577          /*          /*
578           * If the interp has already been freed, then Tcl will have already           * If the interp has already been freed, then Tcl will have already
579           * forcefully released all the literals used by ByteCodes compiled           * forcefully released all the literals used by ByteCodes compiled
580           * with respect to that interp.           * with respect to that interp.
581           */           */
582                    
583          objArrayPtr = codePtr->objArrayPtr;          objArrayPtr = codePtr->objArrayPtr;
584          for (i = 0;  i < numLitObjects;  i++) {          for (i = 0;  i < numLitObjects;  i++) {
585              /*              /*
586               * TclReleaseLiteral sets a ByteCode's object array entry NULL to               * TclReleaseLiteral sets a ByteCode's object array entry NULL to
587               * indicate that it has already freed the literal.               * indicate that it has already freed the literal.
588               */               */
589                            
590              if (*objArrayPtr != NULL) {              if (*objArrayPtr != NULL) {
591                  TclReleaseLiteral(interp, *objArrayPtr);                  TclReleaseLiteral(interp, *objArrayPtr);
592              }              }
593              objArrayPtr++;              objArrayPtr++;
594          }          }
595      }      }
596            
597      auxDataPtr = codePtr->auxDataArrayPtr;      auxDataPtr = codePtr->auxDataArrayPtr;
598      for (i = 0;  i < numAuxDataItems;  i++) {      for (i = 0;  i < numAuxDataItems;  i++) {
599          if (auxDataPtr->type->freeProc != NULL) {          if (auxDataPtr->type->freeProc != NULL) {
600              (*auxDataPtr->type->freeProc)(auxDataPtr->clientData);              (*auxDataPtr->type->freeProc)(auxDataPtr->clientData);
601          }          }
602          auxDataPtr++;          auxDataPtr++;
603      }      }
604    
605      TclHandleRelease(codePtr->interpHandle);      TclHandleRelease(codePtr->interpHandle);
606      ckfree((char *) codePtr);      ckfree((char *) codePtr);
607  }  }
608    
609  /*  /*
610   *----------------------------------------------------------------------   *----------------------------------------------------------------------
611   *   *
612   * TclInitCompileEnv --   * TclInitCompileEnv --
613   *   *
614   *      Initializes a CompileEnv compilation environment structure for the   *      Initializes a CompileEnv compilation environment structure for the
615   *      compilation of a string in an interpreter.   *      compilation of a string in an interpreter.
616   *   *
617   * Results:   * Results:
618   *      None.   *      None.
619   *   *
620   * Side effects:   * Side effects:
621   *      The CompileEnv structure is initialized.   *      The CompileEnv structure is initialized.
622   *   *
623   *----------------------------------------------------------------------   *----------------------------------------------------------------------
624   */   */
625    
626  void  void
627  TclInitCompileEnv(interp, envPtr, string, numBytes)  TclInitCompileEnv(interp, envPtr, string, numBytes)
628      Tcl_Interp *interp;          /* The interpreter for which a CompileEnv      Tcl_Interp *interp;          /* The interpreter for which a CompileEnv
629                                    * structure is initialized. */                                    * structure is initialized. */
630      register CompileEnv *envPtr; /* Points to the CompileEnv structure to      register CompileEnv *envPtr; /* Points to the CompileEnv structure to
631                                    * initialize. */                                    * initialize. */
632      char *string;                /* The source string to be compiled. */      char *string;                /* The source string to be compiled. */
633      int numBytes;                /* Number of bytes in source string. */      int numBytes;                /* Number of bytes in source string. */
634  {  {
635      Interp *iPtr = (Interp *) interp;      Interp *iPtr = (Interp *) interp;
636            
637      envPtr->iPtr = iPtr;      envPtr->iPtr = iPtr;
638      envPtr->source = string;      envPtr->source = string;
639      envPtr->numSrcBytes = numBytes;      envPtr->numSrcBytes = numBytes;
640      envPtr->procPtr = iPtr->compiledProcPtr;      envPtr->procPtr = iPtr->compiledProcPtr;
641      envPtr->numCommands = 0;      envPtr->numCommands = 0;
642      envPtr->exceptDepth = 0;      envPtr->exceptDepth = 0;
643      envPtr->maxExceptDepth = 0;      envPtr->maxExceptDepth = 0;
644      envPtr->maxStackDepth = 0;      envPtr->maxStackDepth = 0;
645      TclInitLiteralTable(&(envPtr->localLitTable));      TclInitLiteralTable(&(envPtr->localLitTable));
646      envPtr->exprIsJustVarRef = 0;      envPtr->exprIsJustVarRef = 0;
647      envPtr->exprIsComparison = 0;      envPtr->exprIsComparison = 0;
648    
649      envPtr->codeStart = envPtr->staticCodeSpace;      envPtr->codeStart = envPtr->staticCodeSpace;
650      envPtr->codeNext = envPtr->codeStart;      envPtr->codeNext = envPtr->codeStart;
651      envPtr->codeEnd = (envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES);      envPtr->codeEnd = (envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES);
652      envPtr->mallocedCodeArray = 0;      envPtr->mallocedCodeArray = 0;
653    
654      envPtr->literalArrayPtr = envPtr->staticLiteralSpace;      envPtr->literalArrayPtr = envPtr->staticLiteralSpace;
655      envPtr->literalArrayNext = 0;      envPtr->literalArrayNext = 0;
656      envPtr->literalArrayEnd = COMPILEENV_INIT_NUM_OBJECTS;      envPtr->literalArrayEnd = COMPILEENV_INIT_NUM_OBJECTS;
657      envPtr->mallocedLiteralArray = 0;      envPtr->mallocedLiteralArray = 0;
658            
659      envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace;      envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace;
660      envPtr->exceptArrayNext = 0;      envPtr->exceptArrayNext = 0;
661      envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;      envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;
662      envPtr->mallocedExceptArray = 0;      envPtr->mallocedExceptArray = 0;
663            
664      envPtr->cmdMapPtr = envPtr->staticCmdMapSpace;      envPtr->cmdMapPtr = envPtr->staticCmdMapSpace;
665      envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE;      envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE;
666      envPtr->mallocedCmdMap = 0;      envPtr->mallocedCmdMap = 0;
667            
668      envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace;      envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace;
669      envPtr->auxDataArrayNext = 0;      envPtr->auxDataArrayNext = 0;
670      envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE;      envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE;
671      envPtr->mallocedAuxDataArray = 0;      envPtr->mallocedAuxDataArray = 0;
672  }  }
673    
674  /*  /*
675   *----------------------------------------------------------------------   *----------------------------------------------------------------------
676   *   *
677   * TclFreeCompileEnv --   * TclFreeCompileEnv --
678   *   *
679   *      Free the storage allocated in a CompileEnv compilation environment   *      Free the storage allocated in a CompileEnv compilation environment
680   *      structure.   *      structure.
681   *   *
682   * Results:   * Results:
683   *      None.   *      None.
684   *   *
685   * Side effects:   * Side effects:
686   *      Allocated storage in the CompileEnv structure is freed. Note that   *      Allocated storage in the CompileEnv structure is freed. Note that
687   *      its local literal table is not deleted and its literal objects are   *      its local literal table is not deleted and its literal objects are
688   *      not released. In addition, storage referenced by its auxiliary data   *      not released. In addition, storage referenced by its auxiliary data
689   *      items is not freed. This is done so that, when compilation is   *      items is not freed. This is done so that, when compilation is
690   *      successful, "ownership" of these objects and aux data items is   *      successful, "ownership" of these objects and aux data items is
691   *      handed over to the corresponding ByteCode structure.   *      handed over to the corresponding ByteCode structure.
692   *   *
693   *----------------------------------------------------------------------   *----------------------------------------------------------------------
694   */   */
695    
696  void  void
697  TclFreeCompileEnv(envPtr)  TclFreeCompileEnv(envPtr)
698      register CompileEnv *envPtr; /* Points to the CompileEnv structure. */      register CompileEnv *envPtr; /* Points to the CompileEnv structure. */
699  {  {
700      if (envPtr->mallocedCodeArray) {      if (envPtr->mallocedCodeArray) {
701          ckfree((char *) envPtr->codeStart);          ckfree((char *) envPtr->codeStart);
702      }      }
703      if (envPtr->mallocedLiteralArray) {      if (envPtr->mallocedLiteralArray) {
704          ckfree((char *) envPtr->literalArrayPtr);          ckfree((char *) envPtr->literalArrayPtr);
705      }      }
706      if (envPtr->mallocedExceptArray) {      if (envPtr->mallocedExceptArray) {
707          ckfree((char *) envPtr->exceptArrayPtr);          ckfree((char *) envPtr->exceptArrayPtr);
708      }      }
709      if (envPtr->mallocedCmdMap) {      if (envPtr->mallocedCmdMap) {
710          ckfree((char *) envPtr->cmdMapPtr);          ckfree((char *) envPtr->cmdMapPtr);
711      }      }
712      if (envPtr->mallocedAuxDataArray) {      if (envPtr->mallocedAuxDataArray) {
713          ckfree((char *) envPtr->auxDataArrayPtr);          ckfree((char *) envPtr->auxDataArrayPtr);
714      }      }
715  }  }
716    
717  /*  /*
718   *----------------------------------------------------------------------   *----------------------------------------------------------------------
719   *   *
720   * TclCompileScript --   * TclCompileScript --
721   *   *
722   *      Compile a Tcl script in a string.   *      Compile a Tcl script in a string.
723   *   *
724   * Results:   * Results:
725   *      The return value is TCL_OK on a successful compilation and TCL_ERROR   *      The return value is TCL_OK on a successful compilation and TCL_ERROR
726   *      on failure. If TCL_ERROR is returned, then the interpreter's result   *      on failure. If TCL_ERROR is returned, then the interpreter's result
727   *      contains an error message.   *      contains an error message.
728   *   *
729   *      interp->termOffset is set to the offset of the character in the   *      interp->termOffset is set to the offset of the character in the
730   *      script just after the last one successfully processed; this will be   *      script just after the last one successfully processed; this will be
731   *      the offset of the ']' if (flags & TCL_BRACKET_TERM).   *      the offset of the ']' if (flags & TCL_BRACKET_TERM).
732   *      envPtr->maxStackDepth is set to the maximum number of stack elements   *      envPtr->maxStackDepth is set to the maximum number of stack elements
733   *      needed to execute the script's commands.   *      needed to execute the script's commands.
734   *   *
735   * Side effects:   * Side effects:
736   *      Adds instructions to envPtr to evaluate the script at runtime.   *      Adds instructions to envPtr to evaluate the script at runtime.
737   *   *
738   *----------------------------------------------------------------------   *----------------------------------------------------------------------
739   */   */
740    
741  int  int
742  TclCompileScript(interp, script, numBytes, nested, envPtr)  TclCompileScript(interp, script, numBytes, nested, envPtr)
743      Tcl_Interp *interp;         /* Used for error and status reporting. */      Tcl_Interp *interp;         /* Used for error and status reporting. */
744      char *script;               /* The source script to compile. */      char *script;               /* The source script to compile. */
745      int numBytes;               /* Number of bytes in script. If < 0, the      int numBytes;               /* Number of bytes in script. If < 0, the
746                                   * script consists of all bytes up to the                                   * script consists of all bytes up to the
747                                   * first null character. */                                   * first null character. */
748      int nested;                 /* Non-zero means this is a nested command:      int nested;                 /* Non-zero means this is a nested command:
749                                   * close bracket ']' should be considered a                                   * close bracket ']' should be considered a
750                                   * command terminator. If zero, close                                   * command terminator. If zero, close
751                                   * bracket has no special meaning. */                                   * bracket has no special meaning. */
752      CompileEnv *envPtr;         /* Holds resulting instructions. */      CompileEnv *envPtr;         /* Holds resulting instructions. */
753  {  {
754      Interp *iPtr = (Interp *) interp;      Interp *iPtr = (Interp *) interp;
755      Tcl_Parse parse;      Tcl_Parse parse;
756      int maxDepth = 0;           /* Maximum number of stack elements needed      int maxDepth = 0;           /* Maximum number of stack elements needed
757                                   * to execute all cmds. */                                   * to execute all cmds. */
758      int lastTopLevelCmdIndex = -1;      int lastTopLevelCmdIndex = -1;
759                                  /* Index of most recent toplevel command in                                  /* Index of most recent toplevel command in
760                                   * the command location table. Initialized                                   * the command location table. Initialized
761                                   * to avoid compiler warning. */                                   * to avoid compiler warning. */
762      int startCodeOffset = -1;   /* Offset of first byte of current command's      int startCodeOffset = -1;   /* Offset of first byte of current command's
763                                   * code. Init. to avoid compiler warning. */                                   * code. Init. to avoid compiler warning. */
764      unsigned char *entryCodeNext = envPtr->codeNext;      unsigned char *entryCodeNext = envPtr->codeNext;
765      char *p, *next;      char *p, *next;
766      Namespace *cmdNsPtr;      Namespace *cmdNsPtr;
767      Command *cmdPtr;      Command *cmdPtr;
768      Tcl_Token *tokenPtr;      Tcl_Token *tokenPtr;
769      int bytesLeft, isFirstCmd, gotParse, wordIdx, currCmdIndex;      int bytesLeft, isFirstCmd, gotParse, wordIdx, currCmdIndex;
770      int commandLength, objIndex, code;      int commandLength, objIndex, code;
771      char prev;      char prev;
772      Tcl_DString ds;      Tcl_DString ds;
773    
774      Tcl_DStringInit(&ds);      Tcl_DStringInit(&ds);
775    
776      if (numBytes < 0) {      if (numBytes < 0) {
777          numBytes = strlen(script);          numBytes = strlen(script);
778      }      }
779      Tcl_ResetResult(interp);      Tcl_ResetResult(interp);
780      isFirstCmd = 1;      isFirstCmd = 1;
781    
782      /*      /*
783       * Each iteration through the following loop compiles the next       * Each iteration through the following loop compiles the next
784       * command from the script.       * command from the script.
785       */       */
786    
787      p = script;      p = script;
788      bytesLeft = numBytes;      bytesLeft = numBytes;
789      gotParse = 0;      gotParse = 0;
790      while (bytesLeft > 0) {      while (bytesLeft > 0) {
791          if (Tcl_ParseCommand(interp, p, bytesLeft, nested, &parse) != TCL_OK) {          if (Tcl_ParseCommand(interp, p, bytesLeft, nested, &parse) != TCL_OK) {
792              code = TCL_ERROR;              code = TCL_ERROR;
793              goto error;              goto error;
794          }          }
795          gotParse = 1;          gotParse = 1;
796          if (parse.numWords > 0) {          if (parse.numWords > 0) {
797              /*              /*
798               * If not the first command, pop the previous command's result               * If not the first command, pop the previous command's result
799               * and, if we're compiling a top level command, update the last               * and, if we're compiling a top level command, update the last
800               * command's code size to account for the pop instruction.               * command's code size to account for the pop instruction.
801               */               */
802    
803              if (!isFirstCmd) {              if (!isFirstCmd) {
804                  TclEmitOpcode(INST_POP, envPtr);                  TclEmitOpcode(INST_POP, envPtr);
805                  if (!nested) {                  if (!nested) {
806                      envPtr->cmdMapPtr[lastTopLevelCmdIndex].numCodeBytes =                      envPtr->cmdMapPtr[lastTopLevelCmdIndex].numCodeBytes =
807                             (envPtr->codeNext - envPtr->codeStart)                             (envPtr->codeNext - envPtr->codeStart)
808                             - startCodeOffset;                             - startCodeOffset;
809                  }                  }
810              }              }
811    
812              /*              /*
813               * Determine the actual length of the command.               * Determine the actual length of the command.
814               */               */
815    
816              commandLength = parse.commandSize;              commandLength = parse.commandSize;
817              prev = '\0';              prev = '\0';
818              if (commandLength > 0) {              if (commandLength > 0) {
819                  prev = parse.commandStart[commandLength-1];                  prev = parse.commandStart[commandLength-1];
820              }              }
821              if (((parse.commandStart+commandLength) != (script+numBytes))              if (((parse.commandStart+commandLength) != (script+numBytes))
822                      || ((prev=='\n') || (nested && (prev==']')))) {                      || ((prev=='\n') || (nested && (prev==']')))) {
823                  /*                  /*
824                   * The command didn't end at the end of the script (i.e.  it                   * The command didn't end at the end of the script (i.e.  it
825                   * ended at a terminator character such as ";".  Reduce the                   * ended at a terminator character such as ";".  Reduce the
826                   * length by one so that the trace message doesn't include                   * length by one so that the trace message doesn't include
827                   * the terminator character.                   * the terminator character.
828                   */                   */
829                                    
830                  commandLength -= 1;                  commandLength -= 1;
831              }              }
832    
833              /*              /*
834               * If tracing, print a line for each top level command compiled.               * If tracing, print a line for each top level command compiled.
835               */               */
836    
837              if ((tclTraceCompile >= 1)              if ((tclTraceCompile >= 1)
838                      && !nested && (envPtr->procPtr == NULL)) {                      && !nested && (envPtr->procPtr == NULL)) {
839                  fprintf(stdout, "  Compiling: ");                  fprintf(stdout, "  Compiling: ");
840                  TclPrintSource(stdout, parse.commandStart,                  TclPrintSource(stdout, parse.commandStart,
841                          TclMin(commandLength, 55));                          TclMin(commandLength, 55));
842                  fprintf(stdout, "\n");                  fprintf(stdout, "\n");
843              }              }
844    
845              /*              /*
846               * Each iteration of the following loop compiles one word               * Each iteration of the following loop compiles one word
847               * from the command.               * from the command.
848               */               */
849                            
850              envPtr->numCommands++;              envPtr->numCommands++;
851              currCmdIndex = (envPtr->numCommands - 1);              currCmdIndex = (envPtr->numCommands - 1);
852              if (!nested) {              if (!nested) {
853                  lastTopLevelCmdIndex = currCmdIndex;                  lastTopLevelCmdIndex = currCmdIndex;
854              }              }
855              startCodeOffset = (envPtr->codeNext - envPtr->codeStart);              startCodeOffset = (envPtr->codeNext - envPtr->codeStart);
856              EnterCmdStartData(envPtr, currCmdIndex,              EnterCmdStartData(envPtr, currCmdIndex,
857                      (parse.commandStart - envPtr->source), startCodeOffset);                      (parse.commandStart - envPtr->source), startCodeOffset);
858                            
859              for (wordIdx = 0, tokenPtr = parse.tokenPtr;              for (wordIdx = 0, tokenPtr = parse.tokenPtr;
860                      wordIdx < parse.numWords;                      wordIdx < parse.numWords;
861                      wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) {                      wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) {
862                  if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {                  if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
863                      /*                      /*
864                       * If this is the first word and the command has a                       * If this is the first word and the command has a
865                       * compile procedure, let it compile the command.                       * compile procedure, let it compile the command.
866                       */                       */
867    
868                      if (wordIdx == 0) {                      if (wordIdx == 0) {
869                          if (envPtr->procPtr != NULL) {                          if (envPtr->procPtr != NULL) {
870                              cmdNsPtr = envPtr->procPtr->cmdPtr->nsPtr;                              cmdNsPtr = envPtr->procPtr->cmdPtr->nsPtr;
871                          } else {                          } else {
872                              cmdNsPtr = NULL; /* use current NS */                              cmdNsPtr = NULL; /* use current NS */
873                          }                          }
874    
875                          /*                          /*
876                           * We copy the string before trying to find the command                           * We copy the string before trying to find the command
877                           * by name.  We used to modify the string in place, but                           * by name.  We used to modify the string in place, but
878                           * this is not safe because the name resolution                           * this is not safe because the name resolution
879                           * handlers could have side effects that rely on the                           * handlers could have side effects that rely on the
880                           * unmodified string.                           * unmodified string.
881                           */                           */
882    
883                          Tcl_DStringSetLength(&ds, 0);                          Tcl_DStringSetLength(&ds, 0);
884                          Tcl_DStringAppend(&ds, tokenPtr[1].start,                          Tcl_DStringAppend(&ds, tokenPtr[1].start,
885                                  tokenPtr[1].size);                                  tokenPtr[1].size);
886    
887                          cmdPtr = (Command *) Tcl_FindCommand(interp,                          cmdPtr = (Command *) Tcl_FindCommand(interp,
888                                  Tcl_DStringValue(&ds),                                  Tcl_DStringValue(&ds),
889                                  (Tcl_Namespace *) cmdNsPtr, /*flags*/ 0);                                  (Tcl_Namespace *) cmdNsPtr, /*flags*/ 0);
890    
891                          if ((cmdPtr != NULL)                          if ((cmdPtr != NULL)
892                                  && (cmdPtr->compileProc != NULL)                                  && (cmdPtr->compileProc != NULL)
893                                  && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) {                                  && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) {
894                              code = (*(cmdPtr->compileProc))(interp, &parse,                              code = (*(cmdPtr->compileProc))(interp, &parse,
895                                      envPtr);                                      envPtr);
896                              if (code == TCL_OK) {                              if (code == TCL_OK) {
897                                  maxDepth = TclMax(envPtr->maxStackDepth,                                  maxDepth = TclMax(envPtr->maxStackDepth,
898                                          maxDepth);                                          maxDepth);
899                                  goto finishCommand;                                  goto finishCommand;
900                              } else if (code == TCL_OUT_LINE_COMPILE) {                              } else if (code == TCL_OUT_LINE_COMPILE) {
901                                  /* do nothing */                                  /* do nothing */
902                              } else { /* an error */                              } else { /* an error */
903                                  /*                                  /*
904                                   * There was a compilation error, the last                                   * There was a compilation error, the last
905                                   * command did not get compiled into (*envPtr).                                   * command did not get compiled into (*envPtr).
906                                   * Decrement the number of commands                                   * Decrement the number of commands
907                                   * claimed to be in (*envPtr).                                   * claimed to be in (*envPtr).
908                                   */                                   */
909                                  envPtr->numCommands--;                                  envPtr->numCommands--;
910                                  goto error;                                  goto error;
911                              }                              }
912                          }                          }
913    
914                          /*                          /*
915                           * No compile procedure so push the word. If the                           * No compile procedure so push the word. If the
916                           * command was found, push a CmdName object to                           * command was found, push a CmdName object to
917                           * reduce runtime lookups.                           * reduce runtime lookups.
918                           */                           */
919    
920                          objIndex = TclRegisterLiteral(envPtr,                          objIndex = TclRegisterLiteral(envPtr,
921                                  tokenPtr[1].start, tokenPtr[1].size,                                  tokenPtr[1].start, tokenPtr[1].size,
922                                  /*onHeap*/ 0);                                  /*onHeap*/ 0);
923                          if (cmdPtr != NULL) {                          if (cmdPtr != NULL) {
924                              TclSetCmdNameObj(interp,                              TclSetCmdNameObj(interp,
925                                     envPtr->literalArrayPtr[objIndex].objPtr,                                     envPtr->literalArrayPtr[objIndex].objPtr,
926                                     cmdPtr);                                     cmdPtr);
927                          }                          }
928                      } else {                      } else {
929                          objIndex = TclRegisterLiteral(envPtr,                          objIndex = TclRegisterLiteral(envPtr,
930                                  tokenPtr[1].start, tokenPtr[1].size,                                  tokenPtr[1].start, tokenPtr[1].size,
931                                  /*onHeap*/ 0);                                  /*onHeap*/ 0);
932                      }                      }
933                      TclEmitPush(objIndex, envPtr);                      TclEmitPush(objIndex, envPtr);
934                      maxDepth = TclMax((wordIdx + 1), maxDepth);                      maxDepth = TclMax((wordIdx + 1), maxDepth);
935                  } else {                  } else {
936                      /*                      /*
937                       * The word is not a simple string of characters.                       * The word is not a simple string of characters.
938                       */                       */
939                                            
940                      code = TclCompileTokens(interp, tokenPtr+1,                      code = TclCompileTokens(interp, tokenPtr+1,
941                              tokenPtr->numComponents, envPtr);                              tokenPtr->numComponents, envPtr);
942                      if (code != TCL_OK) {                      if (code != TCL_OK) {
943                          goto error;                          goto error;
944                      }                      }
945                      maxDepth = TclMax((wordIdx + envPtr->maxStackDepth),                      maxDepth = TclMax((wordIdx + envPtr->maxStackDepth),
946                             maxDepth);                             maxDepth);
947                  }                  }
948              }              }
949    
950              /*              /*
951               * Emit an invoke instruction for the command. We skip this               * Emit an invoke instruction for the command. We skip this
952               * if a compile procedure was found for the command.               * if a compile procedure was found for the command.
953               */               */
954                            
955              if (wordIdx > 0) {              if (wordIdx > 0) {
956                  if (wordIdx <= 255) {                  if (wordIdx <= 255) {
957                      TclEmitInstInt1(INST_INVOKE_STK1, wordIdx, envPtr);                      TclEmitInstInt1(INST_INVOKE_STK1, wordIdx, envPtr);
958                  } else {                  } else {
959                      TclEmitInstInt4(INST_INVOKE_STK4, wordIdx, envPtr);                      TclEmitInstInt4(INST_INVOKE_STK4, wordIdx, envPtr);
960                  }                  }
961              }              }
962    
963              /*              /*
964               * Update the compilation environment structure and record the               * Update the compilation environment structure and record the
965               * offsets of the source and code for the command.               * offsets of the source and code for the command.
966               */               */
967    
968              finishCommand:              finishCommand:
969              EnterCmdExtentData(envPtr, currCmdIndex, commandLength,              EnterCmdExtentData(envPtr, currCmdIndex, commandLength,
970                      (envPtr->codeNext-envPtr->codeStart) - startCodeOffset);                      (envPtr->codeNext-envPtr->codeStart) - startCodeOffset);
971              isFirstCmd = 0;              isFirstCmd = 0;
972          } /* end if parse.numWords > 0 */          } /* end if parse.numWords > 0 */
973    
974          /*          /*
975           * Advance to the next command in the script.           * Advance to the next command in the script.
976           */           */
977                    
978          next = parse.commandStart + parse.commandSize;          next = parse.commandStart + parse.commandSize;
979          bytesLeft -= (next - p);          bytesLeft -= (next - p);
980          p = next;          p = next;
981          Tcl_FreeParse(&parse);          Tcl_FreeParse(&parse);
982          gotParse = 0;          gotParse = 0;
983          if (nested && (p[-1] == ']')) {          if (nested && (p[-1] == ']')) {
984              /*              /*
985               * We get here in the special case where TCL_BRACKET_TERM was               * We get here in the special case where TCL_BRACKET_TERM was
986               * set in the interpreter and we reached a close bracket in the               * set in the interpreter and we reached a close bracket in the
987               * script. Stop compilation.               * script. Stop compilation.
988               */               */
989                            
990              break;              break;
991          }          }
992      }      }
993    
994      /*      /*
995       * If the source script yielded no instructions (e.g., if it was empty),       * If the source script yielded no instructions (e.g., if it was empty),
996       * push an empty string as the command's result.       * push an empty string as the command's result.
997       */       */
998            
999      if (envPtr->codeNext == entryCodeNext) {      if (envPtr->codeNext == entryCodeNext) {
1000          TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0),          TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0),
1001                  envPtr);                  envPtr);
1002          maxDepth = 1;          maxDepth = 1;
1003      }      }
1004            
1005      if ((nested != 0) && (p > script) && (p[-1] == ']')) {      if ((nested != 0) && (p > script) && (p[-1] == ']')) {
1006          iPtr->termOffset = (p - 1) - script;          iPtr->termOffset = (p - 1) - script;
1007      } else {      } else {
1008          iPtr->termOffset = (p - script);          iPtr->termOffset = (p - script);
1009      }      }
1010      envPtr->maxStackDepth = maxDepth;      envPtr->maxStackDepth = maxDepth;
1011      Tcl_DStringFree(&ds);      Tcl_DStringFree(&ds);
1012      return TCL_OK;      return TCL_OK;
1013                    
1014      error:      error:
1015      /*      /*
1016       * Generate various pieces of error information, such as the line       * Generate various pieces of error information, such as the line
1017       * number where the error occurred and information to add to the       * number where the error occurred and information to add to the
1018       * errorInfo variable. Then free resources that had been allocated       * errorInfo variable. Then free resources that had been allocated
1019       * to the command.       * to the command.
1020       */       */
1021    
1022      commandLength = parse.commandSize;      commandLength = parse.commandSize;
1023      prev = '\0';      prev = '\0';
1024      if (commandLength > 0) {      if (commandLength > 0) {
1025          prev = parse.commandStart[commandLength-1];          prev = parse.commandStart[commandLength-1];
1026      }      }
1027      if (((parse.commandStart+commandLength) != (script+numBytes))      if (((parse.commandStart+commandLength) != (script+numBytes))
1028              || ((prev == '\n') || (nested && (prev == ']')))) {              || ((prev == '\n') || (nested && (prev == ']')))) {
1029          /*          /*
1030           * The command where the error occurred didn't end at the end           * The command where the error occurred didn't end at the end
1031           * of the script (i.e. it ended at a terminator character such           * of the script (i.e. it ended at a terminator character such
1032           * as ";".  Reduce the length by one so that the error message           * as ";".  Reduce the length by one so that the error message
1033           * doesn't include the terminator character.           * doesn't include the terminator character.
1034           */           */
1035    
1036          commandLength -= 1;          commandLength -= 1;
1037      }      }
1038      LogCompilationInfo(interp, script, parse.commandStart, commandLength);      LogCompilationInfo(interp, script, parse.commandStart, commandLength);
1039      if (gotParse) {      if (gotParse) {
1040          Tcl_FreeParse(&parse);          Tcl_FreeParse(&parse);
1041      }      }
1042      iPtr->termOffset = (p - script);      iPtr->termOffset = (p - script);
1043      envPtr->maxStackDepth = maxDepth;      envPtr->maxStackDepth = maxDepth;
1044      Tcl_DStringFree(&ds);      Tcl_DStringFree(&ds);
1045      return code;      return code;
1046  }  }
1047    
1048  /*  /*
1049   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1050   *   *
1051   * TclCompileTokens --   * TclCompileTokens --
1052   *   *
1053   *      Given an array of tokens parsed from a Tcl command (e.g., the tokens   *      Given an array of tokens parsed from a Tcl command (e.g., the tokens
1054   *      that make up a word) this procedure emits instructions to evaluate   *      that make up a word) this procedure emits instructions to evaluate
1055   *      the tokens and concatenate their values to form a single result   *      the tokens and concatenate their values to form a single result
1056   *      value on the interpreter's runtime evaluation stack.   *      value on the interpreter's runtime evaluation stack.
1057   *   *
1058   * Results:   * Results:
1059   *      The return value is a standard Tcl result. If an error occurs, an   *      The return value is a standard Tcl result. If an error occurs, an
1060   *      error message is left in the interpreter's result.   *      error message is left in the interpreter's result.
1061   *         *      
1062   *      envPtr->maxStackDepth is updated with the maximum number of stack   *      envPtr->maxStackDepth is updated with the maximum number of stack
1063   *      elements needed to evaluate the tokens.   *      elements needed to evaluate the tokens.
1064   *   *
1065   * Side effects:   * Side effects:
1066   *      Instructions are added to envPtr to push and evaluate the tokens   *      Instructions are added to envPtr to push and evaluate the tokens
1067   *      at runtime.   *      at runtime.
1068   *   *
1069   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1070   */   */
1071    
1072  int  int
1073  TclCompileTokens(interp, tokenPtr, count, envPtr)  TclCompileTokens(interp, tokenPtr, count, envPtr)
1074      Tcl_Interp *interp;         /* Used for error and status reporting. */      Tcl_Interp *interp;         /* Used for error and status reporting. */
1075      Tcl_Token *tokenPtr;        /* Pointer to first in an array of tokens      Tcl_Token *tokenPtr;        /* Pointer to first in an array of tokens
1076                                   * to compile. */                                   * to compile. */
1077      int count;                  /* Number of tokens to consider at tokenPtr.      int count;                  /* Number of tokens to consider at tokenPtr.
1078                                   * Must be at least 1. */                                   * Must be at least 1. */
1079      CompileEnv *envPtr;         /* Holds the resulting instructions. */      CompileEnv *envPtr;         /* Holds the resulting instructions. */
1080  {  {
1081      Tcl_DString textBuffer;     /* Holds concatenated chars from adjacent      Tcl_DString textBuffer;     /* Holds concatenated chars from adjacent
1082                                   * TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */                                   * TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */
1083      char buffer[TCL_UTF_MAX];      char buffer[TCL_UTF_MAX];
1084      char *name, *p;      char *name, *p;
1085      int numObjsToConcat, nameBytes, hasNsQualifiers, localVar;      int numObjsToConcat, nameBytes, hasNsQualifiers, localVar;
1086      int length, maxDepth, depthForVar, i, code;      int length, maxDepth, depthForVar, i, code;
1087      unsigned char *entryCodeNext = envPtr->codeNext;      unsigned char *entryCodeNext = envPtr->codeNext;
1088    
1089      Tcl_DStringInit(&textBuffer);      Tcl_DStringInit(&textBuffer);
1090      maxDepth = 0;      maxDepth = 0;
1091      numObjsToConcat = 0;      numObjsToConcat = 0;
1092      for ( ;  count > 0;  count--, tokenPtr++) {      for ( ;  count > 0;  count--, tokenPtr++) {
1093          switch (tokenPtr->type) {          switch (tokenPtr->type) {
1094              case TCL_TOKEN_TEXT:              case TCL_TOKEN_TEXT:
1095                  Tcl_DStringAppend(&textBuffer, tokenPtr->start,                  Tcl_DStringAppend(&textBuffer, tokenPtr->start,
1096                          tokenPtr->size);                          tokenPtr->size);
1097                  break;                  break;
1098    
1099              case TCL_TOKEN_BS:              case TCL_TOKEN_BS:
1100                  length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL,                  length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL,
1101                          buffer);                          buffer);
1102                  Tcl_DStringAppend(&textBuffer, buffer, length);                  Tcl_DStringAppend(&textBuffer, buffer, length);
1103                  break;                  break;
1104    
1105              case TCL_TOKEN_COMMAND:              case TCL_TOKEN_COMMAND:
1106                  /*                  /*
1107                   * Push any accumulated chars appearing before the command.                   * Push any accumulated chars appearing before the command.
1108                   */                   */
1109                                    
1110                  if (Tcl_DStringLength(&textBuffer) > 0) {                  if (Tcl_DStringLength(&textBuffer) > 0) {
1111                      int literal;                      int literal;
1112                                            
1113                      literal = TclRegisterLiteral(envPtr,                      literal = TclRegisterLiteral(envPtr,
1114                              Tcl_DStringValue(&textBuffer),                              Tcl_DStringValue(&textBuffer),
1115                              Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);                              Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
1116                      TclEmitPush(literal, envPtr);                      TclEmitPush(literal, envPtr);
1117                      numObjsToConcat++;                      numObjsToConcat++;
1118                      maxDepth = TclMax(numObjsToConcat, maxDepth);                      maxDepth = TclMax(numObjsToConcat, maxDepth);
1119                      Tcl_DStringFree(&textBuffer);                      Tcl_DStringFree(&textBuffer);
1120                  }                  }
1121                                    
1122                  code = TclCompileScript(interp, tokenPtr->start+1,                  code = TclCompileScript(interp, tokenPtr->start+1,
1123                          tokenPtr->size-2, /*nested*/ 1, envPtr);                          tokenPtr->size-2, /*nested*/ 1, envPtr);
1124                  if (code != TCL_OK) {                  if (code != TCL_OK) {
1125                      goto error;                      goto error;
1126                  }                  }
1127                  maxDepth = TclMax((numObjsToConcat + envPtr->maxStackDepth),                  maxDepth = TclMax((numObjsToConcat + envPtr->maxStackDepth),
1128                          maxDepth);                          maxDepth);
1129                  numObjsToConcat++;                  numObjsToConcat++;
1130                  break;                  break;
1131    
1132              case TCL_TOKEN_VARIABLE:              case TCL_TOKEN_VARIABLE:
1133                  /*                  /*
1134                   * Push any accumulated chars appearing before the $<var>.                   * Push any accumulated chars appearing before the $<var>.
1135                   */                   */
1136                                    
1137                  if (Tcl_DStringLength(&textBuffer) > 0) {                  if (Tcl_DStringLength(&textBuffer) > 0) {
1138                      int literal;                      int literal;
1139                                            
1140                      literal = TclRegisterLiteral(envPtr,                      literal = TclRegisterLiteral(envPtr,
1141                              Tcl_DStringValue(&textBuffer),                              Tcl_DStringValue(&textBuffer),
1142                              Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);                              Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
1143                      TclEmitPush(literal, envPtr);                      TclEmitPush(literal, envPtr);
1144                      numObjsToConcat++;                      numObjsToConcat++;
1145                      maxDepth = TclMax(numObjsToConcat, maxDepth);                      maxDepth = TclMax(numObjsToConcat, maxDepth);
1146                      Tcl_DStringFree(&textBuffer);                      Tcl_DStringFree(&textBuffer);
1147                  }                  }
1148                                    
1149                  /*                  /*
1150                   * Check if the name contains any namespace qualifiers.                   * Check if the name contains any namespace qualifiers.
1151                   */                   */
1152                                    
1153                  name = tokenPtr[1].start;                  name = tokenPtr[1].start;
1154                  nameBytes = tokenPtr[1].size;                  nameBytes = tokenPtr[1].size;
1155                  hasNsQualifiers = 0;                  hasNsQualifiers = 0;
1156                  for (i = 0, p = name;  i < nameBytes;  i++, p++) {                  for (i = 0, p = name;  i < nameBytes;  i++, p++) {
1157                      if ((*p == ':') && (i < (nameBytes-1))                      if ((*p == ':') && (i < (nameBytes-1))
1158                              && (*(p+1) == ':')) {                              && (*(p+1) == ':')) {
1159                          hasNsQualifiers = 1;                          hasNsQualifiers = 1;
1160                          break;                          break;
1161                      }                      }
1162                  }                  }
1163    
1164                  /*                  /*
1165                   * Either push the variable's name, or find its index in                   * Either push the variable's name, or find its index in
1166                   * the array of local variables in a procedure frame.                   * the array of local variables in a procedure frame.
1167                   */                   */
1168    
1169                  depthForVar = 0;                  depthForVar = 0;
1170                  if ((envPtr->procPtr == NULL) || hasNsQualifiers) {                  if ((envPtr->procPtr == NULL) || hasNsQualifiers) {
1171                      localVar = -1;                      localVar = -1;
1172                      TclEmitPush(TclRegisterLiteral(envPtr, name, nameBytes,                      TclEmitPush(TclRegisterLiteral(envPtr, name, nameBytes,
1173                              /*onHeap*/ 0), envPtr);                              /*onHeap*/ 0), envPtr);
1174                      depthForVar = 1;                      depthForVar = 1;
1175                  } else {                  } else {
1176                      localVar = TclFindCompiledLocal(name, nameBytes,                      localVar = TclFindCompiledLocal(name, nameBytes,
1177                              /*create*/ 0, /*flags*/ 0, envPtr->procPtr);                              /*create*/ 0, /*flags*/ 0, envPtr->procPtr);
1178                      if (localVar < 0) {                      if (localVar < 0) {
1179                          TclEmitPush(TclRegisterLiteral(envPtr, name,                          TclEmitPush(TclRegisterLiteral(envPtr, name,
1180                                  nameBytes, /*onHeap*/ 0), envPtr);                                  nameBytes, /*onHeap*/ 0), envPtr);
1181                          depthForVar = 1;                          depthForVar = 1;
1182                      }                      }
1183                  }                  }
1184    
1185                  /*                  /*
1186                   * Emit instructions to load the variable.                   * Emit instructions to load the variable.
1187                   */                   */
1188                                    
1189                  if (tokenPtr->numComponents == 1) {                  if (tokenPtr->numComponents == 1) {
1190                      if (localVar < 0) {                      if (localVar < 0) {
1191                          TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);                          TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
1192                      } else if (localVar <= 255) {                      } else if (localVar <= 255) {
1193                          TclEmitInstInt1(INST_LOAD_SCALAR1, localVar,                          TclEmitInstInt1(INST_LOAD_SCALAR1, localVar,
1194                                  envPtr);                                  envPtr);
1195                      } else {                      } else {
1196                          TclEmitInstInt4(INST_LOAD_SCALAR4, localVar,                          TclEmitInstInt4(INST_LOAD_SCALAR4, localVar,
1197                                  envPtr);                                  envPtr);
1198                      }                      }
1199                  } else {                  } else {
1200                      code = TclCompileTokens(interp, tokenPtr+2,                      code = TclCompileTokens(interp, tokenPtr+2,
1201                              tokenPtr->numComponents-1, envPtr);                              tokenPtr->numComponents-1, envPtr);
1202                      if (code != TCL_OK) {                      if (code != TCL_OK) {
1203                          sprintf(buffer,                          sprintf(buffer,
1204                                  "\n    (parsing index for array \"%.*s\")",                                  "\n    (parsing index for array \"%.*s\")",
1205                                  ((nameBytes > 100)? 100 : nameBytes), name);                                  ((nameBytes > 100)? 100 : nameBytes), name);
1206                          Tcl_AddObjErrorInfo(interp, buffer, -1);                          Tcl_AddObjErrorInfo(interp, buffer, -1);
1207                          goto error;                          goto error;
1208                      }                      }
1209                      depthForVar += envPtr->maxStackDepth;                      depthForVar += envPtr->maxStackDepth;
1210                      if (localVar < 0) {                      if (localVar < 0) {
1211                          TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);                          TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);
1212                      } else if (localVar <= 255) {                      } else if (localVar <= 255) {
1213                          TclEmitInstInt1(INST_LOAD_ARRAY1, localVar,                          TclEmitInstInt1(INST_LOAD_ARRAY1, localVar,
1214                                  envPtr);                                  envPtr);
1215                      } else {                      } else {
1216                          TclEmitInstInt4(INST_LOAD_ARRAY4, localVar,                          TclEmitInstInt4(INST_LOAD_ARRAY4, localVar,
1217                                  envPtr);                                  envPtr);
1218                      }                      }
1219                  }                  }
1220                  maxDepth = TclMax(numObjsToConcat + depthForVar, maxDepth);                  maxDepth = TclMax(numObjsToConcat + depthForVar, maxDepth);
1221                  numObjsToConcat++;                  numObjsToConcat++;
1222                  count -= tokenPtr->numComponents;                  count -= tokenPtr->numComponents;
1223                  tokenPtr += tokenPtr->numComponents;                  tokenPtr += tokenPtr->numComponents;
1224                  break;                  break;
1225    
1226              default:              default:
1227                  panic("Unexpected token type in TclCompileTokens");                  panic("Unexpected token type in TclCompileTokens");
1228          }          }
1229      }      }
1230    
1231      /*      /*
1232       * Push any accumulated characters appearing at the end.       * Push any accumulated characters appearing at the end.
1233       */       */
1234    
1235      if (Tcl_DStringLength(&textBuffer) > 0) {      if (Tcl_DStringLength(&textBuffer) > 0) {
1236          int literal;          int literal;
1237    
1238          literal = TclRegisterLiteral(envPtr, Tcl_DStringValue(&textBuffer),          literal = TclRegisterLiteral(envPtr, Tcl_DStringValue(&textBuffer),
1239                  Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);                  Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
1240          TclEmitPush(literal, envPtr);          TclEmitPush(literal, envPtr);
1241          numObjsToConcat++;          numObjsToConcat++;
1242          maxDepth = TclMax(numObjsToConcat, maxDepth);          maxDepth = TclMax(numObjsToConcat, maxDepth);
1243      }      }
1244    
1245      /*      /*
1246       * If necessary, concatenate the parts of the word.       * If necessary, concatenate the parts of the word.
1247       */       */
1248    
1249      while (numObjsToConcat > 255) {      while (numObjsToConcat > 255) {
1250          TclEmitInstInt1(INST_CONCAT1, 255, envPtr);          TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
1251          numObjsToConcat -= 254; /* concat pushes 1 obj, the result */          numObjsToConcat -= 254; /* concat pushes 1 obj, the result */
1252      }      }
1253      if (numObjsToConcat > 1) {      if (numObjsToConcat > 1) {
1254          TclEmitInstInt1(INST_CONCAT1, numObjsToConcat, envPtr);          TclEmitInstInt1(INST_CONCAT1, numObjsToConcat, envPtr);
1255      }      }
1256    
1257      /*      /*
1258       * If the tokens yielded no instructions, push an empty string.       * If the tokens yielded no instructions, push an empty string.
1259       */       */
1260            
1261      if (envPtr->codeNext == entryCodeNext) {      if (envPtr->codeNext == entryCodeNext) {
1262          TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0),          TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0),
1263                  envPtr);                  envPtr);
1264          maxDepth = 1;          maxDepth = 1;
1265      }      }
1266      Tcl_DStringFree(&textBuffer);      Tcl_DStringFree(&textBuffer);
1267      envPtr->maxStackDepth = maxDepth;      envPtr->maxStackDepth = maxDepth;
1268      return TCL_OK;      return TCL_OK;
1269    
1270      error:      error:
1271      Tcl_DStringFree(&textBuffer);      Tcl_DStringFree(&textBuffer);
1272      envPtr->maxStackDepth = maxDepth;      envPtr->maxStackDepth = maxDepth;
1273      return code;      return code;
1274  }  }
1275    
1276  /*  /*
1277   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1278   *   *
1279   * TclCompileCmdWord --   * TclCompileCmdWord --
1280   *   *
1281   *      Given an array of parse tokens for a word containing one or more Tcl   *      Given an array of parse tokens for a word containing one or more Tcl
1282   *      commands, emit inline instructions to execute them. This procedure   *      commands, emit inline instructions to execute them. This procedure
1283   *      differs from TclCompileTokens in that a simple word such as a loop   *      differs from TclCompileTokens in that a simple word such as a loop
1284   *      body enclosed in braces is not just pushed as a string, but is   *      body enclosed in braces is not just pushed as a string, but is
1285   *      itself parsed into tokens and compiled.   *      itself parsed into tokens and compiled.
1286   *   *
1287   * Results:   * Results:
1288   *      The return value is a standard Tcl result. If an error occurs, an   *      The return value is a standard Tcl result. If an error occurs, an
1289   *      error message is left in the interpreter's result.   *      error message is left in the interpreter's result.
1290   *         *      
1291   *      envPtr->maxStackDepth is updated with the maximum number of stack   *      envPtr->maxStackDepth is updated with the maximum number of stack
1292   *      elements needed to execute the tokens.   *      elements needed to execute the tokens.
1293   *   *
1294   * Side effects:   * Side effects:
1295   *      Instructions are added to envPtr to execute the tokens at runtime.   *      Instructions are added to envPtr to execute the tokens at runtime.
1296   *   *
1297   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1298   */   */
1299    
1300  int  int
1301  TclCompileCmdWord(interp, tokenPtr, count, envPtr)  TclCompileCmdWord(interp, tokenPtr, count, envPtr)
1302      Tcl_Interp *interp;         /* Used for error and status reporting. */      Tcl_Interp *interp;         /* Used for error and status reporting. */
1303      Tcl_Token *tokenPtr;        /* Pointer to first in an array of tokens      Tcl_Token *tokenPtr;        /* Pointer to first in an array of tokens
1304                                   * for a command word to compile inline. */                                   * for a command word to compile inline. */
1305      int count;                  /* Number of tokens to consider at tokenPtr.      int count;                  /* Number of tokens to consider at tokenPtr.
1306                                   * Must be at least 1. */                                   * Must be at least 1. */
1307      CompileEnv *envPtr;         /* Holds the resulting instructions. */      CompileEnv *envPtr;         /* Holds the resulting instructions. */
1308  {  {
1309      int code;      int code;
1310    
1311      /*      /*
1312       * Handle the common case: if there is a single text token, compile it       * Handle the common case: if there is a single text token, compile it
1313       * into an inline sequence of instructions.       * into an inline sequence of instructions.
1314       */       */
1315            
1316      envPtr->maxStackDepth = 0;      envPtr->maxStackDepth = 0;
1317      if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) {      if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) {
1318          code = TclCompileScript(interp, tokenPtr->start, tokenPtr->size,          code = TclCompileScript(interp, tokenPtr->start, tokenPtr->size,
1319                  /*nested*/ 0, envPtr);                  /*nested*/ 0, envPtr);
1320          return code;          return code;
1321      }      }
1322    
1323      /*      /*
1324       * Multiple tokens or the single token involves substitutions. Emit       * Multiple tokens or the single token involves substitutions. Emit
1325       * instructions to invoke the eval command procedure at runtime on the       * instructions to invoke the eval command procedure at runtime on the
1326       * result of evaluating the tokens.       * result of evaluating the tokens.
1327       */       */
1328    
1329      code = TclCompileTokens(interp, tokenPtr, count, envPtr);      code = TclCompileTokens(interp, tokenPtr, count, envPtr);
1330      if (code != TCL_OK) {      if (code != TCL_OK) {
1331          return code;          return code;
1332      }      }
1333      TclEmitOpcode(INST_EVAL_STK, envPtr);      TclEmitOpcode(INST_EVAL_STK, envPtr);
1334      return TCL_OK;      return TCL_OK;
1335  }  }
1336    
1337  /*  /*
1338   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1339   *   *
1340   * TclCompileExprWords --   * TclCompileExprWords --
1341   *   *
1342   *      Given an array of parse tokens representing one or more words that   *      Given an array of parse tokens representing one or more words that
1343   *      contain a Tcl expression, emit inline instructions to execute the   *      contain a Tcl expression, emit inline instructions to execute the
1344   *      expression. This procedure differs from TclCompileExpr in that it   *      expression. This procedure differs from TclCompileExpr in that it
1345   *      supports Tcl's two-level substitution semantics for expressions that   *      supports Tcl's two-level substitution semantics for expressions that
1346   *      appear as command words.   *      appear as command words.
1347   *   *
1348   * Results:   * Results:
1349   *      The return value is a standard Tcl result. If an error occurs, an   *      The return value is a standard Tcl result. If an error occurs, an
1350   *      error message is left in the interpreter's result.   *      error message is left in the interpreter's result.
1351   *         *      
1352   *      envPtr->maxStackDepth is updated with the maximum number of stack   *      envPtr->maxStackDepth is updated with the maximum number of stack
1353   *      elements needed to execute the expression.   *      elements needed to execute the expression.
1354   *   *
1355   * Side effects:   * Side effects:
1356   *      Instructions are added to envPtr to execute the expression.   *      Instructions are added to envPtr to execute the expression.
1357   *   *
1358   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1359   */   */
1360    
1361  int  int
1362  TclCompileExprWords(interp, tokenPtr, numWords, envPtr)  TclCompileExprWords(interp, tokenPtr, numWords, envPtr)
1363      Tcl_Interp *interp;         /* Used for error and status reporting. */      Tcl_Interp *interp;         /* Used for error and status reporting. */
1364      Tcl_Token *tokenPtr;        /* Points to first in an array of word      Tcl_Token *tokenPtr;        /* Points to first in an array of word
1365                                   * tokens tokens for the expression to                                   * tokens tokens for the expression to
1366                                   * compile inline. */                                   * compile inline. */
1367      int numWords;               /* Number of word tokens starting at      int numWords;               /* Number of word tokens starting at
1368                                   * tokenPtr. Must be at least 1. Each word                                   * tokenPtr. Must be at least 1. Each word
1369                                   * token contains one or more subtokens. */                                   * token contains one or more subtokens. */
1370      CompileEnv *envPtr;         /* Holds the resulting instructions. */      CompileEnv *envPtr;         /* Holds the resulting instructions. */
1371  {  {
1372      Tcl_Token *wordPtr;      Tcl_Token *wordPtr;
1373      int maxDepth, range, numBytes, i, code;      int maxDepth, range, numBytes, i, code;
1374      char *script;      char *script;
1375      int saveExprIsJustVarRef = envPtr->exprIsJustVarRef;      int saveExprIsJustVarRef = envPtr->exprIsJustVarRef;
1376      int saveExprIsComparison = envPtr->exprIsComparison;      int saveExprIsComparison = envPtr->exprIsComparison;
1377    
1378      envPtr->maxStackDepth = 0;      envPtr->maxStackDepth = 0;
1379      maxDepth = 0;      maxDepth = 0;
1380      range = -1;      range = -1;
1381      code = TCL_OK;      code = TCL_OK;
1382    
1383      /*      /*
1384       * If the expression is a single word that doesn't require       * If the expression is a single word that doesn't require
1385       * substitutions, just compile it's string into inline instructions.       * substitutions, just compile it's string into inline instructions.
1386       */       */
1387    
1388      if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {      if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
1389          /*          /*
1390           * Temporarily overwrite the character just after the end of the           * Temporarily overwrite the character just after the end of the
1391           * string with a 0 byte.           * string with a 0 byte.
1392           */           */
1393    
1394          script = tokenPtr[1].start;          script = tokenPtr[1].start;
1395          numBytes = tokenPtr[1].size;          numBytes = tokenPtr[1].size;
1396          code = TclCompileExpr(interp, script, numBytes, envPtr);          code = TclCompileExpr(interp, script, numBytes, envPtr);
1397          return code;          return code;
1398      }      }
1399        
1400      /*      /*
1401       * Emit code to call the expr command proc at runtime. Concatenate the       * Emit code to call the expr command proc at runtime. Concatenate the
1402       * (already substituted once) expr tokens with a space between each.       * (already substituted once) expr tokens with a space between each.
1403       */       */
1404    
1405      wordPtr = tokenPtr;      wordPtr = tokenPtr;
1406      for (i = 0;  i < numWords;  i++) {      for (i = 0;  i < numWords;  i++) {
1407          code = TclCompileTokens(interp, wordPtr+1, wordPtr->numComponents,          code = TclCompileTokens(interp, wordPtr+1, wordPtr->numComponents,
1408                  envPtr);                  envPtr);
1409          if (code != TCL_OK) {          if (code != TCL_OK) {
1410              break;              break;
1411          }          }
1412          if (i < (numWords - 1)) {          if (i < (numWords - 1)) {
1413              TclEmitPush(TclRegisterLiteral(envPtr, " ", 1, /*onHeap*/ 0),              TclEmitPush(TclRegisterLiteral(envPtr, " ", 1, /*onHeap*/ 0),
1414                      envPtr);                      envPtr);
1415              maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);              maxDepth = TclMax((envPtr->maxStackDepth + 1), maxDepth);
1416          } else {          } else {
1417              maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);              maxDepth = TclMax(envPtr->maxStackDepth, maxDepth);
1418          }          }
1419          wordPtr += (wordPtr->numComponents + 1);          wordPtr += (wordPtr->numComponents + 1);
1420      }      }
1421      if (code == TCL_OK) {      if (code == TCL_OK) {
1422          int concatItems = 2*numWords - 1;          int concatItems = 2*numWords - 1;
1423          while (concatItems > 255) {          while (concatItems > 255) {
1424              TclEmitInstInt1(INST_CONCAT1, 255, envPtr);              TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
1425              concatItems -= 254;              concatItems -= 254;
1426          }          }
1427          if (concatItems > 1) {          if (concatItems > 1) {
1428              TclEmitInstInt1(INST_CONCAT1, concatItems, envPtr);              TclEmitInstInt1(INST_CONCAT1, concatItems, envPtr);
1429          }          }
1430          TclEmitOpcode(INST_EXPR_STK, envPtr);          TclEmitOpcode(INST_EXPR_STK, envPtr);
1431      }      }
1432    
1433      envPtr->exprIsJustVarRef = saveExprIsJustVarRef;      envPtr->exprIsJustVarRef = saveExprIsJustVarRef;
1434      envPtr->exprIsComparison = saveExprIsComparison;      envPtr->exprIsComparison = saveExprIsComparison;
1435      envPtr->maxStackDepth = maxDepth;      envPtr->maxStackDepth = maxDepth;
1436      return code;      return code;
1437  }  }
1438    
1439  /*  /*
1440   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1441   *   *
1442   * TclInitByteCodeObj --   * TclInitByteCodeObj --
1443   *   *
1444   *      Create a ByteCode structure and initialize it from a CompileEnv   *      Create a ByteCode structure and initialize it from a CompileEnv
1445   *      compilation environment structure. The ByteCode structure is   *      compilation environment structure. The ByteCode structure is
1446   *      smaller and contains just that information needed to execute   *      smaller and contains just that information needed to execute
1447   *      the bytecode instructions resulting from compiling a Tcl script.   *      the bytecode instructions resulting from compiling a Tcl script.
1448   *      The resulting structure is placed in the specified object.   *      The resulting structure is placed in the specified object.
1449   *   *
1450   * Results:   * Results:
1451   *      A newly constructed ByteCode object is stored in the internal   *      A newly constructed ByteCode object is stored in the internal
1452   *      representation of the objPtr.   *      representation of the objPtr.
1453   *   *
1454   * Side effects:   * Side effects:
1455   *      A single heap object is allocated to hold the new ByteCode structure   *      A single heap object is allocated to hold the new ByteCode structure
1456   *      and its code, object, command location, and aux data arrays. Note   *      and its code, object, command location, and aux data arrays. Note
1457   *      that "ownership" (i.e., the pointers to) the Tcl objects and aux   *      that "ownership" (i.e., the pointers to) the Tcl objects and aux
1458   *      data items will be handed over to the new ByteCode structure from   *      data items will be handed over to the new ByteCode structure from
1459   *      the CompileEnv structure.   *      the CompileEnv structure.
1460   *   *
1461   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1462   */   */
1463    
1464  void  void
1465  TclInitByteCodeObj(objPtr, envPtr)  TclInitByteCodeObj(objPtr, envPtr)
1466      Tcl_Obj *objPtr;             /* Points object that should be      Tcl_Obj *objPtr;             /* Points object that should be
1467                                    * initialized, and whose string rep                                    * initialized, and whose string rep
1468                                    * contains the source code. */                                    * contains the source code. */
1469      register CompileEnv *envPtr; /* Points to the CompileEnv structure from      register CompileEnv *envPtr; /* Points to the CompileEnv structure from
1470                                    * which to create a ByteCode structure. */                                    * which to create a ByteCode structure. */
1471  {  {
1472      register ByteCode *codePtr;      register ByteCode *codePtr;
1473      size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes;      size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes;
1474      size_t auxDataArrayBytes, structureSize;      size_t auxDataArrayBytes, structureSize;
1475      register unsigned char *p;      register unsigned char *p;
1476      unsigned char *nextPtr;      unsigned char *nextPtr;
1477      int numLitObjects = envPtr->literalArrayNext;      int numLitObjects = envPtr->literalArrayNext;
1478      Namespace *namespacePtr;      Namespace *namespacePtr;
1479      int i;      int i;
1480      Interp *iPtr;      Interp *iPtr;
1481    
1482      iPtr = envPtr->iPtr;      iPtr = envPtr->iPtr;
1483    
1484      codeBytes = (envPtr->codeNext - envPtr->codeStart);      codeBytes = (envPtr->codeNext - envPtr->codeStart);
1485      objArrayBytes = (envPtr->literalArrayNext * sizeof(Tcl_Obj *));      objArrayBytes = (envPtr->literalArrayNext * sizeof(Tcl_Obj *));
1486      exceptArrayBytes = (envPtr->exceptArrayNext * sizeof(ExceptionRange));      exceptArrayBytes = (envPtr->exceptArrayNext * sizeof(ExceptionRange));
1487      auxDataArrayBytes = (envPtr->auxDataArrayNext * sizeof(AuxData));      auxDataArrayBytes = (envPtr->auxDataArrayNext * sizeof(AuxData));
1488      cmdLocBytes = GetCmdLocEncodingSize(envPtr);      cmdLocBytes = GetCmdLocEncodingSize(envPtr);
1489            
1490      /*      /*
1491       * Compute the total number of bytes needed for this bytecode.       * Compute the total number of bytes needed for this bytecode.
1492       */       */
1493    
1494      structureSize = sizeof(ByteCode);      structureSize = sizeof(ByteCode);
1495      structureSize += TCL_ALIGN(codeBytes);        /* align object array */      structureSize += TCL_ALIGN(codeBytes);        /* align object array */
1496      structureSize += TCL_ALIGN(objArrayBytes);    /* align exc range arr */      structureSize += TCL_ALIGN(objArrayBytes);    /* align exc range arr */
1497      structureSize += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */      structureSize += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
1498      structureSize += auxDataArrayBytes;      structureSize += auxDataArrayBytes;
1499      structureSize += cmdLocBytes;      structureSize += cmdLocBytes;
1500    
1501      if (envPtr->iPtr->varFramePtr != NULL) {      if (envPtr->iPtr->varFramePtr != NULL) {
1502          namespacePtr = envPtr->iPtr->varFramePtr->nsPtr;          namespacePtr = envPtr->iPtr->varFramePtr->nsPtr;
1503      } else {      } else {
1504          namespacePtr = envPtr->iPtr->globalNsPtr;          namespacePtr = envPtr->iPtr->globalNsPtr;
1505      }      }
1506            
1507      p = (unsigned char *) ckalloc((size_t) structureSize);      p = (unsigned char *) ckalloc((size_t) structureSize);
1508      codePtr = (ByteCode *) p;      codePtr = (ByteCode *) p;
1509      codePtr->interpHandle = TclHandlePreserve(iPtr->handle);      codePtr->interpHandle = TclHandlePreserve(iPtr->handle);
1510      codePtr->compileEpoch = iPtr->compileEpoch;      codePtr->compileEpoch = iPtr->compileEpoch;
1511      codePtr->nsPtr = namespacePtr;      codePtr->nsPtr = namespacePtr;
1512      codePtr->nsEpoch = namespacePtr->resolverEpoch;      codePtr->nsEpoch = namespacePtr->resolverEpoch;
1513      codePtr->refCount = 1;      codePtr->refCount = 1;
1514      codePtr->flags = 0;      codePtr->flags = 0;
1515      codePtr->source = envPtr->source;      codePtr->source = envPtr->source;
1516      codePtr->procPtr = envPtr->procPtr;      codePtr->procPtr = envPtr->procPtr;
1517    
1518      codePtr->numCommands = envPtr->numCommands;      codePtr->numCommands = envPtr->numCommands;
1519      codePtr->numSrcBytes = envPtr->numSrcBytes;      codePtr->numSrcBytes = envPtr->numSrcBytes;
1520      codePtr->numCodeBytes = codeBytes;      codePtr->numCodeBytes = codeBytes;
1521      codePtr->numLitObjects = numLitObjects;      codePtr->numLitObjects = numLitObjects;
1522      codePtr->numExceptRanges = envPtr->exceptArrayNext;      codePtr->numExceptRanges = envPtr->exceptArrayNext;
1523      codePtr->numAuxDataItems = envPtr->auxDataArrayNext;      codePtr->numAuxDataItems = envPtr->auxDataArrayNext;
1524      codePtr->numCmdLocBytes = cmdLocBytes;      codePtr->numCmdLocBytes = cmdLocBytes;
1525      codePtr->maxExceptDepth = envPtr->maxExceptDepth;      codePtr->maxExceptDepth = envPtr->maxExceptDepth;
1526      codePtr->maxStackDepth = envPtr->maxStackDepth;      codePtr->maxStackDepth = envPtr->maxStackDepth;
1527            
1528      p += sizeof(ByteCode);      p += sizeof(ByteCode);
1529      codePtr->codeStart = p;      codePtr->codeStart = p;
1530      memcpy((VOID *) p, (VOID *) envPtr->codeStart, (size_t) codeBytes);      memcpy((VOID *) p, (VOID *) envPtr->codeStart, (size_t) codeBytes);
1531            
1532      p += TCL_ALIGN(codeBytes);        /* align object array */      p += TCL_ALIGN(codeBytes);        /* align object array */
1533      codePtr->objArrayPtr = (Tcl_Obj **) p;      codePtr->objArrayPtr = (Tcl_Obj **) p;
1534      for (i = 0;  i < numLitObjects;  i++) {      for (i = 0;  i < numLitObjects;  i++) {
1535          codePtr->objArrayPtr[i] = envPtr->literalArrayPtr[i].objPtr;          codePtr->objArrayPtr[i] = envPtr->literalArrayPtr[i].objPtr;
1536      }      }
1537    
1538      p += TCL_ALIGN(objArrayBytes);    /* align exception range array */      p += TCL_ALIGN(objArrayBytes);    /* align exception range array */
1539      if (exceptArrayBytes > 0) {      if (exceptArrayBytes > 0) {
1540          codePtr->exceptArrayPtr = (ExceptionRange *) p;          codePtr->exceptArrayPtr = (ExceptionRange *) p;
1541          memcpy((VOID *) p, (VOID *) envPtr->exceptArrayPtr,          memcpy((VOID *) p, (VOID *) envPtr->exceptArrayPtr,
1542                  (size_t) exceptArrayBytes);                  (size_t) exceptArrayBytes);
1543      } else {      } else {
1544          codePtr->exceptArrayPtr = NULL;          codePtr->exceptArrayPtr = NULL;
1545      }      }
1546            
1547      p += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */      p += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
1548      if (auxDataArrayBytes > 0) {      if (auxDataArrayBytes > 0) {
1549          codePtr->auxDataArrayPtr = (AuxData *) p;          codePtr->auxDataArrayPtr = (AuxData *) p;
1550          memcpy((VOID *) p, (VOID *) envPtr->auxDataArrayPtr,          memcpy((VOID *) p, (VOID *) envPtr->auxDataArrayPtr,
1551                  (size_t) auxDataArrayBytes);                  (size_t) auxDataArrayBytes);
1552      } else {      } else {
1553          codePtr->auxDataArrayPtr = NULL;          codePtr->auxDataArrayPtr = NULL;
1554      }      }
1555    
1556      p += auxDataArrayBytes;      p += auxDataArrayBytes;
1557      nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);      nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
1558  #ifdef TCL_COMPILE_DEBUG  #ifdef TCL_COMPILE_DEBUG
1559      if (((size_t)(nextPtr - p)) != cmdLocBytes) {            if (((size_t)(nextPtr - p)) != cmdLocBytes) {      
1560          panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d\n", (nextPtr - p), cmdLocBytes);          panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d\n", (nextPtr - p), cmdLocBytes);
1561      }      }
1562  #endif  #endif
1563            
1564      /*      /*
1565       * Record various compilation-related statistics about the new ByteCode       * Record various compilation-related statistics about the new ByteCode
1566       * structure. Don't include overhead for statistics-related fields.       * structure. Don't include overhead for statistics-related fields.
1567       */       */
1568    
1569  #ifdef TCL_COMPILE_STATS  #ifdef TCL_COMPILE_STATS
1570      codePtr->structureSize = structureSize      codePtr->structureSize = structureSize
1571              - (sizeof(size_t) + sizeof(Tcl_Time));              - (sizeof(size_t) + sizeof(Tcl_Time));
1572      TclpGetTime(&(codePtr->createTime));      TclpGetTime(&(codePtr->createTime));
1573            
1574      RecordByteCodeStats(codePtr);      RecordByteCodeStats(codePtr);
1575  #endif /* TCL_COMPILE_STATS */  #endif /* TCL_COMPILE_STATS */
1576            
1577      /*      /*
1578       * Free the old internal rep then convert the object to a       * Free the old internal rep then convert the object to a
1579       * bytecode object by making its internal rep point to the just       * bytecode object by making its internal rep point to the just
1580       * compiled ByteCode.       * compiled ByteCode.
1581       */       */
1582                            
1583      if ((objPtr->typePtr != NULL) &&      if ((objPtr->typePtr != NULL) &&
1584              (objPtr->typePtr->freeIntRepProc != NULL)) {              (objPtr->typePtr->freeIntRepProc != NULL)) {
1585          (*objPtr->typePtr->freeIntRepProc)(objPtr);          (*objPtr->typePtr->freeIntRepProc)(objPtr);
1586      }      }
1587      objPtr->internalRep.otherValuePtr = (VOID *) codePtr;      objPtr->internalRep.otherValuePtr = (VOID *) codePtr;
1588      objPtr->typePtr = &tclByteCodeType;      objPtr->typePtr = &tclByteCodeType;
1589  }  }
1590    
1591  /*  /*
1592   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1593   *   *
1594   * LogCompilationInfo --   * LogCompilationInfo --
1595   *   *
1596   *      This procedure is invoked after an error occurs during compilation.   *      This procedure is invoked after an error occurs during compilation.
1597   *      It adds information to the "errorInfo" variable to describe the   *      It adds information to the "errorInfo" variable to describe the
1598   *      command that was being compiled when the error occurred.   *      command that was being compiled when the error occurred.
1599   *   *
1600   * Results:   * Results:
1601   *      None.   *      None.
1602   *   *
1603   * Side effects:   * Side effects:
1604   *      Information about the command is added to errorInfo and the   *      Information about the command is added to errorInfo and the
1605   *      line number stored internally in the interpreter is set.  If this   *      line number stored internally in the interpreter is set.  If this
1606   *      is the first call to this procedure or Tcl_AddObjErrorInfo since   *      is the first call to this procedure or Tcl_AddObjErrorInfo since
1607   *      an error occurred, then old information in errorInfo is   *      an error occurred, then old information in errorInfo is
1608   *      deleted.   *      deleted.
1609   *   *
1610   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1611   */   */
1612    
1613  static void  static void
1614  LogCompilationInfo(interp, script, command, length)  LogCompilationInfo(interp, script, command, length)
1615      Tcl_Interp *interp;         /* Interpreter in which to log the      Tcl_Interp *interp;         /* Interpreter in which to log the
1616                                   * information. */                                   * information. */
1617      char *script;               /* First character in script containing      char *script;               /* First character in script containing
1618                                   * command (must be <= command). */                                   * command (must be <= command). */
1619      char *command;              /* First character in command that      char *command;              /* First character in command that
1620                                   * generated the error. */                                   * generated the error. */
1621      int length;                 /* Number of bytes in command (-1 means      int length;                 /* Number of bytes in command (-1 means
1622                                   * use all bytes up to first null byte). */                                   * use all bytes up to first null byte). */
1623  {  {
1624      char buffer[200];      char buffer[200];
1625      register char *p;      register char *p;
1626      char *ellipsis = "";      char *ellipsis = "";
1627      Interp *iPtr = (Interp *) interp;      Interp *iPtr = (Interp *) interp;
1628    
1629      if (iPtr->flags & ERR_ALREADY_LOGGED) {      if (iPtr->flags & ERR_ALREADY_LOGGED) {
1630          /*          /*
1631           * Someone else has already logged error information for this           * Someone else has already logged error information for this
1632           * command; we shouldn't add anything more.           * command; we shouldn't add anything more.
1633           */           */
1634    
1635          return;          return;
1636      }      }
1637    
1638      /*      /*
1639       * Compute the line number where the error occurred.       * Compute the line number where the error occurred.
1640       */       */
1641    
1642      iPtr->errorLine = 1;      iPtr->errorLine = 1;
1643      for (p = script; p != command; p++) {      for (p = script; p != command; p++) {
1644          if (*p == '\n') {          if (*p == '\n') {
1645              iPtr->errorLine++;              iPtr->errorLine++;
1646          }          }
1647      }      }
1648    
1649      /*      /*
1650       * Create an error message to add to errorInfo, including up to a       * Create an error message to add to errorInfo, including up to a
1651       * maximum number of characters of the command.       * maximum number of characters of the command.
1652       */       */
1653    
1654      if (length < 0) {      if (length < 0) {
1655          length = strlen(command);          length = strlen(command);
1656      }      }
1657      if (length > 150) {      if (length > 150) {
1658          length = 150;          length = 150;
1659          ellipsis = "...";          ellipsis = "...";
1660      }      }
1661      sprintf(buffer, "\n    while compiling\n\"%.*s%s\"",      sprintf(buffer, "\n    while compiling\n\"%.*s%s\"",
1662              length, command, ellipsis);              length, command, ellipsis);
1663      Tcl_AddObjErrorInfo(interp, buffer, -1);      Tcl_AddObjErrorInfo(interp, buffer, -1);
1664  }  }
1665    
1666  /*  /*
1667   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1668   *   *
1669   * TclFindCompiledLocal --   * TclFindCompiledLocal --
1670   *   *
1671   *      This procedure is called at compile time to look up and optionally   *      This procedure is called at compile time to look up and optionally
1672   *      allocate an entry ("slot") for a variable in a procedure's array of   *      allocate an entry ("slot") for a variable in a procedure's array of
1673   *      local variables. If the variable's name is NULL, a new temporary   *      local variables. If the variable's name is NULL, a new temporary
1674   *      variable is always created. (Such temporary variables can only be   *      variable is always created. (Such temporary variables can only be
1675   *      referenced using their slot index.)   *      referenced using their slot index.)
1676   *   *
1677   * Results:   * Results:
1678   *      If create is 0 and the name is non-NULL, then if the variable is   *      If create is 0 and the name is non-NULL, then if the variable is
1679   *      found, the index of its entry in the procedure's array of local   *      found, the index of its entry in the procedure's array of local
1680   *      variables is returned; otherwise -1 is returned. If name is NULL,   *      variables is returned; otherwise -1 is returned. If name is NULL,
1681   *      the index of a new temporary variable is returned. Finally, if   *      the index of a new temporary variable is returned. Finally, if
1682   *      create is 1 and name is non-NULL, the index of a new entry is   *      create is 1 and name is non-NULL, the index of a new entry is
1683   *      returned.   *      returned.
1684   *   *
1685   * Side effects:   * Side effects:
1686   *      Creates and registers a new local variable if create is 1 and   *      Creates and registers a new local variable if create is 1 and
1687   *      the variable is unknown, or if the name is NULL.   *      the variable is unknown, or if the name is NULL.
1688   *   *
1689   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1690   */   */
1691    
1692  int  int
1693  TclFindCompiledLocal(name, nameBytes, create, flags, procPtr)  TclFindCompiledLocal(name, nameBytes, create, flags, procPtr)
1694      register char *name;        /* Points to first character of the name of      register char *name;        /* Points to first character of the name of
1695                                   * a scalar or array variable. If NULL, a                                   * a scalar or array variable. If NULL, a
1696                                   * temporary var should be created. */                                   * temporary var should be created. */
1697      int nameBytes;              /* Number of bytes in the name. */      int nameBytes;              /* Number of bytes in the name. */
1698      int create;                 /* If 1, allocate a local frame entry for      int create;                 /* If 1, allocate a local frame entry for
1699                                   * the variable if it is new. */                                   * the variable if it is new. */
1700      int flags;                  /* Flag bits for the compiled local if      int flags;                  /* Flag bits for the compiled local if
1701                                   * created. Only VAR_SCALAR, VAR_ARRAY, and                                   * created. Only VAR_SCALAR, VAR_ARRAY, and
1702                                   * VAR_LINK make sense. */                                   * VAR_LINK make sense. */
1703      register Proc *procPtr;     /* Points to structure describing procedure      register Proc *procPtr;     /* Points to structure describing procedure
1704                                   * containing the variable reference. */                                   * containing the variable reference. */
1705  {  {
1706      register CompiledLocal *localPtr;      register CompiledLocal *localPtr;
1707      int localVar = -1;      int localVar = -1;
1708      register int i;      register int i;
1709    
1710      /*      /*
1711       * If not creating a temporary, does a local variable of the specified       * If not creating a temporary, does a local variable of the specified
1712       * name already exist?       * name already exist?
1713       */       */
1714    
1715      if (name != NULL) {      if (name != NULL) {
1716          int localCt = procPtr->numCompiledLocals;          int localCt = procPtr->numCompiledLocals;
1717          localPtr = procPtr->firstLocalPtr;          localPtr = procPtr->firstLocalPtr;
1718          for (i = 0;  i < localCt;  i++) {          for (i = 0;  i < localCt;  i++) {
1719              if (!TclIsVarTemporary(localPtr)) {              if (!TclIsVarTemporary(localPtr)) {
1720                  char *localName = localPtr->name;                  char *localName = localPtr->name;
1721                  if ((nameBytes == localPtr->nameLength)                  if ((nameBytes == localPtr->nameLength)
1722                          && (strncmp(name, localName, (unsigned) nameBytes) == 0)) {                          && (strncmp(name, localName, (unsigned) nameBytes) == 0)) {
1723                      return i;                      return i;
1724                  }                  }
1725              }              }
1726              localPtr = localPtr->nextPtr;              localPtr = localPtr->nextPtr;
1727          }          }
1728      }      }
1729    
1730      /*      /*
1731       * Create a new variable if appropriate.       * Create a new variable if appropriate.
1732       */       */
1733            
1734      if (create || (name == NULL)) {      if (create || (name == NULL)) {
1735          localVar = procPtr->numCompiledLocals;          localVar = procPtr->numCompiledLocals;
1736          localPtr = (CompiledLocal *) ckalloc((unsigned)          localPtr = (CompiledLocal *) ckalloc((unsigned)
1737                  (sizeof(CompiledLocal) - sizeof(localPtr->name)                  (sizeof(CompiledLocal) - sizeof(localPtr->name)
1738                  + nameBytes+1));                  + nameBytes+1));
1739          if (procPtr->firstLocalPtr == NULL) {          if (procPtr->firstLocalPtr == NULL) {
1740              procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;              procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
1741          } else {          } else {
1742              procPtr->lastLocalPtr->nextPtr = localPtr;              procPtr->lastLocalPtr->nextPtr = localPtr;
1743              procPtr->lastLocalPtr = localPtr;              procPtr->lastLocalPtr = localPtr;
1744          }          }
1745          localPtr->nextPtr = NULL;          localPtr->nextPtr = NULL;
1746          localPtr->nameLength = nameBytes;          localPtr->nameLength = nameBytes;
1747          localPtr->frameIndex = localVar;          localPtr->frameIndex = localVar;
1748          localPtr->flags = flags;          localPtr->flags = flags;
1749          if (name == NULL) {          if (name == NULL) {
1750              localPtr->flags |= VAR_TEMPORARY;              localPtr->flags |= VAR_TEMPORARY;
1751          }          }
1752          localPtr->defValuePtr = NULL;          localPtr->defValuePtr = NULL;
1753          localPtr->resolveInfo = NULL;          localPtr->resolveInfo = NULL;
1754    
1755          if (name != NULL) {          if (name != NULL) {
1756              memcpy((VOID *) localPtr->name, (VOID *) name,              memcpy((VOID *) localPtr->name, (VOID *) name,
1757                      (size_t) nameBytes);                      (size_t) nameBytes);
1758          }          }
1759          localPtr->name[nameBytes] = '\0';          localPtr->name[nameBytes] = '\0';
1760          procPtr->numCompiledLocals++;          procPtr->numCompiledLocals++;
1761      }      }
1762      return localVar;      return localVar;
1763  }  }
1764    
1765  /*  /*
1766   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1767   *   *
1768   * TclInitCompiledLocals --   * TclInitCompiledLocals --
1769   *   *
1770   *      This routine is invoked in order to initialize the compiled   *      This routine is invoked in order to initialize the compiled
1771   *      locals table for a new call frame.   *      locals table for a new call frame.
1772   *   *
1773   * Results:   * Results:
1774   *      None.   *      None.
1775   *   *
1776   * Side effects:   * Side effects:
1777   *      May invoke various name resolvers in order to determine which   *      May invoke various name resolvers in order to determine which
1778   *      variables are being referenced at runtime.   *      variables are being referenced at runtime.
1779   *   *
1780   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1781   */   */
1782    
1783  void  void
1784  TclInitCompiledLocals(interp, framePtr, nsPtr)  TclInitCompiledLocals(interp, framePtr, nsPtr)
1785      Tcl_Interp *interp;         /* Current interpreter. */      Tcl_Interp *interp;         /* Current interpreter. */
1786      CallFrame *framePtr;        /* Call frame to initialize. */      CallFrame *framePtr;        /* Call frame to initialize. */
1787      Namespace *nsPtr;           /* Pointer to current namespace. */      Namespace *nsPtr;           /* Pointer to current namespace. */
1788  {  {
1789      register CompiledLocal *localPtr;      register CompiledLocal *localPtr;
1790      Interp *iPtr = (Interp*) interp;      Interp *iPtr = (Interp*) interp;
1791      Tcl_ResolvedVarInfo *vinfo, *resVarInfo;      Tcl_ResolvedVarInfo *vinfo, *resVarInfo;
1792      Var *varPtr = framePtr->compiledLocals;      Var *varPtr = framePtr->compiledLocals;
1793      Var *resolvedVarPtr;      Var *resolvedVarPtr;
1794      ResolverScheme *resPtr;      ResolverScheme *resPtr;
1795      int result;      int result;
1796    
1797      /*      /*
1798       * Initialize the array of local variables stored in the call frame.       * Initialize the array of local variables stored in the call frame.
1799       * Some variables may have special resolution rules.  In that case,       * Some variables may have special resolution rules.  In that case,
1800       * we call their "resolver" procs to get our hands on the variable,       * we call their "resolver" procs to get our hands on the variable,
1801       * and we make the compiled local a link to the real variable.       * and we make the compiled local a link to the real variable.
1802       */       */
1803    
1804      for (localPtr = framePtr->procPtr->firstLocalPtr;      for (localPtr = framePtr->procPtr->firstLocalPtr;
1805           localPtr != NULL;           localPtr != NULL;
1806           localPtr = localPtr->nextPtr) {           localPtr = localPtr->nextPtr) {
1807    
1808          /*          /*
1809           * Check to see if this local is affected by namespace or           * Check to see if this local is affected by namespace or
1810           * interp resolvers.  The resolver to use is cached for the           * interp resolvers.  The resolver to use is cached for the
1811           * next invocation of the procedure.           * next invocation of the procedure.
1812           */           */
1813    
1814          if (!(localPtr->flags & (VAR_ARGUMENT|VAR_TEMPORARY|VAR_RESOLVED))          if (!(localPtr->flags & (VAR_ARGUMENT|VAR_TEMPORARY|VAR_RESOLVED))
1815                  && (nsPtr->compiledVarResProc || iPtr->resolverPtr)) {                  && (nsPtr->compiledVarResProc || iPtr->resolverPtr)) {
1816              resPtr = iPtr->resolverPtr;              resPtr = iPtr->resolverPtr;
1817    
1818              if (nsPtr->compiledVarResProc) {              if (nsPtr->compiledVarResProc) {
1819                  result = (*nsPtr->compiledVarResProc)(nsPtr->interp,                  result = (*nsPtr->compiledVarResProc)(nsPtr->interp,
1820                          localPtr->name, localPtr->nameLength,                          localPtr->name, localPtr->nameLength,
1821                          (Tcl_Namespace *) nsPtr, &vinfo);                          (Tcl_Namespace *) nsPtr, &vinfo);
1822              } else {              } else {
1823                  result = TCL_CONTINUE;                  result = TCL_CONTINUE;
1824              }              }
1825    
1826              while ((result == TCL_CONTINUE) && resPtr) {              while ((result == TCL_CONTINUE) && resPtr) {
1827                  if (resPtr->compiledVarResProc) {                  if (resPtr->compiledVarResProc) {
1828                      result = (*resPtr->compiledVarResProc)(nsPtr->interp,                      result = (*resPtr->compiledVarResProc)(nsPtr->interp,
1829                              localPtr->name, localPtr->nameLength,                              localPtr->name, localPtr->nameLength,
1830                              (Tcl_Namespace *) nsPtr, &vinfo);                              (Tcl_Namespace *) nsPtr, &vinfo);
1831                  }                  }
1832                  resPtr = resPtr->nextPtr;                  resPtr = resPtr->nextPtr;
1833              }              }
1834              if (result == TCL_OK) {              if (result == TCL_OK) {
1835                  localPtr->resolveInfo = vinfo;                  localPtr->resolveInfo = vinfo;
1836                  localPtr->flags |= VAR_RESOLVED;                  localPtr->flags |= VAR_RESOLVED;
1837              }              }
1838          }          }
1839    
1840          /*          /*
1841           * Now invoke the resolvers to determine the exact variables that           * Now invoke the resolvers to determine the exact variables that
1842           * should be used.           * should be used.
1843           */           */
1844    
1845          resVarInfo = localPtr->resolveInfo;          resVarInfo = localPtr->resolveInfo;
1846          resolvedVarPtr = NULL;          resolvedVarPtr = NULL;
1847    
1848          if (resVarInfo && resVarInfo->fetchProc) {          if (resVarInfo && resVarInfo->fetchProc) {
1849              resolvedVarPtr = (Var*) (*resVarInfo->fetchProc)(interp,              resolvedVarPtr = (Var*) (*resVarInfo->fetchProc)(interp,
1850                      resVarInfo);                      resVarInfo);
1851          }          }
1852    
1853          if (resolvedVarPtr) {          if (resolvedVarPtr) {
1854              varPtr->name = localPtr->name; /* will be just '\0' if temp var */              varPtr->name = localPtr->name; /* will be just '\0' if temp var */
1855              varPtr->nsPtr = NULL;              varPtr->nsPtr = NULL;
1856              varPtr->hPtr = NULL;              varPtr->hPtr = NULL;
1857              varPtr->refCount = 0;              varPtr->refCount = 0;
1858              varPtr->tracePtr = NULL;              varPtr->tracePtr = NULL;
1859              varPtr->searchPtr = NULL;              varPtr->searchPtr = NULL;
1860              varPtr->flags = 0;              varPtr->flags = 0;
1861              TclSetVarLink(varPtr);              TclSetVarLink(varPtr);
1862              varPtr->value.linkPtr = resolvedVarPtr;              varPtr->value.linkPtr = resolvedVarPtr;
1863              resolvedVarPtr->refCount++;              resolvedVarPtr->refCount++;
1864          } else {          } else {
1865              varPtr->value.objPtr = NULL;              varPtr->value.objPtr = NULL;
1866              varPtr->name = localPtr->name; /* will be just '\0' if temp var */              varPtr->name = localPtr->name; /* will be just '\0' if temp var */
1867              varPtr->nsPtr = NULL;              varPtr->nsPtr = NULL;
1868              varPtr->hPtr = NULL;              varPtr->hPtr = NULL;
1869              varPtr->refCount = 0;              varPtr->refCount = 0;
1870              varPtr->tracePtr = NULL;              varPtr->tracePtr = NULL;
1871              varPtr->searchPtr = NULL;              varPtr->searchPtr = NULL;
1872              varPtr->flags = (localPtr->flags | VAR_UNDEFINED);              varPtr->flags = (localPtr->flags | VAR_UNDEFINED);
1873          }          }
1874          varPtr++;          varPtr++;
1875      }      }
1876  }  }
1877    
1878  /*  /*
1879   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1880   *   *
1881   * TclExpandCodeArray --   * TclExpandCodeArray --
1882   *   *
1883   *      Procedure that uses malloc to allocate more storage for a   *      Procedure that uses malloc to allocate more storage for a
1884   *      CompileEnv's code array.   *      CompileEnv's code array.
1885   *   *
1886   * Results:   * Results:
1887   *      None.   *      None.
1888   *   *
1889   * Side effects:   * Side effects:
1890   *      The byte code array in *envPtr is reallocated to a new array of   *      The byte code array in *envPtr is reallocated to a new array of
1891   *      double the size, and if envPtr->mallocedCodeArray is non-zero the   *      double the size, and if envPtr->mallocedCodeArray is non-zero the
1892   *      old array is freed. Byte codes are copied from the old array to the   *      old array is freed. Byte codes are copied from the old array to the
1893   *      new one.   *      new one.
1894   *   *
1895   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1896   */   */
1897    
1898  void  void
1899  TclExpandCodeArray(envPtr)  TclExpandCodeArray(envPtr)
1900      CompileEnv *envPtr;         /* Points to the CompileEnv whose code array      CompileEnv *envPtr;         /* Points to the CompileEnv whose code array
1901                                   * must be enlarged. */                                   * must be enlarged. */
1902  {  {
1903      /*      /*
1904       * envPtr->codeNext is equal to envPtr->codeEnd. The currently defined       * envPtr->codeNext is equal to envPtr->codeEnd. The currently defined
1905       * code bytes are stored between envPtr->codeStart and       * code bytes are stored between envPtr->codeStart and
1906       * (envPtr->codeNext - 1) [inclusive].       * (envPtr->codeNext - 1) [inclusive].
1907       */       */
1908            
1909      size_t currBytes = (envPtr->codeNext - envPtr->codeStart);      size_t currBytes = (envPtr->codeNext - envPtr->codeStart);
1910      size_t newBytes  = 2*(envPtr->codeEnd  - envPtr->codeStart);      size_t newBytes  = 2*(envPtr->codeEnd  - envPtr->codeStart);
1911      unsigned char *newPtr = (unsigned char *) ckalloc((unsigned) newBytes);      unsigned char *newPtr = (unsigned char *) ckalloc((unsigned) newBytes);
1912    
1913      /*      /*
1914       * Copy from old code array to new, free old code array if needed, and       * Copy from old code array to new, free old code array if needed, and
1915       * mark new code array as malloced.       * mark new code array as malloced.
1916       */       */
1917    
1918      memcpy((VOID *) newPtr, (VOID *) envPtr->codeStart, currBytes);      memcpy((VOID *) newPtr, (VOID *) envPtr->codeStart, currBytes);
1919      if (envPtr->mallocedCodeArray) {      if (envPtr->mallocedCodeArray) {
1920          ckfree((char *) envPtr->codeStart);          ckfree((char *) envPtr->codeStart);
1921      }      }
1922      envPtr->codeStart = newPtr;      envPtr->codeStart = newPtr;
1923      envPtr->codeNext = (newPtr + currBytes);      envPtr->codeNext = (newPtr + currBytes);
1924      envPtr->codeEnd  = (newPtr + newBytes);      envPtr->codeEnd  = (newPtr + newBytes);
1925      envPtr->mallocedCodeArray = 1;      envPtr->mallocedCodeArray = 1;
1926  }  }
1927    
1928  /*  /*
1929   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1930   *   *
1931   * EnterCmdStartData --   * EnterCmdStartData --
1932   *   *
1933   *      Registers the starting source and bytecode location of a   *      Registers the starting source and bytecode location of a
1934   *      command. This information is used at runtime to map between   *      command. This information is used at runtime to map between
1935   *      instruction pc and source locations.   *      instruction pc and source locations.
1936   *   *
1937   * Results:   * Results:
1938   *      None.   *      None.
1939   *   *
1940   * Side effects:   * Side effects:
1941   *      Inserts source and code location information into the compilation   *      Inserts source and code location information into the compilation
1942   *      environment envPtr for the command at index cmdIndex. The   *      environment envPtr for the command at index cmdIndex. The
1943   *      compilation environment's CmdLocation array is grown if necessary.   *      compilation environment's CmdLocation array is grown if necessary.
1944   *   *
1945   *----------------------------------------------------------------------   *----------------------------------------------------------------------
1946   */   */
1947    
1948  static void  static void
1949  EnterCmdStartData(envPtr, cmdIndex, srcOffset, codeOffset)  EnterCmdStartData(envPtr, cmdIndex, srcOffset, codeOffset)
1950      CompileEnv *envPtr;         /* Points to the compilation environment      CompileEnv *envPtr;         /* Points to the compilation environment
1951                                   * structure in which to enter command                                   * structure in which to enter command
1952                                   * location information. */                                   * location information. */
1953      int cmdIndex;               /* Index of the command whose start data      int cmdIndex;               /* Index of the command whose start data
1954                                   * is being set. */                                   * is being set. */
1955      int srcOffset;              /* Offset of first char of the command. */      int srcOffset;              /* Offset of first char of the command. */
1956      int codeOffset;             /* Offset of first byte of command code. */      int codeOffset;             /* Offset of first byte of command code. */
1957  {  {
1958      CmdLocation *cmdLocPtr;      CmdLocation *cmdLocPtr;
1959            
1960      if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {      if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
1961          panic("EnterCmdStartData: bad command index %d\n", cmdIndex);          panic("EnterCmdStartData: bad command index %d\n", cmdIndex);
1962      }      }
1963            
1964      if (cmdIndex >= envPtr->cmdMapEnd) {      if (cmdIndex >= envPtr->cmdMapEnd) {
1965          /*          /*
1966           * Expand the command location array by allocating more storage from           * Expand the command location array by allocating more storage from
1967           * the heap. The currently allocated CmdLocation entries are stored           * the heap. The currently allocated CmdLocation entries are stored
1968           * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).           * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).
1969           */           */
1970    
1971          size_t currElems = envPtr->cmdMapEnd;          size_t currElems = envPtr->cmdMapEnd;
1972          size_t newElems  = 2*currElems;          size_t newElems  = 2*currElems;
1973          size_t currBytes = currElems * sizeof(CmdLocation);          size_t currBytes = currElems * sizeof(CmdLocation);
1974          size_t newBytes  = newElems  * sizeof(CmdLocation);          size_t newBytes  = newElems  * sizeof(CmdLocation);
1975          CmdLocation *newPtr = (CmdLocation *) ckalloc((unsigned) newBytes);          CmdLocation *newPtr = (CmdLocation *) ckalloc((unsigned) newBytes);
1976                    
1977          /*          /*
1978           * Copy from old command location array to new, free old command           * Copy from old command location array to new, free old command
1979           * location array if needed, and mark new array as malloced.           * location array if needed, and mark new array as malloced.
1980           */           */
1981                    
1982          memcpy((VOID *) newPtr, (VOID *) envPtr->cmdMapPtr, currBytes);          memcpy((VOID *) newPtr, (VOID *) envPtr->cmdMapPtr, currBytes);
1983          if (envPtr->mallocedCmdMap) {          if (envPtr->mallocedCmdMap) {
1984              ckfree((char *) envPtr->cmdMapPtr);              ckfree((char *) envPtr->cmdMapPtr);
1985          }          }
1986          envPtr->cmdMapPtr = (CmdLocation *) newPtr;          envPtr->cmdMapPtr = (CmdLocation *) newPtr;
1987          envPtr->cmdMapEnd = newElems;          envPtr->cmdMapEnd = newElems;
1988          envPtr->mallocedCmdMap = 1;          envPtr->mallocedCmdMap = 1;
1989      }      }
1990    
1991      if (cmdIndex > 0) {      if (cmdIndex > 0) {
1992          if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {          if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {
1993              panic("EnterCmdStartData: cmd map not sorted by code offset");              panic("EnterCmdStartData: cmd map not sorted by code offset");
1994          }          }
1995      }      }
1996    
1997      cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);      cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
1998      cmdLocPtr->codeOffset = codeOffset;      cmdLocPtr->codeOffset = codeOffset;
1999      cmdLocPtr->srcOffset = srcOffset;      cmdLocPtr->srcOffset = srcOffset;
2000      cmdLocPtr->numSrcBytes = -1;      cmdLocPtr->numSrcBytes = -1;
2001      cmdLocPtr->numCodeBytes = -1;      cmdLocPtr->numCodeBytes = -1;
2002  }  }
2003    
2004  /*  /*
2005   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2006   *   *
2007   * EnterCmdExtentData --   * EnterCmdExtentData --
2008   *   *
2009   *      Registers the source and bytecode length for a command. This   *      Registers the source and bytecode length for a command. This
2010   *      information is used at runtime to map between instruction pc and   *      information is used at runtime to map between instruction pc and
2011   *      source locations.   *      source locations.
2012   *   *
2013   * Results:   * Results:
2014   *      None.   *      None.
2015   *   *
2016   * Side effects:   * Side effects:
2017   *      Inserts source and code length information into the compilation   *      Inserts source and code length information into the compilation
2018   *      environment envPtr for the command at index cmdIndex. Starting   *      environment envPtr for the command at index cmdIndex. Starting
2019   *      source and bytecode information for the command must already   *      source and bytecode information for the command must already
2020   *      have been registered.   *      have been registered.
2021   *   *
2022   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2023   */   */
2024    
2025  static void  static void
2026  EnterCmdExtentData(envPtr, cmdIndex, numSrcBytes, numCodeBytes)  EnterCmdExtentData(envPtr, cmdIndex, numSrcBytes, numCodeBytes)
2027      CompileEnv *envPtr;         /* Points to the compilation environment      CompileEnv *envPtr;         /* Points to the compilation environment
2028                                   * structure in which to enter command                                   * structure in which to enter command
2029                                   * location information. */                                   * location information. */
2030      int cmdIndex;               /* Index of the command whose source and      int cmdIndex;               /* Index of the command whose source and
2031                                   * code length data is being set. */                                   * code length data is being set. */
2032      int numSrcBytes;            /* Number of command source chars. */      int numSrcBytes;            /* Number of command source chars. */
2033      int numCodeBytes;           /* Offset of last byte of command code. */      int numCodeBytes;           /* Offset of last byte of command code. */
2034  {  {
2035      CmdLocation *cmdLocPtr;      CmdLocation *cmdLocPtr;
2036    
2037      if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {      if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
2038          panic("EnterCmdExtentData: bad command index %d\n", cmdIndex);          panic("EnterCmdExtentData: bad command index %d\n", cmdIndex);
2039      }      }
2040            
2041      if (cmdIndex > envPtr->cmdMapEnd) {      if (cmdIndex > envPtr->cmdMapEnd) {
2042          panic("EnterCmdExtentData: missing start data for command %d\n",          panic("EnterCmdExtentData: missing start data for command %d\n",
2043                  cmdIndex);                  cmdIndex);
2044      }      }
2045    
2046      cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);      cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
2047      cmdLocPtr->numSrcBytes = numSrcBytes;      cmdLocPtr->numSrcBytes = numSrcBytes;
2048      cmdLocPtr->numCodeBytes = numCodeBytes;      cmdLocPtr->numCodeBytes = numCodeBytes;
2049  }  }
2050    
2051  /*  /*
2052   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2053   *   *
2054   * TclCreateExceptRange --   * TclCreateExceptRange --
2055   *   *
2056   *      Procedure that allocates and initializes a new ExceptionRange   *      Procedure that allocates and initializes a new ExceptionRange
2057   *      structure of the specified kind in a CompileEnv.   *      structure of the specified kind in a CompileEnv.
2058   *   *
2059   * Results:   * Results:
2060   *      Returns the index for the newly created ExceptionRange.   *      Returns the index for the newly created ExceptionRange.
2061   *   *
2062   * Side effects:   * Side effects:
2063   *      If there is not enough room in the CompileEnv's ExceptionRange   *      If there is not enough room in the CompileEnv's ExceptionRange
2064   *      array, the array in expanded: a new array of double the size is   *      array, the array in expanded: a new array of double the size is
2065   *      allocated, if envPtr->mallocedExceptArray is non-zero the old   *      allocated, if envPtr->mallocedExceptArray is non-zero the old
2066   *      array is freed, and ExceptionRange entries are copied from the old   *      array is freed, and ExceptionRange entries are copied from the old
2067   *      array to the new one.   *      array to the new one.
2068   *   *
2069   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2070   */   */
2071    
2072  int  int
2073  TclCreateExceptRange(type, envPtr)  TclCreateExceptRange(type, envPtr)
2074      ExceptionRangeType type;    /* The kind of ExceptionRange desired. */      ExceptionRangeType type;    /* The kind of ExceptionRange desired. */
2075      register CompileEnv *envPtr;/* Points to CompileEnv for which to      register CompileEnv *envPtr;/* Points to CompileEnv for which to
2076                                   * create a new ExceptionRange structure. */                                   * create a new ExceptionRange structure. */
2077  {  {
2078      register ExceptionRange *rangePtr;      register ExceptionRange *rangePtr;
2079      int index = envPtr->exceptArrayNext;      int index = envPtr->exceptArrayNext;
2080            
2081      if (index >= envPtr->exceptArrayEnd) {      if (index >= envPtr->exceptArrayEnd) {
2082          /*          /*
2083           * Expand the ExceptionRange array. The currently allocated entries           * Expand the ExceptionRange array. The currently allocated entries
2084           * are stored between elements 0 and (envPtr->exceptArrayNext - 1)           * are stored between elements 0 and (envPtr->exceptArrayNext - 1)
2085           * [inclusive].           * [inclusive].
2086           */           */
2087                    
2088          size_t currBytes =          size_t currBytes =
2089                  envPtr->exceptArrayNext * sizeof(ExceptionRange);                  envPtr->exceptArrayNext * sizeof(ExceptionRange);
2090          int newElems = 2*envPtr->exceptArrayEnd;          int newElems = 2*envPtr->exceptArrayEnd;
2091          size_t newBytes = newElems * sizeof(ExceptionRange);          size_t newBytes = newElems * sizeof(ExceptionRange);
2092          ExceptionRange *newPtr = (ExceptionRange *)          ExceptionRange *newPtr = (ExceptionRange *)
2093                  ckalloc((unsigned) newBytes);                  ckalloc((unsigned) newBytes);
2094                    
2095          /*          /*
2096           * Copy from old ExceptionRange array to new, free old           * Copy from old ExceptionRange array to new, free old
2097           * ExceptionRange array if needed, and mark the new ExceptionRange           * ExceptionRange array if needed, and mark the new ExceptionRange
2098           * array as malloced.           * array as malloced.
2099           */           */
2100                    
2101          memcpy((VOID *) newPtr, (VOID *) envPtr->exceptArrayPtr,          memcpy((VOID *) newPtr, (VOID *) envPtr->exceptArrayPtr,
2102                  currBytes);                  currBytes);
2103          if (envPtr->mallocedExceptArray) {          if (envPtr->mallocedExceptArray) {
2104              ckfree((char *) envPtr->exceptArrayPtr);              ckfree((char *) envPtr->exceptArrayPtr);
2105          }          }
2106          envPtr->exceptArrayPtr = (ExceptionRange *) newPtr;          envPtr->exceptArrayPtr = (ExceptionRange *) newPtr;
2107          envPtr->exceptArrayEnd = newElems;          envPtr->exceptArrayEnd = newElems;
2108          envPtr->mallocedExceptArray = 1;          envPtr->mallocedExceptArray = 1;
2109      }      }
2110      envPtr->exceptArrayNext++;      envPtr->exceptArrayNext++;
2111            
2112      rangePtr = &(envPtr->exceptArrayPtr[index]);      rangePtr = &(envPtr->exceptArrayPtr[index]);
2113      rangePtr->type = type;      rangePtr->type = type;
2114      rangePtr->nestingLevel = envPtr->exceptDepth;      rangePtr->nestingLevel = envPtr->exceptDepth;
2115      rangePtr->codeOffset = -1;      rangePtr->codeOffset = -1;
2116      rangePtr->numCodeBytes = -1;      rangePtr->numCodeBytes = -1;
2117      rangePtr->breakOffset = -1;      rangePtr->breakOffset = -1;
2118      rangePtr->continueOffset = -1;      rangePtr->continueOffset = -1;
2119      rangePtr->catchOffset = -1;      rangePtr->catchOffset = -1;
2120      return index;      return index;
2121  }  }
2122    
2123  /*  /*
2124   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2125   *   *
2126   * TclCreateAuxData --   * TclCreateAuxData --
2127   *   *
2128   *      Procedure that allocates and initializes a new AuxData structure in   *      Procedure that allocates and initializes a new AuxData structure in
2129   *      a CompileEnv's array of compilation auxiliary data records. These   *      a CompileEnv's array of compilation auxiliary data records. These
2130   *      AuxData records hold information created during compilation by   *      AuxData records hold information created during compilation by
2131   *      CompileProcs and used by instructions during execution.   *      CompileProcs and used by instructions during execution.
2132   *   *
2133   * Results:   * Results:
2134   *      Returns the index for the newly created AuxData structure.   *      Returns the index for the newly created AuxData structure.
2135   *   *
2136   * Side effects:   * Side effects:
2137   *      If there is not enough room in the CompileEnv's AuxData array,   *      If there is not enough room in the CompileEnv's AuxData array,
2138   *      the AuxData array in expanded: a new array of double the size   *      the AuxData array in expanded: a new array of double the size
2139   *      is allocated, if envPtr->mallocedAuxDataArray is non-zero   *      is allocated, if envPtr->mallocedAuxDataArray is non-zero
2140   *      the old array is freed, and AuxData entries are copied from   *      the old array is freed, and AuxData entries are copied from
2141   *      the old array to the new one.   *      the old array to the new one.
2142   *   *
2143   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2144   */   */
2145    
2146  int  int
2147  TclCreateAuxData(clientData, typePtr, envPtr)  TclCreateAuxData(clientData, typePtr, envPtr)
2148      ClientData clientData;      /* The compilation auxiliary data to store      ClientData clientData;      /* The compilation auxiliary data to store
2149                                   * in the new aux data record. */                                   * in the new aux data record. */
2150      AuxDataType *typePtr;       /* Pointer to the type to attach to this AuxData */      AuxDataType *typePtr;       /* Pointer to the type to attach to this AuxData */
2151      register CompileEnv *envPtr;/* Points to the CompileEnv for which a new      register CompileEnv *envPtr;/* Points to the CompileEnv for which a new
2152                                   * aux data structure is to be allocated. */                                   * aux data structure is to be allocated. */
2153  {  {
2154      int index;                  /* Index for the new AuxData structure. */      int index;                  /* Index for the new AuxData structure. */
2155      register AuxData *auxDataPtr;      register AuxData *auxDataPtr;
2156                                  /* Points to the new AuxData structure */                                  /* Points to the new AuxData structure */
2157            
2158      index = envPtr->auxDataArrayNext;      index = envPtr->auxDataArrayNext;
2159      if (index >= envPtr->auxDataArrayEnd) {      if (index >= envPtr->auxDataArrayEnd) {
2160          /*          /*
2161           * Expand the AuxData array. The currently allocated entries are           * Expand the AuxData array. The currently allocated entries are
2162           * stored between elements 0 and (envPtr->auxDataArrayNext - 1)           * stored between elements 0 and (envPtr->auxDataArrayNext - 1)
2163           * [inclusive].           * [inclusive].
2164           */           */
2165                    
2166          size_t currBytes = envPtr->auxDataArrayNext * sizeof(AuxData);          size_t currBytes = envPtr->auxDataArrayNext * sizeof(AuxData);
2167          int newElems = 2*envPtr->auxDataArrayEnd;          int newElems = 2*envPtr->auxDataArrayEnd;
2168          size_t newBytes = newElems * sizeof(AuxData);          size_t newBytes = newElems * sizeof(AuxData);
2169          AuxData *newPtr = (AuxData *) ckalloc((unsigned) newBytes);          AuxData *newPtr = (AuxData *) ckalloc((unsigned) newBytes);
2170                    
2171          /*          /*
2172           * Copy from old AuxData array to new, free old AuxData array if           * Copy from old AuxData array to new, free old AuxData array if
2173           * needed, and mark the new AuxData array as malloced.           * needed, and mark the new AuxData array as malloced.
2174           */           */
2175                    
2176          memcpy((VOID *) newPtr, (VOID *) envPtr->auxDataArrayPtr,          memcpy((VOID *) newPtr, (VOID *) envPtr->auxDataArrayPtr,
2177                  currBytes);                  currBytes);
2178          if (envPtr->mallocedAuxDataArray) {          if (envPtr->mallocedAuxDataArray) {
2179              ckfree((char *) envPtr->auxDataArrayPtr);              ckfree((char *) envPtr->auxDataArrayPtr);
2180          }          }
2181          envPtr->auxDataArrayPtr = newPtr;          envPtr->auxDataArrayPtr = newPtr;
2182          envPtr->auxDataArrayEnd = newElems;          envPtr->auxDataArrayEnd = newElems;
2183          envPtr->mallocedAuxDataArray = 1;          envPtr->mallocedAuxDataArray = 1;
2184      }      }
2185      envPtr->auxDataArrayNext++;      envPtr->auxDataArrayNext++;
2186            
2187      auxDataPtr = &(envPtr->auxDataArrayPtr[index]);      auxDataPtr = &(envPtr->auxDataArrayPtr[index]);
2188      auxDataPtr->clientData = clientData;      auxDataPtr->clientData = clientData;
2189      auxDataPtr->type = typePtr;      auxDataPtr->type = typePtr;
2190      return index;      return index;
2191  }  }
2192    
2193  /*  /*
2194   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2195   *   *
2196   * TclInitJumpFixupArray --   * TclInitJumpFixupArray --
2197   *   *
2198   *      Initializes a JumpFixupArray structure to hold some number of   *      Initializes a JumpFixupArray structure to hold some number of
2199   *      jump fixup entries.   *      jump fixup entries.
2200   *   *
2201   * Results:   * Results:
2202   *      None.   *      None.
2203   *   *
2204   * Side effects:   * Side effects:
2205   *      The JumpFixupArray structure is initialized.   *      The JumpFixupArray structure is initialized.
2206   *   *
2207   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2208   */   */
2209    
2210  void  void
2211  TclInitJumpFixupArray(fixupArrayPtr)  TclInitJumpFixupArray(fixupArrayPtr)
2212      register JumpFixupArray *fixupArrayPtr;      register JumpFixupArray *fixupArrayPtr;
2213                                   /* Points to the JumpFixupArray structure                                   /* Points to the JumpFixupArray structure
2214                                    * to initialize. */                                    * to initialize. */
2215  {  {
2216      fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace;      fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace;
2217      fixupArrayPtr->next = 0;      fixupArrayPtr->next = 0;
2218      fixupArrayPtr->end = (JUMPFIXUP_INIT_ENTRIES - 1);      fixupArrayPtr->end = (JUMPFIXUP_INIT_ENTRIES - 1);
2219      fixupArrayPtr->mallocedArray = 0;      fixupArrayPtr->mallocedArray = 0;
2220  }  }
2221    
2222  /*  /*
2223   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2224   *   *
2225   * TclExpandJumpFixupArray --   * TclExpandJumpFixupArray --
2226   *   *
2227   *      Procedure that uses malloc to allocate more storage for a   *      Procedure that uses malloc to allocate more storage for a
2228   *      jump fixup array.   *      jump fixup array.
2229   *   *
2230   * Results:   * Results:
2231   *      None.   *      None.
2232   *   *
2233   * Side effects:   * Side effects:
2234   *      The jump fixup array in *fixupArrayPtr is reallocated to a new array   *      The jump fixup array in *fixupArrayPtr is reallocated to a new array
2235   *      of double the size, and if fixupArrayPtr->mallocedArray is non-zero   *      of double the size, and if fixupArrayPtr->mallocedArray is non-zero
2236   *      the old array is freed. Jump fixup structures are copied from the   *      the old array is freed. Jump fixup structures are copied from the
2237   *      old array to the new one.   *      old array to the new one.
2238   *   *
2239   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2240   */   */
2241    
2242  void  void
2243  TclExpandJumpFixupArray(fixupArrayPtr)  TclExpandJumpFixupArray(fixupArrayPtr)
2244      register JumpFixupArray *fixupArrayPtr;      register JumpFixupArray *fixupArrayPtr;
2245                                   /* Points to the JumpFixupArray structure                                   /* Points to the JumpFixupArray structure
2246                                    * to enlarge. */                                    * to enlarge. */
2247  {  {
2248      /*      /*
2249       * The currently allocated jump fixup entries are stored from fixup[0]       * The currently allocated jump fixup entries are stored from fixup[0]
2250       * up to fixup[fixupArrayPtr->fixupNext] (*not* inclusive). We assume       * up to fixup[fixupArrayPtr->fixupNext] (*not* inclusive). We assume
2251       * fixupArrayPtr->fixupNext is equal to fixupArrayPtr->fixupEnd.       * fixupArrayPtr->fixupNext is equal to fixupArrayPtr->fixupEnd.
2252       */       */
2253    
2254      size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup);      size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup);
2255      int newElems = 2*(fixupArrayPtr->end + 1);      int newElems = 2*(fixupArrayPtr->end + 1);
2256      size_t newBytes = newElems * sizeof(JumpFixup);      size_t newBytes = newElems * sizeof(JumpFixup);
2257      JumpFixup *newPtr = (JumpFixup *) ckalloc((unsigned) newBytes);      JumpFixup *newPtr = (JumpFixup *) ckalloc((unsigned) newBytes);
2258    
2259      /*      /*
2260       * Copy from the old array to new, free the old array if needed,       * Copy from the old array to new, free the old array if needed,
2261       * and mark the new array as malloced.       * and mark the new array as malloced.
2262       */       */
2263    
2264      memcpy((VOID *) newPtr, (VOID *) fixupArrayPtr->fixup, currBytes);      memcpy((VOID *) newPtr, (VOID *) fixupArrayPtr->fixup, currBytes);
2265      if (fixupArrayPtr->mallocedArray) {      if (fixupArrayPtr->mallocedArray) {
2266          ckfree((char *) fixupArrayPtr->fixup);          ckfree((char *) fixupArrayPtr->fixup);
2267      }      }
2268      fixupArrayPtr->fixup = (JumpFixup *) newPtr;      fixupArrayPtr->fixup = (JumpFixup *) newPtr;
2269      fixupArrayPtr->end = newElems;      fixupArrayPtr->end = newElems;
2270      fixupArrayPtr->mallocedArray = 1;      fixupArrayPtr->mallocedArray = 1;
2271  }  }
2272    
2273  /*  /*
2274   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2275   *   *
2276   * TclFreeJumpFixupArray --   * TclFreeJumpFixupArray --
2277   *   *
2278   *      Free any storage allocated in a jump fixup array structure.   *      Free any storage allocated in a jump fixup array structure.
2279   *   *
2280   * Results:   * Results:
2281   *      None.   *      None.
2282   *   *
2283   * Side effects:   * Side effects:
2284   *      Allocated storage in the JumpFixupArray structure is freed.   *      Allocated storage in the JumpFixupArray structure is freed.
2285   *   *
2286   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2287   */   */
2288    
2289  void  void
2290  TclFreeJumpFixupArray(fixupArrayPtr)  TclFreeJumpFixupArray(fixupArrayPtr)
2291      register JumpFixupArray *fixupArrayPtr;      register JumpFixupArray *fixupArrayPtr;
2292                                   /* Points to the JumpFixupArray structure                                   /* Points to the JumpFixupArray structure
2293                                    * to free. */                                    * to free. */
2294  {  {
2295      if (fixupArrayPtr->mallocedArray) {      if (fixupArrayPtr->mallocedArray) {
2296          ckfree((char *) fixupArrayPtr->fixup);          ckfree((char *) fixupArrayPtr->fixup);
2297      }      }
2298  }  }
2299    
2300  /*  /*
2301   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2302   *   *
2303   * TclEmitForwardJump --   * TclEmitForwardJump --
2304   *   *
2305   *      Procedure to emit a two-byte forward jump of kind "jumpType". Since   *      Procedure to emit a two-byte forward jump of kind "jumpType". Since
2306   *      the jump may later have to be grown to five bytes if the jump target   *      the jump may later have to be grown to five bytes if the jump target
2307   *      is more than, say, 127 bytes away, this procedure also initializes a   *      is more than, say, 127 bytes away, this procedure also initializes a
2308   *      JumpFixup record with information about the jump.   *      JumpFixup record with information about the jump.
2309   *   *
2310   * Results:   * Results:
2311   *      None.   *      None.
2312   *   *
2313   * Side effects:   * Side effects:
2314   *      The JumpFixup record pointed to by "jumpFixupPtr" is initialized   *      The JumpFixup record pointed to by "jumpFixupPtr" is initialized
2315   *      with information needed later if the jump is to be grown. Also,   *      with information needed later if the jump is to be grown. Also,
2316   *      a two byte jump of the designated type is emitted at the current   *      a two byte jump of the designated type is emitted at the current
2317   *      point in the bytecode stream.   *      point in the bytecode stream.
2318   *   *
2319   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2320   */   */
2321    
2322  void  void
2323  TclEmitForwardJump(envPtr, jumpType, jumpFixupPtr)  TclEmitForwardJump(envPtr, jumpType, jumpFixupPtr)
2324      CompileEnv *envPtr;         /* Points to the CompileEnv structure that      CompileEnv *envPtr;         /* Points to the CompileEnv structure that
2325                                   * holds the resulting instruction. */                                   * holds the resulting instruction. */
2326      TclJumpType jumpType;       /* Indicates the kind of jump: if true or      TclJumpType jumpType;       /* Indicates the kind of jump: if true or
2327                                   * false or unconditional. */                                   * false or unconditional. */
2328      JumpFixup *jumpFixupPtr;    /* Points to the JumpFixup structure to      JumpFixup *jumpFixupPtr;    /* Points to the JumpFixup structure to
2329                                   * initialize with information about this                                   * initialize with information about this
2330                                   * forward jump. */                                   * forward jump. */
2331  {  {
2332      /*      /*
2333       * Initialize the JumpFixup structure:       * Initialize the JumpFixup structure:
2334       *    - codeOffset is offset of first byte of jump below       *    - codeOffset is offset of first byte of jump below
2335       *    - cmdIndex is index of the command after the current one       *    - cmdIndex is index of the command after the current one
2336       *    - exceptIndex is the index of the first ExceptionRange after       *    - exceptIndex is the index of the first ExceptionRange after
2337       *      the current one.       *      the current one.
2338       */       */
2339            
2340      jumpFixupPtr->jumpType = jumpType;      jumpFixupPtr->jumpType = jumpType;
2341      jumpFixupPtr->codeOffset = (envPtr->codeNext - envPtr->codeStart);      jumpFixupPtr->codeOffset = (envPtr->codeNext - envPtr->codeStart);
2342      jumpFixupPtr->cmdIndex = envPtr->numCommands;      jumpFixupPtr->cmdIndex = envPtr->numCommands;
2343      jumpFixupPtr->exceptIndex = envPtr->exceptArrayNext;      jumpFixupPtr->exceptIndex = envPtr->exceptArrayNext;
2344            
2345      switch (jumpType) {      switch (jumpType) {
2346      case TCL_UNCONDITIONAL_JUMP:      case TCL_UNCONDITIONAL_JUMP:
2347          TclEmitInstInt1(INST_JUMP1, 0, envPtr);          TclEmitInstInt1(INST_JUMP1, 0, envPtr);
2348          break;          break;
2349      case TCL_TRUE_JUMP:      case TCL_TRUE_JUMP:
2350          TclEmitInstInt1(INST_JUMP_TRUE1, 0, envPtr);          TclEmitInstInt1(INST_JUMP_TRUE1, 0, envPtr);
2351          break;          break;
2352      default:      default:
2353          TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);          TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
2354          break;          break;
2355      }      }
2356  }  }
2357    
2358  /*  /*
2359   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2360   *   *
2361   * TclFixupForwardJump --   * TclFixupForwardJump --
2362   *   *
2363   *      Procedure that updates a previously-emitted forward jump to jump   *      Procedure that updates a previously-emitted forward jump to jump
2364   *      a specified number of bytes, "jumpDist". If necessary, the jump is   *      a specified number of bytes, "jumpDist". If necessary, the jump is
2365   *      grown from two to five bytes; this is done if the jump distance is   *      grown from two to five bytes; this is done if the jump distance is
2366   *      greater than "distThreshold" (normally 127 bytes). The jump is   *      greater than "distThreshold" (normally 127 bytes). The jump is
2367   *      described by a JumpFixup record previously initialized by   *      described by a JumpFixup record previously initialized by
2368   *      TclEmitForwardJump.   *      TclEmitForwardJump.
2369   *   *
2370   * Results:   * Results:
2371   *      1 if the jump was grown and subsequent instructions had to be moved;   *      1 if the jump was grown and subsequent instructions had to be moved;
2372   *      otherwise 0. This result is returned to allow callers to update   *      otherwise 0. This result is returned to allow callers to update
2373   *      any additional code offsets they may hold.   *      any additional code offsets they may hold.
2374   *   *
2375   * Side effects:   * Side effects:
2376   *      The jump may be grown and subsequent instructions moved. If this   *      The jump may be grown and subsequent instructions moved. If this
2377   *      happens, the code offsets for any commands and any ExceptionRange   *      happens, the code offsets for any commands and any ExceptionRange
2378   *      records between the jump and the current code address will be   *      records between the jump and the current code address will be
2379   *      updated to reflect the moved code. Also, the bytecode instruction   *      updated to reflect the moved code. Also, the bytecode instruction
2380   *      array in the CompileEnv structure may be grown and reallocated.   *      array in the CompileEnv structure may be grown and reallocated.
2381   *   *
2382   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2383   */   */
2384    
2385  int  int
2386  TclFixupForwardJump(envPtr, jumpFixupPtr, jumpDist, distThreshold)  TclFixupForwardJump(envPtr, jumpFixupPtr, jumpDist, distThreshold)
2387      CompileEnv *envPtr;         /* Points to the CompileEnv structure that      CompileEnv *envPtr;         /* Points to the CompileEnv structure that
2388                                   * holds the resulting instruction. */                                   * holds the resulting instruction. */
2389      JumpFixup *jumpFixupPtr;    /* Points to the JumpFixup structure that      JumpFixup *jumpFixupPtr;    /* Points to the JumpFixup structure that
2390                                   * describes the forward jump. */                                   * describes the forward jump. */
2391      int jumpDist;               /* Jump distance to set in jump      int jumpDist;               /* Jump distance to set in jump
2392                                   * instruction. */                                   * instruction. */
2393      int distThreshold;          /* Maximum distance before the two byte      int distThreshold;          /* Maximum distance before the two byte
2394                                   * jump is grown to five bytes. */                                   * jump is grown to five bytes. */
2395  {  {
2396      unsigned char *jumpPc, *p;      unsigned char *jumpPc, *p;
2397      int firstCmd, lastCmd, firstRange, lastRange, k;      int firstCmd, lastCmd, firstRange, lastRange, k;
2398      unsigned int numBytes;      unsigned int numBytes;
2399            
2400      if (jumpDist <= distThreshold) {      if (jumpDist <= distThreshold) {
2401          jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);          jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
2402          switch (jumpFixupPtr->jumpType) {          switch (jumpFixupPtr->jumpType) {
2403          case TCL_UNCONDITIONAL_JUMP:          case TCL_UNCONDITIONAL_JUMP:
2404              TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc);              TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc);
2405              break;              break;
2406          case TCL_TRUE_JUMP:          case TCL_TRUE_JUMP:
2407              TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc);              TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc);
2408              break;              break;
2409          default:          default:
2410              TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc);              TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc);
2411              break;              break;
2412          }          }
2413          return 0;          return 0;
2414      }      }
2415    
2416      /*      /*
2417       * We must grow the jump then move subsequent instructions down.       * We must grow the jump then move subsequent instructions down.
2418       * Note that if we expand the space for generated instructions,       * Note that if we expand the space for generated instructions,
2419       * code addresses might change; be careful about updating any of       * code addresses might change; be careful about updating any of
2420       * these addresses held in variables.       * these addresses held in variables.
2421       */       */
2422            
2423      if ((envPtr->codeNext + 3) > envPtr->codeEnd) {      if ((envPtr->codeNext + 3) > envPtr->codeEnd) {
2424          TclExpandCodeArray(envPtr);          TclExpandCodeArray(envPtr);
2425      }      }
2426      jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);      jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
2427      for (numBytes = envPtr->codeNext-jumpPc-2, p = jumpPc+2+numBytes-1;      for (numBytes = envPtr->codeNext-jumpPc-2, p = jumpPc+2+numBytes-1;
2428              numBytes > 0;  numBytes--, p--) {              numBytes > 0;  numBytes--, p--) {
2429          p[3] = p[0];          p[3] = p[0];
2430      }      }
2431      envPtr->codeNext += 3;      envPtr->codeNext += 3;
2432      jumpDist += 3;      jumpDist += 3;
2433      switch (jumpFixupPtr->jumpType) {      switch (jumpFixupPtr->jumpType) {
2434      case TCL_UNCONDITIONAL_JUMP:      case TCL_UNCONDITIONAL_JUMP:
2435          TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);          TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);
2436          break;          break;
2437      case TCL_TRUE_JUMP:      case TCL_TRUE_JUMP:
2438          TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);          TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);
2439          break;          break;
2440      default:      default:
2441          TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);          TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);
2442          break;          break;
2443      }      }
2444            
2445      /*      /*
2446       * Adjust the code offsets for any commands and any ExceptionRange       * Adjust the code offsets for any commands and any ExceptionRange
2447       * records between the jump and the current code address.       * records between the jump and the current code address.
2448       */       */
2449            
2450      firstCmd = jumpFixupPtr->cmdIndex;      firstCmd = jumpFixupPtr->cmdIndex;
2451      lastCmd  = (envPtr->numCommands - 1);      lastCmd  = (envPtr->numCommands - 1);
2452      if (firstCmd < lastCmd) {      if (firstCmd < lastCmd) {
2453          for (k = firstCmd;  k <= lastCmd;  k++) {          for (k = firstCmd;  k <= lastCmd;  k++) {
2454              (envPtr->cmdMapPtr[k]).codeOffset += 3;              (envPtr->cmdMapPtr[k]).codeOffset += 3;
2455          }          }
2456      }      }
2457            
2458      firstRange = jumpFixupPtr->exceptIndex;      firstRange = jumpFixupPtr->exceptIndex;
2459      lastRange  = (envPtr->exceptArrayNext - 1);      lastRange  = (envPtr->exceptArrayNext - 1);
2460      for (k = firstRange;  k <= lastRange;  k++) {      for (k = firstRange;  k <= lastRange;  k++) {
2461          ExceptionRange *rangePtr = &(envPtr->exceptArrayPtr[k]);          ExceptionRange *rangePtr = &(envPtr->exceptArrayPtr[k]);
2462          rangePtr->codeOffset += 3;          rangePtr->codeOffset += 3;
2463                    
2464          switch (rangePtr->type) {          switch (rangePtr->type) {
2465          case LOOP_EXCEPTION_RANGE:          case LOOP_EXCEPTION_RANGE:
2466              rangePtr->breakOffset += 3;              rangePtr->breakOffset += 3;
2467              if (rangePtr->continueOffset != -1) {              if (rangePtr->continueOffset != -1) {
2468                  rangePtr->continueOffset += 3;                  rangePtr->continueOffset += 3;
2469              }              }
2470              break;              break;
2471          case CATCH_EXCEPTION_RANGE:          case CATCH_EXCEPTION_RANGE:
2472              rangePtr->catchOffset += 3;              rangePtr->catchOffset += 3;
2473              break;              break;
2474          default:          default:
2475              panic("TclFixupForwardJump: bad ExceptionRange type %d\n",              panic("TclFixupForwardJump: bad ExceptionRange type %d\n",
2476                      rangePtr->type);                      rangePtr->type);
2477          }          }
2478      }      }
2479      return 1;                   /* the jump was grown */      return 1;                   /* the jump was grown */
2480  }  }
2481    
2482  /*  /*
2483   *----------------------------------------------------------------------   *----------------------------------------------------------------------
2484   *   *
2485   * TclGetInstructionTable --   * TclGetInstructionTable --
2486   *   *
2487   *  Returns a pointer to the table describing Tcl bytecode instructions.   *  Returns a pointer to the table describing Tcl bytecode instructions.
2488   *  This procedure is defined so that clients can access the pointer from   *  This procedure is defined so that clients can access the pointer from
2489   *  outside the TCL DLLs.   *  outside the TCL DLLs.
2490   *   *
2491   * Results:   * Results:
2492   *      Returns a pointer to the global instruction table, same as the   *      Returns a pointer to the global instruction table, same as the
2493   *      expression (&instructionTable[0]).