<commit_before>#include "pycompiler.h"
#include "../pycencoding.h"
#include "../processor.h"
#include "../dispatcher.h"
#include "../mergepoints.h"
#include "../codemanager.h"

#include "../Objects/pabstract.h"
#include "../Objects/pintobject.h"
#include "../Objects/plongobject.h"
#include "../Objects/ptupleobject.h"
#include "../Objects/plistobject.h"
#include "../Objects/pdictobject.h"
#include "../Objects/pfuncobject.h"

#include <eval.h>
#include "pycinternal.h"


#define KNOWN_VAR(type, varname, loc)   \
    type varname = (type)(KNOWN_SOURCE(loc)->value)


/*****************************************************************/
 /***   Meta functions                                          ***/

DEFINEVAR PyObject* Psyco_Meta_Dict = NULL;

DEFINEFN
void Psyco_DefineMeta(void* c_function, void* psyco_function)
{
	PyObject* key;
	PyObject* value;
	if (Psyco_Meta_Dict == NULL) {
		Psyco_Meta_Dict = PyDict_New();
		if (Psyco_Meta_Dict == NULL)
			return;
	}
        extra_assert(c_function != NULL);
	key = PyInt_FromLong((long) c_function);
	if (key != NULL) {
		value = PyInt_FromLong((long) psyco_function);
		if (value != NULL) {
			PyDict_SetItem(Psyco_Meta_Dict, key, value);
			Py_DECREF(value);
		}
		Py_DECREF(key);
	}
}

DEFINEFN
PyObject* Psyco_DefineMetaModule(char* modulename)
{
	PyObject* module = PyImport_ImportModule(modulename);
	if (module == NULL) {
		PyErr_Clear();
		debug_printf(("psyco: note: module %s not found\n",
			      modulename));
	}
	else {
#if VERBOSE_LEVEL > 1
		debug_printf(("psyco: activated module %s\n", modulename));
#endif
	}
	return module;
}

DEFINEFN
PyObject* Psyco_GetModuleObject(PyObject* module, char* name,
				PyTypeObject* expected_type)
{
	PyObject* fobj;
	if (module == NULL)
		return NULL;
	
	fobj = PyObject_GetAttrString(module, name);
	if (fobj == NULL) {
		debug_printf(("psyco: note: %s.%s not found\n",
			      PyModule_GetName(module), name));
		PyErr_Clear();
		return NULL;
	}
	if (expected_type != NULL && !PyObject_TypeCheck(fobj, expected_type)) {
		debug_printf(("psyco: note: %s.%s is of type %200s instead of "
			      "%200s\n", PyModule_GetName(module), name,
			      fobj->ob_type->tp_name, expected_type->tp_name));
		Py_DECREF(fobj);
		fobj = NULL;
	}
	return fobj;
}

DEFINEFN
PyCFunction Psyco_DefineModuleFn(PyObject* module, char* meth_name,
				 int meth_flags, void* meta_fn)
{
	PyCFunction f;
	PyObject* fobj = Psyco_GetModuleObject(module, meth_name,
					       &PyCFunction_Type);
	if (fobj == NULL)
		return NULL;

	if (PyCFunction_GET_FLAGS(fobj) != meth_flags) {
		f = NULL;
		debug_printf(("psyco: note: %s.%s built-in has wrong "
			      "meth_flags\n", PyModule_GetName(module),
			      meth_name));
	}
	else {
		f = PyCFunction_GET_FUNCTION(fobj);
		Psyco_DefineMeta(f, meta_fn);
	}
	Py_DECREF(fobj);
	return f;
}


#define FORGET_REF     if (has_rtref(vi->source))			\
			    vi->source = remove_rtref(vi->source)

DEFINEFN
vinfo_t* generic_call_check(PsycoObject* po, int flags, vinfo_t* vi)
{
	condition_code_t cc;
	
	switch (flags & CfPyErrMask) {

	case CfPyErrIfNull:   /* a return == 0 (or NULL) means an error */
                cc = integer_cmp_i(po, vi, 0, Py_EQ);
		break;

	case CfPyErrIfNonNull:   /* a return != 0 means an error */
                cc = integer_cmp_i(po, vi, 0, Py_NE);
		break;

	case CfPyErrIfNeg:   /* a return < 0 means an error */
		cc = integer_cmp_i(po, vi, 0, Py_LT);
		break;

	case CfPyErrIfMinus1:     /* only -1 means an error */
		cc = integer_cmp_i(po, vi, -1, Py_EQ);
		break;

	case CfPyErrCheck:    /* always check with PyErr_Occurred() */
		cc = integer_NON_NULL(po, psyco_PyErr_Occurred(po));
		break;

	case CfPyErrCheckMinus1:   /* use PyErr_Occurred() if return is -1 */
		cc = integer_cmp_i(po, vi, -1, Py_NE);
		if (cc == CC_ERROR)
			goto Error;
		if (runtime_condition_t(po, cc))
			return vi;   /* result is not -1, ok */
		cc = integer_NON_NULL(po, psyco_PyErr_Occurred(po));
		break;

        case CfPyErrCheckNeg:   /* use PyErr_Occurred() if return is < 0 */
		cc = integer_cmp_i(po, vi, 0, Py_GE);
		if (cc == CC_ERROR)
			goto Error;
		if (runtime_condition_t(po, cc))
			return vi;   /* result is >= 0, ok */
		cc = integer_NON_NULL(po, psyco_PyErr_Occurred(po));
		break;

	case CfPyErrNotImplemented:   /* test for a Py_NotImplemented result */
		cc = integer_cmp_i(po, vi, (long) Py_NotImplemented, Py_EQ);
		if (cc == CC_ERROR)
			goto Error;
		if (runtime_condition_f(po, cc)) {
			/* result is Py_NotImplemented */
			vinfo_decref(vi, po);
			return psyco_vi_NotImplemented();
		}
		cc = integer_cmp_i(po, vi, 0, Py_EQ);
		break;

#if HAVE_GENERATORS
	case CfPyErrIterNext:    /* specially for tp_iternext slots */
		cc = integer_cmp_i(po, vi, 0, Py_NE);
		if (cc == CC_ERROR)
			goto Error;
		if (runtime_condition_t(po, cc))
			return vi;   /* result is not 0, ok */
		
		FORGET_REF;  /* NULL result */
		vinfo_decref(vi, po);
		cc = integer_NON_NULL(po, psyco_PyErr_Occurred(po));
		if (cc == CC_ERROR || runtime_condition_f(po, cc))
			goto PythonError;  /* PyErr_Occurred() returns true */

		/* NULL result with no error set; it is the end of the
		   iteration. Raise a pseudo PyErr_StopIteration. */
		PycException_SetVInfo(po, PyExc_StopIteration, psyco_vi_None());
		return NULL;
#endif

	case CfPyErrAlways:   /* always set an exception */
		cc = CC_ALWAYS_TRUE;
		break;

	default:
		return vi;
	}
	
	if (cc == CC_ERROR || runtime_condition_f(po, cc)) {

	   Error:
		if ((flags & CfReturnMask) == CfReturnRef) {
			/* in case of error, 'vi' is not a real
			   reference, so forget it */
			FORGET_REF;
		}
		vinfo_decref(vi, po);
		vi = NULL;
		
		/* We have detected that a Python exception must be set at
		   this point. */
	   PythonError:
		PycException_Raise(po, vinfo_new(VirtualTime_New(&ERtPython)),
				   NULL);
	}
	return vi;
}
#undef FORGET_REF

