summaryrefslogtreecommitdiffstats
path: root/generic/tclProc.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclProc.c')
-rw-r--r--generic/tclProc.c1856
1 files changed, 967 insertions, 889 deletions
diff --git a/generic/tclProc.c b/generic/tclProc.c
index a35fe60..d58e8da 100644
--- a/generic/tclProc.c
+++ b/generic/tclProc.c
@@ -4,10 +4,10 @@
* This file contains routines that implement Tcl procedures, including
* the "proc" and "uplevel" commands.
*
- * Copyright © 1987-1993 The Regents of the University of California.
- * Copyright © 1994-1998 Sun Microsystems, Inc.
- * Copyright © 2004-2006 Miguel Sofer
- * Copyright © 2007 Daniel A. Steffen <das@users.sourceforge.net>
+ * Copyright (c) 1987-1993 The Regents of the University of California.
+ * Copyright (c) 1994-1998 Sun Microsystems, Inc.
+ * Copyright (c) 2004-2006 Miguel Sofer
+ * Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net>
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -15,17 +15,6 @@
#include "tclInt.h"
#include "tclCompile.h"
-#include <assert.h>
-
-/*
- * Variables that are part of the [apply] command implementation and which
- * have to be passed to the other side of the NRE call.
- */
-
-typedef struct {
- Command cmd;
- ExtraFrameInfo efi;
-} ApplyExtraData;
/*
* Prototypes for static functions in this file
@@ -34,29 +23,33 @@ typedef struct {
static void DupLambdaInternalRep(Tcl_Obj *objPtr,
Tcl_Obj *copyPtr);
static void FreeLambdaInternalRep(Tcl_Obj *objPtr);
-static int InitArgsAndLocals(Tcl_Interp *interp, Tcl_Size skip);
+static int InitArgsAndLocals(Tcl_Interp *interp,
+ Tcl_Obj *procNameObj, int skip);
static void InitResolvedLocals(Tcl_Interp *interp,
ByteCode *codePtr, Var *defPtr,
- Namespace *nsPtr);
-static void InitLocalCache(Proc *procPtr);
+ Namespace *nsPtr);
+static void InitLocalCache(Proc *procPtr);
+static int PushProcCallFrame(ClientData clientData,
+ register Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[], int isLambda);
static void ProcBodyDup(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr);
static void ProcBodyFree(Tcl_Obj *objPtr);
-static int ProcWrongNumArgs(Tcl_Interp *interp, Tcl_Size skip);
+static int ProcWrongNumArgs(Tcl_Interp *interp, int skip);
static void MakeProcError(Tcl_Interp *interp,
Tcl_Obj *procNameObj);
static void MakeLambdaError(Tcl_Interp *interp,
Tcl_Obj *procNameObj);
static int SetLambdaFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
-
-static Tcl_NRPostProc ApplyNR2;
-static Tcl_NRPostProc InterpProcNR2;
-static Tcl_NRPostProc Uplevel_Callback;
+static int ProcCompileProc(Tcl_Interp *interp, Proc *procPtr,
+ Tcl_Obj *bodyPtr, Namespace *nsPtr,
+ CONST char *description, CONST char *procName,
+ Proc **procPtrPtr);
/*
* The ProcBodyObjType type
*/
-const Tcl_ObjType tclProcBodyType = {
+Tcl_ObjType tclProcBodyType = {
"procbody", /* name for this type */
ProcBodyFree, /* FreeInternalRep function */
ProcBodyDup, /* DupInternalRep function */
@@ -67,31 +60,16 @@ const Tcl_ObjType tclProcBodyType = {
* should panic instead. */
};
-#define ProcSetInternalRep(objPtr, procPtr) \
- do { \
- Tcl_ObjInternalRep ir; \
- (procPtr)->refCount++; \
- ir.twoPtrValue.ptr1 = (procPtr); \
- ir.twoPtrValue.ptr2 = NULL; \
- Tcl_StoreInternalRep((objPtr), &tclProcBodyType, &ir); \
- } while (0)
-
-#define ProcGetInternalRep(objPtr, procPtr) \
- do { \
- const Tcl_ObjInternalRep *irPtr; \
- irPtr = TclFetchInternalRep((objPtr), &tclProcBodyType); \
- (procPtr) = irPtr ? (Proc *)irPtr->twoPtrValue.ptr1 : NULL; \
- } while (0)
-
/*
- * The [upvar]/[uplevel] level reference type. Uses the wideValue field
- * to remember the integer value of a parsed #<integer> format.
+ * The [upvar]/[uplevel] level reference type. Uses the twoPtrValue field,
+ * encoding the type of level reference in ptr1 and the actual parsed out
+ * offset in ptr2.
*
* Uses the default behaviour throughout, and never disposes of the string
* rep; it's just a cache type.
*/
-static const Tcl_ObjType levelReferenceType = {
+static Tcl_ObjType levelReferenceType = {
"levelReference",
NULL, NULL, NULL, NULL
};
@@ -102,34 +80,16 @@ static const Tcl_ObjType levelReferenceType = {
*
* Internally, ptr1 is a pointer to a Proc instance that is not bound to a
* command name, and ptr2 is a pointer to the namespace that the Proc instance
- * will execute within. IF YOU CHANGE THIS, CHECK IN tclDisassemble.c TOO.
+ * will execute within.
*/
-static const Tcl_ObjType lambdaType = {
+static Tcl_ObjType lambdaType = {
"lambdaExpr", /* name */
FreeLambdaInternalRep, /* freeIntRepProc */
DupLambdaInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
SetLambdaFromAny /* setFromAnyProc */
};
-
-#define LambdaSetInternalRep(objPtr, procPtr, nsObjPtr) \
- do { \
- Tcl_ObjInternalRep ir; \
- ir.twoPtrValue.ptr1 = (procPtr); \
- ir.twoPtrValue.ptr2 = (nsObjPtr); \
- Tcl_IncrRefCount((nsObjPtr)); \
- Tcl_StoreInternalRep((objPtr), &lambdaType, &ir); \
- } while (0)
-
-#define LambdaGetInternalRep(objPtr, procPtr, nsObjPtr) \
- do { \
- const Tcl_ObjInternalRep *irPtr; \
- irPtr = TclFetchInternalRep((objPtr), &lambdaType); \
- (procPtr) = irPtr ? (Proc *)irPtr->twoPtrValue.ptr1 : NULL; \
- (nsObjPtr) = irPtr ? (Tcl_Obj *)irPtr->twoPtrValue.ptr2 : NULL; \
- } while (0)
-
/*
*----------------------------------------------------------------------
@@ -148,20 +108,21 @@ static const Tcl_ObjType lambdaType = {
*----------------------------------------------------------------------
*/
-#undef TclObjInterpProc
+ /* ARGSUSED */
int
Tcl_ProcObjCmd(
- TCL_UNUSED(void *),
+ ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
- Tcl_Size objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *CONST objv[]) /* Argument objects. */
{
- Interp *iPtr = (Interp *) interp;
+ register Interp *iPtr = (Interp *) interp;
Proc *procPtr;
- const char *procName;
- const char *simpleName, *procArgs, *procBody;
+ char *fullName;
+ CONST char *procName, *procArgs, *procBody;
Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
Tcl_Command cmd;
+ Tcl_DString ds;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "name args body");
@@ -174,22 +135,25 @@ Tcl_ProcObjCmd(
* namespace.
*/
- procName = TclGetString(objv[1]);
- TclGetNamespaceForQualName(interp, procName, NULL, 0,
- &nsPtr, &altNsPtr, &cxtNsPtr, &simpleName);
+ fullName = TclGetString(objv[1]);
+ TclGetNamespaceForQualName(interp, fullName, NULL, 0,
+ &nsPtr, &altNsPtr, &cxtNsPtr, &procName);
if (nsPtr == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't create procedure \"%s\": unknown namespace",
- procName));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", (void *)NULL);
+ Tcl_AppendResult(interp, "can't create procedure \"", fullName,
+ "\": unknown namespace", NULL);
return TCL_ERROR;
}
- if (simpleName == NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't create procedure \"%s\": bad procedure name",
- procName));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "COMMAND", (void *)NULL);
+ if (procName == NULL) {
+ Tcl_AppendResult(interp, "can't create procedure \"", fullName,
+ "\": bad procedure name", NULL);
+ return TCL_ERROR;
+ }
+ if ((nsPtr != iPtr->globalNsPtr)
+ && (procName != NULL) && (procName[0] == ':')) {
+ Tcl_AppendResult(interp, "can't create procedure \"", procName,
+ "\" in non-global namespace with name starting with \":\"",
+ NULL);
return TCL_ERROR;
}
@@ -197,16 +161,32 @@ Tcl_ProcObjCmd(
* Create the data structure to represent the procedure.
*/
- if (TclCreateProc(interp, /*ignored nsPtr*/ NULL, simpleName, objv[2],
- objv[3], &procPtr) != TCL_OK) {
+ if (TclCreateProc(interp, nsPtr, procName, objv[2], objv[3],
+ &procPtr) != TCL_OK) {
Tcl_AddErrorInfo(interp, "\n (creating proc \"");
- Tcl_AddErrorInfo(interp, simpleName);
+ Tcl_AddErrorInfo(interp, procName);
Tcl_AddErrorInfo(interp, "\")");
return TCL_ERROR;
}
- cmd = TclNRCreateCommandInNs(interp, simpleName, (Tcl_Namespace *) nsPtr,
- TclObjInterpProc, TclNRInterpProc, procPtr, TclProcDeleteProc);
+ /*
+ * 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);
+
+ cmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds),
+ TclObjInterpProc, (ClientData) procPtr, TclProcDeleteProc);
+
+ Tcl_DStringFree(&ds);
/*
* Now initialize the new procedure's cmdPtr field. This will be used
@@ -225,15 +205,17 @@ Tcl_ProcObjCmd(
*
* This code is nearly identical to the #280 code in SetLambdaFromAny, see
* this file. The differences are the different index of the body in the
- * line array of the context, and the lambda code requires some special
+ * line array of the context, and the lamdba code requires some special
* processing. Find a way to factor the common elements into a single
* function.
*/
if (iPtr->cmdFramePtr) {
- CmdFrame *contextPtr = (CmdFrame *)TclStackAlloc(interp, sizeof(CmdFrame));
+ CmdFrame *contextPtr;
+ contextPtr = (CmdFrame *) TclStackAlloc(interp, sizeof(CmdFrame));
*contextPtr = *iPtr->cmdFramePtr;
+
if (contextPtr->type == TCL_LOCATION_BC) {
/*
* Retrieve source information from the bytecode, if possible. If
@@ -261,12 +243,12 @@ Tcl_ProcObjCmd(
if (contextPtr->line
&& (contextPtr->nline >= 4) && (contextPtr->line[3] >= 0)) {
int isNew;
- Tcl_HashEntry *hePtr;
- CmdFrame *cfPtr = (CmdFrame *)ckalloc(sizeof(CmdFrame));
+ Tcl_HashEntry* hePtr;
+ CmdFrame *cfPtr = (CmdFrame *) ckalloc(sizeof(CmdFrame));
cfPtr->level = -1;
cfPtr->type = contextPtr->type;
- cfPtr->line = (Tcl_Size *)ckalloc(sizeof(Tcl_Size));
+ cfPtr->line = (int *) ckalloc(sizeof(int));
cfPtr->line[0] = contextPtr->line[3];
cfPtr->nline = 1;
cfPtr->framePtr = NULL;
@@ -275,35 +257,34 @@ Tcl_ProcObjCmd(
cfPtr->data.eval.path = contextPtr->data.eval.path;
Tcl_IncrRefCount(cfPtr->data.eval.path);
- cfPtr->cmd = NULL;
- cfPtr->len = 0;
+ cfPtr->cmd.str.cmd = NULL;
+ cfPtr->cmd.str.len = 0;
- hePtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr,
- procPtr, &isNew);
+ hePtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr, (char *) procPtr, &isNew);
if (!isNew) {
/*
- * Get the old command frame and release it. See also
+ * Get the old command frame and release it. See also
* TclProcCleanupProc in this file. Currently it seems as
* if only the procbodytest::proc command of the testsuite
* is able to trigger this situation.
*/
- CmdFrame *cfOldPtr = (CmdFrame *)Tcl_GetHashValue(hePtr);
+ CmdFrame* cfOldPtr = (CmdFrame *) Tcl_GetHashValue(hePtr);
if (cfOldPtr->type == TCL_LOCATION_SOURCE) {
Tcl_DecrRefCount(cfOldPtr->data.eval.path);
cfOldPtr->data.eval.path = NULL;
}
- ckfree(cfOldPtr->line);
+ ckfree((char *) cfOldPtr->line);
cfOldPtr->line = NULL;
- ckfree(cfOldPtr);
+ ckfree((char *) cfOldPtr);
}
Tcl_SetHashValue(hePtr, cfPtr);
}
/*
- * 'contextPtr' is going out of scope; account for the reference
- * that it's holding to the path name.
+ * 'contextPtr' is going out of scope; account for the reference that
+ * it's holding to the path name.
*/
Tcl_DecrRefCount(contextPtr->data.eval.path);
@@ -328,7 +309,7 @@ Tcl_ProcObjCmd(
* of all procs whose argument list is just _args_
*/
- if (TclHasInternalRep(objv[3], &tclProcBodyType)) {
+ if (objv[3]->typePtr == &tclProcBodyType) {
goto done;
}
@@ -339,7 +320,7 @@ Tcl_ProcObjCmd(
}
if ((procArgs[0] == 'a') && (strncmp(procArgs, "args", 4) == 0)) {
- Tcl_Size numBytes;
+ int numBytes;
procArgs +=4;
while (*procArgs != '\0') {
@@ -353,7 +334,7 @@ Tcl_ProcObjCmd(
* The argument list is just "args"; check the body
*/
- procBody = TclGetStringFromObj(objv[3], &numBytes);
+ procBody = Tcl_GetStringFromObj(objv[3], &numBytes);
if (TclParseAllWhiteSpace(procBody, numBytes) < numBytes) {
goto done;
}
@@ -396,22 +377,23 @@ Tcl_ProcObjCmd(
int
TclCreateProc(
Tcl_Interp *interp, /* Interpreter containing proc. */
- TCL_UNUSED(Namespace *) /*nsPtr*/,
- const char *procName, /* Unqualified name of this proc. */
+ Namespace *nsPtr, /* Namespace containing this proc. */
+ CONST 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;
+ CONST char **argArray = NULL;
- Proc *procPtr = NULL;
- Tcl_Size i, numArgs;
- CompiledLocal *localPtr = NULL;
- Tcl_Obj **argArray;
- int precompiled = 0, result;
+ register Proc *procPtr;
+ int i, length, result, numArgs;
+ CONST char *args, *bytes, *p;
+ register CompiledLocal *localPtr = NULL;
+ Tcl_Obj *defPtr;
+ int precompiled = 0;
- ProcGetInternalRep(bodyPtr, procPtr);
- if (procPtr != NULL) {
+ if (bodyPtr->typePtr == &tclProcBodyType) {
/*
* Because the body is a TclProProcBody, the actual body is already
* compiled, and it is not shared with anyone else, so it's OK not to
@@ -424,6 +406,7 @@ TclCreateProc(
* will be holding a reference to it.
*/
+ procPtr = bodyPtr->internalRep.twoPtrValue.ptr1;
procPtr->iPtr = iPtr;
procPtr->refCount++;
precompiled = 1;
@@ -444,9 +427,7 @@ TclCreateProc(
*/
if (Tcl_IsShared(bodyPtr)) {
- const char *bytes;
- Tcl_Size length;
- Tcl_Obj *sharedBodyPtr = bodyPtr;
+ Tcl_Obj* sharedBodyPtr = bodyPtr;
bytes = TclGetStringFromObj(bodyPtr, &length);
bodyPtr = Tcl_NewStringObj(bytes, length);
@@ -457,7 +438,7 @@ TclCreateProc(
* not lost and applies to the new body as well.
*/
- TclContinuationsCopy(bodyPtr, sharedBodyPtr);
+ TclContinuationsCopy (bodyPtr, sharedBodyPtr);
}
/*
@@ -468,7 +449,7 @@ TclCreateProc(
Tcl_IncrRefCount(bodyPtr);
- procPtr = (Proc *)ckalloc(sizeof(Proc));
+ procPtr = (Proc *) ckalloc(sizeof(Proc));
procPtr->iPtr = iPtr;
procPtr->refCount = 1;
procPtr->bodyPtr = bodyPtr;
@@ -483,9 +464,12 @@ TclCreateProc(
* argument specifier. If the body is precompiled, processing is limited
* to checking that the parsed argument is consistent with the one stored
* in the Proc.
+ *
+ * THIS FAILS IF THE ARG LIST OBJECT'S STRING REP CONTAINS NULS.
*/
- result = TclListObjGetElements(interp, argsPtr, &numArgs, &argArray);
+ args = TclGetStringFromObj(argsPtr, &length);
+ result = Tcl_SplitList(interp, args, &numArgs, &argArray);
if (result != TCL_OK) {
goto procError;
}
@@ -493,11 +477,9 @@ TclCreateProc(
if (precompiled) {
if (numArgs > procPtr->numArgs) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "procedure \"%s\": arg list contains %" TCL_SIZE_MODIFIER "d entries, "
- "precompiled header expects %" TCL_SIZE_MODIFIER "d", procName, numArgs,
+ "procedure \"%s\": arg list contains %d entries, "
+ "precompiled header expects %d", procName, numArgs,
procPtr->numArgs));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
- "BYTECODELIES", (void *)NULL);
goto procError;
}
localPtr = procPtr->firstLocalPtr;
@@ -507,66 +489,65 @@ TclCreateProc(
}
for (i = 0; i < numArgs; i++) {
- const char *argname, *argnamei, *argnamelast;
- Tcl_Size fieldCount, nameLength;
- Tcl_Obj **fieldValues;
+ int fieldCount, nameLength, valueLength;
+ CONST char **fieldValues;
/*
* Now divide the specifier up into name and default.
*/
- result = TclListObjGetElements(interp, argArray[i], &fieldCount,
+ result = Tcl_SplitList(interp, argArray[i], &fieldCount,
&fieldValues);
if (result != TCL_OK) {
goto procError;
}
if (fieldCount > 2) {
- Tcl_Obj *errorObj = Tcl_NewStringObj(
- "too many fields in argument specifier \"", -1);
- Tcl_AppendObjToObj(errorObj, argArray[i]);
- Tcl_AppendToObj(errorObj, "\"", -1);
- Tcl_SetObjResult(interp, errorObj);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
- "FORMALARGUMENTFORMAT", (void *)NULL);
+ ckfree((char *) fieldValues);
+ Tcl_AppendResult(interp,
+ "too many fields in argument specifier \"",
+ argArray[i], "\"", NULL);
goto procError;
}
- if ((fieldCount == 0) || (TclGetCharLength(fieldValues[0]) == 0)) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "argument with no name", -1));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
- "FORMALARGUMENTFORMAT", (void *)NULL);
+ if ((fieldCount == 0) || (*fieldValues[0] == 0)) {
+ ckfree((char *) fieldValues);
+ Tcl_AppendResult(interp, "argument with no name", NULL);
goto procError;
}
- argname = TclGetStringFromObj(fieldValues[0], &nameLength);
+ nameLength = strlen(fieldValues[0]);
+ if (fieldCount == 2) {
+ valueLength = strlen(fieldValues[1]);
+ } else {
+ valueLength = 0;
+ }
/*
* Check that the formal parameter name is a scalar.
*/
- argnamei = argname;
- argnamelast = (nameLength > 0) ? (argname + nameLength - 1) : argname;
- while (argnamei < argnamelast) {
- if (*argnamei == '(') {
- if (*argnamelast == ')') { /* We have an array element. */
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "formal parameter \"%s\" is an array element",
- Tcl_GetString(fieldValues[0])));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
- "FORMALARGUMENTFORMAT", (void *)NULL);
+ p = fieldValues[0];
+ while (*p != '\0') {
+ if (*p == '(') {
+ CONST char *q = p;
+ do {
+ q++;
+ } while (*q != '\0');
+ q--;
+ if (*q == ')') { /* We have an array element. */
+ Tcl_AppendResult(interp, "formal parameter \"",
+ fieldValues[0],
+ "\" is an array element", NULL);
+ ckfree((char *) fieldValues);
goto procError;
}
- } else if (*argnamei == ':' && *(argnamei+1) == ':') {
- Tcl_Obj *errorObj = Tcl_NewStringObj(
- "formal parameter \"", -1);
- Tcl_AppendObjToObj(errorObj, fieldValues[0]);
- Tcl_AppendToObj(errorObj, "\" is not a simple name", -1);
- Tcl_SetObjResult(interp, errorObj);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
- "FORMALARGUMENTFORMAT", (void *)NULL);
+ } else if ((*p == ':') && (*(p+1) == ':')) {
+ Tcl_AppendResult(interp, "formal parameter \"",
+ fieldValues[0],
+ "\" is not a simple name", NULL);
+ ckfree((char *) fieldValues);
goto procError;
}
- argnamei++;
+ p++;
}
if (precompiled) {
@@ -576,22 +557,21 @@ TclCreateProc(
* (its value was kept the same as pre VarReform to simplify
* tbcload's processing of older byetcodes).
*
- * The only other flag value that is important to retrieve from
+ * The only other flag vlaue that is important to retrieve from
* precompiled procs is VAR_TEMPORARY (also unchanged). It is
* needed later when retrieving the variable names.
*/
if ((localPtr->nameLength != nameLength)
- || (memcmp(localPtr->name, argname, nameLength) != 0)
+ || (strcmp(localPtr->name, fieldValues[0]))
|| (localPtr->frameIndex != i)
|| !(localPtr->flags & VAR_ARGUMENT)
|| (localPtr->defValuePtr == NULL && fieldCount == 2)
|| (localPtr->defValuePtr != NULL && fieldCount != 2)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "procedure \"%s\": formal parameter %" TCL_SIZE_MODIFIER "d is "
+ "procedure \"%s\": formal parameter %d is "
"inconsistent with precompiled body", procName, i));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
- "BYTECODELIES", (void *)NULL);
+ ckfree((char *) fieldValues);
goto procError;
}
@@ -600,21 +580,17 @@ TclCreateProc(
*/
if (localPtr->defValuePtr != NULL) {
- Tcl_Size tmpLength, valueLength;
- const char *tmpPtr = TclGetStringFromObj(localPtr->defValuePtr, &tmpLength);
- const char *value = TclGetStringFromObj(fieldValues[1], &valueLength);
-
- if ((valueLength != tmpLength)
- || memcmp(value, tmpPtr, tmpLength) != 0
- ) {
- Tcl_Obj *errorObj = Tcl_ObjPrintf(
- "procedure \"%s\": formal parameter \"", procName);
- Tcl_AppendObjToObj(errorObj, fieldValues[0]);
- Tcl_AppendToObj(errorObj, "\" has "
- "default value inconsistent with precompiled body", -1);
- Tcl_SetObjResult(interp, errorObj);
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
- "BYTECODELIES", (void *)NULL);
+ int tmpLength;
+ char *tmpPtr = TclGetStringFromObj(localPtr->defValuePtr,
+ &tmpLength);
+
+ if ((valueLength != tmpLength) ||
+ strncmp(fieldValues[1], tmpPtr, (size_t) tmpLength)) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "procedure \"%s\": formal parameter \"%s\" has "
+ "default value inconsistent with precompiled body",
+ procName, fieldValues[0]));
+ ckfree((char *) fieldValues);
goto procError;
}
}
@@ -632,8 +608,9 @@ TclCreateProc(
* local variables for the argument.
*/
- localPtr = (CompiledLocal *)ckalloc(
- offsetof(CompiledLocal, name) + 1U + fieldValues[0]->length);
+ localPtr = (CompiledLocal *) ckalloc((unsigned)
+ (sizeof(CompiledLocal) - sizeof(localPtr->name)
+ + nameLength + 1));
if (procPtr->firstLocalPtr == NULL) {
procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
} else {
@@ -647,22 +624,26 @@ TclCreateProc(
localPtr->resolveInfo = NULL;
if (fieldCount == 2) {
- localPtr->defValuePtr = fieldValues[1];
+ localPtr->defValuePtr =
+ Tcl_NewStringObj(fieldValues[1], valueLength);
Tcl_IncrRefCount(localPtr->defValuePtr);
} else {
localPtr->defValuePtr = NULL;
}
- memcpy(localPtr->name, argname, fieldValues[0]->length + 1);
+ memcpy(localPtr->name, fieldValues[0], nameLength + 1);
if ((i == numArgs - 1)
&& (localPtr->nameLength == 4)
&& (localPtr->name[0] == 'a')
- && (memcmp(localPtr->name, "args", 4) == 0)) {
+ && (strcmp(localPtr->name, "args") == 0)) {
localPtr->flags |= VAR_IS_ARGS;
}
}
+
+ ckfree((char *) fieldValues);
}
*procPtrPtr = procPtr;
+ ckfree((char *) argArray);
return TCL_OK;
procError:
@@ -674,13 +655,17 @@ TclCreateProc(
localPtr = procPtr->firstLocalPtr;
procPtr->firstLocalPtr = localPtr->nextPtr;
- if (localPtr->defValuePtr != NULL) {
- Tcl_DecrRefCount(localPtr->defValuePtr);
+ defPtr = localPtr->defValuePtr;
+ if (defPtr != NULL) {
+ Tcl_DecrRefCount(defPtr);
}
- ckfree(localPtr);
+ ckfree((char *) localPtr);
}
- ckfree(procPtr);
+ ckfree((char *) procPtr);
+ }
+ if (argArray != NULL) {
+ ckfree((char *) argArray);
}
return TCL_ERROR;
}
@@ -713,19 +698,55 @@ TclCreateProc(
int
TclGetFrame(
Tcl_Interp *interp, /* Interpreter in which to find frame. */
- const char *name, /* String describing frame. */
+ CONST char *name, /* String describing frame. */
CallFrame **framePtrPtr) /* Store pointer to frame here (or NULL if
* global frame indicated). */
{
- int result;
- Tcl_Obj obj;
-
- obj.bytes = (char *) name;
- obj.length = strlen(name);
- obj.typePtr = NULL;
- result = TclObjGetFrame(interp, &obj, framePtrPtr);
- TclFreeInternalRep(&obj);
- return result;
+ register Interp *iPtr = (Interp *) interp;
+ int curLevel, level, result;
+ CallFrame *framePtr;
+
+ /*
+ * Parse string to figure out which level number to go to.
+ */
+
+ result = 1;
+ curLevel = iPtr->varFramePtr->level;
+ if (*name== '#') {
+ if (Tcl_GetInt(interp, name+1, &level) != TCL_OK || level < 0) {
+ goto levelError;
+ }
+ } else if (isdigit(UCHAR(*name))) { /* INTL: digit */
+ if (Tcl_GetInt(interp, name, &level) != TCL_OK) {
+ goto levelError;
+ }
+ level = curLevel - level;
+ } else {
+ level = curLevel - 1;
+ result = 0;
+ }
+
+ /*
+ * Figure out which frame to use, and return it to the caller.
+ */
+
+ for (framePtr = iPtr->varFramePtr; framePtr != NULL;
+ framePtr = framePtr->callerVarPtr) {
+ if (framePtr->level == level) {
+ break;
+ }
+ }
+ if (framePtr == NULL) {
+ goto levelError;
+ }
+
+ *framePtrPtr = framePtr;
+ return result;
+
+ levelError:
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "bad level \"", name, "\"", NULL);
+ return -1;
}
/*
@@ -740,7 +761,7 @@ TclGetFrame(
* Results:
* The return value is -1 if an error occurred in finding the frame (in
* this case an error message is left in the interp's result). 1 is
- * returned if objPtr was either an int or an int preceded by "#" and
+ * returned if objPtr was either a number or a number preceded by "#" and
* it specified a valid frame. 0 is returned if objPtr isn't one of the
* two things above (in this case, the lookup acts as if objPtr were
* "1"). The variable pointed to by framePtrPtr is filled in with the
@@ -760,89 +781,95 @@ TclObjGetFrame(
CallFrame **framePtrPtr) /* Store pointer to frame here (or NULL if
* global frame indicated). */
{
- Interp *iPtr = (Interp *) interp;
+ register Interp *iPtr = (Interp *) interp;
int curLevel, level, result;
- const Tcl_ObjInternalRep *irPtr;
- const char *name = NULL;
- Tcl_WideInt w;
+ CallFrame *framePtr;
+ CONST char *name = TclGetString(objPtr);
/*
* Parse object to figure out which level number to go to.
*/
- result = 0;
+ result = 1;
curLevel = iPtr->varFramePtr->level;
+ if (objPtr->typePtr == &levelReferenceType) {
+ if (PTR2INT(objPtr->internalRep.twoPtrValue.ptr1)) {
+ level = curLevel - PTR2INT(objPtr->internalRep.twoPtrValue.ptr2);
+ } else {
+ level = PTR2INT(objPtr->internalRep.twoPtrValue.ptr2);
+ }
+ if (level < 0) {
+ goto levelError;
+ }
+ /* TODO: Consider skipping the typePtr checks */
+ } else if (objPtr->typePtr == &tclIntType
+#ifndef NO_WIDE_TYPE
+ || objPtr->typePtr == &tclWideIntType
+#endif
+ ) {
+ if (TclGetIntFromObj(NULL, objPtr, &level) != TCL_OK || level < 0) {
+ goto levelError;
+ }
+ level = curLevel - level;
+ } else if (*name == '#') {
+ if (Tcl_GetInt(interp, name+1, &level) != TCL_OK || level < 0) {
+ goto levelError;
+ }
- /*
- * Check for integer first, since that has potential to spare us
- * a generation of a stringrep.
- */
+ /*
+ * Cache for future reference.
+ *
+ * TODO: Use the new ptrAndLongRep intrep
+ */
- if (objPtr == NULL) {
- /* Do nothing */
- } else if (TCL_OK == Tcl_GetIntFromObj(NULL, objPtr, &level)) {
- Tcl_GetWideIntFromObj(NULL, objPtr, &w);
- if (w < 0 || w > INT_MAX || curLevel > w + INT_MAX) {
- result = -1;
- } else {
- level = curLevel - level;
- result = 1;
+ TclFreeIntRep(objPtr);
+ objPtr->typePtr = &levelReferenceType;
+ objPtr->internalRep.twoPtrValue.ptr1 = (void *) 0;
+ objPtr->internalRep.twoPtrValue.ptr2 = INT2PTR(level);
+ } else if (isdigit(UCHAR(*name))) { /* INTL: digit */
+ if (Tcl_GetInt(interp, name, &level) != TCL_OK) {
+ return -1;
}
- } else if ((irPtr = TclFetchInternalRep(objPtr, &levelReferenceType))) {
- level = irPtr->wideValue;
- result = 1;
+
+ /*
+ * Cache for future reference.
+ *
+ * TODO: Use the new ptrAndLongRep intrep
+ */
+
+ TclFreeIntRep(objPtr);
+ objPtr->typePtr = &levelReferenceType;
+ objPtr->internalRep.twoPtrValue.ptr1 = (void *) 1;
+ objPtr->internalRep.twoPtrValue.ptr2 = INT2PTR(level);
+ level = curLevel - level;
} else {
- name = TclGetString(objPtr);
- if (name[0] == '#') {
- if (TCL_OK == Tcl_GetInt(NULL, name+1, &level)) {
- if (level < 0 || (level > 0 && name[1] == '-')) {
- result = -1;
- } else {
- Tcl_ObjInternalRep ir;
+ /*
+ * Don't cache as the object *isn't* a level reference.
+ */
- ir.wideValue = level;
- Tcl_StoreInternalRep(objPtr, &levelReferenceType, &ir);
- result = 1;
- }
- } else {
- result = -1;
- }
- } else if (TclGetWideBitsFromObj(NULL, objPtr, &w) == TCL_OK) {
- /*
- * If this were an integer, we'd have succeeded already.
- * Docs say we have to treat this as a 'bad level' error.
- */
- result = -1;
- }
+ level = curLevel - 1;
+ result = 0;
}
- if (result != -1) {
- /* if relative current level */
- if (result == 0) {
- if (!curLevel) {
- /* we are in top-level, so simply generate bad level */
- name = "1";
- goto badLevel;
- }
- level = curLevel - 1;
- }
- if (level >= 0) {
- CallFrame *framePtr;
- for (framePtr = iPtr->varFramePtr; framePtr != NULL;
- framePtr = framePtr->callerVarPtr) {
- if (framePtr->level == level) {
- *framePtrPtr = framePtr;
- return result;
- }
- }
+ /*
+ * Figure out which frame to use, and return it to the caller.
+ */
+
+ for (framePtr = iPtr->varFramePtr; framePtr != NULL;
+ framePtr = framePtr->callerVarPtr) {
+ if (framePtr->level == level) {
+ break;
}
}
-badLevel:
- if (name == NULL) {
- name = objPtr ? TclGetString(objPtr) : "1" ;
+ if (framePtr == NULL) {
+ goto levelError;
}
- Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad level \"%s\"", name));
- Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "LEVEL", name, (void *)NULL);
+ *framePtrPtr = framePtr;
+ return result;
+
+ levelError:
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "bad level \"", name, "\"", NULL);
return -1;
}
@@ -863,76 +890,22 @@ badLevel:
*----------------------------------------------------------------------
*/
-static int
-Uplevel_Callback(
- void *data[],
- Tcl_Interp *interp,
- int result)
-{
- CallFrame *savedVarFramePtr = (CallFrame *)data[0];
-
- if (result == TCL_ERROR) {
- Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
- "\n (\"uplevel\" body line %d)", Tcl_GetErrorLine(interp)));
- }
-
- /*
- * Restore the variable frame, and return.
- */
-
- ((Interp *)interp)->varFramePtr = savedVarFramePtr;
- return result;
-}
-
+ /* ARGSUSED */
int
Tcl_UplevelObjCmd(
- void *clientData,
+ ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
+ Tcl_Obj *CONST objv[]) /* Argument objects. */
{
- return Tcl_NRCallObjProc(interp, TclNRUplevelObjCmd, clientData, objc, objv);
-}
-
-int
-TclNRUplevelObjCmd(
- TCL_UNUSED(void *),
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
-
- Interp *iPtr = (Interp *) interp;
- CmdFrame *invoker = NULL;
- int word = 0;
+ register Interp *iPtr = (Interp *) interp;
int result;
CallFrame *savedVarFramePtr, *framePtr;
- Tcl_Obj *objPtr;
if (objc < 2) {
- /* to do
- * simplify things by interpreting the argument as a command when there
- * is only one argument. This requires a TIP since currently a single
- * argument is interpreted as a level indicator if possible.
- */
uplevelSyntax:
Tcl_WrongNumArgs(interp, 1, objv, "?level? command ?arg ...?");
return TCL_ERROR;
- } else if (!TclHasStringRep(objv[1]) && objc == 2) {
- int status;
- Tcl_Size llength;
- status = TclListObjLength(interp, objv[1], &llength);
- if (status == TCL_OK && llength > 1) {
- /* the first argument can't interpreted as a level. Avoid
- * generating a string representation of the script. */
- result = TclGetFrame(interp, "1", &framePtr);
- if (result == -1) {
- return TCL_ERROR;
- }
- objc -= 1;
- objv += 1;
- goto havelevel;
- }
}
/*
@@ -943,13 +916,11 @@ TclNRUplevelObjCmd(
if (result == -1) {
return TCL_ERROR;
}
- objc -= result + 1;
+ objc -= (result+1);
if (objc == 0) {
goto uplevelSyntax;
}
- objv += result + 1;
-
- havelevel:
+ objv += (result+1);
/*
* Modify the interpreter state to execute in the given frame.
@@ -964,12 +935,14 @@ TclNRUplevelObjCmd(
if (objc == 1) {
/*
- * TIP #280. Make actual argument location available to eval'd script
+ * TIP #280. Make argument location available to eval'd script
*/
- TclArgumentGet(interp, objv[0], &invoker, &word);
- objPtr = objv[0];
+ CmdFrame* invoker = NULL;
+ int word = 0;
+ TclArgumentGet (interp, objv[0], &invoker, &word);
+ result = TclEvalObjEx(interp, objv[0], 0, invoker, word);
} else {
/*
* More than one argument: concatenate them together with spaces
@@ -977,12 +950,22 @@ TclNRUplevelObjCmd(
* object when it decrements its refcount after eval'ing it.
*/
+ Tcl_Obj *objPtr;
+
objPtr = Tcl_ConcatObj(objc, objv);
+ result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT);
}
+ if (result == TCL_ERROR) {
+ Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
+ "\n (\"uplevel\" body line %d)", interp->errorLine));
+ }
+
+ /*
+ * Restore the variable frame, and return.
+ */
- TclNRAddCallback(interp, Uplevel_Callback, savedVarFramePtr, NULL, NULL,
- NULL);
- return TclNREvalObjEx(interp, objPtr, 0, invoker, word);
+ iPtr->varFramePtr = savedVarFramePtr;
+ return result;
}
/*
@@ -1011,9 +994,10 @@ TclNRUplevelObjCmd(
Proc *
TclFindProc(
Interp *iPtr, /* Interpreter in which to look. */
- const char *procName) /* Name of desired procedure. */
+ CONST char *procName) /* Name of desired procedure. */
{
Tcl_Command cmd;
+ Tcl_Command origCmd;
Command *cmdPtr;
cmd = Tcl_FindCommand((Tcl_Interp *) iPtr, procName, NULL, /*flags*/ 0);
@@ -1022,7 +1006,14 @@ TclFindProc(
}
cmdPtr = (Command *) cmd;
- return TclIsProc(cmdPtr);
+ origCmd = TclGetOriginalCommand(cmd);
+ if (origCmd != NULL) {
+ cmdPtr = (Command *) origCmd;
+ }
+ if (cmdPtr->objProc != TclObjInterpProc) {
+ return NULL;
+ }
+ return (Proc *) cmdPtr->objClientData;
}
/*
@@ -1047,25 +1038,46 @@ Proc *
TclIsProc(
Command *cmdPtr) /* Command to test. */
{
- Tcl_Command origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr);
+ Tcl_Command origCmd;
+ origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (origCmd != NULL) {
cmdPtr = (Command *) origCmd;
}
- if (cmdPtr->deleteProc == TclProcDeleteProc) {
- return (Proc *)cmdPtr->objClientData;
+ if (cmdPtr->objProc == TclObjInterpProc) {
+ return (Proc *) cmdPtr->objClientData;
}
- return NULL;
+ return (Proc *) 0;
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * InitArgsAndLocals --
+ *
+ * This routine is invoked in order to initialize the arguments and other
+ * compiled locals table for a new call frame.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * Allocates memory on the stack for the compiled local variables, the
+ * caller is responsible for freeing them. Initialises all variables. May
+ * invoke various name resolvers in order to determine which variables
+ * are being referenced at runtime.
+ *
+ *----------------------------------------------------------------------
+ */
+
static int
ProcWrongNumArgs(
- Tcl_Interp *interp,
- Tcl_Size skip)
+ Tcl_Interp *interp, int skip)
{
CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
- Proc *procPtr = framePtr->procPtr;
- Tcl_Size localCt = procPtr->numCompiledLocals, numArgs, i;
+ register Proc *procPtr = framePtr->procPtr;
+ register Var *defPtr;
+ int localCt = procPtr->numCompiledLocals, numArgs, i;
Tcl_Obj **desiredObjs;
const char *final = NULL;
@@ -1074,40 +1086,39 @@ ProcWrongNumArgs(
*/
numArgs = framePtr->procPtr->numArgs;
- desiredObjs = (Tcl_Obj **)TclStackAlloc(interp,
- sizeof(Tcl_Obj *) * (numArgs+1));
+ desiredObjs = (Tcl_Obj **) TclStackAlloc(interp,
+ (int) sizeof(Tcl_Obj *) * (numArgs+1));
if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
desiredObjs[0] = Tcl_NewStringObj("lambdaExpr", -1);
} else {
+ ((Interp *) interp)->ensembleRewrite.numInsertedObjs -= skip - 1;
+
#ifdef AVOID_HACKS_FOR_ITCL
desiredObjs[0] = framePtr->objv[skip-1];
#else
- desiredObjs[0] = Tcl_NewListObj(1, framePtr->objv + skip - 1);
+ desiredObjs[0] = Tcl_NewListObj(skip, framePtr->objv);
#endif /* AVOID_HACKS_FOR_ITCL */
}
Tcl_IncrRefCount(desiredObjs[0]);
- if (localCt > 0) {
- Var *defPtr = (Var *)(&framePtr->localCachePtr->varName0 + localCt);
-
- for (i=1 ; i<=numArgs ; i++, defPtr++) {
- Tcl_Obj *argObj;
- Tcl_Obj *namePtr = localName(framePtr, i-1);
-
- if (defPtr->value.objPtr != NULL) {
- TclNewObj(argObj);
- Tcl_AppendStringsToObj(argObj, "?", TclGetString(namePtr), "?", (void *)NULL);
- } else if (defPtr->flags & VAR_IS_ARGS) {
- numArgs--;
- final = "?arg ...?";
- break;
- } else {
- argObj = namePtr;
- Tcl_IncrRefCount(namePtr);
- }
- desiredObjs[i] = argObj;
+ defPtr = (Var *) (&framePtr->localCachePtr->varName0 + localCt);
+ for (i=1 ; i<=numArgs ; i++, defPtr++) {
+ Tcl_Obj *argObj;
+ Tcl_Obj *namePtr = localName(framePtr, i-1);
+
+ if (defPtr->value.objPtr != NULL) {
+ TclNewObj(argObj);
+ Tcl_AppendStringsToObj(argObj, "?", TclGetString(namePtr), "?", NULL);
+ } else if (defPtr->flags & VAR_IS_ARGS) {
+ numArgs--;
+ final = "...";
+ break;
+ } else {
+ argObj = namePtr;
+ Tcl_IncrRefCount(namePtr);
}
+ desiredObjs[i] = argObj;
}
Tcl_ResetResult(interp);
@@ -1131,6 +1142,7 @@ ProcWrongNumArgs(
* DEPRECATED: functionality has been inlined elsewhere; this function
* remains to insure binary compatibility with Itcl.
*
+
* Results:
* None.
*
@@ -1140,8 +1152,6 @@ ProcWrongNumArgs(
*
*----------------------------------------------------------------------
*/
-
-#ifndef TCL_NO_DEPRECATED
void
TclInitCompiledLocals(
Tcl_Interp *interp, /* Current interpreter. */
@@ -1153,10 +1163,10 @@ TclInitCompiledLocals(
ByteCode *codePtr;
bodyPtr = framePtr->procPtr->bodyPtr;
- ByteCodeGetInternalRep(bodyPtr, &tclByteCodeType, codePtr);
- if (codePtr == NULL) {
+ if (bodyPtr->typePtr != &tclByteCodeType) {
Tcl_Panic("body object for proc attached to frame is not a byte code type");
}
+ codePtr = bodyPtr->internalRep.twoPtrValue.ptr1;
if (framePtr->numCompiledLocals) {
if (!codePtr->localCachePtr) {
@@ -1168,7 +1178,6 @@ TclInitCompiledLocals(
InitResolvedLocals(interp, codePtr, varPtr, nsPtr);
}
-#endif /* TCL_NO_DEPRECATED */
/*
*----------------------------------------------------------------------
@@ -1212,7 +1221,37 @@ InitResolvedLocals(
}
if (!(haveResolvers && (codePtr->flags & TCL_BYTECODE_RESOLVE_VARS))) {
- goto doInitResolvedLocals;
+ /*
+ * Initialize the array of local variables stored in the call frame.
+ * Some variables may have special resolution rules. In that case, we
+ * call their "resolver" procs to get our hands on the variable, and
+ * we make the compiled local a link to the real variable.
+ */
+
+ doInitResolvedLocals:
+ for (; localPtr != NULL; varPtr++, localPtr = localPtr->nextPtr) {
+ varPtr->flags = 0;
+ varPtr->value.objPtr = NULL;
+
+ /*
+ * Now invoke the resolvers to determine the exact variables
+ * that should be used.
+ */
+
+ resVarInfo = localPtr->resolveInfo;
+ if (resVarInfo && resVarInfo->fetchProc) {
+ Var *resolvedVarPtr = (Var *)
+ (*resVarInfo->fetchProc)(interp, resVarInfo);
+ if (resolvedVarPtr) {
+ if (TclIsVarInHash(resolvedVarPtr)) {
+ VarHashRefCount(resolvedVarPtr)++;
+ }
+ varPtr->flags = VAR_LINK;
+ varPtr->value.linkPtr = resolvedVarPtr;
+ }
+ }
+ }
+ return;
}
/*
@@ -1226,7 +1265,7 @@ InitResolvedLocals(
if (localPtr->resolveInfo->deleteProc) {
localPtr->resolveInfo->deleteProc(localPtr->resolveInfo);
} else {
- ckfree(localPtr->resolveInfo);
+ ckfree((char *) localPtr->resolveInfo);
}
localPtr->resolveInfo = NULL;
}
@@ -1239,7 +1278,7 @@ InitResolvedLocals(
int result;
if (nsPtr->compiledVarResProc) {
- result = nsPtr->compiledVarResProc(nsPtr->interp,
+ result = (*nsPtr->compiledVarResProc)(nsPtr->interp,
localPtr->name, localPtr->nameLength,
(Tcl_Namespace *) nsPtr, &vinfo);
} else {
@@ -1248,7 +1287,7 @@ InitResolvedLocals(
while ((result == TCL_CONTINUE) && resPtr) {
if (resPtr->compiledVarResProc) {
- result = resPtr->compiledVarResProc(nsPtr->interp,
+ result = (*resPtr->compiledVarResProc)(nsPtr->interp,
localPtr->name, localPtr->nameLength,
(Tcl_Namespace *) nsPtr, &vinfo);
}
@@ -1262,75 +1301,48 @@ InitResolvedLocals(
}
localPtr = firstLocalPtr;
codePtr->flags &= ~TCL_BYTECODE_RESOLVE_VARS;
-
- /*
- * Initialize the array of local variables stored in the call frame. Some
- * variables may have special resolution rules. In that case, we call
- * their "resolver" procs to get our hands on the variable, and we make
- * the compiled local a link to the real variable.
- */
-
- doInitResolvedLocals:
- for (; localPtr != NULL; varPtr++, localPtr = localPtr->nextPtr) {
- varPtr->flags = 0;
- varPtr->value.objPtr = NULL;
-
- /*
- * Now invoke the resolvers to determine the exact variables that
- * should be used.
- */
-
- resVarInfo = localPtr->resolveInfo;
- if (resVarInfo && resVarInfo->fetchProc) {
- Var *resolvedVarPtr = (Var *)
- resVarInfo->fetchProc(interp, resVarInfo);
-
- if (resolvedVarPtr) {
- if (TclIsVarInHash(resolvedVarPtr)) {
- VarHashRefCount(resolvedVarPtr)++;
- }
- varPtr->flags = VAR_LINK;
- varPtr->value.linkPtr = resolvedVarPtr;
- }
- }
- }
+ goto doInitResolvedLocals;
}
-
+
void
TclFreeLocalCache(
Tcl_Interp *interp,
LocalCache *localCachePtr)
{
- Tcl_Size i;
+ int i;
Tcl_Obj **namePtrPtr = &localCachePtr->varName0;
for (i = 0; i < localCachePtr->numVars; i++, namePtrPtr++) {
Tcl_Obj *objPtr = *namePtrPtr;
-
+ /*
+ * Note that this can be called with interp==NULL, on interp
+ * deletion. In that case, the literal table and objects go away
+ * on their own.
+ */
if (objPtr) {
- /* TclReleaseLiteral calls Tcl_DecrRefCount for us */
- TclReleaseLiteral(interp, objPtr);
+ if (interp) {
+ TclReleaseLiteral(interp, objPtr);
+ } else {
+ Tcl_DecrRefCount(objPtr);
+ }
}
}
- ckfree(localCachePtr);
+ ckfree((char *) localCachePtr);
}
-
+
static void
-InitLocalCache(
- Proc *procPtr)
+InitLocalCache(Proc *procPtr)
{
Interp *iPtr = procPtr->iPtr;
- ByteCode *codePtr;
- Tcl_Size localCt = procPtr->numCompiledLocals;
- Tcl_Size numArgs = procPtr->numArgs, i = 0;
+ ByteCode *codePtr = procPtr->bodyPtr->internalRep.twoPtrValue.ptr1;
+ int localCt = procPtr->numCompiledLocals;
+ int numArgs = procPtr->numArgs, i = 0;
Tcl_Obj **namePtr;
Var *varPtr;
LocalCache *localCachePtr;
CompiledLocal *localPtr;
- int isNew;
-
- ByteCodeGetInternalRep(procPtr->bodyPtr, &tclByteCodeType, codePtr);
+ int new;
/*
* Cache the names and initial values of local variables; store the
@@ -1338,9 +1350,9 @@ InitLocalCache(
* for future calls.
*/
- localCachePtr = (LocalCache *)ckalloc(offsetof(LocalCache, varName0)
- + localCt * sizeof(Tcl_Obj *)
- + numArgs * sizeof(Var));
+ localCachePtr = (LocalCache *) ckalloc(sizeof(LocalCache)
+ + (localCt-1)*sizeof(Tcl_Obj *)
+ + numArgs*sizeof(Var));
namePtr = &localCachePtr->varName0;
varPtr = (Var *) (namePtr + localCt);
@@ -1351,7 +1363,7 @@ InitLocalCache(
} else {
*namePtr = TclCreateLiteral(iPtr, localPtr->name,
localPtr->nameLength, /* hash */ (unsigned int) -1,
- &isNew, /* nsPtr */ NULL, 0, NULL);
+ &new, /* nsPtr */ NULL, 0, NULL);
Tcl_IncrRefCount(*namePtr);
}
@@ -1362,49 +1374,28 @@ InitLocalCache(
i++;
}
namePtr++;
- localPtr = localPtr->nextPtr;
+ localPtr=localPtr->nextPtr;
}
codePtr->localCachePtr = localCachePtr;
localCachePtr->refCount = 1;
- localCachePtr->numVars = localCt;
+ localCachePtr->numVars = localCt;
}
-
-/*
- *----------------------------------------------------------------------
- *
- * InitArgsAndLocals --
- *
- * This routine is invoked in order to initialize the arguments and other
- * compiled locals table for a new call frame.
- *
- * Results:
- * A standard Tcl result.
- *
- * Side effects:
- * Allocates memory on the stack for the compiled local variables, the
- * caller is responsible for freeing them. Initialises all variables. May
- * invoke various name resolvers in order to determine which variables
- * are being referenced at runtime.
- *
- *----------------------------------------------------------------------
- */
static int
InitArgsAndLocals(
- Tcl_Interp *interp,/* Interpreter in which procedure was
+ register Tcl_Interp *interp,/* Interpreter in which procedure was
* invoked. */
- Tcl_Size skip) /* Number of initial arguments to be skipped,
+ Tcl_Obj *procNameObj, /* Procedure name for error reporting. */
+ int skip) /* Number of initial arguments to be skipped,
* i.e., words in the "command name". */
{
CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
- Proc *procPtr = framePtr->procPtr;
- ByteCode *codePtr;
- Var *varPtr, *defPtr;
- Tcl_Size localCt = procPtr->numCompiledLocals, numArgs, argCt, i, imax;
+ register Proc *procPtr = framePtr->procPtr;
+ ByteCode *codePtr = procPtr->bodyPtr->internalRep.twoPtrValue.ptr1;
+ register Var *varPtr, *defPtr;
+ int localCt = procPtr->numCompiledLocals, numArgs, argCt, i, imax;
Tcl_Obj *const *argObjs;
- ByteCodeGetInternalRep(procPtr->bodyPtr, &tclByteCodeType, codePtr);
-
/*
* Make sure that the local cache of variable names and initial values has
* been initialised properly .
@@ -1427,7 +1418,7 @@ InitArgsAndLocals(
* parameters.
*/
- varPtr = (Var *)TclStackAlloc(interp, localCt * sizeof(Var));
+ varPtr = (Var*) TclStackAlloc(interp, (int)(localCt*sizeof(Var)));
framePtr->compiledLocals = varPtr;
framePtr->numCompiledLocals = localCt;
@@ -1441,6 +1432,7 @@ InitArgsAndLocals(
numArgs = procPtr->numArgs;
argCt = framePtr->objc - skip; /* Set it to the number of args to the
* procedure. */
+ argObjs = framePtr->objv + skip;
if (numArgs == 0) {
if (argCt) {
goto incorrectArgs;
@@ -1448,9 +1440,8 @@ InitArgsAndLocals(
goto correctArgs;
}
}
- argObjs = framePtr->objv + skip;
imax = ((argCt < numArgs-1) ? argCt : numArgs-1);
- for (i = 0; i < imax; i++, varPtr++, defPtr ? defPtr++ : defPtr) {
+ for (i = 0; i < imax; i++, varPtr++, defPtr++) {
/*
* "Normal" arguments; last formal is special, depends on it being
* 'args'.
@@ -1462,20 +1453,21 @@ InitArgsAndLocals(
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr); /* Local var is a reference. */
}
- for (; i < numArgs-1; i++, varPtr++, defPtr ? defPtr++ : defPtr) {
+ for (; i < numArgs-1; i++, varPtr++, defPtr++) {
/*
* This loop is entered if argCt < (numArgs-1). Set default values;
* last formal is special.
*/
- Tcl_Obj *objPtr = defPtr ? defPtr->value.objPtr : NULL;
+ Tcl_Obj *objPtr = defPtr->value.objPtr;
- if (!objPtr) {
+ if (objPtr) {
+ varPtr->flags = 0;
+ varPtr->value.objPtr = objPtr;
+ Tcl_IncrRefCount(objPtr); /* Local var reference. */
+ } else {
goto incorrectArgs;
}
- varPtr->flags = 0;
- varPtr->value.objPtr = objPtr;
- Tcl_IncrRefCount(objPtr); /* Local var reference. */
}
/*
@@ -1483,9 +1475,10 @@ InitArgsAndLocals(
* defPtr and varPtr point to the last argument to be initialized.
*/
+
varPtr->flags = 0;
- if (defPtr && defPtr->flags & VAR_IS_ARGS) {
- Tcl_Obj *listPtr = Tcl_NewListObj((argCt>i)? argCt-i : 0, argObjs+i);
+ if (defPtr->flags & VAR_IS_ARGS) {
+ Tcl_Obj *listPtr = Tcl_NewListObj(argCt-i, argObjs+i);
varPtr->value.objPtr = listPtr;
Tcl_IncrRefCount(listPtr); /* Local var is a reference. */
@@ -1494,7 +1487,7 @@ InitArgsAndLocals(
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr); /* Local var is a reference. */
- } else if ((argCt < numArgs) && defPtr && defPtr->value.objPtr) {
+ } else if ((argCt < numArgs) && (defPtr->value.objPtr != NULL)) {
Tcl_Obj *objPtr = defPtr->value.objPtr;
varPtr->value.objPtr = objPtr;
@@ -1511,8 +1504,7 @@ InitArgsAndLocals(
correctArgs:
if (numArgs < localCt) {
- if (!framePtr->nsPtr->compiledVarResProc
- && !((Interp *)interp)->resolverPtr) {
+ if (!framePtr->nsPtr->compiledVarResProc && !((Interp *)interp)->resolverPtr) {
memset(varPtr, 0, (localCt - numArgs)*sizeof(Var));
} else {
InitResolvedLocals(interp, codePtr, varPtr, framePtr->nsPtr);
@@ -1521,24 +1513,20 @@ InitArgsAndLocals(
return TCL_OK;
+
+ incorrectArgs:
/*
* Initialise all compiled locals to avoid problems at DeleteLocalVars.
*/
- incorrectArgs:
- if ((skip != 1) &&
- TclInitRewriteEnsemble(interp, skip-1, 0, framePtr->objv)) {
- TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL);
- }
- memset(varPtr, 0,
- ((framePtr->compiledLocals + localCt)-varPtr) * sizeof(Var));
+ memset(varPtr, 0, ((framePtr->compiledLocals + localCt)-varPtr)*sizeof(Var));
return ProcWrongNumArgs(interp, skip);
}
/*
*----------------------------------------------------------------------
*
- * TclPushProcCallFrame --
+ * PushProcCallFrame --
*
* Compiles a proc body if necessary, then pushes a CallFrame suitable
* for executing it.
@@ -1553,19 +1541,19 @@ InitArgsAndLocals(
*----------------------------------------------------------------------
*/
-int
-TclPushProcCallFrame(
- void *clientData, /* Record describing procedure to be
+static int
+PushProcCallFrame(
+ ClientData clientData, /* Record describing procedure to be
* interpreted. */
- Tcl_Interp *interp,/* Interpreter in which procedure was
+ register Tcl_Interp *interp,/* Interpreter in which procedure was
* invoked. */
- Tcl_Size objc, /* Count of number of arguments to this
+ int objc, /* Count of number of arguments to this
* procedure. */
- Tcl_Obj *const objv[], /* Argument value objects. */
+ Tcl_Obj *CONST objv[], /* Argument value objects. */
int isLambda) /* 1 if this is a call by ApplyObjCmd: it
* needs special rules for error msg */
{
- Proc *procPtr = (Proc *)clientData;
+ Proc *procPtr = (Proc *) clientData;
Namespace *nsPtr = procPtr->cmdPtr->nsPtr;
CallFrame *framePtr, **framePtrPtr;
int result;
@@ -1579,8 +1567,7 @@ TclPushProcCallFrame(
* local variables are found while compiling.
*/
- ByteCodeGetInternalRep(procPtr->bodyPtr, &tclByteCodeType, codePtr);
- if (codePtr != NULL) {
+ if (procPtr->bodyPtr->typePtr == &tclByteCodeType) {
Interp *iPtr = (Interp *) interp;
/*
@@ -1590,22 +1577,20 @@ TclPushProcCallFrame(
* is up-to-date), the namespace must match (so variable handling
* is right) and the resolverEpoch must match (so that new shadowed
* commands and/or resolver changes are considered).
- * Ensure the ByteCode's procPtr is the same (or it's precompiled).
*/
- if (((Interp *) *codePtr->interpHandle != iPtr)
+ codePtr = procPtr->bodyPtr->internalRep.twoPtrValue.ptr1;
+ if (((Interp *) *codePtr->interpHandle != iPtr)
|| (codePtr->compileEpoch != iPtr->compileEpoch)
|| (codePtr->nsPtr != nsPtr)
- || (codePtr->nsEpoch != nsPtr->resolverEpoch)
- || ((codePtr->procPtr != procPtr) && procPtr->bodyPtr->bytes)
- ) {
+ || (codePtr->nsEpoch != nsPtr->resolverEpoch)) {
goto doCompilation;
}
} else {
doCompilation:
- result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr, nsPtr,
+ result = ProcCompileProc(interp, procPtr, procPtr->bodyPtr, nsPtr,
(isLambda ? "body of lambda term" : "body of proc"),
- TclGetString(objv[isLambda]));
+ TclGetString(objv[isLambda]), &procPtr);
if (result != TCL_OK) {
return result;
}
@@ -1620,9 +1605,12 @@ TclPushProcCallFrame(
*/
framePtrPtr = &framePtr;
- (void) TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
+ result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
(Tcl_Namespace *) nsPtr,
(isLambda? (FRAME_IS_PROC|FRAME_IS_LAMBDA) : FRAME_IS_PROC));
+ if (result != TCL_OK) {
+ return result;
+ }
framePtr->objc = objc;
framePtr->objv = objv;
@@ -1650,44 +1638,28 @@ TclPushProcCallFrame(
int
TclObjInterpProc(
- void *clientData, /* Record describing procedure to be
+ ClientData clientData, /* Record describing procedure to be
* interpreted. */
- Tcl_Interp *interp,/* Interpreter in which procedure was
+ register Tcl_Interp *interp,/* Interpreter in which procedure was
* invoked. */
int objc, /* Count of number of arguments to this
* procedure. */
- Tcl_Obj *const objv[]) /* Argument value objects. */
-{
- /*
- * Not used much in the core; external interface for iTcl
- */
-
- return Tcl_NRCallObjProc(interp, TclNRInterpProc, clientData, objc, objv);
-}
-
-int
-TclNRInterpProc(
- void *clientData, /* Record describing procedure to be
- * interpreted. */
- Tcl_Interp *interp,/* Interpreter in which procedure was
- * invoked. */
- Tcl_Size objc, /* Count of number of arguments to this
- * procedure. */
- Tcl_Obj *const objv[]) /* Argument value objects. */
+ Tcl_Obj *CONST objv[]) /* Argument value objects. */
{
- int result = TclPushProcCallFrame(clientData, interp, objc, objv,
- /*isLambda*/ 0);
+ int result;
- if (result != TCL_OK) {
+ result = PushProcCallFrame(clientData, interp, objc, objv, /*isLambda*/ 0);
+ if (result == TCL_OK) {
+ return TclObjInterpProcCore(interp, objv[0], 1, &MakeProcError);
+ } else {
return TCL_ERROR;
}
- return TclNRInterpProcCore(interp, objv[0], 1, &MakeProcError);
}
/*
*----------------------------------------------------------------------
*
- * TclNRInterpProcCore --
+ * TclObjInterpProcCore --
*
* When a Tcl procedure, lambda term or anything else that works like a
* procedure gets invoked during bytecode evaluation, this object-based
@@ -1703,35 +1675,29 @@ TclNRInterpProc(
*/
int
-TclNRInterpProcCore(
- Tcl_Interp *interp,/* Interpreter in which procedure was
+TclObjInterpProcCore(
+ register Tcl_Interp *interp,/* Interpreter in which procedure was
* invoked. */
Tcl_Obj *procNameObj, /* Procedure name for error reporting. */
- Tcl_Size skip, /* Number of initial arguments to be skipped,
+ int skip, /* Number of initial arguments to be skipped,
* i.e., words in the "command name". */
- ProcErrorProc *errorProc) /* How to convert results from the script into
+ ProcErrorProc errorProc) /* How to convert results from the script into
* results of the overall procedure. */
{
Interp *iPtr = (Interp *) interp;
- Proc *procPtr = iPtr->varFramePtr->procPtr;
+ register Proc *procPtr = iPtr->varFramePtr->procPtr;
int result;
CallFrame *freePtr;
- ByteCode *codePtr;
- result = InitArgsAndLocals(interp, skip);
+ result = InitArgsAndLocals(interp, procNameObj, skip);
if (result != TCL_OK) {
- freePtr = iPtr->framePtr;
- Tcl_PopCallFrame(interp); /* Pop but do not free. */
- TclStackFree(interp, freePtr->compiledLocals);
- /* Free compiledLocals. */
- TclStackFree(interp, freePtr); /* Free CallFrame. */
- return TCL_ERROR;
+ goto procDone;
}
#if defined(TCL_COMPILE_DEBUG)
if (tclTraceExec >= 1) {
- CallFrame *framePtr = iPtr->varFramePtr;
- Tcl_Size i;
+ register CallFrame *framePtr = iPtr->varFramePtr;
+ register int i;
if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
fprintf(stdout, "Calling lambda ");
@@ -1749,42 +1715,25 @@ TclNRInterpProcCore(
#ifdef USE_DTRACE
if (TCL_DTRACE_PROC_ARGS_ENABLED()) {
- Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
- const char *a[10];
- Tcl_Size i;
+ char *a[10];
+ int i = 0;
+ int l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
- for (i = 0 ; i < 10 ; i++) {
+ while (i < 10) {
a[i] = (l < iPtr->varFramePtr->objc ?
- TclGetString(iPtr->varFramePtr->objv[l]) : NULL);
- l++;
+ TclGetString(iPtr->varFramePtr->objv[l]) : NULL); i++; l++;
}
TCL_DTRACE_PROC_ARGS(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
a[8], a[9]);
}
if (TCL_DTRACE_PROC_INFO_ENABLED() && iPtr->cmdFramePtr) {
Tcl_Obj *info = TclInfoFrame(interp, iPtr->cmdFramePtr);
- const char *a[6]; Tcl_Size i[2];
+ char *a[4]; int i[2];
TclDTraceInfo(info, a, i);
- TCL_DTRACE_PROC_INFO(a[0], a[1], a[2], a[3], i[0], i[1], a[4], a[5]);
+ TCL_DTRACE_PROC_INFO(a[0], a[1], a[2], a[3], i[0], i[1]);
TclDecrRefCount(info);
}
- if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
- Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
-
- TCL_DTRACE_PROC_ENTRY(l < iPtr->varFramePtr->objc ?
- TclGetString(iPtr->varFramePtr->objv[l]) : NULL,
- iPtr->varFramePtr->objc - l - 1,
- (Tcl_Obj **)(iPtr->varFramePtr->objv + l + 1));
- }
- if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
- Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
-
- TCL_DTRACE_PROC_ENTRY(l < iPtr->varFramePtr->objc ?
- TclGetString(iPtr->varFramePtr->objv[l]) : NULL,
- iPtr->varFramePtr->objc - l - 1,
- (Tcl_Obj **)(iPtr->varFramePtr->objv + l + 1));
- }
#endif /* USE_DTRACE */
/*
@@ -1792,69 +1741,45 @@ TclNRInterpProcCore(
*/
procPtr->refCount++;
- ByteCodeGetInternalRep(procPtr->bodyPtr, &tclByteCodeType, codePtr);
-
- TclNRAddCallback(interp, InterpProcNR2, procNameObj, errorProc,
- NULL, NULL);
- return TclNRExecuteByteCode(interp, codePtr);
-}
+ iPtr->numLevels++;
-static int
-InterpProcNR2(
- void *data[],
- Tcl_Interp *interp,
- int result)
-{
- Interp *iPtr = (Interp *) interp;
- Proc *procPtr = iPtr->varFramePtr->procPtr;
- CallFrame *freePtr;
- Tcl_Obj *procNameObj = (Tcl_Obj *)data[0];
- ProcErrorProc *errorProc = (ProcErrorProc *)data[1];
-
- if (TCL_DTRACE_PROC_RETURN_ENABLED()) {
- Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
-
- TCL_DTRACE_PROC_RETURN(l < iPtr->varFramePtr->objc ?
- TclGetString(iPtr->varFramePtr->objv[l]) : NULL, result);
- }
- if (procPtr->refCount-- <= 1) {
- TclProcCleanupProc(procPtr);
- }
+ if (TclInterpReady(interp) == TCL_ERROR) {
+ result = TCL_ERROR;
+ } else {
+ register ByteCode *codePtr =
+ procPtr->bodyPtr->internalRep.twoPtrValue.ptr1;
- /*
- * Free the stack-allocated compiled locals and CallFrame. It is important
- * to pop the call frame without freeing it first: the compiledLocals
- * cannot be freed before the frame is popped, as the local variables must
- * be deleted. But the compiledLocals must be freed first, as they were
- * allocated later on the stack.
- */
+ codePtr->refCount++;
+#ifdef USE_DTRACE
+ if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
+ int l;
- if (result != TCL_OK) {
- goto process;
+ l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 2 : 1;
+ TCL_DTRACE_PROC_ENTRY(TclGetString(procNameObj),
+ iPtr->varFramePtr->objc - l,
+ (Tcl_Obj **)(iPtr->varFramePtr->objv + l));
+ }
+#endif /* USE_DTRACE */
+ result = TclExecuteByteCode(interp, codePtr);
+ if (TCL_DTRACE_PROC_RETURN_ENABLED()) {
+ TCL_DTRACE_PROC_RETURN(TclGetString(procNameObj), result);
+ }
+ codePtr->refCount--;
+ if (codePtr->refCount <= 0) {
+ TclCleanupByteCode(codePtr);
+ }
}
- done:
- if (TCL_DTRACE_PROC_RESULT_ENABLED()) {
- Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
- Tcl_Obj *r = Tcl_GetObjResult(interp);
-
- TCL_DTRACE_PROC_RESULT(l < iPtr->varFramePtr->objc ?
- TclGetString(iPtr->varFramePtr->objv[l]) : NULL, result,
- TclGetString(r), r);
+ iPtr->numLevels--;
+ procPtr->refCount--;
+ if (procPtr->refCount <= 0) {
+ TclProcCleanupProc(procPtr);
}
- freePtr = iPtr->framePtr;
- Tcl_PopCallFrame(interp); /* Pop but do not free. */
- TclStackFree(interp, freePtr->compiledLocals);
- /* Free compiledLocals. */
- TclStackFree(interp, freePtr); /* Free CallFrame. */
- return result;
-
/*
- * Process any non-TCL_OK result code.
+ * Process the result code.
*/
- process:
switch (result) {
case TCL_RETURN:
/*
@@ -1871,13 +1796,15 @@ InterpProcNR2(
* transform to an error now.
*/
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "invoked \"%s\" outside of a loop",
- ((result == TCL_BREAK) ? "break" : "continue")));
- Tcl_SetErrorCode(interp, "TCL", "RESULT", "UNEXPECTED", (void *)NULL);
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "invoked \"",
+ ((result == TCL_BREAK) ? "break" : "continue"),
+ "\" outside of a loop", NULL);
result = TCL_ERROR;
- /* FALLTHRU */
+ /*
+ * Fall through to the TCL_ERROR handling code.
+ */
case TCL_ERROR:
/*
@@ -1886,9 +1813,48 @@ InterpProcNR2(
* function handed to us as an argument.
*/
- errorProc(interp, procNameObj);
+ (*errorProc)(interp, procNameObj);
+
+ default:
+ /*
+ * Process other results (OK and non-standard) by doing nothing
+ * special, skipping directly to the code afterwards that cleans up
+ * associated memory.
+ *
+ * Non-standard results are processed by passing them through quickly.
+ * This means they all work as exceptions, unwinding the stack quickly
+ * and neatly. Who knows how well they are handled by third-party code
+ * though...
+ */
+
+ (void) 0; /* do nothing */
+ }
+
+#ifdef USE_DTRACE
+ if (TCL_DTRACE_PROC_RESULT_ENABLED()) {
+ Tcl_Obj *r;
+
+ r = Tcl_GetObjResult(interp);
+ TCL_DTRACE_PROC_RESULT(TclGetString(procNameObj), result,
+ TclGetString(r), r);
}
- goto done;
+#endif /* USE_DTRACE */
+
+ procDone:
+ /*
+ * Free the stack-allocated compiled locals and CallFrame. It is important
+ * to pop the call frame without freeing it first: the compiledLocals
+ * cannot be freed before the frame is popped, as the local variables must
+ * be deleted. But the compiledLocals must be freed first, as they were
+ * allocated later on the stack.
+ */
+
+ freePtr = iPtr->framePtr;
+ Tcl_PopCallFrame(interp); /* Pop but do not free. */
+ TclStackFree(interp, freePtr->compiledLocals);
+ /* Free compiledLocals. */
+ TclStackFree(interp, freePtr); /* Free CallFrame. */
+ return result;
}
/*
@@ -1916,17 +1882,34 @@ TclProcCompileProc(
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.) */
+ * 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. */
+{
+ return ProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description,
+ procName, NULL);
+}
+
+static int
+ProcCompileProc(
+ 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. */
+ CONST char *description, /* string describing this body of code. */
+ CONST char *procName, /* Name of this procedure. */
+ Proc **procPtrPtr) /* Points to storage where a replacement
+ * (Proc *) value may be written. */
{
Interp *iPtr = (Interp *) interp;
+ int i;
Tcl_CallFrame *framePtr;
- ByteCode *codePtr;
-
- ByteCodeGetInternalRep(bodyPtr, &tclByteCodeType, codePtr);
+ ByteCode *codePtr = bodyPtr->internalRep.twoPtrValue.ptr1;
+ CompiledLocal *localPtr;
/*
* If necessary, compile the procedure's body. The compiler will allocate
@@ -1938,107 +1921,126 @@ TclProcCompileProc(
* procPtr->numCompiledLocals if new local variables are found while
* compiling.
*
- * Ensure the ByteCode's procPtr is the same (or it is pure precompiled).
* Precompiled procedure bodies, however, are immutable and therefore they
* are not recompiled, even if things have changed.
*/
- if (codePtr != NULL) {
- if (((Interp *) *codePtr->interpHandle == iPtr)
+ if (bodyPtr->typePtr == &tclByteCodeType) {
+ if (((Interp *) *codePtr->interpHandle == iPtr)
&& (codePtr->compileEpoch == iPtr->compileEpoch)
&& (codePtr->nsPtr == nsPtr)
- && (codePtr->nsEpoch == nsPtr->resolverEpoch)
- && ((codePtr->procPtr == procPtr) || !bodyPtr->bytes)
- ) {
+ && (codePtr->nsEpoch == nsPtr->resolverEpoch)) {
return TCL_OK;
- }
-
- if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
- if ((Interp *) *codePtr->interpHandle != iPtr) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "a precompiled script jumped interps", -1));
- Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
- "CROSSINTERPBYTECODE", (void *)NULL);
- return TCL_ERROR;
- }
- codePtr->compileEpoch = iPtr->compileEpoch;
- codePtr->nsPtr = nsPtr;
} else {
- Tcl_StoreInternalRep(bodyPtr, &tclByteCodeType, NULL);
- codePtr = NULL;
- }
+ 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 {
+ bodyPtr->typePtr->freeIntRepProc(bodyPtr);
+ bodyPtr->typePtr = NULL;
+ }
+ }
}
-
- if (codePtr == NULL) {
+ if (bodyPtr->typePtr != &tclByteCodeType) {
Tcl_HashEntry *hePtr;
#ifdef TCL_COMPILE_DEBUG
- if (tclTraceCompile >= 1) {
- /*
- * Display a line summarizing the top level command we are about
- * to compile.
- */
+ if (tclTraceCompile >= 1) {
+ /*
+ * Display a line summarizing the top level command we are about
+ * to compile.
+ */
Tcl_Obj *message;
TclNewLiteralStringObj(message, "Compiling ");
Tcl_IncrRefCount(message);
- Tcl_AppendStringsToObj(message, description, " \"", (void *)NULL);
- Tcl_AppendLimitedToObj(message, procName, TCL_INDEX_NONE, 50, NULL);
- fprintf(stdout, "%s\"\n", TclGetString(message));
+ Tcl_AppendStringsToObj(message, description, " \"", NULL);
+ Tcl_AppendLimitedToObj(message, procName, -1, 50, NULL);
+ fprintf(stdout, "%s\"\n", TclGetString(message));
Tcl_DecrRefCount(message);
- }
-#else
- (void)description;
- (void)procName;
+ }
#endif
- /*
- * 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.
- */
+ /*
+ * 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.
+ */
+
+ if (procPtrPtr != NULL && procPtr->refCount > 1) {
+ Tcl_Command token;
+ Tcl_CmdInfo info;
+ Proc *newProc = (Proc *) ckalloc(sizeof(Proc));
+
+ newProc->iPtr = procPtr->iPtr;
+ newProc->refCount = 1;
+ newProc->cmdPtr = procPtr->cmdPtr;
+ token = (Tcl_Command) newProc->cmdPtr;
+ newProc->bodyPtr = Tcl_DuplicateObj(bodyPtr);
+ bodyPtr = newProc->bodyPtr;
+ Tcl_IncrRefCount(bodyPtr);
+ newProc->numArgs = procPtr->numArgs;
+
+ newProc->numCompiledLocals = newProc->numArgs;
+ newProc->firstLocalPtr = NULL;
+ newProc->lastLocalPtr = NULL;
+ localPtr = procPtr->firstLocalPtr;
+ for (i=0; i<newProc->numArgs; i++, localPtr=localPtr->nextPtr) {
+ CompiledLocal *copy = (CompiledLocal *) ckalloc((unsigned)
+ (sizeof(CompiledLocal) - sizeof(localPtr->name)
+ + localPtr->nameLength + 1));
- iPtr->compiledProcPtr = procPtr;
+ if (newProc->firstLocalPtr == NULL) {
+ newProc->firstLocalPtr = newProc->lastLocalPtr = copy;
+ } else {
+ newProc->lastLocalPtr->nextPtr = copy;
+ newProc->lastLocalPtr = copy;
+ }
+ copy->nextPtr = NULL;
+ copy->nameLength = localPtr->nameLength;
+ copy->frameIndex = localPtr->frameIndex;
+ copy->flags = localPtr->flags;
+ copy->defValuePtr = localPtr->defValuePtr;
+ if (copy->defValuePtr) {
+ Tcl_IncrRefCount(copy->defValuePtr);
+ }
+ copy->resolveInfo = localPtr->resolveInfo;
+ memcpy(copy->name, localPtr->name, localPtr->nameLength + 1);
+ }
- if (procPtr->numCompiledLocals > procPtr->numArgs) {
- CompiledLocal *clPtr = procPtr->firstLocalPtr;
- CompiledLocal *lastPtr = NULL;
- int i, numArgs = procPtr->numArgs;
+ /*
+ * Reset the ClientData
+ */
- for (i = 0; i < numArgs; i++) {
- lastPtr = clPtr;
- clPtr = clPtr->nextPtr;
+ Tcl_GetCommandInfoFromToken(token, &info);
+ if (info.objClientData == (ClientData) procPtr) {
+ info.objClientData = (ClientData) newProc;
}
-
- if (lastPtr) {
- lastPtr->nextPtr = NULL;
- } else {
- procPtr->firstLocalPtr = NULL;
+ if (info.clientData == (ClientData) procPtr) {
+ info.clientData = (ClientData) newProc;
}
- procPtr->lastLocalPtr = lastPtr;
- while (clPtr) {
- CompiledLocal *toFree = clPtr;
-
- clPtr = clPtr->nextPtr;
- if (toFree->resolveInfo) {
- if (toFree->resolveInfo->deleteProc) {
- toFree->resolveInfo->deleteProc(toFree->resolveInfo);
- } else {
- ckfree(toFree->resolveInfo);
- }
- }
- ckfree(toFree);
+ if (info.deleteData == (ClientData) procPtr) {
+ info.deleteData = (ClientData) newProc;
}
- procPtr->numCompiledLocals = procPtr->numArgs;
+ Tcl_SetCommandInfoFromToken(token, &info);
+
+ procPtr->refCount--;
+ *procPtrPtr = procPtr = newProc;
}
+ iPtr->compiledProcPtr = procPtr;
- (void) TclPushStackFrame(interp, &framePtr, (Tcl_Namespace *) nsPtr,
- /* isProcCallFrame */ 0);
+ (void) TclPushStackFrame(interp, &framePtr,
+ (Tcl_Namespace *) nsPtr, /* isProcCallFrame */ 0);
/*
* TIP #280: We get the invoking context from the cmdFrame which
@@ -2052,8 +2054,9 @@ TclProcCompileProc(
*/
iPtr->invokeWord = 0;
- iPtr->invokeCmdFramePtr = hePtr ? (CmdFrame *)Tcl_GetHashValue(hePtr) : NULL;
- TclSetByteCodeFromAny(interp, bodyPtr, NULL, NULL);
+ iPtr->invokeCmdFramePtr =
+ (hePtr ? (CmdFrame *) Tcl_GetHashValue(hePtr) : NULL);
+ (void) tclByteCodeType.setFromAnyProc(interp, bodyPtr);
iPtr->invokeCmdFramePtr = NULL;
TclPopStackFrame(interp);
} else if (codePtr->nsEpoch != nsPtr->resolverEpoch) {
@@ -2093,15 +2096,14 @@ MakeProcError(
Tcl_Obj *procNameObj) /* Name of the procedure. Used for error
* messages and trace information. */
{
- int overflow, limit = 60;
- Tcl_Size nameLen;
- const char *procName = TclGetStringFromObj(procNameObj, &nameLen);
+ int overflow, limit = 60, nameLen;
+ const char *procName = Tcl_GetStringFromObj(procNameObj, &nameLen);
overflow = (nameLen > limit);
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (procedure \"%.*s%s\" line %d)",
- (overflow ? limit : (int)nameLen), procName,
- (overflow ? "..." : ""), Tcl_GetErrorLine(interp)));
+ (overflow ? limit : nameLen), procName,
+ (overflow ? "..." : ""), interp->errorLine));
}
/*
@@ -2126,11 +2128,12 @@ MakeProcError(
void
TclProcDeleteProc(
- void *clientData) /* Procedure to be deleted. */
+ ClientData clientData) /* Procedure to be deleted. */
{
- Proc *procPtr = (Proc *)clientData;
+ Proc *procPtr = (Proc *) clientData;
- if (procPtr->refCount-- <= 1) {
+ procPtr->refCount--;
+ if (procPtr->refCount <= 0) {
TclProcCleanupProc(procPtr);
}
}
@@ -2154,9 +2157,9 @@ TclProcDeleteProc(
void
TclProcCleanupProc(
- Proc *procPtr) /* Procedure to be deleted. */
+ register Proc *procPtr) /* Procedure to be deleted. */
{
- CompiledLocal *localPtr;
+ register CompiledLocal *localPtr;
Tcl_Obj *bodyPtr = procPtr->bodyPtr;
Tcl_Obj *defPtr;
Tcl_ResolvedVarInfo *resVarInfo;
@@ -2165,13 +2168,6 @@ TclProcCleanupProc(
Interp *iPtr = procPtr->iPtr;
if (bodyPtr != NULL) {
- /* procPtr is stored in body's ByteCode, so ensure to reset it. */
- ByteCode *codePtr;
-
- ByteCodeGetInternalRep(bodyPtr, &tclByteCodeType, codePtr);
- if (codePtr != NULL && codePtr->procPtr == procPtr) {
- codePtr->procPtr = NULL;
- }
Tcl_DecrRefCount(bodyPtr);
}
for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; ) {
@@ -2180,9 +2176,9 @@ TclProcCleanupProc(
resVarInfo = localPtr->resolveInfo;
if (resVarInfo) {
if (resVarInfo->deleteProc) {
- resVarInfo->deleteProc(resVarInfo);
+ (*resVarInfo->deleteProc)(resVarInfo);
} else {
- ckfree(resVarInfo);
+ ckfree((char *) resVarInfo);
}
}
@@ -2190,15 +2186,16 @@ TclProcCleanupProc(
defPtr = localPtr->defValuePtr;
Tcl_DecrRefCount(defPtr);
}
- ckfree(localPtr);
+ ckfree((char *) localPtr);
localPtr = nextPtr;
}
- ckfree(procPtr);
+ ckfree((char *) procPtr);
/*
* TIP #280: Release the location data associated with this Proc
* structure, if any. The interpreter may not exist (For example for
- * procbody structures created by tbcload.
+ * procbody structures created by tbcload. See also Tcl_ProcObjCmd(), when
+ * the same ProcPtr is overwritten with a new CmdFrame.
*/
if (iPtr == NULL) {
@@ -2210,16 +2207,16 @@ TclProcCleanupProc(
return;
}
- cfPtr = (CmdFrame *)Tcl_GetHashValue(hePtr);
+ cfPtr = (CmdFrame *) Tcl_GetHashValue(hePtr);
if (cfPtr) {
if (cfPtr->type == TCL_LOCATION_SOURCE) {
Tcl_DecrRefCount(cfPtr->data.eval.path);
cfPtr->data.eval.path = NULL;
}
- ckfree(cfPtr->line);
+ ckfree((char *) cfPtr->line);
cfPtr->line = NULL;
- ckfree(cfPtr);
+ ckfree((char *) cfPtr);
}
Tcl_DeleteHashEntry(hePtr);
}
@@ -2277,14 +2274,13 @@ TclUpdateReturnInfo(
*
* TclGetObjInterpProc --
*
- * Returns a pointer to the TclObjInterpProc function;
- * this is different from the value obtained from the TclObjInterpProc
- * reference on systems like Windows where import and export versions
- * of a function exported by a DLL exist.
+ * Returns a pointer to the TclObjInterpProc function; this is different
+ * from the value obtained from the TclObjInterpProc reference on systems
+ * like Windows where import and export versions of a function exported
+ * by a DLL exist.
*
* Results:
- * Returns the internal address of the TclObjInterpProc
- * functions.
+ * Returns the internal address of the TclObjInterpProc function.
*
* Side effects:
* None.
@@ -2292,10 +2288,10 @@ TclUpdateReturnInfo(
*----------------------------------------------------------------------
*/
-Tcl_ObjCmdProc *
+TclObjCmdProcType
TclGetObjInterpProc(void)
{
- return TclObjInterpProc;
+ return (TclObjCmdProcType) TclObjInterpProc;
}
/*
@@ -2330,7 +2326,10 @@ TclNewProcBodyObj(
TclNewObj(objPtr);
if (objPtr) {
- ProcSetInternalRep(objPtr, procPtr);
+ objPtr->typePtr = &tclProcBodyType;
+ objPtr->internalRep.twoPtrValue.ptr1 = procPtr;
+
+ procPtr->refCount++;
}
return objPtr;
@@ -2358,10 +2357,11 @@ ProcBodyDup(
Tcl_Obj *srcPtr, /* Object to copy. */
Tcl_Obj *dupPtr) /* Target object for the duplication. */
{
- Proc *procPtr;
- ProcGetInternalRep(srcPtr, procPtr);
+ Proc *procPtr = srcPtr->internalRep.twoPtrValue.ptr1;
- ProcSetInternalRep(dupPtr, procPtr);
+ dupPtr->typePtr = &tclProcBodyType;
+ dupPtr->internalRep.twoPtrValue.ptr1 = procPtr;
+ procPtr->refCount++;
}
/*
@@ -2387,11 +2387,9 @@ static void
ProcBodyFree(
Tcl_Obj *objPtr) /* The object to clean up. */
{
- Proc *procPtr;
+ Proc *procPtr = objPtr->internalRep.twoPtrValue.ptr1;
- ProcGetInternalRep(objPtr, procPtr);
-
- if (procPtr->refCount-- <= 1) {
+ if (procPtr->refCount-- < 2) {
TclProcCleanupProc(procPtr);
}
}
@@ -2413,46 +2411,44 @@ ProcBodyFree(
static void
DupLambdaInternalRep(
Tcl_Obj *srcPtr, /* Object with internal rep to copy. */
- Tcl_Obj *copyPtr) /* Object with internal rep to set. */
+ register Tcl_Obj *copyPtr) /* Object with internal rep to set. */
{
- Proc *procPtr;
- Tcl_Obj *nsObjPtr;
+ Proc *procPtr = srcPtr->internalRep.twoPtrValue.ptr1;
+ Tcl_Obj *nsObjPtr = srcPtr->internalRep.twoPtrValue.ptr2;
- LambdaGetInternalRep(srcPtr, procPtr, nsObjPtr);
- assert(procPtr != NULL);
+ copyPtr->internalRep.twoPtrValue.ptr1 = procPtr;
+ copyPtr->internalRep.twoPtrValue.ptr2 = nsObjPtr;
procPtr->refCount++;
-
- LambdaSetInternalRep(copyPtr, procPtr, nsObjPtr);
+ Tcl_IncrRefCount(nsObjPtr);
+ copyPtr->typePtr = &lambdaType;
}
static void
FreeLambdaInternalRep(
- Tcl_Obj *objPtr) /* CmdName object with internal representation
+ register Tcl_Obj *objPtr) /* CmdName object with internal representation
* to free. */
{
- Proc *procPtr;
- Tcl_Obj *nsObjPtr;
+ Proc *procPtr = objPtr->internalRep.twoPtrValue.ptr1;
+ Tcl_Obj *nsObjPtr = objPtr->internalRep.twoPtrValue.ptr2;
- LambdaGetInternalRep(objPtr, procPtr, nsObjPtr);
- assert(procPtr != NULL);
-
- if (procPtr->refCount-- <= 1) {
+ procPtr->refCount--;
+ if (procPtr->refCount == 0) {
TclProcCleanupProc(procPtr);
}
TclDecrRefCount(nsObjPtr);
+ objPtr->typePtr = NULL;
}
static int
SetLambdaFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
- Tcl_Obj *objPtr) /* The object to convert. */
+ register Tcl_Obj *objPtr) /* The object to convert. */
{
Interp *iPtr = (Interp *) interp;
- const char *name;
- Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv;
- int isNew, result;
- Tcl_Size objc;
+ char *name;
+ Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv, *errPtr;
+ int isNew, objc, result;
CmdFrame *cfPtr = NULL;
Proc *procPtr;
@@ -2465,20 +2461,12 @@ SetLambdaFromAny(
* length is not 2, then it cannot be converted to lambdaType.
*/
- result = TclListObjLength(NULL, objPtr, &objc);
- if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't interpret \"%s\" as a lambda expression",
- Tcl_GetString(objPtr)));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "LAMBDA", (void *)NULL);
- return TCL_ERROR;
- }
result = TclListObjGetElements(NULL, objPtr, &objc, &objv);
if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "can't interpret \"%s\" as a lambda expression",
- Tcl_GetString(objPtr)));
- Tcl_SetErrorCode(interp, "TCL", "VALUE", "LAMBDA", (void *)NULL);
+ TclNewLiteralStringObj(errPtr, "can't interpret \"");
+ Tcl_AppendObjToObj(errPtr, objPtr);
+ Tcl_AppendToObj(errPtr, "\" as a lambda expression", -1);
+ Tcl_SetObjResult(interp, errPtr);
return TCL_ERROR;
}
@@ -2527,9 +2515,11 @@ SetLambdaFromAny(
*/
if (iPtr->cmdFramePtr) {
- CmdFrame *contextPtr = (CmdFrame *)TclStackAlloc(interp, sizeof(CmdFrame));
+ CmdFrame *contextPtr;
+ contextPtr = (CmdFrame *) TclStackAlloc(interp, sizeof(CmdFrame));
*contextPtr = *iPtr->cmdFramePtr;
+
if (contextPtr->type == TCL_LOCATION_BC) {
/*
* Retrieve the source context from the bytecode. This call
@@ -2556,19 +2546,19 @@ SetLambdaFromAny(
if (contextPtr->line
&& (contextPtr->nline >= 2) && (contextPtr->line[1] >= 0)) {
- Tcl_Size buf[2];
+ int buf[2];
/*
* Move from approximation (line of list cmd word) to actual
* location (line of 2nd list element).
*/
- cfPtr = (CmdFrame *)ckalloc(sizeof(CmdFrame));
+ cfPtr = (CmdFrame *) ckalloc(sizeof(CmdFrame));
TclListLines(objPtr, contextPtr->line[1], 2, buf, NULL);
cfPtr->level = -1;
cfPtr->type = contextPtr->type;
- cfPtr->line = (Tcl_Size *)ckalloc(sizeof(Tcl_Size));
+ cfPtr->line = (int *) ckalloc(sizeof(int));
cfPtr->line[0] = buf[1];
cfPtr->nline = 1;
cfPtr->framePtr = NULL;
@@ -2577,8 +2567,8 @@ SetLambdaFromAny(
cfPtr->data.eval.path = contextPtr->data.eval.path;
Tcl_IncrRefCount(cfPtr->data.eval.path);
- cfPtr->cmd = NULL;
- cfPtr->len = 0;
+ cfPtr->cmd.str.cmd = NULL;
+ cfPtr->cmd.str.len = 0;
}
/*
@@ -2590,7 +2580,7 @@ SetLambdaFromAny(
}
TclStackFree(interp, contextPtr);
}
- Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr, procPtr,
+ Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr, (char *) procPtr,
&isNew), cfPtr);
/*
@@ -2601,7 +2591,7 @@ SetLambdaFromAny(
if (objc == 2) {
TclNewLiteralStringObj(nsObjPtr, "::");
} else {
- const char *nsName = TclGetString(objv[2]);
+ char *nsName = TclGetString(objv[2]);
if ((*nsName != ':') || (*(nsName+1) != ':')) {
TclNewLiteralStringObj(nsObjPtr, "::");
@@ -2611,41 +2601,20 @@ SetLambdaFromAny(
}
}
+ Tcl_IncrRefCount(nsObjPtr);
+
/*
* Free the list internalrep of objPtr - this will free argsPtr, but
* bodyPtr retains a reference from the Proc structure. Then finish the
* conversion to lambdaType.
*/
- LambdaSetInternalRep(objPtr, procPtr, nsObjPtr);
- return TCL_OK;
-}
-
-Proc *
-TclGetLambdaFromObj(
- Tcl_Interp *interp,
- Tcl_Obj *objPtr,
- Tcl_Obj **nsObjPtrPtr)
-{
- Proc *procPtr;
- Tcl_Obj *nsObjPtr;
-
- LambdaGetInternalRep(objPtr, procPtr, nsObjPtr);
-
- if (procPtr == NULL) {
- if (SetLambdaFromAny(interp, objPtr) != TCL_OK) {
- return NULL;
- }
- LambdaGetInternalRep(objPtr, procPtr, nsObjPtr);
- }
-
- assert(procPtr != NULL);
- if (procPtr->iPtr != (Interp *)interp) {
- return NULL;
- }
+ objPtr->typePtr->freeIntRepProc(objPtr);
- *nsObjPtrPtr = nsObjPtr;
- return procPtr;
+ objPtr->internalRep.twoPtrValue.ptr1 = procPtr;
+ objPtr->internalRep.twoPtrValue.ptr2 = nsObjPtr;
+ objPtr->typePtr = &lambdaType;
+ return TCL_OK;
}
/*
@@ -2667,92 +2636,113 @@ TclGetLambdaFromObj(
int
Tcl_ApplyObjCmd(
- void *clientData,
+ ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
-{
- return Tcl_NRCallObjProc(interp, TclNRApplyObjCmd, clientData, objc, objv);
-}
-
-int
-TclNRApplyObjCmd(
- TCL_UNUSED(void *),
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
+ Tcl_Obj *CONST objv[]) /* Argument objects. */
{
+ Interp *iPtr = (Interp *) interp;
Proc *procPtr = NULL;
Tcl_Obj *lambdaPtr, *nsObjPtr;
- int result;
+ int result, isRootEnsemble;
+ Command cmd;
Tcl_Namespace *nsPtr;
- ApplyExtraData *extraPtr;
+ ExtraFrameInfo efi;
if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "lambdaExpr ?arg ...?");
+ Tcl_WrongNumArgs(interp, 1, objv, "lambdaExpr ?arg1 arg2 ...?");
return TCL_ERROR;
}
/*
- * Set lambdaPtr, convert it to tclLambdaType in the current interp if
+ * Set lambdaPtr, convert it to lambdaType in the current interp if
* necessary.
*/
lambdaPtr = objv[1];
- procPtr = TclGetLambdaFromObj(interp, lambdaPtr, &nsObjPtr);
-
- if (procPtr == NULL) {
- return TCL_ERROR;
+ if (lambdaPtr->typePtr == &lambdaType) {
+ procPtr = lambdaPtr->internalRep.twoPtrValue.ptr1;
}
- /*
- * Push a call frame for the lambda namespace.
- * Note that TclObjInterpProc() will pop it.
- */
+#define JOE_EXTENSION 0
+#if JOE_EXTENSION
+ else {
+ /*
+ * Joe English's suggestion to allow cmdNames to function as lambdas.
+ * Also requires making tclCmdNameType non-static in tclObj.c
+ */
- result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
- if (result != TCL_OK) {
- return TCL_ERROR;
+ Tcl_Obj *elemPtr;
+ int numElem;
+
+ if ((lambdaPtr->typePtr == &tclCmdNameType) ||
+ (TclListObjGetElements(interp, lambdaPtr, &numElem,
+ &elemPtr) == TCL_OK && numElem == 1)) {
+ return Tcl_EvalObjv(interp, objc-1, objv+1, 0);
+ }
+ }
+#endif
+
+ if ((procPtr == NULL) || (procPtr->iPtr != iPtr)) {
+ result = SetLambdaFromAny(interp, lambdaPtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ procPtr = lambdaPtr->internalRep.twoPtrValue.ptr1;
}
- extraPtr = (ApplyExtraData *)TclStackAlloc(interp, sizeof(ApplyExtraData));
- memset(&extraPtr->cmd, 0, sizeof(Command));
- procPtr->cmdPtr = &extraPtr->cmd;
- extraPtr->cmd.nsPtr = (Namespace *) nsPtr;
+ memset(&cmd, 0, sizeof(Command));
+ procPtr->cmdPtr = &cmd;
/*
* TIP#280 (semi-)HACK!
*
- * Using cmd.clientData to tell [info frame] how to render the lambdaPtr.
- * The InfoFrameCmd will detect this case by testing cmd.hPtr for NULL.
- * This condition holds here because of the memset() above, and nowhere
- * else (in the core). Regular commands always have a valid hPtr, and
- * lambda's never.
+ * Using cmd.clientData to tell [info frame] how to render the
+ * 'lambdaPtr'. The InfoFrameCmd will detect this case by testing cmd.hPtr
+ * for NULL. This condition holds here because of the 'memset' above, and
+ * nowhere else (in the core). Regular commands always have a valid
+ * 'hPtr', and lambda's never.
*/
- extraPtr->efi.length = 1;
- extraPtr->efi.fields[0].name = "lambda";
- extraPtr->efi.fields[0].proc = NULL;
- extraPtr->efi.fields[0].clientData = lambdaPtr;
- extraPtr->cmd.clientData = &extraPtr->efi;
+ efi.length = 1;
+ efi.fields[0].name = "lambda";
+ efi.fields[0].proc = NULL;
+ efi.fields[0].clientData = lambdaPtr;
+ cmd.clientData = &efi;
+
+ /*
+ * Find the namespace where this lambda should run, and push a call frame
+ * for that namespace. Note that TclObjInterpProc() will pop it.
+ */
+
+ nsObjPtr = lambdaPtr->internalRep.twoPtrValue.ptr2;
+ result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+
+ cmd.nsPtr = (Namespace *) nsPtr;
- result = TclPushProcCallFrame(procPtr, interp, objc, objv, 1);
+ isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL);
+ if (isRootEnsemble) {
+ iPtr->ensembleRewrite.sourceObjs = objv;
+ iPtr->ensembleRewrite.numRemovedObjs = 1;
+ iPtr->ensembleRewrite.numInsertedObjs = 0;
+ } else {
+ iPtr->ensembleRewrite.numInsertedObjs -= 1;
+ }
+
+ result = PushProcCallFrame((ClientData) procPtr, interp, objc, objv, 1);
if (result == TCL_OK) {
- TclNRAddCallback(interp, ApplyNR2, extraPtr, NULL, NULL, NULL);
- result = TclNRInterpProcCore(interp, objv[1], 2, &MakeLambdaError);
+ result = TclObjInterpProcCore(interp, objv[1], 2, &MakeLambdaError);
}
- return result;
-}
-static int
-ApplyNR2(
- void *data[],
- Tcl_Interp *interp,
- int result)
-{
- ApplyExtraData *extraPtr = (ApplyExtraData *)data[0];
+ if (isRootEnsemble) {
+ iPtr->ensembleRewrite.sourceObjs = NULL;
+ iPtr->ensembleRewrite.numRemovedObjs = 0;
+ iPtr->ensembleRewrite.numInsertedObjs = 0;
+ }
- TclStackFree(interp, extraPtr);
return result;
}
@@ -2781,50 +2771,138 @@ MakeLambdaError(
Tcl_Obj *procNameObj) /* Name of the procedure. Used for error
* messages and trace information. */
{
- int overflow, limit = 60;
- Tcl_Size nameLen;
- const char *procName = TclGetStringFromObj(procNameObj, &nameLen);
+ int overflow, limit = 60, nameLen;
+ const char *procName = Tcl_GetStringFromObj(procNameObj, &nameLen);
overflow = (nameLen > limit);
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (lambda term \"%.*s%s\" line %d)",
- (overflow ? limit : (int)nameLen), procName,
- (overflow ? "..." : ""), Tcl_GetErrorLine(interp)));
+ (overflow ? limit : nameLen), procName,
+ (overflow ? "..." : ""), interp->errorLine));
}
+
/*
*----------------------------------------------------------------------
*
- * TclGetCmdFrameForProcedure --
- *
- * How to get the CmdFrame information for a procedure.
- *
- * Results:
- * A pointer to the CmdFrame (only guaranteed to be valid until the next
- * Tcl command is processed or the interpreter's state is otherwise
- * modified) or a NULL if the information is not available.
+ * Tcl_DisassembleObjCmd --
*
- * Side effects:
- * none.
+ * Implementation of the "::tcl::unsupported::disassemble" command. This
+ * command is not documented, but will disassemble procedures, lambda
+ * terms and general scripts. Note that will compile terms if necessary
+ * in order to disassemble them.
*
*----------------------------------------------------------------------
*/
-CmdFrame *
-TclGetCmdFrameForProcedure(
- Proc *procPtr) /* The procedure whose cmd-frame is to be
- * looked up. */
+int
+Tcl_DisassembleObjCmd(
+ ClientData dummy, /* Not used. */
+ Tcl_Interp *interp, /* Current interpreter. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *CONST objv[]) /* Argument objects. */
{
- Tcl_HashEntry *hePtr;
+ static const char *types[] = {
+ "lambda", "proc", "script", NULL
+ };
+ enum Types {
+ DISAS_LAMBDA, DISAS_PROC, DISAS_SCRIPT
+ };
+ int idx, result;
+
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 1, objv, "type procName|lambdaTerm|script");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObj(interp, objv[1], types, "type", 0, &idx)!=TCL_OK){
+ return TCL_ERROR;
+ }
- if (procPtr == NULL || procPtr->iPtr == NULL) {
- return NULL;
+ switch ((enum Types) idx) {
+ case DISAS_LAMBDA: {
+ Proc *procPtr = NULL;
+ Command cmd;
+ Tcl_Obj *nsObjPtr;
+ Tcl_Namespace *nsPtr;
+
+ /*
+ * Compile (if uncompiled) and disassemble a lambda term.
+ */
+
+ if (objv[2]->typePtr == &lambdaType) {
+ procPtr = objv[2]->internalRep.twoPtrValue.ptr1;
+ }
+ if (procPtr == NULL || procPtr->iPtr != (Interp *) interp) {
+ result = SetLambdaFromAny(interp, objv[2]);
+ if (result != TCL_OK) {
+ return result;
+ }
+ procPtr = objv[2]->internalRep.twoPtrValue.ptr1;
+ }
+
+ memset(&cmd, 0, sizeof(Command));
+ nsObjPtr = objv[2]->internalRep.twoPtrValue.ptr2;
+ result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
+ if (result != TCL_OK) {
+ return result;
+ }
+ cmd.nsPtr = (Namespace *) nsPtr;
+ procPtr->cmdPtr = &cmd;
+ result = PushProcCallFrame(procPtr, interp, objc, objv, 1);
+ if (result != TCL_OK) {
+ return result;
+ }
+ TclPopStackFrame(interp);
+ if (((ByteCode *) procPtr->bodyPtr->internalRep.twoPtrValue.ptr1)->flags
+ & TCL_BYTECODE_PRECOMPILED) {
+ Tcl_AppendResult(interp, "may not disassemble prebuilt bytecode",
+ NULL);
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, TclDisassembleByteCodeObj(procPtr->bodyPtr));
+ break;
}
- hePtr = Tcl_FindHashEntry(procPtr->iPtr->linePBodyPtr, procPtr);
- if (hePtr == NULL) {
- return NULL;
+ case DISAS_PROC: {
+ Proc *procPtr = TclFindProc((Interp *) interp, TclGetString(objv[2]));
+
+ if (procPtr == NULL) {
+ Tcl_AppendResult(interp, "\"", TclGetString(objv[2]),
+ "\" isn't a procedure", NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Compile (if uncompiled) and disassemble a procedure.
+ */
+
+ result = PushProcCallFrame(procPtr, interp, 2, objv+1, 1);
+ if (result != TCL_OK) {
+ return result;
+ }
+ TclPopStackFrame(interp);
+ if (((ByteCode *) procPtr->bodyPtr->internalRep.twoPtrValue.ptr1)->flags
+ & TCL_BYTECODE_PRECOMPILED) {
+ Tcl_AppendResult(interp, "may not disassemble prebuilt bytecode",
+ NULL);
+ return TCL_ERROR;
+ }
+ Tcl_SetObjResult(interp, TclDisassembleByteCodeObj(procPtr->bodyPtr));
+ break;
}
- return (CmdFrame *) Tcl_GetHashValue(hePtr);
+ case DISAS_SCRIPT:
+ /*
+ * Compile and disassemble a script.
+ */
+
+ if (objv[2]->typePtr != &tclByteCodeType) {
+ if (TclSetByteCodeFromAny(interp, objv[2], NULL, NULL) != TCL_OK){
+ return TCL_ERROR;
+ }
+ }
+ Tcl_SetObjResult(interp, TclDisassembleByteCodeObj(objv[2]));
+ break;
+ }
+ return TCL_OK;
}
/*