1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)callproc.c 5.2 (Berkeley) 04/07/87"; 9 #endif not lint 10 11 /* 12 * Evaluate a call to a procedure. 13 * 14 * This file is a botch as far as modularity is concerned. 15 */ 16 17 #include "defs.h" 18 #include "runtime.h" 19 #include "sym.h" 20 #include "tree.h" 21 #include "breakpoint.h" 22 #include "machine.h" 23 #include "process.h" 24 #include "source.h" 25 #include "frame.rep" 26 #include "sym/classes.h" 27 #include "sym/sym.rep" 28 #include "tree/tree.rep" 29 #include "process/process.rep" 30 #include "process/pxinfo.h" 31 32 LOCAL ADDRESS retaddr; 33 #ifdef tahoe 34 BOOLEAN didret; 35 #endif 36 37 /* 38 * Controlling logic of procedure calling. 39 * Calling a procedure before ever executing the program must 40 * be special cased. 41 */ 42 43 callproc(procnode, arglist) 44 NODE *procnode; 45 NODE *arglist; 46 { 47 register SYM *proc; 48 #ifdef tahoe 49 register int tmpsp, tmptmp; 50 extern BOOLEAN shouldrestart; 51 52 if (shouldrestart) { 53 initstart(); 54 } 55 #endif 56 if (pc == 0) { 57 curline = firstline(program); 58 setbp(curline); 59 resume(); 60 unsetbp(curline); 61 } 62 proc = procnode->nameval; 63 if (!isblock(proc)) { 64 error("\"%s\" is not a procedure or function", proc->symbol); 65 } 66 #ifdef tahoe 67 doret(process); 68 tmpsp = process->sp; 69 #endif 70 pushargs(proc, arglist); 71 #ifdef tahoe 72 tmptmp = tmpsp; 73 tmpsp = process->sp; 74 process->sp = tmptmp; 75 #endif 76 pushenv(proc->symvalue.funcv.codeloc); 77 #ifdef tahoe 78 process->sp = tmpsp; 79 #endif 80 pushframe(proc->blkno); 81 execute(proc); 82 /* NOTREACHED */ 83 } 84 85 /* 86 * Push the arguments on the process' stack. We do this by first 87 * evaluating them on the "eval" stack, then copying into the process' 88 * space. 89 */ 90 91 LOCAL pushargs(proc, arglist) 92 SYM *proc; 93 NODE *arglist; 94 { 95 STACK *savesp; 96 int args_size; 97 98 savesp = sp; 99 #ifdef tahoe 100 /* 101 * evalargs hopefully keeps stack aligned, so we won't bother 102 * aligning it afterwards, neither will we align process->sp 103 * after subtracting args_size. 104 */ 105 #endif 106 evalargs(proc->symbol, proc->chain, arglist); 107 args_size = sp - savesp; 108 process->sp -= args_size; 109 dwrite(savesp, process->sp, args_size); 110 sp = savesp; 111 } 112 113 /* 114 * Evaluate arguments right-to-left because the eval stack 115 * grows up, px's stack grows down. 116 */ 117 118 LOCAL evalargs(procname, arg, explist) 119 char *procname; 120 SYM *arg; 121 NODE *explist; 122 { 123 NODE *exp; 124 STACK *savesp; 125 ADDRESS addr; 126 127 if (arg == NIL) { 128 if (explist != NIL) { 129 error("too many parameters to \"%s\"", procname); 130 } 131 } else if (explist == NIL) { 132 error("not enough parameters to \"%s\"", procname); 133 } else { 134 if (explist->op != O_COMMA) { 135 panic("evalargs: arglist missing comma"); 136 } 137 savesp = sp; 138 evalargs(procname, arg->chain, explist->right); 139 exp = explist->left; 140 if (!compatible(arg->type, exp->nodetype)) { 141 sp = savesp; 142 trerror("%t is not the same type as parameter \"%s\"", 143 exp, arg->symbol); 144 } 145 if (arg->class == REF) { 146 if (exp->op != O_RVAL) { 147 sp = savesp; 148 error("variable expected for parameter \"%s\"", arg->symbol); 149 } 150 addr = lval(exp->left); 151 push(ADDRESS, addr); 152 } else { 153 eval(exp); 154 } 155 } 156 } 157 158 /* 159 * Simulate a CALL instruction by pushing the appropriate 160 * stack frame information. 161 * 162 * Massage register 10 or 11 appropriately since it contains the 163 * stack frame pointer. 164 */ 165 166 LOCAL pushframe(b) 167 int b; 168 { 169 ADDRESS *newdp; 170 FRAME callframe; 171 172 retaddr = program->symvalue.funcv.codeloc; 173 174 /* 175 * This stuff is set by the callee, just here to take up space. 176 */ 177 callframe.stackref = 0; 178 callframe.file = 0; 179 callframe.blockp = 0; 180 callframe.save_loc = NIL; 181 callframe.save_disp = NIL; 182 183 /* 184 * This is the useful stuff. 185 */ 186 callframe.save_dp = curdp(); 187 callframe.save_pc = retaddr + ENDOFF; 188 callframe.save_lino = 0; 189 newdp = DISPLAY + (2 * b); 190 dwrite(&newdp, DP, sizeof(newdp)); 191 process->sp -= sizeof(callframe); 192 dwrite(&callframe, process->sp, sizeof(callframe)); 193 #ifdef tahoe 194 process->reg[11] = process->sp; 195 #else 196 process->reg[10] = process->sp; 197 #endif 198 } 199 200 /* 201 * Execute the procedure. This routine does NOT return because it 202 * calls "cont", which doesn't return. We set a CALLPROC breakpoint 203 * at "retaddr", the address where the called routine will return. 204 * 205 * The action for a CALLPROC is to call "procreturn" where we restore 206 * the environment. 207 */ 208 209 LOCAL execute(f) 210 SYM *f; 211 { 212 isstopped = TRUE; 213 addbp(retaddr, CALLPROC, f, NIL, NIL, 0); 214 cont(); 215 /* NOTREACHED */ 216 } 217 218 procreturn(f) 219 SYM *f; 220 { 221 int len; 222 223 #ifdef tahoe 224 doret(process); 225 #endif 226 printf("%s returns ", f->symbol); 227 if (f->class == FUNC) { 228 len = size(f->type); 229 dread(sp, process->sp, len); 230 #ifdef tahoe 231 len = (len + 3) & ~3; 232 #endif 233 sp += len; 234 printval(f->type); 235 putchar('\n'); 236 } else { 237 printf("successfully\n"); 238 } 239 popenv(); 240 } 241 242 /* 243 * Push the current environment. 244 * 245 * This involves both saving pdx and interpreter values. 246 * LOOPADDR is the address of the main interpreter loop. 247 */ 248 249 LOCAL pushenv(newpc) 250 ADDRESS newpc; 251 { 252 #ifdef tahoe 253 /* this should be done somewhere else, but... */ 254 INTFP = process->fp; 255 #endif 256 push(ADDRESS, pc); 257 push(LINENO, curline); 258 push(char *, cursource); 259 push(BOOLEAN, isstopped); 260 push(SYM *, curfunc); 261 push(WORD, process->pc); 262 push(WORD, process->sp); 263 process->pc = LOOPADDR; 264 pc = newpc; 265 #ifdef tahoe 266 process->reg[12] = pc + ENDOFF; 267 #else 268 process->reg[11] = pc + ENDOFF; 269 #endif 270 } 271 272 /* 273 * Pop back to the real world. 274 */ 275 276 popenv() 277 { 278 register PROCESS *p; 279 char *filename; 280 281 p = process; 282 p->sp = pop(WORD); 283 p->pc = pop(WORD); 284 curfunc = pop(SYM *); 285 isstopped = pop(BOOLEAN); 286 filename = pop(char *); 287 curline = pop(LINENO); 288 pc = pop(ADDRESS); 289 #ifdef tahoe 290 p->reg[12] = pc + 1 + ENDOFF; 291 #endif 292 if (filename != cursource) { 293 skimsource(filename); 294 } 295 } 296