tclLiteral.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:31k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclLiteral.c --
  3.  *
  4.  * Implementation of the global and ByteCode-local literal tables
  5.  * used to manage the Tcl objects created for literal values during
  6.  * compilation of Tcl scripts. This implementation borrows heavily
  7.  * from the more general hashtable implementation of Tcl hash tables
  8.  * that appears in tclHash.c.
  9.  *
  10.  * Copyright (c) 1997-1998 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * RCS: @(#) $Id: tclLiteral.c,v 1.11 2001/10/11 22:28:01 msofer Exp $
  16.  */
  17. #include "tclInt.h"
  18. #include "tclCompile.h"
  19. #include "tclPort.h"
  20. /*
  21.  * When there are this many entries per bucket, on average, rebuild
  22.  * a literal's hash table to make it larger.
  23.  */
  24. #define REBUILD_MULTIPLIER 3
  25. /*
  26.  * Procedure prototypes for static procedures in this file:
  27.  */
  28. static int AddLocalLiteralEntry _ANSI_ARGS_((
  29.     CompileEnv *envPtr, LiteralEntry *globalPtr,
  30.     int localHash));
  31. static void ExpandLocalLiteralArray _ANSI_ARGS_((
  32.     CompileEnv *envPtr));
  33. static unsigned int HashString _ANSI_ARGS_((CONST char *bytes,
  34.     int length));
  35. static void RebuildLiteralTable _ANSI_ARGS_((
  36.     LiteralTable *tablePtr));
  37. /*
  38.  *----------------------------------------------------------------------
  39.  *
  40.  * TclInitLiteralTable --
  41.  *
  42.  * This procedure is called to initialize the fields of a literal table
  43.  * structure for either an interpreter or a compilation's CompileEnv
  44.  * structure.
  45.  *
  46.  * Results:
  47.  * None.
  48.  *
  49.  * Side effects: 
  50.  * The literal table is made ready for use.
  51.  *
  52.  *----------------------------------------------------------------------
  53.  */
  54. void
  55. TclInitLiteralTable(tablePtr)
  56.     register LiteralTable *tablePtr; /* Pointer to table structure, which
  57.       * is supplied by the caller. */
  58. {
  59. #if (TCL_SMALL_HASH_TABLE != 4) 
  60.     panic("TclInitLiteralTable: TCL_SMALL_HASH_TABLE is %d, not 4n",
  61.     TCL_SMALL_HASH_TABLE);
  62. #endif
  63.     
  64.     tablePtr->buckets = tablePtr->staticBuckets;
  65.     tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
  66.     tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
  67.     tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
  68.     tablePtr->numEntries = 0;
  69.     tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER;
  70.     tablePtr->mask = 3;
  71. }
  72. /*
  73.  *----------------------------------------------------------------------
  74.  *
  75.  * TclDeleteLiteralTable --
  76.  *
  77.  * This procedure frees up everything associated with a literal table
  78.  * except for the table's structure itself.
  79.  *
  80.  * Results:
  81.  * None.
  82.  *
  83.  * Side effects:
  84.  * Each literal in the table is released: i.e., its reference count
  85.  * in the global literal table is decremented and, if it becomes zero,
  86.  * the literal is freed. In addition, the table's bucket array is
  87.  * freed.
  88.  *
  89.  *----------------------------------------------------------------------
  90.  */
  91. void
  92. TclDeleteLiteralTable(interp, tablePtr)
  93.     Tcl_Interp *interp; /* Interpreter containing shared literals
  94.  * referenced by the table to delete. */
  95.     LiteralTable *tablePtr; /* Points to the literal table to delete. */
  96. {
  97.     LiteralEntry *entryPtr;
  98.     int i, start;
  99.     /*
  100.      * Release remaining literals in the table. Note that releasing a
  101.      * literal might release other literals, modifying the table, so we
  102.      * restart the search from the bucket chain we last found an entry.
  103.      */
  104. #ifdef TCL_COMPILE_DEBUG
  105.     TclVerifyGlobalLiteralTable((Interp *) interp);
  106. #endif /*TCL_COMPILE_DEBUG*/
  107.     start = 0;
  108.     while (tablePtr->numEntries > 0) {
  109. for (i = start;  i < tablePtr->numBuckets;  i++) {
  110.     entryPtr = tablePtr->buckets[i];
  111.     if (entryPtr != NULL) {
  112. TclReleaseLiteral(interp, entryPtr->objPtr);
  113. start = i;
  114. break;
  115.     }
  116. }
  117.     }
  118.     /*
  119.      * Free up the table's bucket array if it was dynamically allocated.
  120.      */
  121.     if (tablePtr->buckets != tablePtr->staticBuckets) {
  122. ckfree((char *) tablePtr->buckets);
  123.     }
  124. }
  125. /*
  126.  *----------------------------------------------------------------------
  127.  *
  128.  * TclRegisterLiteral --
  129.  *
  130.  * Find, or if necessary create, an object in a CompileEnv literal
  131.  * array that has a string representation matching the argument string.
  132.  *
  133.  * Results:
  134.  * The index in the CompileEnv's literal array that references a
  135.  * shared literal matching the string. The object is created if
  136.  * necessary.
  137.  *
  138.  * Side effects:
  139.  * To maximize sharing, we look up the string in the interpreter's
  140.  * global literal table. If not found, we create a new shared literal
  141.  * in the global table. We then add a reference to the shared
  142.  * literal in the CompileEnv's literal array. 
  143.  *
  144.  * If onHeap is 1, this procedure is given ownership of the string: if
  145.  * an object is created then its string representation is set directly
  146.  * from string, otherwise the string is freed. Typically, a caller sets
  147.  * onHeap 1 if "string" is an already heap-allocated buffer holding the
  148.  * result of backslash substitutions.
  149.  *
  150.  *----------------------------------------------------------------------
  151.  */
  152. int
  153. TclRegisterLiteral(envPtr, bytes, length, onHeap)
  154.     CompileEnv *envPtr; /* Points to the CompileEnv in whose object
  155.  * array an object is found or created. */
  156.     register char *bytes; /* Points to string for which to find or
  157.  * create an object in CompileEnv's object
  158.  * array. */
  159.     int length; /* Number of bytes in the string. If < 0,
  160.  * the string consists of all bytes up to
  161.  * the first null character. */
  162.     int onHeap; /* If 1 then the caller already malloc'd
  163.  * bytes and ownership is passed to this
  164.  * procedure. */
  165. {
  166.     Interp *iPtr = envPtr->iPtr;
  167.     LiteralTable *globalTablePtr = &(iPtr->literalTable);
  168.     LiteralTable *localTablePtr = &(envPtr->localLitTable);
  169.     register LiteralEntry *globalPtr, *localPtr;
  170.     register Tcl_Obj *objPtr;
  171.     unsigned int hash;
  172.     int localHash, globalHash, objIndex;
  173.     long n;
  174.     char buf[TCL_INTEGER_SPACE];
  175.     if (length < 0) {
  176. length = (bytes? strlen(bytes) : 0);
  177.     }
  178.     hash = HashString(bytes, length);
  179.     /*
  180.      * Is the literal already in the CompileEnv's local literal array?
  181.      * If so, just return its index.
  182.      */
  183.     localHash = (hash & localTablePtr->mask);
  184.     for (localPtr = localTablePtr->buckets[localHash];
  185.   localPtr != NULL;  localPtr = localPtr->nextPtr) {
  186. objPtr = localPtr->objPtr;
  187. if ((objPtr->length == length) && ((length == 0)
  188. || ((objPtr->bytes[0] == bytes[0])
  189. && (memcmp(objPtr->bytes, bytes, (unsigned) length)
  190. == 0)))) {
  191.     if (onHeap) {
  192. ckfree(bytes);
  193.     }
  194.     objIndex = (localPtr - envPtr->literalArrayPtr);
  195. #ifdef TCL_COMPILE_DEBUG
  196.     TclVerifyLocalLiteralTable(envPtr);
  197. #endif /*TCL_COMPILE_DEBUG*/
  198.     return objIndex;
  199. }
  200.     }
  201.     /*
  202.      * The literal is new to this CompileEnv. Is it in the interpreter's
  203.      * global literal table?
  204.      */
  205.     globalHash = (hash & globalTablePtr->mask);
  206.     for (globalPtr = globalTablePtr->buckets[globalHash];
  207.  globalPtr != NULL;  globalPtr = globalPtr->nextPtr) {
  208. objPtr = globalPtr->objPtr;
  209. if ((objPtr->length == length) && ((length == 0)
  210. || ((objPtr->bytes[0] == bytes[0])
  211. && (memcmp(objPtr->bytes, bytes, (unsigned) length)
  212. == 0)))) {
  213.     /*
  214.      * A global literal was found. Add an entry to the CompileEnv's
  215.      * local literal array.
  216.      */
  217.     
  218.     if (onHeap) {
  219. ckfree(bytes);
  220.     }
  221.     objIndex = AddLocalLiteralEntry(envPtr, globalPtr, localHash);
  222. #ifdef TCL_COMPILE_DEBUG
  223.     if (globalPtr->refCount < 1) {
  224. panic("TclRegisterLiteral: global literal "%.*s" had bad refCount %d",
  225. (length>60? 60 : length), bytes,
  226. globalPtr->refCount);
  227.     }
  228.     TclVerifyLocalLiteralTable(envPtr);
  229. #endif /*TCL_COMPILE_DEBUG*/ 
  230.     return objIndex;
  231. }
  232.     }
  233.     /*
  234.      * The literal is new to the interpreter. Add it to the global literal
  235.      * table then add an entry to the CompileEnv's local literal array.
  236.      * Convert the object to an integer object if possible.
  237.      */
  238.     TclNewObj(objPtr);
  239.     Tcl_IncrRefCount(objPtr);
  240.     if (onHeap) {
  241. objPtr->bytes = bytes;
  242. objPtr->length = length;
  243.     } else {
  244. TclInitStringRep(objPtr, bytes, length);
  245.     }
  246.     if (TclLooksLikeInt(bytes, length)) {
  247. /*
  248.  * From here we use the objPtr, because it is NULL terminated
  249.  */
  250. if (TclGetLong((Tcl_Interp *) NULL, objPtr->bytes, &n) == TCL_OK) {
  251.     TclFormatInt(buf, n);
  252.     if (strcmp(objPtr->bytes, buf) == 0) {
  253. objPtr->internalRep.longValue = n;
  254. objPtr->typePtr = &tclIntType;
  255.     }
  256. }
  257.     }
  258.     
  259. #ifdef TCL_COMPILE_DEBUG
  260.     if (TclLookupLiteralEntry((Tcl_Interp *) iPtr, objPtr) != NULL) {
  261. panic("TclRegisterLiteral: literal "%.*s" found globally but shouldn't be",
  262.         (length>60? 60 : length), bytes);
  263.     }
  264. #endif
  265.     globalPtr = (LiteralEntry *) ckalloc((unsigned) sizeof(LiteralEntry));
  266.     globalPtr->objPtr = objPtr;
  267.     globalPtr->refCount = 0;
  268.     globalPtr->nextPtr = globalTablePtr->buckets[globalHash];
  269.     globalTablePtr->buckets[globalHash] = globalPtr;
  270.     globalTablePtr->numEntries++;
  271.     /*
  272.      * If the global literal table has exceeded a decent size, rebuild it
  273.      * with more buckets.
  274.      */
  275.     if (globalTablePtr->numEntries >= globalTablePtr->rebuildSize) {
  276. RebuildLiteralTable(globalTablePtr);
  277.     }
  278.     objIndex = AddLocalLiteralEntry(envPtr, globalPtr, localHash);
  279. #ifdef TCL_COMPILE_DEBUG
  280.     TclVerifyGlobalLiteralTable(iPtr);
  281.     TclVerifyLocalLiteralTable(envPtr);
  282.     {
  283. LiteralEntry *entryPtr;
  284. int found, i;
  285. found = 0;
  286. for (i = 0;  i < globalTablePtr->numBuckets;  i++) {
  287.     for (entryPtr = globalTablePtr->buckets[i];
  288.     entryPtr != NULL;  entryPtr = entryPtr->nextPtr) {
  289. if ((entryPtr == globalPtr)
  290.         && (entryPtr->objPtr == objPtr)) {
  291.     found = 1;
  292. }
  293.     }
  294. }
  295. if (!found) {
  296.     panic("TclRegisterLiteral: literal "%.*s" wasn't global",
  297.             (length>60? 60 : length), bytes);
  298. }
  299.     }
  300. #endif /*TCL_COMPILE_DEBUG*/
  301. #ifdef TCL_COMPILE_STATS   
  302.     iPtr->stats.numLiteralsCreated++;
  303.     iPtr->stats.totalLitStringBytes   += (double) (length + 1);
  304.     iPtr->stats.currentLitStringBytes += (double) (length + 1);
  305.     iPtr->stats.literalCount[TclLog2(length)]++;
  306. #endif /*TCL_COMPILE_STATS*/
  307.     return objIndex;
  308. }
  309. /*
  310.  *----------------------------------------------------------------------
  311.  *
  312.  * TclLookupLiteralEntry --
  313.  *
  314.  * Finds the LiteralEntry that corresponds to a literal Tcl object
  315.  *      holding a literal.
  316.  *
  317.  * Results:
  318.  *      Returns the matching LiteralEntry if found, otherwise NULL.
  319.  *
  320.  * Side effects:
  321.  *      None.
  322.  *
  323.  *----------------------------------------------------------------------
  324.  */
  325. LiteralEntry *
  326. TclLookupLiteralEntry(interp, objPtr)
  327.     Tcl_Interp *interp; /* Interpreter for which objPtr was created
  328.                                  * to hold a literal. */
  329.     register Tcl_Obj *objPtr; /* Points to a Tcl object holding a
  330.                                  * literal that was previously created by a
  331.                                  * call to TclRegisterLiteral. */
  332. {
  333.     Interp *iPtr = (Interp *) interp;
  334.     LiteralTable *globalTablePtr = &(iPtr->literalTable);
  335.     register LiteralEntry *entryPtr;
  336.     char *bytes;
  337.     int length, globalHash;
  338.     bytes = Tcl_GetStringFromObj(objPtr, &length);
  339.     globalHash = (HashString(bytes, length) & globalTablePtr->mask);
  340.     for (entryPtr = globalTablePtr->buckets[globalHash];
  341.             entryPtr != NULL;  entryPtr = entryPtr->nextPtr) {
  342.         if (entryPtr->objPtr == objPtr) {
  343.             return entryPtr;
  344.         }
  345.     }
  346.     return NULL;
  347. }
  348. /*
  349.  *----------------------------------------------------------------------
  350.  *
  351.  * TclHideLiteral --
  352.  *
  353.  * Remove a literal entry from the literal hash tables, leaving it in
  354.  * the literal array so existing references continue to function.
  355.  * This makes it possible to turn a shared literal into a private
  356.  * literal that cannot be shared.
  357.  *
  358.  * Results:
  359.  * None.
  360.  *
  361.  * Side effects:
  362.  * Removes the literal from the local hash table and decrements the
  363.  * global hash entry's reference count.
  364.  *
  365.  *----------------------------------------------------------------------
  366.  */
  367. void
  368. TclHideLiteral(interp, envPtr, index)
  369.     Tcl_Interp *interp;  /* Interpreter for which objPtr was created
  370.                                   * to hold a literal. */
  371.     register CompileEnv *envPtr; /* Points to CompileEnv whose literal array
  372.   * contains the entry being hidden. */
  373.     int index;  /* The index of the entry in the literal
  374.   * array. */
  375. {
  376.     LiteralEntry **nextPtrPtr, *entryPtr, *lPtr;
  377.     LiteralTable *localTablePtr = &(envPtr->localLitTable);
  378.     int localHash, length;
  379.     char *bytes;
  380.     Tcl_Obj *newObjPtr;
  381.     lPtr = &(envPtr->literalArrayPtr[index]);
  382.     /*
  383.      * To avoid unwanted sharing we need to copy the object and remove it from
  384.      * the local and global literal tables.  It still has a slot in the literal
  385.      * array so it can be referred to by byte codes, but it will not be matched
  386.      * by literal searches.
  387.      */
  388.     newObjPtr = Tcl_DuplicateObj(lPtr->objPtr);
  389.     Tcl_IncrRefCount(newObjPtr);
  390.     TclReleaseLiteral(interp, lPtr->objPtr);
  391.     lPtr->objPtr = newObjPtr;
  392.     bytes = Tcl_GetStringFromObj(newObjPtr, &length);
  393.     localHash = (HashString(bytes, length) & localTablePtr->mask);
  394.     nextPtrPtr = &localTablePtr->buckets[localHash];
  395.     for (entryPtr = *nextPtrPtr; entryPtr != NULL; entryPtr = *nextPtrPtr) {
  396. if (entryPtr == lPtr) {
  397.     *nextPtrPtr = lPtr->nextPtr;
  398.     lPtr->nextPtr = NULL;
  399.     localTablePtr->numEntries--;
  400.     break;
  401. }
  402. nextPtrPtr = &entryPtr->nextPtr;
  403.     }
  404. }
  405. /*
  406.  *----------------------------------------------------------------------
  407.  *
  408.  * TclAddLiteralObj --
  409.  *
  410.  * Add a single literal object to the literal array.  This
  411.  * function does not add the literal to the local or global
  412.  * literal tables.  The caller is expected to add the entry
  413.  * to whatever tables are appropriate.
  414.  *
  415.  * Results:
  416.  * The index in the CompileEnv's literal array that references the
  417.  * literal.  Stores the pointer to the new literal entry in the
  418.  * location referenced by the localPtrPtr argument.
  419.  *
  420.  * Side effects:
  421.  * Expands the literal array if necessary.  Increments the refcount
  422.  * on the literal object.
  423.  *
  424.  *----------------------------------------------------------------------
  425.  */
  426. int
  427. TclAddLiteralObj(envPtr, objPtr, litPtrPtr)
  428.     register CompileEnv *envPtr; /* Points to CompileEnv in whose literal
  429.   * array the object is to be inserted. */
  430.     Tcl_Obj *objPtr;  /* The object to insert into the array. */
  431.     LiteralEntry **litPtrPtr;  /* The location where the pointer to the
  432.   * new literal entry should be stored.
  433.   * May be NULL. */
  434. {
  435.     register LiteralEntry *lPtr;
  436.     int objIndex;
  437.     if (envPtr->literalArrayNext >= envPtr->literalArrayEnd) {
  438. ExpandLocalLiteralArray(envPtr);
  439.     }
  440.     objIndex = envPtr->literalArrayNext;
  441.     envPtr->literalArrayNext++;
  442.     lPtr = &(envPtr->literalArrayPtr[objIndex]);
  443.     lPtr->objPtr = objPtr;
  444.     Tcl_IncrRefCount(objPtr);
  445.     lPtr->refCount = -1; /* i.e., unused */
  446.     lPtr->nextPtr = NULL;
  447.     if (litPtrPtr) {
  448. *litPtrPtr = lPtr;
  449.     }
  450.     return objIndex;
  451. }
  452. /*
  453.  *----------------------------------------------------------------------
  454.  *
  455.  * AddLocalLiteralEntry --
  456.  *
  457.  * Insert a new literal into a CompileEnv's local literal array.
  458.  *
  459.  * Results:
  460.  * The index in the CompileEnv's literal array that references the
  461.  * literal.
  462.  *
  463.  * Side effects:
  464.  * Increments the ref count of the global LiteralEntry since the
  465.  * CompileEnv now refers to the literal. Expands the literal array
  466.  * if necessary. May rebuild the hash bucket array of the CompileEnv's
  467.  * literal array if it becomes too large.
  468.  *
  469.  *----------------------------------------------------------------------
  470.  */
  471. static int
  472. AddLocalLiteralEntry(envPtr, globalPtr, localHash)
  473.     register CompileEnv *envPtr; /* Points to CompileEnv in whose literal
  474.   * array the object is to be inserted. */
  475.     LiteralEntry *globalPtr;  /* Points to the global LiteralEntry for
  476.   * the literal to add to the CompileEnv. */
  477.     int localHash;  /* Hash value for the literal's string. */
  478. {
  479.     register LiteralTable *localTablePtr = &(envPtr->localLitTable);
  480.     LiteralEntry *localPtr;
  481.     int objIndex;
  482.     
  483.     objIndex = TclAddLiteralObj(envPtr, globalPtr->objPtr, &localPtr);
  484.     /*
  485.      * Add the literal to the local table.
  486.      */
  487.     localPtr->nextPtr = localTablePtr->buckets[localHash];
  488.     localTablePtr->buckets[localHash] = localPtr;
  489.     localTablePtr->numEntries++;
  490.     globalPtr->refCount++;
  491.     /*
  492.      * If the CompileEnv's local literal table has exceeded a decent size,
  493.      * rebuild it with more buckets.
  494.      */
  495.     if (localTablePtr->numEntries >= localTablePtr->rebuildSize) {
  496. RebuildLiteralTable(localTablePtr);
  497.     }
  498. #ifdef TCL_COMPILE_DEBUG
  499.     TclVerifyLocalLiteralTable(envPtr);
  500.     {
  501. char *bytes;
  502. int length, found, i;
  503. found = 0;
  504. for (i = 0;  i < localTablePtr->numBuckets;  i++) {
  505.     for (localPtr = localTablePtr->buckets[i];
  506.     localPtr != NULL;  localPtr = localPtr->nextPtr) {
  507. if (localPtr->objPtr == globalPtr->objPtr) {
  508.     found = 1;
  509. }
  510.     }
  511. }
  512. if (!found) {
  513.     bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length);
  514.     panic("AddLocalLiteralEntry: literal "%.*s" wasn't found locally",
  515.             (length>60? 60 : length), bytes);
  516. }
  517.     }
  518. #endif /*TCL_COMPILE_DEBUG*/
  519.     return objIndex;
  520. }
  521. /*
  522.  *----------------------------------------------------------------------
  523.  *
  524.  * ExpandLocalLiteralArray --
  525.  *
  526.  * Procedure that uses malloc to allocate more storage for a
  527.  * CompileEnv's local literal array.
  528.  *
  529.  * Results:
  530.  * None.
  531.  *
  532.  * Side effects:
  533.  * The literal array in *envPtr is reallocated to a new array of
  534.  * double the size, and if envPtr->mallocedLiteralArray is non-zero
  535.  * the old array is freed. Entries are copied from the old array
  536.  * to the new one. The local literal table is updated to refer to
  537.  * the new entries.
  538.  *
  539.  *----------------------------------------------------------------------
  540.  */
  541. static void
  542. ExpandLocalLiteralArray(envPtr)
  543.     register CompileEnv *envPtr; /* Points to the CompileEnv whose object
  544.   * array must be enlarged. */
  545. {
  546.     /*
  547.      * The current allocated local literal entries are stored between
  548.      * elements 0 and (envPtr->literalArrayNext - 1) [inclusive].
  549.      */
  550.     LiteralTable *localTablePtr = &(envPtr->localLitTable);
  551.     int currElems = envPtr->literalArrayNext;
  552.     size_t currBytes = (currElems * sizeof(LiteralEntry));
  553.     register LiteralEntry *currArrayPtr = envPtr->literalArrayPtr;
  554.     register LiteralEntry *newArrayPtr =
  555.     (LiteralEntry *) ckalloc((unsigned) (2 * currBytes));
  556.     int i;
  557.     
  558.     /*
  559.      * Copy from the old literal array to the new, then update the local
  560.      * literal table's bucket array.
  561.      */
  562.     memcpy((VOID *) newArrayPtr, (VOID *) currArrayPtr, currBytes);
  563.     for (i = 0;  i < currElems;  i++) {
  564. if (currArrayPtr[i].nextPtr == NULL) {
  565.     newArrayPtr[i].nextPtr = NULL;
  566. } else {
  567.     newArrayPtr[i].nextPtr = newArrayPtr
  568.     + (currArrayPtr[i].nextPtr - currArrayPtr);
  569. }
  570.     }
  571.     for (i = 0;  i < localTablePtr->numBuckets;  i++) {
  572. if (localTablePtr->buckets[i] != NULL) {
  573.     localTablePtr->buckets[i] = newArrayPtr
  574.             + (localTablePtr->buckets[i] - currArrayPtr);
  575. }
  576.     }
  577.     /*
  578.      * Free the old literal array if needed, and mark the new literal
  579.      * array as malloced.
  580.      */
  581.     
  582.     if (envPtr->mallocedLiteralArray) {
  583. ckfree((char *) currArrayPtr);
  584.     }
  585.     envPtr->literalArrayPtr = newArrayPtr;
  586.     envPtr->literalArrayEnd = (2 * currElems);
  587.     envPtr->mallocedLiteralArray = 1;
  588. }
  589. /*
  590.  *----------------------------------------------------------------------
  591.  *
  592.  * TclReleaseLiteral --
  593.  *
  594.  * This procedure releases a reference to one of the shared Tcl objects
  595.  * that hold literals. It is called to release the literals referenced
  596.  * by a ByteCode that is being destroyed, and it is also called by
  597.  * TclDeleteLiteralTable.
  598.  *
  599.  * Results:
  600.  * None.
  601.  *
  602.  * Side effects:
  603.  * The reference count for the global LiteralTable entry that 
  604.  * corresponds to the literal is decremented. If no other reference
  605.  * to a global literal object remains, it is freed.
  606.  *
  607.  *----------------------------------------------------------------------
  608.  */
  609. void
  610. TclReleaseLiteral(interp, objPtr)
  611.     Tcl_Interp *interp; /* Interpreter for which objPtr was created
  612.  * to hold a literal. */
  613.     register Tcl_Obj *objPtr; /* Points to a literal object that was
  614.  * previously created by a call to
  615.  * TclRegisterLiteral. */
  616. {
  617.     Interp *iPtr = (Interp *) interp;
  618.     LiteralTable *globalTablePtr = &(iPtr->literalTable);
  619.     register LiteralEntry *entryPtr, *prevPtr;
  620.     ByteCode* codePtr;
  621.     char *bytes;
  622.     int length, index;
  623.     bytes = Tcl_GetStringFromObj(objPtr, &length);
  624.     index = (HashString(bytes, length) & globalTablePtr->mask);
  625.     /*
  626.      * Check to see if the object is in the global literal table and 
  627.      * remove this reference.  The object may not be in the table if
  628.      * it is a hidden local literal.
  629.      */
  630.     for (prevPtr = NULL, entryPtr = globalTablePtr->buckets[index];
  631.     entryPtr != NULL;
  632.     prevPtr = entryPtr, entryPtr = entryPtr->nextPtr) {
  633. if (entryPtr->objPtr == objPtr) {
  634.     entryPtr->refCount--;
  635.     /*
  636.      * If the literal is no longer being used by any ByteCode,
  637.      * delete the entry then remove the reference corresponding 
  638.      * to the global literal table entry (decrement the ref count 
  639.      * of the object).
  640.      */
  641.     if (entryPtr->refCount == 0) {
  642. if (prevPtr == NULL) {
  643.     globalTablePtr->buckets[index] = entryPtr->nextPtr;
  644. } else {
  645.     prevPtr->nextPtr = entryPtr->nextPtr;
  646. }
  647. ckfree((char *) entryPtr);
  648. globalTablePtr->numEntries--;
  649. TclDecrRefCount(objPtr);
  650. /*
  651.  * Check if the LiteralEntry is only being kept alive by 
  652.  * a circular reference from a ByteCode stored as its 
  653.  * internal rep. In that case, set the ByteCode object array 
  654.  * entry NULL to signal to TclCleanupByteCode to not try to 
  655.  * release this about to be freed literal again.
  656.  */
  657.     
  658. if (objPtr->typePtr == &tclByteCodeType) {
  659.     codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
  660.     if ((codePtr->numLitObjects == 1)
  661.             && (codePtr->objArrayPtr[0] == objPtr)) {
  662. codePtr->objArrayPtr[0] = NULL;
  663.     }
  664. }
  665. #ifdef TCL_COMPILE_STATS
  666. iPtr->stats.currentLitStringBytes -= (double) (length + 1);
  667. #endif /*TCL_COMPILE_STATS*/
  668.     }
  669.     break;
  670. }
  671.     }
  672.     
  673.     /*
  674.      * Remove the reference corresponding to the local literal table
  675.      * entry.
  676.      */
  677.     Tcl_DecrRefCount(objPtr);
  678. }
  679. /*
  680.  *----------------------------------------------------------------------
  681.  *
  682.  * HashString --
  683.  *
  684.  * Compute a one-word summary of a text string, which can be
  685.  * used to generate a hash index.
  686.  *
  687.  * Results:
  688.  * The return value is a one-word summary of the information in
  689.  * string.
  690.  *
  691.  * Side effects:
  692.  * None.
  693.  *
  694.  *----------------------------------------------------------------------
  695.  */
  696. static unsigned int
  697. HashString(bytes, length)
  698.     register CONST char *bytes; /* String for which to compute hash
  699.  * value. */
  700.     int length; /* Number of bytes in the string. */
  701. {
  702.     register unsigned int result;
  703.     register int i;
  704.     /*
  705.      * I tried a zillion different hash functions and asked many other
  706.      * people for advice.  Many people had their own favorite functions,
  707.      * all different, but no-one had much idea why they were good ones.
  708.      * I chose the one below (multiply by 9 and add new character)
  709.      * because of the following reasons:
  710.      *
  711.      * 1. Multiplying by 10 is perfect for keys that are decimal strings,
  712.      *    and multiplying by 9 is just about as good.
  713.      * 2. Times-9 is (shift-left-3) plus (old).  This means that each
  714.      *    character's bits hang around in the low-order bits of the
  715.      *    hash value for ever, plus they spread fairly rapidly up to
  716.      *    the high-order bits to fill out the hash value.  This seems
  717.      *    works well both for decimal and non-decimal strings.
  718.      */
  719.     result = 0;
  720.     for (i = 0;  i < length;  i++) {
  721. result += (result<<3) + *bytes++;
  722.     }
  723.     return result;
  724. }
  725. /*
  726.  *----------------------------------------------------------------------
  727.  *
  728.  * RebuildLiteralTable --
  729.  *
  730.  * This procedure is invoked when the ratio of entries to hash buckets
  731.  * becomes too large in a local or global literal table. It allocates
  732.  * a larger bucket array and moves the entries into the new buckets.
  733.  *
  734.  * Results:
  735.  * None.
  736.  *
  737.  * Side effects:
  738.  * Memory gets reallocated and entries get rehashed into new buckets.
  739.  *
  740.  *----------------------------------------------------------------------
  741.  */
  742. static void
  743. RebuildLiteralTable(tablePtr)
  744.     register LiteralTable *tablePtr; /* Local or global table to enlarge. */
  745. {
  746.     LiteralEntry **oldBuckets;
  747.     register LiteralEntry **oldChainPtr, **newChainPtr;
  748.     register LiteralEntry *entryPtr;
  749.     LiteralEntry **bucketPtr;
  750.     char *bytes;
  751.     int oldSize, count, index, length;
  752.     oldSize = tablePtr->numBuckets;
  753.     oldBuckets = tablePtr->buckets;
  754.     /*
  755.      * Allocate and initialize the new bucket array, and set up
  756.      * hashing constants for new array size.
  757.      */
  758.     tablePtr->numBuckets *= 4;
  759.     tablePtr->buckets = (LiteralEntry **) ckalloc((unsigned)
  760.     (tablePtr->numBuckets * sizeof(LiteralEntry *)));
  761.     for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets;
  762.     count > 0;
  763.     count--, newChainPtr++) {
  764. *newChainPtr = NULL;
  765.     }
  766.     tablePtr->rebuildSize *= 4;
  767.     tablePtr->mask = (tablePtr->mask << 2) + 3;
  768.     /*
  769.      * Rehash all of the existing entries into the new bucket array.
  770.      */
  771.     for (oldChainPtr = oldBuckets;
  772.     oldSize > 0;
  773.     oldSize--, oldChainPtr++) {
  774. for (entryPtr = *oldChainPtr;  entryPtr != NULL;
  775.         entryPtr = *oldChainPtr) {
  776.     bytes = Tcl_GetStringFromObj(entryPtr->objPtr, &length);
  777.     index = (HashString(bytes, length) & tablePtr->mask);
  778.     
  779.     *oldChainPtr = entryPtr->nextPtr;
  780.     bucketPtr = &(tablePtr->buckets[index]);
  781.     entryPtr->nextPtr = *bucketPtr;
  782.     *bucketPtr = entryPtr;
  783. }
  784.     }
  785.     /*
  786.      * Free up the old bucket array, if it was dynamically allocated.
  787.      */
  788.     if (oldBuckets != tablePtr->staticBuckets) {
  789. ckfree((char *) oldBuckets);
  790.     }
  791. }
  792. #ifdef TCL_COMPILE_STATS
  793. /*
  794.  *----------------------------------------------------------------------
  795.  *
  796.  * TclLiteralStats --
  797.  *
  798.  * Return statistics describing the layout of the hash table
  799.  * in its hash buckets.
  800.  *
  801.  * Results:
  802.  * The return value is a malloc-ed string containing information
  803.  * about tablePtr.  It is the caller's responsibility to free
  804.  * this string.
  805.  *
  806.  * Side effects:
  807.  * None.
  808.  *
  809.  *----------------------------------------------------------------------
  810.  */
  811. char *
  812. TclLiteralStats(tablePtr)
  813.     LiteralTable *tablePtr; /* Table for which to produce stats. */
  814. {
  815. #define NUM_COUNTERS 10
  816.     int count[NUM_COUNTERS], overflow, i, j;
  817.     double average, tmp;
  818.     register LiteralEntry *entryPtr;
  819.     char *result, *p;
  820.     /*
  821.      * Compute a histogram of bucket usage. For each bucket chain i,
  822.      * j is the number of entries in the chain.
  823.      */
  824.     for (i = 0;  i < NUM_COUNTERS;  i++) {
  825. count[i] = 0;
  826.     }
  827.     overflow = 0;
  828.     average = 0.0;
  829.     for (i = 0;  i < tablePtr->numBuckets;  i++) {
  830. j = 0;
  831. for (entryPtr = tablePtr->buckets[i];  entryPtr != NULL;
  832.         entryPtr = entryPtr->nextPtr) {
  833.     j++;
  834. }
  835. if (j < NUM_COUNTERS) {
  836.     count[j]++;
  837. } else {
  838.     overflow++;
  839. }
  840. tmp = j;
  841. average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
  842.     }
  843.     /*
  844.      * Print out the histogram and a few other pieces of information.
  845.      */
  846.     result = (char *) ckalloc((unsigned) ((NUM_COUNTERS*60) + 300));
  847.     sprintf(result, "%d entries in table, %d bucketsn",
  848.     tablePtr->numEntries, tablePtr->numBuckets);
  849.     p = result + strlen(result);
  850.     for (i = 0; i < NUM_COUNTERS; i++) {
  851. sprintf(p, "number of buckets with %d entries: %dn",
  852. i, count[i]);
  853. p += strlen(p);
  854.     }
  855.     sprintf(p, "number of buckets with %d or more entries: %dn",
  856.     NUM_COUNTERS, overflow);
  857.     p += strlen(p);
  858.     sprintf(p, "average search distance for entry: %.1f", average);
  859.     return result;
  860. }
  861. #endif /*TCL_COMPILE_STATS*/
  862. #ifdef TCL_COMPILE_DEBUG
  863. /*
  864.  *----------------------------------------------------------------------
  865.  *
  866.  * TclVerifyLocalLiteralTable --
  867.  *
  868.  * Check a CompileEnv's local literal table for consistency.
  869.  *
  870.  * Results:
  871.  * None.
  872.  *
  873.  * Side effects:
  874.  * Panics if problems are found.
  875.  *
  876.  *----------------------------------------------------------------------
  877.  */
  878. void
  879. TclVerifyLocalLiteralTable(envPtr)
  880.     CompileEnv *envPtr; /* Points to CompileEnv whose literal
  881.  * table is to be validated. */
  882. {
  883.     register LiteralTable *localTablePtr = &(envPtr->localLitTable);
  884.     register LiteralEntry *localPtr;
  885.     char *bytes;
  886.     register int i;
  887.     int length, count;
  888.     count = 0;
  889.     for (i = 0;  i < localTablePtr->numBuckets;  i++) {
  890. for (localPtr = localTablePtr->buckets[i];
  891.         localPtr != NULL;  localPtr = localPtr->nextPtr) {
  892.     count++;
  893.     if (localPtr->refCount != -1) {
  894. bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
  895. panic("TclVerifyLocalLiteralTable: local literal "%.*s" had bad refCount %d",
  896.         (length>60? 60 : length), bytes,
  897.         localPtr->refCount);
  898.     }
  899.     if (TclLookupLiteralEntry((Tcl_Interp *) envPtr->iPtr,
  900.     localPtr->objPtr) == NULL) {
  901. bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
  902. panic("TclVerifyLocalLiteralTable: local literal "%.*s" is not global",
  903.          (length>60? 60 : length), bytes);
  904.     }
  905.     if (localPtr->objPtr->bytes == NULL) {
  906. panic("TclVerifyLocalLiteralTable: literal has NULL string rep");
  907.     }
  908. }
  909.     }
  910.     if (count != localTablePtr->numEntries) {
  911. panic("TclVerifyLocalLiteralTable: local literal table had %d entries, should be %d",
  912.       count, localTablePtr->numEntries);
  913.     }
  914. }
  915. /*
  916.  *----------------------------------------------------------------------
  917.  *
  918.  * TclVerifyGlobalLiteralTable --
  919.  *
  920.  * Check an interpreter's global literal table literal for consistency.
  921.  *
  922.  * Results:
  923.  * None.
  924.  *
  925.  * Side effects:
  926.  * Panics if problems are found.
  927.  *
  928.  *----------------------------------------------------------------------
  929.  */
  930. void
  931. TclVerifyGlobalLiteralTable(iPtr)
  932.     Interp *iPtr; /* Points to interpreter whose global
  933.  * literal table is to be validated. */
  934. {
  935.     register LiteralTable *globalTablePtr = &(iPtr->literalTable);
  936.     register LiteralEntry *globalPtr;
  937.     char *bytes;
  938.     register int i;
  939.     int length, count;
  940.     count = 0;
  941.     for (i = 0;  i < globalTablePtr->numBuckets;  i++) {
  942. for (globalPtr = globalTablePtr->buckets[i];
  943.         globalPtr != NULL;  globalPtr = globalPtr->nextPtr) {
  944.     count++;
  945.     if (globalPtr->refCount < 1) {
  946. bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length);
  947. panic("TclVerifyGlobalLiteralTable: global literal "%.*s" had bad refCount %d",
  948.         (length>60? 60 : length), bytes,
  949.         globalPtr->refCount);
  950.     }
  951.     if (globalPtr->objPtr->bytes == NULL) {
  952. panic("TclVerifyGlobalLiteralTable: literal has NULL string rep");
  953.     }
  954. }
  955.     }
  956.     if (count != globalTablePtr->numEntries) {
  957. panic("TclVerifyGlobalLiteralTable: global literal table had %d entries, should be %d",
  958.       count, globalTablePtr->numEntries);
  959.     }
  960. }
  961. #endif /*TCL_COMPILE_DEBUG*/