122517Sdist /*
222517Sdist  * Copyright (c) 1980 Regents of the University of California.
322517Sdist  * All rights reserved.  The Berkeley software License Agreement
422517Sdist  * specifies the terms and conditions for redistribution.
522517Sdist  */
65515Slinton 
722517Sdist #ifndef lint
8*36535Smckusick static char sccsid[] = "@(#)callproc.c	5.3 (Berkeley) 01/09/89";
922517Sdist #endif not lint
1030849Smckusick 
115515Slinton /*
125515Slinton  * Evaluate a call to a procedure.
135515Slinton  *
145515Slinton  * This file is a botch as far as modularity is concerned.
15*36535Smckusick  *
16*36535Smckusick  * In fact, FIXME, it does not work on either the Vax or Tahoe
17*36535Smckusick  * at this point (Sep 22, 1988).  It possibly doesn't work because
18*36535Smckusick  * the ptrace interface never sets "pc" back into the interpreter's
19*36535Smckusick  * program counter location.
20*36535Smckusick  *
21*36535Smckusick  * Due to portability changes
22*36535Smckusick  * in px for ANSI C, it is now even further broken, since the operand
23*36535Smckusick  * stack is no longer the system stack and since the interpreter's
24*36535Smckusick  * "pc" that we see is never read by the interpreter.  We could fix
25*36535Smckusick  * this, and increase the modularity, by:
26*36535Smckusick  *
27*36535Smckusick  *    * changing this whole module to build a string of bytecodes
28*36535Smckusick  *	that would: push a series of constant parameters, then call a
29*36535Smckusick  *	procedure, then take a breakpoint.
30*36535Smckusick  *    * Having px allocate a place for us to do this, and pass us the
31*36535Smckusick  *	address of this (otherwise unused) variable.
32*36535Smckusick  *    * Creating an entry point into the px interpreter which would
33*36535Smckusick  *	pick up the pc value from "*addrpc" and then enter the main loop.
34*36535Smckusick  *	Currently we never pick up *addrpc for speed.
35*36535Smckusick  *    * Fix the code below to use the new entry point rather than "loopaddr".
36*36535Smckusick  *
37*36535Smckusick  * But I suspect this code is dead enough that nobody will ever get
38*36535Smckusick  * around to it.		-- gnu@toad.com, 22Sep88
395515Slinton  */
405515Slinton 
415515Slinton #include "defs.h"
425515Slinton #include "runtime.h"
435515Slinton #include "sym.h"
445515Slinton #include "tree.h"
455515Slinton #include "breakpoint.h"
465515Slinton #include "machine.h"
475515Slinton #include "process.h"
485515Slinton #include "source.h"
495515Slinton #include "frame.rep"
505515Slinton #include "sym/classes.h"
515515Slinton #include "sym/sym.rep"
525515Slinton #include "tree/tree.rep"
535515Slinton #include "process/process.rep"
545515Slinton #include "process/pxinfo.h"
555515Slinton 
565515Slinton LOCAL ADDRESS retaddr;
5730849Smckusick #ifdef tahoe
5830849Smckusick BOOLEAN didret;
5930849Smckusick #endif
605515Slinton 
615515Slinton /*
625515Slinton  * Controlling logic of procedure calling.
635515Slinton  * Calling a procedure before ever executing the program must
645515Slinton  * be special cased.
655515Slinton  */
665515Slinton 
675515Slinton callproc(procnode, arglist)
685515Slinton NODE *procnode;
695515Slinton NODE *arglist;
705515Slinton {
7130849Smckusick 	register SYM *proc;
7230849Smckusick #ifdef tahoe
7330849Smckusick 	register int tmpsp, tmptmp;
7430849Smckusick 	extern BOOLEAN shouldrestart;
755515Slinton 
7630849Smckusick 	if (shouldrestart) {
7730849Smckusick 		initstart();
7830849Smckusick 	}
7930849Smckusick #endif
805515Slinton 	if (pc == 0) {
815515Slinton 		curline = firstline(program);
825515Slinton 		setbp(curline);
835515Slinton 		resume();
845515Slinton 		unsetbp(curline);
855515Slinton 	}
865515Slinton 	proc = procnode->nameval;
875515Slinton 	if (!isblock(proc)) {
885515Slinton 		error("\"%s\" is not a procedure or function", proc->symbol);
895515Slinton 	}
9030849Smckusick #ifdef tahoe
9130849Smckusick 	doret(process);
9230849Smckusick 	tmpsp = process->sp;
9330849Smckusick #endif
945659Slinton 	pushargs(proc, arglist);
9530849Smckusick #ifdef tahoe
9630849Smckusick 	tmptmp = tmpsp;
9730849Smckusick 	tmpsp = process->sp;
9830849Smckusick 	process->sp = tmptmp;
9930849Smckusick #endif
1005515Slinton 	pushenv(proc->symvalue.funcv.codeloc);
10130849Smckusick #ifdef tahoe
10230849Smckusick 	process->sp = tmpsp;
10330849Smckusick #endif
1045515Slinton 	pushframe(proc->blkno);
1055515Slinton 	execute(proc);
1065515Slinton 	/* NOTREACHED */
1075515Slinton }
1085515Slinton 
1095515Slinton /*
1105515Slinton  * Push the arguments on the process' stack.  We do this by first
1115515Slinton  * evaluating them on the "eval" stack, then copying into the process'
1125515Slinton  * space.
1135515Slinton  */
1145515Slinton 
1155515Slinton LOCAL pushargs(proc, arglist)
1165515Slinton SYM *proc;
1175515Slinton NODE *arglist;
1185515Slinton {
1195515Slinton 	STACK *savesp;
1205515Slinton 	int args_size;
1215515Slinton 
1225515Slinton 	savesp = sp;
12330849Smckusick #ifdef tahoe
12430849Smckusick 	/*
12530849Smckusick 	 * evalargs hopefully keeps stack aligned, so we won't bother
12630849Smckusick 	 * aligning it afterwards, neither will we align process->sp
12730849Smckusick 	 * after subtracting args_size.
12830849Smckusick 	 */
12930849Smckusick #endif
1305515Slinton 	evalargs(proc->symbol, proc->chain, arglist);
1315515Slinton 	args_size = sp - savesp;
1325515Slinton 	process->sp -= args_size;
1335515Slinton 	dwrite(savesp, process->sp, args_size);
1345515Slinton 	sp = savesp;
1355515Slinton }
1365515Slinton 
1375515Slinton /*
1385515Slinton  * Evaluate arguments right-to-left because the eval stack
1395515Slinton  * grows up, px's stack grows down.
1405515Slinton  */
1415515Slinton 
1425515Slinton LOCAL evalargs(procname, arg, explist)
1435515Slinton char *procname;
1445515Slinton SYM *arg;
1455515Slinton NODE *explist;
1465515Slinton {
1475515Slinton 	NODE *exp;
1485515Slinton 	STACK *savesp;
1495515Slinton 	ADDRESS addr;
1505515Slinton 
1515515Slinton 	if (arg == NIL) {
1525515Slinton 		if (explist != NIL) {
1535515Slinton 			error("too many parameters to \"%s\"", procname);
1545515Slinton 		}
1555515Slinton 	} else if (explist == NIL) {
1565515Slinton 		error("not enough parameters to \"%s\"", procname);
1575515Slinton 	} else {
1585515Slinton 		if (explist->op != O_COMMA) {
1595515Slinton 			panic("evalargs: arglist missing comma");
1605515Slinton 		}
1615515Slinton 		savesp = sp;
1625515Slinton 		evalargs(procname, arg->chain, explist->right);
1635515Slinton 		exp = explist->left;
1645515Slinton 		if (!compatible(arg->type, exp->nodetype)) {
1655515Slinton 			sp = savesp;
1665515Slinton 			trerror("%t is not the same type as parameter \"%s\"",
1675515Slinton 				exp, arg->symbol);
1685515Slinton 		}
1695515Slinton 		if (arg->class == REF) {
1705515Slinton 			if (exp->op != O_RVAL) {
1715515Slinton 				sp = savesp;
1725515Slinton 				error("variable expected for parameter \"%s\"", arg->symbol);
1735515Slinton 			}
1745515Slinton 			addr = lval(exp->left);
1755515Slinton 			push(ADDRESS, addr);
1765515Slinton 		} else {
1775515Slinton 			eval(exp);
1785515Slinton 		}
1795515Slinton 	}
1805515Slinton }
1815515Slinton 
1825515Slinton /*
1835515Slinton  * Simulate a CALL instruction by pushing the appropriate
1845515Slinton  * stack frame information.
1855515Slinton  *
18630849Smckusick  * Massage register 10 or 11 appropriately since it contains the
1875515Slinton  * stack frame pointer.
1885515Slinton  */
1895515Slinton 
1905515Slinton LOCAL pushframe(b)
1915515Slinton int b;
1925515Slinton {
1935515Slinton 	ADDRESS *newdp;
1945515Slinton 	FRAME callframe;
1955515Slinton 
1965515Slinton 	retaddr = program->symvalue.funcv.codeloc;
1975515Slinton 
1985515Slinton /*
1995515Slinton  * This stuff is set by the callee, just here to take up space.
2005515Slinton  */
2015515Slinton 	callframe.stackref = 0;
2025515Slinton 	callframe.file = 0;
2035515Slinton 	callframe.blockp = 0;
2045515Slinton 	callframe.save_loc = NIL;
2055515Slinton 	callframe.save_disp = NIL;
2065515Slinton 
2075515Slinton /*
2085515Slinton  * This is the useful stuff.
2095515Slinton  */
2105515Slinton 	callframe.save_dp = curdp();
2115515Slinton 	callframe.save_pc = retaddr + ENDOFF;
2125515Slinton 	callframe.save_lino = 0;
2135515Slinton 	newdp = DISPLAY + (2 * b);
2145515Slinton 	dwrite(&newdp, DP, sizeof(newdp));
2155515Slinton 	process->sp -= sizeof(callframe);
2165515Slinton 	dwrite(&callframe, process->sp, sizeof(callframe));
21730849Smckusick #ifdef tahoe
21830849Smckusick 	process->reg[11] = process->sp;
21930849Smckusick #else
2205515Slinton 	process->reg[10] = process->sp;
22130849Smckusick #endif
2225515Slinton }
2235515Slinton 
2245515Slinton /*
2255515Slinton  * Execute the procedure.  This routine does NOT return because it
2265515Slinton  * calls "cont", which doesn't return.  We set a CALLPROC breakpoint
2275515Slinton  * at "retaddr", the address where the called routine will return.
2285515Slinton  *
2295515Slinton  * The action for a CALLPROC is to call "procreturn" where we restore
2305515Slinton  * the environment.
2315515Slinton  */
2325515Slinton 
2335515Slinton LOCAL execute(f)
2345515Slinton SYM *f;
2355515Slinton {
2365515Slinton 	isstopped = TRUE;
2375515Slinton 	addbp(retaddr, CALLPROC, f, NIL, NIL, 0);
2385515Slinton 	cont();
2395515Slinton 	/* NOTREACHED */
2405515Slinton }
2415515Slinton 
2425515Slinton procreturn(f)
2435515Slinton SYM *f;
2445515Slinton {
2455515Slinton 	int len;
2465515Slinton 
24730849Smckusick #ifdef tahoe
24830849Smckusick 	doret(process);
24930849Smckusick #endif
2505515Slinton 	printf("%s returns ", f->symbol);
2515515Slinton 	if (f->class == FUNC) {
2525515Slinton 		len = size(f->type);
2535515Slinton 		dread(sp, process->sp, len);
25430849Smckusick #ifdef tahoe
25530849Smckusick 		len = (len + 3) & ~3;
25630849Smckusick #endif
2575515Slinton 		sp += len;
2585515Slinton 		printval(f->type);
2595515Slinton 		putchar('\n');
2605515Slinton 	} else {
2615515Slinton 		printf("successfully\n");
2625515Slinton 	}
2635515Slinton 	popenv();
2645515Slinton }
2655515Slinton 
2665515Slinton /*
2675515Slinton  * Push the current environment.
2685515Slinton  *
2695515Slinton  * This involves both saving pdx and interpreter values.
2705515Slinton  * LOOPADDR is the address of the main interpreter loop.
2715515Slinton  */
2725515Slinton 
2735515Slinton LOCAL pushenv(newpc)
2745515Slinton ADDRESS newpc;
2755515Slinton {
27630849Smckusick #ifdef tahoe
27730849Smckusick 	/* this should be done somewhere else, but... */
27830849Smckusick 	INTFP = process->fp;
27930849Smckusick #endif
2805515Slinton 	push(ADDRESS, pc);
2815515Slinton 	push(LINENO, curline);
2825515Slinton 	push(char *, cursource);
2835515Slinton 	push(BOOLEAN, isstopped);
2845515Slinton 	push(SYM *, curfunc);
2855515Slinton 	push(WORD, process->pc);
2865515Slinton 	push(WORD, process->sp);
2875515Slinton 	process->pc = LOOPADDR;
2885515Slinton 	pc = newpc;
28930849Smckusick #ifdef tahoe
29030849Smckusick 	process->reg[12] = pc + ENDOFF;
29130849Smckusick #else
2925515Slinton 	process->reg[11] = pc + ENDOFF;
29330849Smckusick #endif
2945515Slinton }
2955515Slinton 
2965515Slinton /*
2975515Slinton  * Pop back to the real world.
2985515Slinton  */
2995515Slinton 
3005515Slinton popenv()
3015515Slinton {
3025515Slinton 	register PROCESS *p;
3035515Slinton 	char *filename;
3045515Slinton 
3055515Slinton 	p = process;
3065515Slinton 	p->sp = pop(WORD);
3075515Slinton 	p->pc = pop(WORD);
3085515Slinton 	curfunc = pop(SYM *);
3095515Slinton 	isstopped = pop(BOOLEAN);
3105515Slinton 	filename = pop(char *);
3115515Slinton 	curline = pop(LINENO);
3125515Slinton 	pc = pop(ADDRESS);
31330849Smckusick #ifdef tahoe
31430849Smckusick 	p->reg[12] = pc + 1 + ENDOFF;
31530849Smckusick #endif
3165515Slinton 	if (filename != cursource) {
3175515Slinton 		skimsource(filename);
3185515Slinton 	}
3195515Slinton }
320