diff --git a/Include/stringobject.h b/Include/stringobject.h index a4b4ea65410..fa2e8a133db 100644 --- a/Include/stringobject.h +++ b/Include/stringobject.h @@ -51,6 +51,9 @@ functions should be applied to nil objects. typedef struct { OB_VARHEAD +#ifdef CACHE_HASH + long ob_shash; +#endif char ob_sval[1]; } stringobject; diff --git a/Modules/cstubs b/Modules/cstubs index d8f2d90c1bf..7e99a82790c 100644 --- a/Modules/cstubs +++ b/Modules/cstubs @@ -529,21 +529,21 @@ gl_getmatrix(self, args) object *self; object *args; { - float arg1 [ 16 ] ; + Matrix arg1; object *v, *w; - int i; + int i, j; getmatrix( arg1 ); v = newlistobject(16); if (v == NULL) { return err_nomem(); } - for (i = 0; i < 16; i++) { - w = mknewfloatobject(arg1[i]); + for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) { + w = mknewfloatobject(arg1[i][j]); if (w == NULL) { DECREF(v); return NULL; } - setlistitem(v, i, w); + setlistitem(v, i*4+j, w); } return v; } @@ -559,7 +559,7 @@ gl_altgetmatrix(self, args) object *self; object *args; { - float arg1 [ 4 ] [ 4 ] ; + Matrix arg1; object *v, *w; int i, j; getmatrix( arg1 ); @@ -742,7 +742,7 @@ gl_packrect(self, args) if (packed == NULL) return NULL; parray = (unsigned long *) getstringvalue(unpacked); - p = getstringvalue(packed); + p = (unsigned char *) getstringvalue(packed); for (y = 0; y < height; y += packfactor, parray += packfactor*width) { for (x = 0; x < width; x += packfactor) { pixel = parray[x]; diff --git a/Modules/stropmodule.c b/Modules/stropmodule.c index 6686abf58f1..3a941a8daf1 100644 --- a/Modules/stropmodule.c +++ b/Modules/stropmodule.c @@ -254,24 +254,26 @@ strop_lower(self, args) object *self; /* Not used */ object *args; { - char *s; + char *s, *s_new; int i, n; object *new; int changed; if (!getargs(args, "s#", &s, &n)) return NULL; - new = newsizedstringobject(s, n); + new = newsizedstringobject(NULL, n); if (new == NULL) return NULL; - s = getstringvalue(new); + s_new = getstringvalue(new); changed = 0; for (i = 0; i < n; i++) { - char c = s[i]; + char c = *s++; if (isupper(c)) { changed = 1; - s[i] = tolower(c); - } + *s_new = tolower(c); + } else + *s_new = c; + s_new++; } if (!changed) { DECREF(new); @@ -287,24 +289,26 @@ strop_upper(self, args) object *self; /* Not used */ object *args; { - char *s; + char *s, *s_new; int i, n; object *new; int changed; if (!getargs(args, "s#", &s, &n)) return NULL; - new = newsizedstringobject(s, n); + new = newsizedstringobject(NULL, n); if (new == NULL) return NULL; - s = getstringvalue(new); + s_new = getstringvalue(new); changed = 0; for (i = 0; i < n; i++) { - char c = s[i]; + char c = *s++; if (islower(c)) { changed = 1; - s[i] = toupper(c); - } + *s_new = toupper(c); + } else + *s_new = c; + s_new++; } if (!changed) { DECREF(new); @@ -320,28 +324,31 @@ strop_swapcase(self, args) object *self; /* Not used */ object *args; { - char *s; + char *s, *s_new; int i, n; object *new; int changed; if (!getargs(args, "s#", &s, &n)) return NULL; - new = newsizedstringobject(s, n); + new = newsizedstringobject(NULL, n); if (new == NULL) return NULL; - s = getstringvalue(new); + s_new = getstringvalue(new); changed = 0; for (i = 0; i < n; i++) { - char c = s[i]; + char c = *s++; if (islower(c)) { changed = 1; - s[i] = toupper(c); + *s_new = toupper(c); } else if (isupper(c)) { changed = 1; - s[i] = tolower(c); + *s_new = tolower(c); } + else + *s_new = c; + s_new++; } if (!changed) { DECREF(new); diff --git a/Objects/accessobject.c b/Objects/accessobject.c index 6a8981e1ae0..b2cd4ad0dc5 100644 --- a/Objects/accessobject.c +++ b/Objects/accessobject.c @@ -232,10 +232,11 @@ isprivileged(caller) object *caller; { object *g; - if (caller != NULL && hasattr(caller, "__privileged__")) + static char privileged[] = "__privileged__"; + if (caller != NULL && hasattr(caller, privileged)) return 1; g = getglobals(); - if (g != NULL && dictlookup(g, "__privileged__")) + if (g != NULL && dictlookup(g, privileged)) return 1; return 0; } diff --git a/Objects/classobject.c b/Objects/classobject.c index c0eb8f1e1b0..60089995df6 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -355,13 +355,15 @@ instance_getattr(inst, name) { register object *v; classobject *class; - if (strcmp(name, "__dict__") == 0) { - INCREF(inst->in_dict); - return inst->in_dict; - } - if (strcmp(name, "__class__") == 0) { - INCREF(inst->in_class); - return (object *)inst->in_class; + if (name[0] == '_' && name[1] == '_') { + if (strcmp(name, "__dict__") == 0) { + INCREF(inst->in_dict); + return inst->in_dict; + } + if (strcmp(name, "__class__") == 0) { + INCREF(inst->in_class); + return (object *)inst->in_class; + } } class = NULL; v = dictlookup(inst->in_dict, name); diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 527b062467e..2a51d51dae2 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -242,6 +242,9 @@ mappinglookup(op, key) err_badcall(); return NULL; } +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif hash = hashobject(key); if (hash == -1) return NULL; @@ -260,6 +263,9 @@ mappinginsert(op, key, value) err_badcall(); return -1; } +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif hash = hashobject(key); if (hash == -1) return -1; @@ -289,6 +295,9 @@ mappingremove(op, key) err_badcall(); return -1; } +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif hash = hashobject(key); if (hash == -1) return -1; @@ -447,7 +456,11 @@ mapping_subscript(mp, key) register object *key; { object *v; - long hash = hashobject(key); + long hash; +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif + hash = hashobject(key); if (hash == -1) return NULL; v = lookmapping(mp, key, hash) -> me_value; @@ -628,9 +641,15 @@ mapping_compare(a, b) res = cmpobject(akey, bkey); if (res != 0) break; +#ifdef CACHE_HASH + if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1) +#endif ahash = hashobject(akey); if (ahash == -1) err_clear(); /* Don't want errors here */ +#ifdef CACHE_HASH + if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1) +#endif bhash = hashobject(bkey); if (bhash == -1) err_clear(); /* Don't want errors here */ @@ -661,6 +680,9 @@ mapping_has_key(mp, args) register long ok; if (!getargs(args, "O", &key)) return NULL; +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif hash = hashobject(key); if (hash == -1) return NULL; diff --git a/Objects/mappingobject.c b/Objects/mappingobject.c index 527b062467e..2a51d51dae2 100644 --- a/Objects/mappingobject.c +++ b/Objects/mappingobject.c @@ -242,6 +242,9 @@ mappinglookup(op, key) err_badcall(); return NULL; } +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif hash = hashobject(key); if (hash == -1) return NULL; @@ -260,6 +263,9 @@ mappinginsert(op, key, value) err_badcall(); return -1; } +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif hash = hashobject(key); if (hash == -1) return -1; @@ -289,6 +295,9 @@ mappingremove(op, key) err_badcall(); return -1; } +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif hash = hashobject(key); if (hash == -1) return -1; @@ -447,7 +456,11 @@ mapping_subscript(mp, key) register object *key; { object *v; - long hash = hashobject(key); + long hash; +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif + hash = hashobject(key); if (hash == -1) return NULL; v = lookmapping(mp, key, hash) -> me_value; @@ -628,9 +641,15 @@ mapping_compare(a, b) res = cmpobject(akey, bkey); if (res != 0) break; +#ifdef CACHE_HASH + if (!is_stringobject(akey) || (ahash = ((stringobject *) akey)->ob_shash) == -1) +#endif ahash = hashobject(akey); if (ahash == -1) err_clear(); /* Don't want errors here */ +#ifdef CACHE_HASH + if (!is_stringobject(bkey) || (bhash = ((stringobject *) bkey)->ob_shash) == -1) +#endif bhash = hashobject(bkey); if (bhash == -1) err_clear(); /* Don't want errors here */ @@ -661,6 +680,9 @@ mapping_has_key(mp, args) register long ok; if (!getargs(args, "O", &key)) return NULL; +#ifdef CACHE_HASH + if (!is_stringobject(key) || (hash = ((stringobject *) key)->ob_shash) == -1) +#endif hash = hashobject(key); if (hash == -1) return NULL; diff --git a/Objects/object.c b/Objects/object.c index bc0aeed2958..f2d801bb658 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -38,6 +38,7 @@ long ref_total; static typeobject *type_list; extern int tuple_zero_allocs, fast_tuple_allocs; extern int quick_int_allocs, quick_neg_int_allocs; +extern int null_strings, one_strings; void dump_counts() { @@ -51,6 +52,7 @@ dump_counts() tuple_zero_allocs); printf("fast int allocs: pos: %d, neg: %d\n", quick_int_allocs, quick_neg_int_allocs); + printf("null strings: %d, 1-strings: %d\n", null_strings, one_strings); } void diff --git a/Objects/stringobject.c b/Objects/stringobject.c index a3043d49f43..f66a82ccb89 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -26,21 +26,76 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "allobjects.h" +#ifdef COUNT_ALLOCS +int null_strings, one_strings; +#endif + +#ifdef __STDC__ +#include +#else +#ifndef UCHAR_MAX +#define UCHAR_MAX 255 +#endif +#endif + +static stringobject *characters[UCHAR_MAX + 1]; +static stringobject *nullstring; + +/* + Newsizedstringobject() and newstringobject() try in certain cases + to share string objects. When the size of the string is zero, + these routines always return a pointer to the same string object; + when the size is one, they return a pointer to an already existing + object if the contents of the string is known. For + newstringobject() this is always the case, for + newsizedstringobject() this is the case when the first argument in + not NULL. + A common practice to allocate a string and then fill it in or + change it must be done carefully. It is only allowed to change the + contents of the string if the obect was gotten from + newsizedstringobject() with a NULL first argument, because in the + future these routines may try to do even more sharing of objects. +*/ object * newsizedstringobject(str, size) char *str; int size; { - register stringobject *op = (stringobject *) + register stringobject *op; + if (size == 0 && (op = nullstring) != NULL) { +#ifdef COUNT_ALLOCS + null_strings++; +#endif + INCREF(op); + return op; + } + if (size == 1 && str != NULL && (op = characters[*str & UCHAR_MAX]) != NULL) { +#ifdef COUNT_ALLOCS + one_strings++; +#endif + INCREF(op); + return op; + } + op = (stringobject *) malloc(sizeof(stringobject) + size * sizeof(char)); if (op == NULL) return err_nomem(); op->ob_type = &Stringtype; op->ob_size = size; +#ifdef CACHE_HASH + op->ob_shash = -1; +#endif NEWREF(op); if (str != NULL) memcpy(op->ob_sval, str, size); op->ob_sval[size] = '\0'; + if (size == 0) { + nullstring = op; + INCREF(op); + } else if (size == 1 && str != NULL) { + characters[*str & UCHAR_MAX] = op; + INCREF(op); + } return (object *) op; } @@ -49,14 +104,39 @@ newstringobject(str) char *str; { register unsigned int size = strlen(str); - register stringobject *op = (stringobject *) + register stringobject *op; + if (size == 0 && (op = nullstring) != NULL) { +#ifdef COUNT_ALLOCS + null_strings++; +#endif + INCREF(op); + return op; + } + if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) { +#ifdef COUNT_ALLOCS + one_strings++; +#endif + INCREF(op); + return op; + } + op = (stringobject *) malloc(sizeof(stringobject) + size * sizeof(char)); if (op == NULL) return err_nomem(); op->ob_type = &Stringtype; op->ob_size = size; +#ifdef CACHE_HASH + op->ob_shash = -1; +#endif NEWREF(op); strcpy(op->ob_sval, str); + if (size == 0) { + nullstring = op; + INCREF(op); + } else if (size == 1) { + characters[*str & UCHAR_MAX] = op; + INCREF(op); + } return (object *) op; } @@ -189,6 +269,9 @@ string_concat(a, bb) return err_nomem(); op->ob_type = &Stringtype; op->ob_size = size; +#ifdef CACHE_HASH + op->ob_shash = -1; +#endif NEWREF(op); memcpy(op->ob_sval, a->ob_sval, (int) a->ob_size); memcpy(op->ob_sval + a->ob_size, b->ob_sval, (int) b->ob_size); @@ -218,6 +301,9 @@ string_repeat(a, n) return err_nomem(); op->ob_type = &Stringtype; op->ob_size = size; +#ifdef CACHE_HASH + op->ob_shash = -1; +#endif NEWREF(op); for (i = 0; i < size; i += a->ob_size) memcpy(op->ob_sval+i, a->ob_sval, (int) a->ob_size); @@ -247,16 +333,6 @@ string_slice(a, i, j) return newsizedstringobject(a->ob_sval + i, (int) (j-i)); } -#ifdef __STDC__ -#include -#else -#ifndef UCHAR_MAX -#define UCHAR_MAX 255 -#endif -#endif - -static object *characters[UCHAR_MAX + 1]; - static object * string_item(a, i) stringobject *a; @@ -269,12 +345,16 @@ string_item(a, i) return NULL; } c = a->ob_sval[i] & UCHAR_MAX; - v = characters[c]; + v = (object *) characters[c]; +#ifdef COUNT_ALLOCS + if (v != NULL) + one_strings++; +#endif if (v == NULL) { v = newsizedstringobject((char *)NULL, 1); if (v == NULL) return NULL; - characters[c] = v; + characters[c] = (stringobject *) v; ((stringobject *)v)->ob_sval[0] = c; } INCREF(v); @@ -287,9 +367,14 @@ string_compare(a, b) { int len_a = a->ob_size, len_b = b->ob_size; int min_len = (len_a < len_b) ? len_a : len_b; - int cmp = memcmp(a->ob_sval, b->ob_sval, min_len); - if (cmp != 0) - return cmp; + int cmp; + if (min_len > 0) { + cmp = *a->ob_sval - *b->ob_sval; + if (cmp == 0) + cmp = memcmp(a->ob_sval, b->ob_sval, min_len); + if (cmp != 0) + return cmp; + } return (len_a < len_b) ? -1 : (len_a > len_b) ? 1 : 0; } @@ -297,14 +382,25 @@ static long string_hash(a) stringobject *a; { - register int len = a->ob_size; - register unsigned char *p = (unsigned char *) a->ob_sval; - register long x = *p << 7; + register int len; + register unsigned char *p; + register long x; + +#ifdef CACHE_HASH + if (a->ob_shash != -1) + return a->ob_shash; +#endif + len = a->ob_size; + p = (unsigned char *) a->ob_sval; + x = *p << 7; while (--len >= 0) x = (x + x + x) ^ *p++; x ^= a->ob_size; if (x == -1) x = -2; +#ifdef CACHE_HASH + a->ob_shash = x; +#endif return x; } diff --git a/Python/ceval.c b/Python/ceval.c index 071d664d547..329494e7c4a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -821,7 +821,7 @@ eval_code(co, globals, locals, owner, arg) break; } if ((err = dict2remove(f->f_locals, w)) != 0) - err_setstr(NameError, getstringvalue(w)); + err_setval(NameError, w); break; #ifdef CASE_TOO_BIG @@ -1031,7 +1031,7 @@ eval_code(co, globals, locals, owner, arg) break; } if ((err = dict2remove(f->f_globals, w)) != 0) - err_setstr(NameError, getstringvalue(w)); + err_setval(NameError, w); break; case LOAD_CONST: @@ -1050,8 +1050,7 @@ eval_code(co, globals, locals, owner, arg) err_clear(); x = getbuiltin(w); if (x == NULL) { - err_setstr(NameError, - getstringvalue(w)); + err_setval(NameError, w); break; } } @@ -1073,8 +1072,7 @@ eval_code(co, globals, locals, owner, arg) err_clear(); x = getbuiltin(w); if (x == NULL) { - err_setstr(NameError, - getstringvalue(w)); + err_setval(NameError, w); break; } } @@ -1092,7 +1090,7 @@ eval_code(co, globals, locals, owner, arg) w = GETNAMEV(oparg); x = dict2lookup(f->f_locals, w); if (x == NULL) { - err_setstr(NameError, getstringvalue(w)); + err_setval(NameError, w); break; } if (is_accessobject(x)) {