keyword arguments and faster calls
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 5103622..0be0373 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -80,15 +80,20 @@
 	object *self;
 	object *args;
 {
-	object *func, *alist;
+	object *func, *alist, *kwdict = NULL;
 
-	if (!newgetargs(args, "OO:apply", &func, &alist))
+	if (!newgetargs(args, "O|OO:apply", &func, &alist, &kwdict))
 		return NULL;
-	if (!is_tupleobject(alist)) {
+	if (alist != NULL && !is_tupleobject(alist)) {
 		err_setstr(TypeError, "apply() 2nd argument must be tuple");
 		return NULL;
 	}
-	return call_object(func, alist);
+	if (kwdict != NULL && !is_dictobject(kwdict)) {
+		err_setstr(TypeError,
+			   "apply() 3rd argument must be dictionary");
+		return NULL;
+	}
+	return PyEval_CallObjectWithKeywords(func, alist, kwdict);
 }
 
 static object *
@@ -373,8 +378,7 @@
 			return NULL;
 	}
 	if (is_codeobject(cmd))
-		return eval_code((codeobject *) cmd, globals, locals,
-				 (object *)NULL, (object *)NULL);
+		return eval_code((codeobject *) cmd, globals, locals);
 	if (!is_stringobject(cmd)) {
 		err_setstr(TypeError,
 			   "eval() argument 1 must be string or code object");
diff --git a/Python/ceval.c b/Python/ceval.c
index a55451c..2b501c79 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -24,6 +24,16 @@
 
 /* Execute compiled code */
 
+/* XXX TO DO:
+   XXX how to pass arguments to call_trace?
+   XXX access stuff can probably dereference NULL locals?
+   XXX need to extend apply() to be able to pass keyword args
+   XXX need to be able to call built-in functions with keyword args
+   XXX speed up searching for keywords by using a dictionary
+   XXX unknown keyword shouldn't raise KeyError?
+   XXX document it!
+   */
+
 #include "allobjects.h"
 
 #include "import.h"
@@ -58,6 +68,12 @@
 
 /* Forward declarations */
 
+static object *eval_code2 PROTO((codeobject *,
+				 object *, object *,
+				 object **, int,
+				 object **, int,
+				 object **, int,
+				 object *));
 #ifdef LLTRACE
 static int prtrace PROTO((object *, char *));
 #endif
@@ -78,8 +94,8 @@
 static object *and PROTO((object *, object *));
 static object *xor PROTO((object *, object *));
 static object *or PROTO((object *, object *));
-static object *call_builtin PROTO((object *, object *));
-static object *call_function PROTO((object *, object *));
+static object *call_builtin PROTO((object *, object *, object *));
+static object *call_function PROTO((object *, object *, object *));
 static object *apply_subscript PROTO((object *, object *));
 static object *loop_subscript PROTO((object *, object *));
 static int slice_index PROTO((object *, int, int *));
@@ -259,15 +275,38 @@
 };
 
 
-/* Interpreter main loop */
+/* Backward compatible interface */
 
 object *
-eval_code(co, globals, locals, owner, arg)
+eval_code(co, globals, locals)
 	codeobject *co;
 	object *globals;
 	object *locals;
+{
+	return eval_code2(co,
+			  globals, locals,
+			  (object **)NULL, 0,
+			  (object **)NULL, 0,
+			  (object **)NULL, 0,
+			  (object *)NULL);
+}
+
+
+/* Interpreter main loop */
+
+static object *
+eval_code2(co, globals, locals,
+	   args, argcount, kws, kwcount, defs, defcount, owner)
+	codeobject *co;
+	object *globals;
+	object *locals;
+	object **args;
+	int argcount;
+	object **kws; /* length: 2*kwcount */
+	int kwcount;
+	object **defs;
+	int defcount;
 	object *owner;
-	object *arg;
 {
 	register unsigned char *next_instr;
 	register int opcode;	/* Current opcode */
@@ -281,15 +320,14 @@
 	register object *u;
 	register object *t;
 	register frameobject *f; /* Current frame */
-	register listobject *fastlocals = NULL;
-	object *retval;		/* Return value iff why == WHY_RETURN */
-	int needmerge = 0;	/* Set if need to merge locals back at end */
+	register object **fastlocals;
+	object *retval;		/* Return value */
 	int defmode = 0;	/* Default access mode for new variables */
 #ifdef LLTRACE
 	int lltrace;
 #endif
-#if defined( DEBUG ) || defined( LLTRACE )
-	/* Make it easier to find out where we are with dbx */
+#if defined(DEBUG) || defined(LLTRACE)
+	/* Make it easier to find out where we are with a debugger */
 	char *filename = getstringvalue(co->co_filename);
 #endif
 
@@ -324,8 +362,14 @@
 #define POP()		BASIC_POP()
 #endif
 
-	if (globals == NULL || locals == NULL) {
-		err_setstr(SystemError, "eval_code: NULL globals or locals");
+/* Local variable macros */
+
+#define GETLOCAL(i)	(fastlocals[i])
+#define SETLOCAL(i, value)	do { XDECREF(GETLOCAL(i)); \
+				     GETLOCAL(i) = value; } while (0)
+
+	if (globals == NULL) {
+		err_setstr(SystemError, "eval_code2: NULL globals");
 		return NULL;
 	}
 
@@ -343,9 +387,113 @@
 			20);			/*nblocks*/
 	if (f == NULL)
 		return NULL;
-	
+
 	current_frame = f;
 