DEFINEFN
vinfo_t* Psyco_Meta1x(PsycoObject* po, void* c_function, int flags,
		      const char* arguments, long a1)
{
	void* psyco_fn = Psyco_Lookup(c_function);
	if (psyco_fn == NULL) {
		return psyco_generic_call(po, c_function, flags, arguments,
					  a1);
        }
	else
		return ((vinfo_t*(*)(PsycoObject*, long))(psyco_fn))
			(po, a1);
}

DEFINEFN
vinfo_t* Psyco_Meta2x(PsycoObject* po, void* c_function, int flags,
		      const char* arguments, long a1, long a2)
{
	void* psyco_fn = Psyco_Lookup(c_function);
	if (psyco_fn == NULL)
		return psyco_generic_call(po, c_function, flags, arguments,
					  a1, a2);
	else
		return ((vinfo_t*(*)(PsycoObject*, long, long))(psyco_fn))
			(po, a1, a2);
}

DEFINEFN
vinfo_t* Psyco_Meta3x(PsycoObject* po, void* c_function, int flags,
		      const char* arguments, long a1, long a2, long a3)
{
	void* psyco_fn = Psyco_Lookup(c_function);
	if (psyco_fn == NULL)
		return psyco_generic_call(po, c_function, flags, arguments,
					  a1, a2, a3);
	else
		return ((vinfo_t*(*)(PsycoObject*, long, long, long))(psyco_fn))
			(po, a1, a2, a3);
}

DEFINEFN
vinfo_t* Psyco_Meta4x(PsycoObject* po, void* c_function, int flags,
			     const char* arguments,
			     long a1, long a2, long a3, long a4)
{
	void* psyco_fn = Psyco_Lookup(c_function);
	if (psyco_fn == NULL)
		return psyco_generic_call(po, c_function, flags, arguments,
					   a1, a2, a3, a4);
	else
		return ((vinfo_t*(*)(PsycoObject*, long, long,
				     long, long))(psyco_fn))
			(po, a1, a2, a3, a4);
}


/***************************************************************/
 /***   pyc_data_t                                            ***/


DEFINEFN
void pyc_data_build(PsycoObject* po, PyObject* merge_points)
{
	/* rebuild the data in the pyc_data_t */
	int i;
        PyCodeObject* co = po->pr.co;
	int stack_base = po->vlocals.count - co->co_stacksize;
	for (i=stack_base; i<po->vlocals.count; i++)
		if (po->vlocals.items[i] == NULL)
			break;
	po->pr.stack_base = stack_base;
	po->pr.stack_level = i - stack_base;
	po->pr.merge_points = merge_points;
}

static void block_setup(PsycoObject* po, int type, int handler, int level)
{
  PyTryBlock *b;
  if (po->pr.iblock >= CO_MAXBLOCKS)
    Py_FatalError("block stack overflow");
  b = &po->pr.blockstack[po->pr.iblock++];
  b->b_type = type;
  b->b_level = level;
  b->b_handler = handler;
}

static PyTryBlock* block_pop(PsycoObject* po)
{
  if (po->pr.iblock <= 0)
    Py_FatalError("block stack underflow");
  return &po->pr.blockstack[--po->pr.iblock];
}


/*****************************************************************/
 /***   Compile-time Pseudo exceptions                          ***/


DEFINEVAR source_virtual_t ERtPython;  /* Exception raised by Python */
DEFINEVAR source_virtual_t EReturn;    /* 'return' statement */
DEFINEVAR source_virtual_t EBreak;     /* 'break' statement */
DEFINEVAR source_virtual_t EContinue;  /* 'continue' statement */

DEFINEFN
void PycException_SetString(PsycoObject* po, PyObject* e, const char* text)
{
	PyObject* s = PyString_FromString(text);
	if (s == NULL)
		OUT_OF_MEMORY();
	PycException_SetObject(po, e, s);
}

DEFINEFN
void PycException_SetObject(PsycoObject* po, PyObject* e, PyObject* v)
{
	PycException_Raise(po, vinfo_new(CompileTime_New((long) e)),
			   vinfo_new(CompileTime_NewSk(sk_new((long) v,
                                                              SkFlagPyObj))));
}

DEFINEFN
void PycException_SetVInfo(PsycoObject* po, PyObject* e, vinfo_t* v)
{
	PycException_Raise(po, vinfo_new(CompileTime_New((long) e)), v);
}

DEFINEFN
void PycException_Promote(PsycoObject* po, vinfo_t* vi, c_promotion_t* promotion)
{
	vinfo_incref(vi);
	PycException_Raise(po, vinfo_new(VirtualTime_New(&promotion->header)),
			   vi);
}

#if !HAVE_PyString_FromFormatV
/* This code is copied from Python 2.2. */
PyObject *
PyString_FromFormatV(const char *format, va_list vargs)
{
	va_list count;
	int n = 0;
	const char* f;
	char *s;
	PyObject* string;

#ifdef VA_LIST_IS_ARRAY
	memcpy(count, vargs, sizeof(va_list));
#else
	count = vargs;
#endif
	/* step 1: figure out how large a buffer we need */
	for (f = format; *f; f++) {
		if (*f == '%') {
			const char* p = f;
			while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
				;

			/* skip the 'l' in %ld, since it doesn't change the
			   width.  although only %d is supported (see
			   "expand" section below), others can be easily
			   added */
			if (*f == 'l' && *(f+1) == 'd')
				++f;
			
			switch (*f) {
			case 'c':
				(void)va_arg(count, int);
				/* fall through... */
			case '%':
				n++;
				break;
			case 'd': case 'i': case 'x':
				(void) va_arg(count, int);
				/* 20 bytes is enough to hold a 64-bit
				   integer.  Decimal takes the most space.
				   This isn't enough for octal. */
				n += 20;
				break;
			case 's':
				s = va_arg(count, char*);
				n += strlen(s);
				break;
			case 'p':
				(void) va_arg(count, int);
				/* maximum 64-bit pointer representation:
				 * 0xffffffffffffffff
				 * so 19 characters is enough.
				 * XXX I count 18 -- what's the extra for?
				 */
				n += 19;
				break;
			default:
				/* if we stumble upon an unknown
				   formatting code, copy the rest of
				   the format string to the output
				   string. (we cannot just skip the
				   code, since there's no way to know
				   what's in the argument list) */ 
				n += strlen(p);
				goto expand;
			}
		} else
			n++;
	}
 expand:
	/* step 2: fill the buffer */
	/* Since we've analyzed how much space we need for the worst case,
	   use sprintf directly instead of the slower PyOS_snprintf. */
	string = PyString_FromStringAndSize(NULL, n);
	if (!string)
		return NULL;
	
	s = PyString_AsString(string);

	for (f = format; *f; f++) {
		if (*f == '%') {
			const char* p = f++;
			int i, longflag = 0;
			/* parse the width.precision part (we're only
			   interested in the precision value, if any) */
			n = 0;
			while (isdigit(Py_CHARMASK(*f)))
				n = (n*10) + *f++ - '0';
			if (*f == '.') {
				f++;
				n = 0;
				while (isdigit(Py_CHARMASK(*f)))
					n = (n*10) + *f++ - '0';
			}
			while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
				f++;
			/* handle the long flag, but only for %ld.  others
			   can be added when necessary. */
			if (*f == 'l' && *(f+1) == 'd') {
				longflag = 1;
				++f;
			}
			
			switch (*f) {
			case 'c':
				*s++ = va_arg(vargs, int);
				break;
			case 'd':
				if (longflag)
					sprintf(s, "%ld", va_arg(vargs, long));
				else
					sprintf(s, "%d", va_arg(vargs, int));
				s += strlen(s);
				break;
			case 'i':
				sprintf(s, "%i", va_arg(vargs, int));
				s += strlen(s);
				break;
			case 'x':
				sprintf(s, "%x", va_arg(vargs, int));
				s += strlen(s);
				break;
			case 's':
				p = va_arg(vargs, char*);
				i = strlen(p);
				if (n > 0 && i > n)
					i = n;
				memcpy(s, p, i);
				s += i;
				break;
			case 'p':
				sprintf(s, "%p", va_arg(vargs, void*));
				/* %p is ill-defined:  ensure leading 0x. */
				if (s[1] == 'X')
					s[1] = 'x';
				else if (s[1] != 'x') {
					memmove(s+2, s, strlen(s)+1);
					s[0] = '0';
					s[1] = 'x';
				}
				s += strlen(s);
				break;
			case '%':
				*s++ = '%';
				break;
			default:
				strcpy(s, p);
				s += strlen(s);
				goto end;
			}
		} else
			*s++ = *f;
	}
	
 end:
	_PyString_Resize(&string, s - PyString_AS_STRING(string));
	return string;
}
#endif /* !HAVE_PyString_FromFormatV */

