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