
/* Frame object interface */

#ifndef Py_FRAMEOBJECT_H
#define Py_FRAMEOBJECT_H
#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
	int b_type;		/* what kind of block this is */
	int b_handler;		/* where to jump to find handler */
	int b_level;		/* value stack level to pop to */
} PyTryBlock;


typedef PyObject *(PyFrame_ExecFunc) (struct _frame *, PyObject *);
typedef int (PyFrame_GuardFunc) (struct _frame *, int);
typedef int (PyFrame_DeallocFunc) (struct _frame *, struct _frame **);

typedef struct _frame {
	PyObject_HEAD
	struct _frame *f_back;	/* previous frame, or NULL */

	PyCodeObject *f_code;	/* code segment */
	PyObject *f_builtins;	/* builtin symbol table (PyDictObject) */
	PyObject *f_globals;	/* global symbol table (PyDictObject) */
	PyObject *f_locals;	/* local symbol table (PyDictObject) */
	PyObject **f_valuestack; /* points after the last local */
	PyObject *f_trace;	/* Trace function */
	PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
	PyThreadState *f_tstate;
	int f_lasti;		/* Last instruction if called */
	int f_lineno;		/* Current line number */
	int f_restricted;	/* Flag set if restricted operations
						   in this scope */
	int f_iblock;		/* index in f_blockstack */
	PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
	int f_nlocals;		/* number of locals */
	int f_stacksize;	/* size of value stack */

	int f_referers;			/* y2k0410 how many frames return to me */
	unsigned char *f_first_instr;
	unsigned char *f_next_instr;	/* updated on every entry/exit of eval loop */
	PyObject **f_stackpointer;		/* ditto */
	int f_statusflags;		/* update fast locals, expect result, ... */
	PyObject *f_hold_ref;	/* hook for things which must be kept alive for this frame */
	PyObject *f_temp_val;	/* return value when the function result is occupied */

	/** all of the above is visible state for ceval.c and must be preserved.
		The fields below are for interpreter specific purposes but need to
		be handled here since frame creation and destruction cannot be
		overwritten.

		The following function defines the interpreter of the frame, and also
		the meaning of the additional fields. In a sense, this makes a dynamic type.
		It is the interface to the dispatcher.
	 */

	PyFrame_ExecFunc *f_execute;

	/** in the context of eval_code2_loop, this function acts as a
		callback. It is checked at every opcode and assigned dynamically.
	 */
	PyFrame_GuardFunc *f_callguard;

	PyFrame_DeallocFunc *f_dealloc; 	/* monitor frame deallocation. */

	/* Stackless extension fields */
	void *f_memory; 		/* not used here */
	struct PyCoNode *f_node;
	struct PyCoObject *f_co;
	struct _frame *f_coframes;
	int f_depth;
	int f_age;
	int f_reg3;

	/* end of stackless Python specifics */
	PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
} PyFrameObject;


typedef struct PyCoObject {
	PyObject_HEAD
	PyFrameObject *frame;
	int flags;
} PyCoObject;

typedef struct PyCoNode {
	PyObject_HEAD
	int count;
	int weakflag;
	PyFrameObject *frame;
	PyFrameObject *freelist;
} PyCoNode;

/* Standard object interface */

extern DL_IMPORT(PyTypeObject) PyFrame_Type;

#define PyFrame_Check(op) ((op)->ob_type == &PyFrame_Type)

DL_IMPORT(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
									   PyObject *, PyObject *);


/* The rest of the interface is specific for frame objects */

/* Tuple access macros */

#ifndef Py_DEBUG
#define GETITEM(v, i) PyTuple_GET_ITEM((PyTupleObject *)(v), (i))
#define GETITEMNAME(v, i) \
	PyString_AS_STRING((PyStringObject *)GETITEM((v), (i)))
#else
#define GETITEM(v, i) PyTuple_GetItem((v), (i))
#define GETITEMNAME(v, i) PyString_AsString(GETITEM(v, i))
#endif

#define GETUSTRINGVALUE(s) ((unsigned char *)PyString_AS_STRING(s))

/* Code access macros */

#define Getconst(f, i)	(GETITEM((f)->f_code->co_consts, (i)))
#define Getname(f, i)	(GETITEMNAME((f)->f_code->co_names, (i)))
#define Getnamev(f, i)	(GETITEM((f)->f_code->co_names, (i)))


/* Block management functions */

DL_IMPORT(void) PyFrame_BlockSetup (PyFrameObject *, int, int, int);
DL_IMPORT(PyTryBlock *) PyFrame_BlockPop (PyFrameObject *);

/* Extend the value stack */

DL_IMPORT(PyObject **) PyFrame_ExtendStack (PyFrameObject *, int, int);

/* Conversions between "fast locals" and locals in dictionary */

DL_IMPORT(void) PyFrame_LocalsToFast (PyFrameObject *, int);
DL_IMPORT(void) PyFrame_FastToLocals (PyFrameObject *);

/* adjusting f_lasti which is no longer comupted in ceval.c */

DL_IMPORT(int) PyFrame_PreviousInstr (PyFrameObject *, int);

/* stackless support:

_Py_UnwindTokenStruct is an object which will (hopefully) never be
seen in a Python program. it's only purpose is to be used as
a notification token.
A function which returns this token tells the interpreter
to stop the current frame and to execute the topmost frame
of the frame chain.

This object does *not* expect to be refcounted.
*/

extern DL_IMPORT(PyObject) _Py_UnwindTokenStruct; /* Don't use this directly */

#define Py_UnwindToken (&_Py_UnwindTokenStruct)

DL_IMPORT(int) PyFrame_HoldReference (PyFrameObject *, PyObject *);

/* a finalizer hook which will called after PyFrame_Fini */
/* mainly in order to avoid spoiling pythonrun */
typedef void (PyFrame_FiniChainFunc) (void);

extern DL_IMPORT(PyFrame_FiniChainFunc*) PyFrame_FiniChain;

#ifdef FRAME_DEBUG
extern DL_IMPORT(int) PyFrame_NumberOfFrames;
extern DL_IMPORT(int) PyFrame_ActiveDeletes;
#endif

#ifdef __cplusplus
}
#endif
#endif /* !Py_FRAMEOBJECT_H */