DEFINEFN
void PycException_SetFormat(PsycoObject* po, PyObject* e, const char* fmt, ...)
{
	PyObject* s;
	va_list vargs;

#ifdef HAVE_STDARG_PROTOTYPES
	va_start(vargs, fmt);
#else
	va_start(vargs);
#endif
	s = PyString_FromFormatV(fmt, vargs);
	va_end(vargs);

	if (s == NULL)
		OUT_OF_MEMORY();
	PycException_SetObject(po, e, s);
}

DEFINEFN
vinfo_t* PycException_Matches(PsycoObject* po, PyObject* e)
{
	vinfo_t* result;
	if (PycException_Is(po, &ERtPython)) {
		/* Exception raised by Python, emit a call to
		   PyErr_ExceptionMatches() */
		result = psyco_generic_call(po, PyErr_ExceptionMatches,
					    CfReturnNormal, "l", (long) e);
	}
	else if (PycException_IsPython(po)) {
		/* Exception virtually set, that is, present in the PsycoObject
		   but not actually set at run-time by Python's PyErr_SetXxx */
		result = psyco_generic_call(po, PyErr_GivenExceptionMatches,
					    CfPure | CfReturnNormal,
					    "vl", po->pr.exc, (long) e);
	}
	else {   /* pseudo exceptions don't match real Python ones */
		result = psyco_vi_Zero();
	}
	return result;
}

inline void clear_pseudo_exception(PsycoObject* po)
{
	extra_assert(PycException_Occurred(po));
	if (po->pr.tb != NULL) {
		vinfo_decref(po->pr.tb, po);
		po->pr.tb = NULL;
	}
        if (po->pr.val != NULL) {
		vinfo_decref(po->pr.val, po);
		po->pr.val = NULL;
	}
	vinfo_decref(po->pr.exc, po);
	po->pr.exc = NULL;
}

DEFINEFN
void PycException_Clear(PsycoObject* po)
{
	if (PycException_Is(po, &ERtPython)) {
		/* Clear the Python exception set at run-time */
		psyco_call_void(po, PyErr_Clear);
	}
	clear_pseudo_exception(po);
}

DEFINEFN
void psyco_virtualize_exception(PsycoObject* po)
{
	/* fetch a Python exception set at compile-time (that is, now)
	   and turn into a pseudo-exception (typically to be re-raised
	   at run-time). */
	PyObject *exc, *val, *tb;
	vinfo_t *vexc, *vval, *vtb;
	PyErr_Fetch(&exc, &val, &tb);
	extra_assert(exc != NULL);

	vexc = vinfo_new(CompileTime_NewSk(sk_new((long) exc, SkFlagPyObj)));
	vval = vinfo_new(CompileTime_NewSk(sk_new((long) val, SkFlagPyObj)));
	vtb  = tb == NULL ? NULL :
	       vinfo_new(CompileTime_NewSk(sk_new((long) tb,  SkFlagPyObj)));
	PycException_Restore(po, vexc, vval, vtb);
}

static void cimpl_pyerr_fetch(PyObject* target[])
{
        extra_assert(PyErr_Occurred());
	PyErr_Fetch(target+0, target+1, target+2);
	if (target[0] == NULL) {
		target[0] = Py_None;
		Py_INCREF(Py_None);
	}
	if (target[1] == NULL) {
		target[1] = Py_None;
		Py_INCREF(Py_None);
	}
	if (target[2] == NULL) {
		target[2] = Py_None;
		Py_INCREF(Py_None);
	}
}

DEFINEFN
void cimpl_finalize_frame_locals(PyObject* f_exc_type,
				 PyObject* f_exc_value,
				 PyObject* f_exc_traceback)
{
	/* Called by code emitted by pycencoding.h when a function exits,
	   but only if f_exc_type!=NULL. Works like reset_exc_info() of
	   Python. */
	PyThreadState *tstate = PyThreadState_GET();
	PyObject *tmp_type, *tmp_value, *tmp_tb;

	/* This frame caught an exception */
	tmp_type = tstate->exc_type;
	tmp_value = tstate->exc_value;
	tmp_tb = tstate->exc_traceback;
	tstate->exc_type = f_exc_type;  /* references are transferred */
	tstate->exc_value = f_exc_value;
	tstate->exc_traceback = f_exc_traceback;
	Py_XDECREF(tmp_type);
	Py_XDECREF(tmp_value);
	Py_XDECREF(tmp_tb);
	/* For b/w compatibility */
	PySys_SetObject("exc_type", f_exc_type);
	PySys_SetObject("exc_value", f_exc_value);
	PySys_SetObject("exc_traceback", f_exc_traceback);
}

inline void cimpl_set_exc_info(PyObject* target[],
			       PyObject** f_exc_type,
			       PyObject** f_exc_value,
			       PyObject** f_exc_traceback)
{
	/* Equivalent of PyErr_NormalizeException() + set_exc_info() */
	PyThreadState *tstate = PyThreadState_GET();
        PyObject *type, *value, *tb;
	PyObject *tmp_type, *tmp_value, *tmp_tb;

        PyErr_NormalizeException(target+0, target+1, target+2);
        type = target[0];
        value = target[1];
	tb = target[2];

	if (*f_exc_type == NULL) {
		/* This frame didn't catch an exception before */
		/* Save previous exception of this thread in this frame */
		if (tstate->exc_type == NULL) {
			Py_INCREF(Py_None);
			tstate->exc_type = Py_None;
		}
		Py_INCREF(tstate->exc_type);
		Py_XINCREF(tstate->exc_value);
		Py_XINCREF(tstate->exc_traceback);
		*f_exc_type = tstate->exc_type;
		*f_exc_value = tstate->exc_value;
		*f_exc_traceback = tstate->exc_traceback;
	}
	/* Set new exception for this thread */
	tmp_type = tstate->exc_type;
	tmp_value = tstate->exc_value;
	tmp_tb = tstate->exc_traceback;
	Py_XINCREF(type);
	Py_XINCREF(value);
	Py_XINCREF(tb);
	tstate->exc_type = type;
	tstate->exc_value = value;
	tstate->exc_traceback = tb;
	Py_XDECREF(tmp_type);
	Py_XDECREF(tmp_value);
	Py_XDECREF(tmp_tb);
	/* For b/w compatibility */
	PySys_SetObject("exc_type", type);
	PySys_SetObject("exc_value", value);
	PySys_SetObject("exc_traceback", tb);
}

static void cimpl_pyerr_fetch_and_normalize(PyObject* target[],
					    PyObject** f_exc_type,
					    PyObject** f_exc_value,
					    PyObject** f_exc_traceback)
{
        extra_assert(PyErr_Occurred());
	PyErr_Fetch(target+0, target+1, target+2);
        cimpl_set_exc_info(target,
			   f_exc_type, f_exc_value, f_exc_traceback);
}

static void cimpl_pyerr_normalize(PyObject* exc, PyObject* val, PyObject* tb,
				  PyObject* target[],
				  PyObject** f_exc_type,
				  PyObject** f_exc_value,
				  PyObject** f_exc_traceback)
{
	target[0] = exc;  Py_INCREF(exc);
	target[1] = val;  Py_XINCREF(val);
	target[2] = tb;   Py_XINCREF(tb);
        cimpl_set_exc_info(target,
			   f_exc_type, f_exc_value, f_exc_traceback);
}

DEFINEFN
void PycException_Fetch(PsycoObject* po)
{
	if (PycException_Is(po, &ERtPython)) {
/* 		vinfo_t* exc = vinfo_new(SOURCE_DUMMY_WITH_REF); */
/* 		vinfo_t* val = vinfo_new(SOURCE_DUMMY_WITH_REF); */
/* 		vinfo_t* tb  = vinfo_new(SOURCE_DUMMY_WITH_REF); */
/* 		psyco_generic_call(po, PyErr_Fetch, CfNoReturnValue, */
/* 				   "rrr", exc, val, tb); */
/* 		vinfo_decref(tb, po); */
		vinfo_array_t* array = array_new(3);
		psyco_generic_call(po, cimpl_pyerr_fetch,
				   CfNoReturnValue, "A", array);
		clear_pseudo_exception(po);
		po->pr.exc = array->items[0];
		po->pr.val = array->items[1];  /* po->pr.val!=NULL after this */
		po->pr.tb  = array->items[2];  /* po->pr.tb!=NULL after this */
		array_release(array);
	}
}

inline bool PycException_FetchNormalize(PsycoObject* po)
{
	vinfo_t* result;
	vinfo_array_t* array = array_new(3);
	vinfo_array_t* f_exc = LOC_CONTINUATION->array;

        /* At runtime, we load the following data into the array:

           array[0] -- exc_type       new exception, normalized
           array[1] -- exc_value      new exception, normalized
           array[2] -- exc_traceback  new exception, normalized
        */
	extra_assert(f_exc->count >= 3);
	if (PycException_Is(po, &ERtPython)) {
		/* fetch and normalize the exception */
		result = psyco_generic_call(po, cimpl_pyerr_fetch_and_normalize,
					    CfNoReturnValue, "Arrr", array,
					    f_exc->items[0],
					    f_exc->items[1],
					    f_exc->items[2]);
	}
	else {
		char args[8];
		args[0] = 'v';
		args[1] = po->pr.val == NULL ? 'l' : 'v';
		args[2] = po->pr.tb  == NULL ? 'l' : 'v';
		args[3] = 'A';
		args[4] = 'r';
		args[5] = 'r';
		args[6] = 'r';
		args[7] = 0;
		/* normalize the already-given exception */
		result = psyco_generic_call(po, cimpl_pyerr_normalize,
					    CfNoReturnValue, args,
					    po->pr.exc, po->pr.val, po->pr.tb,
					    array,
					    f_exc->items[0],
					    f_exc->items[1],
					    f_exc->items[2]);
	}
	if (result == NULL) {
		array_release(array);
		return false;
	}
	clear_pseudo_exception(po);
	po->pr.exc = array->items[0];
	po->pr.val = array->items[1];  /* po->pr.val!=NULL after this */
	po->pr.tb  = array->items[2];  /* po->pr.tb!=NULL after this */
	array_release(array);
	return true;
}

static PyFrameObject* cimpl_new_frame(PyThreadState* tstate, PyCodeObject* code,
				      PyObject* globals, int lasti, int lineno)
{
	/* Make a minimalistic frame object, working around the specific
	   expectations of PyFrame_New(), which is the only reasonable way
	   to create frame objects (because of free lists etc) */
	PyFrameObject* result;
	PyFrameObject* back = tstate->frame;
	tstate->frame = NULL;  /* frame objects are not created in stack order
				  with Psyco, so it's probably better not to
				  create plain wrong chained lists */
	result = PyFrame_New(tstate, code, globals, NULL);
	tstate->frame = back;
	if (result != NULL) {
		result->f_lasti = lasti;
		result->f_lineno = lineno;
	}
	return result;
}

static void cimpl_rt_traceback(PyCodeObject* code, PyObject* globals,
			       int lasti, int lineno)
{
	PyThreadState* tstate = PyThreadState_GET();
	PyFrameObject* f = cimpl_new_frame(tstate, code, globals, lasti, lineno);
	/* an out-of-memory error just replaces the current exception */
	if (f != NULL) {
		PyTraceBack_Here(f);
		Py_DECREF(f);
	}
}

static PyObject* cimpl_vt_traceback(PyCodeObject* code, PyObject* globals,
				    int lasti, int lineno)
{
	/* This is a hack around the limited interface to tracebacks.
	   PyTraceBack_Here() seems to be the only clean way to create new
	   traceback objects. */
	PyObject* oldtb;
	PyObject* newtb;
	PyThreadState* tstate = PyThreadState_GET();
	PyFrameObject* f = cimpl_new_frame(tstate, code, globals, lasti, lineno);
	if (f == NULL) {
		/* out-of-memory error */
		Py_INCREF(Py_None);
		return Py_None;
	}
	oldtb = tstate->curexc_traceback;  /* might be NULL */
	Py_XINCREF(oldtb);
	if (PyTraceBack_Here(f)) {
		/* out-of-memory error */
		Py_XDECREF(oldtb);
		Py_DECREF(f);
		Py_INCREF(Py_None);
		return Py_None;
	}
	/* the new traceback is now in curexc_traceback */
	newtb = tstate->curexc_traceback;  /* extracts the reference */
	tstate->curexc_traceback = oldtb;  /* consumes the reference */
	Py_DECREF(f);
	return newtb;
}

inline void PsycoTraceBack_Here(PsycoObject* po, int lasti)
{
	if (PycException_Is(po, &ERtPython)) {
		/* Python exception is actually set at run-time */
		psyco_generic_call(po, cimpl_rt_traceback,
				   CfNoReturnValue, "lvl",
				   (long) po->pr.co, LOC_GLOBALS, lasti);
	}
	else {
		/* We only have a virtual-time exception (not set in Python),
		   so we build po->pr.tb without actually setting it either */
		extra_assert(po->pr.tb == NULL);
		po->pr.tb = psyco_generic_call(po, cimpl_vt_traceback,
					       CfReturnRef, "lvl",
					       (long) po->pr.co, LOC_GLOBALS,
					       lasti);
	}
}


 /***************************************************************/
/***                      Initialization                       ***/
 /***************************************************************/

DEFINEVAR source_known_t psyco_skNone;    /* known value 'Py_None' */
DEFINEVAR source_known_t psyco_skZero;    /* known value 0 */
DEFINEVAR source_known_t psyco_skOne;     /* known value 1 */
DEFINEVAR source_known_t psyco_skNotImplemented;

static PyObject* s_builtin_object;   /* intern string '__builtins__' */

INITIALIZATIONFN<commit_msg>line numbers in tracebacks fixed<commit_after>#include "pycompiler.h"
#include "../pycencoding.h"
#include "../processor.h"
#include "../dispatcher.h"
#include "../mergepoints.h"
#include "../codemanager.h"

#include "../Objects/pabstract.h"
#include "../Objects/pintobject.h"
#include "../Objects/plongobject.h"
#include "../Objects/ptupleobject.h"
#include "../Objects/plistobject.h"
#include "../Objects/pdictobject.h"
#include "../Objects/pfuncobject.h"

#include <eval.h>
#include "pycinternal.h"


#define KNOWN_VAR(type, varname, loc)   \
    type varname = (type)(KNOWN_SOURCE(loc)->value)


/*****************************************************************/
 /***   Meta functions                                          ***/

DEFINEVAR PyObject* Psyco_Meta_Dict = NULL;

DEFINEFN
void Psyco_DefineMeta(void* c_function, void* psyco_function)
{
	PyObject* key;
	PyObject* value;
	if (Psyco_Meta_Dict == NULL) {
		Psyco_Meta_Dict = PyDict_New();
		if (Psyco_Meta_Dict == NULL)
			return;
	}
        extra_assert(c_function != NULL);
	key = PyInt_FromLong((long) c_function);
	if (key != NULL) {
		value = PyInt_FromLong((long) psyco_function);
		if (value != NULL) {
			PyDict_SetItem(Psyco_Meta_Dict, key, value);
			Py_DECREF(value);
		}
		Py_DECREF(key);
	}
}

DEFINEFN
PyObject* Psyco_DefineMetaModule(char* modulename)
{
	PyObject* module = PyImport_ImportModule(modulename);
	if (module == NULL) {
		PyErr_Clear();
		debug_printf(("psyco: note: module %s not found\n",
			      modulename));
	}
	else {
#if VERBOSE_LEVEL > 1
		debug_printf(("psyco: activated module %s\n", modulename));
#endif
	}
	return module;
}

DEFINEFN
PyObject* Psyco_GetModuleObject(PyObject* module, char* name,
				PyTypeObject* expected_type)
{
	PyObject* fobj;
	if (module == NULL)
		return NULL;
	
	fobj = PyObject_GetAttrString(module, name);
	if (fobj == NULL) {
		debug_printf(("psyco: note: %s.%s not found\n",
			      PyModule_GetName(module), name));
		PyErr_Clear();
		return NULL;
	}
	if (expected_type != NULL && !PyObject_TypeCheck(fobj, expected_type)) {
		debug_printf(("psyco: note: %s.%s is of type %200s instead of "
			      "%200s\n", PyModule_GetName(module), name,
			      fobj->ob_type->tp_name, expected_type->tp_name));
		Py_DECREF(fobj);
		fobj = NULL;
	}
	return fobj;
}

DEFINEFN
PyCFunction Psyco_DefineModuleFn(PyObject* module, char* meth_name,
				 int meth_flags, void* meta_fn)
{
	PyCFunction f;
	PyObject* fobj = Psyco_GetModuleObject(module, meth_name,
					       &PyCFunction_Type);
	if (fobj == NULL)
		return NULL;

	if (PyCFunction_GET_FLAGS(fobj) != meth_flags) {
		f = NULL;
		debug_printf(("psyco: note: %s.%s built-in has wrong "
			      "meth_flags\n", PyModule_GetName(module),
			      meth_name));
	}
	else {
		f = PyCFunction_GET_FUNCTION(fobj);
		Psyco_DefineMeta(f, meta_fn);
	}
	Py_DECREF(fobj);
	return f;
}


#define FORGET_REF     if (has_rtref(vi->source))			\
			    vi->source = remove_rtref(vi->source)

DEFINEFN
vinfo_t* generic_call_check(PsycoObject* po, int flags, vinfo_t* vi)
{
	condition_code_t cc;
	
	switch (flags & CfPyErrMask) {

	case CfPyErrIfNull:   /* a return == 0 (or NULL) means an error */
                cc = integer_cmp_i(po, vi, 0, Py_EQ);
		break;

	case CfPyErrIfNonNull:   /* a return != 0 means an error */
                cc = integer_cmp_i(po, vi, 0, Py_NE);
		break;

	case CfPyErrIfNeg:   /* a return < 0 means an error */
		cc = integer_cmp_i(po, vi, 0, Py_LT);
		break;

	case CfPyErrIfMinus1:     /* only -1 means an error */
		cc = integer_cmp_i(po, vi, -1, Py_EQ);
		break;

	case CfPyErrCheck:    /* always check with PyErr_Occurred() */
		cc = integer_NON_NULL(po, psyco_PyErr_Occurred(po));
		break;

	case CfPyErrCheckMinus1:   /* use PyErr_Occurred() if return is -1 */
		cc = integer_cmp_i(po, vi, -1, Py_NE);
		if (cc == CC_ERROR)
			goto Error;
		if (runtime_condition_t(po, cc))
			return vi;   /* result is not -1, ok */
		cc = integer_NON_NULL(po, psyco_PyErr_Occurred(po));
		break;

        case CfPyErrCheckNeg:   /* use PyErr_Occurred() if return is < 0 */
		cc = integer_cmp_i(po, vi, 0, Py_GE);
		if (cc == CC_ERROR)
			goto Error;
		if (runtime_condition_t(po, cc))
			return vi;   /* result is >= 0, ok */
		cc = integer_NON_NULL(po, psyco_PyErr_Occurred(po));
		break;

	case CfPyErrNotImplemented:   /* test for a Py_NotImplemented result */
		cc = integer_cmp_i(po, vi, (long) Py_NotImplemented, Py_EQ);
		if (cc == CC_ERROR)
			goto Error;
		if (runtime_condition_f(po, cc)) {
			/* result is Py_NotImplemented */
			vinfo_decref(vi, po);
			return psyco_vi_NotImplemented();
		}
		cc = integer_cmp_i(po, vi, 0, Py_EQ);
		break;

#if HAVE_GENERATORS
	case CfPyErrIterNext:    /* specially for tp_iternext slots */
		cc = integer_cmp_i(po, vi, 0, Py_NE);
		if (cc == CC_ERROR)
			goto Error;
		if (runtime_condition_t(po, cc))
			return vi;   /* result is not 0, ok */
		
		FORGET_REF;  /* NULL result */
		vinfo_decref(vi, po);
		cc = integer_NON_NULL(po, psyco_PyErr_Occurred(po));
		if (cc == CC_ERROR || runtime_condition_f(po, cc))
			goto PythonError;  /* PyErr_Occurred() returns true */

		/* NULL result with no error set; it is the end of the
		   iteration. Raise a pseudo PyErr_StopIteration. */
		PycException_SetVInfo(po, PyExc_StopIteration, psyco_vi_None());
		return NULL;
#endif

	case CfPyErrAlways:   /* always set an exception */
		cc = CC_ALWAYS_TRUE;
		break;

	default:
		return vi;
	}
	
	if (cc == CC_ERROR || runtime_condition_f(po, cc)) {

	   Error:
		if ((flags & CfReturnMask) == CfReturnRef) {
			/* in case of error, 'vi' is not a real
			   reference, so forget it */
			FORGET_REF;
		}
		vinfo_decref(vi, po);
		vi = NULL;
		
		/* We have detected that a Python exception must be set at
		   this point. */
	   PythonError:
		PycException_Raise(po, vinfo_new(VirtualTime_New(&ERtPython)),
				   NULL);
	}
	return vi;
}
#undef FORGET_REF

DEFINEFN
vinfo_t* Psyco_Meta1x(PsycoObject* po, void* c_function, int flags,
		      const char* arguments, long a1)
{
	void* psyco_fn = Psyco_Lookup(c_function);
	if (psyco_fn == NULL) {
		return psyco_generic_call(po, c_function, flags, arguments,
					  a1);
        }
	else
		return ((vinfo_t*(*)(PsycoObject*, long))(psyco_fn))
			(po, a1);
}

