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*30849Smckusick static char sccsid[] = "@(#)callproc.c	5.2 (Berkeley) 04/07/87";
922517Sdist #endif not lint
10*30849Smckusick 
115515Slinton /*
125515Slinton  * Evaluate a call to a procedure.
135515Slinton  *
145515Slinton  * This file is a botch as far as modularity is concerned.
155515Slinton  */
165515Slinton 
175515Slinton #include "defs.h"
185515Slinton #include "runtime.h"
195515Slinton #include "sym.h"
205515Slinton #include "tree.h"
215515Slinton #include "breakpoint.h"
225515Slinton #include "machine.h"
235515Slinton #include "process.h"
245515Slinton #include "source.h"
255515Slinton #include "frame.rep"
265515Slinton #include "sym/classes.h"
275515Slinton #include "sym/sym.rep"
285515Slinton #include "tree/tree.rep"
295515Slinton #include "process/process.rep"
305515Slinton #include "process/pxinfo.h"
315515Slinton 
325515Slinton LOCAL ADDRESS retaddr;
33*30849Smckusick #ifdef tahoe
34*30849Smckusick BOOLEAN didret;
35*30849Smckusick #endif
365515Slinton 
375515Slinton /*
385515Slinton  * Controlling logic of procedure calling.
395515Slinton  * Calling a procedure before ever executing the program must
405515Slinton  * be special cased.
415515Slinton  */
425515Slinton 
435515Slinton callproc(procnode, arglist)
445515Slinton NODE *procnode;
455515Slinton NODE *arglist;
465515Slinton {
47*30849Smckusick 	register SYM *proc;
48*30849Smckusick #ifdef tahoe
49*30849Smckusick 	register int tmpsp, tmptmp;
50*30849Smckusick 	extern BOOLEAN shouldrestart;
515515Slinton 
52*30849Smckusick 	if (shouldrestart) {
53*30849Smckusick 		initstart();
54*30849Smckusick 	}
55*30849Smckusick #endif
565515Slinton 	if (pc == 0) {
575515Slinton 		curline = firstline(program);
585515Slinton 		setbp(curline);
595515Slinton 		resume();
605515Slinton 		unsetbp(curline);
615515Slinton 	}
625515Slinton 	proc = procnode->nameval;
635515Slinton 	if (!isblock(proc)) {
645515Slinton 		error("\"%s\" is not a procedure or function", proc->symbol);
655515Slinton 	}
66*30849Smckusick #ifdef tahoe
67*30849Smckusick 	doret(process);
68*30849Smckusick 	tmpsp = process->sp;
69*30849Smckusick #endif
705659Slinton 	pushargs(proc, arglist);
71*30849Smckusick #ifdef tahoe
72*30849Smckusick 	tmptmp = tmpsp;
73*30849Smckusick 	tmpsp = process->sp;
74*30849Smckusick 	process->sp = tmptmp;
75*30849Smckusick #endif
765515Slinton 	pushenv(proc->symvalue.funcv.codeloc);
77*30849Smckusick #ifdef tahoe
78*30849Smckusick 	process->sp = tmpsp;
79*30849Smckusick #endif
805515Slinton 	pushframe(proc->blkno);
815515Slinton 	execute(proc);
825515Slinton 	/* NOTREACHED */
835515Slinton }
845515Slinton 
855515Slinton /*
865515Slinton  * Push the arguments on the process' stack.  We do this by first
875515Slinton  * evaluating them on the "eval" stack, then copying into the process'
885515Slinton  * space.
895515Slinton  */
905515Slinton 
915515Slinton LOCAL pushargs(proc, arglist)
925515Slinton SYM *proc;
935515Slinton NODE *arglist;
945515Slinton {
955515Slinton 	STACK *savesp;
965515Slinton 	int args_size;
975515Slinton 
985515Slinton 	savesp = sp;
99*30849Smckusick #ifdef tahoe
100*30849Smckusick 	/*
101*30849Smckusick 	 * evalargs hopefully keeps stack aligned, so we won't bother
102*30849Smckusick 	 * aligning it afterwards, neither will we align process->sp
103*30849Smckusick 	 * after subtracting args_size.
104*30849Smckusick 	 */
105*30849Smckusick #endif
1065515Slinton 	evalargs(proc->symbol, proc->chain, arglist);
1075515Slinton 	args_size = sp - savesp;
1085515Slinton 	process->sp -= args_size;
1095515Slinton 	dwrite(savesp, process->sp, args_size);
1105515Slinton 	sp = savesp;
1115515Slinton }
1125515Slinton 
1135515Slinton /*
1145515Slinton  * Evaluate arguments right-to-left because the eval stack
1155515Slinton  * grows up, px's stack grows down.
1165515Slinton  */
1175515Slinton 
1185515Slinton LOCAL evalargs(procname, arg, explist)
1195515Slinton char *procname;
1205515Slinton SYM *arg;
1215515Slinton NODE *explist;
1225515Slinton {
1235515Slinton 	NODE *exp;
1245515Slinton 	STACK *savesp;
1255515Slinton 	ADDRESS addr;
1265515Slinton 
1275515Slinton 	if (arg == NIL) {
1285515Slinton 		if (explist != NIL) {
1295515Slinton 			error("too many parameters to \"%s\"", procname);
1305515Slinton 		}
1315515Slinton 	} else if (explist == NIL) {
1325515Slinton 		error("not enough parameters to \"%s\"", procname);
1335515Slinton 	} else {
1345515Slinton 		if (explist->op != O_COMMA) {
1355515Slinton 			panic("evalargs: arglist missing comma");
1365515Slinton 		}
1375515Slinton 		savesp = sp;
1385515Slinton 		evalargs(procname, arg->chain, explist->right);
1395515Slinton 		exp = explist->left;
1405515Slinton 		if (!compatible(arg->type, exp->nodetype)) {
1415515Slinton 			sp = savesp;
1425515Slinton 			trerror("%t is not the same type as parameter \"%s\"",
1435515Slinton 				exp, arg->symbol);
1445515Slinton 		}
1455515Slinton 		if (arg->class == REF) {
1465515Slinton 			if (exp->op != O_RVAL) {
1475515Slinton 				sp = savesp;
1485515Slinton 				error("variable expected for parameter \"%s\"", arg->symbol);
1495515Slinton 			}
1505515Slinton 			addr = lval(exp->left);
1515515Slinton 			push(ADDRESS, addr);
1525515Slinton 		} else {
1535515Slinton 			eval(exp);
1545515Slinton 		}
1555515Slinton 	}
1565515Slinton }
1575515Slinton 
1585515Slinton /*
1595515Slinton  * Simulate a CALL instruction by pushing the appropriate
1605515Slinton  * stack frame information.
1615515Slinton  *
162*30849Smckusick  * Massage register 10 or 11 appropriately since it contains the
1635515Slinton  * stack frame pointer.
1645515Slinton  */
1655515Slinton 
1665515Slinton LOCAL pushframe(b)
1675515Slinton int b;
1685515Slinton {
1695515Slinton 	ADDRESS *newdp;
1705515Slinton 	FRAME callframe;
1715515Slinton 
1725515Slinton 	retaddr = program->symvalue.funcv.codeloc;
1735515Slinton 
1745515Slinton /*
1755515Slinton  * This stuff is set by the callee, just here to take up space.
1765515Slinton  */
1775515Slinton 	callframe.stackref = 0;
1785515Slinton 	callframe.file = 0;
1795515Slinton 	callframe.blockp = 0;
1805515Slinton 	callframe.save_loc = NIL;
1815515Slinton 	callframe.save_disp = NIL;
1825515Slinton 
1835515Slinton /*
1845515Slinton  * This is the useful stuff.
1855515Slinton  */
1865515Slinton 	callframe.save_dp = curdp();
1875515Slinton 	callframe.save_pc = retaddr + ENDOFF;
1885515Slinton 	callframe.save_lino = 0;
1895515Slinton 	newdp = DISPLAY + (2 * b);
1905515Slinton 	dwrite(&newdp, DP, sizeof(newdp));
1915515Slinton 	process->sp -= sizeof(callframe);
1925515Slinton 	dwrite(&callframe, process->sp, sizeof(callframe));
193*30849Smckusick #ifdef tahoe
194*30849Smckusick 	process->reg[11] = process->sp;
195*30849Smckusick #else
1965515Slinton 	process->reg[10] = process->sp;
197*30849Smckusick #endif
1985515Slinton }
1995515Slinton 
2005515Slinton /*
2015515Slinton  * Execute the procedure.  This routine does NOT return because it
2025515Slinton  * calls "cont", which doesn't return.  We set a CALLPROC breakpoint
2035515Slinton  * at "retaddr", the address where the called routine will return.
2045515Slinton  *
2055515Slinton  * The action for a CALLPROC is to call "procreturn" where we restore
2065515Slinton  * the environment.
2075515Slinton  */
2085515Slinton 
2095515Slinton LOCAL execute(f)
2105515Slinton SYM *f;
2115515Slinton {
2125515Slinton 	isstopped = TRUE;
2135515Slinton 	addbp(retaddr, CALLPROC, f, NIL, NIL, 0);
2145515Slinton 	cont();
2155515Slinton 	/* NOTREACHED */
2165515Slinton }
2175515Slinton 
2185515Slinton procreturn(f)
2195515Slinton SYM *f;
2205515Slinton {
2215515Slinton 	int len;
2225515Slinton 
223*30849Smckusick #ifdef tahoe
224*30849Smckusick 	doret(process);
225*30849Smckusick #endif
2265515Slinton 	printf("%s returns ", f->symbol);
2275515Slinton 	if (f->class == FUNC) {
2285515Slinton 		len = size(f->type);
2295515Slinton 		dread(sp, process->sp, len);
230*30849Smckusick #ifdef tahoe
231*30849Smckusick 		len = (len + 3) & ~3;
232*30849Smckusick #endif
2335515Slinton 		sp += len;
2345515Slinton 		printval(f->type);
2355515Slinton 		putchar('\n');
2365515Slinton 	} else {
2375515Slinton 		printf("successfully\n");
2385515Slinton 	}
2395515Slinton 	popenv();
2405515Slinton }
2415515Slinton 
2425515Slinton /*
2435515Slinton  * Push the current environment.
2445515Slinton  *
2455515Slinton  * This involves both saving pdx and interpreter values.
2465515Slinton  * LOOPADDR is the address of the main interpreter loop.
2475515Slinton  */
2485515Slinton 
2495515Slinton LOCAL pushenv(newpc)
2505515Slinton ADDRESS newpc;
2515515Slinton {
252*30849Smckusick #ifdef tahoe
253*30849Smckusick 	/* this should be done somewhere else, but... */
254*30849Smckusick 	INTFP = process->fp;
255*30849Smckusick #endif
2565515Slinton 	push(ADDRESS, pc);
2575515Slinton 	push(LINENO, curline);
2585515Slinton 	push(char *, cursource);
2595515Slinton 	push(BOOLEAN, isstopped);
2605515Slinton 	push(SYM *, curfunc);
2615515Slinton 	push(WORD, process->pc);
2625515Slinton 	push(WORD, process->sp);
2635515Slinton 	process->pc = LOOPADDR;
2645515Slinton 	pc = newpc;
265*30849Smckusick #ifdef tahoe
266*30849Smckusick 	process->reg[12] = pc + ENDOFF;
267*30849Smckusick #else
2685515Slinton 	process->reg[11] = pc + ENDOFF;
269*30849Smckusick #endif
2705515Slinton }
2715515Slinton 
2725515Slinton /*
2735515Slinton  * Pop back to the real world.
2745515Slinton  */
2755515Slinton 
2765515Slinton popenv()
2775515Slinton {
2785515Slinton 	register PROCESS *p;
2795515Slinton 	char *filename;
2805515Slinton 
2815515Slinton 	p = process;
2825515Slinton 	p->sp = pop(WORD);
2835515Slinton 	p->pc = pop(WORD);
2845515Slinton 	curfunc = pop(SYM *);
2855515Slinton 	isstopped = pop(BOOLEAN);
2865515Slinton 	filename = pop(char *);
2875515Slinton 	curline = pop(LINENO);
2885515Slinton 	pc = pop(ADDRESS);
289*30849Smckusick #ifdef tahoe
290*30849Smckusick 	p->reg[12] = pc + 1 + ENDOFF;
291*30849Smckusick #endif
2925515Slinton 	if (filename != cursource) {
2935515Slinton 		skimsource(filename);
2945515Slinton 	}
2955515Slinton }
296