Commit 2db5e4bb authored by Carl Shapiro's avatar Carl Shapiro

cmd/cc: use a temporary bitmap when constructing pointer maps

This change makes the way cc constructs pointer maps closer to
what gc does and is being done in preparation for changes to
the internal content of the pointer map such as a change to
distinguish interface pointers from ordinary pointers.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/12692043
parent 14903f65
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <u.h>
#include <libc.h>
#include "cc.h"
enum {
WORDSIZE = sizeof(uint32),
WORDBITS = 32,
};
uintptr
bvsize(uintptr n)
{
return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
}
Bvec*
bvalloc(int32 n)
{
Bvec *bv;
uintptr nbytes;
if(n < 0)
fatal(Z, "bvalloc: initial size is negative\n");
nbytes = sizeof(Bvec) + bvsize(n);
bv = malloc(nbytes);
if(bv == nil)
fatal(Z, "bvalloc: malloc failed\n");
memset(bv, 0, nbytes);
bv->n = n;
return bv;
}
void
bvset(Bvec *bv, int32 i)
{
uint32 mask;
if(i < 0 || i >= bv->n)
fatal(Z, "bvset: index %d is out of bounds with length %d\n", i, bv->n);
mask = 1 << (i % WORDBITS);
bv->b[i / WORDBITS] |= mask;
}
......@@ -52,6 +52,7 @@ typedef struct Hist Hist;
typedef struct Term Term;
typedef struct Init Init;
typedef struct Bits Bits;
typedef struct Bvec Bvec;
typedef struct Dynimp Dynimp;
typedef struct Dynexp Dynexp;
......@@ -76,6 +77,12 @@ struct Bits
uint32 b[BITS];
};
struct Bvec
{
int32 n; // number of bits
uint32 b[];
};
struct Node
{
Node* left;
......@@ -750,6 +757,12 @@ Bits blsh(uint);
int beq(Bits, Bits);
int bset(Bits, uint);
/*
* bv.c
*/
Bvec* bvalloc(int32 n);
void bvset(Bvec *bv, int32 i);
/*
* dpchk.c
*/
......
......@@ -31,7 +31,7 @@
#include "gc.h"
#include "../../pkg/runtime/funcdata.h"
static int32 pointermap(Sym *gcsym, int32 offset);
static void dumpgcargs(Type *fn, Sym *sym);
int
hasdotdotdot(void)
......@@ -82,7 +82,6 @@ codgen(Node *n, Node *nn)
Sym *gcsym, *gclocalssym;
static int ngcsym, ngclocalssym;
static char namebuf[40];
int32 off;
cursafe = 0;
curarg = 0;
......@@ -165,6 +164,8 @@ codgen(Node *n, Node *nn)
maxargsafe = xround(maxargsafe, 8);
sp->to.offset += maxargsafe;
dumpgcargs(thisfn, gcsym);
// 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
......@@ -174,16 +175,9 @@ codgen(Node *n, Node *nn)
// area its own section.
// That said, we've been using stkoff for months
// and nothing too terrible has happened.
off = 0;
off = pointermap(gcsym, off); // nptrs and ptrs[...]
gcsym->type = typ(0, T);
gcsym->type->width = off;
off = 0;
gextern(gclocalssym, nodconst(-stkoff), off, 4); // locals
off += 4;
gextern(gclocalssym, nodconst(-stkoff), 0, 4); // locals
gclocalssym->type = typ(0, T);
gclocalssym->type->width = off;
gclocalssym->type->width = 4;
}
void
......@@ -652,15 +646,12 @@ bcomplex(Node *n, Node *c)
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)
// Updates the bitvector with a set bit for each pointer containing
// value in the type description starting at offset.
static void
walktype1(Type *t, int32 offset, Bvec *bv)
{
Type *t1;
int32 idx;
int32 m;
switch(t->etype) {
case TCHAR:
......@@ -676,80 +667,74 @@ pointermap_type(Type *t, int32 offset, int32 baseidx)
case TFLOAT:
case TDOUBLE:
// non-pointer types
return 0;
break;
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;
bvset(bv, (offset + t->offset) / ewidth[TIND]);
break;
case TSTRUCT:
// build map recursively
m = 0;
for(t1=t->link; t1; t1=t1->down)
m |= pointermap_type(t1, offset, baseidx);
return m;
for(t1 = t->link; t1 != T; t1 = t1->down)
walktype1(t1, offset, bv);
break;
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;
walktype1(t->link, offset, bv);
break;
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)
static void
dumpgcargs(Type *fn, Sym *sym)
{
int32 nptrs;
int32 i;
int32 s; // offset in argument list (in bytes)
int32 m; // current ptrs[i/32]
Bvec *bv;
Type *t;
int32 i;
int32 symoffset, argoffset;
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])
gextern(sym, nodconst(0), 0, 4); // nptrs=0
symoffset = 4;
} else {
bv = bvalloc((argsize() + ewidth[TIND] - 1) / ewidth[TIND]);
argoffset = align(0, fn->link, Aarg0, nil);
if(argoffset > 0) {
// The 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(argoffset != ewidth[TIND])
yyerror("passbyptr arg not the right size");
m = 1;
bvset(bv, 0);
}
for(t=thisfn->down; t!=T; t=t->down) {
for(t = fn->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);
argoffset = align(argoffset, t, Aarg1, nil);
walktype1(t, argoffset, bv);
argoffset = align(argoffset, t, Aarg2, nil);
}
gextern(sym, nodconst(bv->n), 0, 4);
symoffset = 4;
for(i = 0; i < bv->n; i += 32) {
gextern(sym, nodconst(bv->b[i/32]), symoffset, 4);
symoffset += 4;
}
gextern(gcsym, nodconst(m), off, 4);
off += 4;
free(bv);
}
return off;
// TODO: needs a test for nptrs>32
sym->type = typ(0, T);
sym->type->width = symoffset;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment