summaryrefslogtreecommitdiffstats
path: root/generic/tclProc.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclProc.c')
-rw-r--r--generic/tclProc.c500
1 files changed, 339 insertions, 161 deletions
diff --git a/generic/tclProc.c b/generic/tclProc.c
index ab2accd..385ad93 100644
--- a/generic/tclProc.c
+++ b/generic/tclProc.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * SCCS: @(#) tclProc.c 1.128 98/02/17 15:57:10
+ * RCS: @(#) $Id: tclProc.c,v 1.1.2.2 1998/09/24 23:59:02 stanton Exp $
*/
#include "tclInt.h"
@@ -20,12 +20,6 @@
* Forward references to procedures defined later in this file:
*/
-static void CleanupProc _ANSI_ARGS_((Proc *procPtr));
-static int CompileProcBody _ANSI_ARGS_((Tcl_Interp *interp,
- Proc *procPtr, char *procName, int nameLen));
-static int InterpProc _ANSI_ARGS_((ClientData clientData,
- Tcl_Interp *interp, int argc, char **argv));
-static void ProcDeleteProc _ANSI_ARGS_((ClientData clientData));
static int ProcessProcResultCode _ANSI_ARGS_((Tcl_Interp *interp,
char *procName, int nameLen, int returnCode));
@@ -56,14 +50,11 @@ Tcl_ProcObjCmd(dummy, interp, objc, objv)
{
register Interp *iPtr = (Interp *) interp;
register Proc *procPtr;
- char *fullName, *procName, *args, *bytes, *p;
- char **argArray = NULL;
+ char *fullName, *procName;
Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
- Tcl_Obj *defPtr, *bodyPtr;
Tcl_Command cmd;
Tcl_DString ds;
- int numArgs, length, result, i;
- register CompiledLocal *localPtr;
+ int result;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "name args body");
@@ -105,6 +96,82 @@ Tcl_ProcObjCmd(dummy, interp, objc, objv)
}
/*
+ * Create the data structure to represent the procedure.
+ */
+ if (TclCreateProc(interp, nsPtr, procName, objv[2], objv[3],
+ &procPtr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Now create a command for the procedure. This will initially be in
+ * the current namespace unless the procedure's name included namespace
+ * qualifiers. To create the new command in the right namespace, we
+ * generate a fully qualified name for it.
+ */
+
+ Tcl_DStringInit(&ds);
+ if (nsPtr != iPtr->globalNsPtr) {
+ Tcl_DStringAppend(&ds, nsPtr->fullName, -1);
+ Tcl_DStringAppend(&ds, "::", 2);
+ }
+ Tcl_DStringAppend(&ds, procName, -1);
+
+ Tcl_CreateCommand(interp, Tcl_DStringValue(&ds), TclProcInterpProc,
+ (ClientData) procPtr, TclProcDeleteProc);
+ cmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds),
+ TclObjInterpProc, (ClientData) procPtr, TclProcDeleteProc);
+
+ /*
+ * Now initialize the new procedure's cmdPtr field. This will be used
+ * later when the procedure is called to determine what namespace the
+ * procedure will run in. This will be different than the current
+ * namespace if the proc was renamed into a different namespace.
+ */
+
+ procPtr->cmdPtr = (Command *) cmd;
+
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclCreateProc --
+ *
+ * Creates the data associated with a Tcl procedure definition.
+ *
+ * Results:
+ * Returns TCL_OK on success, along with a pointer to a Tcl
+ * procedure definition in procPtrPtr. This definition should
+ * be freed by calling TclCleanupProc() when it is no longer
+ * needed. Returns TCL_ERROR if anything goes wrong.
+ *
+ * Side effects:
+ * If anything goes wrong, this procedure returns an error
+ * message in the interpreter.
+ *
+ *----------------------------------------------------------------------
+ */
+int
+TclCreateProc(interp, nsPtr, procName, argsPtr, bodyPtr, procPtrPtr)
+ Tcl_Interp *interp; /* interpreter containing proc */
+ Namespace *nsPtr; /* namespace containing this proc */
+ char *procName; /* unqualified name of this proc */
+ Tcl_Obj *argsPtr; /* description of arguments */
+ Tcl_Obj *bodyPtr; /* command body */
+ Proc **procPtrPtr; /* returns: pointer to proc data */
+{
+ Interp *iPtr = (Interp*)interp;
+ char **argArray = NULL;
+
+ register Proc *procPtr;
+ int i, length, result, numArgs;
+ char *args, *bytes, *p;
+ register CompiledLocal *localPtr;
+ Tcl_Obj *defPtr;
+
+ /*
* If the procedure's body object is shared because its string value is
* identical to, e.g., the body of another procedure, we must create a
* private copy for this procedure to use. Such sharing of procedure
@@ -118,10 +185,9 @@ Tcl_ProcObjCmd(dummy, interp, objc, objv)
* we would not want any bytecode internal representation.
*/
- bodyPtr = objv[3];
if (Tcl_IsShared(bodyPtr)) {
- bytes = Tcl_GetStringFromObj(bodyPtr, &length);
- bodyPtr = Tcl_NewStringObj(bytes, length);
+ bytes = Tcl_GetStringFromObj(bodyPtr, &length);
+ bodyPtr = Tcl_NewStringObj(bytes, length);
}
/*
@@ -146,9 +212,10 @@ Tcl_ProcObjCmd(dummy, interp, objc, objv)
/*
* Break up the argument list into argument specifiers, then process
* each argument specifier.
+ * THIS FAILS IF THE ARG LIST OBJECT'S STRING REP CONTAINS NULLS.
*/
- args = Tcl_GetStringFromObj(objv[2], &length);
+ args = Tcl_GetStringFromObj(argsPtr, &length);
result = Tcl_SplitList(interp, args, &numArgs, &argArray);
if (result != TCL_OK) {
goto procError;
@@ -179,7 +246,7 @@ Tcl_ProcObjCmd(dummy, interp, objc, objv)
if ((fieldCount == 0) || (*fieldValues[0] == 0)) {
ckfree((char *) fieldValues);
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "procedure \"", fullName,
+ "procedure \"", procName,
"\" has argument with no name", (char *) NULL);
goto procError;
}
@@ -205,7 +272,7 @@ Tcl_ProcObjCmd(dummy, interp, objc, objv)
q--;
if (*q == ')') { /* we have an array element */
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "procedure \"", fullName,
+ "procedure \"", procName,
"\" has formal parameter \"", fieldValues[0],
"\" that is an array element",
(char *) NULL);
@@ -233,9 +300,9 @@ Tcl_ProcObjCmd(dummy, interp, objc, objv)
localPtr->nextPtr = NULL;
localPtr->nameLength = nameLength;
localPtr->frameIndex = i;
- localPtr->isArg = 1;
- localPtr->isTemp = 0;
- localPtr->flags = VAR_SCALAR;
+ localPtr->flags = VAR_SCALAR | VAR_ARGUMENT;
+ localPtr->resolveInfo = NULL;
+
if (fieldCount == 2) {
localPtr->defValuePtr =
Tcl_NewStringObj(fieldValues[1], valueLength);
@@ -249,37 +316,17 @@ Tcl_ProcObjCmd(dummy, interp, objc, objv)
}
/*
- * Now create a command for the procedure. This will initially be in
- * the current namespace unless the procedure's name included namespace
- * qualifiers. To create the new command in the right namespace, we
- * generate a fully qualified name for it.
- */
-
- Tcl_DStringInit(&ds);
- if (nsPtr != iPtr->globalNsPtr) {
- Tcl_DStringAppend(&ds, nsPtr->fullName, -1);
- Tcl_DStringAppend(&ds, "::", 2);
- }
- Tcl_DStringAppend(&ds, procName, -1);
-
- Tcl_CreateCommand(interp, Tcl_DStringValue(&ds), InterpProc,
- (ClientData) procPtr, ProcDeleteProc);
- cmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds),
- TclObjInterpProc, (ClientData) procPtr, ProcDeleteProc);
-
- /*
* Now initialize the new procedure's cmdPtr field. This will be used
* later when the procedure is called to determine what namespace the
* procedure will run in. This will be different than the current
* namespace if the proc was renamed into a different namespace.
*/
- procPtr->cmdPtr = (Command *) cmd;
-
+ *procPtrPtr = procPtr;
ckfree((char *) argArray);
return TCL_OK;
- procError:
+procError:
Tcl_DecrRefCount(bodyPtr);
while (procPtr->firstLocalPtr != NULL) {
localPtr = procPtr->firstLocalPtr;
@@ -496,22 +543,25 @@ TclFindProc(iPtr, procName)
Interp *iPtr; /* Interpreter in which to look. */
char *procName; /* Name of desired procedure. */
{
- Command *cmdPtr, *realCmdPtr;
-
- cmdPtr = (Command *) Tcl_FindCommand((Tcl_Interp *) iPtr, procName,
+ Tcl_Command cmd;
+ Tcl_Command origCmd;
+ Command *cmdPtr;
+
+ cmd = Tcl_FindCommand((Tcl_Interp *) iPtr, procName,
(Tcl_Namespace *) NULL, /*flags*/ 0);
- if (cmdPtr == NULL) {
+ if (cmd == (Tcl_Command) NULL) {
return NULL;
}
-
- if (cmdPtr->proc == InterpProc) {
- return (Proc *) cmdPtr->clientData;
+ cmdPtr = (Command *) cmd;
+
+ origCmd = TclGetOriginalCommand(cmd);
+ if (origCmd != NULL) {
+ cmdPtr = (Command *) origCmd;
}
- realCmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
- if ((realCmdPtr != NULL) && (realCmdPtr->proc == InterpProc)) {
- return (Proc *) realCmdPtr->clientData;
+ if (cmdPtr->proc != TclProcInterpProc) {
+ return NULL;
}
- return NULL;
+ return (Proc *) cmdPtr->clientData;
}
/*
@@ -522,7 +572,7 @@ TclFindProc(iPtr, procName)
* Tells whether a command is a Tcl procedure or not.
*
* Results:
- * If the given command is actuall a Tcl procedure, the
+ * If the given command is actually a Tcl procedure, the
* return value is the address of the record describing
* the procedure. Otherwise the return value is 0.
*
@@ -536,7 +586,13 @@ Proc *
TclIsProc(cmdPtr)
Command *cmdPtr; /* Command to test. */
{
- if (cmdPtr->proc == InterpProc) {
+ Tcl_Command origCmd;
+
+ origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr);
+ if (origCmd != NULL) {
+ cmdPtr = (Command *) origCmd;
+ }
+ if (cmdPtr->proc == TclProcInterpProc) {
return (Proc *) cmdPtr->clientData;
}
return (Proc *) 0;
@@ -545,7 +601,7 @@ TclIsProc(cmdPtr)
/*
*----------------------------------------------------------------------
*
- * InterpProc --
+ * TclProcInterpProc --
*
* When a Tcl procedure gets invoked with an argc/argv array of
* strings, this routine gets invoked to interpret the procedure.
@@ -559,8 +615,8 @@ TclIsProc(cmdPtr)
*----------------------------------------------------------------------
*/
-static int
-InterpProc(clientData, interp, argc, argv)
+int
+TclProcInterpProc(clientData, interp, argc, argv)
ClientData clientData; /* Record describing procedure to be
* interpreted. */
Tcl_Interp *interp; /* Interpreter in which procedure was
@@ -664,7 +720,7 @@ TclObjInterpProc(clientData, interp, objc, objv)
{
Interp *iPtr = (Interp *) interp;
register Proc *procPtr = (Proc *) clientData;
- Tcl_Obj *bodyPtr = procPtr->bodyPtr;
+ Namespace *nsPtr = procPtr->cmdPtr->nsPtr;
CallFrame frame;
register CallFrame *framePtr = &frame;
register Var *varPtr;
@@ -691,28 +747,16 @@ TclObjInterpProc(clientData, interp, objc, objv)
/*
* If necessary, compile the procedure's body. The compiler will
* allocate frame slots for the procedure's non-argument local
- * variables. If the ByteCode already exists, make sure it hasn't been
- * invalidated by someone redefining a core command (this might make the
- * compiled code wrong). Also, if the code was compiled in/for a
- * different interpreter, we recompile it. Note that compiling the body
- * might increase procPtr->numCompiledLocals if new local variables are
- * found while compiling.
+ * variables. Note that compiling the body might increase
+ * procPtr->numCompiledLocals if new local variables are found
+ * while compiling.
*/
- if (bodyPtr->typePtr == &tclByteCodeType) {
- ByteCode *codePtr = (ByteCode *) bodyPtr->internalRep.otherValuePtr;
-
- if (((Interp *) *codePtr->interpHandle != iPtr)
- || (codePtr->compileEpoch != iPtr->compileEpoch)) {
- (*tclByteCodeType.freeIntRepProc)(bodyPtr);
- bodyPtr->typePtr = (Tcl_ObjType *) NULL;
- }
- }
- if (bodyPtr->typePtr != &tclByteCodeType) {
- result = CompileProcBody(interp, procPtr, procName, nameLen);
- if (result != TCL_OK) {
- return result;
- }
+ result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr, nsPtr,
+ "body of proc", procName);
+
+ if (result != TCL_OK) {
+ return result;
}
/*
@@ -735,34 +779,24 @@ TclObjInterpProc(clientData, interp, objc, objv)
*/
result = Tcl_PushCallFrame(interp, (Tcl_CallFrame *) framePtr,
- (Tcl_Namespace *) procPtr->cmdPtr->nsPtr,
- /*isProcCallFrame*/ 1);
+ (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 1);
+
if (result != TCL_OK) {
return result;
}
+
framePtr->objc = objc;
framePtr->objv = objv; /* ref counts for args are incremented below */
- framePtr->procPtr = procPtr;
- framePtr->numCompiledLocals = localCt;
- framePtr->compiledLocals = compiledLocals;
/*
- * Initialize the array of local variables stored in the call frame.
+ * Initialize and resolve compiled variable references.
*/
- varPtr = framePtr->compiledLocals;
- for (localPtr = procPtr->firstLocalPtr; localPtr != NULL;
- localPtr = localPtr->nextPtr) {
- varPtr->value.objPtr = NULL;
- varPtr->name = localPtr->name; /* will be just '\0' if temp var */
- varPtr->nsPtr = NULL;
- varPtr->hPtr = NULL;
- varPtr->refCount = 0;
- varPtr->tracePtr = NULL;
- varPtr->searchPtr = NULL;
- varPtr->flags = (localPtr->flags | VAR_UNDEFINED);
- varPtr++;
- }
+ framePtr->procPtr = procPtr;
+ framePtr->numCompiledLocals = localCt;
+ framePtr->compiledLocals = compiledLocals;
+
+ TclInitCompiledLocals(interp, framePtr, nsPtr);
/*
* Match and assign the call's actual parameters to the procedure's
@@ -776,12 +810,12 @@ TclObjInterpProc(clientData, interp, objc, objv)
localPtr = procPtr->firstLocalPtr;
argCt = objc;
for (i = 1, argCt -= 1; i <= numArgs; i++, argCt--) {
- if (!localPtr->isArg) {
+ if (!TclIsVarArgument(localPtr)) {
panic("TclObjInterpProc: local variable %s is not argument but should be",
localPtr->name);
return TCL_ERROR;
}
- if (localPtr->isTemp) {
+ if (TclIsVarTemporary(localPtr)) {
panic("TclObjInterpProc: local variable %d is temporary but should be an argument", i);
return TCL_ERROR;
}
@@ -854,7 +888,7 @@ TclObjInterpProc(clientData, interp, objc, objv)
result = Tcl_EvalObj(interp, procPtr->bodyPtr, 0);
procPtr->refCount--;
if (procPtr->refCount <= 0) {
- CleanupProc(procPtr);
+ TclProcCleanupProc(procPtr);
}
if (result != TCL_OK) {
@@ -878,71 +912,155 @@ TclObjInterpProc(clientData, interp, objc, objv)
/*
*----------------------------------------------------------------------
*
- * CompileProcBody --
+ * TclProcCompileProc --
*
- * This procedure is called by TclObjInterpProc to compile the body
- * script of a Tcl procedure.
+ * Called just before a procedure is executed to compile the
+ * body to byte codes. If the type of the body is not
+ * "byte code" or if the compile conditions have changed
+ * (namespace context, epoch counters, etc.) then the body
+ * is recompiled. Otherwise, this procedure does nothing.
*
* Results:
- * If the compilation succeeds, TCL_OK is returned. Otherwise,
- * TCL_ERROR is returned and an error message is left in the
- * interpreter's result.
+ * None.
*
* Side effects:
- * Modifies the Tcl object that is the body of the procedure to
- * be a ByteCode object. Also arranges (by setting the interpreter's
- * compiledProcPtr field) to have the compiler set various fields in
- * the procedure's Proc structure such as the number of compiled local
- * variables.
+ * May change the internal representation of the body object
+ * to compiled code.
*
*----------------------------------------------------------------------
*/
-
-static int
-CompileProcBody(interp, procPtr, procName, nameLen)
- Tcl_Interp *interp; /* The interpreter in which to compile the
- * procedure's body. */
- Proc *procPtr; /* Points to structure describing the Tcl
- * procedure. */
- char *procName; /* Name of the procedure. Used for error
- * messages and trace information. */
- int nameLen; /* Number of bytes in procedure's name. */
+
+int
+TclProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description, procName)
+ Tcl_Interp *interp; /* Interpreter containing procedure. */
+ Proc *procPtr; /* Data associated with procedure. */
+ Tcl_Obj *bodyPtr; /* Body of proc. (Usually procPtr->bodyPtr,
+ * but could be any code fragment compiled
+ * in the context of this procedure.) */
+ Namespace *nsPtr; /* Namespace containing procedure. */
+ CONST char *description; /* string describing this body of code. */
+ CONST char *procName; /* Name of this procedure. */
{
- register Interp *iPtr = (Interp *) interp;
- Tcl_Obj *bodyPtr = procPtr->bodyPtr;
+ Interp *iPtr = (Interp*)interp;
+ int result;
+ Tcl_CallFrame frame;
Proc *saveProcPtr;
- char buf[100 + TCL_INTEGER_SPACE];
- int numChars, result;
- char *ellipsis;
-
- if (tclTraceCompile >= 1) {
- numChars = nameLen;
- ellipsis = "";
- if (numChars > 50) {
- numChars = 50;
- ellipsis = "...";
- }
- fprintf(stdout, "Compiling body of proc \"%.*s%s\"\n",
- numChars, procName, ellipsis);
+ ByteCode *codePtr = (ByteCode *) bodyPtr->internalRep.otherValuePtr;
+
+ /*
+ * If necessary, compile the procedure's body. The compiler will
+ * allocate frame slots for the procedure's non-argument local
+ * variables. If the ByteCode already exists, make sure it hasn't been
+ * invalidated by someone redefining a core command (this might make the
+ * compiled code wrong). Also, if the code was compiled in/for a
+ * different interpreter, we recompile it. Note that compiling the body
+ * might increase procPtr->numCompiledLocals if new local variables are
+ * found while compiling.
+ *
+ * Precompiled procedure bodies, however, are immutable and therefore
+ * they are not recompiled, even if things have changed.
+ */
+
+ if (bodyPtr->typePtr == &tclByteCodeType) {
+ if (((Interp *) *codePtr->interpHandle != iPtr)
+ || (codePtr->compileEpoch != iPtr->compileEpoch)
+ || (codePtr->nsPtr != nsPtr)) {
+ if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
+ if ((Interp *) *codePtr->interpHandle != iPtr) {
+ Tcl_AppendResult(interp,
+ "a precompiled script jumped interps", NULL);
+ return TCL_ERROR;
+ }
+ codePtr->compileEpoch = iPtr->compileEpoch;
+ codePtr->nsPtr = nsPtr;
+ } else {
+ (*tclByteCodeType.freeIntRepProc)(bodyPtr);
+ bodyPtr->typePtr = (Tcl_ObjType *) NULL;
+ }
+ }
}
-
- saveProcPtr = iPtr->compiledProcPtr;
- iPtr->compiledProcPtr = procPtr;
- result = tclByteCodeType.setFromAnyProc(interp, bodyPtr);
- iPtr->compiledProcPtr = saveProcPtr;
-
- if (result == TCL_ERROR) {
- numChars = nameLen;
- ellipsis = "";
- if (numChars > 50) {
- numChars = 50;
- ellipsis = "...";
+ if (bodyPtr->typePtr != &tclByteCodeType) {
+ char buf[100];
+ int numChars;
+ char *ellipsis;
+
+ if (tclTraceCompile >= 1) {
+ /*
+ * Display a line summarizing the top level command we
+ * are about to compile.
+ */
+
+ numChars = strlen(procName);
+ ellipsis = "";
+ if (numChars > 50) {
+ numChars = 50;
+ ellipsis = "...";
+ }
+ fprintf(stdout, "Compiling %s \"%.*s%s\"\n",
+ description, numChars, procName, ellipsis);
+ }
+
+ /*
+ * Plug the current procPtr into the interpreter and coerce
+ * the code body to byte codes. The interpreter needs to
+ * know which proc it's compiling so that it can access its
+ * list of compiled locals.
+ *
+ * TRICKY NOTE: Be careful to push a call frame with the
+ * proper namespace context, so that the byte codes are
+ * compiled in the appropriate class context.
+ */
+
+ saveProcPtr = iPtr->compiledProcPtr;
+ iPtr->compiledProcPtr = procPtr;
+
+ result = Tcl_PushCallFrame(interp, &frame,
+ (Tcl_Namespace*)nsPtr, /* isProcCallFrame */ 0);
+
+ if (result == TCL_OK) {
+ result = tclByteCodeType.setFromAnyProc(interp, bodyPtr);
+ Tcl_PopCallFrame(interp);
+ }
+
+ iPtr->compiledProcPtr = saveProcPtr;
+
+ if (result != TCL_OK) {
+ if (result == TCL_ERROR) {
+ numChars = strlen(procName);
+ ellipsis = "";
+ if (numChars > 50) {
+ numChars = 50;
+ ellipsis = "...";
+ }
+ sprintf(buf, "\n (compiling %s \"%.*s%s\", line %d)",
+ description, numChars, procName, ellipsis,
+ interp->errorLine);
+ Tcl_AddObjErrorInfo(interp, buf, -1);
+ }
+ return result;
+ }
+ } else if (codePtr->nsEpoch != nsPtr->resolverEpoch) {
+ register CompiledLocal *localPtr;
+
+ /*
+ * The resolver epoch has changed, but we only need to invalidate
+ * the resolver cache.
+ */
+
+ for (localPtr = procPtr->firstLocalPtr; localPtr != NULL;
+ localPtr = localPtr->nextPtr) {
+ localPtr->flags &= ~(VAR_RESOLVED);
+ if (localPtr->resolveInfo) {
+ if (localPtr->resolveInfo->deleteProc) {
+ localPtr->resolveInfo->deleteProc(localPtr->resolveInfo);
+ } else {
+ ckfree((char*)localPtr->resolveInfo);
+ }
+ localPtr->resolveInfo = NULL;
+ }
}
- sprintf(buf, "\n (compiling body of proc \"%.*s%s\", line %d)",
- numChars, procName, ellipsis, interp->errorLine);
- Tcl_AddObjErrorInfo(interp, buf, -1);
}
- return result;
+ return TCL_OK;
}
/*
@@ -1001,7 +1119,7 @@ ProcessProcResultCode(interp, procName, nameLen, returnCode)
/*
*----------------------------------------------------------------------
*
- * ProcDeleteProc --
+ * TclProcDeleteProc --
*
* This procedure is invoked just before a command procedure is
* removed from an interpreter. Its job is to release all the
@@ -1018,22 +1136,22 @@ ProcessProcResultCode(interp, procName, nameLen, returnCode)
*----------------------------------------------------------------------
*/
-static void
-ProcDeleteProc(clientData)
+void
+TclProcDeleteProc(clientData)
ClientData clientData; /* Procedure to be deleted. */
{
Proc *procPtr = (Proc *) clientData;
procPtr->refCount--;
if (procPtr->refCount <= 0) {
- CleanupProc(procPtr);
+ TclProcCleanupProc(procPtr);
}
}
/*
*----------------------------------------------------------------------
*
- * CleanupProc --
+ * TclProcCleanupProc --
*
* This procedure does all the real work of freeing up a Proc
* structure. It's called only when the structure's reference
@@ -1048,13 +1166,14 @@ ProcDeleteProc(clientData)
*----------------------------------------------------------------------
*/
-static void
-CleanupProc(procPtr)
+void
+TclProcCleanupProc(procPtr)
register Proc *procPtr; /* Procedure to be deleted. */
{
register CompiledLocal *localPtr;
Tcl_Obj *bodyPtr = procPtr->bodyPtr;
Tcl_Obj *defPtr;
+ Tcl_ResolvedVarInfo *resVarInfo;
if (bodyPtr != NULL) {
Tcl_DecrRefCount(bodyPtr);
@@ -1062,6 +1181,15 @@ CleanupProc(procPtr)
for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; ) {
CompiledLocal *nextPtr = localPtr->nextPtr;
+ resVarInfo = localPtr->resolveInfo;
+ if (resVarInfo) {
+ if (resVarInfo->deleteProc) {
+ (*resVarInfo->deleteProc)(resVarInfo);
+ } else {
+ ckfree((char *) resVarInfo);
+ }
+ }
+
if (localPtr->defValuePtr != NULL) {
defPtr = localPtr->defValuePtr;
Tcl_DecrRefCount(defPtr);
@@ -1114,3 +1242,53 @@ TclUpdateReturnInfo(iPtr)
}
return code;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclGetInterpProc --
+ *
+ * Returns a pointer to the TclProcInterpProc procedure; this is different
+ * from the value obtained from the TclProcInterpProc reference on systems
+ * like Windows where import and export versions of a procedure exported
+ * by a DLL exist.
+ *
+ * Results:
+ * Returns the internal address of the TclProcInterpProc procedure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+TclCmdProcType
+TclGetInterpProc()
+{
+ return TclProcInterpProc;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclGetObjInterpProc --
+ *
+ * Returns a pointer to the TclObjInterpProc procedure; this is different
+ * from the value obtained from the TclObjInterpProc reference on systems
+ * like Windows where import and export versions of a procedure exported
+ * by a DLL exist.
+ *
+ * Results:
+ * Returns the internal address of the TclProcInterpProc procedure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+TclObjCmdProcType
+TclGetObjInterpProc()
+{
+ return TclObjInterpProc;
+}