|
|
1.1 root 1: /* Copyright (c) 1979 Regents of the University of California */
2:
3: static char sccsid[] = "@(#)call.c 1.24 6/3/83";
4:
5: #include "whoami.h"
6: #include "0.h"
7: #include "tree.h"
8: #include "opcode.h"
9: #include "objfmt.h"
10: #ifdef PC
11: # include "pc.h"
12: # include "pcops.h"
13: #endif PC
14: #include "tmps.h"
15:
16: /*
17: * Call generates code for calls to
18: * user defined procedures and functions
19: * and is called by proc and funccod.
20: * P is the result of the lookup
21: * of the procedure/function symbol,
22: * and porf is PROC or FUNC.
23: * Psbn is the block number of p.
24: *
25: * the idea here is that regular scalar functions are just called,
26: * while structure functions and formal functions have their results
27: * stored in a temporary after the call.
28: * structure functions do this because they return pointers
29: * to static results, so we copy the static
30: * and return a pointer to the copy.
31: * formal functions do this because we have to save the result
32: * around a call to the runtime routine which restores the display,
33: * so we can't just leave the result lying around in registers.
34: * formal calls save the address of the descriptor in a local
35: * temporary, so it can be addressed for the call which restores
36: * the display (FRTN).
37: * calls to formal parameters pass the formal as a hidden argument
38: * to a special entry point for the formal call.
39: * [this is somewhat dependent on the way arguments are addressed.]
40: * so PROCs and scalar FUNCs look like
41: * p(...args...)
42: * structure FUNCs look like
43: * (temp = p(...args...),&temp)
44: * formal FPROCs look like
45: * ( t=p,( t -> entryaddr )(...args...,t,s),FRTN(t,s))
46: * formal scalar FFUNCs look like
47: * ( t=p,temp=( t -> entryaddr )(...args...,t,s),FRTN(t,s),temp)
48: * formal structure FFUNCs look like
49: * (t=p,temp = ( t -> entryaddr )(...args...,t,s),FRTN(t,s),&temp)
50: */
51: struct nl *
52: call(p, argv, porf, psbn)
53: struct nl *p;
54: int *argv, porf, psbn;
55: {
56: register struct nl *p1, *q;
57: int *r;
58: struct nl *p_type_class = classify( p -> type );
59: bool chk = TRUE;
60: struct nl *savedispnp; /* temporary to hold saved display */
61: # ifdef PC
62: long p_p2type = p2type( p );
63: long p_type_p2type = p2type( p -> type );
64: bool noarguments;
65: long calltype; /* type of the call */
66: /*
67: * these get used if temporaries and structures are used
68: */
69: struct nl *tempnlp;
70: long temptype; /* type of the temporary */
71: long p_type_width;
72: long p_type_align;
73: char extname[ BUFSIZ ];
74: struct nl *tempdescrp;
75: # endif PC
76:
77: if (p->class == FFUNC || p->class == FPROC) {
78: /*
79: * allocate space to save the display for formal calls
80: */
81: savedispnp = tmpalloc( sizeof display , NIL , NOREG );
82: }
83: # ifdef OBJ
84: if (p->class == FFUNC || p->class == FPROC) {
85: put(2, O_LV | cbn << 8 + INDX ,
86: (int) savedispnp -> value[ NL_OFFS ] );
87: put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
88: }
89: if (porf == FUNC) {
90: /*
91: * Push some space
92: * for the function return type
93: */
94: put(2, O_PUSH, leven(-lwidth(p->type)));
95: }
96: # endif OBJ
97: # ifdef PC
98: /*
99: * if this is a formal call,
100: * stash the address of the descriptor
101: * in a temporary so we can find it
102: * after the FCALL for the call to FRTN
103: */
104: if ( p -> class == FFUNC || p -> class == FPROC ) {
105: tempdescrp = tmpalloc(sizeof( struct formalrtn *) , NIL ,
106: REGOK );
107: putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
108: tempdescrp -> extra_flags , P2PTR|P2STRTY );
109: putRV( 0 , psbn , p -> value[ NL_OFFS ] ,
110: p -> extra_flags , P2PTR|P2STRTY );
111: putop( P2ASSIGN , P2PTR | P2STRTY );
112: }
113: /*
114: * if we have to store a temporary,
115: * temptype will be its type,
116: * otherwise, it's P2UNDEF.
117: */
118: temptype = P2UNDEF;
119: calltype = P2INT;
120: if ( porf == FUNC ) {
121: p_type_width = width( p -> type );
122: switch( p_type_class ) {
123: case TSTR:
124: case TSET:
125: case TREC:
126: case TFILE:
127: case TARY:
128: calltype = temptype = P2STRTY;
129: p_type_align = align( p -> type );
130: break;
131: default:
132: if ( p -> class == FFUNC ) {
133: calltype = temptype = p2type( p -> type );
134: }
135: break;
136: }
137: if ( temptype != P2UNDEF ) {
138: tempnlp = tmpalloc(p_type_width, p -> type, NOREG);
139: /*
140: * temp
141: * for (temp = ...
142: */
143: putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
144: tempnlp -> extra_flags , temptype );
145: }
146: }
147: switch ( p -> class ) {
148: case FUNC:
149: case PROC:
150: /*
151: * ... p( ...
152: */
153: sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) );
154: putleaf( P2ICON , 0 , 0 , p2type( p ) , extname );
155: break;
156: case FFUNC:
157: case FPROC:
158:
159: /*
160: * ... ( t -> entryaddr )( ...
161: */
162: /* the descriptor */
163: putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
164: tempdescrp -> extra_flags , P2PTR | P2STRTY );
165: /* the entry address within the descriptor */
166: if ( FENTRYOFFSET != 0 ) {
167: putleaf( P2ICON , FENTRYOFFSET , 0 , P2INT , 0 );
168: putop( P2PLUS ,
169: ADDTYPE(
170: ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) ,
171: P2PTR ) ,
172: P2PTR ) );
173: }
174: /*
175: * indirect to fetch the formal entry address
176: * with the result type of the routine.
177: */
178: if (p -> class == FFUNC) {
179: putop( P2UNARY P2MUL ,
180: ADDTYPE(ADDTYPE(p2type(p -> type), P2FTN),
181: P2PTR));
182: } else {
183: /* procedures are int returning functions */
184: putop( P2UNARY P2MUL ,
185: ADDTYPE(ADDTYPE(P2INT, P2FTN), P2PTR));
186: }
187: break;
188: default:
189: panic("call class");
190: }
191: noarguments = TRUE;
192: # endif PC
193: /*
194: * Loop and process each of
195: * arguments to the proc/func.
196: * ... ( ... args ... ) ...
197: */
198: for (p1 = plist(p); p1 != NIL; p1 = p1->chain) {
199: if (argv == NIL) {
200: error("Not enough arguments to %s", p->symbol);
201: return (NIL);
202: }
203: switch (p1->class) {
204: case REF:
205: /*
206: * Var parameter
207: */
208: r = argv[1];
209: if (r != NIL && r[0] != T_VAR) {
210: error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol);
211: chk = FALSE;
212: break;
213: }
214: q = lvalue( (int *) argv[1], MOD | ASGN , LREQ );
215: if (q == NIL) {
216: chk = FALSE;
217: break;
218: }
219: if (q != p1->type) {
220: error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol);
221: chk = FALSE;
222: break;
223: }
224: break;
225: case VAR:
226: /*
227: * Value parameter
228: */
229: # ifdef OBJ
230: q = rvalue(argv[1], p1->type , RREQ );
231: # endif OBJ
232: # ifdef PC
233: /*
234: * structure arguments require lvalues,
235: * scalars use rvalue.
236: */
237: switch( classify( p1 -> type ) ) {
238: case TFILE:
239: case TARY:
240: case TREC:
241: case TSET:
242: case TSTR:
243: q = stkrval( argv[1] , p1 -> type , LREQ );
244: break;
245: case TINT:
246: case TSCAL:
247: case TBOOL:
248: case TCHAR:
249: precheck( p1 -> type , "_RANG4" , "_RSNG4" );
250: q = stkrval( argv[1] , p1 -> type , RREQ );
251: postcheck(p1 -> type, nl+T4INT);
252: break;
253: case TDOUBLE:
254: q = stkrval( argv[1] , p1 -> type , RREQ );
255: sconv(p2type(q), P2DOUBLE);
256: break;
257: default:
258: q = rvalue( argv[1] , p1 -> type , RREQ );
259: break;
260: }
261: # endif PC
262: if (q == NIL) {
263: chk = FALSE;
264: break;
265: }
266: if (incompat(q, p1->type, argv[1])) {
267: cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol);
268: chk = FALSE;
269: break;
270: }
271: # ifdef OBJ
272: if (isa(p1->type, "bcsi"))
273: rangechk(p1->type, q);
274: if (q->class != STR)
275: convert(q, p1->type);
276: # endif OBJ
277: # ifdef PC
278: switch( classify( p1 -> type ) ) {
279: case TFILE:
280: case TARY:
281: case TREC:
282: case TSET:
283: case TSTR:
284: putstrop( P2STARG
285: , p2type( p1 -> type )
286: , lwidth( p1 -> type )
287: , align( p1 -> type ) );
288: }
289: # endif PC
290: break;
291: case FFUNC:
292: /*
293: * function parameter
294: */
295: q = flvalue( (int *) argv[1] , p1 );
296: chk = (chk && fcompat(q, p1));
297: break;
298: case FPROC:
299: /*
300: * procedure parameter
301: */
302: q = flvalue( (int *) argv[1] , p1 );
303: chk = (chk && fcompat(q, p1));
304: break;
305: default:
306: panic("call");
307: }
308: # ifdef PC
309: /*
310: * if this is the nth (>1) argument,
311: * hang it on the left linear list of arguments
312: */
313: if ( noarguments ) {
314: noarguments = FALSE;
315: } else {
316: putop( P2LISTOP , P2INT );
317: }
318: # endif PC
319: argv = argv[2];
320: }
321: if (argv != NIL) {
322: error("Too many arguments to %s", p->symbol);
323: rvlist(argv);
324: return (NIL);
325: }
326: if (chk == FALSE)
327: return NIL;
328: # ifdef OBJ
329: if ( p -> class == FFUNC || p -> class == FPROC ) {
330: put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]);
331: put(2, O_LV | cbn << 8 + INDX ,
332: (int) savedispnp -> value[ NL_OFFS ] );
333: put(1, O_FCALL);
334: put(2, O_FRTN, even(width(p->type)));
335: } else {
336: put(2, O_CALL | psbn << 8, (long)p->value[NL_ENTLOC]);
337: }
338: # endif OBJ
339: # ifdef PC
340: /*
341: * for formal calls: add the hidden argument
342: * which is the formal struct describing the
343: * environment of the routine.
344: * and the argument which is the address of the
345: * space into which to save the display.
346: */
347: if ( p -> class == FFUNC || p -> class == FPROC ) {
348: putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
349: tempdescrp -> extra_flags , P2PTR|P2STRTY );
350: if ( !noarguments ) {
351: putop( P2LISTOP , P2INT );
352: }
353: noarguments = FALSE;
354: putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] ,
355: savedispnp -> extra_flags , P2PTR | P2STRTY );
356: putop( P2LISTOP , P2INT );
357: }
358: /*
359: * do the actual call:
360: * either ... p( ... ) ...
361: * or ... ( t -> entryaddr )( ... ) ...
362: * and maybe an assignment.
363: */
364: if ( porf == FUNC ) {
365: switch ( p_type_class ) {
366: case TBOOL:
367: case TCHAR:
368: case TINT:
369: case TSCAL:
370: case TDOUBLE:
371: case TPTR:
372: putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) ,
373: p_type_p2type );
374: if ( p -> class == FFUNC ) {
375: putop( P2ASSIGN , p_type_p2type );
376: }
377: break;
378: default:
379: putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ),
380: ADDTYPE( p_type_p2type , P2PTR ) ,
381: p_type_width , p_type_align );
382: putstrop(P2STASG, ADDTYPE(p_type_p2type, P2PTR),
383: lwidth(p -> type), align(p -> type));
384: break;
385: }
386: } else {
387: putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT );
388: }
389: /*
390: * ( t=p , ... , FRTN( t ) ...
391: */
392: if ( p -> class == FFUNC || p -> class == FPROC ) {
393: putop( P2COMOP , P2INT );
394: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) ,
395: "_FRTN" );
396: putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] ,
397: tempdescrp -> extra_flags , P2PTR | P2STRTY );
398: putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] ,
399: savedispnp -> extra_flags , P2PTR | P2STRTY );
400: putop( P2LISTOP , P2INT );
401: putop( P2CALL , P2INT );
402: putop( P2COMOP , P2INT );
403: }
404: /*
405: * if required:
406: * either ... , temp )
407: * or ... , &temp )
408: */
409: if ( porf == FUNC && temptype != P2UNDEF ) {
410: if ( temptype != P2STRTY ) {
411: putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
412: tempnlp -> extra_flags , p_type_p2type );
413: } else {
414: putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] ,
415: tempnlp -> extra_flags , p_type_p2type );
416: }
417: putop( P2COMOP , P2INT );
418: }
419: if ( porf == PROC ) {
420: putdot( filename , line );
421: }
422: # endif PC
423: return (p->type);
424: }
425:
426: rvlist(al)
427: register int *al;
428: {
429:
430: for (; al != NIL; al = al[2])
431: rvalue( (int *) al[1], NLNIL , RREQ );
432: }
433:
434: /*
435: * check that two function/procedure namelist entries are compatible
436: */
437: bool
438: fcompat( formal , actual )
439: struct nl *formal;
440: struct nl *actual;
441: {
442: register struct nl *f_chain;
443: register struct nl *a_chain;
444: bool compat = TRUE;
445:
446: if ( formal == NIL || actual == NIL ) {
447: return FALSE;
448: }
449: for (a_chain = plist(actual), f_chain = plist(formal);
450: f_chain != NIL;
451: f_chain = f_chain->chain, a_chain = a_chain->chain) {
452: if (a_chain == NIL) {
453: error("%s %s declared on line %d has more arguments than",
454: parnam(formal->class), formal->symbol,
455: linenum(formal));
456: cerror("%s %s declared on line %d",
457: parnam(actual->class), actual->symbol,
458: linenum(actual));
459: return FALSE;
460: }
461: if ( a_chain -> class != f_chain -> class ) {
462: error("%s parameter %s of %s declared on line %d is not identical",
463: parnam(f_chain->class), f_chain->symbol,
464: formal->symbol, linenum(formal));
465: cerror("with %s parameter %s of %s declared on line %d",
466: parnam(a_chain->class), a_chain->symbol,
467: actual->symbol, linenum(actual));
468: compat = FALSE;
469: } else if (a_chain->class == FFUNC || a_chain->class == FPROC) {
470: compat = (compat && fcompat(f_chain, a_chain));
471: }
472: if ((a_chain->class != FPROC && f_chain->class != FPROC) &&
473: (a_chain->type != f_chain->type)) {
474: error("Type of %s parameter %s of %s declared on line %d is not identical",
475: parnam(f_chain->class), f_chain->symbol,
476: formal->symbol, linenum(formal));
477: cerror("to type of %s parameter %s of %s declared on line %d",
478: parnam(a_chain->class), a_chain->symbol,
479: actual->symbol, linenum(actual));
480: compat = FALSE;
481: }
482: }
483: if (a_chain != NIL) {
484: error("%s %s declared on line %d has fewer arguments than",
485: parnam(formal->class), formal->symbol,
486: linenum(formal));
487: cerror("%s %s declared on line %d",
488: parnam(actual->class), actual->symbol,
489: linenum(actual));
490: return FALSE;
491: }
492: return compat;
493: }
494:
495: char *
496: parnam(nltype)
497: int nltype;
498: {
499: switch(nltype) {
500: case REF:
501: return "var";
502: case VAR:
503: return "value";
504: case FUNC:
505: case FFUNC:
506: return "function";
507: case PROC:
508: case FPROC:
509: return "procedure";
510: default:
511: return "SNARK";
512: }
513: }
514:
515: plist(p)
516: struct nl *p;
517: {
518: switch (p->class) {
519: case FFUNC:
520: case FPROC:
521: return p->ptr[ NL_FCHAIN ];
522: case PROC:
523: case FUNC:
524: return p->chain;
525: default:
526: panic("plist");
527: }
528: }
529:
530: linenum(p)
531: struct nl *p;
532: {
533: if (p->class == FUNC)
534: return p->ptr[NL_FVAR]->value[NL_LINENO];
535: return p->value[NL_LINENO];
536: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.