/*
 * Copyright (c) 1980 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

#ifndef lint
static char sccsid[] = "@(#)frame.c	5.1 (Berkeley) 6/6/85";
#endif not lint

/*
 * Activation record handling.
 *
 * The routines curframe and nextframe cheat by using a global copy
 * of the display.  This means there can't be multiple instances of
 * them active at the same time and nextframe won't work in arbitrary cases.
 *
 * This could be solved by putting the display copy into the FRAME structure,
 * but I didn't feel like doing this.  The idea is that they be used
 * in looping through all frames, if I had generators I would use them.
 */

#include "defs.h"
#include "runtime.h"
#include "machine.h"
#include "process.h"
#include "sym.h"
#include "object.h"
#include "mappings.h"
#include "process/pxinfo.h"
#include "frame.rep"

/*
 * Return a pointer to the current activation record.
 * Return NIL if currently in the main program.
 * The storage is static.
 */

#define MAXDEPTH 7
#define dispblk(dp)		((dp - DISPLAY) / 2)

LOCAL ADDRESS *display[MAXDEPTH];
LOCAL int dispindex;

FRAME *curframe()
{
	static FRAME frame;
	FRAME *frp;
	ADDRESS *dp, *disp;
	int i;

	frp = &frame;
	dp = curdp();
	disp = contents(dp);
	if (dispblk(dp) <= MAINBLK) {
		return NIL;
	} else {
		getframe(frp, disp);
		for (i = 1; i < MAXDEPTH; i++) {
			display[i] = dispval(i);
		}
		dispindex = dispblk(dp);
		return frp;
	}
}

/*
 * Return a pointer to the next activation record up the stack.
 * Return NIL if there is none.
 * Writes over space pointed to by given argument.
 */

FRAME *nextframe(frp)
FRAME *frp;
{
	ADDRESS *fp;

	if (dispblk(frp->save_dp) <= MAINBLK) {
		return(NIL);
	} else {
		display[dispindex] = frp->save_disp;
		dispindex = dispblk(frp->save_dp);
		fp = display[dispindex];
		getframe(frp, fp);
		return(frp);
	}
}

/*
 * Return the frame associated with the given function.
 */

FRAME *findframe(f)
SYM *f;
{
	static FRAME frame;
	FRAME *frp, *prevfrp;

	frame.save_dp = curdp();
	frame.save_disp = contents(frame.save_dp);
	prevfrp = &frame;
	for (frp = curframe(); frp != NIL; frp = nextframe(frp)) {
		if (whatblock(entry(frp)) == f) {
			return frp;
		}
		*prevfrp = *frp;
	}
	if (f == program) {
		return prevfrp;
	} else {
		return NIL;
	}
}

/*
 * Get the activation record associated with the given display pointer.
 */

LOCAL getframe(frp, disp)
FRAME *frp;
ADDRESS *disp;
{
	if (disp == NIL) {
		panic("bad disp in getframe");
	}
	dread(frp, disp, sizeof(FRAME));
	frp->save_pc -= ENDOFF;
}

/*
 * Return the address of the display in the px process for the given block.
 */

ADDRESS *dispval(b)
int b;
{
	ADDRESS *r;

	dread(&r, (ADDRESS) (DISPLAY + 2*b), sizeof(r));
	return r;
}

/*
 * Return the current display pointer.
 */

ADDRESS *curdp()
{
	ADDRESS *r;

	dread(&r, (ADDRESS) DP, sizeof(r));
	return r;
}

/*
 * Return the contents of the given display pointer.
 */

ADDRESS *contents(dp)
ADDRESS *dp;
{
	ADDRESS *r;

	dread(&r, (ADDRESS) dp, sizeof(r));
	return r;
}

/*
 * Return the px stack address associated with a given frame pointer.
 * Actually, to confuse the issue we want the stack address of the
 * frame one up from the given one.
 */

ADDRESS stkaddr(frp, b)
FRAME *frp;
int b;
{
	return (ADDRESS) display[b];
}
