tclCompile.c

Go to the documentation of this file.
00001 /*
00002  * tclCompile.c --
00003  *
00004  *      This file contains procedures that compile Tcl commands or parts of
00005  *      commands (like quoted strings or nested sub-commands) into a sequence
00006  *      of instructions ("bytecodes").
00007  *
00008  * Copyright (c) 1996-1998 Sun Microsystems, Inc.
00009  * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
00010  *
00011  * See the file "license.terms" for information on usage and redistribution of
00012  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00013  *
00014  * RCS: @(#) $Id: tclCompile.c,v 1.146 2008/01/23 21:21:30 dgp Exp $
00015  */
00016 
00017 #include "tclInt.h"
00018 #include "tclCompile.h"
00019 
00020 /*
00021  * Table of all AuxData types.
00022  */
00023 
00024 static Tcl_HashTable auxDataTypeTable;
00025 static int auxDataTypeTableInitialized; /* 0 means not yet initialized. */
00026 
00027 TCL_DECLARE_MUTEX(tableMutex)
00028 
00029 /*
00030  * Variable that controls whether compilation tracing is enabled and, if so,
00031  * what level of tracing is desired:
00032  *    0: no compilation tracing
00033  *    1: summarize compilation of top level cmds and proc bodies
00034  *    2: display all instructions of each ByteCode compiled
00035  * This variable is linked to the Tcl variable "tcl_traceCompile".
00036  */
00037 
00038 #ifdef TCL_COMPILE_DEBUG
00039 int tclTraceCompile = 0;
00040 static int traceInitialized = 0;
00041 #endif
00042 
00043 /*
00044  * A table describing the Tcl bytecode instructions. Entries in this table
00045  * must correspond to the instruction opcode definitions in tclCompile.h. The
00046  * names "op1" and "op4" refer to an instruction's one or four byte first
00047  * operand. Similarly, "stktop" and "stknext" refer to the topmost and next to
00048  * topmost stack elements.
00049  *
00050  * Note that the load, store, and incr instructions do not distinguish local
00051  * from global variables; the bytecode interpreter at runtime uses the
00052  * existence of a procedure call frame to distinguish these.
00053  */
00054 
00055 InstructionDesc tclInstructionTable[] = {
00056     /* Name           Bytes stackEffect #Opnds  Operand types */
00057     {"done",              1,   -1,         0,   {OPERAND_NONE}},
00058         /* Finish ByteCode execution and return stktop (top stack item) */
00059     {"push1",             2,   +1,         1,   {OPERAND_UINT1}},
00060         /* Push object at ByteCode objArray[op1] */
00061     {"push4",             5,   +1,         1,   {OPERAND_UINT4}},
00062         /* Push object at ByteCode objArray[op4] */
00063     {"pop",               1,   -1,         0,   {OPERAND_NONE}},
00064         /* Pop the topmost stack object */
00065     {"dup",               1,   +1,         0,   {OPERAND_NONE}},
00066         /* Duplicate the topmost stack object and push the result */
00067     {"concat1",           2,   INT_MIN,    1,   {OPERAND_UINT1}},
00068         /* Concatenate the top op1 items and push result */
00069     {"invokeStk1",        2,   INT_MIN,    1,   {OPERAND_UINT1}},
00070         /* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
00071     {"invokeStk4",        5,   INT_MIN,    1,   {OPERAND_UINT4}},
00072         /* Invoke command named objv[0]; <objc,objv> = <op4,top op4> */
00073     {"evalStk",           1,   0,          0,   {OPERAND_NONE}},
00074         /* Evaluate command in stktop using Tcl_EvalObj. */
00075     {"exprStk",           1,   0,          0,   {OPERAND_NONE}},
00076         /* Execute expression in stktop using Tcl_ExprStringObj. */
00077 
00078     {"loadScalar1",       2,   1,          1,   {OPERAND_LVT1}},
00079         /* Load scalar variable at index op1 <= 255 in call frame */
00080     {"loadScalar4",       5,   1,          1,   {OPERAND_LVT4}},
00081         /* Load scalar variable at index op1 >= 256 in call frame */
00082     {"loadScalarStk",     1,   0,          0,   {OPERAND_NONE}},
00083         /* Load scalar variable; scalar's name is stktop */
00084     {"loadArray1",        2,   0,          1,   {OPERAND_LVT1}},
00085         /* Load array element; array at slot op1<=255, element is stktop */
00086     {"loadArray4",        5,   0,          1,   {OPERAND_LVT4}},
00087         /* Load array element; array at slot op1 > 255, element is stktop */
00088     {"loadArrayStk",      1,   -1,         0,   {OPERAND_NONE}},
00089         /* Load array element; element is stktop, array name is stknext */
00090     {"loadStk",           1,   0,          0,   {OPERAND_NONE}},
00091         /* Load general variable; unparsed variable name is stktop */
00092     {"storeScalar1",      2,   0,          1,   {OPERAND_LVT1}},
00093         /* Store scalar variable at op1<=255 in frame; value is stktop */
00094     {"storeScalar4",      5,   0,          1,   {OPERAND_LVT4}},
00095         /* Store scalar variable at op1 > 255 in frame; value is stktop */
00096     {"storeScalarStk",    1,   -1,         0,   {OPERAND_NONE}},
00097         /* Store scalar; value is stktop, scalar name is stknext */
00098     {"storeArray1",       2,   -1,         1,   {OPERAND_LVT1}},
00099         /* Store array element; array at op1<=255, value is top then elem */
00100     {"storeArray4",       5,   -1,         1,   {OPERAND_LVT4}},
00101         /* Store array element; array at op1>=256, value is top then elem */
00102     {"storeArrayStk",     1,   -2,         0,   {OPERAND_NONE}},
00103         /* Store array element; value is stktop, then elem, array names */
00104     {"storeStk",          1,   -1,         0,   {OPERAND_NONE}},
00105         /* Store general variable; value is stktop, then unparsed name */
00106 
00107     {"incrScalar1",       2,   0,          1,   {OPERAND_LVT1}},
00108         /* Incr scalar at index op1<=255 in frame; incr amount is stktop */
00109     {"incrScalarStk",     1,   -1,         0,   {OPERAND_NONE}},
00110         /* Incr scalar; incr amount is stktop, scalar's name is stknext */
00111     {"incrArray1",        2,   -1,         1,   {OPERAND_LVT1}},
00112         /* Incr array elem; arr at slot op1<=255, amount is top then elem */
00113     {"incrArrayStk",      1,   -2,         0,   {OPERAND_NONE}},
00114         /* Incr array element; amount is top then elem then array names */
00115     {"incrStk",           1,   -1,         0,   {OPERAND_NONE}},
00116         /* Incr general variable; amount is stktop then unparsed var name */
00117     {"incrScalar1Imm",    3,   +1,         2,   {OPERAND_LVT1, OPERAND_INT1}},
00118         /* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
00119     {"incrScalarStkImm",  2,   0,          1,   {OPERAND_INT1}},
00120         /* Incr scalar; scalar name is stktop; incr amount is op1 */
00121     {"incrArray1Imm",     3,   0,          2,   {OPERAND_LVT1, OPERAND_INT1}},
00122         /* Incr array elem; array at slot op1 <= 255, elem is stktop,
00123          * amount is 2nd operand byte */
00124     {"incrArrayStkImm",   2,   -1,         1,   {OPERAND_INT1}},
00125         /* Incr array element; elem is top then array name, amount is op1 */
00126     {"incrStkImm",        2,   0,          1,   {OPERAND_INT1}},
00127         /* Incr general variable; unparsed name is top, amount is op1 */
00128 
00129     {"jump1",             2,   0,          1,   {OPERAND_INT1}},
00130         /* Jump relative to (pc + op1) */
00131     {"jump4",             5,   0,          1,   {OPERAND_INT4}},
00132         /* Jump relative to (pc + op4) */
00133     {"jumpTrue1",         2,   -1,         1,   {OPERAND_INT1}},
00134         /* Jump relative to (pc + op1) if stktop expr object is true */
00135     {"jumpTrue4",         5,   -1,         1,   {OPERAND_INT4}},
00136         /* Jump relative to (pc + op4) if stktop expr object is true */
00137     {"jumpFalse1",        2,   -1,         1,   {OPERAND_INT1}},
00138         /* Jump relative to (pc + op1) if stktop expr object is false */
00139     {"jumpFalse4",        5,   -1,         1,   {OPERAND_INT4}},
00140         /* Jump relative to (pc + op4) if stktop expr object is false */
00141 
00142     {"lor",               1,   -1,         0,   {OPERAND_NONE}},
00143         /* Logical or:  push (stknext || stktop) */
00144     {"land",              1,   -1,         0,   {OPERAND_NONE}},
00145         /* Logical and: push (stknext && stktop) */
00146     {"bitor",             1,   -1,         0,   {OPERAND_NONE}},
00147         /* Bitwise or:  push (stknext | stktop) */
00148     {"bitxor",            1,   -1,         0,   {OPERAND_NONE}},
00149         /* Bitwise xor  push (stknext ^ stktop) */
00150     {"bitand",            1,   -1,         0,   {OPERAND_NONE}},
00151         /* Bitwise and: push (stknext & stktop) */
00152     {"eq",                1,   -1,         0,   {OPERAND_NONE}},
00153         /* Equal:       push (stknext == stktop) */
00154     {"neq",               1,   -1,         0,   {OPERAND_NONE}},
00155         /* Not equal:   push (stknext != stktop) */
00156     {"lt",                1,   -1,         0,   {OPERAND_NONE}},
00157         /* Less:        push (stknext < stktop) */
00158     {"gt",                1,   -1,         0,   {OPERAND_NONE}},
00159         /* Greater:     push (stknext || stktop) */
00160     {"le",                1,   -1,         0,   {OPERAND_NONE}},
00161         /* Less or equal: push (stknext || stktop) */
00162     {"ge",                1,   -1,         0,   {OPERAND_NONE}},
00163         /* Greater or equal: push (stknext || stktop) */
00164     {"lshift",            1,   -1,         0,   {OPERAND_NONE}},
00165         /* Left shift:  push (stknext << stktop) */
00166     {"rshift",            1,   -1,         0,   {OPERAND_NONE}},
00167         /* Right shift: push (stknext >> stktop) */
00168     {"add",               1,   -1,         0,   {OPERAND_NONE}},
00169         /* Add:         push (stknext + stktop) */
00170     {"sub",               1,   -1,         0,   {OPERAND_NONE}},
00171         /* Sub:         push (stkext - stktop) */
00172     {"mult",              1,   -1,         0,   {OPERAND_NONE}},
00173         /* Multiply:    push (stknext * stktop) */
00174     {"div",               1,   -1,         0,   {OPERAND_NONE}},
00175         /* Divide:      push (stknext / stktop) */
00176     {"mod",               1,   -1,         0,   {OPERAND_NONE}},
00177         /* Mod:         push (stknext % stktop) */
00178     {"uplus",             1,   0,          0,   {OPERAND_NONE}},
00179         /* Unary plus:  push +stktop */
00180     {"uminus",            1,   0,          0,   {OPERAND_NONE}},
00181         /* Unary minus: push -stktop */
00182     {"bitnot",            1,   0,          0,   {OPERAND_NONE}},
00183         /* Bitwise not: push ~stktop */
00184     {"not",               1,   0,          0,   {OPERAND_NONE}},
00185         /* Logical not: push !stktop */
00186     {"callBuiltinFunc1",  2,   1,          1,   {OPERAND_UINT1}},
00187         /* Call builtin math function with index op1; any args are on stk */
00188     {"callFunc1",         2,   INT_MIN,    1,   {OPERAND_UINT1}},
00189         /* Call non-builtin func objv[0]; <objc,objv>=<op1,top op1> */
00190     {"tryCvtToNumeric",   1,   0,          0,   {OPERAND_NONE}},
00191         /* Try converting stktop to first int then double if possible. */
00192 
00193     {"break",             1,   0,          0,   {OPERAND_NONE}},
00194         /* Abort closest enclosing loop; if none, return TCL_BREAK code. */
00195     {"continue",          1,   0,          0,   {OPERAND_NONE}},
00196         /* Skip to next iteration of closest enclosing loop; if none, return
00197          * TCL_CONTINUE code. */
00198 
00199     {"foreach_start4",    5,   0,          1,   {OPERAND_AUX4}},
00200         /* Initialize execution of a foreach loop. Operand is aux data index
00201          * of the ForeachInfo structure for the foreach command. */
00202     {"foreach_step4",     5,   +1,         1,   {OPERAND_AUX4}},
00203         /* "Step" or begin next iteration of foreach loop. Push 0 if to
00204          * terminate loop, else push 1. */
00205 
00206     {"beginCatch4",       5,   0,          1,   {OPERAND_UINT4}},
00207         /* Record start of catch with the operand's exception index. Push the
00208          * current stack depth onto a special catch stack. */
00209     {"endCatch",          1,   0,          0,   {OPERAND_NONE}},
00210         /* End of last catch. Pop the bytecode interpreter's catch stack. */
00211     {"pushResult",        1,   +1,         0,   {OPERAND_NONE}},
00212         /* Push the interpreter's object result onto the stack. */
00213     {"pushReturnCode",    1,   +1,         0,   {OPERAND_NONE}},
00214         /* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as a new
00215          * object onto the stack. */
00216 
00217     {"streq",             1,   -1,         0,   {OPERAND_NONE}},
00218         /* Str Equal:   push (stknext eq stktop) */
00219     {"strneq",            1,   -1,         0,   {OPERAND_NONE}},
00220         /* Str !Equal:  push (stknext neq stktop) */
00221     {"strcmp",            1,   -1,         0,   {OPERAND_NONE}},
00222         /* Str Compare: push (stknext cmp stktop) */
00223     {"strlen",            1,   0,          0,   {OPERAND_NONE}},
00224         /* Str Length:  push (strlen stktop) */
00225     {"strindex",          1,   -1,         0,   {OPERAND_NONE}},
00226         /* Str Index:   push (strindex stknext stktop) */
00227     {"strmatch",          2,   -1,         1,   {OPERAND_INT1}},
00228         /* Str Match:   push (strmatch stknext stktop) opnd == nocase */
00229 
00230     {"list",              5,   INT_MIN,    1,   {OPERAND_UINT4}},
00231         /* List:        push (stk1 stk2 ... stktop) */
00232     {"listIndex",         1,   -1,         0,   {OPERAND_NONE}},
00233         /* List Index:  push (listindex stknext stktop) */
00234     {"listLength",        1,   0,          0,   {OPERAND_NONE}},
00235         /* List Len:    push (listlength stktop) */
00236 
00237     {"appendScalar1",     2,   0,          1,   {OPERAND_LVT1}},
00238         /* Append scalar variable at op1<=255 in frame; value is stktop */
00239     {"appendScalar4",     5,   0,          1,   {OPERAND_LVT4}},
00240         /* Append scalar variable at op1 > 255 in frame; value is stktop */
00241     {"appendArray1",      2,   -1,         1,   {OPERAND_LVT1}},
00242         /* Append array element; array at op1<=255, value is top then elem */
00243     {"appendArray4",      5,   -1,         1,   {OPERAND_LVT4}},
00244         /* Append array element; array at op1>=256, value is top then elem */
00245     {"appendArrayStk",    1,   -2,         0,   {OPERAND_NONE}},
00246         /* Append array element; value is stktop, then elem, array names */
00247     {"appendStk",         1,   -1,         0,   {OPERAND_NONE}},
00248         /* Append general variable; value is stktop, then unparsed name */
00249     {"lappendScalar1",    2,   0,          1,   {OPERAND_LVT1}},
00250         /* Lappend scalar variable at op1<=255 in frame; value is stktop */
00251     {"lappendScalar4",    5,   0,          1,   {OPERAND_LVT4}},
00252         /* Lappend scalar variable at op1 > 255 in frame; value is stktop */
00253     {"lappendArray1",     2,   -1,         1,   {OPERAND_LVT1}},
00254         /* Lappend array element; array at op1<=255, value is top then elem */
00255     {"lappendArray4",     5,   -1,         1,   {OPERAND_LVT4}},
00256         /* Lappend array element; array at op1>=256, value is top then elem */
00257     {"lappendArrayStk",   1,   -2,         0,   {OPERAND_NONE}},
00258         /* Lappend array element; value is stktop, then elem, array names */
00259     {"lappendStk",        1,   -1,         0,   {OPERAND_NONE}},
00260         /* Lappend general variable; value is stktop, then unparsed name */
00261 
00262     {"lindexMulti",       5,   INT_MIN,    1,   {OPERAND_UINT4}},
00263         /* Lindex with generalized args, operand is number of stacked objs
00264          * used: (operand-1) entries from stktop are the indices; then list to
00265          * process. */
00266     {"over",              5,   +1,         1,   {OPERAND_UINT4}},
00267         /* Duplicate the arg-th element from top of stack (TOS=0) */
00268     {"lsetList",          1,   -2,         0,   {OPERAND_NONE}},
00269         /* Four-arg version of 'lset'. stktop is old value; next is new
00270          * element value, next is the index list; pushes new value */
00271     {"lsetFlat",          5,   INT_MIN,    1,   {OPERAND_UINT4}},
00272         /* Three- or >=5-arg version of 'lset', operand is number of stacked
00273          * objs: stktop is old value, next is new element value, next come
00274          * (operand-2) indices; pushes the new value.
00275          */
00276 
00277     {"returnImm",         9,   -1,         2,   {OPERAND_INT4, OPERAND_UINT4}},
00278         /* Compiled [return], code, level are operands; options and result
00279          * are on the stack. */
00280     {"expon",             1,   -1,         0,   {OPERAND_NONE}},
00281         /* Binary exponentiation operator: push (stknext ** stktop) */
00282 
00283     /*
00284      * NOTE: the stack effects of expandStkTop and invokeExpanded are wrong -
00285      * but it cannot be done right at compile time, the stack effect is only
00286      * known at run time. The value for invokeExpanded is estimated better at
00287      * compile time.
00288      * See the comments further down in this file, where INST_INVOKE_EXPANDED
00289      * is emitted.
00290      */
00291     {"expandStart",       1,    0,          0,  {OPERAND_NONE}},
00292         /* Start of command with {*} (expanded) arguments */
00293     {"expandStkTop",      5,    0,          1,  {OPERAND_UINT4}},
00294         /* Expand the list at stacktop: push its elements on the stack */
00295     {"invokeExpanded",    1,    0,          0,  {OPERAND_NONE}},
00296         /* Invoke the command marked by the last 'expandStart' */
00297 
00298     {"listIndexImm",      5,    0,         1,   {OPERAND_IDX4}},
00299         /* List Index:  push (lindex stktop op4) */
00300     {"listRangeImm",      9,    0,         2,   {OPERAND_IDX4, OPERAND_IDX4}},
00301         /* List Range:  push (lrange stktop op4 op4) */
00302     {"startCommand",      9,    0,         2,   {OPERAND_INT4,OPERAND_UINT4}},
00303         /* Start of bytecoded command: op is the length of the cmd's code, op2
00304          * is number of commands here */
00305 
00306     {"listIn",            1,    -1,        0,   {OPERAND_NONE}},
00307         /* List containment: push [lsearch stktop stknext]>=0) */
00308     {"listNotIn",         1,    -1,        0,   {OPERAND_NONE}},
00309         /* List negated containment: push [lsearch stktop stknext]<0) */
00310 
00311     {"pushReturnOpts",    1,    +1,        0,   {OPERAND_NONE}},
00312         /* Push the interpreter's return option dictionary as an object on the
00313          * stack. */
00314     {"returnStk",         1,    -2,        0,   {OPERAND_NONE}},
00315         /* Compiled [return]; options and result are on the stack, code and
00316          * level are in the options. */
00317 
00318     {"dictGet",           5,    INT_MIN,   1,   {OPERAND_UINT4}},
00319         /* The top op4 words (min 1) are a key path into the dictionary just
00320          * below the keys on the stack, and all those values are replaced by
00321          * the value read out of that key-path (like [dict get]).
00322          * Stack:  ... dict key1 ... keyN => ... value */
00323     {"dictSet",           9,    INT_MIN,   2,   {OPERAND_UINT4, OPERAND_LVT4}},
00324         /* Update a dictionary value such that the keys are a path pointing to
00325          * the value. op4#1 = numKeys, op4#2 = LVTindex
00326          * Stack:  ... key1 ... keyN value => ... newDict */
00327     {"dictUnset",         9,    INT_MIN,   2,   {OPERAND_UINT4, OPERAND_LVT4}},
00328         /* Update a dictionary value such that the keys are not a path pointing
00329          * to any value. op4#1 = numKeys, op4#2 = LVTindex
00330          * Stack:  ... key1 ... keyN => ... newDict */
00331     {"dictIncrImm",       9,    0,         2,   {OPERAND_INT4, OPERAND_LVT4}},
00332         /* Update a dictionary value such that the value pointed to by key is
00333          * incremented by some value (or set to it if the key isn't in the
00334          * dictionary at all). op4#1 = incrAmount, op4#2 = LVTindex
00335          * Stack:  ... key => ... newDict */
00336     {"dictAppend",        5,    -1,        1,   {OPERAND_LVT4}},
00337         /* Update a dictionary value such that the value pointed to by key has
00338          * some value string-concatenated onto it. op4 = LVTindex
00339          * Stack:  ... key valueToAppend => ... newDict */
00340     {"dictLappend",       5,    -1,        1,   {OPERAND_LVT4}},
00341         /* Update a dictionary value such that the value pointed to by key has
00342          * some value list-appended onto it. op4 = LVTindex
00343          * Stack:  ... key valueToAppend => ... newDict */
00344     {"dictFirst",         5,    +2,        1,   {OPERAND_LVT4}},
00345         /* Begin iterating over the dictionary, using the local scalar
00346          * indicated by op4 to hold the iterator state. If doneBool is true,
00347          * dictDone *must* be called later on.
00348          * Stack:  ... dict => ... value key doneBool */
00349     {"dictNext",          5,    +3,        1,   {OPERAND_LVT4}},
00350         /* Get the next iteration from the iterator in op4's local scalar.
00351          * Stack:  ... => ... value key doneBool */
00352     {"dictDone",          5,    0,         1,   {OPERAND_LVT4}},
00353         /* Terminate the iterator in op4's local scalar. */
00354     {"dictUpdateStart",   9,    0,         2,   {OPERAND_LVT4, OPERAND_AUX4}},
00355         /* Create the variables (described in the aux data referred to by the
00356          * second immediate argument) to mirror the state of the dictionary in
00357          * the variable referred to by the first immediate argument. The list
00358          * of keys (popped from the stack) must be the same length as the list
00359          * of variables.
00360          * Stack:  ... keyList => ... */
00361     {"dictUpdateEnd",     9,    -1,        2,   {OPERAND_LVT4, OPERAND_AUX4}},
00362         /* Reflect the state of local variables (described in the aux data
00363          * referred to by the second immediate argument) back to the state of
00364          * the dictionary in the variable referred to by the first immediate
00365          * argument. The list of keys (popped from the stack) must be the same
00366          * length as the list of variables.
00367          * Stack:  ... keyList => ... */
00368     {"jumpTable",         5,    -1,        1,   {OPERAND_AUX4}},
00369         /* Jump according to the jump-table (in AuxData as indicated by the
00370          * operand) and the argument popped from the list. Always executes the
00371          * next instruction if no match against the table's entries was found.
00372          * Stack:  ... value => ...
00373          * Note that the jump table contains offsets relative to the PC when
00374          * it points to this instruction; the code is relocatable. */
00375     {"upvar",            5,     0,        1,   {OPERAND_LVT4}},
00376          /* finds level and otherName in stack, links to local variable at
00377           * index op1. Leaves the level on stack. */
00378     {"nsupvar",          5,     0,        1,   {OPERAND_LVT4}},
00379          /* finds namespace and otherName in stack, links to local variable at
00380           * index op1. Leaves the namespace on stack. */
00381     {"variable",         5,     0,        1,   {OPERAND_LVT4}},
00382          /* finds namespace and otherName in stack, links to local variable at
00383           * index op1. Leaves the namespace on stack. */
00384     {"syntax",           9,   -1,         2,    {OPERAND_INT4, OPERAND_UINT4}},
00385         /* Compiled bytecodes to signal syntax error. */
00386     {"reverse",          5,    0,         1,    {OPERAND_UINT4}},
00387         /* Reverse the order of the arg elements at the top of stack */
00388 
00389     {"regexp",           2,   -1,         1,    {OPERAND_INT1}},
00390         /* Regexp:      push (regexp stknext stktop) opnd == nocase */
00391 
00392     {"existScalar",      5,    1,         1,    {OPERAND_LVT4}},
00393         /* Test if scalar variable at index op1 in call frame exists */
00394     {"existArray",       5,    0,         1,    {OPERAND_LVT4}},
00395         /* Test if array element exists; array at slot op1, element is
00396          * stktop */
00397     {"existArrayStk",    1,    -1,        0,    {OPERAND_NONE}},
00398         /* Test if array element exists; element is stktop, array name is
00399          * stknext */
00400     {"existStk",         1,    0,         0,    {OPERAND_NONE}},
00401         /* Test if general variable exists; unparsed variable name is stktop*/
00402     {0}
00403 };
00404 
00405 /*
00406  * Prototypes for procedures defined later in this file:
00407  */
00408 
00409 static void             DupByteCodeInternalRep(Tcl_Obj *srcPtr,
00410                             Tcl_Obj *copyPtr);
00411 static unsigned char *  EncodeCmdLocMap(CompileEnv *envPtr,
00412                             ByteCode *codePtr, unsigned char *startPtr);
00413 static void             EnterCmdExtentData(CompileEnv *envPtr,
00414                             int cmdNumber, int numSrcBytes, int numCodeBytes);
00415 static void             EnterCmdStartData(CompileEnv *envPtr,
00416                             int cmdNumber, int srcOffset, int codeOffset);
00417 static void             FreeByteCodeInternalRep(Tcl_Obj *objPtr);
00418 static int              GetCmdLocEncodingSize(CompileEnv *envPtr);
00419 #ifdef TCL_COMPILE_STATS
00420 static void             RecordByteCodeStats(ByteCode *codePtr);
00421 #endif /* TCL_COMPILE_STATS */
00422 static int              SetByteCodeFromAny(Tcl_Interp *interp,
00423                             Tcl_Obj *objPtr);
00424 static int              FormatInstruction(ByteCode *codePtr,
00425                             unsigned char *pc, Tcl_Obj *bufferObj);
00426 static void             PrintSourceToObj(Tcl_Obj *appendObj,
00427                             const char *stringPtr, int maxChars);
00428 /*
00429  * TIP #280: Helper for building the per-word line information of all compiled
00430  * commands.
00431  */
00432 static void             EnterCmdWordData(ExtCmdLoc *eclPtr, int srcOffset,
00433                             Tcl_Token *tokenPtr, const char *cmd, int len,
00434                             int numWords, int line, int **lines);
00435 
00436 /*
00437  * The structure below defines the bytecode Tcl object type by means of
00438  * procedures that can be invoked by generic object code.
00439  */
00440 
00441 Tcl_ObjType tclByteCodeType = {
00442     "bytecode",                 /* name */
00443     FreeByteCodeInternalRep,    /* freeIntRepProc */
00444     DupByteCodeInternalRep,     /* dupIntRepProc */
00445     NULL,                       /* updateStringProc */
00446     SetByteCodeFromAny          /* setFromAnyProc */
00447 };
00448 
00449 /*
00450  *----------------------------------------------------------------------
00451  *
00452  * TclSetByteCodeFromAny --
00453  *
00454  *      Part of the bytecode Tcl object type implementation. Attempts to
00455  *      generate an byte code internal form for the Tcl object "objPtr" by
00456  *      compiling its string representation. This function also takes a hook
00457  *      procedure that will be invoked to perform any needed post processing
00458  *      on the compilation results before generating byte codes.
00459  *
00460  * Results:
00461  *      The return value is a standard Tcl object result. If an error occurs
00462  *      during compilation, an error message is left in the interpreter's
00463  *      result unless "interp" is NULL.
00464  *
00465  * Side effects:
00466  *      Frees the old internal representation. If no error occurs, then the
00467  *      compiled code is stored as "objPtr"s bytecode representation. Also, if
00468  *      debugging, initializes the "tcl_traceCompile" Tcl variable used to
00469  *      trace compilations.
00470  *
00471  *----------------------------------------------------------------------
00472  */
00473 
00474 int
00475 TclSetByteCodeFromAny(
00476     Tcl_Interp *interp,         /* The interpreter for which the code is being
00477                                  * compiled. Must not be NULL. */
00478     Tcl_Obj *objPtr,            /* The object to make a ByteCode object. */
00479     CompileHookProc *hookProc,  /* Procedure to invoke after compilation. */
00480     ClientData clientData)      /* Hook procedure private data. */
00481 {
00482     Interp *iPtr = (Interp *) interp;
00483     CompileEnv compEnv;         /* Compilation environment structure allocated
00484                                  * in frame. */
00485     register AuxData *auxDataPtr;
00486     LiteralEntry *entryPtr;
00487     register int i;
00488     int length, result = TCL_OK;
00489     const char *stringPtr;
00490 
00491 #ifdef TCL_COMPILE_DEBUG
00492     if (!traceInitialized) {
00493         if (Tcl_LinkVar(interp, "tcl_traceCompile",
00494                 (char *) &tclTraceCompile, TCL_LINK_INT) != TCL_OK) {
00495             Tcl_Panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
00496         }
00497         traceInitialized = 1;
00498     }
00499 #endif
00500 
00501     stringPtr = TclGetStringFromObj(objPtr, &length);
00502 
00503     /*
00504      * TIP #280: Pick up the CmdFrame in which the BC compiler was invoked and
00505      * use to initialize the tracking in the compiler. This information was
00506      * stored by TclCompEvalObj and ProcCompileProc.
00507      */
00508 
00509     TclInitCompileEnv(interp, &compEnv, stringPtr, length,
00510             iPtr->invokeCmdFramePtr, iPtr->invokeWord);
00511     TclCompileScript(interp, stringPtr, length, &compEnv);
00512 
00513     /*
00514      * Successful compilation. Add a "done" instruction at the end.
00515      */
00516 
00517     TclEmitOpcode(INST_DONE, &compEnv);
00518 
00519     /*
00520      * Invoke the compilation hook procedure if one exists.
00521      */
00522 
00523     if (hookProc) {
00524         result = (*hookProc)(interp, &compEnv, clientData);
00525     }
00526 
00527     /*
00528      * Change the object into a ByteCode object. Ownership of the literal
00529      * objects and aux data items is given to the ByteCode object.
00530      */
00531 
00532 #ifdef TCL_COMPILE_DEBUG
00533     TclVerifyLocalLiteralTable(&compEnv);
00534 #endif /*TCL_COMPILE_DEBUG*/
00535 
00536     TclInitByteCodeObj(objPtr, &compEnv);
00537 #ifdef TCL_COMPILE_DEBUG
00538     if (tclTraceCompile >= 2) {
00539         TclPrintByteCodeObj(interp, objPtr);
00540         fflush(stdout);
00541     }
00542 #endif /* TCL_COMPILE_DEBUG */
00543 
00544     if (result != TCL_OK) {
00545         /*
00546          * Handle any error from the hookProc
00547          */
00548 
00549         entryPtr = compEnv.literalArrayPtr;
00550         for (i = 0;  i < compEnv.literalArrayNext;  i++) {
00551             TclReleaseLiteral(interp, entryPtr->objPtr);
00552             entryPtr++;
00553         }
00554 #ifdef TCL_COMPILE_DEBUG
00555         TclVerifyGlobalLiteralTable(iPtr);
00556 #endif /*TCL_COMPILE_DEBUG*/
00557 
00558         auxDataPtr = compEnv.auxDataArrayPtr;
00559         for (i = 0;  i < compEnv.auxDataArrayNext;  i++) {
00560             if (auxDataPtr->type->freeProc != NULL) {
00561                 auxDataPtr->type->freeProc(auxDataPtr->clientData);
00562             }
00563             auxDataPtr++;
00564         }
00565     }
00566 
00567     TclFreeCompileEnv(&compEnv);
00568     return result;
00569 }
00570 
00571 /*
00572  *-----------------------------------------------------------------------
00573  *
00574  * SetByteCodeFromAny --
00575  *
00576  *      Part of the bytecode Tcl object type implementation. Attempts to
00577  *      generate an byte code internal form for the Tcl object "objPtr" by
00578  *      compiling its string representation.
00579  *
00580  * Results:
00581  *      The return value is a standard Tcl object result. If an error occurs
00582  *      during compilation, an error message is left in the interpreter's
00583  *      result unless "interp" is NULL.
00584  *
00585  * Side effects:
00586  *      Frees the old internal representation. If no error occurs, then the
00587  *      compiled code is stored as "objPtr"s bytecode representation. Also, if
00588  *      debugging, initializes the "tcl_traceCompile" Tcl variable used to
00589  *      trace compilations.
00590  *
00591  *----------------------------------------------------------------------
00592  */
00593 
00594 static int
00595 SetByteCodeFromAny(
00596     Tcl_Interp *interp,         /* The interpreter for which the code is being
00597                                  * compiled. Must not be NULL. */
00598     Tcl_Obj *objPtr)            /* The object to make a ByteCode object. */
00599 {
00600     (void) TclSetByteCodeFromAny(interp, objPtr, NULL, (ClientData) NULL);
00601     return TCL_OK;
00602 }
00603 
00604 /*
00605  *----------------------------------------------------------------------
00606  *
00607  * DupByteCodeInternalRep --
00608  *
00609  *      Part of the bytecode Tcl object type implementation. However, it does
00610  *      not copy the internal representation of a bytecode Tcl_Obj, but
00611  *      instead leaves the new object untyped (with a NULL type pointer).
00612  *      Code will be compiled for the new object only if necessary.
00613  *
00614  * Results:
00615  *      None.
00616  *
00617  * Side effects:
00618  *      None.
00619  *
00620  *----------------------------------------------------------------------
00621  */
00622 
00623 static void
00624 DupByteCodeInternalRep(
00625     Tcl_Obj *srcPtr,            /* Object with internal rep to copy. */
00626     Tcl_Obj *copyPtr)           /* Object with internal rep to set. */
00627 {
00628     return;
00629 }
00630 
00631 /*
00632  *----------------------------------------------------------------------
00633  *
00634  * FreeByteCodeInternalRep --
00635  *
00636  *      Part of the bytecode Tcl object type implementation. Frees the storage
00637  *      associated with a bytecode object's internal representation unless its
00638  *      code is actively being executed.
00639  *
00640  * Results:
00641  *      None.
00642  *
00643  * Side effects:
00644  *      The bytecode object's internal rep is marked invalid and its code gets
00645  *      freed unless the code is actively being executed. In that case the
00646  *      cleanup is delayed until the last execution of the code completes.
00647  *
00648  *----------------------------------------------------------------------
00649  */
00650 
00651 static void
00652 FreeByteCodeInternalRep(
00653     register Tcl_Obj *objPtr)   /* Object whose internal rep to free. */
00654 {
00655     register ByteCode *codePtr = (ByteCode *)
00656             objPtr->internalRep.otherValuePtr;
00657 
00658     codePtr->refCount--;
00659     if (codePtr->refCount <= 0) {
00660         TclCleanupByteCode(codePtr);
00661     }
00662     objPtr->typePtr = NULL;
00663     objPtr->internalRep.otherValuePtr = NULL;
00664 }
00665 
00666 /*
00667  *----------------------------------------------------------------------
00668  *
00669  * TclCleanupByteCode --
00670  *
00671  *      This procedure does all the real work of freeing up a bytecode
00672  *      object's ByteCode structure. It's called only when the structure's
00673  *      reference count becomes zero.
00674  *
00675  * Results:
00676  *      None.
00677  *
00678  * Side effects:
00679  *      Frees objPtr's bytecode internal representation and sets its type and
00680  *      objPtr->internalRep.otherValuePtr NULL. Also releases its literals and
00681  *      frees its auxiliary data items.
00682  *
00683  *----------------------------------------------------------------------
00684  */
00685 
00686 void
00687 TclCleanupByteCode(
00688     register ByteCode *codePtr) /* Points to the ByteCode to free. */
00689 {
00690     Tcl_Interp *interp = (Tcl_Interp *) *codePtr->interpHandle;
00691     Interp *iPtr = (Interp *) interp;
00692     int numLitObjects = codePtr->numLitObjects;
00693     int numAuxDataItems = codePtr->numAuxDataItems;
00694     register Tcl_Obj **objArrayPtr, *objPtr;
00695     register AuxData *auxDataPtr;
00696     int i;
00697 #ifdef TCL_COMPILE_STATS
00698 
00699     if (interp != NULL) {
00700         ByteCodeStats *statsPtr;
00701         Tcl_Time destroyTime;
00702         int lifetimeSec, lifetimeMicroSec, log2;
00703 
00704         statsPtr = &((Interp *) interp)->stats;
00705 
00706         statsPtr->numByteCodesFreed++;
00707         statsPtr->currentSrcBytes -= (double) codePtr->numSrcBytes;
00708         statsPtr->currentByteCodeBytes -= (double) codePtr->structureSize;
00709 
00710         statsPtr->currentInstBytes -= (double) codePtr->numCodeBytes;
00711         statsPtr->currentLitBytes -= (double)
00712                 codePtr->numLitObjects * sizeof(Tcl_Obj *);
00713         statsPtr->currentExceptBytes -= (double)
00714                 codePtr->numExceptRanges * sizeof(ExceptionRange);
00715         statsPtr->currentAuxBytes -= (double)
00716                 codePtr->numAuxDataItems * sizeof(AuxData);
00717         statsPtr->currentCmdMapBytes -= (double) codePtr->numCmdLocBytes;
00718 
00719         Tcl_GetTime(&destroyTime);
00720         lifetimeSec = destroyTime.sec - codePtr->createTime.sec;
00721         if (lifetimeSec > 2000) {       /* avoid overflow */
00722             lifetimeSec = 2000;
00723         }
00724         lifetimeMicroSec = 1000000 * lifetimeSec +
00725                 (destroyTime.usec - codePtr->createTime.usec);
00726 
00727         log2 = TclLog2(lifetimeMicroSec);
00728         if (log2 > 31) {
00729             log2 = 31;
00730         }
00731         statsPtr->lifetimeCount[log2]++;
00732     }
00733 #endif /* TCL_COMPILE_STATS */
00734 
00735     /*
00736      * A single heap object holds the ByteCode structure and its code, object,
00737      * command location, and auxiliary data arrays. This means we only need to
00738      * 1) decrement the ref counts of the LiteralEntry's in its literal array,
00739      * 2) call the free procs for the auxiliary data items, 3) free the
00740      * localCache if it is unused, and finally 4) free the ByteCode
00741      * structure's heap object.
00742      *
00743      * The case for TCL_BYTECODE_PRECOMPILED (precompiled ByteCodes, like
00744      * those generated from tbcload) is special, as they doesn't make use of
00745      * the global literal table. They instead maintain private references to
00746      * their literals which must be decremented.
00747      *
00748      * In order to insure a proper and efficient cleanup of the literal array
00749      * when it contains non-shared literals [Bug 983660], we also distinguish
00750      * the case of an interpreter being deleted (signaled by interp == NULL).
00751      * Also, as the interp deletion will remove the global literal table
00752      * anyway, we avoid the extra cost of updating it for each literal being
00753      * released.
00754      */
00755 
00756     if ((codePtr->flags & TCL_BYTECODE_PRECOMPILED) || (interp == NULL)) {
00757 
00758         objArrayPtr = codePtr->objArrayPtr;
00759         for (i = 0;  i < numLitObjects;  i++) {
00760             objPtr = *objArrayPtr;
00761             if (objPtr) {
00762                 Tcl_DecrRefCount(objPtr);
00763             }
00764             objArrayPtr++;
00765         }
00766         codePtr->numLitObjects = 0;
00767     } else {
00768         objArrayPtr = codePtr->objArrayPtr;
00769         for (i = 0;  i < numLitObjects;  i++) {
00770             /*
00771              * TclReleaseLiteral sets a ByteCode's object array entry NULL to
00772              * indicate that it has already freed the literal.
00773              */
00774 
00775             objPtr = *objArrayPtr;
00776             if (objPtr != NULL) {
00777                 TclReleaseLiteral(interp, objPtr);
00778             }
00779             objArrayPtr++;
00780         }
00781     }
00782 
00783     auxDataPtr = codePtr->auxDataArrayPtr;
00784     for (i = 0;  i < numAuxDataItems;  i++) {
00785         if (auxDataPtr->type->freeProc != NULL) {
00786             (auxDataPtr->type->freeProc)(auxDataPtr->clientData);
00787         }
00788         auxDataPtr++;
00789     }
00790 
00791     /*
00792      * TIP #280. Release the location data associated with this byte code
00793      * structure, if any. NOTE: The interp we belong to may be gone already,
00794      * and the data with it.
00795      *
00796      * See also tclBasic.c, DeleteInterpProc
00797      */
00798 
00799     if (iPtr) {
00800         Tcl_HashEntry *hePtr = Tcl_FindHashEntry(iPtr->lineBCPtr,
00801                 (char *) codePtr);
00802         if (hePtr) {
00803             ExtCmdLoc *eclPtr = Tcl_GetHashValue(hePtr);
00804             int i;
00805 
00806             if (eclPtr->type == TCL_LOCATION_SOURCE) {
00807                 Tcl_DecrRefCount(eclPtr->path);
00808             }
00809             for (i=0 ; i<eclPtr->nuloc ; i++) {
00810                 ckfree((char *) eclPtr->loc[i].line);
00811             }
00812 
00813             if (eclPtr->loc != NULL) {
00814                 ckfree((char *) eclPtr->loc);
00815             }
00816 
00817             ckfree((char *) eclPtr);
00818             Tcl_DeleteHashEntry(hePtr);
00819         }
00820     }
00821 
00822     if (codePtr->localCachePtr && (--codePtr->localCachePtr->refCount == 0)) {
00823         TclFreeLocalCache(interp, codePtr->localCachePtr);
00824     }
00825 
00826     TclHandleRelease(codePtr->interpHandle);
00827     ckfree((char *) codePtr);
00828 }
00829 
00830 /*
00831  *----------------------------------------------------------------------
00832  *
00833  * TclInitCompileEnv --
00834  *
00835  *      Initializes a CompileEnv compilation environment structure for the
00836  *      compilation of a string in an interpreter.
00837  *
00838  * Results:
00839  *      None.
00840  *
00841  * Side effects:
00842  *      The CompileEnv structure is initialized.
00843  *
00844  *----------------------------------------------------------------------
00845  */
00846 
00847 void
00848 TclInitCompileEnv(
00849     Tcl_Interp *interp,         /* The interpreter for which a CompileEnv
00850                                  * structure is initialized. */
00851     register CompileEnv *envPtr,/* Points to the CompileEnv structure to
00852                                  * initialize. */
00853     const char *stringPtr,      /* The source string to be compiled. */
00854     int numBytes,               /* Number of bytes in source string. */
00855     const CmdFrame *invoker,    /* Location context invoking the bcc */
00856     int word)                   /* Index of the word in that context getting
00857                                  * compiled */
00858 {
00859     Interp *iPtr = (Interp *) interp;
00860 
00861     envPtr->iPtr = iPtr;
00862     envPtr->source = stringPtr;
00863     envPtr->numSrcBytes = numBytes;
00864     envPtr->procPtr = iPtr->compiledProcPtr;
00865     envPtr->numCommands = 0;
00866     envPtr->exceptDepth = 0;
00867     envPtr->maxExceptDepth = 0;
00868     envPtr->maxStackDepth = 0;
00869     envPtr->currStackDepth = 0;
00870     TclInitLiteralTable(&(envPtr->localLitTable));
00871 
00872     envPtr->codeStart = envPtr->staticCodeSpace;
00873     envPtr->codeNext = envPtr->codeStart;
00874     envPtr->codeEnd = (envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES);
00875     envPtr->mallocedCodeArray = 0;
00876 
00877     envPtr->literalArrayPtr = envPtr->staticLiteralSpace;
00878     envPtr->literalArrayNext = 0;
00879     envPtr->literalArrayEnd = COMPILEENV_INIT_NUM_OBJECTS;
00880     envPtr->mallocedLiteralArray = 0;
00881 
00882     envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace;
00883     envPtr->exceptArrayNext = 0;
00884     envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;
00885     envPtr->mallocedExceptArray = 0;
00886 
00887     envPtr->cmdMapPtr = envPtr->staticCmdMapSpace;
00888     envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE;
00889     envPtr->mallocedCmdMap = 0;
00890     envPtr->atCmdStart = 1;
00891 
00892     /*
00893      * TIP #280: Set up the extended command location information, based on
00894      * the context invoking the byte code compiler. This structure is used to
00895      * keep the per-word line information for all compiled commands.
00896      *
00897      * See also tclBasic.c, TclEvalObjEx, for the equivalent code in the
00898      * non-compiling evaluator
00899      */
00900 
00901     envPtr->extCmdMapPtr = (ExtCmdLoc *) ckalloc(sizeof(ExtCmdLoc));
00902     envPtr->extCmdMapPtr->loc = NULL;
00903     envPtr->extCmdMapPtr->nloc = 0;
00904     envPtr->extCmdMapPtr->nuloc = 0;
00905     envPtr->extCmdMapPtr->path = NULL;
00906 
00907     if (invoker == NULL) {
00908         /*
00909          * Initialize the compiler for relative counting.
00910          */
00911 
00912         envPtr->line = 1;
00913         envPtr->extCmdMapPtr->type =
00914                 (envPtr->procPtr ? TCL_LOCATION_PROC : TCL_LOCATION_BC);
00915     } else {
00916         /*
00917          * Initialize the compiler using the context, making counting absolute
00918          * to that context. Note that the context can be byte code execution.
00919          * In that case we have to fill out the missing pieces (line, path,
00920          * ...) which may make change the type as well.
00921          */
00922 
00923         if ((invoker->nline <= word) || (invoker->line[word] < 0)) {
00924             /*
00925              * Word is not a literal, relative counting.
00926              */
00927 
00928             envPtr->line = 1;
00929             envPtr->extCmdMapPtr->type =
00930                     (envPtr->procPtr ? TCL_LOCATION_PROC : TCL_LOCATION_BC);
00931         } else {
00932             CmdFrame *ctxPtr;
00933             int pc = 0;
00934 
00935             ctxPtr = (CmdFrame *) TclStackAlloc(interp, sizeof(CmdFrame));
00936             *ctxPtr = *invoker;
00937 
00938             if (invoker->type == TCL_LOCATION_BC) {
00939                 /*
00940                  * Note: Type BC => ctx.data.eval.path    is not used.
00941                  *                  ctx.data.tebc.codePtr is used instead.
00942                  */
00943 
00944                 TclGetSrcInfoForPc(ctxPtr);
00945                 pc = 1;
00946             }
00947 
00948             envPtr->line = ctxPtr->line[word];
00949             envPtr->extCmdMapPtr->type = ctxPtr->type;
00950 
00951             if (ctxPtr->type == TCL_LOCATION_SOURCE) {
00952                 if (pc) {
00953                     /*
00954                      * The reference 'TclGetSrcInfoForPc' made is transfered.
00955                      */
00956 
00957                     envPtr->extCmdMapPtr->path = ctxPtr->data.eval.path;
00958                     ctxPtr->data.eval.path = NULL;
00959                 } else {
00960                     /*
00961                      * We have a new reference here.
00962                      */
00963 
00964                     envPtr->extCmdMapPtr->path = ctxPtr->data.eval.path;
00965                     Tcl_IncrRefCount(envPtr->extCmdMapPtr->path);
00966                 }
00967             }
00968             TclStackFree(interp, ctxPtr);
00969         }
00970     }
00971 
00972     envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace;
00973     envPtr->auxDataArrayNext = 0;
00974     envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE;
00975     envPtr->mallocedAuxDataArray = 0;
00976 }
00977 
00978 /*
00979  *----------------------------------------------------------------------
00980  *
00981  * TclFreeCompileEnv --
00982  *
00983  *      Free the storage allocated in a CompileEnv compilation environment
00984  *      structure.
00985  *
00986  * Results:
00987  *      None.
00988  *
00989  * Side effects:
00990  *      Allocated storage in the CompileEnv structure is freed. Note that its
00991  *      local literal table is not deleted and its literal objects are not
00992  *      released. In addition, storage referenced by its auxiliary data items
00993  *      is not freed. This is done so that, when compilation is successful,
00994  *      "ownership" of these objects and aux data items is handed over to the
00995  *      corresponding ByteCode structure.
00996  *
00997  *----------------------------------------------------------------------
00998  */
00999 
01000 void
01001 TclFreeCompileEnv(
01002     register CompileEnv *envPtr)/* Points to the CompileEnv structure. */
01003 {
01004     if (envPtr->localLitTable.buckets != envPtr->localLitTable.staticBuckets) {
01005         ckfree((char *) envPtr->localLitTable.buckets);
01006         envPtr->localLitTable.buckets = envPtr->localLitTable.staticBuckets;
01007     }
01008     if (envPtr->mallocedCodeArray) {
01009         ckfree((char *) envPtr->codeStart);
01010     }
01011     if (envPtr->mallocedLiteralArray) {
01012         ckfree((char *) envPtr->literalArrayPtr);
01013     }
01014     if (envPtr->mallocedExceptArray) {
01015         ckfree((char *) envPtr->exceptArrayPtr);
01016     }
01017     if (envPtr->mallocedCmdMap) {
01018         ckfree((char *) envPtr->cmdMapPtr);
01019     }
01020     if (envPtr->mallocedAuxDataArray) {
01021         ckfree((char *) envPtr->auxDataArrayPtr);
01022     }
01023     if (envPtr->extCmdMapPtr) {
01024         ckfree((char *) envPtr->extCmdMapPtr);
01025     }
01026 }
01027 
01028 /*
01029  *----------------------------------------------------------------------
01030  *
01031  * TclWordKnownAtCompileTime --
01032  *
01033  *      Test whether the value of a token is completely known at compile time.
01034  *
01035  * Results:
01036  *      Returns true if the tokenPtr argument points to a word value that is
01037  *      completely known at compile time. Generally, values that are known at
01038  *      compile time can be compiled to their values, while values that cannot
01039  *      be known until substitution at runtime must be compiled to bytecode
01040  *      instructions that perform that substitution. For several commands,
01041  *      whether or not arguments are known at compile time determine whether
01042  *      it is worthwhile to compile at all.
01043  *
01044  * Side effects:
01045  *      When returning true, appends the known value of the word to the
01046  *      unshared Tcl_Obj (*valuePtr), unless valuePtr is NULL.
01047  *
01048  *----------------------------------------------------------------------
01049  */
01050 
01051 int
01052 TclWordKnownAtCompileTime(
01053     Tcl_Token *tokenPtr,        /* Points to Tcl_Token we should check */
01054     Tcl_Obj *valuePtr)          /* If not NULL, points to an unshared Tcl_Obj
01055                                  * to which we should append the known value
01056                                  * of the word. */
01057 {
01058     int numComponents = tokenPtr->numComponents;
01059     Tcl_Obj *tempPtr = NULL;
01060 
01061     if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
01062         if (valuePtr != NULL) {
01063             Tcl_AppendToObj(valuePtr, tokenPtr[1].start, tokenPtr[1].size);
01064         }
01065         return 1;
01066     }
01067     if (tokenPtr->type != TCL_TOKEN_WORD) {
01068         return 0;
01069     }
01070     tokenPtr++;
01071     if (valuePtr != NULL) {
01072         tempPtr = Tcl_NewObj();
01073         Tcl_IncrRefCount(tempPtr);
01074     }
01075     while (numComponents--) {
01076         switch (tokenPtr->type) {
01077         case TCL_TOKEN_TEXT:
01078             if (tempPtr != NULL) {
01079                 Tcl_AppendToObj(tempPtr, tokenPtr->start, tokenPtr->size);
01080             }
01081             break;
01082 
01083         case TCL_TOKEN_BS:
01084             if (tempPtr != NULL) {
01085                 char utfBuf[TCL_UTF_MAX];
01086                 int length = Tcl_UtfBackslash(tokenPtr->start, NULL, utfBuf);
01087                 Tcl_AppendToObj(tempPtr, utfBuf, length);
01088             }
01089             break;
01090 
01091         default:
01092             if (tempPtr != NULL) {
01093                 Tcl_DecrRefCount(tempPtr);
01094             }
01095             return 0;
01096         }
01097         tokenPtr++;
01098     }
01099     if (valuePtr != NULL) {
01100         Tcl_AppendObjToObj(valuePtr, tempPtr);
01101         Tcl_DecrRefCount(tempPtr);
01102     }
01103     return 1;
01104 }
01105 
01106 /*
01107  *----------------------------------------------------------------------
01108  *
01109  * TclCompileScript --
01110  *
01111  *      Compile a Tcl script in a string.
01112  *
01113  * Results:
01114  *      The return value is TCL_OK on a successful compilation and TCL_ERROR
01115  *      on failure. If TCL_ERROR is returned, then the interpreter's result
01116  *      contains an error message.
01117  *
01118  * Side effects:
01119  *      Adds instructions to envPtr to evaluate the script at runtime.
01120  *
01121  *----------------------------------------------------------------------
01122  */
01123 
01124 void
01125 TclCompileScript(
01126     Tcl_Interp *interp,         /* Used for error and status reporting. Also
01127                                  * serves as context for finding and compiling
01128                                  * commands. May not be NULL. */
01129     const char *script,         /* The source script to compile. */
01130     int numBytes,               /* Number of bytes in script. If < 0, the
01131                                  * script consists of all bytes up to the
01132                                  * first null character. */
01133     CompileEnv *envPtr)         /* Holds resulting instructions. */
01134 {
01135     Interp *iPtr = (Interp *) interp;
01136     int lastTopLevelCmdIndex = -1;
01137                                 /* Index of most recent toplevel command in
01138                                  * the command location table. Initialized to
01139                                  * avoid compiler warning. */
01140     int startCodeOffset = -1;   /* Offset of first byte of current command's
01141                                  * code. Init. to avoid compiler warning. */
01142     unsigned char *entryCodeNext = envPtr->codeNext;
01143     const char *p, *next;
01144     Namespace *cmdNsPtr;
01145     Command *cmdPtr;
01146     Tcl_Token *tokenPtr;
01147     int bytesLeft, isFirstCmd, gotParse, wordIdx, currCmdIndex;
01148     int commandLength, objIndex;
01149     Tcl_DString ds;
01150     /* TIP #280 */
01151     ExtCmdLoc *eclPtr = envPtr->extCmdMapPtr;
01152     int *wlines, wlineat, cmdLine;
01153     Tcl_Parse *parsePtr = (Tcl_Parse *)
01154             TclStackAlloc(interp, sizeof(Tcl_Parse));
01155 
01156     Tcl_DStringInit(&ds);
01157 
01158     if (numBytes < 0) {
01159         numBytes = strlen(script);
01160     }
01161     Tcl_ResetResult(interp);
01162     isFirstCmd = 1;
01163 
01164     if (envPtr->procPtr != NULL) {
01165         cmdNsPtr = envPtr->procPtr->cmdPtr->nsPtr;
01166     } else {
01167         cmdNsPtr = NULL;        /* use current NS */
01168     }
01169 
01170     /*
01171      * Each iteration through the following loop compiles the next command
01172      * from the script.
01173      */
01174 
01175     p = script;
01176     bytesLeft = numBytes;
01177     gotParse = 0;
01178     cmdLine = envPtr->line;
01179     do {
01180         if (Tcl_ParseCommand(interp, p, bytesLeft, 0, parsePtr) != TCL_OK) {
01181             /*
01182              * Compile bytecodes to report the parse error at runtime.
01183              */
01184 
01185             Tcl_LogCommandInfo(interp, script, parsePtr->commandStart,
01186                     /* Drop the command terminator (";","]") if appropriate */
01187                     (parsePtr->term ==
01188                     parsePtr->commandStart + parsePtr->commandSize - 1)?
01189                     parsePtr->commandSize - 1 : parsePtr->commandSize);
01190             TclCompileSyntaxError(interp, envPtr);
01191             break;
01192         }
01193         gotParse = 1;
01194         if (parsePtr->numWords > 0) {
01195             int expand = 0;     /* Set if there are dynamic expansions to
01196                                  * handle */
01197 
01198             /*
01199              * If not the first command, pop the previous command's result
01200              * and, if we're compiling a top level command, update the last
01201              * command's code size to account for the pop instruction.
01202              */
01203 
01204             if (!isFirstCmd) {
01205                 TclEmitOpcode(INST_POP, envPtr);
01206                 envPtr->cmdMapPtr[lastTopLevelCmdIndex].numCodeBytes =
01207                         (envPtr->codeNext - envPtr->codeStart)
01208                         - startCodeOffset;
01209             }
01210 
01211             /*
01212              * Determine the actual length of the command.
01213              */
01214 
01215             commandLength = parsePtr->commandSize;
01216             if (parsePtr->term == parsePtr->commandStart + commandLength - 1) {
01217                 /*
01218                  * The command terminator character (such as ; or ]) is the
01219                  * last character in the parsed command. Reduce the length by
01220                  * one so that the trace message doesn't include the
01221                  * terminator character.
01222                  */
01223 
01224                 commandLength -= 1;
01225             }
01226 
01227 #ifdef TCL_COMPILE_DEBUG
01228             /*
01229              * If tracing, print a line for each top level command compiled.
01230              */
01231 
01232             if ((tclTraceCompile >= 1) && (envPtr->procPtr == NULL)) {
01233                 fprintf(stdout, "  Compiling: ");
01234                 TclPrintSource(stdout, parsePtr->commandStart,
01235                         TclMin(commandLength, 55));
01236                 fprintf(stdout, "\n");
01237             }
01238 #endif
01239 
01240             /*
01241              * Check whether expansion has been requested for any of the
01242              * words.
01243              */
01244 
01245             for (wordIdx = 0, tokenPtr = parsePtr->tokenPtr;
01246                     wordIdx < parsePtr->numWords;
01247                     wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) {
01248                 if (tokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
01249                     expand = 1;
01250                     break;
01251                 }
01252             }
01253 
01254             envPtr->numCommands++;
01255             currCmdIndex = (envPtr->numCommands - 1);
01256             lastTopLevelCmdIndex = currCmdIndex;
01257             startCodeOffset = (envPtr->codeNext - envPtr->codeStart);
01258             EnterCmdStartData(envPtr, currCmdIndex,
01259                     parsePtr->commandStart - envPtr->source, startCodeOffset);
01260 
01261             /*
01262              * Should only start issuing instructions after the "command has
01263              * started" so that the command range is correct in the bytecode.
01264              */
01265 
01266             if (expand) {
01267                 TclEmitOpcode(INST_EXPAND_START, envPtr);
01268             }
01269 
01270             /*
01271              * TIP #280. Scan the words and compute the extended location
01272              * information. The map first contain full per-word line
01273              * information for use by the compiler. This is later replaced by
01274              * a reduced form which signals non-literal words, stored in
01275              * 'wlines'.
01276              */
01277 
01278             TclAdvanceLines(&cmdLine, p, parsePtr->commandStart);
01279             EnterCmdWordData(eclPtr, parsePtr->commandStart - envPtr->source,
01280                     parsePtr->tokenPtr, parsePtr->commandStart,
01281                     parsePtr->commandSize, parsePtr->numWords, cmdLine,
01282                     &wlines);
01283             wlineat = eclPtr->nuloc - 1;
01284 
01285             /*
01286              * Each iteration of the following loop compiles one word from the
01287              * command.
01288              */
01289 
01290             for (wordIdx = 0, tokenPtr = parsePtr->tokenPtr;
01291                     wordIdx < parsePtr->numWords; wordIdx++,
01292                     tokenPtr += (tokenPtr->numComponents + 1)) {
01293 
01294                 envPtr->line = eclPtr->loc[wlineat].line[wordIdx];
01295                 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
01296                     /*
01297                      * The word is not a simple string of characters.
01298                      */
01299 
01300                     TclCompileTokens(interp, tokenPtr+1,
01301                             tokenPtr->numComponents, envPtr);
01302                     if (tokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
01303                         TclEmitInstInt4(INST_EXPAND_STKTOP,
01304                                 envPtr->currStackDepth, envPtr);
01305                     }
01306                     continue;
01307                 }
01308 
01309                 /*
01310                  * This is a simple string of literal characters (i.e. we know
01311                  * it absolutely and can use it directly). If this is the
01312                  * first word and the command has a compile procedure, let it
01313                  * compile the command.
01314                  */
01315 
01316                 if ((wordIdx == 0) && !expand) {
01317                     /*
01318                      * We copy the string before trying to find the command by
01319                      * name. We used to modify the string in place, but this
01320                      * is not safe because the name resolution handlers could
01321                      * have side effects that rely on the unmodified string.
01322                      */
01323 
01324                     Tcl_DStringSetLength(&ds, 0);
01325                     Tcl_DStringAppend(&ds, tokenPtr[1].start,tokenPtr[1].size);
01326 
01327                     cmdPtr = (Command *) Tcl_FindCommand(interp,
01328                             Tcl_DStringValue(&ds),
01329                             (Tcl_Namespace *) cmdNsPtr, /*flags*/ 0);
01330 
01331                     if ((cmdPtr != NULL)
01332                             && (cmdPtr->compileProc != NULL)
01333                             && !(cmdPtr->flags & CMD_HAS_EXEC_TRACES)
01334                             && !(iPtr->flags & DONT_COMPILE_CMDS_INLINE)) {
01335                         int savedNumCmds = envPtr->numCommands;
01336                         unsigned savedCodeNext =
01337                                 envPtr->codeNext - envPtr->codeStart;
01338                         int update = 0, code;
01339 
01340                         /*
01341                          * Mark the start of the command; the proper bytecode
01342                          * length will be updated later. There is no need to
01343                          * do this for the first bytecode in the compile env,
01344                          * as the check is done before calling
01345                          * TclExecuteByteCode(). Do emit an INST_START_CMD in
01346                          * special cases where the first bytecode is in a
01347                          * loop, to insure that the corresponding command is
01348                          * counted properly. Compilers for commands able to
01349                          * produce such a beast (currently 'while 1' only) set
01350                          * envPtr->atCmdStart to 0 in order to signal this
01351                          * case. [Bug 1752146]
01352                          *
01353                          * Note that the environment is initialised with
01354                          * atCmdStart=1 to avoid emitting ISC for the first
01355                          * command.
01356                          */
01357 
01358                         if (envPtr->atCmdStart) {
01359                             if (savedCodeNext != 0) {
01360                                 /*
01361                                  * Increase the number of commands being
01362                                  * started at the current point. Note that
01363                                  * this depends on the exact layout of the
01364                                  * INST_START_CMD's operands, so be careful!
01365                                  */
01366 
01367                                 unsigned char *fixPtr = envPtr->codeNext - 4;
01368 
01369                                 TclStoreInt4AtPtr(TclGetUInt4AtPtr(fixPtr)+1,
01370                                         fixPtr);
01371                             }
01372                         } else {
01373                             TclEmitInstInt4(INST_START_CMD, 0, envPtr);
01374                             TclEmitInt4(1, envPtr);
01375                             update = 1;
01376                         }
01377 
01378                         code = (cmdPtr->compileProc)(interp, parsePtr,
01379                                 cmdPtr, envPtr);
01380 
01381                         if (code == TCL_OK) {
01382                             if (update) {
01383                                 /*
01384                                  * Fix the bytecode length.
01385                                  */
01386 
01387                                 unsigned char *fixPtr = envPtr->codeStart
01388                                         + savedCodeNext + 1;
01389                                 unsigned fixLen = envPtr->codeNext
01390                                         - envPtr->codeStart - savedCodeNext;
01391 
01392                                 TclStoreInt4AtPtr(fixLen, fixPtr);
01393                             }
01394                             goto finishCommand;
01395                         } else {
01396                             if (envPtr->atCmdStart && savedCodeNext != 0) {
01397                                 /*
01398                                  * Decrease the number of commands being
01399                                  * started at the current point. Note that
01400                                  * this depends on the exact layout of the
01401                                  * INST_START_CMD's operands, so be careful!
01402                                  */
01403 
01404                                 unsigned char *fixPtr = envPtr->codeNext - 4;
01405 
01406                                 TclStoreInt4AtPtr(TclGetUInt4AtPtr(fixPtr)-1,
01407                                         fixPtr);
01408                             }
01409 
01410                             /*
01411                              * Restore numCommands and codeNext to their
01412                              * correct values, removing any commands compiled
01413                              * before the failure to produce bytecode got
01414                              * reported. [Bugs 705406 and 735055]
01415                              */
01416 
01417                             envPtr->numCommands = savedNumCmds;
01418                             envPtr->codeNext = envPtr->codeStart+savedCodeNext;
01419                         }
01420                     }
01421 
01422                     /*
01423                      * No compile procedure so push the word. If the command
01424                      * was found, push a CmdName object to reduce runtime
01425                      * lookups. Avoid sharing this literal among different
01426                      * namespaces to reduce shimmering.
01427                      */
01428 
01429                     objIndex = TclRegisterNewNSLiteral(envPtr,
01430                             tokenPtr[1].start, tokenPtr[1].size);
01431                     if (cmdPtr != NULL) {
01432                         TclSetCmdNameObj(interp,
01433                               envPtr->literalArrayPtr[objIndex].objPtr,cmdPtr);
01434                     }
01435                     if ((wordIdx == 0) && (parsePtr->numWords == 1)) {
01436                         /*
01437                          * Single word script: unshare the command name to
01438                          * avoid shimmering between bytecode and cmdName
01439                          * representations [Bug 458361]
01440                          */
01441 
01442                         TclHideLiteral(interp, envPtr, objIndex);
01443                     }
01444                 } else {
01445                     objIndex = TclRegisterNewLiteral(envPtr,
01446                             tokenPtr[1].start, tokenPtr[1].size);
01447                 }
01448                 TclEmitPush(objIndex, envPtr);
01449             } /* for loop */
01450 
01451             /*
01452              * Emit an invoke instruction for the command. We skip this if a
01453              * compile procedure was found for the command.
01454              */
01455 
01456             if (expand) {
01457                 /*
01458                  * The stack depth during argument expansion can only be
01459                  * managed at runtime, as the number of elements in the
01460                  * expanded lists is not known at compile time. We adjust here
01461                  * the stack depth estimate so that it is correct after the
01462                  * command with expanded arguments returns.
01463                  *
01464                  * The end effect of this command's invocation is that all the
01465                  * words of the command are popped from the stack, and the
01466                  * result is pushed: the stack top changes by (1-wordIdx).
01467                  *
01468                  * Note that the estimates are not correct while the command
01469                  * is being prepared and run, INST_EXPAND_STKTOP is not
01470                  * stack-neutral in general.
01471                  */
01472 
01473                 TclEmitOpcode(INST_INVOKE_EXPANDED, envPtr);
01474                 TclAdjustStackDepth((1-wordIdx), envPtr);
01475             } else if (wordIdx > 0) {
01476                 if (wordIdx <= 255) {
01477                     TclEmitInstInt1(INST_INVOKE_STK1, wordIdx, envPtr);
01478                 } else {
01479                     TclEmitInstInt4(INST_INVOKE_STK4, wordIdx, envPtr);
01480                 }
01481             }
01482 
01483             /*
01484              * Update the compilation environment structure and record the
01485              * offsets of the source and code for the command.
01486              */
01487 
01488         finishCommand:
01489             EnterCmdExtentData(envPtr, currCmdIndex, commandLength,
01490                     (envPtr->codeNext-envPtr->codeStart) - startCodeOffset);
01491             isFirstCmd = 0;
01492 
01493             /*
01494              * TIP #280: Free full form of per-word line data and insert the
01495              * reduced form now
01496              */
01497 
01498             ckfree((char *) eclPtr->loc[wlineat].line);
01499             eclPtr->loc[wlineat].line = wlines;
01500         } /* end if parsePtr->numWords > 0 */
01501 
01502         /*
01503          * Advance to the next command in the script.
01504          */
01505 
01506         next = parsePtr->commandStart + parsePtr->commandSize;
01507         bytesLeft -= next - p;
01508         p = next;
01509 
01510         /*
01511          * TIP #280: Track lines in the just compiled command.
01512          */
01513 
01514         TclAdvanceLines(&cmdLine, parsePtr->commandStart, p);
01515         Tcl_FreeParse(parsePtr);
01516         gotParse = 0;
01517     } while (bytesLeft > 0);
01518 
01519     /*
01520      * If the source script yielded no instructions (e.g., if it was empty),
01521      * push an empty string as the command's result.
01522      *
01523      * WARNING: push an unshared object! If the script being compiled is a
01524      * shared empty string, it will otherwise be self-referential and cause
01525      * difficulties with literal management [Bugs 467523, 983660]. We used to
01526      * have special code in TclReleaseLiteral to handle this particular
01527      * self-reference, but now opt for avoiding its creation altogether.
01528      */
01529 
01530     if (envPtr->codeNext == entryCodeNext) {
01531         TclEmitPush(TclAddLiteralObj(envPtr, Tcl_NewObj(), NULL), envPtr);
01532     }
01533 
01534     envPtr->numSrcBytes = (p - script);
01535     TclStackFree(interp, parsePtr);
01536     Tcl_DStringFree(&ds);
01537 }
01538 
01539 /*
01540  *----------------------------------------------------------------------
01541  *
01542  * TclCompileTokens --
01543  *
01544  *      Given an array of tokens parsed from a Tcl command (e.g., the tokens
01545  *      that make up a word) this procedure emits instructions to evaluate the
01546  *      tokens and concatenate their values to form a single result value on
01547  *      the interpreter's runtime evaluation stack.
01548  *
01549  * Results:
01550  *      The return value is a standard Tcl result. If an error occurs, an
01551  *      error message is left in the interpreter's result.
01552  *
01553  * Side effects:
01554  *      Instructions are added to envPtr to push and evaluate the tokens at
01555  *      runtime.
01556  *
01557  *----------------------------------------------------------------------
01558  */
01559 
01560 void
01561 TclCompileTokens(
01562     Tcl_Interp *interp,         /* Used for error and status reporting. */
01563     Tcl_Token *tokenPtr,        /* Pointer to first in an array of tokens to
01564                                  * compile. */
01565     int count,                  /* Number of tokens to consider at tokenPtr.
01566                                  * Must be at least 1. */
01567     CompileEnv *envPtr)         /* Holds the resulting instructions. */
01568 {
01569     Tcl_DString textBuffer;     /* Holds concatenated chars from adjacent
01570                                  * TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */
01571     char buffer[TCL_UTF_MAX];
01572     const char *name, *p;
01573     int numObjsToConcat, nameBytes, localVarName, localVar;
01574     int length, i;
01575     unsigned char *entryCodeNext = envPtr->codeNext;
01576 
01577     Tcl_DStringInit(&textBuffer);
01578     numObjsToConcat = 0;
01579     for ( ;  count > 0;  count--, tokenPtr++) {
01580         switch (tokenPtr->type) {
01581         case TCL_TOKEN_TEXT:
01582             Tcl_DStringAppend(&textBuffer, tokenPtr->start, tokenPtr->size);
01583             break;
01584 
01585         case TCL_TOKEN_BS:
01586             length = Tcl_UtfBackslash(tokenPtr->start, NULL, buffer);
01587             Tcl_DStringAppend(&textBuffer, buffer, length);
01588             break;
01589 
01590         case TCL_TOKEN_COMMAND:
01591             /*
01592              * Push any accumulated chars appearing before the command.
01593              */
01594 
01595             if (Tcl_DStringLength(&textBuffer) > 0) {
01596                 int literal = TclRegisterNewLiteral(envPtr,
01597                         Tcl_DStringValue(&textBuffer),
01598                         Tcl_DStringLength(&textBuffer));
01599 
01600                 TclEmitPush(literal, envPtr);
01601                 numObjsToConcat++;
01602                 Tcl_DStringFree(&textBuffer);
01603             }
01604 
01605             TclCompileScript(interp, tokenPtr->start+1,
01606                     tokenPtr->size-2, envPtr);
01607             numObjsToConcat++;
01608             break;
01609 
01610         case TCL_TOKEN_VARIABLE:
01611             /*
01612              * Push any accumulated chars appearing before the $<var>.
01613              */
01614 
01615             if (Tcl_DStringLength(&textBuffer) > 0) {
01616                 int literal;
01617 
01618                 literal = TclRegisterNewLiteral(envPtr,
01619                         Tcl_DStringValue(&textBuffer),
01620                         Tcl_DStringLength(&textBuffer));
01621                 TclEmitPush(literal, envPtr);
01622                 numObjsToConcat++;
01623                 Tcl_DStringFree(&textBuffer);
01624             }
01625 
01626             /*
01627              * Determine how the variable name should be handled: if it
01628              * contains any namespace qualifiers it is not a local variable
01629              * (localVarName=-1); if it looks like an array element and the
01630              * token has a single component, it should not be created here
01631              * [Bug 569438] (localVarName=0); otherwise, the local variable
01632              * can safely be created (localVarName=1).
01633              */
01634 
01635             name = tokenPtr[1].start;
01636             nameBytes = tokenPtr[1].size;
01637             localVarName = -1;
01638             if (envPtr->procPtr != NULL) {
01639                 localVarName = 1;
01640                 for (i = 0, p = name;  i < nameBytes;  i++, p++) {
01641                     if ((*p == ':') && (i < nameBytes-1) && (*(p+1) == ':')) {
01642                         localVarName = -1;
01643                         break;
01644                     } else if ((*p == '(')
01645                             && (tokenPtr->numComponents == 1)
01646                             && (*(name + nameBytes - 1) == ')')) {
01647                         localVarName = 0;
01648                         break;
01649                     }
01650                 }
01651             }
01652 
01653             /*
01654              * Either push the variable's name, or find its index in the array
01655              * of local variables in a procedure frame.
01656              */
01657 
01658             localVar = -1;
01659             if (localVarName != -1) {
01660                 localVar = TclFindCompiledLocal(name, nameBytes, localVarName,
01661                         envPtr->procPtr);
01662             }
01663             if (localVar < 0) {
01664                 TclEmitPush(TclRegisterNewLiteral(envPtr, name, nameBytes),
01665                         envPtr);
01666             }
01667 
01668             /*
01669              * Emit instructions to load the variable.
01670              */
01671 
01672             if (tokenPtr->numComponents == 1) {
01673                 if (localVar < 0) {
01674                     TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
01675                 } else if (localVar <= 255) {
01676                     TclEmitInstInt1(INST_LOAD_SCALAR1, localVar, envPtr);
01677                 } else {
01678                     TclEmitInstInt4(INST_LOAD_SCALAR4, localVar, envPtr);
01679                 }
01680             } else {
01681                 TclCompileTokens(interp, tokenPtr+2,
01682                         tokenPtr->numComponents-1, envPtr);
01683                 if (localVar < 0) {
01684                     TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);
01685                 } else if (localVar <= 255) {
01686                     TclEmitInstInt1(INST_LOAD_ARRAY1, localVar, envPtr);
01687                 } else {
01688                     TclEmitInstInt4(INST_LOAD_ARRAY4, localVar, envPtr);
01689                 }
01690             }
01691             numObjsToConcat++;
01692             count -= tokenPtr->numComponents;
01693             tokenPtr += tokenPtr->numComponents;
01694             break;
01695 
01696         default:
01697             Tcl_Panic("Unexpected token type in TclCompileTokens: %d; %.*s",
01698                     tokenPtr->type, tokenPtr->size, tokenPtr->start);
01699         }
01700     }
01701 
01702     /*
01703      * Push any accumulated characters appearing at the end.
01704      */
01705 
01706     if (Tcl_DStringLength(&textBuffer) > 0) {
01707         int literal;
01708 
01709         literal = TclRegisterNewLiteral(envPtr, Tcl_DStringValue(&textBuffer),
01710                 Tcl_DStringLength(&textBuffer));
01711         TclEmitPush(literal, envPtr);
01712         numObjsToConcat++;
01713     }
01714 
01715     /*
01716      * If necessary, concatenate the parts of the word.
01717      */
01718 
01719     while (numObjsToConcat > 255) {
01720         TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
01721         numObjsToConcat -= 254; /* concat pushes 1 obj, the result */
01722     }
01723     if (numObjsToConcat > 1) {
01724         TclEmitInstInt1(INST_CONCAT1, numObjsToConcat, envPtr);
01725     }
01726 
01727     /*
01728      * If the tokens yielded no instructions, push an empty string.
01729      */
01730 
01731     if (envPtr->codeNext == entryCodeNext) {
01732         TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
01733     }
01734     Tcl_DStringFree(&textBuffer);
01735 }
01736 
01737 /*
01738  *----------------------------------------------------------------------
01739  *
01740  * TclCompileCmdWord --
01741  *
01742  *      Given an array of parse tokens for a word containing one or more Tcl
01743  *      commands, emit inline instructions to execute them. This procedure
01744  *      differs from TclCompileTokens in that a simple word such as a loop
01745  *      body enclosed in braces is not just pushed as a string, but is itself
01746  *      parsed into tokens and compiled.
01747  *
01748  * Results:
01749  *      The return value is a standard Tcl result. If an error occurs, an
01750  *      error message is left in the interpreter's result.
01751  *
01752  * Side effects:
01753  *      Instructions are added to envPtr to execute the tokens at runtime.
01754  *
01755  *----------------------------------------------------------------------
01756  */
01757 
01758 void
01759 TclCompileCmdWord(
01760     Tcl_Interp *interp,         /* Used for error and status reporting. */
01761     Tcl_Token *tokenPtr,        /* Pointer to first in an array of tokens for
01762                                  * a command word to compile inline. */
01763     int count,                  /* Number of tokens to consider at tokenPtr.
01764                                  * Must be at least 1. */
01765     CompileEnv *envPtr)         /* Holds the resulting instructions. */
01766 {
01767     if ((count == 1) && (tokenPtr->type == TCL_TOKEN_TEXT)) {
01768         /*
01769          * Handle the common case: if there is a single text token, compile it
01770          * into an inline sequence of instructions.
01771          */
01772 
01773         TclCompileScript(interp, tokenPtr->start, tokenPtr->size, envPtr);
01774     } else {
01775         /*
01776          * Multiple tokens or the single token involves substitutions. Emit
01777          * instructions to invoke the eval command procedure at runtime on the
01778          * result of evaluating the tokens.
01779          */
01780 
01781         TclCompileTokens(interp, tokenPtr, count, envPtr);
01782         TclEmitOpcode(INST_EVAL_STK, envPtr);
01783     }
01784 }
01785 
01786 /*
01787  *----------------------------------------------------------------------
01788  *
01789  * TclCompileExprWords --
01790  *
01791  *      Given an array of parse tokens representing one or more words that
01792  *      contain a Tcl expression, emit inline instructions to execute the
01793  *      expression. This procedure differs from TclCompileExpr in that it
01794  *      supports Tcl's two-level substitution semantics for expressions that
01795  *      appear as command words.
01796  *
01797  * Results:
01798  *      The return value is a standard Tcl result. If an error occurs, an
01799  *      error message is left in the interpreter's result.
01800  *
01801  * Side effects:
01802  *      Instructions are added to envPtr to execute the expression.
01803  *
01804  *----------------------------------------------------------------------
01805  */
01806 
01807 void
01808 TclCompileExprWords(
01809     Tcl_Interp *interp,         /* Used for error and status reporting. */
01810     Tcl_Token *tokenPtr,        /* Points to first in an array of word tokens
01811                                  * tokens for the expression to compile
01812                                  * inline. */
01813     int numWords,               /* Number of word tokens starting at tokenPtr.
01814                                  * Must be at least 1. Each word token
01815                                  * contains one or more subtokens. */
01816     CompileEnv *envPtr)         /* Holds the resulting instructions. */
01817 {
01818     Tcl_Token *wordPtr;
01819     int i, concatItems;
01820 
01821     /*
01822      * If the expression is a single word that doesn't require substitutions,
01823      * just compile its string into inline instructions.
01824      */
01825 
01826     if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
01827         TclCompileExpr(interp, tokenPtr[1].start, tokenPtr[1].size, envPtr, 1);
01828         return;
01829     }
01830 
01831     /*
01832      * Emit code to call the expr command proc at runtime. Concatenate the
01833      * (already substituted once) expr tokens with a space between each.
01834      */
01835 
01836     wordPtr = tokenPtr;
01837     for (i = 0;  i < numWords;  i++) {
01838         TclCompileTokens(interp, wordPtr+1, wordPtr->numComponents, envPtr);
01839         if (i < (numWords - 1)) {
01840             TclEmitPush(TclRegisterNewLiteral(envPtr, " ", 1), envPtr);
01841         }
01842         wordPtr += (wordPtr->numComponents + 1);
01843     }
01844     concatItems = 2*numWords - 1;
01845     while (concatItems > 255) {
01846         TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
01847         concatItems -= 254;
01848     }
01849     if (concatItems > 1) {
01850         TclEmitInstInt1(INST_CONCAT1, concatItems, envPtr);
01851     }
01852     TclEmitOpcode(INST_EXPR_STK, envPtr);
01853 }
01854 
01855 /*
01856  *----------------------------------------------------------------------
01857  *
01858  * TclCompileNoOp --
01859  *
01860  *      Function called to compile no-op's
01861  *
01862  * Results:
01863  *      The return value is TCL_OK, indicating successful compilation.
01864  *
01865  * Side effects:
01866  *      Instructions are added to envPtr to execute a no-op at runtime. No
01867  *      result is pushed onto the stack: the compiler has to take care of this
01868  *      itself if the last compiled command is a NoOp.
01869  *
01870  *----------------------------------------------------------------------
01871  */
01872 
01873 int
01874 TclCompileNoOp(
01875     Tcl_Interp *interp,         /* Used for error reporting. */
01876     Tcl_Parse *parsePtr,        /* Points to a parse structure for the command
01877                                  * created by Tcl_ParseCommand. */
01878     Command *cmdPtr,            /* Points to defintion of command being
01879                                  * compiled. */
01880     CompileEnv *envPtr)         /* Holds resulting instructions. */
01881 {
01882     Tcl_Token *tokenPtr;
01883     int i;
01884     int savedStackDepth = envPtr->currStackDepth;
01885 
01886     tokenPtr = parsePtr->tokenPtr;
01887     for(i = 1; i < parsePtr->numWords; i++) {
01888         tokenPtr = tokenPtr + tokenPtr->numComponents + 1;
01889         envPtr->currStackDepth = savedStackDepth;
01890 
01891         if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
01892             TclCompileTokens(interp, tokenPtr+1, tokenPtr->numComponents,
01893                     envPtr);
01894             TclEmitOpcode(INST_POP, envPtr);
01895         }
01896     }
01897     envPtr->currStackDepth = savedStackDepth;
01898     TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
01899     return TCL_OK;
01900 }
01901 
01902 /*
01903  *----------------------------------------------------------------------
01904  *
01905  * TclInitByteCodeObj --
01906  *
01907  *      Create a ByteCode structure and initialize it from a CompileEnv
01908  *      compilation environment structure. The ByteCode structure is smaller
01909  *      and contains just that information needed to execute the bytecode
01910  *      instructions resulting from compiling a Tcl script. The resulting
01911  *      structure is placed in the specified object.
01912  *
01913  * Results:
01914  *      A newly constructed ByteCode object is stored in the internal
01915  *      representation of the objPtr.
01916  *
01917  * Side effects:
01918  *      A single heap object is allocated to hold the new ByteCode structure
01919  *      and its code, object, command location, and aux data arrays. Note that
01920  *      "ownership" (i.e., the pointers to) the Tcl objects and aux data items
01921  *      will be handed over to the new ByteCode structure from the CompileEnv
01922  *      structure.
01923  *
01924  *----------------------------------------------------------------------
01925  */
01926 
01927 void
01928 TclInitByteCodeObj(
01929     Tcl_Obj *objPtr,            /* Points object that should be initialized,
01930                                  * and whose string rep contains the source
01931                                  * code. */
01932     register CompileEnv *envPtr)/* Points to the CompileEnv structure from
01933                                  * which to create a ByteCode structure. */
01934 {
01935     register ByteCode *codePtr;
01936     size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes;
01937     size_t auxDataArrayBytes, structureSize;
01938     register unsigned char *p;
01939 #ifdef TCL_COMPILE_DEBUG
01940     unsigned char *nextPtr;
01941 #endif
01942     int numLitObjects = envPtr->literalArrayNext;
01943     Namespace *namespacePtr;
01944     int i, isNew;
01945     Interp *iPtr;
01946 
01947     iPtr = envPtr->iPtr;
01948 
01949     codeBytes = (envPtr->codeNext - envPtr->codeStart);
01950     objArrayBytes = (envPtr->literalArrayNext * sizeof(Tcl_Obj *));
01951     exceptArrayBytes = (envPtr->exceptArrayNext * sizeof(ExceptionRange));
01952     auxDataArrayBytes = (envPtr->auxDataArrayNext * sizeof(AuxData));
01953     cmdLocBytes = GetCmdLocEncodingSize(envPtr);
01954 
01955     /*
01956      * Compute the total number of bytes needed for this bytecode.
01957      */
01958 
01959     structureSize = sizeof(ByteCode);
01960     structureSize += TCL_ALIGN(codeBytes);        /* align object array */
01961     structureSize += TCL_ALIGN(objArrayBytes);    /* align exc range arr */
01962     structureSize += TCL_ALIGN(exceptArrayBytes); /* align AuxData array */
01963     structureSize += auxDataArrayBytes;
01964     structureSize += cmdLocBytes;
01965 
01966     if (envPtr->iPtr->varFramePtr != NULL) {
01967         namespacePtr = envPtr->iPtr->varFramePtr->nsPtr;
01968     } else {
01969         namespacePtr = envPtr->iPtr->globalNsPtr;
01970     }
01971 
01972     p = (unsigned char *) ckalloc((size_t) structureSize);
01973     codePtr = (ByteCode *) p;
01974     codePtr->interpHandle = TclHandlePreserve(iPtr->handle);
01975     codePtr->compileEpoch = iPtr->compileEpoch;
01976     codePtr->nsPtr = namespacePtr;
01977     codePtr->nsEpoch = namespacePtr->resolverEpoch;
01978     codePtr->refCount = 1;
01979     if (namespacePtr->compiledVarResProc || iPtr->resolverPtr) {
01980         codePtr->flags = TCL_BYTECODE_RESOLVE_VARS;
01981     } else {
01982         codePtr->flags = 0;
01983     }
01984     codePtr->source = envPtr->source;
01985     codePtr->procPtr = envPtr->procPtr;
01986 
01987     codePtr->numCommands = envPtr->numCommands;
01988     codePtr->numSrcBytes = envPtr->numSrcBytes;
01989     codePtr->numCodeBytes = codeBytes;
01990     codePtr->numLitObjects = numLitObjects;
01991     codePtr->numExceptRanges = envPtr->exceptArrayNext;
01992     codePtr->numAuxDataItems = envPtr->auxDataArrayNext;
01993     codePtr->numCmdLocBytes = cmdLocBytes;
01994     codePtr->maxExceptDepth = envPtr->maxExceptDepth;
01995     codePtr->maxStackDepth = envPtr->maxStackDepth;
01996 
01997     p += sizeof(ByteCode);
01998     codePtr->codeStart = p;
01999     memcpy(p, envPtr->codeStart, (size_t) codeBytes);
02000 
02001     p += TCL_ALIGN(codeBytes);          /* align object array */
02002     codePtr->objArrayPtr = (Tcl_Obj **) p;
02003     for (i = 0;  i < numLitObjects;  i++) {
02004         codePtr->objArrayPtr[i] = envPtr->literalArrayPtr[i].objPtr;
02005     }
02006 
02007     p += TCL_ALIGN(objArrayBytes);      /* align exception range array */
02008     if (exceptArrayBytes > 0) {
02009         codePtr->exceptArrayPtr = (ExceptionRange *) p;
02010         memcpy(p, envPtr->exceptArrayPtr, (size_t) exceptArrayBytes);
02011     } else {
02012         codePtr->exceptArrayPtr = NULL;
02013     }
02014 
02015     p += TCL_ALIGN(exceptArrayBytes);   /* align AuxData array */
02016     if (auxDataArrayBytes > 0) {
02017         codePtr->auxDataArrayPtr = (AuxData *) p;
02018         memcpy(p, envPtr->auxDataArrayPtr, (size_t) auxDataArrayBytes);
02019     } else {
02020         codePtr->auxDataArrayPtr = NULL;
02021     }
02022 
02023     p += auxDataArrayBytes;
02024 #ifndef TCL_COMPILE_DEBUG
02025     EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
02026 #else
02027     nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
02028     if (((size_t)(nextPtr - p)) != cmdLocBytes) {
02029         Tcl_Panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d", (nextPtr - p), cmdLocBytes);
02030     }
02031 #endif
02032 
02033     /*
02034      * Record various compilation-related statistics about the new ByteCode
02035      * structure. Don't include overhead for statistics-related fields.
02036      */
02037 
02038 #ifdef TCL_COMPILE_STATS
02039     codePtr->structureSize = structureSize
02040             - (sizeof(size_t) + sizeof(Tcl_Time));
02041     Tcl_GetTime(&(codePtr->createTime));
02042 
02043     RecordByteCodeStats(codePtr);
02044 #endif /* TCL_COMPILE_STATS */
02045 
02046     /*
02047      * Free the old internal rep then convert the object to a bytecode object
02048      * by making its internal rep point to the just compiled ByteCode.
02049      */
02050 
02051     TclFreeIntRep(objPtr);
02052     objPtr->internalRep.otherValuePtr = (void *) codePtr;
02053     objPtr->typePtr = &tclByteCodeType;
02054 
02055     /*
02056      * TIP #280. Associate the extended per-word line information with the
02057      * byte code object (internal rep), for use with the bc compiler.
02058      */
02059 
02060     Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->lineBCPtr, (char *) codePtr,
02061             &isNew), envPtr->extCmdMapPtr);
02062     envPtr->extCmdMapPtr = NULL;
02063 
02064     codePtr->localCachePtr = NULL;
02065 }
02066 
02067 /*
02068  *----------------------------------------------------------------------
02069  *
02070  * TclFindCompiledLocal --
02071  *
02072  *      This procedure is called at compile time to look up and optionally
02073  *      allocate an entry ("slot") for a variable in a procedure's array of
02074  *      local variables. If the variable's name is NULL, a new temporary
02075  *      variable is always created. (Such temporary variables can only be
02076  *      referenced using their slot index.)
02077  *
02078  * Results:
02079  *      If create is 0 and the name is non-NULL, then if the variable is
02080  *      found, the index of its entry in the procedure's array of local
02081  *      variables is returned; otherwise -1 is returned. If name is NULL, the
02082  *      index of a new temporary variable is returned. Finally, if create is 1
02083  *      and name is non-NULL, the index of a new entry is returned.
02084  *
02085  * Side effects:
02086  *      Creates and registers a new local variable if create is 1 and the
02087  *      variable is unknown, or if the name is NULL.
02088  *
02089  *----------------------------------------------------------------------
02090  */
02091 
02092 int
02093 TclFindCompiledLocal(
02094     register const char *name,  /* Points to first character of the name of a
02095                                  * scalar or array variable. If NULL, a
02096                                  * temporary var should be created. */
02097     int nameBytes,              /* Number of bytes in the name. */
02098     int create,                 /* If 1, allocate a local frame entry for the
02099                                  * variable if it is new. */
02100     register Proc *procPtr)     /* Points to structure describing procedure
02101                                  * containing the variable reference. */
02102 {
02103     register CompiledLocal *localPtr;
02104     int localVar = -1;
02105     register int i;
02106 
02107     /*
02108      * If not creating a temporary, does a local variable of the specified
02109      * name already exist?
02110      */
02111 
02112     if (name != NULL) {
02113         int localCt = procPtr->numCompiledLocals;
02114 
02115         localPtr = procPtr->firstLocalPtr;
02116         for (i = 0;  i < localCt;  i++) {
02117             if (!TclIsVarTemporary(localPtr)) {
02118                 char *localName = localPtr->name;
02119 
02120                 if ((nameBytes == localPtr->nameLength) &&
02121                         (strncmp(name,localName,(unsigned)nameBytes) == 0)) {
02122                     return i;
02123                 }
02124             }
02125             localPtr = localPtr->nextPtr;
02126         }
02127     }
02128 
02129     /*
02130      * Create a new variable if appropriate.
02131      */
02132 
02133     if (create || (name == NULL)) {
02134         localVar = procPtr->numCompiledLocals;
02135         localPtr = (CompiledLocal *) ckalloc((unsigned)
02136                 (sizeof(CompiledLocal) - sizeof(localPtr->name)
02137                 + nameBytes + 1));
02138         if (procPtr->firstLocalPtr == NULL) {
02139             procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
02140         } else {
02141             procPtr->lastLocalPtr->nextPtr = localPtr;
02142             procPtr->lastLocalPtr = localPtr;
02143         }
02144         localPtr->nextPtr = NULL;
02145         localPtr->nameLength = nameBytes;
02146         localPtr->frameIndex = localVar;
02147         localPtr->flags = 0;
02148         if (name == NULL) {
02149             localPtr->flags |= VAR_TEMPORARY;
02150         }
02151         localPtr->defValuePtr = NULL;
02152         localPtr->resolveInfo = NULL;
02153 
02154         if (name != NULL) {
02155             memcpy(localPtr->name, name, (size_t) nameBytes);
02156         }
02157         localPtr->name[nameBytes] = '\0';
02158         procPtr->numCompiledLocals++;
02159     }
02160     return localVar;
02161 }
02162 
02163 /*
02164  *----------------------------------------------------------------------
02165  *
02166  * TclExpandCodeArray --
02167  *
02168  *      Procedure that uses malloc to allocate more storage for a CompileEnv's
02169  *      code array.
02170  *
02171  * Results:
02172  *      None.
02173  *
02174  * Side effects:
02175  *      The byte code array in *envPtr is reallocated to a new array of double
02176  *      the size, and if envPtr->mallocedCodeArray is non-zero the old array
02177  *      is freed. Byte codes are copied from the old array to the new one.
02178  *
02179  *----------------------------------------------------------------------
02180  */
02181 
02182 void
02183 TclExpandCodeArray(
02184     void *envArgPtr)            /* Points to the CompileEnv whose code array
02185                                  * must be enlarged. */
02186 {
02187     CompileEnv *envPtr = (CompileEnv *) envArgPtr;
02188                                 /* The CompileEnv containing the code array to
02189                                  * be doubled in size. */
02190 
02191     /*
02192      * envPtr->codeNext is equal to envPtr->codeEnd. The currently defined
02193      * code bytes are stored between envPtr->codeStart and envPtr->codeNext-1
02194      * [inclusive].
02195      */
02196 
02197     size_t currBytes = (envPtr->codeNext - envPtr->codeStart);
02198     size_t newBytes = 2*(envPtr->codeEnd - envPtr->codeStart);
02199 
02200     if (envPtr->mallocedCodeArray) {
02201         envPtr->codeStart = (unsigned char *)
02202                 ckrealloc((char *)envPtr->codeStart, newBytes);
02203     } else {
02204         /*
02205          * envPtr->codeStart isn't a ckalloc'd pointer, so we must
02206          * code a ckrealloc equivalent for ourselves.
02207          */
02208         unsigned char *newPtr = (unsigned char *) ckalloc((unsigned) newBytes);
02209         memcpy(newPtr, envPtr->codeStart, currBytes);
02210         envPtr->codeStart = newPtr;
02211         envPtr->mallocedCodeArray = 1;
02212     }
02213 
02214     envPtr->codeNext = (envPtr->codeStart + currBytes);
02215     envPtr->codeEnd = (envPtr->codeStart + newBytes);
02216 }
02217 
02218 /*
02219  *----------------------------------------------------------------------
02220  *
02221  * EnterCmdStartData --
02222  *
02223  *      Registers the starting source and bytecode location of a command. This
02224  *      information is used at runtime to map between instruction pc and
02225  *      source locations.
02226  *
02227  * Results:
02228  *      None.
02229  *
02230  * Side effects:
02231  *      Inserts source and code location information into the compilation
02232  *      environment envPtr for the command at index cmdIndex. The compilation
02233  *      environment's CmdLocation array is grown if necessary.
02234  *
02235  *----------------------------------------------------------------------
02236  */
02237 
02238 static void
02239 EnterCmdStartData(
02240     CompileEnv *envPtr,         /* Points to the compilation environment
02241                                  * structure in which to enter command
02242                                  * location information. */
02243     int cmdIndex,               /* Index of the command whose start data is
02244                                  * being set. */
02245     int srcOffset,              /* Offset of first char of the command. */
02246     int codeOffset)             /* Offset of first byte of command code. */
02247 {
02248     CmdLocation *cmdLocPtr;
02249 
02250     if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
02251         Tcl_Panic("EnterCmdStartData: bad command index %d", cmdIndex);
02252     }
02253 
02254     if (cmdIndex >= envPtr->cmdMapEnd) {
02255         /*
02256          * Expand the command location array by allocating more storage from
02257          * the heap. The currently allocated CmdLocation entries are stored
02258          * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).
02259          */
02260 
02261         size_t currElems = envPtr->cmdMapEnd;
02262         size_t newElems = 2*currElems;
02263         size_t currBytes = currElems * sizeof(CmdLocation);
02264         size_t newBytes = newElems * sizeof(CmdLocation);
02265 
02266         if (envPtr->mallocedCmdMap) {
02267             envPtr->cmdMapPtr = (CmdLocation *)
02268                     ckrealloc((char *) envPtr->cmdMapPtr, newBytes);
02269         } else {
02270             /*
02271              * envPtr->cmdMapPtr isn't a ckalloc'd pointer, so we must
02272              * code a ckrealloc equivalent for ourselves.
02273              */
02274             CmdLocation *newPtr = (CmdLocation *) ckalloc((unsigned) newBytes);
02275             memcpy(newPtr, envPtr->cmdMapPtr, currBytes);
02276             envPtr->cmdMapPtr = newPtr;
02277             envPtr->mallocedCmdMap = 1;
02278         }
02279         envPtr->cmdMapEnd = newElems;
02280     }
02281 
02282     if (cmdIndex > 0) {
02283         if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {
02284             Tcl_Panic("EnterCmdStartData: cmd map not sorted by code offset");
02285         }
02286     }
02287 
02288     cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
02289     cmdLocPtr->codeOffset = codeOffset;
02290     cmdLocPtr->srcOffset = srcOffset;
02291     cmdLocPtr->numSrcBytes = -1;
02292     cmdLocPtr->numCodeBytes = -1;
02293 }
02294 
02295 /*
02296  *----------------------------------------------------------------------
02297  *
02298  * EnterCmdExtentData --
02299  *
02300  *      Registers the source and bytecode length for a command. This
02301  *      information is used at runtime to map between instruction pc and
02302  *      source locations.
02303  *
02304  * Results:
02305  *      None.
02306  *
02307  * Side effects:
02308  *      Inserts source and code length information into the compilation
02309  *      environment envPtr for the command at index cmdIndex. Starting source
02310  *      and bytecode information for the command must already have been
02311  *      registered.
02312  *
02313  *----------------------------------------------------------------------
02314  */
02315 
02316 static void
02317 EnterCmdExtentData(
02318     CompileEnv *envPtr,         /* Points to the compilation environment
02319                                  * structure in which to enter command
02320                                  * location information. */
02321     int cmdIndex,               /* Index of the command whose source and code
02322                                  * length data is being set. */
02323     int numSrcBytes,            /* Number of command source chars. */
02324     int numCodeBytes)           /* Offset of last byte of command code. */
02325 {
02326     CmdLocation *cmdLocPtr;
02327 
02328     if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
02329         Tcl_Panic("EnterCmdExtentData: bad command index %d", cmdIndex);
02330     }
02331 
02332     if (cmdIndex > envPtr->cmdMapEnd) {
02333         Tcl_Panic("EnterCmdExtentData: missing start data for command %d",
02334                 cmdIndex);
02335     }
02336 
02337     cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
02338     cmdLocPtr->numSrcBytes = numSrcBytes;
02339     cmdLocPtr->numCodeBytes = numCodeBytes;
02340 }
02341 
02342 /*
02343  *----------------------------------------------------------------------
02344  * TIP #280
02345  *
02346  * EnterCmdWordData --
02347  *
02348  *      Registers the lines for the words of a command. This information is
02349  *      used at runtime by 'info frame'.
02350  *
02351  * Results:
02352  *      None.
02353  *
02354  * Side effects:
02355  *      Inserts word location information into the compilation environment
02356  *      envPtr for the command at index cmdIndex. The compilation
02357  *      environment's ExtCmdLoc.ECL array is grown if necessary.
02358  *
02359  *----------------------------------------------------------------------
02360  */
02361 
02362 static void
02363 EnterCmdWordData(
02364     ExtCmdLoc *eclPtr,          /* Points to the map environment structure in
02365                                  * which to enter command location
02366                                  * information. */
02367     int srcOffset,              /* Offset of first char of the command. */
02368     Tcl_Token *tokenPtr,
02369     const char *cmd,
02370     int len,
02371     int numWords,
02372     int line,
02373     int **wlines)
02374 {
02375     ECL *ePtr;
02376     const char *last;
02377     int wordIdx, wordLine, *wwlines;
02378 
02379     if (eclPtr->nuloc >= eclPtr->nloc) {
02380         /*
02381          * Expand the ECL array by allocating more storage from the heap. The
02382          * currently allocated ECL entries are stored from eclPtr->loc[0] up
02383          * to eclPtr->loc[eclPtr->nuloc-1] (inclusive).
02384          */
02385 
02386         size_t currElems = eclPtr->nloc;
02387         size_t newElems = (currElems ? 2*currElems : 1);
02388         size_t newBytes = newElems * sizeof(ECL);
02389 
02390         eclPtr->loc = (ECL *) ckrealloc((char *)(eclPtr->loc), newBytes);
02391         eclPtr->nloc = newElems;
02392     }
02393 
02394     ePtr = &eclPtr->loc[eclPtr->nuloc];
02395     ePtr->srcOffset = srcOffset;
02396     ePtr->line = (int *) ckalloc(numWords * sizeof(int));
02397     ePtr->nline = numWords;
02398     wwlines = (int *) ckalloc(numWords * sizeof(int));
02399 
02400     last = cmd;
02401     wordLine = line;
02402     for (wordIdx=0 ; wordIdx<numWords;
02403             wordIdx++, tokenPtr += tokenPtr->numComponents + 1) {
02404         TclAdvanceLines(&wordLine, last, tokenPtr->start);
02405         wwlines[wordIdx] =
02406                 (TclWordKnownAtCompileTime(tokenPtr, NULL) ? wordLine : -1);
02407         ePtr->line[wordIdx] = wordLine;
02408         last = tokenPtr->start;
02409     }
02410 
02411     *wlines = wwlines;
02412     eclPtr->nuloc ++;
02413 }
02414 
02415 /*
02416  *----------------------------------------------------------------------
02417  *
02418  * TclCreateExceptRange --
02419  *
02420  *      Procedure that allocates and initializes a new ExceptionRange
02421  *      structure of the specified kind in a CompileEnv.
02422  *
02423  * Results:
02424  *      Returns the index for the newly created ExceptionRange.
02425  *
02426  * Side effects:
02427  *      If there is not enough room in the CompileEnv's ExceptionRange array,
02428  *      the array in expanded: a new array of double the size is allocated, if
02429  *      envPtr->mallocedExceptArray is non-zero the old array is freed, and
02430  *      ExceptionRange entries are copied from the old array to the new one.
02431  *
02432  *----------------------------------------------------------------------
02433  */
02434 
02435 int
02436 TclCreateExceptRange(
02437     ExceptionRangeType type,    /* The kind of ExceptionRange desired. */
02438     register CompileEnv *envPtr)/* Points to CompileEnv for which to create a
02439                                  * new ExceptionRange structure. */
02440 {
02441     register ExceptionRange *rangePtr;
02442     int index = envPtr->exceptArrayNext;
02443 
02444     if (index >= envPtr->exceptArrayEnd) {
02445         /*
02446          * Expand the ExceptionRange array. The currently allocated entries
02447          * are stored between elements 0 and (envPtr->exceptArrayNext - 1)
02448          * [inclusive].
02449          */
02450 
02451         size_t currBytes =
02452                 envPtr->exceptArrayNext * sizeof(ExceptionRange);
02453         int newElems = 2*envPtr->exceptArrayEnd;
02454         size_t newBytes = newElems * sizeof(ExceptionRange);
02455 
02456         if (envPtr->mallocedExceptArray) {
02457             envPtr->exceptArrayPtr = (ExceptionRange *)
02458                     ckrealloc((char *)(envPtr->exceptArrayPtr), newBytes);
02459         } else {
02460             /*
02461              * envPtr->exceptArrayPtr isn't a ckalloc'd pointer, so we must
02462              * code a ckrealloc equivalent for ourselves.
02463              */
02464             ExceptionRange *newPtr = (ExceptionRange *)
02465                     ckalloc((unsigned) newBytes);
02466             memcpy(newPtr, envPtr->exceptArrayPtr, currBytes);
02467             envPtr->exceptArrayPtr = newPtr;
02468             envPtr->mallocedExceptArray = 1;
02469         }
02470         envPtr->exceptArrayEnd = newElems;
02471     }
02472     envPtr->exceptArrayNext++;
02473 
02474     rangePtr = &(envPtr->exceptArrayPtr[index]);
02475     rangePtr->type = type;
02476     rangePtr->nestingLevel = envPtr->exceptDepth;
02477     rangePtr->codeOffset = -1;
02478     rangePtr->numCodeBytes = -1;
02479     rangePtr->breakOffset = -1;
02480     rangePtr->continueOffset = -1;
02481     rangePtr->catchOffset = -1;
02482     return index;
02483 }
02484 
02485 /*
02486  *----------------------------------------------------------------------
02487  *
02488  * TclCreateAuxData --
02489  *
02490  *      Procedure that allocates and initializes a new AuxData structure in a
02491  *      CompileEnv's array of compilation auxiliary data records. These
02492  *      AuxData records hold information created during compilation by
02493  *      CompileProcs and used by instructions during execution.
02494  *
02495  * Results:
02496  *      Returns the index for the newly created AuxData structure.
02497  *
02498  * Side effects:
02499  *      If there is not enough room in the CompileEnv's AuxData array, the
02500  *      AuxData array in expanded: a new array of double the size is
02501  *      allocated, if envPtr->mallocedAuxDataArray is non-zero the old array
02502  *      is freed, and AuxData entries are copied from the old array to the new
02503  *      one.
02504  *
02505  *----------------------------------------------------------------------
02506  */
02507 
02508 int
02509 TclCreateAuxData(
02510     ClientData clientData,      /* The compilation auxiliary data to store in
02511                                  * the new aux data record. */
02512     AuxDataType *typePtr,       /* Pointer to the type to attach to this
02513                                  * AuxData */
02514     register CompileEnv *envPtr)/* Points to the CompileEnv for which a new
02515                                  * aux data structure is to be allocated. */
02516 {
02517     int index;                  /* Index for the new AuxData structure. */
02518     register AuxData *auxDataPtr;
02519                                 /* Points to the new AuxData structure */
02520 
02521     index = envPtr->auxDataArrayNext;
02522     if (index >= envPtr->auxDataArrayEnd) {
02523         /*
02524          * Expand the AuxData array. The currently allocated entries are
02525          * stored between elements 0 and (envPtr->auxDataArrayNext - 1)
02526          * [inclusive].
02527          */
02528 
02529         size_t currBytes = envPtr->auxDataArrayNext * sizeof(AuxData);
02530         int newElems = 2*envPtr->auxDataArrayEnd;
02531         size_t newBytes = newElems * sizeof(AuxData);
02532 
02533         if (envPtr->mallocedAuxDataArray) {
02534             envPtr->auxDataArrayPtr = (AuxData *)
02535                     ckrealloc((char *)(envPtr->auxDataArrayPtr), newBytes);
02536         } else {
02537             /*
02538              * envPtr->auxDataArrayPtr isn't a ckalloc'd pointer, so we must
02539              * code a ckrealloc equivalent for ourselves.
02540              */
02541             AuxData *newPtr = (AuxData *) ckalloc((unsigned) newBytes);
02542             memcpy(newPtr, envPtr->auxDataArrayPtr, currBytes);
02543             envPtr->auxDataArrayPtr = newPtr;
02544             envPtr->mallocedAuxDataArray = 1;
02545         }
02546         envPtr->auxDataArrayEnd = newElems;
02547     }
02548     envPtr->auxDataArrayNext++;
02549 
02550     auxDataPtr = &(envPtr->auxDataArrayPtr[index]);
02551     auxDataPtr->clientData = clientData;
02552     auxDataPtr->type = typePtr;
02553     return index;
02554 }
02555 
02556 /*
02557  *----------------------------------------------------------------------
02558  *
02559  * TclInitJumpFixupArray --
02560  *
02561  *      Initializes a JumpFixupArray structure to hold some number of jump
02562  *      fixup entries.
02563  *
02564  * Results:
02565  *      None.
02566  *
02567  * Side effects:
02568  *      The JumpFixupArray structure is initialized.
02569  *
02570  *----------------------------------------------------------------------
02571  */
02572 
02573 void
02574 TclInitJumpFixupArray(
02575     register JumpFixupArray *fixupArrayPtr)
02576                                 /* Points to the JumpFixupArray structure to
02577                                  * initialize. */
02578 {
02579     fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace;
02580     fixupArrayPtr->next = 0;
02581     fixupArrayPtr->end = (JUMPFIXUP_INIT_ENTRIES - 1);
02582     fixupArrayPtr->mallocedArray = 0;
02583 }
02584 
02585 /*
02586  *----------------------------------------------------------------------
02587  *
02588  * TclExpandJumpFixupArray --
02589  *
02590  *      Procedure that uses malloc to allocate more storage for a jump fixup
02591  *      array.
02592  *
02593  * Results:
02594  *      None.
02595  *
02596  * Side effects:
02597  *      The jump fixup array in *fixupArrayPtr is reallocated to a new array
02598  *      of double the size, and if fixupArrayPtr->mallocedArray is non-zero
02599  *      the old array is freed. Jump fixup structures are copied from the old
02600  *      array to the new one.
02601  *
02602  *----------------------------------------------------------------------
02603  */
02604 
02605 void
02606 TclExpandJumpFixupArray(
02607     register JumpFixupArray *fixupArrayPtr)
02608                                 /* Points to the JumpFixupArray structure
02609                                  * to enlarge. */
02610 {
02611     /*
02612      * The currently allocated jump fixup entries are stored from fixup[0] up
02613      * to fixup[fixupArrayPtr->fixupNext] (*not* inclusive). We assume
02614      * fixupArrayPtr->fixupNext is equal to fixupArrayPtr->fixupEnd.
02615      */
02616 
02617     size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup);
02618     int newElems = 2*(fixupArrayPtr->end + 1);
02619     size_t newBytes = newElems * sizeof(JumpFixup);
02620 
02621     if (fixupArrayPtr->mallocedArray) {
02622         fixupArrayPtr->fixup = (JumpFixup *)
02623                 ckrealloc((char *)(fixupArrayPtr->fixup), newBytes);
02624     } else {
02625         /*
02626          * fixupArrayPtr->fixup isn't a ckalloc'd pointer, so we must
02627          * code a ckrealloc equivalent for ourselves.
02628          */
02629         JumpFixup *newPtr = (JumpFixup *) ckalloc((unsigned) newBytes);
02630         memcpy(newPtr, fixupArrayPtr->fixup, currBytes);
02631         fixupArrayPtr->fixup = newPtr;
02632         fixupArrayPtr->mallocedArray = 1;
02633     }
02634     fixupArrayPtr->end = newElems;
02635 }
02636 
02637 /*
02638  *----------------------------------------------------------------------
02639  *
02640  * TclFreeJumpFixupArray --
02641  *
02642  *      Free any storage allocated in a jump fixup array structure.
02643  *
02644  * Results:
02645  *      None.
02646  *
02647  * Side effects:
02648  *      Allocated storage in the JumpFixupArray structure is freed.
02649  *
02650  *----------------------------------------------------------------------
02651  */
02652 
02653 void
02654 TclFreeJumpFixupArray(
02655     register JumpFixupArray *fixupArrayPtr)
02656                                 /* Points to the JumpFixupArray structure to
02657                                  * free. */
02658 {
02659     if (fixupArrayPtr->mallocedArray) {
02660         ckfree((char *) fixupArrayPtr->fixup);
02661     }
02662 }
02663 
02664 /*
02665  *----------------------------------------------------------------------
02666  *
02667  * TclEmitForwardJump --
02668  *
02669  *      Procedure to emit a two-byte forward jump of kind "jumpType". Since
02670  *      the jump may later have to be grown to five bytes if the jump target
02671  *      is more than, say, 127 bytes away, this procedure also initializes a
02672  *      JumpFixup record with information about the jump.
02673  *
02674  * Results:
02675  *      None.
02676  *
02677  * Side effects:
02678  *      The JumpFixup record pointed to by "jumpFixupPtr" is initialized with
02679  *      information needed later if the jump is to be grown. Also, a two byte
02680  *      jump of the designated type is emitted at the current point in the
02681  *      bytecode stream.
02682  *
02683  *----------------------------------------------------------------------
02684  */
02685 
02686 void
02687 TclEmitForwardJump(
02688     CompileEnv *envPtr,         /* Points to the CompileEnv structure that
02689                                  * holds the resulting instruction. */
02690     TclJumpType jumpType,       /* Indicates the kind of jump: if true or
02691                                  * false or unconditional. */
02692     JumpFixup *jumpFixupPtr)    /* Points to the JumpFixup structure to
02693                                  * initialize with information about this
02694                                  * forward jump. */
02695 {
02696     /*
02697      * Initialize the JumpFixup structure:
02698      *    - codeOffset is offset of first byte of jump below
02699      *    - cmdIndex is index of the command after the current one
02700      *    - exceptIndex is the index of the first ExceptionRange after the
02701      *      current one.
02702      */
02703 
02704     jumpFixupPtr->jumpType = jumpType;
02705     jumpFixupPtr->codeOffset = (envPtr->codeNext - envPtr->codeStart);
02706     jumpFixupPtr->cmdIndex = envPtr->numCommands;
02707     jumpFixupPtr->exceptIndex = envPtr->exceptArrayNext;
02708 
02709     switch (jumpType) {
02710     case TCL_UNCONDITIONAL_JUMP:
02711         TclEmitInstInt1(INST_JUMP1, 0, envPtr);
02712         break;
02713     case TCL_TRUE_JUMP:
02714         TclEmitInstInt1(INST_JUMP_TRUE1, 0, envPtr);
02715         break;
02716     default:
02717         TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
02718         break;
02719     }
02720 }
02721 
02722 /*
02723  *----------------------------------------------------------------------
02724  *
02725  * TclFixupForwardJump --
02726  *
02727  *      Procedure that updates a previously-emitted forward jump to jump a
02728  *      specified number of bytes, "jumpDist". If necessary, the jump is grown
02729  *      from two to five bytes; this is done if the jump distance is greater
02730  *      than "distThreshold" (normally 127 bytes). The jump is described by a
02731  *      JumpFixup record previously initialized by TclEmitForwardJump.
02732  *
02733  * Results:
02734  *      1 if the jump was grown and subsequent instructions had to be moved;
02735  *      otherwise 0. This result is returned to allow callers to update any
02736  *      additional code offsets they may hold.
02737  *
02738  * Side effects:
02739  *      The jump may be grown and subsequent instructions moved. If this
02740  *      happens, the code offsets for any commands and any ExceptionRange
02741  *      records between the jump and the current code address will be updated
02742  *      to reflect the moved code. Also, the bytecode instruction array in the
02743  *      CompileEnv structure may be grown and reallocated.
02744  *
02745  *----------------------------------------------------------------------
02746  */
02747 
02748 int
02749 TclFixupForwardJump(
02750     CompileEnv *envPtr,         /* Points to the CompileEnv structure that
02751                                  * holds the resulting instruction. */
02752     JumpFixup *jumpFixupPtr,    /* Points to the JumpFixup structure that
02753                                  * describes the forward jump. */
02754     int jumpDist,               /* Jump distance to set in jump instr. */
02755     int distThreshold)          /* Maximum distance before the two byte jump
02756                                  * is grown to five bytes. */
02757 {
02758     unsigned char *jumpPc, *p;
02759     int firstCmd, lastCmd, firstRange, lastRange, k;
02760     unsigned numBytes;
02761 
02762     if (jumpDist <= distThreshold) {
02763         jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
02764         switch (jumpFixupPtr->jumpType) {
02765         case TCL_UNCONDITIONAL_JUMP:
02766             TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc);
02767             break;
02768         case TCL_TRUE_JUMP:
02769             TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc);
02770             break;
02771         default:
02772             TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc);
02773             break;
02774         }
02775         return 0;
02776     }
02777 
02778     /*
02779      * We must grow the jump then move subsequent instructions down. Note that
02780      * if we expand the space for generated instructions, code addresses might
02781      * change; be careful about updating any of these addresses held in
02782      * variables.
02783      */
02784 
02785     if ((envPtr->codeNext + 3) > envPtr->codeEnd) {
02786         TclExpandCodeArray(envPtr);
02787     }
02788     jumpPc = (envPtr->codeStart + jumpFixupPtr->codeOffset);
02789     numBytes = envPtr->codeNext-jumpPc-2;
02790     p = jumpPc+2;
02791     memmove(p+3, p, numBytes);
02792 
02793     envPtr->codeNext += 3;
02794     jumpDist += 3;
02795     switch (jumpFixupPtr->jumpType) {
02796     case TCL_UNCONDITIONAL_JUMP:
02797         TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);
02798         break;
02799     case TCL_TRUE_JUMP:
02800         TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);
02801         break;
02802     default:
02803         TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);
02804         break;
02805     }
02806 
02807     /*
02808      * Adjust the code offsets for any commands and any ExceptionRange records
02809      * between the jump and the current code address.
02810      */
02811 
02812     firstCmd = jumpFixupPtr->cmdIndex;
02813     lastCmd = (envPtr->numCommands - 1);
02814     if (firstCmd < lastCmd) {
02815         for (k = firstCmd;  k <= lastCmd;  k++) {
02816             (envPtr->cmdMapPtr[k]).codeOffset += 3;
02817         }
02818     }
02819 
02820     firstRange = jumpFixupPtr->exceptIndex;
02821     lastRange = (envPtr->exceptArrayNext - 1);
02822     for (k = firstRange;  k <= lastRange;  k++) {
02823         ExceptionRange *rangePtr = &(envPtr->exceptArrayPtr[k]);
02824         rangePtr->codeOffset += 3;
02825 
02826         switch (rangePtr->type) {
02827         case LOOP_EXCEPTION_RANGE:
02828             rangePtr->breakOffset += 3;
02829             if (rangePtr->continueOffset != -1) {
02830                 rangePtr->continueOffset += 3;
02831             }
02832             break;
02833         case CATCH_EXCEPTION_RANGE:
02834             rangePtr->catchOffset += 3;
02835             break;
02836         default:
02837             Tcl_Panic("TclFixupForwardJump: bad ExceptionRange type %d",
02838                     rangePtr->type);
02839         }
02840     }
02841     return 1;                   /* the jump was grown */
02842 }
02843 
02844 /*
02845  *----------------------------------------------------------------------
02846  *
02847  * TclGetInstructionTable --
02848  *
02849  *      Returns a pointer to the table describing Tcl bytecode instructions.
02850  *      This procedure is defined so that clients can access the pointer from
02851  *      outside the TCL DLLs.
02852  *
02853  * Results:
02854  *      Returns a pointer to the global instruction table, same as the
02855  *      expression (&tclInstructionTable[0]).
02856  *
02857  * Side effects:
02858  *      None.
02859  *
02860  *----------------------------------------------------------------------
02861  */
02862 
02863 void * /* == InstructionDesc* == */
02864 TclGetInstructionTable(void)
02865 {
02866     return &tclInstructionTable[0];
02867 }
02868 
02869 /*
02870  *--------------------------------------------------------------
02871  *
02872  * TclRegisterAuxDataType --
02873  *
02874  *      This procedure is called to register a new AuxData type in the table
02875  *      of all AuxData types supported by Tcl.
02876  *
02877  * Results:
02878  *      None.
02879  *
02880  * Side effects:
02881  *      The type is registered in the AuxData type table. If there was already
02882  *      a type with the same name as in typePtr, it is replaced with the new
02883  *      type.
02884  *
02885  *--------------------------------------------------------------
02886  */
02887 
02888 void
02889 TclRegisterAuxDataType(
02890     AuxDataType *typePtr)       /* Information about object type; storage must
02891                                  * be statically allocated (must live forever;
02892                                  * will not be deallocated). */
02893 {
02894     register Tcl_HashEntry *hPtr;
02895     int isNew;
02896 
02897     Tcl_MutexLock(&tableMutex);
02898     if (!auxDataTypeTableInitialized) {
02899         TclInitAuxDataTypeTable();
02900     }
02901 
02902     /*
02903      * If there's already a type with the given name, remove it.
02904      */
02905 
02906     hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typePtr->name);
02907     if (hPtr != NULL) {
02908         Tcl_DeleteHashEntry(hPtr);
02909     }
02910 
02911     /*
02912      * Now insert the new object type.
02913      */
02914 
02915     hPtr = Tcl_CreateHashEntry(&auxDataTypeTable, typePtr->name, &isNew);
02916     if (isNew) {
02917         Tcl_SetHashValue(hPtr, typePtr);
02918     }
02919     Tcl_MutexUnlock(&tableMutex);
02920 }
02921 
02922 /*
02923  *----------------------------------------------------------------------
02924  *
02925  * TclGetAuxDataType --
02926  *
02927  *      This procedure looks up an Auxdata type by name.
02928  *
02929  * Results:
02930  *      If an AuxData type with name matching "typeName" is found, a pointer
02931  *      to its AuxDataType structure is returned; otherwise, NULL is returned.
02932  *
02933  * Side effects:
02934  *      None.
02935  *
02936  *----------------------------------------------------------------------
02937  */
02938 
02939 AuxDataType *
02940 TclGetAuxDataType(
02941     char *typeName)             /* Name of AuxData type to look up. */
02942 {
02943     register Tcl_HashEntry *hPtr;
02944     AuxDataType *typePtr = NULL;
02945 
02946     Tcl_MutexLock(&tableMutex);
02947     if (!auxDataTypeTableInitialized) {
02948         TclInitAuxDataTypeTable();
02949     }
02950 
02951     hPtr = Tcl_FindHashEntry(&auxDataTypeTable, typeName);
02952     if (hPtr != NULL) {
02953         typePtr = (AuxDataType *) Tcl_GetHashValue(hPtr);
02954     }
02955     Tcl_MutexUnlock(&tableMutex);
02956 
02957     return typePtr;
02958 }
02959 
02960 /*
02961  *--------------------------------------------------------------
02962  *
02963  * TclInitAuxDataTypeTable --
02964  *
02965  *      This procedure is invoked to perform once-only initialization of the
02966  *      AuxData type table. It also registers the AuxData types defined in
02967  *      this file.
02968  *
02969  * Results:
02970  *      None.
02971  *
02972  * Side effects:
02973  *      Initializes the table of defined AuxData types "auxDataTypeTable" with
02974  *      builtin AuxData types defined in this file.
02975  *
02976  *--------------------------------------------------------------
02977  */
02978 
02979 void
02980 TclInitAuxDataTypeTable(void)
02981 {
02982     /*
02983      * The table mutex must already be held before this routine is invoked.
02984      */
02985 
02986     auxDataTypeTableInitialized = 1;
02987     Tcl_InitHashTable(&auxDataTypeTable, TCL_STRING_KEYS);
02988 
02989     /*
02990      * There are only two AuxData type at this time, so register them here.
02991      */
02992 
02993     TclRegisterAuxDataType(&tclForeachInfoType);
02994     TclRegisterAuxDataType(&tclJumptableInfoType);
02995 }
02996 
02997 /*
02998  *----------------------------------------------------------------------
02999  *
03000  * TclFinalizeAuxDataTypeTable --
03001  *
03002  *      This procedure is called by Tcl_Finalize after all exit handlers have
03003  *      been run to free up storage associated with the table of AuxData
03004  *      types. This procedure is called by TclFinalizeExecution() which is
03005  *      called by Tcl_Finalize().
03006  *
03007  * Results:
03008  *      None.
03009  *
03010  * Side effects:
03011  *      Deletes all entries in the hash table of AuxData types.
03012  *
03013  *----------------------------------------------------------------------
03014  */
03015 
03016 void
03017 TclFinalizeAuxDataTypeTable(void)
03018 {
03019     Tcl_MutexLock(&tableMutex);
03020     if (auxDataTypeTableInitialized) {
03021         Tcl_DeleteHashTable(&auxDataTypeTable);
03022         auxDataTypeTableInitialized = 0;
03023     }
03024     Tcl_MutexUnlock(&tableMutex);
03025 }
03026 
03027 /*
03028  *----------------------------------------------------------------------
03029  *
03030  * GetCmdLocEncodingSize --
03031  *
03032  *      Computes the total number of bytes needed to encode the command
03033  *      location information for some compiled code.
03034  *
03035  * Results:
03036  *      The byte count needed to encode the compiled location information.
03037  *
03038  * Side effects:
03039  *      None.
03040  *
03041  *----------------------------------------------------------------------
03042  */
03043 
03044 static int
03045 GetCmdLocEncodingSize(
03046     CompileEnv *envPtr)         /* Points to compilation environment structure
03047                                  * containing the CmdLocation structure to
03048                                  * encode. */
03049 {
03050     register CmdLocation *mapPtr = envPtr->cmdMapPtr;
03051     int numCmds = envPtr->numCommands;
03052     int codeDelta, codeLen, srcDelta, srcLen;
03053     int codeDeltaNext, codeLengthNext, srcDeltaNext, srcLengthNext;
03054                                 /* The offsets in their respective byte
03055                                  * sequences where the next encoded offset or
03056                                  * length should go. */
03057     int prevCodeOffset, prevSrcOffset, i;
03058 
03059     codeDeltaNext = codeLengthNext = srcDeltaNext = srcLengthNext = 0;
03060     prevCodeOffset = prevSrcOffset = 0;
03061     for (i = 0;  i < numCmds;  i++) {
03062         codeDelta = (mapPtr[i].codeOffset - prevCodeOffset);
03063         if (codeDelta < 0) {
03064             Tcl_Panic("GetCmdLocEncodingSize: bad code offset");
03065         } else if (codeDelta <= 127) {
03066             codeDeltaNext++;
03067         } else {
03068             codeDeltaNext += 5;  /* 1 byte for 0xFF, 4 for positive delta */
03069         }
03070         prevCodeOffset = mapPtr[i].codeOffset;
03071 
03072         codeLen = mapPtr[i].numCodeBytes;
03073         if (codeLen < 0) {
03074             Tcl_Panic("GetCmdLocEncodingSize: bad code length");
03075         } else if (codeLen <= 127) {
03076             codeLengthNext++;
03077         } else {
03078             codeLengthNext += 5; /* 1 byte for 0xFF, 4 for length */
03079         }
03080 
03081         srcDelta = (mapPtr[i].srcOffset - prevSrcOffset);
03082         if ((-127 <= srcDelta) && (srcDelta <= 127)) {
03083             srcDeltaNext++;
03084         } else {
03085             srcDeltaNext += 5;   /* 1 byte for 0xFF, 4 for delta */
03086         }
03087         prevSrcOffset = mapPtr[i].srcOffset;
03088 
03089         srcLen = mapPtr[i].numSrcBytes;
03090         if (srcLen < 0) {
03091             Tcl_Panic("GetCmdLocEncodingSize: bad source length");
03092         } else if (srcLen <= 127) {
03093             srcLengthNext++;
03094         } else {
03095             srcLengthNext += 5;  /* 1 byte for 0xFF, 4 for length */
03096         }
03097     }
03098 
03099     return (codeDeltaNext + codeLengthNext + srcDeltaNext + srcLengthNext);
03100 }
03101 
03102 /*
03103  *----------------------------------------------------------------------
03104  *
03105  * EncodeCmdLocMap --
03106  *
03107  *      Encode the command location information for some compiled code into a
03108  *      ByteCode structure. The encoded command location map is stored as
03109  *      three adjacent byte sequences.
03110  *
03111  * Results:
03112  *      Pointer to the first byte after the encoded command location
03113  *      information.
03114  *
03115  * Side effects:
03116  *      The encoded information is stored into the block of memory headed by
03117  *      codePtr. Also records pointers to the start of the four byte sequences
03118  *      in fields in codePtr's ByteCode header structure.
03119  *
03120  *----------------------------------------------------------------------
03121  */
03122 
03123 static unsigned char *
03124 EncodeCmdLocMap(
03125     CompileEnv *envPtr,         /* Points to compilation environment structure
03126                                  * containing the CmdLocation structure to
03127                                  * encode. */
03128     ByteCode *codePtr,          /* ByteCode in which to encode envPtr's
03129                                  * command location information. */
03130     unsigned char *startPtr)    /* Points to the first byte in codePtr's
03131                                  * memory block where the location information
03132                                  * is to be stored. */
03133 {
03134     register CmdLocation *mapPtr = envPtr->cmdMapPtr;
03135     int numCmds = envPtr->numCommands;
03136     register unsigned char *p = startPtr;
03137     int codeDelta, codeLen, srcDelta, srcLen, prevOffset;
03138     register int i;
03139 
03140     /*
03141      * Encode the code offset for each command as a sequence of deltas.
03142      */
03143 
03144     codePtr->codeDeltaStart = p;
03145     prevOffset = 0;
03146     for (i = 0;  i < numCmds;  i++) {
03147         codeDelta = (mapPtr[i].codeOffset - prevOffset);
03148         if (codeDelta < 0) {
03149             Tcl_Panic("EncodeCmdLocMap: bad code offset");
03150         } else if (codeDelta <= 127) {
03151             TclStoreInt1AtPtr(codeDelta, p);
03152             p++;
03153         } else {
03154             TclStoreInt1AtPtr(0xFF, p);
03155             p++;
03156             TclStoreInt4AtPtr(codeDelta, p);
03157             p += 4;
03158         }
03159         prevOffset = mapPtr[i].codeOffset;
03160     }
03161 
03162     /*
03163      * Encode the code length for each command.
03164      */
03165 
03166     codePtr->codeLengthStart = p;
03167     for (i = 0;  i < numCmds;  i++) {
03168         codeLen = mapPtr[i].numCodeBytes;
03169         if (codeLen < 0) {
03170             Tcl_Panic("EncodeCmdLocMap: bad code length");
03171         } else if (codeLen <= 127) {
03172             TclStoreInt1AtPtr(codeLen, p);
03173             p++;
03174         } else {
03175             TclStoreInt1AtPtr(0xFF, p);
03176             p++;
03177             TclStoreInt4AtPtr(codeLen, p);
03178             p += 4;
03179         }
03180     }
03181 
03182     /*
03183      * Encode the source offset for each command as a sequence of deltas.
03184      */
03185 
03186     codePtr->srcDeltaStart = p;
03187     prevOffset = 0;
03188     for (i = 0;  i < numCmds;  i++) {
03189         srcDelta = (mapPtr[i].srcOffset - prevOffset);
03190         if ((-127 <= srcDelta) && (srcDelta <= 127)) {
03191             TclStoreInt1AtPtr(srcDelta, p);
03192             p++;
03193         } else {
03194             TclStoreInt1AtPtr(0xFF, p);
03195             p++;
03196             TclStoreInt4AtPtr(srcDelta, p);
03197             p += 4;
03198         }
03199         prevOffset = mapPtr[i].srcOffset;
03200     }
03201 
03202     /*
03203      * Encode the source length for each command.
03204      */
03205 
03206     codePtr->srcLengthStart = p;
03207     for (i = 0;  i < numCmds;  i++) {
03208         srcLen = mapPtr[i].numSrcBytes;
03209         if (srcLen < 0) {
03210             Tcl_Panic("EncodeCmdLocMap: bad source length");
03211         } else if (srcLen <= 127) {
03212             TclStoreInt1AtPtr(srcLen, p);
03213             p++;
03214         } else {
03215             TclStoreInt1AtPtr(0xFF, p);
03216             p++;
03217             TclStoreInt4AtPtr(srcLen, p);
03218             p += 4;
03219         }
03220     }
03221 
03222     return p;
03223 }
03224 
03225 #ifdef TCL_COMPILE_DEBUG
03226 /*
03227  *----------------------------------------------------------------------
03228  *
03229  * TclPrintByteCodeObj --
03230  *
03231  *      This procedure prints ("disassembles") the instructions of a bytecode
03232  *      object to stdout.
03233  *
03234  * Results:
03235  *      None.
03236  *
03237  * Side effects:
03238  *      None.
03239  *
03240  *----------------------------------------------------------------------
03241  */
03242 
03243 void
03244 TclPrintByteCodeObj(
03245     Tcl_Interp *interp,         /* Used only for Tcl_GetStringFromObj. */
03246     Tcl_Obj *objPtr)            /* The bytecode object to disassemble. */
03247 {
03248     Tcl_Obj *bufPtr = TclDisassembleByteCodeObj(objPtr);
03249 
03250     fprintf(stdout, "\n%s", TclGetString(bufPtr));
03251     Tcl_DecrRefCount(bufPtr);
03252 }
03253 
03254 /*
03255  *----------------------------------------------------------------------
03256  *
03257  * TclPrintInstruction --
03258  *
03259  *      This procedure prints ("disassembles") one instruction from a bytecode
03260  *      object to stdout.
03261  *
03262  * Results:
03263  *      Returns the length in bytes of the current instruiction.
03264  *
03265  * Side effects:
03266  *      None.
03267  *
03268  *----------------------------------------------------------------------
03269  */
03270 
03271 int
03272 TclPrintInstruction(
03273     ByteCode *codePtr,          /* Bytecode containing the instruction. */
03274     unsigned char *pc)          /* Points to first byte of instruction. */
03275 {
03276     Tcl_Obj *bufferObj;
03277     int numBytes;
03278 
03279     TclNewObj(bufferObj);
03280     numBytes = FormatInstruction(codePtr, pc, bufferObj);
03281     fprintf(stdout, "%s", TclGetString(bufferObj));
03282     Tcl_DecrRefCount(bufferObj);
03283     return numBytes;
03284 }
03285 
03286 /*
03287  *----------------------------------------------------------------------
03288  *
03289  * TclPrintObject --
03290  *
03291  *      This procedure prints up to a specified number of characters from the
03292  *      argument Tcl object's string representation to a specified file.
03293  *
03294  * Results:
03295  *      None.
03296  *
03297  * Side effects:
03298  *      Outputs characters to the specified file.
03299  *
03300  *----------------------------------------------------------------------
03301  */
03302 
03303 void
03304 TclPrintObject(
03305     FILE *outFile,              /* The file to print the source to. */
03306     Tcl_Obj *objPtr,            /* Points to the Tcl object whose string
03307                                  * representation should be printed. */
03308     int maxChars)               /* Maximum number of chars to print. */
03309 {
03310     char *bytes;
03311     int length;
03312 
03313     bytes = Tcl_GetStringFromObj(objPtr, &length);
03314     TclPrintSource(outFile, bytes, TclMin(length, maxChars));
03315 }
03316 
03317 /*
03318  *----------------------------------------------------------------------
03319  *
03320  * TclPrintSource --
03321  *
03322  *      This procedure prints up to a specified number of characters from the
03323  *      argument string to a specified file. It tries to produce legible
03324  *      output by adding backslashes as necessary.
03325  *
03326  * Results:
03327  *      None.
03328  *
03329  * Side effects:
03330  *      Outputs characters to the specified file.
03331  *
03332  *----------------------------------------------------------------------
03333  */
03334 
03335 void
03336 TclPrintSource(
03337     FILE *outFile,              /* The file to print the source to. */
03338     const char *stringPtr,      /* The string to print. */
03339     int maxChars)               /* Maximum number of chars to print. */
03340 {
03341     Tcl_Obj *bufferObj;
03342 
03343     TclNewObj(bufferObj);
03344     PrintSourceToObj(bufferObj, stringPtr, maxChars);
03345     fprintf(outFile, TclGetString(bufferObj));
03346     Tcl_DecrRefCount(bufferObj);
03347 }
03348 #endif /* TCL_COMPILE_DEBUG */
03349 
03350 /*
03351  *----------------------------------------------------------------------
03352  *
03353  * TclDisassembleByteCodeObj --
03354  *
03355  *      Given an object which is of bytecode type, return a disassembled
03356  *      version of the bytecode (in a new refcount 0 object). No guarantees
03357  *      are made about the details of the contents of the result.
03358  *
03359  *----------------------------------------------------------------------
03360  */
03361 
03362 Tcl_Obj *
03363 TclDisassembleByteCodeObj(
03364     Tcl_Obj *objPtr)            /* The bytecode object to disassemble. */
03365 {
03366     ByteCode *codePtr = objPtr->internalRep.otherValuePtr;
03367     unsigned char *codeStart, *codeLimit, *pc;
03368     unsigned char *codeDeltaNext, *codeLengthNext;
03369     unsigned char *srcDeltaNext, *srcLengthNext;
03370     int codeOffset, codeLen, srcOffset, srcLen, numCmds, delta, i;
03371     Interp *iPtr = (Interp *) *codePtr->interpHandle;
03372     Tcl_Obj *bufferObj;
03373     char ptrBuf1[20], ptrBuf2[20];
03374 
03375     TclNewObj(bufferObj);
03376     if (codePtr->refCount <= 0) {
03377         return bufferObj;       /* Already freed. */
03378     }
03379 
03380     codeStart = codePtr->codeStart;
03381     codeLimit = (codeStart + codePtr->numCodeBytes);
03382     numCmds = codePtr->numCommands;
03383 
03384     /*
03385      * Print header lines describing the ByteCode.
03386      */
03387 
03388     sprintf(ptrBuf1, "%p", codePtr);
03389     sprintf(ptrBuf2, "%p", iPtr);
03390     Tcl_AppendPrintfToObj(bufferObj,
03391             "ByteCode 0x%s, refCt %u, epoch %u, interp 0x%s (epoch %u)\n",
03392             ptrBuf1, codePtr->refCount, codePtr->compileEpoch, ptrBuf2,
03393             iPtr->compileEpoch);
03394     Tcl_AppendToObj(bufferObj, "  Source ", -1);
03395     PrintSourceToObj(bufferObj, codePtr->source,
03396             TclMin(codePtr->numSrcBytes, 55));
03397     Tcl_AppendPrintfToObj(bufferObj,
03398             "\n  Cmds %d, src %d, inst %d, litObjs %u, aux %d, stkDepth %u, code/src %.2f\n",
03399             numCmds, codePtr->numSrcBytes, codePtr->numCodeBytes,
03400             codePtr->numLitObjects, codePtr->numAuxDataItems,
03401             codePtr->maxStackDepth,
03402 #ifdef TCL_COMPILE_STATS
03403             codePtr->numSrcBytes?
03404                     codePtr->structureSize/(float)codePtr->numSrcBytes :
03405 #endif
03406             0.0);
03407 
03408 #ifdef TCL_COMPILE_STATS
03409     Tcl_AppendPrintfToObj(bufferObj,
03410             "  Code %lu = header %lu+inst %d+litObj %lu+exc %lu+aux %lu+cmdMap %d\n",
03411             (unsigned long) codePtr->structureSize,
03412             (unsigned long) (sizeof(ByteCode) - sizeof(size_t) - sizeof(Tcl_Time)),
03413             codePtr->numCodeBytes,
03414             (unsigned long) (codePtr->numLitObjects * sizeof(Tcl_Obj *)),
03415             (unsigned long) (codePtr->numExceptRanges*sizeof(ExceptionRange)),
03416             (unsigned long) (codePtr->numAuxDataItems * sizeof(AuxData)),
03417             codePtr->numCmdLocBytes);
03418 #endif /* TCL_COMPILE_STATS */
03419 
03420     /*
03421      * If the ByteCode is the compiled body of a Tcl procedure, print
03422      * information about that procedure. Note that we don't know the
03423      * procedure's name since ByteCode's can be shared among procedures.
03424      */
03425 
03426     if (codePtr->procPtr != NULL) {
03427         Proc *procPtr = codePtr->procPtr;
03428         int numCompiledLocals = procPtr->numCompiledLocals;
03429 
03430         sprintf(ptrBuf1, "%p", procPtr);
03431         Tcl_AppendPrintfToObj(bufferObj,
03432                 "  Proc 0x%s, refCt %d, args %d, compiled locals %d\n",
03433                 ptrBuf1, procPtr->refCount, procPtr->numArgs,
03434                 numCompiledLocals);
03435         if (numCompiledLocals > 0) {
03436             CompiledLocal *localPtr = procPtr->firstLocalPtr;
03437 
03438             for (i = 0;  i < numCompiledLocals;  i++) {
03439                 Tcl_AppendPrintfToObj(bufferObj,
03440                         "      slot %d%s%s%s%s%s%s", i,
03441                         (localPtr->flags & (VAR_ARRAY|VAR_LINK)) ? "" : ", scalar",
03442                         (localPtr->flags & VAR_ARRAY) ? ", array" : "",
03443                         (localPtr->flags & VAR_LINK) ? ", link" : "",
03444                         (localPtr->flags & VAR_ARGUMENT) ? ", arg" : "",
03445                         (localPtr->flags & VAR_TEMPORARY) ? ", temp" : "",
03446                         (localPtr->flags & VAR_RESOLVED) ? ", resolved" : "");
03447                 if (TclIsVarTemporary(localPtr)) {
03448                     Tcl_AppendToObj(bufferObj, "\n", -1);
03449                 } else {
03450                     Tcl_AppendPrintfToObj(bufferObj, ", \"%s\"\n",
03451                             localPtr->name);
03452                 }
03453                 localPtr = localPtr->nextPtr;
03454             }
03455         }
03456     }
03457 
03458     /*
03459      * Print the ExceptionRange array.
03460      */
03461 
03462     if (codePtr->numExceptRanges > 0) {
03463         Tcl_AppendPrintfToObj(bufferObj, "  Exception ranges %d, depth %d:\n",
03464                 codePtr->numExceptRanges, codePtr->maxExceptDepth);
03465         for (i = 0;  i < codePtr->numExceptRanges;  i++) {
03466             ExceptionRange *rangePtr = &(codePtr->exceptArrayPtr[i]);
03467 
03468             Tcl_AppendPrintfToObj(bufferObj,
03469                     "      %d: level %d, %s, pc %d-%d, ",
03470                     i, rangePtr->nestingLevel,
03471                     (rangePtr->type==LOOP_EXCEPTION_RANGE ? "loop" : "catch"),
03472                     rangePtr->codeOffset,
03473                     (rangePtr->codeOffset + rangePtr->numCodeBytes - 1));
03474             switch (rangePtr->type) {
03475             case LOOP_EXCEPTION_RANGE:
03476                 Tcl_AppendPrintfToObj(bufferObj, "continue %d, break %d\n",
03477                         rangePtr->continueOffset, rangePtr->breakOffset);
03478                 break;
03479             case CATCH_EXCEPTION_RANGE:
03480                 Tcl_AppendPrintfToObj(bufferObj, "catch %d\n",
03481                         rangePtr->catchOffset);
03482                 break;
03483             default:
03484                 Tcl_Panic("TclDisassembleByteCodeObj: bad ExceptionRange type %d",
03485                         rangePtr->type);
03486             }
03487         }
03488     }
03489 
03490     /*
03491      * If there were no commands (e.g., an expression or an empty string was
03492      * compiled), just print all instructions and return.
03493      */
03494 
03495     if (numCmds == 0) {
03496         pc = codeStart;
03497         while (pc < codeLimit) {
03498             Tcl_AppendToObj(bufferObj, "    ", -1);
03499             pc += FormatInstruction(codePtr, pc, bufferObj);
03500         }
03501         return bufferObj;
03502     }
03503 
03504     /*
03505      * Print table showing the code offset, source offset, and source length
03506      * for each command. These are encoded as a sequence of bytes.
03507      */
03508 
03509     Tcl_AppendPrintfToObj(bufferObj, "  Commands %d:", numCmds);
03510     codeDeltaNext = codePtr->codeDeltaStart;
03511     codeLengthNext = codePtr->codeLengthStart;
03512     srcDeltaNext = codePtr->srcDeltaStart;
03513     srcLengthNext = codePtr->srcLengthStart;
03514     codeOffset = srcOffset = 0;
03515     for (i = 0;  i < numCmds;  i++) {
03516         if ((unsigned) *codeDeltaNext == (unsigned) 0xFF) {
03517             codeDeltaNext++;
03518             delta = TclGetInt4AtPtr(codeDeltaNext);
03519             codeDeltaNext += 4;
03520         } else {
03521             delta = TclGetInt1AtPtr(codeDeltaNext);
03522             codeDeltaNext++;
03523         }
03524         codeOffset += delta;
03525 
03526         if ((unsigned) *codeLengthNext == (unsigned) 0xFF) {
03527             codeLengthNext++;
03528             codeLen = TclGetInt4AtPtr(codeLengthNext);
03529             codeLengthNext += 4;
03530         } else {
03531             codeLen = TclGetInt1AtPtr(codeLengthNext);
03532             codeLengthNext++;
03533         }
03534 
03535         if ((unsigned) *srcDeltaNext == (unsigned) 0xFF) {
03536             srcDeltaNext++;
03537             delta = TclGetInt4AtPtr(srcDeltaNext);
03538             srcDeltaNext += 4;
03539         } else {
03540             delta = TclGetInt1AtPtr(srcDeltaNext);
03541             srcDeltaNext++;
03542         }
03543         srcOffset += delta;
03544 
03545         if ((unsigned) *srcLengthNext == (unsigned) 0xFF) {
03546             srcLengthNext++;
03547             srcLen = TclGetInt4AtPtr(srcLengthNext);
03548             srcLengthNext += 4;
03549         } else {
03550             srcLen = TclGetInt1AtPtr(srcLengthNext);
03551             srcLengthNext++;
03552         }
03553 
03554         Tcl_AppendPrintfToObj(bufferObj, "%s%4d: pc %d-%d, src %d-%d",
03555                 ((i % 2)? "     " : "\n   "),
03556                 (i+1), codeOffset, (codeOffset + codeLen - 1),
03557                 srcOffset, (srcOffset + srcLen - 1));
03558     }
03559     if (numCmds > 0) {
03560         Tcl_AppendToObj(bufferObj, "\n", -1);
03561     }
03562 
03563     /*
03564      * Print each instruction. If the instruction corresponds to the start of
03565      * a command, print the command's source. Note that we don't need the code
03566      * length here.
03567      */
03568 
03569     codeDeltaNext = codePtr->codeDeltaStart;
03570     srcDeltaNext = codePtr->srcDeltaStart;
03571     srcLengthNext = codePtr->srcLengthStart;
03572     codeOffset = srcOffset = 0;
03573     pc = codeStart;
03574     for (i = 0;  i < numCmds;  i++) {
03575         if ((unsigned) *codeDeltaNext == (unsigned) 0xFF) {
03576             codeDeltaNext++;
03577             delta = TclGetInt4AtPtr(codeDeltaNext);
03578             codeDeltaNext += 4;
03579         } else {
03580             delta = TclGetInt1AtPtr(codeDeltaNext);
03581             codeDeltaNext++;
03582         }
03583         codeOffset += delta;
03584 
03585         if ((unsigned) *srcDeltaNext == (unsigned) 0xFF) {
03586             srcDeltaNext++;
03587             delta = TclGetInt4AtPtr(srcDeltaNext);
03588             srcDeltaNext += 4;
03589         } else {
03590             delta = TclGetInt1AtPtr(srcDeltaNext);
03591             srcDeltaNext++;
03592         }
03593         srcOffset += delta;
03594 
03595         if ((unsigned) *srcLengthNext == (unsigned) 0xFF) {
03596             srcLengthNext++;
03597             srcLen = TclGetInt4AtPtr(srcLengthNext);
03598             srcLengthNext += 4;
03599         } else {
03600             srcLen = TclGetInt1AtPtr(srcLengthNext);
03601             srcLengthNext++;
03602         }
03603 
03604         /*
03605          * Print instructions before command i.
03606          */
03607 
03608         while ((pc-codeStart) < codeOffset) {
03609             Tcl_AppendToObj(bufferObj, "    ", -1);
03610             pc += FormatInstruction(codePtr, pc, bufferObj);
03611         }
03612 
03613         Tcl_AppendPrintfToObj(bufferObj, "  Command %d: ", i+1);
03614         PrintSourceToObj(bufferObj, (codePtr->source + srcOffset),
03615                 TclMin(srcLen, 55));
03616         Tcl_AppendToObj(bufferObj, "\n", -1);
03617     }
03618     if (pc < codeLimit) {
03619         /*
03620          * Print instructions after the last command.
03621          */
03622 
03623         while (pc < codeLimit) {
03624             Tcl_AppendToObj(bufferObj, "    ", -1);
03625             pc += FormatInstruction(codePtr, pc, bufferObj);
03626         }
03627     }
03628     return bufferObj;
03629 }
03630 
03631 /*
03632  *----------------------------------------------------------------------
03633  *
03634  * FormatInstruction --
03635  *
03636  *      Appends a representation of a bytecode instruction to a Tcl_Obj.
03637  *
03638  *----------------------------------------------------------------------
03639  */
03640 
03641 static int
03642 FormatInstruction(
03643     ByteCode *codePtr,          /* Bytecode containing the instruction. */
03644     unsigned char *pc,          /* Points to first byte of instruction. */
03645     Tcl_Obj *bufferObj)         /* Object to append instruction info to. */
03646 {
03647     Proc *procPtr = codePtr->procPtr;
03648     unsigned char opCode = *pc;
03649     register InstructionDesc *instDesc = &tclInstructionTable[opCode];
03650     unsigned char *codeStart = codePtr->codeStart;
03651     unsigned pcOffset = pc - codeStart;
03652     int opnd = 0, i, j, numBytes = 1;
03653     int localCt = procPtr ? procPtr->numCompiledLocals : 0;
03654     CompiledLocal *localPtr = procPtr ? procPtr->firstLocalPtr : NULL;
03655     char suffixBuffer[128];     /* Additional info to print after main opcode
03656                                  * and immediates. */
03657     char *suffixSrc = NULL;
03658     Tcl_Obj *suffixObj = NULL;
03659     AuxData *auxPtr = NULL;
03660 
03661     suffixBuffer[0] = '\0';
03662     Tcl_AppendPrintfToObj(bufferObj, "(%u) %s ", pcOffset, instDesc->name);
03663     for (i = 0;  i < instDesc->numOperands;  i++) {
03664         switch (instDesc->opTypes[i]) {
03665         case OPERAND_INT1:
03666             opnd = TclGetInt1AtPtr(pc+numBytes); numBytes++;
03667             if (opCode == INST_JUMP1 || opCode == INST_JUMP_TRUE1
03668                     || opCode == INST_JUMP_FALSE1) {
03669                 sprintf(suffixBuffer, "pc %u", pcOffset+opnd);
03670             }
03671             Tcl_AppendPrintfToObj(bufferObj, "%+d ", opnd);
03672             break;
03673         case OPERAND_INT4:
03674             opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
03675             if (opCode == INST_JUMP4 || opCode == INST_JUMP_TRUE4
03676                     || opCode == INST_JUMP_FALSE4) {
03677                 sprintf(suffixBuffer, "pc %u", pcOffset+opnd);
03678             } else if (opCode == INST_START_CMD) {
03679                 sprintf(suffixBuffer, "next cmd at pc %u", pcOffset+opnd);
03680             }
03681             Tcl_AppendPrintfToObj(bufferObj, "%+d ", opnd);
03682             break;
03683         case OPERAND_UINT1:
03684             opnd = TclGetUInt1AtPtr(pc+numBytes); numBytes++;
03685             if (opCode == INST_PUSH1) {
03686                 suffixObj = codePtr->objArrayPtr[opnd];
03687             }
03688             Tcl_AppendPrintfToObj(bufferObj, "%u ", (unsigned) opnd);
03689             break;
03690         case OPERAND_AUX4:
03691         case OPERAND_UINT4:
03692             opnd = TclGetUInt4AtPtr(pc+numBytes); numBytes += 4;
03693             if (opCode == INST_PUSH4) {
03694                 suffixObj = codePtr->objArrayPtr[opnd];
03695             } else if (opCode == INST_START_CMD && opnd != 1) {
03696                 sprintf(suffixBuffer+strlen(suffixBuffer),
03697                         ", %u cmds start here", opnd);
03698             }
03699             Tcl_AppendPrintfToObj(bufferObj, "%u ", (unsigned) opnd);
03700             if (instDesc->opTypes[i] == OPERAND_AUX4) {
03701                 auxPtr = &codePtr->auxDataArrayPtr[opnd];
03702             }
03703             break;
03704         case OPERAND_IDX4:
03705             opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
03706             if (opnd >= -1) {
03707                 Tcl_AppendPrintfToObj(bufferObj, "%d ", opnd);
03708             } else if (opnd == -2) {
03709                 Tcl_AppendPrintfToObj(bufferObj, "end ");
03710             } else {
03711                 Tcl_AppendPrintfToObj(bufferObj, "end-%d ", -2-opnd);
03712             }
03713             break;
03714         case OPERAND_LVT1:
03715             opnd = TclGetUInt1AtPtr(pc+numBytes);
03716             numBytes++;
03717             goto printLVTindex;
03718         case OPERAND_LVT4:
03719             opnd = TclGetUInt4AtPtr(pc+numBytes);
03720             numBytes += 4;
03721         printLVTindex:
03722             if (localPtr != NULL) {
03723                 if (opnd >= localCt) {
03724                     Tcl_Panic("FormatInstruction: bad local var index %u (%u locals)",
03725                             (unsigned) opnd, localCt);
03726                 }
03727                 for (j = 0;  j < opnd;  j++) {
03728                     localPtr = localPtr->nextPtr;
03729                 }
03730                 if (TclIsVarTemporary(localPtr)) {
03731                     sprintf(suffixBuffer, "temp var %u", (unsigned) opnd);
03732                 } else {
03733                     sprintf(suffixBuffer, "var ");
03734                     suffixSrc = localPtr->name;
03735                 }
03736             }
03737             Tcl_AppendPrintfToObj(bufferObj, "%%v%u ", (unsigned) opnd);
03738             break;
03739         case OPERAND_NONE:
03740         default:
03741             break;
03742         }
03743     }
03744     if (suffixObj) {
03745         char *bytes;
03746         int length;
03747 
03748         Tcl_AppendToObj(bufferObj, "\t# ", -1);
03749         bytes = Tcl_GetStringFromObj(codePtr->objArrayPtr[opnd], &length);
03750         PrintSourceToObj(bufferObj, bytes, TclMin(length, 40));
03751     } else if (suffixBuffer[0]) {
03752         Tcl_AppendPrintfToObj(bufferObj, "\t# %s", suffixBuffer);
03753         if (suffixSrc) {
03754             PrintSourceToObj(bufferObj, suffixSrc, 40);
03755         }
03756     }
03757     Tcl_AppendToObj(bufferObj, "\n", -1);
03758     if (auxPtr && auxPtr->type->printProc) {
03759         Tcl_AppendToObj(bufferObj, "\t\t[", -1);
03760         auxPtr->type->printProc(auxPtr->clientData, bufferObj, codePtr,
03761                 pcOffset);
03762         Tcl_AppendToObj(bufferObj, "]\n", -1);
03763     }
03764     return numBytes;
03765 }
03766 
03767 /*
03768  *----------------------------------------------------------------------
03769  *
03770  * PrintSourceToObj --
03771  *
03772  *      Appends a quoted representation of a string to a Tcl_Obj.
03773  *
03774  *----------------------------------------------------------------------
03775  */
03776 
03777 static void
03778 PrintSourceToObj(
03779     Tcl_Obj *appendObj,         /* The object to print the source to. */
03780     const char *stringPtr,      /* The string to print. */
03781     int maxChars)               /* Maximum number of chars to print. */
03782 {
03783     register const char *p;
03784     register int i = 0;
03785 
03786     if (stringPtr == NULL) {
03787         Tcl_AppendToObj(appendObj, "\"\"", -1);
03788         return;
03789     }
03790 
03791     Tcl_AppendToObj(appendObj, "\"", -1);
03792     p = stringPtr;
03793     for (;  (*p != '\0') && (i < maxChars);  p++, i++) {
03794         switch (*p) {
03795         case '"':
03796             Tcl_AppendToObj(appendObj, "\\\"", -1);
03797             continue;
03798         case '\f':
03799             Tcl_AppendToObj(appendObj, "\\f", -1);
03800             continue;
03801         case '\n':
03802             Tcl_AppendToObj(appendObj, "\\n", -1);
03803             continue;
03804         case '\r':
03805             Tcl_AppendToObj(appendObj, "\\r", -1);
03806             continue;
03807         case '\t':
03808             Tcl_AppendToObj(appendObj, "\\t", -1);
03809             continue;
03810         case '\v':
03811             Tcl_AppendToObj(appendObj, "\\v", -1);
03812             continue;
03813         default:
03814             Tcl_AppendPrintfToObj(appendObj, "%c", *p);
03815             continue;
03816         }
03817     }
03818     Tcl_AppendToObj(appendObj, "\"", -1);
03819 }
03820 
03821 #ifdef TCL_COMPILE_STATS
03822 /*
03823  *----------------------------------------------------------------------
03824  *
03825  * RecordByteCodeStats --
03826  *
03827  *      Accumulates various compilation-related statistics for each newly
03828  *      compiled ByteCode. Called by the TclInitByteCodeObj when Tcl is
03829  *      compiled with the -DTCL_COMPILE_STATS flag
03830  *
03831  * Results:
03832  *      None.
03833  *
03834  * Side effects:
03835  *      Accumulates aggregate code-related statistics in the interpreter's
03836  *      ByteCodeStats structure. Records statistics specific to a ByteCode in
03837  *      its ByteCode structure.
03838  *
03839  *----------------------------------------------------------------------
03840  */
03841 
03842 void
03843 RecordByteCodeStats(
03844     ByteCode *codePtr)          /* Points to ByteCode structure with info
03845                                  * to add to accumulated statistics. */
03846 {
03847     Interp *iPtr = (Interp *) *codePtr->interpHandle;
03848     register ByteCodeStats *statsPtr = &(iPtr->stats);
03849 
03850     statsPtr->numCompilations++;
03851     statsPtr->totalSrcBytes += (double) codePtr->numSrcBytes;
03852     statsPtr->totalByteCodeBytes += (double) codePtr->structureSize;
03853     statsPtr->currentSrcBytes += (double) codePtr->numSrcBytes;
03854     statsPtr->currentByteCodeBytes += (double) codePtr->structureSize;
03855 
03856     statsPtr->srcCount[TclLog2(codePtr->numSrcBytes)]++;
03857     statsPtr->byteCodeCount[TclLog2((int)(codePtr->structureSize))]++;
03858 
03859     statsPtr->currentInstBytes += (double) codePtr->numCodeBytes;
03860     statsPtr->currentLitBytes += (double)
03861             codePtr->numLitObjects * sizeof(Tcl_Obj *);
03862     statsPtr->currentExceptBytes += (double)
03863             codePtr->numExceptRanges * sizeof(ExceptionRange);
03864     statsPtr->currentAuxBytes += (double)
03865             codePtr->numAuxDataItems * sizeof(AuxData);
03866     statsPtr->currentCmdMapBytes += (double) codePtr->numCmdLocBytes;
03867 }
03868 #endif /* TCL_COMPILE_STATS */
03869 
03870 /*
03871  * Local Variables:
03872  * mode: c
03873  * c-basic-offset: 4
03874  * fill-column: 78
03875  * End:
03876  */



Generated on Wed Mar 12 12:18:14 2008 by  doxygen 1.5.1