diff options
author | andreask <andreask> | 2011-05-17 21:26:26 (GMT) |
---|---|---|
committer | andreask <andreask> | 2011-05-17 21:26:26 (GMT) |
commit | b1afef184bd6e770f5f2f45c2492011a9da336d2 (patch) | |
tree | a4bbac44980f75997bbb2923ce29f7d17cb3a70d /generic/tclCompile.c | |
parent | 4ac324aa8ce1d6355bcf7086f6e4fe2faf4143bc (diff) | |
download | tcl-b1afef184bd6e770f5f2f45c2492011a9da336d2.zip tcl-b1afef184bd6e770f5f2f45c2492011a9da336d2.tar.gz tcl-b1afef184bd6e770f5f2f45c2492011a9da336d2.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/tclCompile.c')
-rw-r--r-- | generic/tclCompile.c | 64 |
1 files changed, 64 insertions, 0 deletions
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 */ } |