This source file includes following definitions.
- ispkgin
- isforkfunc
- racewalk
- racewalklist
- racewalknode
- isartificial
- callinstr
- makeaddable
- uintptraddr
- basenod
- detachexpr
- foreachnode
- foreachlist
- foreach
- hascallspred
- appendinit
#include <u.h>
#include <libc.h>
#include "go.h"
static void racewalklist(NodeList *l, NodeList **init);
static void racewalknode(Node **np, NodeList **init, int wr, int skip);
static int callinstr(Node **n, NodeList **init, int wr, int skip);
static Node* uintptraddr(Node *n);
static void makeaddable(Node *n);
static Node* basenod(Node *n);
static void foreach(Node *n, void(*f)(Node*, void*), void *c);
static void hascallspred(Node *n, void *c);
static void appendinit(Node **np, NodeList *init);
static Node* detachexpr(Node *n, NodeList **init);
static const char *omit_pkgs[] = {"runtime", "runtime/race"};
static const char *noinst_pkgs[] = {"sync", "sync/atomic"};
static int
ispkgin(const char **pkgs, int n)
{
int i;
if(myimportpath) {
for(i=0; i<n; i++) {
if(strcmp(myimportpath, pkgs[i]) == 0)
return 1;
}
}
return 0;
}
static int
isforkfunc(Node *fn)
{
return myimportpath != nil && strcmp(myimportpath, "syscall") == 0 &&
strcmp(fn->nname->sym->name, "forkAndExecInChild") == 0;
}
void
racewalk(Node *fn)
{
Node *nd;
Node *nodpc;
char s[1024];
if(ispkgin(omit_pkgs, nelem(omit_pkgs)) || isforkfunc(fn))
return;
if(!ispkgin(noinst_pkgs, nelem(noinst_pkgs))) {
racewalklist(fn->nbody, nil);
racewalklist(fn->exit, nil);
}
nodpc = nod(OXXX, nil, nil);
*nodpc = *nodfp;
nodpc->type = types[TUINTPTR];
nodpc->xoffset = -widthptr;
nd = mkcall("racefuncenter", T, nil, nodpc);
fn->enter = concat(list1(nd), fn->enter);
nd = mkcall("racefuncexit", T, nil);
fn->exit = list(fn->exit, nd);
if(debug['W']) {
snprint(s, sizeof(s), "after racewalk %S", fn->nname->sym);
dumplist(s, fn->nbody);
snprint(s, sizeof(s), "enter %S", fn->nname->sym);
dumplist(s, fn->enter);
snprint(s, sizeof(s), "exit %S", fn->nname->sym);
dumplist(s, fn->exit);
}
}
static void
racewalklist(NodeList *l, NodeList **init)
{
NodeList *instr;
for(; l; l = l->next) {
instr = nil;
racewalknode(&l->n, &instr, 0, 0);
if(init == nil)
l->n->ninit = concat(l->n->ninit, instr);
else
*init = concat(*init, instr);
}
}
static void
racewalknode(Node **np, NodeList **init, int wr, int skip)
{
Node *n, *n1;
NodeList *l;
NodeList *fini;
n = *np;
if(n == N)
return;
if(debug['w'] > 1)
dump("racewalk-before", n);
setlineno(n);
if(init == nil)
fatal("racewalk: bad init list");
if(init == &n->ninit) {
l = n->ninit;
n->ninit = nil;
racewalklist(l, nil);
racewalknode(&n, &l, wr, skip);
appendinit(&n, l);
*np = n;
return;
}
racewalklist(n->ninit, nil);
switch(n->op) {
default:
fatal("racewalk: unknown node type %O", n->op);
case OASOP:
case OAS:
case OAS2:
case OAS2RECV:
case OAS2FUNC:
case OAS2MAPR:
racewalknode(&n->left, init, 1, 0);
racewalknode(&n->right, init, 0, 0);
goto ret;
case OCFUNC:
case OVARKILL:
goto ret;
case OBLOCK:
if(n->list == nil)
goto ret;
switch(n->list->n->op) {
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
racewalknode(&n->list->n, &n->list->n->ninit, 0, 0);
fini = nil;
racewalklist(n->list->next, &fini);
n->list = concat(n->list, fini);
break;
default:
racewalklist(n->list, nil);
break;
}
goto ret;
case ODEFER:
racewalknode(&n->left, init, 0, 0);
goto ret;
case OPROC:
racewalknode(&n->left, init, 0, 0);
goto ret;
case OCALLINTER:
racewalknode(&n->left, init, 0, 0);
goto ret;
case OCALLFUNC:
racewalknode(&n->left, init, 0, 0);
goto ret;
case ONOT:
case OMINUS:
case OPLUS:
case OREAL:
case OIMAG:
case OCOM:
racewalknode(&n->left, init, wr, 0);
goto ret;
case ODOTINTER:
racewalknode(&n->left, init, 0, 0);
goto ret;
case ODOT:
racewalknode(&n->left, init, 0, 1);
callinstr(&n, init, wr, skip);
goto ret;
case ODOTPTR:
racewalknode(&n->left, init, 0, 0);
callinstr(&n, init, wr, skip);
goto ret;
case OIND:
racewalknode(&n->left, init, 0, 0);
callinstr(&n, init, wr, skip);
goto ret;
case OSPTR:
case OLEN:
case OCAP:
racewalknode(&n->left, init, 0, 0);
if(istype(n->left->type, TMAP)) {
n1 = nod(OCONVNOP, n->left, N);
n1->type = ptrto(types[TUINT8]);
n1 = nod(OIND, n1, N);
typecheck(&n1, Erv);
callinstr(&n1, init, 0, skip);
}
goto ret;
case OLSH:
case ORSH:
case OLROT:
case OAND:
case OANDNOT:
case OOR:
case OXOR:
case OSUB:
case OMUL:
case OHMUL:
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case OADD:
case OCOMPLEX:
racewalknode(&n->left, init, wr, 0);
racewalknode(&n->right, init, wr, 0);
goto ret;
case OANDAND:
case OOROR:
racewalknode(&n->left, init, wr, 0);
racewalknode(&n->right, &n->right->ninit, wr, 0);
goto ret;
case ONAME:
callinstr(&n, init, wr, skip);
goto ret;
case OCONV:
racewalknode(&n->left, init, wr, 0);
goto ret;
case OCONVNOP:
racewalknode(&n->left, init, wr, 0);
goto ret;
case ODIV:
case OMOD:
racewalknode(&n->left, init, wr, 0);
racewalknode(&n->right, init, wr, 0);
goto ret;
case OINDEX:
if(!isfixedarray(n->left->type))
racewalknode(&n->left, init, 0, 0);
else if(!islvalue(n->left)) {
racewalknode(&n->left, init, wr, 0);
racewalknode(&n->right, init, 0, 0);
goto ret;
}
racewalknode(&n->right, init, 0, 0);
if(n->left->type->etype != TSTRING)
callinstr(&n, init, wr, skip);
goto ret;
case OSLICE:
case OSLICEARR:
case OSLICE3:
case OSLICE3ARR:
goto ret;
case OADDR:
racewalknode(&n->left, init, 0, 1);
goto ret;
case OEFACE:
racewalknode(&n->left, init, 0, 0);
racewalknode(&n->right, init, 0, 0);
goto ret;
case OITAB:
racewalknode(&n->left, init, 0, 0);
goto ret;
case OSEND:
case ORECV:
case OCLOSE:
case ONEW:
case OXCASE:
case OXFALL:
case OCASE:
case OPANIC:
case ORECOVER:
case OCONVIFACE:
case OCMPIFACE:
case OMAKECHAN:
case OMAKEMAP:
case OMAKESLICE:
case OCALL:
case OCOPY:
case OAPPEND:
case ORUNESTR:
case OARRAYBYTESTR:
case OARRAYRUNESTR:
case OSTRARRAYBYTE:
case OSTRARRAYRUNE:
case OINDEXMAP:
case OCMPSTR:
case OADDSTR:
case ODOTTYPE:
case ODOTTYPE2:
case OAS2DOTTYPE:
case OCALLPART:
case OCLOSURE:
case ORANGE:
case OARRAYLIT:
case OMAPLIT:
case OSTRUCTLIT:
yyerror("racewalk: %O must be lowered by now", n->op);
goto ret;
case ORROTC:
case OEXTEND:
yyerror("racewalk: %O cannot exist now", n->op);
goto ret;
case OFOR:
case OIF:
case OCALLMETH:
case ORETURN:
case ORETJMP:
case OSWITCH:
case OSELECT:
case OEMPTY:
case OBREAK:
case OCONTINUE:
case OFALL:
case OGOTO:
case OLABEL:
goto ret;
case OPRINT:
case OPRINTN:
case OCHECKNIL:
case OPARAM:
case OCLOSUREVAR:
case ODOTMETH:
case OINDREG:
case ODCL:
case ODCLCONST:
case ODCLTYPE:
case OTYPE:
case ONONAME:
case OLITERAL:
case OSLICESTR:
case OTYPESW:
goto ret;
}
ret:
if(n->op != OBLOCK)
racewalklist(n->list, init);
racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
racewalklist(n->nbody, nil);
racewalklist(n->nelse, nil);
racewalklist(n->rlist, nil);
*np = n;
}
static int
isartificial(Node *n)
{
if(n->op == ONAME && n->sym != S && n->sym->name != nil) {
if(strcmp(n->sym->name, "_") == 0)
return 1;
if(strncmp(n->sym->name, "autotmp_", sizeof("autotmp_")-1) == 0)
return 1;
if(strncmp(n->sym->name, "statictmp_", sizeof("statictmp_")-1) == 0)
return 1;
if(n->sym->pkg && n->sym->pkg->name && strcmp(n->sym->pkg->name, "go.itab") == 0)
return 1;
}
return 0;
}
static int
callinstr(Node **np, NodeList **init, int wr, int skip)
{
Node *f, *b, *n;
Type *t;
int class, hascalls;
n = *np;
if(skip || n->type == T || n->type->etype >= TIDEAL)
return 0;
t = n->type;
if(isartificial(n))
return 0;
b = basenod(n);
if(isartificial(b))
return 0;
class = b->class;
if((class&PHEAP) || class == PPARAMREF || class == PEXTERN
|| b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) {
hascalls = 0;
foreach(n, hascallspred, &hascalls);
if(hascalls) {
n = detachexpr(n, init);
*np = n;
}
n = treecopy(n);
makeaddable(n);
if(t->etype == TSTRUCT || isfixedarray(t)) {
f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n),
nodintconst(t->width));
} else
f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n));
*init = list(*init, f);
return 1;
}
return 0;
}
static void
makeaddable(Node *n)
{
switch(n->op) {
case OINDEX:
if(isfixedarray(n->left->type))
makeaddable(n->left);
break;
case ODOT:
case OXDOT:
if(n->left->op == OCONVNOP)
n->left = n->left->left;
makeaddable(n->left);
break;
case ODOTPTR:
default:
break;
}
}
static Node*
uintptraddr(Node *n)
{
Node *r;
r = nod(OADDR, n, N);
r->bounded = 1;
r = conv(r, types[TUNSAFEPTR]);
r = conv(r, types[TUINTPTR]);
return r;
}
static Node*
basenod(Node *n)
{
for(;;) {
if(n->op == ODOT || n->op == OXDOT || n->op == OCONVNOP || n->op == OCONV || n->op == OPAREN) {
n = n->left;
continue;
}
if(n->op == OINDEX && isfixedarray(n->type)) {
n = n->left;
continue;
}
break;
}
return n;
}
static Node*
detachexpr(Node *n, NodeList **init)
{
Node *addr, *as, *ind, *l;
addr = nod(OADDR, n, N);
l = temp(ptrto(n->type));
as = nod(OAS, l, addr);
typecheck(&as, Etop);
walkexpr(&as, init);
*init = list(*init, as);
ind = nod(OIND, l, N);
typecheck(&ind, Erv);
walkexpr(&ind, init);
return ind;
}
static void
foreachnode(Node *n, void(*f)(Node*, void*), void *c)
{
if(n)
f(n, c);
}
static void
foreachlist(NodeList *l, void(*f)(Node*, void*), void *c)
{
for(; l; l = l->next)
foreachnode(l->n, f, c);
}
static void
foreach(Node *n, void(*f)(Node*, void*), void *c)
{
foreachlist(n->ninit, f, c);
foreachnode(n->left, f, c);
foreachnode(n->right, f, c);
foreachlist(n->list, f, c);
foreachnode(n->ntest, f, c);
foreachnode(n->nincr, f, c);
foreachlist(n->nbody, f, c);
foreachlist(n->nelse, f, c);
foreachlist(n->rlist, f, c);
}
static void
hascallspred(Node *n, void *c)
{
switch(n->op) {
case OCALL:
case OCALLFUNC:
case OCALLMETH:
case OCALLINTER:
(*(int*)c)++;
}
}
static void
appendinit(Node **np, NodeList *init)
{
Node *n;
if(init == nil)
return;
n = *np;
switch(n->op) {
case ONAME:
case OLITERAL:
n = nod(OCONVNOP, n, N);
n->type = n->left->type;
n->typecheck = 1;
*np = n;
break;
}
n->ninit = concat(n->ninit, init);
n->ullman = UINF;
}