#include "gc.h"
#include "../../pkg/runtime/funcdata.h"
-static int32 pointermap(Sym *gcsym, int32 offset);
-
int
hasdotdotdot(void)
{
p = gtext(n1->sym, stkoff);
sp = p;
-
- /*
- * generate funcdata symbol for this function.
- * data is filled in at the end of codgen().
- */
- snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++);
- gcsym = slookup(namebuf);
- gcsym->class = CSTATIC;
-
- memset(&nod, 0, sizeof nod);
- nod.op = ONAME;
- nod.sym = gcsym;
- nod.class = CSTATIC;
-
- gins(AFUNCDATA, nodconst(FUNCDATA_GC), &nod);
-
+
/*
* isolate first argument
*/
maxargsafe = xround(maxargsafe, 8);
sp->to.offset += maxargsafe;
+ snprint(namebuf, sizeof namebuf, "gc·%d", ngcsym++);
+ gcsym = slookup(namebuf);
+ gcsym->class = CSTATIC;
+
+ memset(&nod, 0, sizeof nod);
+ nod.op = ONAME;
+ nod.sym = gcsym;
+ nod.class = CSTATIC;
+
+ gins(AFUNCDATA, nodconst(FUNCDATA_GC), &nod);
+
// TODO(rsc): "stkoff" is not right. It does not account for
// the possibility of data stored in .safe variables.
// Unfortunately those move up and down just like
off = 0;
gextern(gcsym, nodconst(stkoff), off, 4); // locals
off += 4;
- off = pointermap(gcsym, off); // nptrs and ptrs[...]
+ gextern(gcsym, nodconst(0), off, 4); // nptrs
+ off += 4;
gcsym->type = typ(0, T);
gcsym->type->width = off;
}
boolgen(n, 1, Z);
return 0;
}
-
-// Makes a bitmap marking the the pointers in t. t starts at the given byte
-// offset in the argument list. The returned bitmap should be for pointer
-// indexes (relative to offset 0) between baseidx and baseidx+32.
-static int32
-pointermap_type(Type *t, int32 offset, int32 baseidx)
-{
- Type *t1;
- int32 idx;
- int32 m;
-
- switch(t->etype) {
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TINT:
- case TUINT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TFLOAT:
- case TDOUBLE:
- // non-pointer types
- return 0;
- case TIND:
- case TARRAY: // unlike Go, C passes arrays by reference
- // pointer types
- if((offset + t->offset) % ewidth[TIND] != 0)
- yyerror("unaligned pointer");
- idx = (offset + t->offset) / ewidth[TIND];
- if(idx >= baseidx && idx < baseidx + 32)
- return 1 << (idx - baseidx);
- return 0;
- case TSTRUCT:
- // build map recursively
- m = 0;
- for(t1=t->link; t1; t1=t1->down)
- m |= pointermap_type(t1, offset, baseidx);
- return m;
- case TUNION:
- // We require that all elements of the union have the same pointer map.
- m = pointermap_type(t->link, offset, baseidx);
- for(t1=t->link->down; t1; t1=t1->down) {
- if(pointermap_type(t1, offset, baseidx) != m)
- yyerror("invalid union in argument list - pointer maps differ");
- }
- return m;
- default:
- yyerror("can't handle arg type %s\n", tnames[t->etype]);
- return 0;
- }
-}
-
-// Compute a bit vector to describe the pointer containing locations
-// in the argument list. Adds the data to gcsym and returns the offset
-// of end of the bit vector.
-static int32
-pointermap(Sym *gcsym, int32 off)
-{
- int32 nptrs;
- int32 i;
- int32 s; // offset in argument list (in bytes)
- int32 m; // current ptrs[i/32]
- Type *t;
-
- if(hasdotdotdot()) {
- // give up for C vararg functions.
- // TODO: maybe make a map just for the args we do know?
- gextern(gcsym, nodconst(0), off, 4); // nptrs=0
- return off + 4;
- }
- nptrs = (argsize() + ewidth[TIND] - 1) / ewidth[TIND];
- gextern(gcsym, nodconst(nptrs), off, 4);
- off += 4;
-
- for(i = 0; i < nptrs; i += 32) {
- // generate mask for ptrs at offsets i ... i+31
- m = 0;
- s = align(0, thisfn->link, Aarg0, nil);
- if(s > 0 && i == 0) {
- // C Calling convention returns structs by copying
- // them to a location pointed to by a hidden first
- // argument. This first argument is a pointer.
- if(s != ewidth[TIND])
- yyerror("passbyptr arg not the right size");
- m = 1;
- }
- for(t=thisfn->down; t!=T; t=t->down) {
- if(t->etype == TVOID)
- continue;
- s = align(s, t, Aarg1, nil);
- m |= pointermap_type(t, s, i);
- s = align(s, t, Aarg2, nil);
- }
- gextern(gcsym, nodconst(m), off, 4);
- off += 4;
- }
- return off;
- // TODO: needs a test for nptrs>32
-}