Several optimizations and speed improvements.
cstubs: Use Matrix type instead of float[4][4].
diff --git a/Include/stringobject.h b/Include/stringobject.h
index a4b4ea6..fa2e8a1 100644
--- a/Include/stringobject.h
+++ b/Include/stringobject.h
@@ -51,6 +51,9 @@
 
 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 d8f2d90..7e99a82 100644
--- a/Modules/cstubs
+++ b/Modules/cstubs
@@ -529,21 +529,21 @@
 	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 @@
 	object *self;
 	object *args;
 {
-	float arg1 [ 4 ] [ 4 ] ;
+	Matrix arg1;
 	object *v, *w;
 	int i, j;
 	getmatrix( arg1 );
@@ -742,7 +742,7 @@
 	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 6686abf..3a941a8 100644
--- a/Modules/stropmodule.c
+++ b/Modules/stropmodule.c
@@ -254,24 +254,26 @@
 	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 @@
 	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 @@
 	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 6a8981e..b2cd4ad 100644
--- a/Objects/accessobject.c
+++ b/Objects/accessobject.c
@@ -232,10 +232,11 @@
 	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 c0eb8f1..6008999 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -355,13 +355,15 @@
 {
 	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 527b062..2a51d51 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -242,6 +242,9 @@
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 	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 527b062..2a51d51 100644
--- a/Objects/mappingobject.c
+++ b/Objects/mappingobject.c
@@ -242,6 +242,9 @@
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 	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 bc0aeed..f2d801b 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -38,6 +38,7 @@
 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 @@
 	       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 a3043d4..f66a82c 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -26,21 +26,76 @@
 
 #include "allobjects.h"
 
+#ifdef COUNT_ALLOCS
+int null_strings, one_strings;
+#endif
+
+#ifdef __STDC__
+#include <limits.h>
+#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 @@
 	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 @@
 		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 @@
 		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 @@
 	return newsizedstringobject(a->ob_sval + i, (int) (j-i));
 }
 
-#ifdef __STDC__
-#include <limits.h>
-#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 @@
 		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 @@
 {
 	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 @@
 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 071d664..329494e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -821,7 +821,7 @@
 				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 @@
 				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 @@
 					err_clear();
 					x = getbuiltin(w);
 					if (x == NULL) {
-						err_setstr(NameError,
-							getstringvalue(w));
+						err_setval(NameError, w);
 						break;
 					}
 				}
@@ -1073,8 +1072,7 @@
 				err_clear();
 				x = getbuiltin(w);
 				if (x == NULL) {
-					err_setstr(NameError,
-						getstringvalue(w));
+					err_setval(NameError, w);
 					break;
 				}
 			}
@@ -1092,7 +1090,7 @@
 			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)) {