os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclCompile.c
Update contrib.
4 * This file contains procedures that compile Tcl commands or parts
5 * of commands (like quoted strings or nested sub-commands) into a
6 * sequence of instructions ("bytecodes").
8 * Copyright (c) 1996-1998 Sun Microsystems, Inc.
9 * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
10 * Portions Copyright (c) 2007 Nokia Corporation and/or its subsidiaries. All rights reserved.
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 * RCS: @(#) $Id: tclCompile.c,v 1.43.2.7 2006/11/28 22:20:00 andreas_kupries Exp $
19 #include "tclCompile.h"
20 #if defined(__SYMBIAN32__) && defined(__WINSCW__)
21 #include "tclSymbianGlobals.h"
22 #define dataKey getdataKey(0)
25 #if !defined(__SYMBIAN32__) || !defined(__WINSCW__)
27 * Table of all AuxData types.
30 static Tcl_HashTable auxDataTypeTable;
31 static int auxDataTypeTableInitialized; /* 0 means not yet initialized. */
33 TCL_DECLARE_MUTEX(tableMutex)
36 * Variable that controls whether compilation tracing is enabled and, if so,
37 * what level of tracing is desired:
38 * 0: no compilation tracing
39 * 1: summarize compilation of top level cmds and proc bodies
40 * 2: display all instructions of each ByteCode compiled
41 * This variable is linked to the Tcl variable "tcl_traceCompile".
44 #ifdef TCL_COMPILE_DEBUG
45 int tclTraceCompile = 0;
46 static int traceInitialized = 0;
50 * A table describing the Tcl bytecode instructions. Entries in this table
51 * must correspond to the instruction opcode definitions in tclCompile.h.
52 * The names "op1" and "op4" refer to an instruction's one or four byte
53 * first operand. Similarly, "stktop" and "stknext" refer to the topmost
54 * and next to topmost stack elements.
56 * Note that the load, store, and incr instructions do not distinguish local
57 * from global variables; the bytecode interpreter at runtime uses the
58 * existence of a procedure call frame to distinguish these.
61 InstructionDesc tclInstructionTable[] = {
62 /* Name Bytes stackEffect #Opnds Operand types Stack top, next */
63 {"done", 1, -1, 0, {OPERAND_NONE}},
64 /* Finish ByteCode execution and return stktop (top stack item) */
65 {"push1", 2, +1, 1, {OPERAND_UINT1}},
66 /* Push object at ByteCode objArray[op1] */
67 {"push4", 5, +1, 1, {OPERAND_UINT4}},
68 /* Push object at ByteCode objArray[op4] */
69 {"pop", 1, -1, 0, {OPERAND_NONE}},
70 /* Pop the topmost stack object */
71 {"dup", 1, +1, 0, {OPERAND_NONE}},
72 /* Duplicate the topmost stack object and push the result */
73 {"concat1", 2, INT_MIN, 1, {OPERAND_UINT1}},
74 /* Concatenate the top op1 items and push result */
75 {"invokeStk1", 2, INT_MIN, 1, {OPERAND_UINT1}},
76 /* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
77 {"invokeStk4", 5, INT_MIN, 1, {OPERAND_UINT4}},
78 /* Invoke command named objv[0]; <objc,objv> = <op4,top op4> */
79 {"evalStk", 1, 0, 0, {OPERAND_NONE}},
80 /* Evaluate command in stktop using Tcl_EvalObj. */
81 {"exprStk", 1, 0, 0, {OPERAND_NONE}},
82 /* Execute expression in stktop using Tcl_ExprStringObj. */
84 {"loadScalar1", 2, 1, 1, {OPERAND_UINT1}},
85 /* Load scalar variable at index op1 <= 255 in call frame */
86 {"loadScalar4", 5, 1, 1, {OPERAND_UINT4}},
87 /* Load scalar variable at index op1 >= 256 in call frame */
88 {"loadScalarStk", 1, 0, 0, {OPERAND_NONE}},
89 /* Load scalar variable; scalar's name is stktop */
90 {"loadArray1", 2, 0, 1, {OPERAND_UINT1}},
91 /* Load array element; array at slot op1<=255, element is stktop */
92 {"loadArray4", 5, 0, 1, {OPERAND_UINT4}},
93 /* Load array element; array at slot op1 > 255, element is stktop */
94 {"loadArrayStk", 1, -1, 0, {OPERAND_NONE}},
95 /* Load array element; element is stktop, array name is stknext */
96 {"loadStk", 1, 0, 0, {OPERAND_NONE}},
97 /* Load general variable; unparsed variable name is stktop */
98 {"storeScalar1", 2, 0, 1, {OPERAND_UINT1}},
99 /* Store scalar variable at op1<=255 in frame; value is stktop */
100 {"storeScalar4", 5, 0, 1, {OPERAND_UINT4}},
101 /* Store scalar variable at op1 > 255 in frame; value is stktop */
102 {"storeScalarStk", 1, -1, 0, {OPERAND_NONE}},
103 /* Store scalar; value is stktop, scalar name is stknext */
104 {"storeArray1", 2, -1, 1, {OPERAND_UINT1}},
105 /* Store array element; array at op1<=255, value is top then elem */
106 {"storeArray4", 5, -1, 1, {OPERAND_UINT4}},
107 /* Store array element; array at op1>=256, value is top then elem */
108 {"storeArrayStk", 1, -2, 0, {OPERAND_NONE}},
109 /* Store array element; value is stktop, then elem, array names */
110 {"storeStk", 1, -1, 0, {OPERAND_NONE}},
111 /* Store general variable; value is stktop, then unparsed name */
113 {"incrScalar1", 2, 0, 1, {OPERAND_UINT1}},
114 /* Incr scalar at index op1<=255 in frame; incr amount is stktop */
115 {"incrScalarStk", 1, -1, 0, {OPERAND_NONE}},
116 /* Incr scalar; incr amount is stktop, scalar's name is stknext */
117 {"incrArray1", 2, -1, 1, {OPERAND_UINT1}},
118 /* Incr array elem; arr at slot op1<=255, amount is top then elem */
119 {"incrArrayStk", 1, -2, 0, {OPERAND_NONE}},
120 /* Incr array element; amount is top then elem then array names */
121 {"incrStk", 1, -1, 0, {OPERAND_NONE}},
122 /* Incr general variable; amount is stktop then unparsed var name */
123 {"incrScalar1Imm", 3, +1, 2, {OPERAND_UINT1, OPERAND_INT1}},
124 /* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
125 {"incrScalarStkImm", 2, 0, 1, {OPERAND_INT1}},
126 /* Incr scalar; scalar name is stktop; incr amount is op1 */
127 {"incrArray1Imm", 3, 0, 2, {OPERAND_UINT1, OPERAND_INT1}},
128 /* Incr array elem; array at slot op1 <= 255, elem is stktop,
129 * amount is 2nd operand byte */
130 {"incrArrayStkImm", 2, -1, 1, {OPERAND_INT1}},
131 /* Incr array element; elem is top then array name, amount is op1 */
132 {"incrStkImm", 2, 0, 1, {OPERAND_INT1}},
133 /* Incr general variable; unparsed name is top, amount is op1 */
135 {"jump1", 2, 0, 1, {OPERAND_INT1}},
136 /* Jump relative to (pc + op1) */
137 {"jump4", 5, 0, 1, {OPERAND_INT4}},
138 /* Jump relative to (pc + op4) */
139 {"jumpTrue1", 2, -1, 1, {OPERAND_INT1}},
140 /* Jump relative to (pc + op1) if stktop expr object is true */
141 {"jumpTrue4", 5, -1, 1, {OPERAND_INT4}},
142 /* Jump relative to (pc + op4) if stktop expr object is true */
143 {"jumpFalse1", 2, -1, 1, {OPERAND_INT1}},
144 /* Jump relative to (pc + op1) if stktop expr object is false */
145 {"jumpFalse4", 5, -1, 1, {OPERAND_INT4}},
146 /* Jump relative to (pc + op4) if stktop expr object is false */
148 {"lor", 1, -1, 0, {OPERAND_NONE}},
149 /* Logical or: push (stknext || stktop) */
150 {"land", 1, -1, 0, {OPERAND_NONE}},
151 /* Logical and: push (stknext && stktop) */
152 {"bitor", 1, -1, 0, {OPERAND_NONE}},
153 /* Bitwise or: push (stknext | stktop) */
154 {"bitxor", 1, -1, 0, {OPERAND_NONE}},
155 /* Bitwise xor push (stknext ^ stktop) */
156 {"bitand", 1, -1, 0, {OPERAND_NONE}},
157 /* Bitwise and: push (stknext & stktop) */
158 {"eq", 1, -1, 0, {OPERAND_NONE}},
159 /* Equal: push (stknext == stktop) */
160 {"neq", 1, -1, 0, {OPERAND_NONE}},
161 /* Not equal: push (stknext != stktop) */
162 {"lt", 1, -1, 0, {OPERAND_NONE}},
163 /* Less: push (stknext < stktop) */
164 {"gt", 1, -1, 0, {OPERAND_NONE}},
165 /* Greater: push (stknext || stktop) */
166 {"le", 1, -1, 0, {OPERAND_NONE}},
167 /* Logical or: push (stknext || stktop) */
168 {"ge", 1, -1, 0, {OPERAND_NONE}},
169 /* Logical or: push (stknext || stktop) */
170 {"lshift", 1, -1, 0, {OPERAND_NONE}},
171 /* Left shift: push (stknext << stktop) */
172 {"rshift", 1, -1, 0, {OPERAND_NONE}},
173 /* Right shift: push (stknext >> stktop) */
174 {"add", 1, -1, 0, {OPERAND_NONE}},
175 /* Add: push (stknext + stktop) */
176 {"sub", 1, -1, 0, {OPERAND_NONE}},
177 /* Sub: push (stkext - stktop) */
178 {"mult", 1, -1, 0, {OPERAND_NONE}},
179 /* Multiply: push (stknext * stktop) */
180 {"div", 1, -1, 0, {OPERAND_NONE}},
181 /* Divide: push (stknext / stktop) */
182 {"mod", 1, -1, 0, {OPERAND_NONE}},
183 /* Mod: push (stknext % stktop) */
184 {"uplus", 1, 0, 0, {OPERAND_NONE}},
185 /* Unary plus: push +stktop */
186 {"uminus", 1, 0, 0, {OPERAND_NONE}},
187 /* Unary minus: push -stktop */
188 {"bitnot", 1, 0, 0, {OPERAND_NONE}},
189 /* Bitwise not: push ~stktop */
190 {"not", 1, 0, 0, {OPERAND_NONE}},
191 /* Logical not: push !stktop */
192 {"callBuiltinFunc1", 2, 1, 1, {OPERAND_UINT1}},
193 /* Call builtin math function with index op1; any args are on stk */
194 {"callFunc1", 2, INT_MIN, 1, {OPERAND_UINT1}},
195 /* Call non-builtin func objv[0]; <objc,objv>=<op1,top op1> */
196 {"tryCvtToNumeric", 1, 0, 0, {OPERAND_NONE}},
197 /* Try converting stktop to first int then double if possible. */
199 {"break", 1, 0, 0, {OPERAND_NONE}},
200 /* Abort closest enclosing loop; if none, return TCL_BREAK code. */
201 {"continue", 1, 0, 0, {OPERAND_NONE}},
202 /* Skip to next iteration of closest enclosing loop; if none,
203 * return TCL_CONTINUE code. */
205 {"foreach_start4", 5, 0, 1, {OPERAND_UINT4}},
206 /* Initialize execution of a foreach loop. Operand is aux data index
207 * of the ForeachInfo structure for the foreach command. */
208 {"foreach_step4", 5, +1, 1, {OPERAND_UINT4}},
209 /* "Step" or begin next iteration of foreach loop. Push 0 if to
210 * terminate loop, else push 1. */
212 {"beginCatch4", 5, 0, 1, {OPERAND_UINT4}},
213 /* Record start of catch with the operand's exception index.
214 * Push the current stack depth onto a special catch stack. */
215 {"endCatch", 1, 0, 0, {OPERAND_NONE}},
216 /* End of last catch. Pop the bytecode interpreter's catch stack. */
217 {"pushResult", 1, +1, 0, {OPERAND_NONE}},
218 /* Push the interpreter's object result onto the stack. */
219 {"pushReturnCode", 1, +1, 0, {OPERAND_NONE}},
220 /* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as
221 * a new object onto the stack. */
222 {"streq", 1, -1, 0, {OPERAND_NONE}},
223 /* Str Equal: push (stknext eq stktop) */
224 {"strneq", 1, -1, 0, {OPERAND_NONE}},
225 /* Str !Equal: push (stknext neq stktop) */
226 {"strcmp", 1, -1, 0, {OPERAND_NONE}},
227 /* Str Compare: push (stknext cmp stktop) */
228 {"strlen", 1, 0, 0, {OPERAND_NONE}},
229 /* Str Length: push (strlen stktop) */
230 {"strindex", 1, -1, 0, {OPERAND_NONE}},
231 /* Str Index: push (strindex stknext stktop) */
232 {"strmatch", 2, -1, 1, {OPERAND_INT1}},
233 /* Str Match: push (strmatch stknext stktop) opnd == nocase */
234 {"list", 5, INT_MIN, 1, {OPERAND_UINT4}},
235 /* List: push (stk1 stk2 ... stktop) */
236 {"listindex", 1, -1, 0, {OPERAND_NONE}},
237 /* List Index: push (listindex stknext stktop) */
238 {"listlength", 1, 0, 0, {OPERAND_NONE}},
239 /* List Len: push (listlength stktop) */
240 {"appendScalar1", 2, 0, 1, {OPERAND_UINT1}},
241 /* Append scalar variable at op1<=255 in frame; value is stktop */
242 {"appendScalar4", 5, 0, 1, {OPERAND_UINT4}},
243 /* Append scalar variable at op1 > 255 in frame; value is stktop */
244 {"appendArray1", 2, -1, 1, {OPERAND_UINT1}},
245 /* Append array element; array at op1<=255, value is top then elem */
246 {"appendArray4", 5, -1, 1, {OPERAND_UINT4}},
247 /* Append array element; array at op1>=256, value is top then elem */
248 {"appendArrayStk", 1, -2, 0, {OPERAND_NONE}},
249 /* Append array element; value is stktop, then elem, array names */
250 {"appendStk", 1, -1, 0, {OPERAND_NONE}},
251 /* Append general variable; value is stktop, then unparsed name */
252 {"lappendScalar1", 2, 0, 1, {OPERAND_UINT1}},
253 /* Lappend scalar variable at op1<=255 in frame; value is stktop */
254 {"lappendScalar4", 5, 0, 1, {OPERAND_UINT4}},
255 /* Lappend scalar variable at op1 > 255 in frame; value is stktop */
256 {"lappendArray1", 2, -1, 1, {OPERAND_UINT1}},
257 /* Lappend array element; array at op1<=255, value is top then elem */
258 {"lappendArray4", 5, -1, 1, {OPERAND_UINT4}},
259 /* Lappend array element; array at op1>=256, value is top then elem */
260 {"lappendArrayStk", 1, -2, 0, {OPERAND_NONE}},
261 /* Lappend array element; value is stktop, then elem, array names */
262 {"lappendStk", 1, -1, 0, {OPERAND_NONE}},
263 /* Lappend general variable; value is stktop, then unparsed name */
264 {"lindexMulti", 5, INT_MIN, 1, {OPERAND_UINT4}},
265 /* Lindex with generalized args, operand is number of stacked objs
266 * used: (operand-1) entries from stktop are the indices; then list
268 {"over", 5, +1, 1, {OPERAND_UINT4}},
269 /* Duplicate the arg-th element from top of stack (TOS=0) */
270 {"lsetList", 1, -2, 0, {OPERAND_NONE}},
271 /* Four-arg version of 'lset'. stktop is old value; next is
272 * new element value, next is the index list; pushes new value */
273 {"lsetFlat", 5, INT_MIN, 1, {OPERAND_UINT4}},
274 /* Three- or >=5-arg version of 'lset', operand is number of
275 * stacked objs: stktop is old value, next is new element value, next
276 * come (operand-2) indices; pushes the new value.
282 * Prototypes for procedures defined later in this file:
285 static void DupByteCodeInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
287 static unsigned char * EncodeCmdLocMap _ANSI_ARGS_((
288 CompileEnv *envPtr, ByteCode *codePtr,
289 unsigned char *startPtr));
290 static void EnterCmdExtentData _ANSI_ARGS_((
291 CompileEnv *envPtr, int cmdNumber,
292 int numSrcBytes, int numCodeBytes));
293 static void EnterCmdStartData _ANSI_ARGS_((
294 CompileEnv *envPtr, int cmdNumber,
295 int srcOffset, int codeOffset));
296 static void FreeByteCodeInternalRep _ANSI_ARGS_((
298 static int GetCmdLocEncodingSize _ANSI_ARGS_((
299 CompileEnv *envPtr));
300 static void LogCompilationInfo _ANSI_ARGS_((Tcl_Interp *interp,
301 CONST char *script, CONST char *command,
303 #ifdef TCL_COMPILE_STATS
304 static void RecordByteCodeStats _ANSI_ARGS_((
306 #endif /* TCL_COMPILE_STATS */
307 static int SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp,
311 /* TIP #280 : Helper for building the per-word line information of all
312 * compiled commands */
313 static void EnterCmdWordData _ANSI_ARGS_((
314 ExtCmdLoc *eclPtr, int srcOffset, Tcl_Token* tokenPtr,
315 CONST char* cmd, int len, int numWords, int line,
321 * The structure below defines the bytecode Tcl object type by
322 * means of procedures that can be invoked by generic object code.
325 Tcl_ObjType tclByteCodeType = {
326 "bytecode", /* name */
327 FreeByteCodeInternalRep, /* freeIntRepProc */
328 DupByteCodeInternalRep, /* dupIntRepProc */
329 (Tcl_UpdateStringProc *) NULL, /* updateStringProc */
330 SetByteCodeFromAny /* setFromAnyProc */
334 *----------------------------------------------------------------------
336 * TclSetByteCodeFromAny --
338 * Part of the bytecode Tcl object type implementation. Attempts to
339 * generate an byte code internal form for the Tcl object "objPtr" by
340 * compiling its string representation. This function also takes
341 * a hook procedure that will be invoked to perform any needed post
342 * processing on the compilation results before generating byte
346 * The return value is a standard Tcl object result. If an error occurs
347 * during compilation, an error message is left in the interpreter's
348 * result unless "interp" is NULL.
351 * Frees the old internal representation. If no error occurs, then the
352 * compiled code is stored as "objPtr"s bytecode representation.
353 * Also, if debugging, initializes the "tcl_traceCompile" Tcl variable
354 * used to trace compilations.
356 *----------------------------------------------------------------------
360 TclSetByteCodeFromAny(interp, objPtr, hookProc, clientData)
361 Tcl_Interp *interp; /* The interpreter for which the code is
362 * being compiled. Must not be NULL. */
363 Tcl_Obj *objPtr; /* The object to make a ByteCode object. */
364 CompileHookProc *hookProc; /* Procedure to invoke after compilation. */
365 ClientData clientData; /* Hook procedure private data. */
367 Interp *iPtr = (Interp *) interp;
368 CompileEnv compEnv; /* Compilation environment structure
369 * allocated in frame. */
370 LiteralTable *localTablePtr = &(compEnv.localLitTable);
371 register AuxData *auxDataPtr;
372 LiteralEntry *entryPtr;
374 int length, nested, result;
377 #ifdef TCL_COMPILE_DEBUG
378 if (!traceInitialized) {
379 if (Tcl_LinkVar(interp, "tcl_traceCompile",
380 (char *) &tclTraceCompile, TCL_LINK_INT) != TCL_OK) {
381 panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
383 traceInitialized = 1;
387 if (iPtr->evalFlags & TCL_BRACKET_TERM) {
392 string = Tcl_GetStringFromObj(objPtr, &length);
394 TclInitCompileEnv(interp, &compEnv, string, length);
397 * TIP #280. Pick up the CmdFrame in which the BC compiler was invoked
398 * and use to initialize the tracking in the compiler. This information
399 * was stored by TclCompEvalObj (tclExecute.c), and ProcCompileProc
403 TclInitCompileEnv(interp, &compEnv, string, length,
404 iPtr->invokeCmdFramePtr, iPtr->invokeWord);
406 result = TclCompileScript(interp, string, length, nested, &compEnv);
408 if (result == TCL_OK) {
410 * Successful compilation. Add a "done" instruction at the end.
413 compEnv.numSrcBytes = iPtr->termOffset;
414 TclEmitOpcode(INST_DONE, &compEnv);
417 * Invoke the compilation hook procedure if one exists.
421 result = (*hookProc)(interp, &compEnv, clientData);
425 * Change the object into a ByteCode object. Ownership of the literal
426 * objects and aux data items is given to the ByteCode object.
429 #ifdef TCL_COMPILE_DEBUG
430 TclVerifyLocalLiteralTable(&compEnv);
431 #endif /*TCL_COMPILE_DEBUG*/
433 TclInitByteCodeObj(objPtr, &compEnv);
434 #ifdef TCL_COMPILE_DEBUG
435 if (tclTraceCompile >= 2) {
436 TclPrintByteCodeObj(interp, objPtr);
438 #endif /* TCL_COMPILE_DEBUG */
441 if (result != TCL_OK) {
443 * Compilation errors.
446 entryPtr = compEnv.literalArrayPtr;
447 for (i = 0; i < compEnv.literalArrayNext; i++) {
448 TclReleaseLiteral(interp, entryPtr->objPtr);
451 #ifdef TCL_COMPILE_DEBUG
452 TclVerifyGlobalLiteralTable(iPtr);
453 #endif /*TCL_COMPILE_DEBUG*/
455 auxDataPtr = compEnv.auxDataArrayPtr;
456 for (i = 0; i < compEnv.auxDataArrayNext; i++) {
457 if (auxDataPtr->type->freeProc != NULL) {
458 auxDataPtr->type->freeProc(auxDataPtr->clientData);
466 * Free storage allocated during compilation.
469 if (localTablePtr->buckets != localTablePtr->staticBuckets) {
470 ckfree((char *) localTablePtr->buckets);
472 TclFreeCompileEnv(&compEnv);
477 *-----------------------------------------------------------------------
479 * SetByteCodeFromAny --
481 * Part of the bytecode Tcl object type implementation. Attempts to
482 * generate an byte code internal form for the Tcl object "objPtr" by
483 * compiling its string representation.
486 * The return value is a standard Tcl object result. If an error occurs
487 * during compilation, an error message is left in the interpreter's
488 * result unless "interp" is NULL.
491 * Frees the old internal representation. If no error occurs, then the
492 * compiled code is stored as "objPtr"s bytecode representation.
493 * Also, if debugging, initializes the "tcl_traceCompile" Tcl variable
494 * used to trace compilations.
496 *----------------------------------------------------------------------
500 SetByteCodeFromAny(interp, objPtr)
501 Tcl_Interp *interp; /* The interpreter for which the code is
502 * being compiled. Must not be NULL. */
503 Tcl_Obj *objPtr; /* The object to make a ByteCode object. */
505 return TclSetByteCodeFromAny(interp, objPtr,
506 (CompileHookProc *) NULL, (ClientData) NULL);
510 *----------------------------------------------------------------------
512 * DupByteCodeInternalRep --
514 * Part of the bytecode Tcl object type implementation. However, it
515 * does not copy the internal representation of a bytecode Tcl_Obj, but
516 * instead leaves the new object untyped (with a NULL type pointer).
517 * Code will be compiled for the new object only if necessary.
525 *----------------------------------------------------------------------
529 DupByteCodeInternalRep(srcPtr, copyPtr)
530 Tcl_Obj *srcPtr; /* Object with internal rep to copy. */
531 Tcl_Obj *copyPtr; /* Object with internal rep to set. */
537 *----------------------------------------------------------------------
539 * FreeByteCodeInternalRep --
541 * Part of the bytecode Tcl object type implementation. Frees the
542 * storage associated with a bytecode object's internal representation
543 * unless its code is actively being executed.
549 * The bytecode object's internal rep is marked invalid and its
550 * code gets freed unless the code is actively being executed.
551 * In that case the cleanup is delayed until the last execution
552 * of the code completes.
554 *----------------------------------------------------------------------
558 FreeByteCodeInternalRep(objPtr)
559 register Tcl_Obj *objPtr; /* Object whose internal rep to free. */
561 register ByteCode *codePtr =
562 (ByteCode *) objPtr->internalRep.otherValuePtr;
565 if (codePtr->refCount <= 0) {
566 TclCleanupByteCode(codePtr);
568 objPtr->typePtr = NULL;
569 objPtr->internalRep.otherValuePtr = NULL;
573 *----------------------------------------------------------------------
575 * TclCleanupByteCode --
577 * This procedure does all the real work of freeing up a bytecode
578 * object's ByteCode structure. It's called only when the structure's
579 * reference count becomes zero.
585 * Frees objPtr's bytecode internal representation and sets its type
586 * and objPtr->internalRep.otherValuePtr NULL. Also releases its
587 * literals and frees its auxiliary data items.
589 *----------------------------------------------------------------------
593 TclCleanupByteCode(codePtr)
594 register ByteCode *codePtr; /* Points to the ByteCode to free. */
596 Tcl_Interp *interp = (Tcl_Interp *) *codePtr->interpHandle;
598 Interp* iPtr = (Interp*) interp;
600 int numLitObjects = codePtr->numLitObjects;
601 int numAuxDataItems = codePtr->numAuxDataItems;
602 register Tcl_Obj **objArrayPtr;
603 register AuxData *auxDataPtr;
605 #ifdef TCL_COMPILE_STATS
607 if (interp != NULL) {
608 ByteCodeStats *statsPtr;
609 Tcl_Time destroyTime;
610 int lifetimeSec, lifetimeMicroSec, log2;
612 statsPtr = &((Interp *) interp)->stats;
614 statsPtr->numByteCodesFreed++;
615 statsPtr->currentSrcBytes -= (double) codePtr->numSrcBytes;
616 statsPtr->currentByteCodeBytes -= (double) codePtr->structureSize;
618 statsPtr->currentInstBytes -= (double) codePtr->numCodeBytes;
619 statsPtr->currentLitBytes -=
620 (double) (codePtr->numLitObjects * sizeof(Tcl_Obj *));
621 statsPtr->currentExceptBytes -=
622 (double) (codePtr->numExceptRanges * sizeof(ExceptionRange));
623 statsPtr->currentAuxBytes -=
624 (double) (codePtr->numAuxDataItems * sizeof(AuxData));
625 statsPtr->currentCmdMapBytes -= (double) codePtr->numCmdLocBytes;
627 Tcl_GetTime(&destroyTime);
628 lifetimeSec = destroyTime.sec - codePtr->createTime.sec;
629 if (lifetimeSec > 2000) { /* avoid overflow */
633 1000000*lifetimeSec + (destroyTime.usec - codePtr->createTime.usec);
635 log2 = TclLog2(lifetimeMicroSec);
639 statsPtr->lifetimeCount[log2]++;
641 #endif /* TCL_COMPILE_STATS */
644 * A single heap object holds the ByteCode structure and its code,
645 * object, command location, and auxiliary data arrays. This means we
646 * only need to 1) decrement the ref counts of the LiteralEntry's in
647 * its literal array, 2) call the free procs for the auxiliary data
648 * items, and 3) free the ByteCode structure's heap object.
650 * The case for TCL_BYTECODE_PRECOMPILED (precompiled ByteCodes,
651 * like those generated from tbcload) is special, as they doesn't
652 * make use of the global literal table. They instead maintain
653 * private references to their literals which must be decremented.
656 if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
657 register Tcl_Obj *objPtr;
659 objArrayPtr = codePtr->objArrayPtr;
660 for (i = 0; i < numLitObjects; i++) {
661 objPtr = *objArrayPtr;
663 Tcl_DecrRefCount(objPtr);
667 codePtr->numLitObjects = 0;
668 } else if (interp != NULL) {
670 * If the interp has already been freed, then Tcl will have already
671 * forcefully released all the literals used by ByteCodes compiled
672 * with respect to that interp.
675 objArrayPtr = codePtr->objArrayPtr;
676 for (i = 0; i < numLitObjects; i++) {
678 * TclReleaseLiteral sets a ByteCode's object array entry NULL to
679 * indicate that it has already freed the literal.
682 if (*objArrayPtr != NULL) {
683 TclReleaseLiteral(interp, *objArrayPtr);
689 auxDataPtr = codePtr->auxDataArrayPtr;
690 for (i = 0; i < numAuxDataItems; i++) {
691 if (auxDataPtr->type->freeProc != NULL) {
692 (*auxDataPtr->type->freeProc)(auxDataPtr->clientData);
699 * TIP #280. Release the location data associated with this byte code
700 * structure, if any. NOTE: The interp we belong to may be gone already,
701 * and the data with it.
703 * See also tclBasic.c, DeleteInterpProc
707 Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr);
709 ExtCmdLoc* eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr);
712 if (eclPtr->type == TCL_LOCATION_SOURCE) {
713 Tcl_DecrRefCount (eclPtr->path);
715 for (i=0; i< eclPtr->nuloc; i++) {
716 ckfree ((char*) eclPtr->loc[i].line);
719 if (eclPtr->loc != NULL) {
720 ckfree ((char*) eclPtr->loc);
723 ckfree ((char*) eclPtr);
724 Tcl_DeleteHashEntry (hePtr);
729 TclHandleRelease(codePtr->interpHandle);
730 ckfree((char *) codePtr);
734 *----------------------------------------------------------------------
736 * TclInitCompileEnv --
738 * Initializes a CompileEnv compilation environment structure for the
739 * compilation of a string in an interpreter.
745 * The CompileEnv structure is initialized.
747 *----------------------------------------------------------------------
752 TclInitCompileEnv(interp, envPtr, string, numBytes)
754 TclInitCompileEnv(interp, envPtr, string, numBytes, invoker, word)
756 Tcl_Interp *interp; /* The interpreter for which a CompileEnv
757 * structure is initialized. */
758 register CompileEnv *envPtr; /* Points to the CompileEnv structure to
760 char *string; /* The source string to be compiled. */
761 int numBytes; /* Number of bytes in source string. */
763 CONST CmdFrame* invoker; /* Location context invoking the bcc */
764 int word; /* Index of the word in that context
765 * getting compiled */
768 Interp *iPtr = (Interp *) interp;
771 envPtr->source = string;
772 envPtr->numSrcBytes = numBytes;
773 envPtr->procPtr = iPtr->compiledProcPtr;
774 envPtr->numCommands = 0;
775 envPtr->exceptDepth = 0;
776 envPtr->maxExceptDepth = 0;
777 envPtr->maxStackDepth = 0;
778 envPtr->currStackDepth = 0;
779 TclInitLiteralTable(&(envPtr->localLitTable));
781 envPtr->codeStart = envPtr->staticCodeSpace;
782 envPtr->codeNext = envPtr->codeStart;
783 envPtr->codeEnd = (envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES);
784 envPtr->mallocedCodeArray = 0;
786 envPtr->literalArrayPtr = envPtr->staticLiteralSpace;
787 envPtr->literalArrayNext = 0;
788 envPtr->literalArrayEnd = COMPILEENV_INIT_NUM_OBJECTS;
789 envPtr->mallocedLiteralArray = 0;
791 envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace;
792 envPtr->exceptArrayNext = 0;
793 envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;
794 envPtr->mallocedExceptArray = 0;
796 envPtr->cmdMapPtr = envPtr->staticCmdMapSpace;
797 envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE;
798 envPtr->mallocedCmdMap = 0;
802 * TIP #280: Set up the extended command location information, based on
803 * the context invoking the byte code compiler. This structure is used to
804 * keep the per-word line information for all compiled commands.
806 * See also tclBasic.c, TclEvalObjEx, for the equivalent code in the
807 * non-compiling evaluator
810 envPtr->extCmdMapPtr = (ExtCmdLoc*) ckalloc (sizeof (ExtCmdLoc));
811 envPtr->extCmdMapPtr->loc = NULL;
812 envPtr->extCmdMapPtr->nloc = 0;
813 envPtr->extCmdMapPtr->nuloc = 0;
814 envPtr->extCmdMapPtr->path = NULL;
816 if (invoker == NULL) {
817 /* Initialize the compiler for relative counting */
820 envPtr->extCmdMapPtr->type = (envPtr->procPtr
824 /* Initialize the compiler using the context, making counting absolute
825 * to that context. Note that the context can be byte code
826 * execution. In that case we have to fill out the missing pieces
827 * (line, path, ...). Which may make change the type as well.
830 if ((invoker->nline <= word) || (invoker->line[word] < 0)) {
831 /* Word is not a literal, relative counting */
834 envPtr->extCmdMapPtr->type = (envPtr->procPtr
838 CmdFrame ctx = *invoker;
841 if (invoker->type == TCL_LOCATION_BC) {
842 /* Note: Type BC => ctx.data.eval.path is not used.
843 * ctx.data.tebc.codePtr is used instead.
845 TclGetSrcInfoForPc (&ctx);
849 envPtr->line = ctx.line [word];
850 envPtr->extCmdMapPtr->type = ctx.type;
852 if (ctx.type == TCL_LOCATION_SOURCE) {
854 /* The reference 'TclGetSrcInfoForPc' made is transfered */
855 envPtr->extCmdMapPtr->path = ctx.data.eval.path;
856 ctx.data.eval.path = NULL;
858 /* We have a new reference here */
859 envPtr->extCmdMapPtr->path = ctx.data.eval.path;
860 Tcl_IncrRefCount (envPtr->extCmdMapPtr->path);
867 envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace;
868 envPtr->auxDataArrayNext = 0;
869 envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE;
870 envPtr->mallocedAuxDataArray = 0;
874 *----------------------------------------------------------------------
876 * TclFreeCompileEnv --
878 * Free the storage allocated in a CompileEnv compilation environment
885 * Allocated storage in the CompileEnv structure is freed. Note that
886 * its local literal table is not deleted and its literal objects are
887 * not released. In addition, storage referenced by its auxiliary data
888 * items is not freed. This is done so that, when compilation is
889 * successful, "ownership" of these objects and aux data items is
890 * handed over to the corresponding ByteCode structure.
892 *----------------------------------------------------------------------
896 TclFreeCompileEnv(envPtr)
897 register CompileEnv *envPtr; /* Points to the CompileEnv structure. */
899 if (envPtr->mallocedCodeArray) {
900 ckfree((char *) envPtr->codeStart);
902 if (envPtr->mallocedLiteralArray) {
903 ckfree((char *) envPtr->literalArrayPtr);
905 if (envPtr->mallocedExceptArray) {
906 ckfree((char *) envPtr->exceptArrayPtr);
908 if (envPtr->mallocedCmdMap) {
909 ckfree((char *) envPtr->cmdMapPtr);
911 if (envPtr->mallocedAuxDataArray) {
912 ckfree((char *) envPtr->auxDataArrayPtr);
918 *----------------------------------------------------------------------
920 * TclWordKnownAtCompileTime --
922 * Test whether the value of a token is completely known at compile time.
925 * Returns true if the tokenPtr argument points to a word value that is
926 * completely known at compile time. Generally, values that are known at
927 * compile time can be compiled to their values, while values that cannot
928 * be known until substitution at runtime must be compiled to bytecode
929 * instructions that perform that substitution. For several commands,
930 * whether or not arguments are known at compile time determine whether
931 * it is worthwhile to compile at all.
937 *----------------------------------------------------------------------
941 TclWordKnownAtCompileTime (tokenPtr)
947 if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {return 1;};
948 if (tokenPtr->type != TCL_TOKEN_WORD) {return 0;};
950 /* Check the sub tokens of the word. It is a literal if we find
951 * only BS and TEXT tokens */
953 for (i=0, sub = tokenPtr + 1;
954 i < tokenPtr->numComponents;
956 if (sub->type == TCL_TOKEN_TEXT) continue;
957 if (sub->type == TCL_TOKEN_BS) continue;
965 *----------------------------------------------------------------------
967 * TclCompileScript --
969 * Compile a Tcl script in a string.
972 * The return value is TCL_OK on a successful compilation and TCL_ERROR
973 * on failure. If TCL_ERROR is returned, then the interpreter's result
974 * contains an error message.
976 * interp->termOffset is set to the offset of the character in the
977 * script just after the last one successfully processed; this will be
978 * the offset of the ']' if (flags & TCL_BRACKET_TERM).
981 * Adds instructions to envPtr to evaluate the script at runtime.
983 *----------------------------------------------------------------------
987 TclCompileScript(interp, script, numBytes, nested, envPtr)
988 Tcl_Interp *interp; /* Used for error and status reporting.
989 * Also serves as context for finding and
990 * compiling commands. May not be NULL. */
991 CONST char *script; /* The source script to compile. */
992 int numBytes; /* Number of bytes in script. If < 0, the
993 * script consists of all bytes up to the
994 * first null character. */
995 int nested; /* Non-zero means this is a nested command:
996 * close bracket ']' should be considered a
997 * command terminator. If zero, close
998 * bracket has no special meaning. */
999 CompileEnv *envPtr; /* Holds resulting instructions. */
1001 Interp *iPtr = (Interp *) interp;
1003 int lastTopLevelCmdIndex = -1;
1004 /* Index of most recent toplevel command in
1005 * the command location table. Initialized
1006 * to avoid compiler warning. */
1007 int startCodeOffset = -1; /* Offset of first byte of current command's
1008 * code. Init. to avoid compiler warning. */
1009 unsigned char *entryCodeNext = envPtr->codeNext;
1010 CONST char *p, *next;
1011 Namespace *cmdNsPtr;
1013 Tcl_Token *tokenPtr;
1014 int bytesLeft, isFirstCmd, gotParse, wordIdx, currCmdIndex;
1015 int commandLength, objIndex, code;
1020 ExtCmdLoc* eclPtr = envPtr->extCmdMapPtr;
1022 int wlineat, cmdLine;
1025 Tcl_DStringInit(&ds);
1028 numBytes = strlen(script);
1030 Tcl_ResetResult(interp);
1034 * Each iteration through the following loop compiles the next
1035 * command from the script.
1039 bytesLeft = numBytes;
1042 cmdLine = envPtr->line;
1046 if (Tcl_ParseCommand(interp, p, bytesLeft, nested, &parse) != TCL_OK) {
1053 * This is an unusual situation where the caller has passed us
1054 * a non-zero value for "nested". How unusual? Well, this
1055 * procedure, TclCompileScript, is internal to Tcl, so all
1056 * callers should be within Tcl itself. All but one of those
1057 * callers explicitly pass in (nested = 0). The exceptional
1058 * caller is TclSetByteCodeFromAny, which will pass in
1059 * (nested = 1) if and only if the flag TCL_BRACKET_TERM
1060 * is set in the evalFlags field of interp.
1062 * It appears that the TCL_BRACKET_TERM flag is only ever set
1063 * by Tcl_SubstObj, and it immediately calls Tcl_EvalEx
1064 * which clears the flag before passing the interp along.
1065 * So, I don't think this procedure, TclCompileScript, is
1066 * **ever** called with (nested != 0).
1067 * (The testsuite indeed doesn't exercise this code. MS)
1069 * This means that the branches in this procedure that are
1070 * only active when (nested != 0) are probably never exercised.
1071 * This means that any bugs in them go unnoticed, and any bug
1072 * fixes in them have a semi-theoretical nature.
1074 * All that said, the spec for this procedure says it should
1075 * handle the (nested != 0) case, so here's an attempt to fix
1076 * bugs (Tcl Bug 681841) in that case. Just in case some
1077 * callers eventually come along and expect it to work...
1080 if (parse.term == (script + numBytes)) {
1082 * The (nested != 0) case is meant to indicate that the
1083 * caller found an open bracket ([) and asked us to
1084 * parse and compile Tcl commands up to the matching
1085 * close bracket (]). We have to detect and handle
1086 * the case where the close bracket is missing.
1089 Tcl_SetObjResult(interp,
1090 Tcl_NewStringObj("missing close-bracket", -1));
1095 if (parse.numWords > 0) {
1097 * If not the first command, pop the previous command's result
1098 * and, if we're compiling a top level command, update the last
1099 * command's code size to account for the pop instruction.
1103 TclEmitOpcode(INST_POP, envPtr);
1105 envPtr->cmdMapPtr[lastTopLevelCmdIndex].numCodeBytes =
1106 (envPtr->codeNext - envPtr->codeStart)
1112 * Determine the actual length of the command.
1115 commandLength = parse.commandSize;
1116 if (parse.term == parse.commandStart + commandLength - 1) {
1118 * The command terminator character (such as ; or ]) is
1119 * the last character in the parsed command. Reduce the
1120 * length by one so that the trace message doesn't include
1121 * the terminator character.
1127 #ifdef TCL_COMPILE_DEBUG
1129 * If tracing, print a line for each top level command compiled.
1132 if ((tclTraceCompile >= 1)
1133 && !nested && (envPtr->procPtr == NULL)) {
1134 fprintf(stdout, " Compiling: ");
1135 TclPrintSource(stdout, parse.commandStart,
1136 TclMin(commandLength, 55));
1137 fprintf(stdout, "\n");
1141 * Each iteration of the following loop compiles one word
1145 envPtr->numCommands++;
1146 currCmdIndex = (envPtr->numCommands - 1);
1148 lastTopLevelCmdIndex = currCmdIndex;
1150 startCodeOffset = (envPtr->codeNext - envPtr->codeStart);
1151 EnterCmdStartData(envPtr, currCmdIndex,
1152 (parse.commandStart - envPtr->source), startCodeOffset);
1155 /* TIP #280. Scan the words and compute the extended location
1156 * information. The map first contain full per-word line
1157 * information for use by the compiler. This is later replaced by
1158 * a reduced form which signals non-literal words, stored in
1162 TclAdvanceLines (&cmdLine, p, parse.commandStart);
1163 EnterCmdWordData (eclPtr, (parse.commandStart - envPtr->source),
1164 parse.tokenPtr, parse.commandStart, parse.commandSize,
1165 parse.numWords, cmdLine, &wlines);
1166 wlineat = eclPtr->nuloc - 1;
1169 for (wordIdx = 0, tokenPtr = parse.tokenPtr;
1170 wordIdx < parse.numWords;
1171 wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) {
1173 envPtr->line = eclPtr->loc [wlineat].line [wordIdx];
1175 if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
1177 * If this is the first word and the command has a
1178 * compile procedure, let it compile the command.
1182 if (envPtr->procPtr != NULL) {
1183 cmdNsPtr = envPtr->procPtr->cmdPtr->nsPtr;
1185 cmdNsPtr = NULL; /* use current NS */
1189 * We copy the string before trying to find the command
1190 * by name. We used to modify the string in place, but
1191 * this is not safe because the name resolution
1192 * handlers could have side effects that rely on the
1193 * unmodified string.
1196 Tcl_DStringSetLength(&ds, 0);
1197 Tcl_DStringAppend(&ds, tokenPtr[1].start,
1200 cmdPtr = (Command *) Tcl_FindCommand(interp,
1201 Tcl_DStringValue(&ds),
1202 (Tcl_Namespace *) cmdNsPtr, /*flags*/ 0);
1204 if ((cmdPtr != NULL)
1205 && (cmdPtr->compileProc != NULL)
1206 && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES)
1207 && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) {
1208 int savedNumCmds = envPtr->numCommands;
1209 unsigned int savedCodeNext =
1210 envPtr->codeNext - envPtr->codeStart;
1212 code = (*(cmdPtr->compileProc))(interp, &parse,
1214 if (code == TCL_OK) {
1216 } else if (code == TCL_OUT_LINE_COMPILE) {
1218 * Restore numCommands and codeNext to their correct
1219 * values, removing any commands compiled before
1220 * TCL_OUT_LINE_COMPILE [Bugs 705406 and 735055]
1222 envPtr->numCommands = savedNumCmds;
1223 envPtr->codeNext = envPtr->codeStart + savedCodeNext;
1224 } else { /* an error */
1226 * There was a compilation error, the last
1227 * command did not get compiled into (*envPtr).
1228 * Decrement the number of commands
1229 * claimed to be in (*envPtr).
1231 envPtr->numCommands--;
1237 * No compile procedure so push the word. If the
1238 * command was found, push a CmdName object to
1239 * reduce runtime lookups.
1242 objIndex = TclRegisterNewLiteral(envPtr,
1243 tokenPtr[1].start, tokenPtr[1].size);
1244 if (cmdPtr != NULL) {
1245 TclSetCmdNameObj(interp,
1246 envPtr->literalArrayPtr[objIndex].objPtr,
1250 objIndex = TclRegisterNewLiteral(envPtr,
1251 tokenPtr[1].start, tokenPtr[1].size);
1253 TclEmitPush(objIndex, envPtr);
1256 * The word is not a simple string of characters.
1258 code = TclCompileTokens(interp, tokenPtr+1,
1259 tokenPtr->numComponents, envPtr);
1260 if (code != TCL_OK) {
1267 * Emit an invoke instruction for the command. We skip this
1268 * if a compile procedure was found for the command.
1272 if (wordIdx <= 255) {
1273 TclEmitInstInt1(INST_INVOKE_STK1, wordIdx, envPtr);
1275 TclEmitInstInt4(INST_INVOKE_STK4, wordIdx, envPtr);
1280 * Update the compilation environment structure and record the
1281 * offsets of the source and code for the command.
1285 EnterCmdExtentData(envPtr, currCmdIndex, commandLength,
1286 (envPtr->codeNext-envPtr->codeStart) - startCodeOffset);
1290 /* TIP #280: Free full form of per-word line data and insert
1291 * the reduced form now
1293 ckfree ((char*) eclPtr->loc [wlineat].line);
1294 eclPtr->loc [wlineat].line = wlines;
1296 } /* end if parse.numWords > 0 */
1299 * Advance to the next command in the script.
1302 next = parse.commandStart + parse.commandSize;
1303 bytesLeft -= (next - p);
1306 /* TIP #280 : Track lines in the just compiled command */
1307 TclAdvanceLines (&cmdLine, parse.commandStart, p);
1309 Tcl_FreeParse(&parse);
1311 if (nested && (*parse.term == ']')) {
1313 * We get here in the special case where TCL_BRACKET_TERM was
1314 * set in the interpreter and the latest parsed command was
1315 * terminated by the matching close-bracket we were looking for.
1321 } while (bytesLeft > 0);
1324 * If the source script yielded no instructions (e.g., if it was empty),
1325 * push an empty string as the command's result.
1328 if (envPtr->codeNext == entryCodeNext) {
1329 TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0),
1335 * When (nested != 0) back up 1 character to have
1336 * iPtr->termOffset indicate the offset to the matching
1340 iPtr->termOffset = (p - 1) - script;
1342 iPtr->termOffset = (p - script);
1344 Tcl_DStringFree(&ds);
1349 * Generate various pieces of error information, such as the line
1350 * number where the error occurred and information to add to the
1351 * errorInfo variable. Then free resources that had been allocated
1355 commandLength = parse.commandSize;
1356 if (parse.term == parse.commandStart + commandLength - 1) {
1358 * The terminator character (such as ; or ]) of the command where
1359 * the error occurred is the last character in the parsed command.
1360 * Reduce the length by one so that the error message doesn't
1361 * include the terminator character.
1368 LogCompilationInfo(interp, script, parse.commandStart, commandLength);
1370 Tcl_FreeParse(&parse);
1372 iPtr->termOffset = (p - script);
1373 Tcl_DStringFree(&ds);
1378 *----------------------------------------------------------------------
1380 * TclCompileTokens --
1382 * Given an array of tokens parsed from a Tcl command (e.g., the tokens
1383 * that make up a word) this procedure emits instructions to evaluate
1384 * the tokens and concatenate their values to form a single result
1385 * value on the interpreter's runtime evaluation stack.
1388 * The return value is a standard Tcl result. If an error occurs, an
1389 * error message is left in the interpreter's result.
1392 * Instructions are added to envPtr to push and evaluate the tokens
1395 *----------------------------------------------------------------------
1399 TclCompileTokens(interp, tokenPtr, count, envPtr)
1400 Tcl_Interp *interp; /* Used for error and status reporting. */
1401 Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens
1403 int count; /* Number of tokens to consider at tokenPtr.
1404 * Must be at least 1. */
1405 CompileEnv *envPtr; /* Holds the resulting instructions. */
1407 Tcl_DString textBuffer; /* Holds concatenated chars from adjacent
1408 * TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */
1409 char buffer[TCL_UTF_MAX];
1410 CONST char *name, *p;
1411 int numObjsToConcat, nameBytes, localVarName, localVar;
1412 int length, i, code;
1413 unsigned char *entryCodeNext = envPtr->codeNext;
1415 Tcl_DStringInit(&textBuffer);
1416 numObjsToConcat = 0;
1417 for ( ; count > 0; count--, tokenPtr++) {
1418 switch (tokenPtr->type) {
1419 case TCL_TOKEN_TEXT:
1420 Tcl_DStringAppend(&textBuffer, tokenPtr->start,
1425 length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL,
1427 Tcl_DStringAppend(&textBuffer, buffer, length);
1430 case TCL_TOKEN_COMMAND:
1432 * Push any accumulated chars appearing before the command.
1435 if (Tcl_DStringLength(&textBuffer) > 0) {
1438 literal = TclRegisterLiteral(envPtr,
1439 Tcl_DStringValue(&textBuffer),
1440 Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
1441 TclEmitPush(literal, envPtr);
1443 Tcl_DStringFree(&textBuffer);
1446 code = TclCompileScript(interp, tokenPtr->start+1,
1447 tokenPtr->size-2, /*nested*/ 0, envPtr);
1448 if (code != TCL_OK) {
1454 case TCL_TOKEN_VARIABLE:
1456 * Push any accumulated chars appearing before the $<var>.
1459 if (Tcl_DStringLength(&textBuffer) > 0) {
1462 literal = TclRegisterLiteral(envPtr,
1463 Tcl_DStringValue(&textBuffer),
1464 Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
1465 TclEmitPush(literal, envPtr);
1467 Tcl_DStringFree(&textBuffer);
1471 * Determine how the variable name should be handled: if it contains
1472 * any namespace qualifiers it is not a local variable (localVarName=-1);
1473 * if it looks like an array element and the token has a single component,
1474 * it should not be created here [Bug 569438] (localVarName=0); otherwise,
1475 * the local variable can safely be created (localVarName=1).
1478 name = tokenPtr[1].start;
1479 nameBytes = tokenPtr[1].size;
1481 if (envPtr->procPtr != NULL) {
1483 for (i = 0, p = name; i < nameBytes; i++, p++) {
1484 if ((*p == ':') && (i < (nameBytes-1))
1485 && (*(p+1) == ':')) {
1488 } else if ((*p == '(')
1489 && (tokenPtr->numComponents == 1)
1490 && (*(name + nameBytes - 1) == ')')) {
1498 * Either push the variable's name, or find its index in
1499 * the array of local variables in a procedure frame.
1503 if (localVarName != -1) {
1504 localVar = TclFindCompiledLocal(name, nameBytes,
1505 localVarName, /*flags*/ 0, envPtr->procPtr);
1508 TclEmitPush(TclRegisterNewLiteral(envPtr, name, nameBytes),
1513 * Emit instructions to load the variable.
1516 if (tokenPtr->numComponents == 1) {
1518 TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
1519 } else if (localVar <= 255) {
1520 TclEmitInstInt1(INST_LOAD_SCALAR1, localVar,
1523 TclEmitInstInt4(INST_LOAD_SCALAR4, localVar,
1527 code = TclCompileTokens(interp, tokenPtr+2,
1528 tokenPtr->numComponents-1, envPtr);
1529 if (code != TCL_OK) {
1530 char errorBuffer[150];
1531 sprintf(errorBuffer,
1532 "\n (parsing index for array \"%.*s\")",
1533 ((nameBytes > 100)? 100 : nameBytes), name);
1534 Tcl_AddObjErrorInfo(interp, errorBuffer, -1);
1538 TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);
1539 } else if (localVar <= 255) {
1540 TclEmitInstInt1(INST_LOAD_ARRAY1, localVar,
1543 TclEmitInstInt4(INST_LOAD_ARRAY4, localVar,
1548 count -= tokenPtr->numComponents;
1549 tokenPtr += tokenPtr->numComponents;
1553 panic("Unexpected token type in TclCompileTokens");
1558 * Push any accumulated characters appearing at the end.
1561 if (Tcl_DStringLength(&textBuffer) > 0) {
1564 literal = TclRegisterLiteral(envPtr, Tcl_DStringValue(&textBuffer),
1565 Tcl_DStringLength(&textBuffer), /*onHeap*/ 0);
1566 TclEmitPush(literal, envPtr);
1571 * If necessary, concatenate the parts of the word.
1574 while (numObjsToConcat > 255) {
1575 TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
1576 numObjsToConcat -= 254; /* concat pushes 1 obj, the result */
1578 if (numObjsToConcat > 1) {
1579 TclEmitInstInt1(INST_CONCAT1, numObjsToConcat, envPtr);
1583 * If the tokens yielded no instructions, push an empty string.
1586 if (envPtr->codeNext == entryCodeNext) {
1587 TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0),
1590 Tcl_DStringFree(&textBuffer);
1594 Tcl_DStringFree(&textBuffer);
1599 *----------------------------------------------------------------------
1601 * TclCompileCmdWord --
1603 * Given an array of parse tokens for a word containing one or more Tcl
1604 * commands, emit inline instructions to execute them. This procedure
1605 * differs from TclCompileTokens in that a simple word such as a loop
1606 * body enclosed in braces is not just pushed as a string, but is
1607 * itself parsed into tokens and compiled.
1610 * The return value is a standard Tcl result. If an error occurs, an
1611 * error message is left in the interpreter's result.
1614 * Instructions are added to envPtr to execute the tokens at runtime.
1616 *----------------------------------------------------------------------
1620 TclCompileCmdWord(interp, tokenPtr, count, envPtr)
1621 Tcl_Interp *interp; /* Used for error and status reporting. */
1622 Tcl_Token *tokenPtr; /* Pointer to first in an array of tokens
1623 * for a command word to compile inline. */
1624 int count; /* Number of tokens to consider at tokenPtr.
1625 * Must be at least 1. */
1626 CompileEnv *envPtr; /* Holds the resulting instructions. */
1631 * Handle the common case: if there is a single text token, compile it
1632 * into an inline sequence of instructions.
1635 if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) {
1636 code = TclCompileScript(interp, tokenPtr->start, tokenPtr->size,
1637 /*nested*/ 0, envPtr);
1642 * Multiple tokens or the single token involves substitutions. Emit
1643 * instructions to invoke the eval command procedure at runtime on the
1644 * result of evaluating the tokens.
1647 code = TclCompileTokens(interp, tokenPtr, count, envPtr);
1648 if (code != TCL_OK) {
1651 TclEmitOpcode(INST_EVAL_STK, envPtr);
1656 *----------------------------------------------------------------------
1658 * TclCompileExprWords --
1660 * Given an array of parse tokens representing one or more words that
1661 * contain a Tcl expression, emit inline instructions to execute the
1662 * expression. This procedure differs from TclCompileExpr in that it
1663 * supports Tcl's two-level substitution semantics for expressions that
1664 * appear as command words.
1667 * The return value is a standard Tcl result. If an error occurs, an
1668 * error message is left in the interpreter's result.
1671 * Instructions are added to envPtr to execute the expression.
1673 *----------------------------------------------------------------------
1677 TclCompileExprWords(interp, tokenPtr, numWords, envPtr)
1678 Tcl_Interp *interp; /* Used for error and status reporting. */
1679 Tcl_Token *tokenPtr; /* Points to first in an array of word
1680 * tokens tokens for the expression to
1681 * compile inline. */
1682 int numWords; /* Number of word tokens starting at
1683 * tokenPtr. Must be at least 1. Each word
1684 * token contains one or more subtokens. */
1685 CompileEnv *envPtr; /* Holds the resulting instructions. */
1688 int numBytes, i, code;
1694 * If the expression is a single word that doesn't require
1695 * substitutions, just compile its string into inline instructions.
1698 if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
1699 script = tokenPtr[1].start;
1700 numBytes = tokenPtr[1].size;
1701 code = TclCompileExpr(interp, script, numBytes, envPtr);
1706 * Emit code to call the expr command proc at runtime. Concatenate the
1707 * (already substituted once) expr tokens with a space between each.
1711 for (i = 0; i < numWords; i++) {
1712 code = TclCompileTokens(interp, wordPtr+1, wordPtr->numComponents,
1714 if (code != TCL_OK) {
1717 if (i < (numWords - 1)) {
1718 TclEmitPush(TclRegisterLiteral(envPtr, " ", 1, /*onHeap*/ 0),
1721 wordPtr += (wordPtr->numComponents + 1);
1723 if (code == TCL_OK) {
1724 int concatItems = 2*numWords - 1;
1725 while (concatItems > 255) {
1726 TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
1729 if (concatItems > 1) {
1730 TclEmitInstInt1(INST_CONCAT1, concatItems, envPtr);
1732 TclEmitOpcode(INST_EXPR_STK, envPtr);
1739 *----------------------------------------------------------------------
1741 * TclInitByteCodeObj --
1743 * Create a ByteCode structure and initialize it from a CompileEnv
1744 * compilation environment structure. The ByteCode structure is
1745 * smaller and contains just that information needed to execute
1746 * the bytecode instructions resulting from compiling a Tcl script.
1747 * The resulting structure is placed in the specified object.
1750 * A newly constructed ByteCode object is stored in the internal
1751 * representation of the objPtr.
1754 * A single heap object is allocated to hold the new ByteCode structure
1755 * and its code, object, command location, and aux data arrays. Note
1756 * that "ownership" (i.e., the pointers to) the Tcl objects and aux
1757 * data items will be handed over to the new ByteCode structure from
1758 * the CompileEnv structure.
1760 *----------------------------------------------------------------------
1764 TclInitByteCodeObj(objPtr, envPtr)
1765 Tcl_Obj *objPtr; /* Points object that should be
1766 * initialized, and whose string rep
1767 * contains the source code. */
1768 register CompileEnv *envPtr; /* Points to the CompileEnv structure from
1769 * which to create a ByteCode structure. */
1771 register ByteCode *codePtr;
1772 size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes;
1773 size_t auxDataArrayBytes, structureSize;
1774 register unsigned char *p;
1775 #ifdef TCL_COMPILE_DEBUG
1776 unsigned char *nextPtr;
1778 int numLitObjects = envPtr->literalArrayNext;
1779 Namespace *namespacePtr;
1786 iPtr = envPtr->iPtr;
1788 codeBytes = (envPtr->codeNext - envPtr->codeStart);
1789 objArrayBytes = (envPtr->literalArrayNext * sizeof(Tcl_Obj *));
1790 exceptArrayBytes = (envPtr->exceptArrayNext * sizeof(ExceptionRange));
1791 auxDataArrayBytes = (envPtr->auxDataArrayNext * sizeof(AuxData));
1792 cmdLocBytes = GetCmdLocEncodingSize(envPtr);
1795 * Compute the total number of bytes needed for this bytecode.
1798 structureSize = sizeof(ByteCode);
1799 structureSize += TCL_ALIGN(codeBytes); /* align object array */
1800 structureSize += TCL_ALIGN(objArrayBytes); /* align exc range arr */
1801 structureSize += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
1802 structureSize += auxDataArrayBytes;
1803 structureSize += cmdLocBytes;
1805 if (envPtr->iPtr->varFramePtr != NULL) {
1806 namespacePtr = envPtr->iPtr->varFramePtr->nsPtr;
1808 namespacePtr = envPtr->iPtr->globalNsPtr;
1811 p = (unsigned char *) ckalloc((size_t) structureSize);
1812 codePtr = (ByteCode *) p;
1813 codePtr->interpHandle = TclHandlePreserve(iPtr->handle);
1814 codePtr->compileEpoch = iPtr->compileEpoch;
1815 codePtr->nsPtr = namespacePtr;
1816 codePtr->nsEpoch = namespacePtr->resolverEpoch;
1817 codePtr->refCount = 1;
1819 codePtr->source = envPtr->source;
1820 codePtr->procPtr = envPtr->procPtr;
1822 codePtr->numCommands = envPtr->numCommands;
1823 codePtr->numSrcBytes = envPtr->numSrcBytes;
1824 codePtr->numCodeBytes = codeBytes;
1825 codePtr->numLitObjects = numLitObjects;
1826 codePtr->numExceptRanges = envPtr->exceptArrayNext;
1827 codePtr->numAuxDataItems = envPtr->auxDataArrayNext;
1828 codePtr->numCmdLocBytes = cmdLocBytes;
1829 codePtr->maxExceptDepth = envPtr->maxExceptDepth;
1830 codePtr->maxStackDepth = envPtr->maxStackDepth;
1832 p += sizeof(ByteCode);
1833 codePtr->codeStart = p;
1834 memcpy((VOID *) p, (VOID *) envPtr->codeStart, (size_t) codeBytes);
1836 p += TCL_ALIGN(codeBytes); /* align object array */
1837 codePtr->objArrayPtr = (Tcl_Obj **) p;
1838 for (i = 0; i < numLitObjects; i++) {
1839 codePtr->objArrayPtr[i] = envPtr->literalArrayPtr[i].objPtr;
1842 p += TCL_ALIGN(objArrayBytes); /* align exception range array */
1843 if (exceptArrayBytes > 0) {
1844 codePtr->exceptArrayPtr = (ExceptionRange *) p;
1845 memcpy((VOID *) p, (VOID *) envPtr->exceptArrayPtr,
1846 (size_t) exceptArrayBytes);
1848 codePtr->exceptArrayPtr = NULL;
1851 p += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
1852 if (auxDataArrayBytes > 0) {
1853 codePtr->auxDataArrayPtr = (AuxData *) p;
1854 memcpy((VOID *) p, (VOID *) envPtr->auxDataArrayPtr,
1855 (size_t) auxDataArrayBytes);
1857 codePtr->auxDataArrayPtr = NULL;
1860 p += auxDataArrayBytes;
1861 #ifndef TCL_COMPILE_DEBUG
1862 EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
1864 nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
1865 if (((size_t)(nextPtr - p)) != cmdLocBytes) {
1866 panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d\n", (nextPtr - p), cmdLocBytes);
1871 * Record various compilation-related statistics about the new ByteCode
1872 * structure. Don't include overhead for statistics-related fields.
1875 #ifdef TCL_COMPILE_STATS
1876 codePtr->structureSize = structureSize
1877 - (sizeof(size_t) + sizeof(Tcl_Time));
1878 Tcl_GetTime(&(codePtr->createTime));
1880 RecordByteCodeStats(codePtr);
1881 #endif /* TCL_COMPILE_STATS */
1884 * Free the old internal rep then convert the object to a
1885 * bytecode object by making its internal rep point to the just
1886 * compiled ByteCode.
1889 if ((objPtr->typePtr != NULL) &&
1890 (objPtr->typePtr->freeIntRepProc != NULL)) {
1891 (*objPtr->typePtr->freeIntRepProc)(objPtr);
1893 objPtr->internalRep.otherValuePtr = (VOID *) codePtr;
1894 objPtr->typePtr = &tclByteCodeType;
1897 /* TIP #280. Associate the extended per-word line information with the
1898 * byte code object (internal rep), for use with the bc compiler.
1901 Tcl_SetHashValue (Tcl_CreateHashEntry (iPtr->lineBCPtr, (char*) codePtr, &new),
1902 envPtr->extCmdMapPtr);
1903 envPtr->extCmdMapPtr = NULL;
1908 *----------------------------------------------------------------------
1910 * LogCompilationInfo --
1912 * This procedure is invoked after an error occurs during compilation.
1913 * It adds information to the "errorInfo" variable to describe the
1914 * command that was being compiled when the error occurred.
1920 * Information about the command is added to errorInfo and the
1921 * line number stored internally in the interpreter is set. If this
1922 * is the first call to this procedure or Tcl_AddObjErrorInfo since
1923 * an error occurred, then old information in errorInfo is
1926 *----------------------------------------------------------------------
1930 LogCompilationInfo(interp, script, command, length)
1931 Tcl_Interp *interp; /* Interpreter in which to log the
1933 CONST char *script; /* First character in script containing
1934 * command (must be <= command). */
1935 CONST char *command; /* First character in command that
1936 * generated the error. */
1937 int length; /* Number of bytes in command (-1 means
1938 * use all bytes up to first null byte). */
1941 register CONST char *p;
1942 char *ellipsis = "";
1943 Interp *iPtr = (Interp *) interp;
1945 if (iPtr->flags & ERR_ALREADY_LOGGED) {
1947 * Someone else has already logged error information for this
1948 * command; we shouldn't add anything more.
1955 * Compute the line number where the error occurred.
1958 iPtr->errorLine = 1;
1959 for (p = script; p != command; p++) {
1966 * Create an error message to add to errorInfo, including up to a
1967 * maximum number of characters of the command.
1971 length = strlen(command);
1977 while ( (command[length] & 0xC0) == 0x80 ) {
1979 * Back up truncation point so that we don't truncate in the
1980 * middle of a multi-byte character (in UTF-8)
1985 sprintf(buffer, "\n while compiling\n\"%.*s%s\"",
1986 length, command, ellipsis);
1987 Tcl_AddObjErrorInfo(interp, buffer, -1);
1991 *----------------------------------------------------------------------
1993 * TclFindCompiledLocal --
1995 * This procedure is called at compile time to look up and optionally
1996 * allocate an entry ("slot") for a variable in a procedure's array of
1997 * local variables. If the variable's name is NULL, a new temporary
1998 * variable is always created. (Such temporary variables can only be
1999 * referenced using their slot index.)
2002 * If create is 0 and the name is non-NULL, then if the variable is
2003 * found, the index of its entry in the procedure's array of local
2004 * variables is returned; otherwise -1 is returned. If name is NULL,
2005 * the index of a new temporary variable is returned. Finally, if
2006 * create is 1 and name is non-NULL, the index of a new entry is
2010 * Creates and registers a new local variable if create is 1 and
2011 * the variable is unknown, or if the name is NULL.
2013 *----------------------------------------------------------------------
2017 TclFindCompiledLocal(name, nameBytes, create, flags, procPtr)
2018 register CONST char *name; /* Points to first character of the name of
2019 * a scalar or array variable. If NULL, a
2020 * temporary var should be created. */
2021 int nameBytes; /* Number of bytes in the name. */
2022 int create; /* If 1, allocate a local frame entry for
2023 * the variable if it is new. */
2024 int flags; /* Flag bits for the compiled local if
2025 * created. Only VAR_SCALAR, VAR_ARRAY, and
2026 * VAR_LINK make sense. */
2027 register Proc *procPtr; /* Points to structure describing procedure
2028 * containing the variable reference. */
2030 register CompiledLocal *localPtr;
2035 * If not creating a temporary, does a local variable of the specified
2036 * name already exist?
2040 int localCt = procPtr->numCompiledLocals;
2041 localPtr = procPtr->firstLocalPtr;
2042 for (i = 0; i < localCt; i++) {
2043 if (!TclIsVarTemporary(localPtr)) {
2044 char *localName = localPtr->name;
2045 if ((nameBytes == localPtr->nameLength)
2046 && (strncmp(name, localName, (unsigned) nameBytes) == 0)) {
2050 localPtr = localPtr->nextPtr;
2055 * Create a new variable if appropriate.
2058 if (create || (name == NULL)) {
2059 localVar = procPtr->numCompiledLocals;
2060 localPtr = (CompiledLocal *) ckalloc((unsigned)
2061 (sizeof(CompiledLocal) - sizeof(localPtr->name)
2063 if (procPtr->firstLocalPtr == NULL) {
2064 procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
2066 procPtr->lastLocalPtr->nextPtr = localPtr;
2067 procPtr->lastLocalPtr = localPtr;
2069 localPtr->nextPtr = NULL;
2070 localPtr->nameLength = nameBytes;
2071 localPtr->frameIndex = localVar;
2072 localPtr->flags = flags | VAR_UNDEFINED;
2074 localPtr->flags |= VAR_TEMPORARY;
2076 localPtr->defValuePtr = NULL;
2077 localPtr->resolveInfo = NULL;
2080 memcpy((VOID *) localPtr->name, (VOID *) name,
2081 (size_t) nameBytes);
2083 localPtr->name[nameBytes] = '\0';
2084 procPtr->numCompiledLocals++;
2090 *----------------------------------------------------------------------
2092 * TclInitCompiledLocals --
2094 * This routine is invoked in order to initialize the compiled
2095 * locals table for a new call frame.
2101 * May invoke various name resolvers in order to determine which
2102 * variables are being referenced at runtime.
2104 *----------------------------------------------------------------------
2108 TclInitCompiledLocals(interp, framePtr, nsPtr)
2109 Tcl_Interp *interp; /* Current interpreter. */
2110 CallFrame *framePtr; /* Call frame to initialize. */
2111 Namespace *nsPtr; /* Pointer to current namespace. */
2113 register CompiledLocal *localPtr;
2114 Interp *iPtr = (Interp*) interp;
2115 Tcl_ResolvedVarInfo *vinfo, *resVarInfo;
2116 Var *varPtr = framePtr->compiledLocals;
2117 Var *resolvedVarPtr;
2118 ResolverScheme *resPtr;
2122 * Initialize the array of local variables stored in the call frame.
2123 * Some variables may have special resolution rules. In that case,
2124 * we call their "resolver" procs to get our hands on the variable,
2125 * and we make the compiled local a link to the real variable.
2128 for (localPtr = framePtr->procPtr->firstLocalPtr;
2130 localPtr = localPtr->nextPtr) {
2133 * Check to see if this local is affected by namespace or
2134 * interp resolvers. The resolver to use is cached for the
2135 * next invocation of the procedure.
2138 if (!(localPtr->flags & (VAR_ARGUMENT|VAR_TEMPORARY|VAR_RESOLVED))
2139 && (nsPtr->compiledVarResProc || iPtr->resolverPtr)) {
2140 resPtr = iPtr->resolverPtr;
2142 if (nsPtr->compiledVarResProc) {
2143 result = (*nsPtr->compiledVarResProc)(nsPtr->interp,
2144 localPtr->name, localPtr->nameLength,
2145 (Tcl_Namespace *) nsPtr, &vinfo);
2147 result = TCL_CONTINUE;
2150 while ((result == TCL_CONTINUE) && resPtr) {
2151 if (resPtr->compiledVarResProc) {
2152 result = (*resPtr->compiledVarResProc)(nsPtr->interp,
2153 localPtr->name, localPtr->nameLength,
2154 (Tcl_Namespace *) nsPtr, &vinfo);
2156 resPtr = resPtr->nextPtr;
2158 if (result == TCL_OK) {
2159 localPtr->resolveInfo = vinfo;
2160 localPtr->flags |= VAR_RESOLVED;
2165 * Now invoke the resolvers to determine the exact variables that
2169 resVarInfo = localPtr->resolveInfo;
2170 resolvedVarPtr = NULL;
2172 if (resVarInfo && resVarInfo->fetchProc) {
2173 resolvedVarPtr = (Var*) (*resVarInfo->fetchProc)(interp,
2177 if (resolvedVarPtr) {
2178 varPtr->name = localPtr->name; /* will be just '\0' if temp var */
2179 varPtr->nsPtr = NULL;
2180 varPtr->hPtr = NULL;
2181 varPtr->refCount = 0;
2182 varPtr->tracePtr = NULL;
2183 varPtr->searchPtr = NULL;
2185 TclSetVarLink(varPtr);
2186 varPtr->value.linkPtr = resolvedVarPtr;
2187 resolvedVarPtr->refCount++;
2189 varPtr->value.objPtr = NULL;
2190 varPtr->name = localPtr->name; /* will be just '\0' if temp var */
2191 varPtr->nsPtr = NULL;
2192 varPtr->hPtr = NULL;
2193 varPtr->refCount = 0;
2194 varPtr->tracePtr = NULL;
2195 varPtr->searchPtr = NULL;
2196 varPtr->flags = localPtr->flags;
2203 *----------------------------------------------------------------------
2205 * TclExpandCodeArray --
2207 * Procedure that uses malloc to allocate more storage for a
2208 * CompileEnv's code array.
2214 * The byte code array in *envPtr is reallocated to a new array of
2215 * double the size, and if envPtr->mallocedCodeArray is non-zero the
2216 * old array is freed. Byte codes are copied from the old array to the
2219 *----------------------------------------------------------------------
2223 TclExpandCodeArray(envArgPtr)
2224 void *envArgPtr; /* Points to the CompileEnv whose code array
2225 * must be enlarged. */
2227 CompileEnv *envPtr = (CompileEnv*) envArgPtr; /* Points to the CompileEnv whose code array
2228 * must be enlarged. */
2231 * envPtr->codeNext is equal to envPtr->codeEnd. The currently defined
2232 * code bytes are stored between envPtr->codeStart and
2233 * (envPtr->codeNext - 1) [inclusive].
2236 size_t currBytes = (envPtr->codeNext - envPtr->codeStart);
2237 size_t newBytes = 2*(envPtr->codeEnd - envPtr->codeStart);
2238 unsigned char *newPtr = (unsigned char *) ckalloc((unsigned) newBytes);
2241 * Copy from old code array to new, free old code array if needed, and
2242 * mark new code array as malloced.
2245 memcpy((VOID *) newPtr, (VOID *) envPtr->codeStart, currBytes);
2246 if (envPtr->mallocedCodeArray) {
2247 ckfree((char *) envPtr->codeStart);
2249 envPtr->codeStart = newPtr;
2250 envPtr->codeNext = (newPtr + currBytes);
2251 envPtr->codeEnd = (newPtr + newBytes);
2252 envPtr->mallocedCodeArray = 1;
2256 *----------------------------------------------------------------------
2258 * EnterCmdStartData --
2260 * Registers the starting source and bytecode location of a
2261 * command. This information is used at runtime to map between
2262 * instruction pc and source locations.
2268 * Inserts source and code location information into the compilation
2269 * environment envPtr for the command at index cmdIndex. The
2270 * compilation environment's CmdLocation array is grown if necessary.
2272 *----------------------------------------------------------------------
2276 EnterCmdStartData(envPtr, cmdIndex, srcOffset, codeOffset)
2277 CompileEnv *envPtr; /* Points to the compilation environment
2278 * structure in which to enter command
2279 * location information. */
2280 int cmdIndex; /* Index of the command whose start data
2282 int srcOffset; /* Offset of first char of the command. */
2283 int codeOffset; /* Offset of first byte of command code. */
2285 CmdLocation *cmdLocPtr;
2287 if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
2288 panic("EnterCmdStartData: bad command index %d\n", cmdIndex);
2291 if (cmdIndex >= envPtr->cmdMapEnd) {
2293 * Expand the command location array by allocating more storage from
2294 * the heap. The currently allocated CmdLocation entries are stored
2295 * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).
2298 size_t currElems = envPtr->cmdMapEnd;
2299 size_t newElems = 2*currElems;
2300 size_t currBytes = currElems * sizeof(CmdLocation);
2301 size_t newBytes = newElems * sizeof(CmdLocation);
2302 CmdLocation *newPtr = (CmdLocation *) ckalloc((unsigned) newBytes);
2305 * Copy from old command location array to new, free old command
2306 * location array if needed, and mark new array as malloced.
2309 memcpy((VOID *) newPtr, (VOID *) envPtr->cmdMapPtr, currBytes);
2310 if (envPtr->mallocedCmdMap) {
2311 ckfree((char *) envPtr->cmdMapPtr);
2313 envPtr->cmdMapPtr = (CmdLocation *) newPtr;
2314 envPtr->cmdMapEnd = newElems;
2315 envPtr->mallocedCmdMap = 1;
2319 if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {
2320 panic("EnterCmdStartData: cmd map not sorted by code offset");
2324 cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
2325 cmdLocPtr->codeOffset = codeOffset;
2326 cmdLocPtr->srcOffset = srcOffset;
2327 cmdLocPtr->numSrcBytes = -1;
2328 cmdLocPtr->numCodeBytes = -1;
2332 *----------------------------------------------------------------------
2334 * EnterCmdExtentData --
2336 * Registers the source and bytecode length for a command. This
2337 * information is used at runtime to map between instruction pc and
2344 * Inserts source and code length information into the compilation
2345 * environment envPtr for the command at index cmdIndex. Starting
2346 * source and bytecode information for the command must already
2347 * have been registered.
2349 *----------------------------------------------------------------------
2353 EnterCmdExtentData(envPtr, cmdIndex, numSrcBytes, numCodeBytes)
2354 CompileEnv *envPtr; /* Points to the compilation environment
2355 * structure in which to enter command
2356 * location information. */
2357 int cmdIndex; /* Index of the command whose source and
2358 * code length data is being set. */
2359 int numSrcBytes; /* Number of command source chars. */
2360 int numCodeBytes; /* Offset of last byte of command code. */
2362 CmdLocation *cmdLocPtr;
2364 if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
2365 panic("EnterCmdExtentData: bad command index %d\n", cmdIndex);
2368 if (cmdIndex > envPtr->cmdMapEnd) {
2369 panic("EnterCmdExtentData: missing start data for command %d\n",
2373 cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
2374 cmdLocPtr->numSrcBytes = numSrcBytes;
2375 cmdLocPtr->numCodeBytes = numCodeBytes;
2380 *----------------------------------------------------------------------
2383 * EnterCmdWordData --
2385 * Registers the lines for the words of a command. This information
2386 * is used at runtime by 'info frame'.
2392 * Inserts word location information into the compilation
2393 * environment envPtr for the command at index cmdIndex. The
2394 * compilation environment's ExtCmdLoc.ECL array is grown if necessary.
2396 *----------------------------------------------------------------------
2400 EnterCmdWordData(eclPtr, srcOffset, tokenPtr, cmd, len, numWords, line, wlines)
2401 ExtCmdLoc *eclPtr; /* Points to the map environment
2402 * structure in which to enter command
2403 * location information. */
2404 int srcOffset; /* Offset of first char of the command. */
2405 Tcl_Token* tokenPtr;
2418 if (eclPtr->nuloc >= eclPtr->nloc) {
2420 * Expand the ECL array by allocating more storage from the
2421 * heap. The currently allocated ECL entries are stored from
2422 * eclPtr->loc[0] up to eclPtr->loc[eclPtr->nuloc-1] (inclusive).
2425 size_t currElems = eclPtr->nloc;
2426 size_t newElems = (currElems ? 2*currElems : 1);
2427 size_t currBytes = currElems * sizeof(ECL);
2428 size_t newBytes = newElems * sizeof(ECL);
2429 ECL * newPtr = (ECL *) ckalloc((unsigned) newBytes);
2432 * Copy from old ECL array to new, free old ECL array if
2437 memcpy((VOID *) newPtr, (VOID *) eclPtr->loc, currBytes);
2439 if (eclPtr->loc != NULL) {
2440 ckfree((char *) eclPtr->loc);
2442 eclPtr->loc = (ECL *) newPtr;
2443 eclPtr->nloc = newElems;
2446 ePtr = &eclPtr->loc [eclPtr->nuloc];
2447 ePtr->srcOffset = srcOffset;
2448 ePtr->line = (int*) ckalloc (numWords * sizeof (int));
2449 ePtr->nline = numWords;
2450 wwlines = (int*) ckalloc (numWords * sizeof (int));
2456 wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) {
2457 TclAdvanceLines (&wordLine, last, tokenPtr->start);
2458 wwlines [wordIdx] = (TclWordKnownAtCompileTime (tokenPtr)
2461 ePtr->line [wordIdx] = wordLine;
2462 last = tokenPtr->start;
2471 *----------------------------------------------------------------------
2473 * TclCreateExceptRange --
2475 * Procedure that allocates and initializes a new ExceptionRange
2476 * structure of the specified kind in a CompileEnv.
2479 * Returns the index for the newly created ExceptionRange.
2482 * If there is not enough room in the CompileEnv's ExceptionRange
2483 * array, the array in expanded: a new array of double the size is
2484 * allocated, if envPtr->mallocedExceptArray is non-zero the old
2485 * array is freed, and ExceptionRange entries are copied from the old
2486 * array to the new one.
2488 *----------------------------------------------------------------------
2492 TclCreateExceptRange(type, envPtr)
2493 ExceptionRangeType type; /* The kind of ExceptionRange desired. */
2494 register CompileEnv *envPtr;/* Points to CompileEnv for which to
2495 * create a new ExceptionRange structure. */
2497 register ExceptionRange *rangePtr;
2498 int index = envPtr->exceptArrayNext;
2500 if (index >= envPtr->exceptArrayEnd) {
2502 * Expand the ExceptionRange array. The currently allocated entries
2503 * are stored between elements 0 and (envPtr->exceptArrayNext - 1)
2508 envPtr->exceptArrayNext * sizeof(ExceptionRange);
2509 int newElems = 2*envPtr->exceptArrayEnd;
2510 size_t newBytes = newElems * sizeof(ExceptionRange);
2511 ExceptionRange *newPtr = (ExceptionRange *)
2512 ckalloc((unsigned) newBytes);
2515 * Copy from old ExceptionRange array to new, free old
2516 * ExceptionRange array if needed, and mark the new ExceptionRange
2517 * array as malloced.
2520 memcpy((VOID *) newPtr, (VOID *) envPtr->exceptArrayPtr,
2522 if (envPtr->mallocedExceptArray) {
2523 ckfree((char *) envPtr->exceptArrayPtr);
2525 envPtr->exceptArrayPtr = (ExceptionRange *) newPtr;
2526 envPtr->exceptArrayEnd = newElems;
2527 envPtr->mallocedExceptArray = 1;
2529 envPtr->exceptArrayNext++;
2531 rangePtr = &(envPtr->exceptArrayPtr[index]);
2532 rangePtr->type = type;
2533 rangePtr->nestingLevel = envPtr->exceptDepth;
2534 rangePtr->codeOffset = -1;
2535 rangePtr->numCodeBytes = -1;
2536 rangePtr->breakOffset = -1;
2537 rangePtr->continueOffset = -1;
2538 rangePtr->catchOffset = -1;
2543 *----------------------------------------------------------------------
2545 * TclCreateAuxData --
2547 * Procedure that allocates and initializes a new AuxData structure in
2548 * a CompileEnv's array of compilation auxiliary data records. These
2549 * AuxData records hold information created during compilation by
2550 * CompileProcs and used by instructions during execution.
2553 * Returns the index for the newly created AuxData structure.
2556 * If there is not enough room in the CompileEnv's AuxData array,
2557 * the AuxData array in expanded: a new array of double the size
2558 * is allocated, if envPtr->mallocedAuxDataArray is non-zero
2559 * the old array is freed, and AuxData entries are copied from
2560 * the old array to the new one.
2562 *----------------------------------------------------------------------
2566 TclCreateAuxData(clientData, typePtr, envPtr)
2567 ClientData clientData; /* The compilation auxiliary data to store
2568 * in the new aux data record. */
2569 AuxDataType *typePtr; /* Pointer to the type to attach to this AuxData */
2570 register CompileEnv *envPtr;/* Points to the CompileEnv for which a new
2571 * aux data structure is to be allocated. */
2573 int index; /* Index for the new AuxData structure. */
2574 register AuxData *auxDataPtr;
2575 /* Points to the new AuxData structure */
2577 index = envPtr->auxDataArrayNext;
2578 if (index >= envPtr->auxDataArrayEnd) {
2580 * Expand the AuxData array. The currently allocated entries are
2581 * stored between elements 0 and (envPtr->auxDataArrayNext - 1)
2585 size_t currBytes = envPtr->auxDataArrayNext * sizeof(AuxData);
2586 int newElems = 2*envPtr->auxDataArrayEnd;
2587 size_t newBytes = newElems * sizeof(AuxData);
2588 AuxData *newPtr = (AuxData *) ckalloc((unsigned) newBytes);
2591 * Copy from old AuxData array to new, free old AuxData array if
2592 * needed, and mark the new AuxData array as malloced.
2595 memcpy((VOID *) newPtr, (VOID *) envPtr->auxDataArrayPtr,
2597 if (envPtr->mallocedAuxDataArray) {
2598 ckfree((char *) envPtr->auxDataArrayPtr);
2600 envPtr->auxDataArrayPtr = newPtr;
2601 envPtr->auxDataArrayEnd = newElems;
2602 envPtr->mallocedAuxDataArray = 1;
2604 envPtr->auxDataArrayNext++;
2606 auxDataPtr = &(envPtr->auxDataArrayPtr[index]);
2607 auxDataPtr->clientData = clientData;
2608 auxDataPtr->type = typePtr;
2613 *----------------------------------------------------------------------
2615 * TclInitJumpFixupArray --
2617 * Initializes a JumpFixupArray structure to hold some number of
2618 * jump fixup entries.
2624 * The JumpFixupArray structure is initialized.
2626 *----------------------------------------------------------------------
2630 TclInitJumpFixupArray(fixupArrayPtr)
2631 register JumpFixupArray *fixupArrayPtr;
2632 /* Points to the JumpFixupArray structure
2635 fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace;
2636 fixupArrayPtr->next = 0;
2637 fixupArrayPtr->end = (JUMPFIXUP_INIT_ENTRIES - 1);
2638 fixupArrayPtr->mallocedArray = 0;
2642 *----------------------------------------------------------------------
2644 * TclExpandJumpFixupArray --
2646 * Procedure that uses malloc to allocate more storage for a
2653 * The jump fixup array in *fixupArrayPtr is reallocated to a new array
2654 * of double the size, and if fixupArrayPtr->mallocedArray is non-zero
2655 * the old array is freed. Jump fixup structures are copied from the
2656 * old array to the new one.
2658 *----------------------------------------------------------------------
2662 TclExpandJumpFixupArray(fixupArrayPtr)
2663 register JumpFixupArray *fixupArrayPtr;
2664 /* Points to the JumpFixupArray structure
2668 * The currently allocated jump fixup entries are stored from fixup[0]
2669 * up to fixup[fixupArrayPtr->fixupNext] (*not* inclusive). We assume
2670 * fixupArrayPtr->fixupNext is equal to fixupArrayPtr->fixupEnd.
2673 size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup);
2674 int newElems = 2*(fixupArrayPtr->end + 1);
2675 size_t newBytes = newElems * sizeof(JumpFixup);
2676 JumpFixup *newPtr = (JumpFixup *) ckalloc((unsigned) newBytes);
2679 * Copy from the old array to new, free the old array if needed,
2680 * and mark the new array as malloced.
2683 memcpy((VOID *) newPtr, (VOID *) fixupArrayPtr->fixup, currBytes);
2684 if (fixupArrayPtr->mallocedArray) {
2685 ckfree((char *) fixupArrayPtr->fixup);
2687 fixupArrayPtr->fixup = (JumpFixup *) newPtr;
2688 fixupArrayPtr->end = newElems;
2689 fixupArrayPtr->mallocedArray = 1;
2693 *----------------------------------------------------------------------
2695 * TclFreeJumpFixupArray --
2697 * Free any storage allocated in a jump fixup array structure.
2703 * Allocated storage in the JumpFixupArray structure is freed.
2705 *----------------------------------------------------------------------
2709 TclFreeJumpFixupArray(fixupArrayPtr)
2710 register JumpFixupArray *fixupArrayPtr;
2711 /* Points to the JumpFixupArray structure
2714 if (fixupArrayPtr->mallocedArray) {
2715 ckfree((char *) fixupArrayPtr->fixup);
2720 *----------------------------------------------------------------------
2722 * TclEmitForwardJump --
2724 * Procedure to emit a two-byte forward jump of kind "jumpType". Since
2725 * the jump may later have to be grown to five bytes if the jump target
2726 * is more than, say, 127 bytes away, this procedure also initializes a
2727 * JumpFixup record with information about the jump.
2733 * The JumpFixup record pointed to by "jumpFixupPtr" is initialized
2734 * with information needed later if the jump is to be grown. Also,
2735 * a two byte jump of the designated type is emitted at the current
2736 * point in the bytecode stream.
2738 *----------------------------------------------------------------------
2742 TclEmitForwardJump(envPtr, jumpType, jumpFixupPtr)
2743 CompileEnv *envPtr; /* Points to the CompileEnv structure that
2744 * holds the resulting instruction. */
2745 TclJumpType jumpType; /* Indicates the kind of jump: if true or
2746 * false or unconditional. */
2747 JumpFixup *jumpFixupPtr; /* Points to the JumpFixup structure to
2748 * initialize with information about this
2752 * Initialize the JumpFixup structure:
2753 * - codeOffset is offset of first byte of jump below
2754 * - cmdIndex is index of the command after the current one
2755 * - exceptIndex is the index of the first ExceptionRange after
2759 jumpFixupPtr->jumpType = jumpType;
2760 jumpFixupPtr->codeOffset = (envPtr->codeNext - envPtr->codeStart);
2761 jumpFixupPtr->cmdIndex = envPtr->numCommands;
2762 jumpFixupPtr->exceptIndex = envPtr->exceptArrayNext;
2765 case TCL_UNCONDITIONAL_JUMP:
2766 TclEmitInstInt1(INST_JUMP1, 0, envPtr);
2769 TclEmitInstInt1(INST_JUMP_TRUE1, 0, envPtr);
2772 TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
2778 *----------------------------------------------------------------------
2780 * TclFixupForwardJump --
2782 * Procedure that updates a previously-emitted forward jump to jump
2783 * a specified number of bytes, "jumpDist". If necessary, the jump is
2784 * grown from two to five bytes; this is done if the jump distance is
2785 * greater than "distThreshold" (normally 127 bytes). The jump is
2786 * described by a JumpFixup record previously initialized by
2787 * TclEmitForwardJump.
2790 * 1 if the jump was grown and subsequent instructions had to be moved;
2791 * otherwise 0. This result is returned to allow callers to update
2792 * any additional code offsets they may hold.
2795 * The jump may be grown and subsequent instructions moved. If this
2796 * happens, the code offsets for any commands and any ExceptionRange
2797 * records between the jump and the current code address will be
2798 * updated to reflect the moved code. Also, the bytecode instruction
2799 * array in the CompileEnv structure may be grown and reallocated.
2801 *----------------------------------------------------------------------
2805 TclFixupForwardJump(envPtr, jumpFixupPtr, jumpDist, distThreshold)
2806 CompileEnv *envPtr; /* Points to the CompileEnv structure that
2807 * holds the resulting instruction. */
2808 JumpFixup *jumpFixupPtr; /* Points to the JumpFixup structure that
2809 * describes the forward jump. */
2810 int jumpDist; /* Jump distance to set in jump
2812 int distThreshold; /* Maximum distance before the two byte
2813 * jump is grown to five bytes. */
2815 unsigned char *jumpPc, *p;
2816 int firstCmd, lastCmd, firstRange, lastRange, k;
2817 unsigned int numBytes;
2819 if (jumpDist <= distThreshold) {
2820 jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
2821 switch (jumpFixupPtr->jumpType) {
2822 case TCL_UNCONDITIONAL_JUMP:
2823 TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc);
2826 TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc);
2829 TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc);
2836 * We must grow the jump then move subsequent instructions down.
2837 * Note that if we expand the space for generated instructions,
2838 * code addresses might change; be careful about updating any of
2839 * these addresses held in variables.
2842 if ((envPtr->codeNext + 3) > envPtr->codeEnd) {
2843 TclExpandCodeArray(envPtr);
2845 jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
2846 for (numBytes = envPtr->codeNext-jumpPc-2, p = jumpPc+2+numBytes-1;
2847 numBytes > 0; numBytes--, p--) {
2850 envPtr->codeNext += 3;
2852 switch (jumpFixupPtr->jumpType) {
2853 case TCL_UNCONDITIONAL_JUMP:
2854 TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);
2857 TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);
2860 TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);
2865 * Adjust the code offsets for any commands and any ExceptionRange
2866 * records between the jump and the current code address.
2869 firstCmd = jumpFixupPtr->cmdIndex;
2870 lastCmd = (envPtr->numCommands - 1);
2871 if (firstCmd < lastCmd) {
2872 for (k = firstCmd; k <= lastCmd; k++) {
2873 (envPtr->cmdMapPtr[k]).codeOffset += 3;
2877 firstRange = jumpFixupPtr->exceptIndex;
2878 lastRange = (envPtr->exceptArrayNext - 1);
2879 for (k = firstRange; k <= lastRange; k++) {
2880 ExceptionRange *rangePtr = &(envPtr->exceptArrayPtr[k]);
2881 rangePtr->codeOffset += 3;
2883 switch (rangePtr->type) {
2884 case LOOP_EXCEPTION_RANGE:
2885 rangePtr->breakOffset += 3;
2886 if (rangePtr->continueOffset != -1) {
2887 rangePtr->continueOffset += 3;
2890 case CATCH_EXCEPTION_RANGE:
2891 rangePtr->catchOffset += 3;
2894 panic("TclFixupForwardJump: bad ExceptionRange type %d\n",
2898 return 1; /* the jump was grown */
2902 *----------------------------------------------------------------------
2904 * TclGetInstructionTable --
2906 * Returns a pointer to the table describing Tcl bytecode instructions.
2907 * This procedure is defined so that clients can access the pointer from
2908 * outside the TCL DLLs.
2911 * Returns a pointer to the global instruction table, same as the
2912 * expression (&tclInstructionTable[0]).
2917 *----------------------------------------------------------------------
2920 void * /* == InstructionDesc* == */
2921 TclGetInstructionTable()
2923 return &tclInstructionTable[0];
2927 *--------------------------------------------------------------
2929 * TclRegisterAuxDataType --
2931 * This procedure is called to register a new AuxData type
2932 * in the table of all AuxData types supported by Tcl.
2938 * The type is registered in the AuxData type table. If there was already
2939 * a type with the same name as in typePtr, it is replaced with the
2942 *--------------------------------------------------------------
2946 TclRegisterAuxDataType(typePtr)
2947 AuxDataType *typePtr; /* Information about object type;
2948 * storage must be statically
2949 * allocated (must live forever). */
2951 register Tcl_HashEntry *hPtr;
2954 Tcl_MutexLock(&tableMutex);
2955 if (!auxDataTypeTableInitialized) {
2956 TclInitAuxDataTypeTable();
2960 * If there's already a type with the given name, remove it.
2963 hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typePtr->name);
2964 if (hPtr != (Tcl_HashEntry *) NULL) {
2965 Tcl_DeleteHashEntry(hPtr);
2969 * Now insert the new object type.
2972 hPtr = Tcl_CreateHashEntry(&auxDataTypeTable, typePtr->name, &new);
2974 Tcl_SetHashValue(hPtr, typePtr);
2976 Tcl_MutexUnlock(&tableMutex);
2980 *----------------------------------------------------------------------
2982 * TclGetAuxDataType --
2984 * This procedure looks up an Auxdata type by name.
2987 * If an AuxData type with name matching "typeName" is found, a pointer
2988 * to its AuxDataType structure is returned; otherwise, NULL is returned.
2993 *----------------------------------------------------------------------
2997 TclGetAuxDataType(typeName)
2998 char *typeName; /* Name of AuxData type to look up. */
3000 register Tcl_HashEntry *hPtr;
3001 AuxDataType *typePtr = NULL;
3003 Tcl_MutexLock(&tableMutex);
3004 if (!auxDataTypeTableInitialized) {
3005 TclInitAuxDataTypeTable();
3008 hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typeName);
3009 if (hPtr != (Tcl_HashEntry *) NULL) {
3010 typePtr = (AuxDataType *) Tcl_GetHashValue(hPtr);
3012 Tcl_MutexUnlock(&tableMutex);
3018 *--------------------------------------------------------------
3020 * TclInitAuxDataTypeTable --
3022 * This procedure is invoked to perform once-only initialization of
3023 * the AuxData type table. It also registers the AuxData types defined in
3030 * Initializes the table of defined AuxData types "auxDataTypeTable" with
3031 * builtin AuxData types defined in this file.
3033 *--------------------------------------------------------------
3037 TclInitAuxDataTypeTable()
3040 * The table mutex must already be held before this routine is invoked.
3043 auxDataTypeTableInitialized = 1;
3044 Tcl_InitHashTable(&auxDataTypeTable, TCL_STRING_KEYS);
3047 * There is only one AuxData type at this time, so register it here.
3050 TclRegisterAuxDataType(&tclForeachInfoType);
3054 *----------------------------------------------------------------------
3056 * TclFinalizeAuxDataTypeTable --
3058 * This procedure is called by Tcl_Finalize after all exit handlers
3059 * have been run to free up storage associated with the table of AuxData
3060 * types. This procedure is called by TclFinalizeExecution() which
3061 * is called by Tcl_Finalize().
3067 * Deletes all entries in the hash table of AuxData types.
3069 *----------------------------------------------------------------------
3073 TclFinalizeAuxDataTypeTable()
3075 Tcl_MutexLock(&tableMutex);
3076 if (auxDataTypeTableInitialized) {
3077 Tcl_DeleteHashTable(&auxDataTypeTable);
3078 auxDataTypeTableInitialized = 0;
3080 Tcl_MutexUnlock(&tableMutex);
3084 *----------------------------------------------------------------------
3086 * GetCmdLocEncodingSize --
3088 * Computes the total number of bytes needed to encode the command
3089 * location information for some compiled code.
3092 * The byte count needed to encode the compiled location information.
3097 *----------------------------------------------------------------------
3101 GetCmdLocEncodingSize(envPtr)
3102 CompileEnv *envPtr; /* Points to compilation environment
3103 * structure containing the CmdLocation
3104 * structure to encode. */
3106 register CmdLocation *mapPtr = envPtr->cmdMapPtr;
3107 int numCmds = envPtr->numCommands;
3108 int codeDelta, codeLen, srcDelta, srcLen;
3109 int codeDeltaNext, codeLengthNext, srcDeltaNext, srcLengthNext;
3110 /* The offsets in their respective byte
3111 * sequences where the next encoded offset
3112 * or length should go. */
3113 int prevCodeOffset, prevSrcOffset, i;
3115 codeDeltaNext = codeLengthNext = srcDeltaNext = srcLengthNext = 0;
3116 prevCodeOffset = prevSrcOffset = 0;
3117 for (i = 0; i < numCmds; i++) {
3118 codeDelta = (mapPtr[i].codeOffset - prevCodeOffset);
3119 if (codeDelta < 0) {
3120 panic("GetCmdLocEncodingSize: bad code offset");
3121 } else if (codeDelta <= 127) {
3124 codeDeltaNext += 5; /* 1 byte for 0xFF, 4 for positive delta */
3126 prevCodeOffset = mapPtr[i].codeOffset;
3128 codeLen = mapPtr[i].numCodeBytes;
3130 panic("GetCmdLocEncodingSize: bad code length");
3131 } else if (codeLen <= 127) {
3134 codeLengthNext += 5; /* 1 byte for 0xFF, 4 for length */
3137 srcDelta = (mapPtr[i].srcOffset - prevSrcOffset);
3138 if ((-127 <= srcDelta) && (srcDelta <= 127)) {
3141 srcDeltaNext += 5; /* 1 byte for 0xFF, 4 for delta */
3143 prevSrcOffset = mapPtr[i].srcOffset;
3145 srcLen = mapPtr[i].numSrcBytes;
3147 panic("GetCmdLocEncodingSize: bad source length");
3148 } else if (srcLen <= 127) {
3151 srcLengthNext += 5; /* 1 byte for 0xFF, 4 for length */
3155 return (codeDeltaNext + codeLengthNext + srcDeltaNext + srcLengthNext);
3159 *----------------------------------------------------------------------
3161 * EncodeCmdLocMap --
3163 * Encode the command location information for some compiled code into
3164 * a ByteCode structure. The encoded command location map is stored as
3165 * three adjacent byte sequences.
3168 * Pointer to the first byte after the encoded command location
3172 * The encoded information is stored into the block of memory headed
3173 * by codePtr. Also records pointers to the start of the four byte
3174 * sequences in fields in codePtr's ByteCode header structure.
3176 *----------------------------------------------------------------------
3179 static unsigned char *
3180 EncodeCmdLocMap(envPtr, codePtr, startPtr)
3181 CompileEnv *envPtr; /* Points to compilation environment
3182 * structure containing the CmdLocation
3183 * structure to encode. */
3184 ByteCode *codePtr; /* ByteCode in which to encode envPtr's
3185 * command location information. */
3186 unsigned char *startPtr; /* Points to the first byte in codePtr's
3187 * memory block where the location
3188 * information is to be stored. */
3190 register CmdLocation *mapPtr = envPtr->cmdMapPtr;
3191 int numCmds = envPtr->numCommands;
3192 register unsigned char *p = startPtr;
3193 int codeDelta, codeLen, srcDelta, srcLen, prevOffset;
3197 * Encode the code offset for each command as a sequence of deltas.
3200 codePtr->codeDeltaStart = p;
3202 for (i = 0; i < numCmds; i++) {
3203 codeDelta = (mapPtr[i].codeOffset - prevOffset);
3204 if (codeDelta < 0) {
3205 panic("EncodeCmdLocMap: bad code offset");
3206 } else if (codeDelta <= 127) {
3207 TclStoreInt1AtPtr(codeDelta, p);
3210 TclStoreInt1AtPtr(0xFF, p);
3212 TclStoreInt4AtPtr(codeDelta, p);
3215 prevOffset = mapPtr[i].codeOffset;
3219 * Encode the code length for each command.
3222 codePtr->codeLengthStart = p;
3223 for (i = 0; i < numCmds; i++) {
3224 codeLen = mapPtr[i].numCodeBytes;
3226 panic("EncodeCmdLocMap: bad code length");
3227 } else if (codeLen <= 127) {
3228 TclStoreInt1AtPtr(codeLen, p);
3231 TclStoreInt1AtPtr(0xFF, p);
3233 TclStoreInt4AtPtr(codeLen, p);
3239 * Encode the source offset for each command as a sequence of deltas.
3242 codePtr->srcDeltaStart = p;
3244 for (i = 0; i < numCmds; i++) {
3245 srcDelta = (mapPtr[i].srcOffset - prevOffset);
3246 if ((-127 <= srcDelta) && (srcDelta <= 127)) {
3247 TclStoreInt1AtPtr(srcDelta, p);
3250 TclStoreInt1AtPtr(0xFF, p);
3252 TclStoreInt4AtPtr(srcDelta, p);
3255 prevOffset = mapPtr[i].srcOffset;
3259 * Encode the source length for each command.
3262 codePtr->srcLengthStart = p;
3263 for (i = 0; i < numCmds; i++) {
3264 srcLen = mapPtr[i].numSrcBytes;
3266 panic("EncodeCmdLocMap: bad source length");
3267 } else if (srcLen <= 127) {
3268 TclStoreInt1AtPtr(srcLen, p);
3271 TclStoreInt1AtPtr(0xFF, p);
3273 TclStoreInt4AtPtr(srcLen, p);
3281 #ifdef TCL_COMPILE_DEBUG
3283 *----------------------------------------------------------------------
3285 * TclPrintByteCodeObj --
3287 * This procedure prints ("disassembles") the instructions of a
3288 * bytecode object to stdout.
3296 *----------------------------------------------------------------------
3300 TclPrintByteCodeObj(interp, objPtr)
3301 Tcl_Interp *interp; /* Used only for Tcl_GetStringFromObj. */
3302 Tcl_Obj *objPtr; /* The bytecode object to disassemble. */
3304 ByteCode* codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
3305 unsigned char *codeStart, *codeLimit, *pc;
3306 unsigned char *codeDeltaNext, *codeLengthNext;
3307 unsigned char *srcDeltaNext, *srcLengthNext;
3308 int codeOffset, codeLen, srcOffset, srcLen, numCmds, delta, i;
3309 Interp *iPtr = (Interp *) *codePtr->interpHandle;
3311 if (codePtr->refCount <= 0) {
3312 return; /* already freed */
3315 codeStart = codePtr->codeStart;
3316 codeLimit = (codeStart + codePtr->numCodeBytes);
3317 numCmds = codePtr->numCommands;
3320 * Print header lines describing the ByteCode.
3323 fprintf(stdout, "\nByteCode 0x%x, refCt %u, epoch %u, interp 0x%x (epoch %u)\n",
3324 (unsigned int) codePtr, codePtr->refCount,
3325 codePtr->compileEpoch, (unsigned int) iPtr,
3326 iPtr->compileEpoch);
3327 fprintf(stdout, " Source ");
3328 TclPrintSource(stdout, codePtr->source,
3329 TclMin(codePtr->numSrcBytes, 55));
3330 fprintf(stdout, "\n Cmds %d, src %d, inst %d, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n",
3331 numCmds, codePtr->numSrcBytes, codePtr->numCodeBytes,
3332 codePtr->numLitObjects, codePtr->numAuxDataItems,
3333 codePtr->maxStackDepth,
3334 #ifdef TCL_COMPILE_STATS
3335 (codePtr->numSrcBytes?
3336 ((float)codePtr->structureSize)/((float)codePtr->numSrcBytes) : 0.0));
3340 #ifdef TCL_COMPILE_STATS
3342 " Code %d = header %d+inst %d+litObj %d+exc %d+aux %d+cmdMap %d\n",
3343 codePtr->structureSize,
3344 (sizeof(ByteCode) - (sizeof(size_t) + sizeof(Tcl_Time))),
3345 codePtr->numCodeBytes,
3346 (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
3347 (codePtr->numExceptRanges * sizeof(ExceptionRange)),
3348 (codePtr->numAuxDataItems * sizeof(AuxData)),
3349 codePtr->numCmdLocBytes);
3350 #endif /* TCL_COMPILE_STATS */
3353 * If the ByteCode is the compiled body of a Tcl procedure, print
3354 * information about that procedure. Note that we don't know the
3355 * procedure's name since ByteCode's can be shared among procedures.
3358 if (codePtr->procPtr != NULL) {
3359 Proc *procPtr = codePtr->procPtr;
3360 int numCompiledLocals = procPtr->numCompiledLocals;
3362 " Proc 0x%x, refCt %d, args %d, compiled locals %d\n",
3363 (unsigned int) procPtr, procPtr->refCount, procPtr->numArgs,
3365 if (numCompiledLocals > 0) {
3366 CompiledLocal *localPtr = procPtr->firstLocalPtr;
3367 for (i = 0; i < numCompiledLocals; i++) {
3368 fprintf(stdout, " slot %d%s%s%s%s%s%s", i,
3369 ((localPtr->flags & VAR_SCALAR)? ", scalar" : ""),
3370 ((localPtr->flags & VAR_ARRAY)? ", array" : ""),
3371 ((localPtr->flags & VAR_LINK)? ", link" : ""),
3372 ((localPtr->flags & VAR_ARGUMENT)? ", arg" : ""),
3373 ((localPtr->flags & VAR_TEMPORARY)? ", temp" : ""),
3374 ((localPtr->flags & VAR_RESOLVED)? ", resolved" : ""));
3375 if (TclIsVarTemporary(localPtr)) {
3376 fprintf(stdout, "\n");
3378 fprintf(stdout, ", \"%s\"\n", localPtr->name);
3380 localPtr = localPtr->nextPtr;
3386 * Print the ExceptionRange array.
3389 if (codePtr->numExceptRanges > 0) {
3390 fprintf(stdout, " Exception ranges %d, depth %d:\n",
3391 codePtr->numExceptRanges, codePtr->maxExceptDepth);
3392 for (i = 0; i < codePtr->numExceptRanges; i++) {
3393 ExceptionRange *rangePtr = &(codePtr->exceptArrayPtr[i]);
3394 fprintf(stdout, " %d: level %d, %s, pc %d-%d, ",
3395 i, rangePtr->nestingLevel,
3396 ((rangePtr->type == LOOP_EXCEPTION_RANGE)
3397 ? "loop" : "catch"),
3398 rangePtr->codeOffset,
3399 (rangePtr->codeOffset + rangePtr->numCodeBytes - 1));
3400 switch (rangePtr->type) {
3401 case LOOP_EXCEPTION_RANGE:
3402 fprintf(stdout, "continue %d, break %d\n",
3403 rangePtr->continueOffset, rangePtr->breakOffset);
3405 case CATCH_EXCEPTION_RANGE:
3406 fprintf(stdout, "catch %d\n", rangePtr->catchOffset);
3409 panic("TclPrintByteCodeObj: bad ExceptionRange type %d\n",
3416 * If there were no commands (e.g., an expression or an empty string
3417 * was compiled), just print all instructions and return.
3422 while (pc < codeLimit) {
3423 fprintf(stdout, " ");
3424 pc += TclPrintInstruction(codePtr, pc);
3430 * Print table showing the code offset, source offset, and source
3431 * length for each command. These are encoded as a sequence of bytes.
3434 fprintf(stdout, " Commands %d:", numCmds);
3435 codeDeltaNext = codePtr->codeDeltaStart;
3436 codeLengthNext = codePtr->codeLengthStart;
3437 srcDeltaNext = codePtr->srcDeltaStart;
3438 srcLengthNext = codePtr->srcLengthStart;
3439 codeOffset = srcOffset = 0;
3440 for (i = 0; i < numCmds; i++) {
3441 if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
3443 delta = TclGetInt4AtPtr(codeDeltaNext);
3446 delta = TclGetInt1AtPtr(codeDeltaNext);
3449 codeOffset += delta;
3451 if ((unsigned int) (*codeLengthNext) == (unsigned int) 0xFF) {
3453 codeLen = TclGetInt4AtPtr(codeLengthNext);
3454 codeLengthNext += 4;
3456 codeLen = TclGetInt1AtPtr(codeLengthNext);
3460 if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
3462 delta = TclGetInt4AtPtr(srcDeltaNext);
3465 delta = TclGetInt1AtPtr(srcDeltaNext);
3470 if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
3472 srcLen = TclGetInt4AtPtr(srcLengthNext);
3475 srcLen = TclGetInt1AtPtr(srcLengthNext);
3479 fprintf(stdout, "%s%4d: pc %d-%d, src %d-%d",
3480 ((i % 2)? " " : "\n "),
3481 (i+1), codeOffset, (codeOffset + codeLen - 1),
3482 srcOffset, (srcOffset + srcLen - 1));
3485 fprintf(stdout, "\n");
3489 * Print each instruction. If the instruction corresponds to the start
3490 * of a command, print the command's source. Note that we don't need
3491 * the code length here.
3494 codeDeltaNext = codePtr->codeDeltaStart;
3495 srcDeltaNext = codePtr->srcDeltaStart;
3496 srcLengthNext = codePtr->srcLengthStart;
3497 codeOffset = srcOffset = 0;
3499 for (i = 0; i < numCmds; i++) {
3500 if ((unsigned int) (*codeDeltaNext) == (unsigned int) 0xFF) {
3502 delta = TclGetInt4AtPtr(codeDeltaNext);
3505 delta = TclGetInt1AtPtr(codeDeltaNext);
3508 codeOffset += delta;
3510 if ((unsigned int) (*srcDeltaNext) == (unsigned int) 0xFF) {
3512 delta = TclGetInt4AtPtr(srcDeltaNext);
3515 delta = TclGetInt1AtPtr(srcDeltaNext);
3520 if ((unsigned int) (*srcLengthNext) == (unsigned int) 0xFF) {
3522 srcLen = TclGetInt4AtPtr(srcLengthNext);
3525 srcLen = TclGetInt1AtPtr(srcLengthNext);
3530 * Print instructions before command i.
3533 while ((pc-codeStart) < codeOffset) {
3534 fprintf(stdout, " ");
3535 pc += TclPrintInstruction(codePtr, pc);
3538 fprintf(stdout, " Command %d: ", (i+1));
3539 TclPrintSource(stdout, (codePtr->source + srcOffset),
3540 TclMin(srcLen, 55));
3541 fprintf(stdout, "\n");
3543 if (pc < codeLimit) {
3545 * Print instructions after the last command.
3548 while (pc < codeLimit) {
3549 fprintf(stdout, " ");
3550 pc += TclPrintInstruction(codePtr, pc);
3554 #endif /* TCL_COMPILE_DEBUG */
3557 *----------------------------------------------------------------------
3559 * TclPrintInstruction --
3561 * This procedure prints ("disassembles") one instruction from a
3562 * bytecode object to stdout.
3565 * Returns the length in bytes of the current instruiction.
3570 *----------------------------------------------------------------------
3574 TclPrintInstruction(codePtr, pc)
3575 ByteCode* codePtr; /* Bytecode containing the instruction. */
3576 unsigned char *pc; /* Points to first byte of instruction. */
3578 Proc *procPtr = codePtr->procPtr;
3579 unsigned char opCode = *pc;
3580 register InstructionDesc *instDesc = &tclInstructionTable[opCode];
3581 unsigned char *codeStart = codePtr->codeStart;
3582 unsigned int pcOffset = (pc - codeStart);
3585 fprintf(stdout, "(%u) %s ", pcOffset, instDesc->name);
3586 for (i = 0; i < instDesc->numOperands; i++) {
3587 switch (instDesc->opTypes[i]) {
3589 opnd = TclGetInt1AtPtr(pc+1+i);
3590 if ((i == 0) && ((opCode == INST_JUMP1)
3591 || (opCode == INST_JUMP_TRUE1)
3592 || (opCode == INST_JUMP_FALSE1))) {
3593 fprintf(stdout, "%d # pc %u", opnd, (pcOffset + opnd));
3595 fprintf(stdout, "%d", opnd);
3599 opnd = TclGetInt4AtPtr(pc+1+i);
3600 if ((i == 0) && ((opCode == INST_JUMP4)
3601 || (opCode == INST_JUMP_TRUE4)
3602 || (opCode == INST_JUMP_FALSE4))) {
3603 fprintf(stdout, "%d # pc %u", opnd, (pcOffset + opnd));
3605 fprintf(stdout, "%d", opnd);
3609 opnd = TclGetUInt1AtPtr(pc+1+i);
3610 if ((i == 0) && (opCode == INST_PUSH1)) {
3611 fprintf(stdout, "%u # ", (unsigned int) opnd);
3612 TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40);
3613 } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR1)
3614 || (opCode == INST_LOAD_ARRAY1)
3615 || (opCode == INST_STORE_SCALAR1)
3616 || (opCode == INST_STORE_ARRAY1))) {
3617 int localCt = procPtr->numCompiledLocals;
3618 CompiledLocal *localPtr = procPtr->firstLocalPtr;
3619 if (opnd >= localCt) {
3620 panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
3621 (unsigned int) opnd, localCt);
3622 return instDesc->numBytes;
3624 for (j = 0; j < opnd; j++) {
3625 localPtr = localPtr->nextPtr;
3627 if (TclIsVarTemporary(localPtr)) {
3628 fprintf(stdout, "%u # temp var %u",
3629 (unsigned int) opnd, (unsigned int) opnd);
3631 fprintf(stdout, "%u # var ", (unsigned int) opnd);
3632 TclPrintSource(stdout, localPtr->name, 40);
3635 fprintf(stdout, "%u ", (unsigned int) opnd);
3639 opnd = TclGetUInt4AtPtr(pc+1+i);
3640 if (opCode == INST_PUSH4) {
3641 fprintf(stdout, "%u # ", opnd);
3642 TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40);
3643 } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR4)
3644 || (opCode == INST_LOAD_ARRAY4)
3645 || (opCode == INST_STORE_SCALAR4)
3646 || (opCode == INST_STORE_ARRAY4))) {
3647 int localCt = procPtr->numCompiledLocals;
3648 CompiledLocal *localPtr = procPtr->firstLocalPtr;
3649 if (opnd >= localCt) {
3650 panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
3651 (unsigned int) opnd, localCt);
3652 return instDesc->numBytes;
3654 for (j = 0; j < opnd; j++) {
3655 localPtr = localPtr->nextPtr;
3657 if (TclIsVarTemporary(localPtr)) {
3658 fprintf(stdout, "%u # temp var %u",
3659 (unsigned int) opnd, (unsigned int) opnd);
3661 fprintf(stdout, "%u # var ", (unsigned int) opnd);
3662 TclPrintSource(stdout, localPtr->name, 40);
3665 fprintf(stdout, "%u ", (unsigned int) opnd);
3673 fprintf(stdout, "\n");
3674 return instDesc->numBytes;
3678 *----------------------------------------------------------------------
3682 * This procedure prints up to a specified number of characters from
3683 * the argument Tcl object's string representation to a specified file.
3689 * Outputs characters to the specified file.
3691 *----------------------------------------------------------------------
3695 TclPrintObject(outFile, objPtr, maxChars)
3696 FILE *outFile; /* The file to print the source to. */
3697 Tcl_Obj *objPtr; /* Points to the Tcl object whose string
3698 * representation should be printed. */
3699 int maxChars; /* Maximum number of chars to print. */
3704 bytes = Tcl_GetStringFromObj(objPtr, &length);
3705 TclPrintSource(outFile, bytes, TclMin(length, maxChars));
3709 *----------------------------------------------------------------------
3713 * This procedure prints up to a specified number of characters from
3714 * the argument string to a specified file. It tries to produce legible
3715 * output by adding backslashes as necessary.
3721 * Outputs characters to the specified file.
3723 *----------------------------------------------------------------------
3727 TclPrintSource(outFile, string, maxChars)
3728 FILE *outFile; /* The file to print the source to. */
3729 CONST char *string; /* The string to print. */
3730 int maxChars; /* Maximum number of chars to print. */
3732 register CONST char *p;
3735 if (string == NULL) {
3736 fprintf(outFile, "\"\"");
3740 fprintf(outFile, "\"");
3742 for (; (*p != '\0') && (i < maxChars); p++, i++) {
3745 fprintf(outFile, "\\\"");
3748 fprintf(outFile, "\\f");
3751 fprintf(outFile, "\\n");
3754 fprintf(outFile, "\\r");
3757 fprintf(outFile, "\\t");
3760 fprintf(outFile, "\\v");
3763 fprintf(outFile, "%c", *p);
3767 fprintf(outFile, "\"");
3770 #ifdef TCL_COMPILE_STATS
3772 *----------------------------------------------------------------------
3774 * RecordByteCodeStats --
3776 * Accumulates various compilation-related statistics for each newly
3777 * compiled ByteCode. Called by the TclInitByteCodeObj when Tcl is
3778 * compiled with the -DTCL_COMPILE_STATS flag
3784 * Accumulates aggregate code-related statistics in the interpreter's
3785 * ByteCodeStats structure. Records statistics specific to a ByteCode
3786 * in its ByteCode structure.
3788 *----------------------------------------------------------------------
3792 RecordByteCodeStats(codePtr)
3793 ByteCode *codePtr; /* Points to ByteCode structure with info
3794 * to add to accumulated statistics. */
3796 Interp *iPtr = (Interp *) *codePtr->interpHandle;
3797 register ByteCodeStats *statsPtr = &(iPtr->stats);
3799 statsPtr->numCompilations++;
3800 statsPtr->totalSrcBytes += (double) codePtr->numSrcBytes;
3801 statsPtr->totalByteCodeBytes += (double) codePtr->structureSize;
3802 statsPtr->currentSrcBytes += (double) codePtr->numSrcBytes;
3803 statsPtr->currentByteCodeBytes += (double) codePtr->structureSize;
3805 statsPtr->srcCount[TclLog2(codePtr->numSrcBytes)]++;
3806 statsPtr->byteCodeCount[TclLog2((int)(codePtr->structureSize))]++;
3808 statsPtr->currentInstBytes += (double) codePtr->numCodeBytes;
3809 statsPtr->currentLitBytes +=
3810 (double) (codePtr->numLitObjects * sizeof(Tcl_Obj *));
3811 statsPtr->currentExceptBytes +=
3812 (double) (codePtr->numExceptRanges * sizeof(ExceptionRange));
3813 statsPtr->currentAuxBytes +=
3814 (double) (codePtr->numAuxDataItems * sizeof(AuxData));
3815 statsPtr->currentCmdMapBytes += (double) codePtr->numCmdLocBytes;
3817 #endif /* TCL_COMPILE_STATS */