diff options
author | andreask <andreask> | 2011-05-17 21:26:26 (GMT) |
---|---|---|
committer | andreask <andreask> | 2011-05-17 21:26:26 (GMT) |
commit | ae8c7e936a3c00a11a29a50f2b80df021acbea51 (patch) | |
tree | a4bbac44980f75997bbb2923ce29f7d17cb3a70d /generic | |
parent | 96524bb4dd0127496d2baf6792d0de093157297b (diff) | |
download | tcl-ae8c7e936a3c00a11a29a50f2b80df021acbea51.zip tcl-ae8c7e936a3c00a11a29a50f2b80df021acbea51.tar.gz tcl-ae8c7e936a3c00a11a29a50f2b80df021acbea51.tar.bz2 |
* generic/tclCompile.c (TclFixupForwardJump): Tracked down and fixed
* generic/tclBasic.c (TclArgumentBCEnter): the cause of a violation
of my assertion that 'ePtr->nline == objc' in TclArgumentBCEnter.
When a bytecode was grown during jump fixup the pc -> command line
mapping was not updated. When things aligned just wrong the mapping
would direct command A to the data for command B, with a different
number of arguments.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclBasic.c | 4 | ||||
-rw-r--r-- | generic/tclCompile.c | 64 |
2 files changed, 68 insertions, 0 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 71bd45c..750c9e2 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -4764,6 +4764,10 @@ TclArgumentBCEnter(interp,objv,objc,codePtr,cfPtr,pc) * have to save them at compile time. */ + if (ePtr->nline != objc) { + Tcl_Panic ("TIP 280 data structure inconsistency"); + } + for (word = 1; word < objc; word++) { if (ePtr->line[word] >= 0) { int isnew; diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 2d8d58c..8a7cbf8 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -3020,6 +3020,70 @@ TclFixupForwardJump( rangePtr->type); } } + + /* + * TIP #280: Adjust the mapping from PC values to the per-command + * information about arguments and their line numbers. + * + * Note: We cannot simply remove an out-of-date entry and then reinsert + * with the proper PC, because then we might overwrite another entry which + * was at that location. Therefore we pull (copy + delete) all effected + * entries (beyond the fixed PC) into an array, update them there, and at + * last reinsert them all. + */ + + { + ExtCmdLoc* eclPtr = envPtr->extCmdMapPtr; + + /* A helper structure */ + + typedef struct { + int pc; + int cmd; + } MAP; + + /* + * And the helper array. At most the whole hashtable is placed into + * this. + */ + + MAP *map = (MAP*) ckalloc (sizeof(MAP) * eclPtr->litInfo.numEntries); + + Tcl_HashSearch hSearch; + Tcl_HashEntry* hPtr; + int n, k, isnew; + + /* + * Phase I: Locate the affected entries, and save them in adjusted + * form to the array. This removes them from the hash. + */ + + for (n = 0, hPtr = Tcl_FirstHashEntry(&eclPtr->litInfo, &hSearch); + hPtr != NULL; + hPtr = Tcl_NextHashEntry(&hSearch)) { + + map [n].cmd = PTR2INT(Tcl_GetHashValue(hPtr)); + map [n].pc = PTR2INT(Tcl_GetHashKey (&eclPtr->litInfo,hPtr)); + + if (map[n].pc >= (jumpFixupPtr->codeOffset + 2)) { + Tcl_DeleteHashEntry(hPtr); + map [n].pc += 3; + n++; + } + } + + /* + * Phase II: Re-insert the modified entries into the hash. + */ + + for (k=0;k<n;k++) { + hPtr = Tcl_CreateHashEntry(&eclPtr->litInfo, INT2PTR(map[k].pc), &isnew); + Tcl_SetHashValue(hPtr, INT2PTR(map[k].cmd)); + } + + ckfree (map); + } + return 1; /* the jump was grown */ } |