DEFINEFN
vinfo_t* Psyco_Meta2x(PsycoObject* po, void* c_function, int flags,
		      const char* arguments, long a1, long a2)
{
	void* psyco_fn = Psyco_Lookup(c_function);
	if (psyco_fn == NULL)
		return psyco_generic_call(po, c_function, flags, arguments,
					  a1, a2);
	else
		return ((vinfo_t*(*)(PsycoObject*, long, long))(psyco_fn))
			(po, a1, a2);
}

DEFINEFN
vinfo_t* Psyco_Meta3x(PsycoObject* po, void* c_function, int flags,
		      const char* arguments, long a1, long a2, long a3)
{
	void* psyco_fn = Psyco_Lookup(c_function);
	if (psyco_fn == NULL)
		return psyco_generic_call(po, c_function, flags, arguments,
					  a1, a2, a3);
	else
		return ((vinfo_t*(*)(PsycoObject*, long, long, long))(psyco_fn))
			(po, a1, a2, a3);
}

DEFINEFN
vinfo_t* Psyco_Meta4x(PsycoObject* po, void* c_function, int flags,
			     const char* arguments,
			     long a1, long a2, long a3, long a4)
{
	void* psyco_fn = Psyco_Lookup(c_function);
	if (psyco_fn == NULL)
		return psyco_generic_call(po, c_function, flags, arguments,
					   a1, a2, a3, a4);
	else
		return ((vinfo_t*(*)(PsycoObject*, long, long,
				     long, long))(psyco_fn))
			(po, a1, a2, a3, a4);
}


/***************************************************************/
 /***   pyc_data_t                                            ***/


DEFINEFN
void pyc_data_build(PsycoObject* po, PyObject* merge_points)
{
	/* rebuild the data in the pyc_data_t */
	int i;
        PyCodeObject* co = po->pr.co;
	int stack_base = po->vlocals.count - co->co_stacksize;
	for (i=stack_base; i<po->vlocals.count; i++)
		if (po->vlocals.items[i] == NULL)
			break;
	po->pr.stack_base = stack_base;
	po->pr.stack_level = i - stack_base;
	po->pr.merge_points = merge_points;
}

static void block_setup(PsycoObject* po, int type, int handler, int level)
{
  PyTryBlock *b;
  if (po->pr.iblock >= CO_MAXBLOCKS)
    Py_FatalError("block stack overflow");
  b = &po->pr.blockstack[po->pr.iblock++];
  b->b_type = type;
  b->b_level = level;
  b->b_handler = handler;
}

static PyTryBlock* block_pop(PsycoObject* po)
{
  if (po->pr.iblock <= 0)
    Py_FatalError("block stack underflow");
  return &po->pr.blockstack[--po->pr.iblock];
}


/*****************************************************************/
 /***   Compile-time Pseudo exceptions                          ***/


DEFINEVAR source_virtual_t ERtPython;  /* Exception raised by Python */
DEFINEVAR source_virtual_t EReturn;    /* 'return' statement */
DEFINEVAR source_virtual_t EBreak;     /* 'break' statement */
DEFINEVAR source_virtual_t EContinue;  /* 'continue' statement */

DEFINEFN
void PycException_SetString(PsycoObject* po, PyObject* e, const char* text)
{
	PyObject* s = PyString_FromString(text);
	if (s == NULL)
		OUT_OF_MEMORY();
	PycException_SetObject(po, e, s);
}

DEFINEFN
void PycException_SetObject(PsycoObject* po, PyObject* e, PyObject* v)
{
	PycException_Raise(po, vinfo_new(CompileTime_New((long) e)),
			   vinfo_new(CompileTime_NewSk(sk_new((long) v,
                                                              SkFlagPyObj))));
}

DEFINEFN
void PycException_SetVInfo(PsycoObject* po, PyObject* e, vinfo_t* v)
{
	PycException_Raise(po, vinfo_new(CompileTime_New((long) e)), v);
}

DEFINEFN
void PycException_Promote(PsycoObject* po, vinfo_t* vi, c_promotion_t* promotion)
{
	vinfo_incref(vi);
	PycException_Raise(po, vinfo_new(VirtualTime_New(&promotion->header)),
			   vi);
}

#if !HAVE_PyString_FromFormatV
/* This code is copied from Python 2.2. */
PyObject *
PyString_FromFormatV(const char *format, va_list vargs)
{
	va_list count;
	int n = 0;
	const char* f;
	char *s;
	PyObject* string;

#ifdef VA_LIST_IS_ARRAY
	memcpy(count, vargs, sizeof(va_list));
#else
	count = vargs;
#endif
	/* step 1: figure out how large a buffer we need */
	for (f = format; *f; f++) {
		if (*f == '%') {
			const char* p = f;
			while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
				;

			/* skip the 'l' in %ld, since it doesn't change the
			   width.  although only %d is supported (see
			   "expand" section below), others can be easily
			   added */
			if (*f == 'l' && *(f+1) == 'd')
				++f;
			
			switch (*f) {
			case 'c':
				(void)va_arg(count, int);
				/* fall through... */
			case '%':
				n++;
				break;
			case 'd': case 'i': case 'x':
				(void) va_arg(count, int);
				/* 20 bytes is enough to hold a 64-bit
				   integer.  Decimal takes the most space.
				   This isn't enough for octal. */
				n += 20;
				break;
			case 's':
				s = va_arg(count, char*);
				n += strlen(s);
				break;
			case 'p':
				(void) va_arg(count, int);
				/* maximum 64-bit pointer representation:
				 * 0xffffffffffffffff
				 * so 19 characters is enough.
				 * XXX I count 18 -- what's the extra for?
				 */
				n += 19;
				break;
			default:
				/* if we stumble upon an unknown
				   formatting code, copy the rest of
				   the format string to the output
				   string. (we cannot just skip the
				   code, since there's no way to know
				   what's in the argument list) */ 
				n += strlen(p);
				goto expand;
			}
		} else
			n++;
	}
 expand:
	/* step 2: fill the buffer */
	/* Since we've analyzed how much space we need for the worst case,
	   use sprintf directly instead of the slower PyOS_snprintf. */
	string = PyString_FromStringAndSize(NULL, n);
	if (!string)
		return NULL;
	
	s = PyString_AsString(string);

	for (f = format; *f; f++) {
		if (*f == '%') {
			const char* p = f++;
			int i, longflag = 0;
			/* parse the width.precision part (we're only
			   interested in the precision value, if any) */
			n = 0;
			while (isdigit(Py_CHARMASK(*f)))
				n = (n*10) + *f++ - '0';
			if (*f == '.') {
				f++;
				n = 0;
				while (isdigit(Py_CHARMASK(*f)))
					n = (n*10) + *f++ - '0';
			}
			while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
				f++;
			/* handle the long flag, but only for %ld.  others
			   can be added when necessary. */
			if (*f == 'l' && *(f+1) == 'd') {
				longflag = 1;
				++f;
			}
			
			switch (*f) {
			case 'c':
				*s++ = va_arg(vargs, int);
				break;
			case 'd':
				if (longflag)
					sprintf(s, "%ld", va_arg(vargs, long));
				else
					sprintf(s, "%d", va_arg(vargs, int));
				s += strlen(s);
				break;
			case 'i':
				sprintf(s, "%i", va_arg(vargs, int));
				s += strlen(s);
				break;
			case 'x':
				sprintf(s, "%x", va_arg(vargs, int));
				s += strlen(s);
				break;
			case 's':
				p = va_arg(vargs, char*);
				i = strlen(p);
				if (n > 0 && i > n)
					i = n;
				memcpy(s, p, i);
				s += i;
				break;
			case 'p':
				sprintf(s, "%p", va_arg(vargs, void*));
				/* %p is ill-defined:  ensure leading 0x. */
				if (s[1] == 'X')
					s[1] = 'x';
				else if (s[1] != 'x') {
					memmove(s+2, s, strlen(s)+1);
					s[0] = '0';
					s[1] = 'x';
				}
				s += strlen(s);
				break;
			case '%':
				*s++ = '%';
				break;
			default:
				strcpy(s, p);
				s += strlen(s);
				goto end;
			}
		} else
			*s++ = *f;
	}
	
 end:
	_PyString_Resize(&string, s - PyString_AS_STRING(string));
	return string;
}
#endif /* !HAVE_PyString_FromFormatV */

