From d57677488f057b142552a7611ebd5dd23e0cf359 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 12 Apr 2024 21:13:23 +0000 Subject: amend to [295b0570ff660950]: the bug was fixed incompletely, this is full bug fix now - don't allow direct compare if keys contain values rather than pointers. introduced new hash-key type flag TCL_HASH_KEY_DIRECT_COMPARE... I know it is public interface, but the bug is grave, and I don't know how one could fix it without that, by retaining same performance for pointer hashes (e. g. vars, dicts and all of TclObjs). --- generic/tcl.h | 8 ++++++++ generic/tclDictObj.c | 2 +- generic/tclHash.c | 49 ++++++++++++++++++++++++++++++++++--------------- generic/tclObj.c | 2 +- generic/tclVar.c | 2 +- 5 files changed, 45 insertions(+), 18 deletions(-) diff --git a/generic/tcl.h b/generic/tcl.h index d71a333..ff7d0d7 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -1162,10 +1162,18 @@ struct Tcl_HashEntry { * TCL_HASH_KEY_SYSTEM_HASH - If this flag is set then all memory internally * allocated for the hash table that is not for an * entry will use the system heap. + * TCL_HASH_KEY_DIRECT_COMPARE - + * Allows fast comparison for hash keys directly + * by compare of their key.oneWordValue values, + * before call of compareKeysProc (much slower + * than a direct compare, so it is speed-up only + * flag). Don't use it if keys contain values rather + * than pointers. */ #define TCL_HASH_KEY_RANDOMIZE_HASH 0x1 #define TCL_HASH_KEY_SYSTEM_HASH 0x2 +#define TCL_HASH_KEY_DIRECT_COMPARE 0x4 /* * Structure definition for the methods associated with a hash table key type. diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index bde8162..3a02bbd 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -168,7 +168,7 @@ Tcl_ObjType tclDictType = { static Tcl_HashKeyType chainHashType = { TCL_HASH_KEY_TYPE_VERSION, - 0, + TCL_HASH_KEY_DIRECT_COMPARE, /* allows compare keys by pointers */ TclHashObjKey, TclCompareObjKeys, AllocChainEntry, diff --git a/generic/tclHash.c b/generic/tclHash.c index 02a16a0..40a855b 100644 --- a/generic/tclHash.c +++ b/generic/tclHash.c @@ -317,23 +317,42 @@ CreateHashEntry( if (typePtr->compareKeysProc) { Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc; - for (hPtr = tablePtr->buckets[index]; hPtr != NULL; - hPtr = hPtr->nextPtr) { + + if (typePtr->flags & TCL_HASH_KEY_DIRECT_COMPARE) { + for (hPtr = tablePtr->buckets[index]; hPtr != NULL; + hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH - if (hash != PTR2UINT(hPtr->hash)) { - continue; - } + if (hash != PTR2UINT(hPtr->hash)) { + continue; + } #endif - /* if keys pointers or values are equal */ - if ((key == hPtr->key.oneWordValue) - || compareKeysProc((VOID *) key, hPtr) - ) { - if (newPtr) { - *newPtr = 0; - } - return hPtr; - } - } + /* if keys pointers or values are equal */ + if ((key == hPtr->key.oneWordValue) + || compareKeysProc((VOID *) key, hPtr) + ) { + if (newPtr) { + *newPtr = 0; + } + return hPtr; + } + } + } else { + for (hPtr = tablePtr->buckets[index]; hPtr != NULL; + hPtr = hPtr->nextPtr) { +#if TCL_HASH_KEY_STORE_HASH + if (hash != PTR2UINT(hPtr->hash)) { + continue; + } +#endif + /* if keys pointers or values are equal */ + if (compareKeysProc((VOID *) key, hPtr)) { + if (newPtr) { + *newPtr = 0; + } + return hPtr; + } + } + } } else { for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { diff --git a/generic/tclObj.c b/generic/tclObj.c index 6bff71c..f5bd137 100644 --- a/generic/tclObj.c +++ b/generic/tclObj.c @@ -297,7 +297,7 @@ Tcl_ObjType tclBignumType = { Tcl_HashKeyType tclObjHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ - 0, /* flags */ + TCL_HASH_KEY_DIRECT_COMPARE,/* allows compare keys by pointers */ TclHashObjKey, /* hashKeyProc */ TclCompareObjKeys, /* compareKeysProc */ AllocObjEntry, /* allocEntryProc */ diff --git a/generic/tclVar.c b/generic/tclVar.c index d4e5339..baac5da 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -30,7 +30,7 @@ static unsigned int HashVarKey(Tcl_HashTable *tablePtr, void *keyPtr); static Tcl_HashKeyType tclVarHashKeyType = { TCL_HASH_KEY_TYPE_VERSION, /* version */ - 0, /* flags */ + TCL_HASH_KEY_DIRECT_COMPARE,/* allows compare keys by pointers */ HashVarKey, /* hashKeyProc */ CompareVarKeys, /* compareKeysProc */ AllocVarEntry, /* allocEntryProc */ -- cgit v0.12 From 42dcfe9f62c31bcf0543c3c1b3316fc28543f6e9 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 12 Apr 2024 21:40:07 +0000 Subject: Add missing documentation for TIP 598 Tcl_WinConvertError --- doc/SetErrno.3 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/SetErrno.3 b/doc/SetErrno.3 index c202e2e..84d7553 100644 --- a/doc/SetErrno.3 +++ b/doc/SetErrno.3 @@ -8,7 +8,7 @@ .so man.macros .BS .SH NAME -Tcl_SetErrno, Tcl_GetErrno, Tcl_ErrnoId, Tcl_ErrnoMsg \- manipulate errno to store and retrieve error codes +Tcl_SetErrno, Tcl_GetErrno, Tcl_ErrnoId, Tcl_ErrnoMsg, Tcl_WinConvertError \- manipulate errno to store and retrieve error codes .SH SYNOPSIS .nf \fB#include \fR @@ -25,10 +25,16 @@ const char * const char * \fBTcl_ErrnoMsg\fR(\fIerrorCode\fR) .sp +void +\fBTcl_WinConvertError\fR(\fIwinErrorCode\fR) +.fi .SH ARGUMENTS .AS int errorCode .AP int errorCode in A POSIX error code such as \fBENOENT\fR. +.AS unsigned int winErrorCode in +.AP DWORD winErrorCode in +A Windows or Winsock error code such as \fBERROR_FILE_NOT_FOUND\fR. .BE .SH DESCRIPTION @@ -61,6 +67,9 @@ that corresponds to the value of its typically the value returned by \fBTcl_GetErrno\fR. The strings returned by these functions are statically allocated and the caller must not free or modify them. +.PP +\fBTcl_WinConvertError\fR (Windows only) maps the passed Windows or Winsock +error code to a POSIX error and stores it in \fBerrno\fR. .SH KEYWORDS errno, error code, global variables -- cgit v0.12 From 05fad8df8972def0af73c6f528308220660ba67b Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 12 Apr 2024 22:55:14 +0000 Subject: minor backport from my core: simple speed-up if searching for the key from hash itself (it is safe to compare needle with an address to key.string); back to mixed identation (removed before) --- generic/tclHash.c | 62 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/generic/tclHash.c b/generic/tclHash.c index 40a855b..4c204a2 100644 --- a/generic/tclHash.c +++ b/generic/tclHash.c @@ -319,40 +319,42 @@ CreateHashEntry( Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc; if (typePtr->flags & TCL_HASH_KEY_DIRECT_COMPARE) { - for (hPtr = tablePtr->buckets[index]; hPtr != NULL; - hPtr = hPtr->nextPtr) { + for (hPtr = tablePtr->buckets[index]; hPtr != NULL; + hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH - if (hash != PTR2UINT(hPtr->hash)) { - continue; - } + if (hash != PTR2UINT(hPtr->hash)) { + continue; + } #endif - /* if keys pointers or values are equal */ - if ((key == hPtr->key.oneWordValue) - || compareKeysProc((VOID *) key, hPtr) - ) { - if (newPtr) { - *newPtr = 0; - } - return hPtr; - } - } - } else { - for (hPtr = tablePtr->buckets[index]; hPtr != NULL; - hPtr = hPtr->nextPtr) { + /* if keys pointers or values are equal */ + if ((key == hPtr->key.oneWordValue) + || compareKeysProc((VOID *) key, hPtr) + ) { + if (newPtr) { + *newPtr = 0; + } + return hPtr; + } + } + } else { + for (hPtr = tablePtr->buckets[index]; hPtr != NULL; + hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH - if (hash != PTR2UINT(hPtr->hash)) { - continue; - } + if (hash != PTR2UINT(hPtr->hash)) { + continue; + } #endif - /* if keys pointers or values are equal */ - if (compareKeysProc((VOID *) key, hPtr)) { - if (newPtr) { - *newPtr = 0; - } - return hPtr; - } - } - } + /* if needle pointer equals content pointer or values equal */ + if ((key == hPtr->key.string) + || compareKeysProc((VOID *) key, hPtr) + ) { + if (newPtr) { + *newPtr = 0; + } + return hPtr; + } + } + } } else { for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { -- cgit v0.12 From ae0d35c2744747f5e538c9aa52e21289b7eccfc1 Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 12 Apr 2024 23:02:15 +0000 Subject: explaination comment --- generic/tclHash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclHash.c b/generic/tclHash.c index 189748c..45af73e 100644 --- a/generic/tclHash.c +++ b/generic/tclHash.c @@ -336,7 +336,7 @@ CreateHashEntry( return hPtr; } } - } else { /* no direct compare */ + } else { /* no direct compare - compare key addresses only */ for (hPtr = tablePtr->buckets[index]; hPtr != NULL; hPtr = hPtr->nextPtr) { #if TCL_HASH_KEY_STORE_HASH -- cgit v0.12