tclCompile.cGo 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 1.5.1 |