DEFINEFN
void PycException_SetFormat(PsycoObject* po, PyObject* e, const char* fmt, ...)
{
	PyObject* s;
	va_list vargs;

#ifdef HAVE_STDARG_PROTOTYPES
	va_start(vargs, fmt);
#else
	va_start(vargs);
#endif
	s = PyString_FromFormatV(fmt, vargs);
	va_end(vargs);

	if (s == NULL)
		OUT_OF_MEMORY();
	PycException_SetObject(po, e, s);
}

DEFINEFN
vinfo_t* PycException_Matches(PsycoObject* po, PyObject* e)
{
	vinfo_t* result;
	if (PycException_Is(po, &ERtPython)) {
		/* Exception raised by Python, emit a call to
		   PyErr_ExceptionMatches() */
		result = psyco_generic_call(po, PyErr_ExceptionMatches,
					    CfReturnNormal, "l", (long) e);
	}
	else if (PycException_IsPython(po)) {
		/* Exception virtually set, that is, present in the PsycoObject
		   but not actually set at run-time by Python's PyErr_SetXxx */
		result = psyco_generic_call(po, PyErr_GivenExceptionMatches,
					    CfPure | CfReturnNormal,
					    "vl", po->pr.exc, (long) e);
	}
	else {   /* pseudo exceptions don't match real Python ones */
		result = psyco_vi_Zero();
	}
	return result;
}

inline void clear_pseudo_exception(PsycoObject* po)
{
	extra_assert(PycException_Occurred(po));
	if (po->pr.tb != NULL) {
		vinfo_decref(po->pr.tb, po);
		po->pr.tb = NULL;
	}
        if (po->pr.val != NULL) {
		vinfo_decref(po->pr.val, po);
		po->pr.val = NULL;
	}
	vinfo_decref(po->pr.exc, po);
	po->pr.exc = NULL;
}

DEFINEFN
void PycException_Clear(PsycoObject* po)
{
	if (PycException_Is(po, &ERtPython)) {
		/* Clear the Python exception set at run-time */
		psyco_call_void(po, PyErr_Clear);
	}
	clear_pseudo_exception(po);
}

DEFINEFN
void psyco_virtualize_exception(PsycoObject* po)
{
	/* fetch a Python exception set at compile-time (that is, now)
	   and turn into a pseudo-exception (typically to be re-raised
	   at run-time). */
	PyObject *exc, *val, *tb;
	vinfo_t *vexc, *vval, *vtb;
	PyErr_Fetch(&exc, &val, &tb);
	extra_assert(exc != NULL);

	vexc = vinfo_new(CompileTime_NewSk(sk_new((long) exc, SkFlagPyObj)));
	vval = vinfo_new(CompileTime_NewSk(sk_new((long) val, SkFlagPyObj)));
	vtb  = tb == NULL ? NULL :
	       vinfo_new(CompileTime_NewSk(sk_new((long) tb,  SkFlagPyObj)));
	PycException_Restore(po, vexc, vval, vtb);
}

static void cimpl_pyerr_fetch(PyObject* target[])
{
        extra_assert(PyErr_Occurred());
	PyErr_Fetch(target+0, target+1, target+2);
	if (target[0] == NULL) {
		target[0] = Py_None;
		Py_INCREF(Py_None);
	}
	if (target[1] == NULL) {
		target[1] = Py_None;
		Py_INCREF(Py_None);
	}
	if (target[2] == NULL) {
		target[2] = Py_None;
		Py_INCREF(Py_None);
	}
}

DEFINEFN
void cimpl_finalize_frame_locals(PyObject* f_exc_type,
				 PyObject* f_exc_value,
				 PyObject* f_exc_traceback)
{
	/* Called by code emitted by pycencoding.h when a function exits,
	   but only if f_exc_type!=NULL. Works like reset_exc_info() of
	   Python. */
	PyThreadState *tstate = PyThreadState_GET();
	PyObject *tmp_type, *tmp_value, *tmp_tb;

	/* This frame caught an exception */
	tmp_type = tstate->exc_type;
	tmp_value = tstate->exc_value;
	tmp_tb = tstate->exc_traceback;
	tstate->exc_type = f_exc_type;  /* references are transferred */
	tstate->exc_value = f_exc_value;
	tstate->exc_traceback = f_exc_traceback;
	Py_XDECREF(tmp_type);
	Py_XDECREF(tmp_value);
	Py_XDECREF(tmp_tb);
	/* For b/w compatibility */
	PySys_SetObject("exc_type", f_exc_type);
	PySys_SetObject("exc_value", f_exc_value);
	PySys_SetObject("exc_traceback", f_exc_traceback);
}

inline void cimpl_set_exc_info(PyObject* target[],
			       PyObject** f_exc_type,
			       PyObject** f_exc_value,
			       PyObject** f_exc_traceback)
{
	/* Equivalent of PyErr_NormalizeException() + set_exc_info() */
	PyThreadState *tstate = PyThreadState_GET();
        PyObject *type, *value, *tb;
	PyObject *tmp_type, *tmp_value, *tmp_tb;

        PyErr_NormalizeException(target+0, target+1, target+2);
        type = target[0];
        value = target[1];
	tb = target[2];

	if (*f_exc_type == NULL) {
		/* This frame didn't catch an exception before */
		/* Save previous exception of this thread in this frame */
		if (tstate->exc_type == NULL) {
			Py_INCREF(Py_None);
			tstate->exc_type = Py_None;
		}
		Py_INCREF(tstate->exc_type);
		Py_XINCREF(tstate->exc_value);
		Py_XINCREF(tstate->exc_traceback);
		*f_exc_type = tstate->exc_type;
		*f_exc_value = tstate->exc_value;
		*f_exc_traceback = tstate->exc_traceback;
	}
	/* Set new exception for this thread */
	tmp_type = tstate->exc_type;
	tmp_value = tstate->exc_value;
	tmp_tb = tstate->exc_traceback;
	Py_XINCREF(type);
	Py_XINCREF(value);
	Py_XINCREF(tb);
	tstate->exc_type = type;
	tstate->exc_value = value;
	tstate->exc_traceback = tb;
	Py_XDECREF(tmp_type);
	Py_XDECREF(tmp_value);
	Py_XDECREF(tmp_tb);
	/* For b/w compatibility */
	PySys_SetObject("exc_type", type);
	PySys_SetObject("exc_value", value);
	PySys_SetObject("exc_traceback", tb);
}

