summaryrefslogtreecommitdiffstats
path: root/generic/tclBasic.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclBasic.c')
-rw-r--r--generic/tclBasic.c220
1 files changed, 150 insertions, 70 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 264fdc8..a097976 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -16,7 +16,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclBasic.c,v 1.394 2009/05/08 08:48:19 dkf Exp $
+ * RCS: @(#) $Id: tclBasic.c,v 1.395 2009/07/14 16:34:08 andreas_kupries Exp $
*/
#include "tclInt.h"
@@ -1545,9 +1545,7 @@ DeleteInterpProc(
ckfree((char *) eclPtr->loc);
}
- if (eclPtr->eiloc != NULL) {
- ckfree((char *) eclPtr->eiloc);
- }
+ Tcl_DeleteHashTable (&eclPtr->litInfo);
ckfree((char *) eclPtr);
Tcl_DeleteHashEntry(hPtr);
@@ -5448,49 +5446,74 @@ TclArgumentRelease(
void
TclArgumentBCEnter(
- Tcl_Interp *interp,
- void *codePtr,
- CmdFrame *cfPtr)
+ Tcl_Interp* interp,
+ Tcl_Obj* objv[],
+ int objc,
+ void* codePtr,
+ CmdFrame* cfPtr,
+ int pc)
{
- Interp *iPtr = (Interp *) interp;
- Tcl_HashEntry *hePtr = Tcl_FindHashEntry(iPtr->lineBCPtr,
- (char *) codePtr);
+ Interp* iPtr = (Interp*) interp;
+ Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->lineBCPtr, (char *) codePtr);
if (hePtr) {
- ExtCmdLoc *eclPtr = Tcl_GetHashValue(hePtr);
- int i;
+ ExtCmdLoc* eclPtr = (ExtCmdLoc*) Tcl_GetHashValue (hePtr);
+ hePtr = Tcl_FindHashEntry(&eclPtr->litInfo, (char*) pc);
- for (i = 0; i < eclPtr->nueiloc; i++) {
- ExtIndex *eiPtr = &eclPtr->eiloc[i];
- Tcl_Obj *obj = eiPtr->obj;
- int new;
- Tcl_HashEntry *hPtr;
- CFWordBC *cfwPtr;
+ if (hePtr) {
+ int word;
+ int cmd = (int) Tcl_GetHashValue(hePtr);
+ ECL* ePtr = &eclPtr->loc[cmd];
+ CFWordBC* lastPtr = 0;
- hPtr = Tcl_CreateHashEntry(iPtr->lineLABCPtr, (char *) obj, &new);
- if (new) {
- /*
- * The word is not on the stack yet, remember the current
- * location and initialize references.
- */
+ /*
+ * A few truths ...
+ * (1) ePtr->nline == objc
+ * (2) (ePtr->line[word] < 0) => !literal, for all words
+ * (3) (word == 0) => !literal
+ *
+ * Item (2) is why we can use objv to get the literals, and do not
+ * have to save them at compile time.
+ */
- cfwPtr = (CFWordBC *) ckalloc(sizeof(CFWordBC));
- cfwPtr->framePtr = cfPtr;
- cfwPtr->eiPtr = eiPtr;
- cfwPtr->refCount = 1;
- Tcl_SetHashValue(hPtr, cfwPtr);
- } else {
- /*
- * The word is already on the stack, its current location is
- * not relevant. Just remember the reference to prevent early
- * removal.
- */
+ for (word = 1; word < objc; word++) {
+ if (ePtr->line[word] >= 0) {
+ int isnew;
+ Tcl_HashEntry* hPtr =
+ Tcl_CreateHashEntry (iPtr->lineLABCPtr,
+ (char*) objv[word], &isnew);
+ CFWordBC* cfwPtr = (CFWordBC*) ckalloc (sizeof (CFWordBC));
+
+ cfwPtr->framePtr = cfPtr;
+ cfwPtr->obj = objv[word];
+ cfwPtr->pc = pc;
+ cfwPtr->word = word;
+ cfwPtr->nextPtr = lastPtr;
+ lastPtr = cfwPtr;
+
+ if (isnew) {
+ /*
+ * The word is not on the stack yet, remember the
+ * current location and initialize references.
+ */
+ cfwPtr->prevPtr = NULL;
+ } else {
+ /*
+ * The object is already on the stack, however it may
+ * have a different location now (literal sharing may
+ * map multiple location to a single Tcl_Obj*. Save
+ * the old information in the new structure.
+ */
+ cfwPtr->prevPtr = (CFWordBC*) Tcl_GetHashValue(hPtr);
+ }
- cfwPtr = Tcl_GetHashValue(hPtr);
- cfwPtr->refCount++;
- }
- }
- }
+ Tcl_SetHashValue (hPtr, cfwPtr);
+ }
+ } /* for */
+
+ cfPtr->litarg = lastPtr;
+ } /* if */
+ } /* if */
}
/*
@@ -5516,37 +5539,33 @@ TclArgumentBCEnter(
void
TclArgumentBCRelease(
Tcl_Interp *interp,
- void *codePtr)
+ CmdFrame* cfPtr)
{
- Interp *iPtr = (Interp *) interp;
- Tcl_HashEntry *hePtr = Tcl_FindHashEntry(iPtr->lineBCPtr,
- (char *) codePtr);
+ Interp* iPtr = (Interp*) interp;
+ CFWordBC* cfwPtr = (CFWordBC*) cfPtr->litarg;
- if (hePtr) {
- ExtCmdLoc *eclPtr = Tcl_GetHashValue(hePtr);
- int i;
-
- for (i = 0; i < eclPtr->nueiloc; i++) {
- Tcl_Obj *obj = eclPtr->eiloc[i].obj;
- Tcl_HashEntry *hPtr = Tcl_FindHashEntry(iPtr->lineLABCPtr,
- (char *) obj);
- CFWordBC *cfwPtr;
-
- if (!hPtr) {
- continue;
- }
-
- cfwPtr = Tcl_GetHashValue(hPtr);
+ while (cfwPtr) {
+ CFWordBC* nextPtr = cfwPtr->nextPtr;
+ Tcl_HashEntry* hPtr =
+ Tcl_FindHashEntry(iPtr->lineLABCPtr, (char *) cfwPtr->obj);
+ CFWordBC* xPtr = (CFWordBC*) Tcl_GetHashValue (hPtr);
- cfwPtr->refCount--;
- if (cfwPtr->refCount > 0) {
- continue;
- }
+ if (xPtr != cfwPtr) {
+ Tcl_Panic ("TclArgumentBC Enter/Release Mismatch");
+ }
- ckfree((char *) cfwPtr);
+ if (cfwPtr->prevPtr) {
+ Tcl_SetHashValue(hPtr, cfwPtr->prevPtr);
+ } else {
Tcl_DeleteHashEntry(hPtr);
}
+
+ ckfree((char *) cfwPtr);
+
+ cfwPtr = nextPtr;
}
+
+ cfPtr->litarg = NULL;
}
/*
@@ -5612,13 +5631,12 @@ TclArgumentGet(
hPtr = Tcl_FindHashEntry(iPtr->lineLABCPtr, (char *) obj);
if (hPtr) {
CFWordBC *cfwPtr = Tcl_GetHashValue(hPtr);
- ExtIndex *eiPtr = cfwPtr->eiPtr;
framePtr = cfwPtr->framePtr;
framePtr->data.tebc.pc = (char *) (((ByteCode *)
- framePtr->data.tebc.codePtr)->codeStart + eiPtr->pc);
+ framePtr->data.tebc.codePtr)->codeStart + cfwPtr->pc);
*cfPtrPtr = cfwPtr->framePtr;
- *wordPtr = eiPtr->word;
+ *wordPtr = cfwPtr->word;
return;
}
}
@@ -8072,6 +8090,16 @@ TclNRTailcallObjCmd(
* TclNRAddCallBack macro to build the callback)
*/
+ /*
+ * In a bytecode execution context the engine has called
+ * TclArgumentBCEnter() which, due to the tailcall, is not paired with a
+ * regular TclArgumentBCRelease. Get rid of it on our own.
+ */
+
+ if (iPtr->cmdFramePtr->type == TCL_LOCATION_BC) {
+ TclArgumentBCRelease (interp, iPtr->cmdFramePtr);
+ }
+
TclNRAddCallback(interp, NRTailcallEval, listPtr, nsObjPtr, NULL, NULL);
tailcallPtr = TOP_CB(interp);
TOP_CB(interp) = tailcallPtr->nextPtr;
@@ -8182,12 +8210,14 @@ static const CorContext NULL_CONTEXT = {NULL, NULL, NULL};
#define SAVE_CONTEXT(context) \
(context).framePtr = iPtr->framePtr; \
(context).varFramePtr = iPtr->varFramePtr; \
- (context).cmdFramePtr = iPtr->cmdFramePtr
+ (context).cmdFramePtr = iPtr->cmdFramePtr; \
+ (context).lineLABCPtr = iPtr->lineLABCPtr
#define RESTORE_CONTEXT(context) \
iPtr->framePtr = (context).framePtr; \
iPtr->varFramePtr = (context).varFramePtr; \
- iPtr->cmdFramePtr = (context).cmdFramePtr
+ iPtr->cmdFramePtr = (context).cmdFramePtr; \
+ iPtr->lineLABCPtr = (context).lineLABCPtr
#define iPtr ((Interp *) interp)
@@ -8384,7 +8414,8 @@ NRCoroutineExitCallback(
TclDeleteExecEnv(corPtr->eePtr);
corPtr->eePtr = NULL;
- /* RESTORE_CONTEXT(corPtr->caller); AUTOMATIC! */
+ SAVE_CONTEXT(corPtr->running);
+ RESTORE_CONTEXT(corPtr->caller);
NRE_ASSERT(iPtr->framePtr == corPtr->caller.framePtr);
NRE_ASSERT(iPtr->cmdFramePtr == corPtr->caller.cmdFramePtr);
@@ -8392,6 +8423,16 @@ NRCoroutineExitCallback(
iPtr->execEnvPtr = corPtr->callerEEPtr;
+ /*
+ * #280.
+ * Drop the coroutine-owned copy of the lineLABCPtr hashtable for literal
+ * command arguments in bytecode.
+ */
+
+ Tcl_DeleteHashTable(corPtr->base.lineLABCPtr);
+ ckfree((char *) corPtr->base.lineLABCPtr);
+ corPtr->base.lineLABCPtr = NULL;
+
return result;
}
@@ -8555,6 +8596,45 @@ TclNRCoroutineObjCmd(
corPtr->running = NULL_CONTEXT;
/*
+ * #280.
+ * Provide the new coroutine with its own copy of the lineLABCPtr
+ * hashtable for literal command arguments in bytecode. Note that that
+ * CFWordBC chains are not duplicated, only the entrypoints to them. This
+ * means that in the presence of coroutines each chain is potentially a
+ * tree. Like the chain -> tree conversion of the CmdFrame stack.
+ */
+
+ {
+ Tcl_HashSearch hSearch;
+ Tcl_HashEntry* hePtr;
+
+ corPtr->base.lineLABCPtr = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
+ Tcl_InitHashTable(corPtr->base.lineLABCPtr, TCL_ONE_WORD_KEYS);
+
+ for (hePtr = Tcl_FirstHashEntry(iPtr->lineLABCPtr,&hSearch);
+ hePtr;
+ hePtr = Tcl_NextHashEntry(&hSearch)) {
+ int isNew;
+ Tcl_HashEntry* newPtr =
+ Tcl_CreateHashEntry(corPtr->base.lineLABCPtr,
+ (char *) Tcl_GetHashKey (iPtr->lineLABCPtr, hePtr),
+ &isNew);
+ Tcl_SetHashValue(newPtr, Tcl_GetHashValue(hePtr));
+ }
+
+ /*
+ * The new copy is immediately plugged interpreter for use by the
+ * first coroutine commands (see below). The interp's copy of the
+ * table is already saved, see the SAVE_CONTEXT found just above this
+ * whole code block. This also properly prepares us for the
+ * SAVE/RESTORE dances during yields which swizzle the pointers
+ * around.
+ */
+
+ iPtr->lineLABCPtr = corPtr->base.lineLABCPtr;
+ }
+
+ /*
* Eval things in 'uplevel #0', except for the very first command lookup
* which should be looked up in caller's context.
*