+	if (co->co_nlocals > 0)
+		fastlocals = ((listobject *)f->f_fastlocals)->ob_item;
+
+	if (co->co_argcount > 0 ||
+	    co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
+		int i;
+		int n = argcount;
+		object *kwdict = NULL;
+		if (co->co_flags & CO_VARKEYWORDS) {
+			kwdict = newmappingobject();
+			if (kwdict == NULL)
+				goto fail;
+		}
+		if (argcount > co->co_argcount) {
+			if (!(co->co_flags & CO_VARARGS)) {
+				err_setstr(TypeError, "too many arguments");
+				goto fail;
+			}
+			n = co->co_argcount;
+		}
+		for (i = 0; i < n; i++) {
+			x = args[i];
+			INCREF(x);
+			SETLOCAL(i, x);
+		}
+		if (co->co_flags & CO_VARARGS) {
+			u = newtupleobject(argcount - n);
+			for (i = n; i < argcount; i++) {
+				x = args[i];
+				INCREF(x);
+				SETTUPLEITEM(u, i-n, x);
+			}
+			SETLOCAL(co->co_argcount, u);
+		}
+		for (i = 0; i < kwcount; i++) {
+			object *keyword = kws[2*i];
+			object *value = kws[2*i + 1];
+			int j;
+			/* XXX slow -- speed up using dictionary? */
+			for (j = 0; j < co->co_argcount; j++) {
+				object *nm = GETTUPLEITEM(co->co_varnames, j);
+				if (cmpobject(keyword, nm) == 0)
+					break;
+			}
+			if (j >= co->co_argcount) {
+				if (kwdict == NULL) {
+					err_setval(KeyError/*XXX*/, keyword);
+					goto fail;
+				}
+				mappinginsert(kwdict, keyword, value);
+			}
+			else {
+				if (GETLOCAL(j) != NULL) {
+					err_setstr(TypeError,
+						"keyword parameter redefined");
+					goto fail;
+				}
+				INCREF(value);
+				SETLOCAL(j, value);
+			}
+		}
+		if (argcount < co->co_argcount) {
+			int m = co->co_argcount - defcount;
+			for (i = argcount; i < m; i++) {
+				if (GETLOCAL(i) == NULL) {
+					err_setstr(TypeError,
+						   "not enough arguments");
+					goto fail;
+				}
+			}
+			if (n > m)
+				i = n - m;
+			else
+				i = 0;
+			for (; i < defcount; i++) {
+				if (GETLOCAL(m+i) == NULL) {
+					object *def = defs[i];
+					INCREF(def);
+					SETLOCAL(m+i, def);
+				}
+			}
+		}
+		if (kwdict != NULL) {
+			i = co->co_argcount;
+			if (co->co_flags & CO_VARARGS)
+				i++;
+			SETLOCAL(i, kwdict);
+		}
+		if (0) {
+	 fail:
+			XDECREF(kwdict);
+			goto fail2;
+		}
+	}
+	else {
+		if (argcount > 0 || kwcount > 0) {
+			err_setstr(TypeError, "no arguments expected");
+ fail2:
+			current_frame = f->f_back;
+			DECREF(f);
+			return NULL;
+		}
+	}
+
 	if (sys_trace != NULL) {
 		/* sys_trace, if defined, is a function that will
 		   be called  on *every* entry to a code block.
@@ -359,7 +507,8 @@
 		   depends on the situation.  The global trace function
 		   (sys.trace) is also called whenever an exception
 		   is detected. */
-		if (call_trace(&sys_trace, &f->f_trace, f, "call", arg)) {
+		if (call_trace(&sys_trace, &f->f_trace, f, "call",
+			       None/*XXX how to compute arguments now?*/)) {
 			/* Trace function raised an error */
 			current_frame = f->f_back;
 			DECREF(f);
@@ -370,7 +519,8 @@
 	if (sys_profile != NULL) {
 		/* Similar for sys_profile, except it needn't return
 		   itself and isn't called for "line" events */
-		if (call_trace(&sys_profile, (object**)0, f, "call", arg)) {
+		if (call_trace(&sys_profile, (object**)0, f, "call",
+			       None/*XXX*/)) {
 			current_frame = f->f_back;
 			DECREF(f);
 			return NULL;
@@ -380,11 +530,6 @@
 	next_instr = GETUSTRINGVALUE(f->f_code->co_code);
 	stack_pointer = f->f_valuestack;
 	
-	if (arg != NULL) {
-		INCREF(arg);
-		PUSH(arg);
-	}
-	
 	why = WHY_NOT;
 	err = 0;
 	x = None;	/* Not a reference, just anything non-NULL */
@@ -522,14 +667,6 @@
 			DECREF(v);
 			PUSH(x);
 			break;
-		
-		case UNARY_CALL:
-			v = POP();
-			f->f_lasti = INSTR_OFFSET() - 1; /* For tracing */
-			x = call_object(v, (object *)NULL);
-			DECREF(v);
-			PUSH(x);
-			break;
 			
 		case UNARY_INVERT:
 			v = POP();
@@ -592,16 +729,6 @@
 			PUSH(x);
 			break;
 		
-		case BINARY_CALL:
-			w = POP();
-			v = POP();
-			f->f_lasti = INSTR_OFFSET() - 1; /* For tracing */
-			x = call_object(v, w);
-			DECREF(v);
-			DECREF(w);
-			PUSH(x);
-			break;
-		
 		case BINARY_LSHIFT:
 			w = POP();
 			v = POP();
@@ -776,9 +903,6 @@
 			why = WHY_BREAK;
 			break;
 
-		case RAISE_EXCEPTION:
-			oparg = 2;
-			/* Fallthrough */
 		case RAISE_VARARGS:
 			u = v = w = NULL;
 			switch (oparg) {
@@ -788,10 +912,7 @@
 					DECREF(u);
 					u = NULL;
 				}
-				else if (strcmp(u->ob_type->tp_name,
-						"traceback") != 0) {
-					/* XXX traceback.h needs to define
-					   is_traceback() */
+				else if (!PyTraceback_Check(u)) {
 					err_setstr(TypeError,
 				    "raise 3rd arg must be traceback or None");
 					goto raise_error;
@@ -814,8 +935,8 @@
 			}
 			/* A tuple is equivalent to its first element here */
 			while (is_tupleobject(w) && gettuplesize(w) > 0) {
-				object *t = w;
-				w = GETTUPLEITEM(t, 0);
+				t = w;
+				w = GETTUPLEITEM(w, 0);
 				INCREF(w);
 				DECREF(t);
 			}
@@ -861,9 +982,12 @@
 			break;
 		
 		case LOAD_LOCALS:
-			v = f->f_locals;
-			INCREF(v);
-			PUSH(v);
+			if ((x = f->f_locals) == NULL) {
+				err_setstr(SystemError, "no locals");
+				break;
+			}
+			INCREF(x);
+			PUSH(x);
 			break;
 		
 		case RETURN_VALUE:
@@ -871,12 +995,6 @@
 			why = WHY_RETURN;
 			break;
 
-		case LOAD_GLOBALS:
-			v = f->f_locals;
-			INCREF(v);
-			PUSH(v);
-			break;
-
 		case EXEC_STMT:
 			w = POP();
 			v = POP();
@@ -887,21 +1005,6 @@
 			DECREF(w);
 			break;
 		
-		case BUILD_FUNCTION:
-			v = POP();
-			x = newfuncobject(v, f->f_globals);
-			DECREF(v);
-			PUSH(x);
-			break;
-
-		case SET_FUNC_ARGS:
-			v = POP(); /* The function */
-			w = POP(); /* The argument list */
-			err = setfuncargstuff(v, oparg, w);
-			PUSH(v);
-			DECREF(w);
-			break;
-		
 		case POP_BLOCK:
 			{
 				block *b = pop_block(f);
@@ -947,14 +1050,18 @@
 		case STORE_NAME:
 			w = GETNAMEV(oparg);
 			v = POP();
-			u = dict2lookup(f->f_locals, w);
+			if ((x = f->f_locals) == NULL) {
+				err_setstr(SystemError, "no locals");
+				break;
+			}
+			u = dict2lookup(x, w);
 			if (u == NULL) {
 				if (defmode != 0) {
 					if (v != None)
 						u = (object *)v->ob_type;
 					else
 						u = NULL;
-					x = newaccessobject(v, f->f_locals,
+					x = newaccessobject(v, x,
 							    (typeobject *)u,
 							    defmode);
 					DECREF(v);
@@ -964,23 +1071,27 @@
 				}
 			}
 			else if (is_accessobject(u)) {
-				err = setaccessvalue(u, f->f_locals, v);
+				err = setaccessvalue(u, x, v);
 				DECREF(v);
 				break;
 			}
-			err = dict2insert(f->f_locals, w, v);
+			err = dict2insert(x, w, v);
 			DECREF(v);
 			break;
 		
 		case DELETE_NAME:
 			w = GETNAMEV(oparg);
-			u = dict2lookup(f->f_locals, w);
+			if ((x = f->f_locals) == NULL) {
+				err_setstr(SystemError, "no locals");
+				break;
+			}
+			u = dict2lookup(x, w);
 			if (u != NULL && is_accessobject(u)) {
-				err = setaccessvalue(u, f->f_locals,
+				err = setaccessvalue(u, x,
 						     (object *)NULL);
 				break;
 			}
-			if ((err = dict2remove(f->f_locals, w)) != 0)
+			if ((err = dict2remove(x, w)) != 0)
 				err_setval(NameError, w);
 			break;
 
@@ -988,74 +1099,6 @@
 		default: switch (opcode) {
 #endif
 		
-		case UNPACK_VARARG:
-			if (EMPTY()) {
-				err_setstr(TypeError,
-					   "no argument list");
-				why = WHY_EXCEPTION;
-				break;
-			}
-			v = POP();
-			if (!is_tupleobject(v)) {
-				err_setstr(TypeError,
-					   "bad argument list");
-				why = WHY_EXCEPTION;
-			}
-			else if (gettuplesize(v) < oparg) {
-				err_setstr(TypeError,
-					"not enough arguments");
-				why = WHY_EXCEPTION;
-			}
-			else if (oparg == 0) {
-				PUSH(v);
-				break;
-			}
-			else {
-				x = gettupleslice(v, oparg, gettuplesize(v));
-				if (x != NULL) {
-					PUSH(x);
-					if (!CHECK_STACK(oparg)) {
-						x = NULL;
-						break;
-					}
-					for (; --oparg >= 0; ) {
-						w = GETTUPLEITEM(v, oparg);
-						INCREF(w);
-						PUSH(w);
-					}
-				}
-			}
-			DECREF(v);
-			break;
-		
-		case UNPACK_ARG:
-			{
-				int n;
-				if (EMPTY()) {
-					err_setstr(TypeError,
-						   "no argument list");
-					why = WHY_EXCEPTION;
-					break;
-				}
-				v = POP();
-				if (!is_tupleobject(v)) {
-					err_setstr(TypeError,
-						   "bad argument list");
-					why = WHY_EXCEPTION;
-					DECREF(v);
-					break;
-				}
-				n = gettuplesize(v);
-				if (n != oparg) {
-					err_setstr(TypeError,
-						"arg count mismatch");
-					why = WHY_EXCEPTION;
-					DECREF(v);
-					break;
-				}
-				PUSH(v);
-			}
-			/* Fall through */
 		case UNPACK_TUPLE:
 			v = POP();
 			if (!is_tupleobject(v)) {
@@ -1125,11 +1168,14 @@
 		case STORE_GLOBAL:
 			w = GETNAMEV(oparg);
 			v = POP();
-			u = dict2lookup(f->f_locals, w);
-			if (u != NULL && is_accessobject(u)) {
-				err = setaccessvalue(u, f->f_globals, v);
-				DECREF(v);
-				break;
+			if (f->f_locals != NULL) {
+				u = dict2lookup(f->f_locals, w);
+				if (u != NULL && is_accessobject(u)) {
+					err = setaccessvalue(u, f->f_globals,
+							     v);
+					DECREF(v);
+					break;
+				}
 			}
 			err = dict2insert(f->f_globals, w, v);
 			DECREF(v);
@@ -1137,11 +1183,13 @@
 		
 		case DELETE_GLOBAL:
 			w = GETNAMEV(oparg);
-			u = dict2lookup(f->f_locals, w);
-			if (u != NULL && is_accessobject(u)) {
-				err = setaccessvalue(u, f->f_globals,
-						     (object *)NULL);
-				break;
+			if (f->f_locals != NULL) {
+				u = dict2lookup(f->f_locals, w);
+				if (u != NULL && is_accessobject(u)) {
+					err = setaccessvalue(u, f->f_globals,
+							     (object *)NULL);
+					break;
+				}
 			}
 			if ((err = dict2remove(f->f_globals, w)) != 0)
 				err_setval(NameError, w);
@@ -1155,7 +1203,11 @@
 		
 		case LOAD_NAME:
 			w = GETNAMEV(oparg);
-			x = dict2lookup(f->f_locals, w);
+			if ((x = f->f_locals) == NULL) {
+				err_setstr(SystemError, "no locals");
+				break;
+			}
+			x = dict2lookup(x, w);
 			if (x == NULL) {
 				err_clear();
 				x = dict2lookup(f->f_globals, w);
@@ -1198,10 +1250,15 @@
 				INCREF(x);
 			PUSH(x);
 			break;
-		
+
+#if 0
 		case LOAD_LOCAL:
 			w = GETNAMEV(oparg);
-			x = dict2lookup(f->f_locals, w);
+			if ((x = f->f_locals) == NULL) {
+				err_setstr(SystemError, "no locals");
+				break;
+			}
+			x = dict2lookup(x, w);
 			if (x == NULL) {
 				err_setval(NameError, w);
 				break;
@@ -1215,29 +1272,14 @@
 				INCREF(x);
 			PUSH(x);
 			break;
-
-		case RESERVE_FAST:
-			x = GETCONST(oparg);
-			if (x == None)
-				break;
-			if (x == NULL || !is_tupleobject(x)) {
-				err_setstr(SystemError, "bad RESERVE_FAST");
-				x = NULL;
-				break;
-			}
-			XDECREF(f->f_fastlocals);
-			XDECREF(f->f_localmap);
-			INCREF(x);
-			f->f_localmap = x;
-			f->f_fastlocals = x = newlistobject(gettuplesize(x));
-			fastlocals = (listobject *) x;
-			break;
+#endif
 
 		case LOAD_FAST:
-			x = GETLISTITEM(fastlocals, oparg);
+			x = GETLOCAL(oparg);
 			if (x == NULL) {
 				err_setval(NameError,
-					   gettupleitem(f->f_localmap, oparg));
+					   gettupleitem(co->co_varnames,
+							oparg));
 				break;
 			}
 			if (is_accessobject(x)) {
@@ -1252,30 +1294,29 @@
 
 		case STORE_FAST:
 			v = POP();
-			w = GETLISTITEM(fastlocals, oparg);
+			w = GETLOCAL(oparg);
 			if (w != NULL && is_accessobject(w)) {
 				err = setaccessvalue(w, f->f_locals, v);
 				DECREF(v);
 				break;
 			}
-			GETLISTITEM(fastlocals, oparg) = v;
-			XDECREF(w);
+			SETLOCAL(oparg, v);
 			break;
 
 		case DELETE_FAST:
-			x = GETLISTITEM(fastlocals, oparg);
+			x = GETLOCAL(oparg);
 			if (x == NULL) {
 				err_setval(NameError,
-					   gettupleitem(f->f_localmap, oparg));
+					   gettupleitem(co->co_varnames,
+							oparg));
 				break;
 			}
-			if (x != NULL && is_accessobject(x)) {
+			if (is_accessobject(x)) {
 				err = setaccessvalue(x, f->f_locals,
 						     (object *)NULL);
 				break;
 			}
-			GETLISTITEM(fastlocals, oparg) = NULL;
-			DECREF(x);
+			SETLOCAL(oparg, NULL);
 			break;
 		
 		case BUILD_TUPLE:
@@ -1343,7 +1384,11 @@
 					break;
 				}
 			}
-			w = mkvalue("(OOOO)", w, f->f_globals, f->f_locals, u);
+			w = mkvalue("(OOOO)",
+				    w,
+				    f->f_globals,
+				    f->f_locals == NULL ? None : f->f_locals,
+				    u);
 			DECREF(u);
 			if (w == NULL) {
 				x = NULL;
@@ -1358,7 +1403,11 @@
 			w = GETNAMEV(oparg);
 			v = TOP();
 			fast_2_locals(f);
-			err = import_from(f->f_locals, v, w);
+			if ((x = f->f_locals) == NULL) {
+				err_setstr(SystemError, "no locals");
+				break;
+			}
+			err = import_from(x, v, w);
 			locals_2_fast(f, 0);
 			break;
 
@@ -1447,12 +1496,6 @@
 
 		case CALL_FUNCTION:
 		{
-			/* XXX To do:
-			   - fill in default arguments here
-			   - proper handling of keyword parameters
-			   - change eval_code interface to take an
-			     array of arguments instead of a tuple
-			   */
 			int na = oparg & 0xff;
 			int nk = (oparg>>8) & 0xff;
 			int n = na + 2*nk;
@@ -1460,75 +1503,120 @@
 			object *func = *pfunc;
 			object *self = NULL;
 			object *class = NULL;
-			object *args;
 			f->f_lasti = INSTR_OFFSET() - 3; /* For tracing */
-			INCREF(func);
 			if (is_instancemethodobject(func)) {
 				self = instancemethodgetself(func);
+				class = instancemethodgetclass(func);
+				func = instancemethodgetfunc(func);
+				INCREF(func);
 				if (self != NULL) {
-					class = instancemethodgetclass(func);
-					DECREF(func);
-					func = instancemethodgetfunc(func);
-					INCREF(func);
 					INCREF(self);
 					DECREF(*pfunc);
 					*pfunc = self;
 					na++;
 					n++;
 				}
-			}
-			args = newtupleobject(n);
-			if (args == NULL)
-				x = NULL;
-			else {
-				while (--n >= 0) {
-					w = POP();
-					SETTUPLEITEM(args, n, w);
-				}
-				if (self == NULL)
-					 POP();
-				if (is_funcobject(func)) {
-					int argcount;
-					object *argdefs =
-					    getfuncargstuff(func, &argcount);
-					if (argdefs == NULL) { /* Fast path */
-						object *co, *loc, *glob;
-						co = getfunccode(func);
-						loc = newdictobject();
-						if (loc == NULL) {
-							x = NULL;
-							DECREF(func);
-							break;
-						}
-						glob = getfuncglobals(func);
-						INCREF(glob);
-						x = eval_code(
-							(codeobject *)co,
-							glob,
-							loc,
-							class,
-							args);
-						DECREF(glob);
-						DECREF(loc);
-						DECREF(args);
-						DECREF(func);
-						PUSH(x);
-						break;
+				else {
+					/* Unbound methods must be
+					   called with an instance of
+					   the class (or a derived
+					   class) as first argument */
+					if (na > 0 &&
+					    (self = stack_pointer[-n])
+					 	!= NULL &&
+					    is_instanceobject(self) &&
+					    issubclass(
+						    (object *)
+						    (((instanceobject *)self)
+						     ->in_class),
+						    class))
+						/* Handy-dandy */ ;
+					else {
+						err_setstr(TypeError,
+	   "unbound method must be called with class instance 1st argument");
+						return NULL;
 					}
 				}
-				x = call_object(func, args);
-				DECREF(args);
-				PUSH(x);
+			}
+			else
+				INCREF(func);
+			if (is_funcobject(func)) {
+				object *co = getfunccode(func);
+				object *globals = getfuncglobals(func);
+				object *argdefs = PyFunction_GetDefaults(func);
+				object **d;
+				int nd;
+				if (argdefs != NULL) {
+					d = &GETTUPLEITEM(argdefs, 0);
+					nd = ((tupleobject *)argdefs)->ob_size;
+				}
+				else {
+					d = NULL;
+					nd = 0;
+				}
+				x = eval_code2(
+					(codeobject *)co,
+					globals, (object *)NULL,
+					stack_pointer-n, na,
+					stack_pointer-2*nk, nk,
+					d, nd,
+					class);
+			}
+			else {
+				object *args = newtupleobject(na);
+				object *kwdict = NULL;
+				if (args == NULL)
+					x = NULL;
+				else if (nk > 0) {
+					err_setstr(SystemError,
+			"calling built-in with keywords not yet implemented");
+					x = NULL;
+				}
+				else {
+					while (--na >= 0) {
+						w = POP();
+						SETTUPLEITEM(args, na, w);
+					}
+					x = call_object(func, args);
+					DECREF(args);
+				}
 			}
 			DECREF(func);
+			while (stack_pointer > pfunc) {
+				w = POP();
+				DECREF(w);
+			}
+			PUSH(x);
 			break;
 		}
 		
+		case MAKE_FUNCTION:
+			v = POP(); /* code object */
+			x = newfuncobject(v, f->f_globals);
+			DECREF(v);
+			/* XXX Maybe this should be a separate opcode? */
+			if (x != NULL && oparg > 0) {
+				v = newtupleobject(oparg);
+				if (v == NULL) {
+					DECREF(x);
+					x = NULL;
+					break;
+				}
+				while (--oparg >= 0) {
+					w = POP();
+					SETTUPLEITEM(v, oparg, w);
+				}
+				err = PyFunction_SetDefaults(x, v);
+				DECREF(v);
+			}
+			PUSH(x);
+			break;
+		
 		default:
 			fprintf(stderr,
 				"XXX lineno: %d, opcode: %d\n",
 				f->f_lineno, opcode);
-			err_setstr(SystemError, "eval_code: unknown opcode");
+			err_setstr(SystemError, "unknown opcode");
 			why = WHY_EXCEPTION;
 			break;
 
@@ -1543,8 +1631,15 @@
 		/* Quickly continue if no error occurred */
 		
 		if (why == WHY_NOT) {
-			if (err == 0 && x != NULL)
-				continue; /* Normal, fast path */
+			if (err == 0 && x != NULL) {
+#ifdef CHECKEXC
+				if (err_occurred())
+					fprintf(stderr,
+						"XXX undetected error\n");
+				else
+#endif
+					continue; /* Normal, fast path */
+			}
 			why = WHY_EXCEPTION;
 			x = None;
 			err = 0;
@@ -1561,8 +1656,12 @@
 			}
 		}
 		else {
-			if (err_occurred())
-				fatal("XXX undetected error");
+			if (err_occurred()) {
+				fprintf(stderr,
+					"XXX undetected error (why=%d)\n",
+					why);
+				why = WHY_EXCEPTION;
+			}
 		}
 #endif
 
@@ -1672,12 +1771,9 @@
 	}
 	
 	/* Restore previous frame and release the current one */
-	
+
 	current_frame = f->f_back;
 	DECREF(f);
-
-	if (needmerge)
-		locals_2_fast(current_frame, 1);
 	
 	return retval;
 }
@@ -2134,38 +2230,66 @@
 }
 
 
-/* External interface to call any callable object. The arg may be NULL. */
+/* External interface to call any callable object.
+   The arg must be a tuple or NULL. */
 
 object *
 call_object(func, arg)
 	object *func;
 	object *arg;
 {
-        binaryfunc call;
-        object *result;
-        
-        if (call = func->ob_type->tp_call)
-                result = (*call)(func, arg);
-        else if (is_instancemethodobject(func) || is_funcobject(func))
-		result = call_function(func, arg);
-	else
-		result = call_builtin(func, arg);
+	return PyEval_CallObjectWithKeywords(func, arg, (object *)NULL);
+}
 
+object *
+PyEval_CallObjectWithKeywords(func, arg, kw)
+	object *func;
+	object *arg;
+	object *kw;
+{
+        ternaryfunc call;
+        object *result;
+
+	if (arg == NULL)
+		arg = newtupleobject(0);
+	else if (!is_tupleobject(arg)) {
+		err_setstr(TypeError, "argument list must be a tuple");
+		return NULL;
+	}
+	else
+		INCREF(arg);
+
+        if (call = func->ob_type->tp_call)
+                result = (*call)(func, arg, kw);
+        else if (is_instancemethodobject(func) || is_funcobject(func))
+		result = call_function(func, arg, kw);
+	else
+		result = call_builtin(func, arg, kw);
+
+	DECREF(arg);
+	
         if (result == NULL && !err_occurred())
-		fatal("null result without error in call_object");
+		err_setstr(SystemError,
+			   "NULL result without error in call_object");
         
         return result;
 }
 
 static object *
-call_builtin(func, arg)
+call_builtin(func, arg, kw)
 	object *func;
 	object *arg;
+	object *kw;
 {
+	if (kw != NULL) {
+		err_setstr(SystemError,
+			"calling built-in with keywords not yet implemented");
+		return NULL;
+	}
 	if (is_methodobject(func)) {
 		method meth = getmethod(func);
 		object *self = getself(func);
-		if (!getvarargs(func) && arg != NULL && is_tupleobject(arg)) {
+		if (!getvarargs(func)) {
 			int size = gettuplesize(arg);
 			if (size == 1)
 				arg = GETTUPLEITEM(arg, 0);
@@ -2181,7 +2305,8 @@
 	        object *res, *call = getattr(func,"__call__");
 		if (call == NULL) {
 			err_clear();
-			err_setstr(AttributeError, "no __call__ method defined");
+			err_setstr(AttributeError,
+				   "no __call__ method defined");
 			return NULL;
 		}
 		res = call_object(call, arg);
@@ -2193,16 +2318,21 @@
 }
 
 static object *
-call_function(func, arg)
+call_function(func, arg, kw)
 	object *func;
 	object *arg;
+	object *kw;
 {
-	object *newarg = NULL;
-	object *newlocals, *newglobals;
-	object *class = NULL;
-	object *co, *v;
+	object *class = NULL; /* == owner */
 	object *argdefs;
-	int	argcount;
+	object **d, **k;
+	int nk, nd;
+	object *result;
+	
+	if (kw != NULL && !is_dictobject(kw)) {
+		err_badcall();
+		return NULL;
+	}
 	
 	if (is_instancemethodobject(func)) {
 		object *self = instancemethodgetself(func);
@@ -2211,48 +2341,36 @@
 		if (self == NULL) {
 			/* Unbound methods must be called with an instance of
 			   the class (or a derived class) as first argument */
-			if (arg != NULL && is_tupleobject(arg) &&
-			    gettuplesize(arg) >= 1) {
+			if (gettuplesize(arg) >= 1) {
 				self = GETTUPLEITEM(arg, 0);
 				if (self != NULL &&
 				    is_instanceobject(self) &&
 				    issubclass((object *)
 				      (((instanceobject *)self)->in_class),
 					       class))
-					/* self = self */ ;
+					/* Handy-dandy */ ;
 				else
 					self = NULL;
 			}
 			if (self == NULL) {
 				err_setstr(TypeError,
-	   "unbound method must be called with class instance argument");
+	   "unbound method must be called with class instance 1st argument");
 				return NULL;
 			}
+			INCREF(arg);
 		}
 		else {
-			if (arg == NULL)
-				argcount = 0;
-			else if (is_tupleobject(arg))
-				argcount = gettuplesize(arg);
-			else
-				argcount = 1;
-			newarg = newtupleobject(argcount + 1);
+			int argcount = gettuplesize(arg);
+			object *newarg = newtupleobject(argcount + 1);
+			int i;
 			if (newarg == NULL)
 				return NULL;
 			INCREF(self);
 			SETTUPLEITEM(newarg, 0, self);
-			if (arg != NULL && !is_tupleobject(arg)) {
-				INCREF(arg);
-				SETTUPLEITEM(newarg, 1, arg);
-			}
-			else {
-				int i;
-				object *v;
-				for (i = 0; i < argcount; i++) {
-					v = GETTUPLEITEM(arg, i);
-					XINCREF(v);
-					SETTUPLEITEM(newarg, i+1, v);
-				}
+			for (i = 0; i < argcount; i++) {
+				object *v = GETTUPLEITEM(arg, i);
+				XINCREF(v);
+				SETTUPLEITEM(newarg, i+1, v);
 			}
 			arg = newarg;
 		}
@@ -2262,65 +2380,51 @@
 			err_setstr(TypeError, "call of non-function");
 			return NULL;
 		}
+		INCREF(arg);
 	}
-
-	argdefs = getfuncargstuff(func, &argcount);
-	if (argdefs != NULL && arg != NULL && is_tupleobject(arg)) {
-		int actualcount, j;
-		/* Process default arguments */
-		if (argcount & 0x4000)
-			argcount ^= 0x4000;
-		actualcount = gettuplesize(arg);
-		j = gettuplesize(argdefs) - (argcount - actualcount);
-		if (actualcount < argcount && j >= 0) {
-			int i;
-			object *v;
-			if (newarg == NULL)
-				INCREF(arg);
-			newarg = newtupleobject(argcount);
-			if (newarg == NULL) {
-				DECREF(arg);
-				return NULL;
-			}
-			for (i = 0; i < actualcount; i++) {
-				v = GETTUPLEITEM(arg, i);
-				XINCREF(v);
-				SETTUPLEITEM(newarg, i, v);
-			}
-			for (; i < argcount; i++, j++) {
-				v = GETTUPLEITEM(argdefs, j);
-				XINCREF(v);
-				SETTUPLEITEM(newarg, i, v);
-			}
+	
+	argdefs = PyFunction_GetDefaults(func);
+	if (argdefs != NULL && is_tupleobject(argdefs)) {
+		d = &GETTUPLEITEM((tupleobject *)argdefs, 0);
+		nd = gettuplesize(argdefs);
+	}
+	else {
+		d = NULL;
+		nd = 0;
+	}
+	
+	if (kw != NULL) {
+		int pos, i;
+		nk = getmappingsize(kw);
+		k = NEW(object *, 2*nk);
+		if (k == NULL) {
+			err_nomem();
 			DECREF(arg);
-			arg = newarg;
+			return NULL;
 		}
+		pos = i = 0;
+		while (mappinggetnext(kw, &pos, &k[i], &k[i+1]))
+			i += 2;
+		nk = i/2;
+		/* XXX This is broken if the caller deletes dict items! */
+	}
+	else {
+		k = NULL;
+		nk = 0;
 	}
 	
-	co = getfunccode(func);
-	if (co == NULL) {
-		XDECREF(newarg);
-		return NULL;
-	}
-	if (!is_codeobject(co))
-		fatal("XXX Bad code");
-	newlocals = newdictobject();
-	if (newlocals == NULL) {
-		XDECREF(newarg);
-		return NULL;
-	}
+	result = eval_code2(
+		(codeobject *)getfunccode(func),
+		getfuncglobals(func), (object *)NULL,
+		&GETTUPLEITEM(arg, 0), gettuplesize(arg),
+		k, nk,
+		d, nd,
+		class);
 	
-	newglobals = getfuncglobals(func);
-	INCREF(newglobals);
+	DECREF(arg);
+	XDEL(k);
 	
-	v = eval_code((codeobject *)co, newglobals, newlocals, class, arg);
-	
-	DECREF(newlocals);
-	DECREF(newglobals);
-	
-	XDECREF(newarg);
-	
-	return v;
+	return result;
 }
 
 static object *
@@ -2690,21 +2794,9 @@
 	int mode = getintvalue(vmode);
 	object *value, *ac;
 	typeobject *type;
-	int fastind, ret;
-	fastind = -1;
-	if (f->f_localmap == NULL)
-		value = dict2lookup(f->f_locals, name);
-	else {
-		object *map = f->f_localmap;
-		value = NULL;
-		for (fastind = gettuplesize(map); --fastind >= 0; ) {
-			object *fname = GETTUPLEITEM(map, fastind);
-			if (cmpobject(name, fname) == 0) {
-				value = getlistitem(f->f_fastlocals, fastind);
-				break;
-			}
-		}
-	}
+	int ret;
+	fast_2_locals(f);
+	value = dict2lookup(f->f_locals, name);
 	if (value && is_accessobject(value)) {
 		err_setstr(AccessError, "can't override access");
 		return -1;
@@ -2717,12 +2809,9 @@
 	ac = newaccessobject(value, f->f_locals, type, mode);
 	if (ac == NULL)
 		return -1;
-	if (fastind >= 0)
-		ret = setlistitem(f->f_fastlocals, fastind, ac);
-	else {
-		ret = dict2insert(f->f_locals, name, ac);
-		DECREF(ac);
-	}
+	ret = mappinginsert(f->f_locals, name, ac);
+	DECREF(ac);
+	locals_2_fast(f, 0);
 	return ret;
 }
 
@@ -2735,6 +2824,7 @@
 	char *s;
 	int n;
 	object *v;
+	int plain = 0;
 
 	if (is_tupleobject(prog) && globals == None && locals == None &&
 	    ((n = gettuplesize(prog)) == 2 || n == 3)) {
@@ -2746,8 +2836,10 @@
 	}
 	if (globals == None) {
 		globals = getglobals();
-		if (locals == None)
+		if (locals == None) {
 			locals = getlocals();
+			plain = 1;
+		}
 	}
 	else if (locals == None)
 		locals = globals;
@@ -2766,8 +2858,7 @@
 	if (dictlookup(globals, "__builtins__") == NULL)
 		dictinsert(globals, "__builtins__", current_frame->f_builtins);
 	if (is_codeobject(prog)) {
-		if (eval_code((codeobject *) prog, globals, locals,
-				 (object *)NULL, (object *)NULL) == NULL)
+		if (eval_code((codeobject *) prog, globals, locals) == NULL)
 			return -1;
 		return 0;
 	}
@@ -2783,13 +2874,16 @@
 		err_setstr(ValueError, "embedded '\\0' in exec string");
 		return -1;
 	}
-	if ((v = run_string(s, file_input, globals, locals)) == NULL)
+	v = run_string(s, file_input, globals, locals);
+	if (v == NULL)
 		return -1;
 	DECREF(v);
+	if (plain)
+		locals_2_fast(current_frame, 0);
 	return 0;
 }
 
-/* Hack for Ken Manheimer */
+/* Hack for newimp.py */
 static object *
 find_from_args(f, nexti)
 	frameobject *f;
@@ -2812,7 +2906,8 @@
 		return NULL;
 	
 	do {
-		oparg = (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]);
+		oparg = (next_instr[1]<<8) + next_instr[0];
+		next_instr += 2;
 		name = Getnamev(f, oparg);
 		if (addlistitem(list, name) < 0) {
 			DECREF(list);
diff --git a/Python/compile.c b/Python/compile.c
index df81f8f..9f15254 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -25,8 +25,14 @@
 /* Compile an expression node to intermediate code */
 
 /* XXX TO DO:
-   XXX Compute maximum needed stack sizes while compiling
+   XXX Compute maximum needed stack sizes while compiling;
+   XXX   then frame object can be one malloc and no stack checks are needed
+   XXX add __doc__ attribute == co_doc to code object attributes
+   XXX don't execute doc string
    XXX Generate simple jump for break/return outside 'try...finally'
+   XXX get rid of SET_LINENO instructions, use JAR's table trick
+   XXX   (need an option to put them back in, for debugger!)
+   XXX other JAR tricks?
 */
 
 #include "allobjects.h"
@@ -44,9 +50,13 @@
 #define OFF(x) offsetof(codeobject, x)
 
 static struct memberlist code_memberlist[] = {
+	{"co_argcount",	T_INT,		OFF(co_argcount),	READONLY},
+	{"co_nlocals",	T_INT,		OFF(co_nlocals),	READONLY},
+	{"co_flags",	T_INT,		OFF(co_flags),		READONLY},
 	{"co_code",	T_OBJECT,	OFF(co_code),		READONLY},
 	{"co_consts",	T_OBJECT,	OFF(co_consts),		READONLY},
 	{"co_names",	T_OBJECT,	OFF(co_names),		READONLY},
+	{"co_varnames",	T_OBJECT,	OFF(co_varnames),	READONLY},
 	{"co_filename",	T_OBJECT,	OFF(co_filename),	READONLY},
 	{"co_name",	T_OBJECT,	OFF(co_name),		READONLY},
 	{NULL}	/* Sentinel */
@@ -69,6 +79,7 @@
 	XDECREF(co->co_names);
 	XDECREF(co->co_filename);
 	XDECREF(co->co_name);
+	XDECREF(co->co_varnames);
 	DEL(co);
 }
 
@@ -97,11 +108,19 @@
 	codeobject *co, *cp;
 {
 	int cmp;
+	cmp = cp->co_argcount - cp->co_argcount;
+	if (cmp) return cmp;
+	cmp = cp->co_nlocals - cp->co_nlocals;
+	if (cmp) return cmp;
+	cmp = cp->co_flags - cp->co_flags;
+	if (cmp) return cmp;
 	cmp = cmpobject((object *)co->co_code, (object *)cp->co_code);
 	if (cmp) return cmp;
 	cmp = cmpobject(co->co_consts, cp->co_consts);
 	if (cmp) return cmp;
 	cmp = cmpobject(co->co_names, cp->co_names);
+	if (cmp) return cmp;
+	cmp = cmpobject(co->co_varnames, cp->co_varnames);
 	return cmp;
 }
 
@@ -109,14 +128,17 @@
 code_hash(co)
 	codeobject *co;
 {
-	long h, h1, h2, h3;
+	long h, h1, h2, h3, h4;
 	h1 = hashobject((object *)co->co_code);
 	if (h1 == -1) return -1;
 	h2 = hashobject(co->co_consts);
 	if (h2 == -1) return -1;
 	h3 = hashobject(co->co_names);
 	if (h3 == -1) return -1;
-	h = h1 ^ h2 ^ h3;
+	h4 = hashobject(co->co_varnames);
+	if (h4 == -1) return -1;
+	h = h1 ^ h2 ^ h3 ^ h4 ^
+		co->co_argcount ^ co->co_nlocals ^ co->co_flags;
 	if (h == -1) h = -2;
 	return h;
 }
@@ -140,67 +162,64 @@
 };
 
 codeobject *
-newcodeobject(code, consts, names, filename, name)
+newcodeobject(argcount, nlocals, flags,
+	      code, consts, names, varnames, filename, name)
+	int argcount;
+	int nlocals;
+	int flags;
 	object *code;
 	object *consts;
 	object *names;
+	object *varnames;
 	object *filename;
 	object *name;
 {
 	codeobject *co;
 	int i;
 	/* Check argument types */
-	if (code == NULL || !is_stringobject(code) ||
-		consts == NULL ||
-		names == NULL ||
-		name == NULL || !(is_stringobject(name) || name == None)) {
+	if (argcount < 0 || nlocals < 0 ||
+	    code == NULL || !is_stringobject(code) ||
+	    consts == NULL || !is_tupleobject(consts) ||
+	    names == NULL || !is_tupleobject(names) ||
+	    varnames == NULL || !is_tupleobject(varnames) ||
+	    name == NULL || !is_stringobject(name) ||
+	    filename == NULL || !is_stringobject(filename)) {
 		err_badcall();
 		return NULL;
 	}
-	/* Allow two lists instead of two tuples */
-	if (is_listobject(consts) && is_listobject(names)) {
-		consts = listtuple(consts);
-		if (consts == NULL)
-			return NULL;
-		names = listtuple(names);
-		if (names == NULL) {
-			DECREF(consts);
-			return NULL;
-		}
-	}
-	else if (!is_tupleobject(consts) && !is_tupleobject(names)) {
-		err_badcall();
-		return NULL;
-	}
-	else {
-		INCREF(consts);
-		INCREF(names);
-	}
-	/* Make sure the list of names contains only strings */
+	/* Make sure names and varnames are all strings */
 	for (i = gettuplesize(names); --i >= 0; ) {
 		object *v = gettupleitem(names, i);
 		if (v == NULL || !is_stringobject(v)) {
-			DECREF(consts);
-			DECREF(names);
+			err_badcall();
+			return NULL;
+		}
+	}
+	for (i = gettuplesize(varnames); --i >= 0; ) {
+		object *v = gettupleitem(varnames, i);
+		if (v == NULL || !is_stringobject(v)) {
 			err_badcall();
 			return NULL;
 		}
 	}
 	co = NEWOBJ(codeobject, &Codetype);
 	if (co != NULL) {
+		co->co_argcount = argcount;
+		co->co_nlocals = nlocals;
+		co->co_flags = flags;
 		INCREF(code);
 		co->co_code = (stringobject *)code;
+		INCREF(consts);
 		co->co_consts = consts;
+		INCREF(names);
 		co->co_names = names;
+		INCREF(varnames);
+		co->co_varnames = varnames;
 		INCREF(filename);
 		co->co_filename = filename;
 		INCREF(name);
 		co->co_name = name;
 	}
-	else {
-		DECREF(consts);
-		DECREF(names);
-	}
 	return co;
 }
 
@@ -213,7 +232,12 @@
 	object *c_code;		/* string */
 	object *c_consts;	/* list of objects */
 	object *c_names;	/* list of strings (names) */
-	object *c_globals;	/* dictionary */
+	object *c_globals;	/* dictionary (value=None) */
+	object *c_locals;	/* dictionary (value=localID) */
+	object *c_varnames;	/* list (inverse of c_locals) */
+	int c_nlocals;		/* index of next local */
+	int c_argcount;		/* number of top-level arguments */
+	int c_flags;		/* same as co_flags */
 	int c_nexti;		/* index into c_code */
 	int c_errors;		/* counts errors occurred */
 	int c_infunction;	/* set when compiling a function */
@@ -257,7 +281,7 @@
 }
 
 
-/* Prototypes */
+/* Prototype forward declarations */
 
 static int com_init PROTO((struct compiling *, char *));
 static void com_free PROTO((struct compiling *));
@@ -273,7 +297,8 @@
 static int com_addname PROTO((struct compiling *, object *));
 static void com_addopname PROTO((struct compiling *, int, node *));
 static void com_list PROTO((struct compiling *, node *, int));
-static int com_argdefs PROTO((struct compiling *, node *, int *));
+static int com_argdefs PROTO((struct compiling *, node *));
+static int com_newlocal PROTO((struct compiling *, char *));
 
 static int
 com_init(c, filename)
@@ -288,6 +313,13 @@
 		goto fail_1;
 	if ((c->c_globals = newdictobject()) == NULL)
 		goto fail_0;
+	if ((c->c_locals = newdictobject()) == NULL)
+		goto fail_00;
+	if ((c->c_varnames = newlistobject(0)) == NULL)
+		goto fail_000;
+	c->c_nlocals = 0;
+	c->c_argcount = 0;
+	c->c_flags = 0;
 	c->c_nexti = 0;
 	c->c_errors = 0;
 	c->c_infunction = 0;
@@ -299,6 +331,10 @@
 	c->c_name = "?";
 	return 1;
 	
+  fail_000:
+  	DECREF(c->c_locals);
+  fail_00:
+  	DECREF(c->c_globals);
   fail_0:
   	DECREF(c->c_names);
   fail_1:
@@ -317,6 +353,8 @@
 	XDECREF(c->c_consts);
 	XDECREF(c->c_names);
 	XDECREF(c->c_globals);
+	XDECREF(c->c_locals);
+	XDECREF(c->c_varnames);
 }
 
 static void
@@ -333,6 +371,7 @@
 	int byte;
 {
 	int len;
+	/*fprintf(stderr, "%3d: %3d\n", c->c_nexti, byte);*/
 	if (byte < 0 || byte > 255) {
 		/*
 		fprintf(stderr, "XXX compiling bad byte: %d\n", byte);
@@ -1221,8 +1260,7 @@
 	if (NCH(n) == 1 && TYPE(CHILD(n, 0)) == lambdef) {
 		object *v;
 		int i;
-		int argcount;
-		int ndefs = com_argdefs(c, CHILD(n, 0), &argcount);
+		int ndefs = com_argdefs(c, CHILD(n, 0));
 		v = (object *) compile(CHILD(n, 0), c->c_filename);
 		if (v == NULL) {
 			c->c_errors++;
@@ -1233,9 +1271,7 @@
 			DECREF(v);
 		}
 		com_addoparg(c, LOAD_CONST, i);
-		com_addbyte(c, BUILD_FUNCTION);
-		if (ndefs > 0)
-			com_addoparg(c, SET_FUNC_ARGS, argcount);
+		com_addoparg(c, MAKE_FUNCTION, ndefs);
 	}
 	else {
 		int anchor = 0;
@@ -1537,16 +1573,12 @@
 {
 	REQ(n, raise_stmt); /* 'raise' test [',' test [',' test]] */
 	com_node(c, CHILD(n, 1));
-	if (NCH(n) > 3)
+	if (NCH(n) > 3) {
 		com_node(c, CHILD(n, 3));
-	else
-		com_addoparg(c, LOAD_CONST, com_addconst(c, None));
-	if (NCH(n) > 5) {
-		com_node(c, CHILD(n, 5));
-		com_addoparg(c, RAISE_VARARGS, 3);
+		if (NCH(n) > 5)
+			com_node(c, CHILD(n, 5));
 	}
-	else
-		com_addbyte(c, RAISE_EXCEPTION);
+	com_addoparg(c, RAISE_VARARGS, NCH(n)/2);
 }
 
 static void
@@ -1585,11 +1617,69 @@
 	REQ(n, global_stmt);
 	/* 'global' NAME (',' NAME)* */
 	for (i = 1; i < NCH(n); i += 2) {
-		if (dictinsert(c->c_globals, STR(CHILD(n, i)), None) != 0)
+		char *s = STR(CHILD(n, i));
+		if (dictlookup(c->c_locals, s) != NULL) {
+			err_setstr(SyntaxError, "name is local and global");
+			c->c_errors++;
+		}
+		else if (dictinsert(c->c_globals, s, None) != 0)
 			c->c_errors++;
 	}
 }
 
+static int
+com_newlocal_o(c, nameval)
+	struct compiling *c;
+	object *nameval;
+{
+	int i;
+	object *ival;
+	if (getlistsize(c->c_varnames) != c->c_nlocals) {
+		/* This is usually caused by an error on a previous call */
+		if (c->c_errors == 0) {
+			err_setstr(SystemError, "mixed up var name/index");
+			c->c_errors++;
+		}
+		return 0;
+	}
+	ival = newintobject(i = c->c_nlocals++);
+	if (ival == NULL)
+		c->c_errors++;
+	else if (mappinginsert(c->c_locals, nameval, ival) != 0)
+		c->c_errors++;
+	else if (addlistitem(c->c_varnames, nameval) != 0)
+		c->c_errors++;
+	XDECREF(ival);
+	return i;
+}
+
+static int
+com_addlocal_o(c, nameval)
+	struct compiling *c;
+	object *nameval;
+{
+	object *ival =  mappinglookup(c->c_locals, nameval);
+	if (ival != NULL)
+		return getintvalue(ival);
+	return com_newlocal_o(c, nameval);
+}
+
+static int
+com_newlocal(c, name)
+	struct compiling *c;
+	char *name;
+{
+	object *nameval = newstringobject(name);
+	int i;
+	if (nameval == NULL) {
+		c->c_errors++;
+		return 0;
+	}
+	i = com_newlocal_o(c, nameval);
+	DECREF(nameval);
+	return i;
+}
+
 #define strequ(a, b) (strcmp((a), (b)) == 0)
 
 static void
@@ -2019,12 +2109,11 @@
 }
 
 static int
-com_argdefs(c, n, argcount_return)
+com_argdefs(c, n)
 	struct compiling *c;
 	node *n;
-	int *argcount_return;
 {
-	int i, nch, nargs, ndefs, star;
+	int i, nch, nargs, ndefs;
 	if (TYPE(n) == lambdef) {
 		/* lambdef: 'lambda' [varargslist] ':' test */
 		n = CHILD(n, 1);
@@ -2036,14 +2125,13 @@
 		n = CHILD(n, 1);
 	}
 	if (TYPE(n) != varargslist)
-		    return -1;
+		    return 0;
 	/* varargslist:
-		(fpdef ['=' test] ',')* '*' NAME ....... |
+		(fpdef ['=' test] ',')* '*' ....... |
 		fpdef ['=' test] (',' fpdef ['=' test])* [','] */
 	nch = NCH(n);
 	nargs = 0;
 	ndefs = 0;
-	star = 0;
 	for (i = 0; i < nch; i++) {
 		int t;
 		if (TYPE(CHILD(n, i)) == STAR)
@@ -2073,11 +2161,6 @@
 		if (t != COMMA)
 			break;
 	}
-	if (star)
-		nargs ^= 0x4000;
-	*argcount_return = nargs;
-	if (ndefs > 0)
-		com_addoparg(c, BUILD_TUPLE, ndefs);
 	return ndefs;
 }
 
@@ -2093,12 +2176,9 @@
 		c->c_errors++;
 	else {
 		int i = com_addconst(c, v);
-		int argcount;
-		int ndefs = com_argdefs(c, n, &argcount);
+		int ndefs = com_argdefs(c, n);
 		com_addoparg(c, LOAD_CONST, i);
-		com_addbyte(c, BUILD_FUNCTION);
-		if (ndefs > 0)
-			com_addoparg(c, SET_FUNC_ARGS, argcount);
+		com_addoparg(c, MAKE_FUNCTION, ndefs);
 		com_addopname(c, STORE_NAME, CHILD(n, 1));
 		DECREF(v);
 	}
@@ -2145,8 +2225,8 @@
 	else {
 		i = com_addconst(c, v);
 		com_addoparg(c, LOAD_CONST, i);
-		com_addbyte(c, BUILD_FUNCTION);
-		com_addbyte(c, UNARY_CALL);
+		com_addoparg(c, MAKE_FUNCTION, 0);
+		com_addoparg(c, CALL_FUNCTION, 0);
 		com_addbyte(c, BUILD_CLASS);
 		com_addopname(c, STORE_NAME, CHILD(n, 1));
 		DECREF(v);
@@ -2312,7 +2392,7 @@
 	if (TYPE(CHILD(n, 0)) == LPAR)
 		com_fplist(c, CHILD(n, 1));
 	else
-		com_addopname(c, STORE_NAME, CHILD(n, 0));
+		com_addoparg(c, STORE_FAST, com_newlocal(c, STR(CHILD(n, 0))));
 }
 
 static void
@@ -2337,53 +2417,87 @@
 	struct compiling *c;
 	node *n;
 {
-	int nch, op, nargs, i, t;
+	int nch, i;
+	int complex = 0;
 	REQ(n, varargslist);
 	/* varargslist:
-		(fpdef ['=' test] ',')* '*' NAME ..... |
-		fpdef ['=' test] (',' fpdef ['=' test])* [','] */
+		(fpdef ['=' test] ',')* (fpdef ['=' test] | '*' .....) */
 	nch = NCH(n);
-	op = UNPACK_ARG;
-	nargs = 0;
+	/* Enter all arguments in table of locals */
 	for (i = 0; i < nch; i++) {
-		if (TYPE(CHILD(n, i)) == STAR) {
-			nch = i;
-			if (TYPE(CHILD(n, i+1)) != STAR)
-				op = UNPACK_VARARG;
+		node *ch = CHILD(n, i);
+		node *fp;
+		char *name;
+		if (TYPE(ch) == STAR)
 			break;
+		REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
+		fp = CHILD(ch, 0);
+		if (TYPE(fp) == NAME)
+			name = STR(fp);
+		else {
+			name = "";
+			complex= 1;
 		}
-		nargs++;
-		i++;
-		if (i >= nch)
+		com_newlocal(c, name);
+		c->c_argcount++;
+		if (++i >= nch)
 			break;
-		t = TYPE(CHILD(n, i));
-		if (t == EQUAL) {
+		ch = CHILD(n, i);
+		if (TYPE(ch) == EQUAL)
 			i += 2;
-			if (i >= nch)
-				break;
-			t = TYPE(CHILD(n, i));
-		}
-		if (t != COMMA)
-			break;
+		else
+			REQ(ch, COMMA);
 	}
-	com_addoparg(c, op, nargs);
-	for (i = 0; i < nch; i++) {
-		com_fpdef(c, CHILD(n, i));
-		i++;
-		if (i >= nch)
-			break;
-		t = TYPE(CHILD(n, i));
-		if (t == EQUAL) {
-			i += 2;
-			if (i >= nch)
-				break;
-			t = TYPE(CHILD(n, i));
+	/* Handle *arguments */
+	if (i < nch) {
+		node *ch;
+		ch = CHILD(n, i);
+		REQ(ch, STAR);
+		ch = CHILD(n, i+1);
+		if (TYPE(ch) == NAME) {
+			c->c_flags |= CO_VARARGS;
+			i += 3;
+			com_newlocal(c, STR(ch));
 		}
-		if (t != COMMA)
-			break;
 	}
-	if (op == UNPACK_VARARG)
-		com_addopname(c, STORE_NAME, CHILD(n, nch+1));
+	/* Handle **keywords */
+	if (i < nch) {
+		node *ch;
+		ch = CHILD(n, i);
+		REQ(ch, STAR);
+		ch = CHILD(n, i+1);
+		REQ(ch, STAR);
+		ch = CHILD(n, i+2);
+		REQ(ch, NAME);
+		c->c_flags |= CO_VARKEYWORDS;
+		com_newlocal(c, STR(ch));
+	}
+	if (complex) {
+		/* Generate code for complex arguments only after
+		   having counted the simple arguments */
+		int ilocal = 0;
+		for (i = 0; i < nch; i++) {
+			node *ch = CHILD(n, i);
+			node *fp;
+			char *name;
+			if (TYPE(ch) == STAR)
+				break;
+			REQ(ch, fpdef); /* fpdef: NAME | '(' fplist ')' */
+			fp = CHILD(ch, 0);
+			if (TYPE(fp) != NAME) {
+				com_addoparg(c, LOAD_FAST, ilocal);
+				com_fpdef(c, ch);
+			}
+			ilocal++;
+			if (++i >= nch)
+				break;
+			ch = CHILD(n, i);
+			if (TYPE(ch) == EQUAL)
+				i += 2;
+			else
+				REQ(ch, COMMA);
+		}
+	}
 }
 
 static void
@@ -2424,12 +2538,11 @@
 		(void) com_addconst(c, doc);
 		DECREF(doc);
 	}
-	com_addoparg(c, RESERVE_FAST, com_addconst(c, None)); /* Patched! */
+	else
+		(void) com_addconst(c, None); /* No docstring */
 	ch = CHILD(n, 2); /* parameters: '(' [varargslist] ')' */
 	ch = CHILD(ch, 1); /* ')' | varargslist */
-	if (TYPE(ch) == RPAR)
-		com_addoparg(c, UNPACK_ARG, 0);
-	else
+	if (TYPE(ch) == varargslist)
 		com_arglist(c, ch);
 	c->c_infunction = 1;
 	com_node(c, CHILD(n, 4));
@@ -2444,21 +2557,18 @@
 	node *n;
 {
 	node *ch;
-	REQ(n, lambdef); /* lambdef: 'lambda' [parameters] ':' test */
+	REQ(n, lambdef); /* lambdef: 'lambda' [varargslist] ':' test */
 	c->c_name = "<lambda>";
 
 	ch = CHILD(n, 1);
-	(void) com_addconst(c, None);
-	if (TYPE(ch) == COLON) {
-		com_addoparg(c, UNPACK_ARG, 0);
-		com_node(c, CHILD(n, 2));
-	}
-	else {
-		com_addoparg(c, RESERVE_FAST, com_addconst(c, None));
+	(void) com_addconst(c, None); /* No docstring */
+	if (TYPE(ch) == varargslist) {
 		com_arglist(c, ch);
-		com_node(c, CHILD(n, 3));
+		ch = CHILD(n, 3);
 	}
-
+	else
+		ch = CHILD(n, 2);
+	com_node(c, ch);
 	com_addbyte(c, RETURN_VALUE);
 }
 
@@ -2544,34 +2654,31 @@
    The latter instructions are much faster because they don't need to
    look up the variable name in a dictionary.
 
-   To find all local variables, we check all STORE_NAME, IMPORT_FROM and
-   DELETE_NAME instructions.  This yields all local variables, including
-   arguments, function definitions, class definitions and import
-   statements.
+   To find all local variables, we check all STORE_NAME, IMPORT_FROM
+   and DELETE_NAME instructions.  This yields all local variables,
+   function definitions, class definitions and import statements.
+   Argument names have already been entered into the list by the
+   special processing for the argument list.
 
    All remaining LOAD_NAME instructions must refer to non-local (global
    or builtin) variables, so are replaced by LOAD_GLOBAL.
 
    There are two problems:  'from foo import *' and 'exec' may introduce
    local variables that we can't know while compiling.  If this is the
-   case, we don't optimize at all (this rarely happens, since exec is
-   rare, & this form of import statement is mostly used at the module
-   level).
+   case, we can still optimize bona fide locals (since those
+   statements will be surrounded by fast_2_locals() and
+   locals_2_fast()), but we can't change LOAD_NAME to LOAD_GLOBAL.
 
-   NB: this modifies the string object co->co_code!
-*/
+   NB: this modifies the string object c->c_code!  */
 
 static void
 optimize(c)
 	struct compiling *c;
 {
 	unsigned char *next_instr, *cur_instr;
-	object *locals;
-	int nlocals;
 	int opcode;
 	int oparg;
 	object *name;
-	int fast_reserved;
 	object *error_type, *error_value, *error_traceback;
 	
 #define NEXTOP()	(*next_instr++)
@@ -2579,53 +2686,33 @@
 #define GETITEM(v, i)	(getlistitem((v), (i)))
 #define GETNAMEOBJ(i)	(GETITEM(c->c_names, (i)))
 	
-	locals = newdictobject();
-	if (locals == NULL) {
-		c->c_errors++;
-		return;
-	}
-	nlocals = 0;
-
 	err_fetch(&error_type, &error_value, &error_traceback);
+
+	c->c_flags |= CO_OPTIMIZED;
 	
 	next_instr = (unsigned char *) getstringvalue(c->c_code);
 	for (;;) {
 		opcode = NEXTOP();
 		if (opcode == STOP_CODE)
 			break;
-		if (opcode == EXEC_STMT)
-			goto end; /* Don't optimize if exec present */
 		if (HAS_ARG(opcode))
 			oparg = NEXTARG();
-		if (opcode == STORE_NAME || opcode == DELETE_NAME ||
-		    opcode == IMPORT_FROM) {
-			object *v;
-			name = GETNAMEOBJ(oparg);
-			if (dict2lookup(locals, name) != NULL)
-				continue;
-			err_clear();
-			v = newintobject(nlocals);
-			if (v == NULL) {
-				c->c_errors++;
-				goto err;
-			}
-			nlocals++;
-			if (dict2insert(locals, name, v) != 0) {
-				DECREF(v);
-				c->c_errors++;
-				goto err;
-			}
-			DECREF(v);
+		switch (opcode) {
+		case STORE_NAME:
+		case DELETE_NAME:
+		case IMPORT_FROM:
+			com_addlocal_o(c, GETNAMEOBJ(oparg));
+			break;
+		case EXEC_STMT:
+			c->c_flags &= ~CO_OPTIMIZED;
+			break;
 		}
 	}
 	
-	if (dictlookup(locals, "*") != NULL) {
-		/* Don't optimize anything */
-		goto end;
-	}
+	if (dictlookup(c->c_locals, "*") != NULL)
+		c->c_flags &= ~CO_OPTIMIZED;
 	
 	next_instr = (unsigned char *) getstringvalue(c->c_code);
-	fast_reserved = 0;
 	for (;;) {
 		cur_instr = next_instr;
 		opcode = NEXTOP();
@@ -2633,45 +2720,17 @@
 			break;
 		if (HAS_ARG(opcode))
 			oparg = NEXTARG();
-		if (opcode == RESERVE_FAST) {
-			int i;
-			object *localmap = newtupleobject(nlocals);
-			int pos;
-			object *key, *value;
-			if (localmap == NULL) { /* XXX mask error */
-				err_clear();
-				continue;
-			}
-			pos = 0;
-			while (mappinggetnext(locals, &pos, &key, &value)) {
-				int j;
-				if (!is_intobject(value))
-					continue;
-				j = getintvalue(value);
-				if (0 <= j && j < nlocals) {
-					INCREF(key);
-					settupleitem(localmap, j, key);
-				}
-			}
-			i = com_addconst(c, localmap);
-			cur_instr[1] = i & 0xff;
-			cur_instr[2] = (i>>8) & 0xff;
-			fast_reserved = 1;
-			DECREF(localmap);
-			continue;
-		}
-		if (!fast_reserved)
-			continue;
 		if (opcode == LOAD_NAME ||
 		    opcode == STORE_NAME ||
 		    opcode == DELETE_NAME) {
 			object *v;
 			int i;
 			name = GETNAMEOBJ(oparg);
-			v = dict2lookup(locals, name);
+			v = dict2lookup(c->c_locals, name);
 			if (v == NULL) {
 				err_clear();
-				if (opcode == LOAD_NAME)
+				if (opcode == LOAD_NAME &&
+				    (c->c_flags&CO_OPTIMIZED))
 					cur_instr[0] = LOAD_GLOBAL;
 				continue;
 			}
@@ -2686,10 +2745,8 @@
 		}
 	}
 
- end:
-	err_restore(error_type, error_value, error_traceback);
- err:
-	DECREF(locals);
+	if (c->c_errors == 0)
+		err_restore(error_type, error_value, error_traceback);
 }
 
 codeobject *
@@ -2703,18 +2760,35 @@
 		return NULL;
 	compile_node(&sc, n);
 	com_done(&sc);
-	if ((TYPE(n) == funcdef || TYPE(n) == lambdef) && sc.c_errors == 0)
+	if ((TYPE(n) == funcdef || TYPE(n) == lambdef) && sc.c_errors == 0) {
 		optimize(&sc);
+		sc.c_flags |= CO_NEWLOCALS;
+	}
+	else if (TYPE(n) == classdef)
+		sc.c_flags |= CO_NEWLOCALS;
 	co = NULL;
 	if (sc.c_errors == 0) {
-		object *v, *w;
-		v = newstringobject(sc.c_filename);
-		w = newstringobject(sc.c_name);
-		if (v != NULL && w != NULL)
-			co = newcodeobject(sc.c_code, sc.c_consts,
-					   sc.c_names, v, w);
-		XDECREF(v);
-		XDECREF(w);
+		object *consts, *names, *varnames, *filename, *name;
+		consts = listtuple(sc.c_consts);
+		names = listtuple(sc.c_names);
+		varnames = listtuple(sc.c_varnames);
+		filename = newstringobject(sc.c_filename);
+		name = newstringobject(sc.c_name);
+		if (!err_occurred())
+			co = newcodeobject(sc.c_argcount,
+					   sc.c_nlocals,
+					   sc.c_flags,
+					   sc.c_code,
+					   consts,
+					   names,
+					   varnames,
+					   filename,
+					   name);
+		XDECREF(consts);
+		XDECREF(names);
+		XDECREF(varnames);
+		XDECREF(filename);
+		XDECREF(name);
 	}
 	com_free(&sc);
 	return co;
diff --git a/Python/import.c b/Python/import.c
index 4239e12..4a4c3d4 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -54,7 +54,7 @@
    Apple MPW compiler swaps their values, botching string constants */
 /* XXX Perhaps the magic number should be frozen and a version field
    added to the .pyc file header? */
-#define MAGIC (0x4127L | ((long)'\r'<<16) | ((long)'\n'<<24))
+#define MAGIC (11913 | ((long)'\r'<<16) | ((long)'\n'<<24))
 
 object *import_modules; /* This becomes sys.modules */
 
@@ -159,7 +159,7 @@
 		if (dictinsert(d, "__builtins__", getbuiltins()) != 0)
 			return NULL;
 	}
-	v = eval_code((codeobject *)co, d, d, d, (object *)NULL);
+	v = eval_code((codeobject *)co, d, d); /* XXX owner? */
 	if (v == NULL)
 		return NULL;
 	DECREF(v);
diff --git a/Python/marshal.c b/Python/marshal.c
index 8c01020..05265f5 100644
--- a/Python/marshal.c
+++ b/Python/marshal.c
@@ -44,7 +44,7 @@
 #define TYPE_TUPLE	'('
 #define TYPE_LIST	'['
 #define TYPE_DICT	'{'
-#define TYPE_CODE	'C'
+#define TYPE_CODE	'c'
 #define TYPE_UNKNOWN	'?'
 
 typedef struct {
@@ -187,9 +187,13 @@
 	else if (is_codeobject(v)) {
 		codeobject *co = (codeobject *)v;
 		w_byte(TYPE_CODE, p);
+		w_short(co->co_argcount, p);
+		w_short(co->co_nlocals, p);
+		w_short(co->co_flags, p);
 		w_object((object *)co->co_code, p);
 		w_object(co->co_consts, p);
 		w_object(co->co_names, p);
+		w_object(co->co_varnames, p);
 		w_object(co->co_filename, p);
 		w_object(co->co_name, p);
 	}
@@ -374,14 +378,20 @@
 	
 	case TYPE_CODE:
 		{
+			int argcount = r_short(p);
+			int nlocals = r_short(p);
+			int flags = r_short(p);
 			object *code = r_object(p);
 			object *consts = r_object(p);
 			object *names = r_object(p);
+			object *varnames = r_object(p);
 			object *filename = r_object(p);
 			object *name = r_object(p);
 			if (!err_occurred()) {
-				v = (object *) newcodeobject(code,
-						consts, names, filename, name);
+				v = (object *) newcodeobject(
+					argcount, nlocals, flags, 
+					code, consts, names, varnames,
+					filename, name);
 			}
 			else
 				v = NULL;
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 2268c71..f087545 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -430,7 +430,7 @@
 	freetree(n);
 	if (co == NULL)
 		return NULL;
-	v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL);
+	v = eval_code(co, globals, locals);
 	DECREF(co);
 	return v;
 }
@@ -462,7 +462,7 @@
 		return NULL;
 	}
 	co = (codeobject *)v;
-	v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL);
+	v = eval_code(co, globals, locals);
 	DECREF(co);
 	return v;
 }
@@ -603,16 +603,9 @@
 	object *exitfunc = sysget("exitfunc");
 
 	if (exitfunc) {
-		object *arg;
 		object *res;
 		sysset("exitfunc", (object *)NULL);
-		arg = newtupleobject(0);
-		if (arg == NULL)
-			res = NULL;
-		else {
-			res = call_object(exitfunc, arg);
-			DECREF(arg);
-		}
+		res = call_object(exitfunc, (object *)NULL);
 		if (res == NULL) {
 			fprintf(stderr, "Error in sys.exitfunc:\n");
 			print_error();
diff --git a/Python/traceback.c b/Python/traceback.c
index 1ab880a..1f803da 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -68,7 +68,10 @@
 	DEL(tb);
 }
 
-static typeobject Tracebacktype = {
+#define Tracebacktype PyTraceback_Type
+#define is_tracebackobject PyTraceback_Check
+
+typeobject Tracebacktype = {
 	OB_HEAD_INIT(&Typetype)
 	0,
 	"traceback",
@@ -85,8 +88,6 @@
 	0,		/*tp_as_mapping*/
 };
 
-#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype)
-
 static tracebackobject *
 newtracebackobject(next, frame, lasti, lineno)
 	tracebackobject *next;