summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorandreask <andreask>2011-05-17 21:38:46 (GMT)
committerandreask <andreask>2011-05-17 21:38:46 (GMT)
commit305650f1080fae0aea9e332254c68e54b6ec52c1 (patch)
treeb5e7c39efe55151da282aae8a06fc6d25a81b1e5 /generic
parent525e8327035d58f720479724c2e40e65f9bbf3da (diff)
parentb1afef184bd6e770f5f2f45c2492011a9da336d2 (diff)
downloadtcl-305650f1080fae0aea9e332254c68e54b6ec52c1.zip
tcl-305650f1080fae0aea9e332254c68e54b6ec52c1.tar.gz
tcl-305650f1080fae0aea9e332254c68e54b6ec52c1.tar.bz2
Merged core-8-5-branch, fixup of TIP 280 location mapping.
Diffstat (limited to 'generic')
-rw-r--r--generic/tclBasic.c4
-rw-r--r--generic/tclCompile.c64
2 files changed, 68 insertions, 0 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 2da455b..d80731e 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -5590,6 +5590,10 @@ TclArgumentBCEnter(
* 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 2194ae1..0eaf834 100644
--- a/generic/tclCompile.c
+++ b/generic/tclCompile.c
@@ -3320,6 +3320,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 */
}