static void cimpl_pyerr_fetch_and_normalize(PyObject* target[],
					    PyObject** f_exc_type,
					    PyObject** f_exc_value,
					    PyObject** f_exc_traceback)
{
        extra_assert(PyErr_Occurred());
	PyErr_Fetch(target+0, target+1, target+2);
        cimpl_set_exc_info(target,
			   f_exc_type, f_exc_value, f_exc_traceback);
}

static void cimpl_pyerr_normalize(PyObject* exc, PyObject* val, PyObject* tb,
				  PyObject* target[],
				  PyObject** f_exc_type,
				  PyObject** f_exc_value,
				  PyObject** f_exc_traceback)
{
	target[0] = exc;  Py_INCREF(exc);
	target[1] = val;  Py_XINCREF(val);
	target[2] = tb;   Py_XINCREF(tb);
        cimpl_set_exc_info(target,
			   f_exc_type, f_exc_value, f_exc_traceback);
}

DEFINEFN
void PycException_Fetch(PsycoObject* po)
{
	if (PycException_Is(po, &ERtPython)) {
/* 		vinfo_t* exc = vinfo_new(SOURCE_DUMMY_WITH_REF); */
/* 		vinfo_t* val = vinfo_new(SOURCE_DUMMY_WITH_REF); */
/* 		vinfo_t* tb  = vinfo_new(SOURCE_DUMMY_WITH_REF); */
/* 		psyco_generic_call(po, PyErr_Fetch, CfNoReturnValue, */
/* 				   "rrr", exc, val, tb); */
/* 		vinfo_decref(tb, po); */
		vinfo_array_t* array = array_new(3);
		psyco_generic_call(po, cimpl_pyerr_fetch,
				   CfNoReturnValue, "A", array);
		clear_pseudo_exception(po);
		po->pr.exc = array->items[0];
		po->pr.val = array->items[1];  /* po->pr.val!=NULL after this */
		po->pr.tb  = array->items[2];  /* po->pr.tb!=NULL after this */
		array_release(array);
	}
}

inline bool PycException_FetchNormalize(PsycoObject* po)
{
	vinfo_t* result;
	vinfo_array_t* array = array_new(3);
	vinfo_array_t* f_exc = LOC_CONTINUATION->array;

        /* At runtime, we load the following data into the array:

           array[0] -- exc_type       new exception, normalized
           array[1] -- exc_value      new exception, normalized
           array[2] -- exc_traceback  new exception, normalized
        */
	extra_assert(f_exc->count >= 3);
	if (PycException_Is(po, &ERtPython)) {
		/* fetch and normalize the exception */
		result = psyco_generic_call(po, cimpl_pyerr_fetch_and_normalize,
					    CfNoReturnValue, "Arrr", array,
					    f_exc->items[0],
					    f_exc->items[1],
					    f_exc->items[2]);
	}
	else {
		char args[8];
		args[0] = 'v';
		args[1] = po->pr.val == NULL ? 'l' : 'v';
		args[2] = po->pr.tb  == NULL ? 'l' : 'v';
		args[3] = 'A';
		args[4] = 'r';
		args[5] = 'r';
		args[6] = 'r';
		args[7] = 0;
		/* normalize the already-given exception */
		result = psyco_generic_call(po, cimpl_pyerr_normalize,
					    CfNoReturnValue, args,
					    po->pr.exc, po->pr.val, po->pr.tb,
					    array,
					    f_exc->items[0],
					    f_exc->items[1],
					    f_exc->items[2]);
	}
	if (result == NULL) {
		array_release(array);
		return false;
	}
	clear_pseudo_exception(po);
	po->pr.exc = array->items[0];
	po->pr.val = array->items[1];  /* po->pr.val!=NULL after this */
	po->pr.tb  = array->items[2];  /* po->pr.tb!=NULL after this */
	array_release(array);
	return true;
}

static PyFrameObject* cimpl_new_frame(PyThreadState* tstate, PyCodeObject* code,
				      PyObject* globals, int lasti, int lineno)
{
	/* Make a minimalistic frame object, working around the specific
	   expectations of PyFrame_New(), which is the only reasonable way
	   to create frame objects (because of free lists etc) */
	PyFrameObject* result;
	PyFrameObject* back = tstate->frame;
	tstate->frame = NULL;  /* frame objects are not created in stack order
				  with Psyco, so it's probably better not to
				  create plain wrong chained lists */
	result = PyFrame_New(tstate, code, globals, NULL);
	tstate->frame = back;
	if (result != NULL) {
		result->f_lasti = lasti;
		result->f_lineno = lineno;
	}
	return result;
}

static void cimpl_rt_traceback(PyCodeObject* code, PyObject* globals,
			       int lasti, int lineno)
{
	PyThreadState* tstate = PyThreadState_GET();
	PyFrameObject* f = cimpl_new_frame(tstate, code, globals, lasti, lineno);
	/* an out-of-memory error just replaces the current exception */
	if (f != NULL) {
		PyTraceBack_Here(f);
		Py_DECREF(f);
	}
}

static PyObject* cimpl_vt_traceback(PyCodeObject* code, PyObject* globals,
				    int lasti, int lineno)
{
	/* This is a hack around the limited interface to tracebacks.
	   PyTraceBack_Here() seems to be the only clean way to create new
	   traceback objects. */
	PyObject* oldtb;
	PyObject* newtb;
	PyThreadState* tstate = PyThreadState_GET();
	PyFrameObject* f = cimpl_new_frame(tstate, code, globals, lasti, lineno);
	if (f == NULL) {
		/* out-of-memory error */
		Py_INCREF(Py_None);
		return Py_None;
	}
	oldtb = tstate->curexc_traceback;  /* might be NULL */
	Py_XINCREF(oldtb);
	if (PyTraceBack_Here(f)) {
		/* out-of-memory error */
		Py_XDECREF(oldtb);
		Py_DECREF(f);
		Py_INCREF(Py_None);
		return Py_None;
	}
	/* the new traceback is now in curexc_traceback */
	newtb = tstate->curexc_traceback;  /* extracts the reference */
	tstate->curexc_traceback = oldtb;  /* consumes the reference */
	Py_DECREF(f);
	return newtb;
}

inline void PsycoTraceBack_Here(PsycoObject* po, int lasti)
{
	int lineno = PyCode_Addr2Line(po->pr.co, lasti);
	
	if (PycException_Is(po, &ERtPython)) {
		/* Python exception is actually set at run-time */
		psyco_generic_call(po, cimpl_rt_traceback,
				   CfNoReturnValue, "lvll",
				   (long) po->pr.co, LOC_GLOBALS, lasti, lineno);
	}
	else {
		/* We only have a virtual-time exception (not set in Python),
		   so we build po->pr.tb without actually setting it either */
		extra_assert(po->pr.tb == NULL);
		po->pr.tb = psyco_generic_call(po, cimpl_vt_traceback,
					       CfReturnRef, "lvll",
					       (long) po->pr.co, LOC_GLOBALS,
					       lasti, lineno);
	}
}


 /***************************************************************/
/***                      Initialization                       ***/
 /***************************************************************/

DEFINEVAR source_known_t psyco_skNone;    /* known value 'Py_None' */
DEFINEVAR source_known_t psyco_skZero;    /* known value 0 */
DEFINEVAR source_known_t psyco_skOne;     /* known value 1 */
DEFINEVAR source_known_t psyco_skNotImplemented;

static PyObject* s_builtin_object;   /* intern string '__builtins__' */

INITIALIZATIONFN
{'fraction_non_alphanumeric': 0.15247244288441406, 'fraction_numerical': 0.006342755095757128, 'mean_word_length': 3.421272347762955, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 210, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2058283', 'n_tokens_mistral': 20239, 'n_tokens_neox': 18359, 'n_words': 4333}