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