github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/gc/closure.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  /*
     6   * function literals aka closures
     7   */
     8  
     9  #include <u.h>
    10  #include <libc.h>
    11  #include "go.h"
    12  
    13  void
    14  closurehdr(Node *ntype)
    15  {
    16  	Node *n, *name, *a;
    17  	NodeList *l;
    18  
    19  	n = nod(OCLOSURE, N, N);
    20  	n->ntype = ntype;
    21  	n->funcdepth = funcdepth;
    22  
    23  	funchdr(n);
    24  
    25  	// steal ntype's argument names and
    26  	// leave a fresh copy in their place.
    27  	// references to these variables need to
    28  	// refer to the variables in the external
    29  	// function declared below; see walkclosure.
    30  	n->list = ntype->list;
    31  	n->rlist = ntype->rlist;
    32  	ntype->list = nil;
    33  	ntype->rlist = nil;
    34  	for(l=n->list; l; l=l->next) {
    35  		name = l->n->left;
    36  		if(name)
    37  			name = newname(name->sym);
    38  		a = nod(ODCLFIELD, name, l->n->right);
    39  		a->isddd = l->n->isddd;
    40  		if(name)
    41  			name->isddd = a->isddd;
    42  		ntype->list = list(ntype->list, a);
    43  	}
    44  	for(l=n->rlist; l; l=l->next) {
    45  		name = l->n->left;
    46  		if(name)
    47  			name = newname(name->sym);
    48  		ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
    49  	}
    50  }
    51  
    52  Node*
    53  closurebody(NodeList *body)
    54  {
    55  	Node *func, *v;
    56  	NodeList *l;
    57  
    58  	if(body == nil)
    59  		body = list1(nod(OEMPTY, N, N));
    60  
    61  	func = curfn;
    62  	func->nbody = body;
    63  	func->endlineno = lineno;
    64  	funcbody(func);
    65  
    66  	// closure-specific variables are hanging off the
    67  	// ordinary ones in the symbol table; see oldname.
    68  	// unhook them.
    69  	// make the list of pointers for the closure call.
    70  	for(l=func->cvars; l; l=l->next) {
    71  		v = l->n;
    72  		v->closure->closure = v->outer;
    73  		v->heapaddr = nod(OADDR, oldname(v->sym), N);
    74  	}
    75  
    76  	return func;
    77  }
    78  
    79  static Node* makeclosure(Node *func);
    80  
    81  void
    82  typecheckclosure(Node *func, int top)
    83  {
    84  	Node *oldfn;
    85  	NodeList *l;
    86  	Node *v;
    87  
    88  	oldfn = curfn;
    89  	typecheck(&func->ntype, Etype);
    90  	func->type = func->ntype->type;
    91  	
    92  	// Type check the body now, but only if we're inside a function.
    93  	// At top level (in a variable initialization: curfn==nil) we're not
    94  	// ready to type check code yet; we'll check it later, because the
    95  	// underlying closure function we create is added to xtop.
    96  	if(curfn && func->type != T) {
    97  		curfn = func;
    98  		typechecklist(func->nbody, Etop);
    99  		curfn = oldfn;
   100  	}
   101  
   102  	// type check the & of closed variables outside the closure,
   103  	// so that the outer frame also grabs them and knows they
   104  	// escape.
   105  	func->enter = nil;
   106  	for(l=func->cvars; l; l=l->next) {
   107  		v = l->n;
   108  		if(v->type == T) {
   109  			// if v->type is nil, it means v looked like it was
   110  			// going to be used in the closure but wasn't.
   111  			// this happens because when parsing a, b, c := f()
   112  			// the a, b, c gets parsed as references to older
   113  			// a, b, c before the parser figures out this is a
   114  			// declaration.
   115  			v->op = 0;
   116  			continue;
   117  		}
   118  		// For a closure that is called in place, but not
   119  		// inside a go statement, avoid moving variables to the heap.
   120  		if ((top & (Ecall|Eproc)) == Ecall)
   121  			v->heapaddr->etype = 1;
   122  		typecheck(&v->heapaddr, Erv);
   123  		func->enter = list(func->enter, v->heapaddr);
   124  		v->heapaddr = N;
   125  	}
   126  
   127  	// Create top-level function 
   128  	xtop = list(xtop, makeclosure(func));
   129  }
   130  
   131  static Node*
   132  makeclosure(Node *func)
   133  {
   134  	Node *xtype, *v, *addr, *xfunc, *cv;
   135  	NodeList *l, *body;
   136  	static int closgen;
   137  	char *p;
   138  	vlong offset;
   139  
   140  	/*
   141  	 * wrap body in external function
   142  	 * that begins by reading closure parameters.
   143  	 */
   144  	xtype = nod(OTFUNC, N, N);
   145  	xtype->list = func->list;
   146  	xtype->rlist = func->rlist;
   147  
   148  	// create the function
   149  	xfunc = nod(ODCLFUNC, N, N);
   150  	snprint(namebuf, sizeof namebuf, "func·%.3d", ++closgen);
   151  	xfunc->nname = newname(lookup(namebuf));
   152  	xfunc->nname->sym->flags |= SymExported; // disable export
   153  	xfunc->nname->ntype = xtype;
   154  	xfunc->nname->defn = xfunc;
   155  	declare(xfunc->nname, PFUNC);
   156  	xfunc->nname->funcdepth = func->funcdepth;
   157  	xfunc->funcdepth = func->funcdepth;
   158  	xfunc->endlineno = func->endlineno;
   159  	
   160  	// declare variables holding addresses taken from closure
   161  	// and initialize in entry prologue.
   162  	body = nil;
   163  	offset = widthptr;
   164  	xfunc->needctxt = func->cvars != nil;
   165  	for(l=func->cvars; l; l=l->next) {
   166  		v = l->n;
   167  		if(v->op == 0)
   168  			continue;
   169  		addr = nod(ONAME, N, N);
   170  		p = smprint("&%s", v->sym->name);
   171  		addr->sym = lookup(p);
   172  		free(p);
   173  		addr->ntype = nod(OIND, typenod(v->type), N);
   174  		addr->class = PAUTO;
   175  		addr->addable = 1;
   176  		addr->ullman = 1;
   177  		addr->used = 1;
   178  		addr->curfn = xfunc;
   179  		xfunc->dcl = list(xfunc->dcl, addr);
   180  		v->heapaddr = addr;
   181  		cv = nod(OCLOSUREVAR, N, N);
   182  		cv->type = ptrto(v->type);
   183  		cv->xoffset = offset;
   184  		body = list(body, nod(OAS, addr, cv));
   185  		offset += widthptr;
   186  	}
   187  	typechecklist(body, Etop);
   188  	walkstmtlist(body);
   189  	xfunc->enter = body;
   190  
   191  	xfunc->nbody = func->nbody;
   192  	xfunc->dcl = concat(func->dcl, xfunc->dcl);
   193  	if(xfunc->nbody == nil)
   194  		fatal("empty body - won't generate any code");
   195  	typecheck(&xfunc, Etop);
   196  
   197  	xfunc->closure = func;
   198  	func->closure = xfunc;
   199  	
   200  	func->nbody = nil;
   201  	func->list = nil;
   202  	func->rlist = nil;
   203  
   204  	return xfunc;
   205  }
   206  
   207  Node*
   208  walkclosure(Node *func, NodeList **init)
   209  {
   210  	Node *clos, *typ;
   211  	NodeList *l;
   212  	char buf[20];
   213  	int narg;
   214  
   215  	// If no closure vars, don't bother wrapping.
   216  	if(func->cvars == nil)
   217  		return func->closure->nname;
   218  
   219  	// Create closure in the form of a composite literal.
   220  	// supposing the closure captures an int i and a string s
   221  	// and has one float64 argument and no results,
   222  	// the generated code looks like:
   223  	//
   224  	//	clos = &struct{F uintptr; A0 *int; A1 *string}{func·001, &i, &s}
   225  	//
   226  	// The use of the struct provides type information to the garbage
   227  	// collector so that it can walk the closure. We could use (in this case)
   228  	// [3]unsafe.Pointer instead, but that would leave the gc in the dark.
   229  	// The information appears in the binary in the form of type descriptors;
   230  	// the struct is unnamed so that closures in multiple packages with the
   231  	// same struct type can share the descriptor.
   232  
   233  	narg = 0;
   234  	typ = nod(OTSTRUCT, N, N);
   235  	typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
   236  	for(l=func->cvars; l; l=l->next) {
   237  		if(l->n->op == 0)
   238  			continue;
   239  		snprint(buf, sizeof buf, "A%d", narg++);
   240  		typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup(buf)), l->n->heapaddr->ntype));
   241  	}
   242  
   243  	clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
   244  	clos->esc = func->esc;
   245  	clos->right->implicit = 1;
   246  	clos->list = concat(list1(nod(OCFUNC, func->closure->nname, N)), func->enter);
   247  
   248  	// Force type conversion from *struct to the func type.
   249  	clos = nod(OCONVNOP, clos, N);
   250  	clos->type = func->type;
   251  
   252  	typecheck(&clos, Erv);
   253  	// typecheck will insert a PTRLIT node under CONVNOP,
   254  	// tag it with escape analysis result.
   255  	clos->left->esc = func->esc;
   256  	// non-escaping temp to use, if any.
   257  	// orderexpr did not compute the type; fill it in now.
   258  	if(func->alloc != N) {
   259  		func->alloc->type = clos->left->left->type;
   260  		func->alloc->orig->type = func->alloc->type;
   261  		clos->left->right = func->alloc;
   262  		func->alloc = N;
   263  	}
   264  	walkexpr(&clos, init);
   265  
   266  	return clos;
   267  }
   268  
   269  static Node *makepartialcall(Node*, Type*, Node*);
   270  
   271  void
   272  typecheckpartialcall(Node *fn, Node *sym)
   273  {
   274  	switch(fn->op) {
   275  	case ODOTINTER:
   276  	case ODOTMETH:
   277  		break;
   278  	default:
   279  		fatal("invalid typecheckpartialcall");
   280  	}
   281  
   282  	// Create top-level function.
   283  	fn->nname = makepartialcall(fn, fn->type, sym);
   284  	fn->right = sym;
   285  	fn->op = OCALLPART;
   286  	fn->type = fn->nname->type;
   287  }
   288  
   289  static Node*
   290  makepartialcall(Node *fn, Type *t0, Node *meth)
   291  {
   292  	Node *ptr, *n, *fld, *call, *xtype, *xfunc, *cv, *savecurfn;
   293  	Type *rcvrtype, *basetype, *t;
   294  	NodeList *body, *l, *callargs, *retargs;
   295  	char *p;
   296  	Sym *sym;
   297  	Pkg *spkg;
   298  	static Pkg* gopkg;
   299  	int i, ddd;
   300  
   301  	// TODO: names are not right
   302  	rcvrtype = fn->left->type;
   303  	if(exportname(meth->sym->name))
   304  		p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name);
   305  	else
   306  		p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym);
   307  	basetype = rcvrtype;
   308  	if(isptr[rcvrtype->etype])
   309  		basetype = basetype->type;
   310  	if(basetype->etype != TINTER && basetype->sym == S)
   311  		fatal("missing base type for %T", rcvrtype);
   312  
   313  	spkg = nil;
   314  	if(basetype->sym != S)
   315  		spkg = basetype->sym->pkg;
   316  	if(spkg == nil) {
   317  		if(gopkg == nil)
   318  			gopkg = mkpkg(strlit("go"));
   319  		spkg = gopkg;
   320  	}
   321  	sym = pkglookup(p, spkg);
   322  	free(p);
   323  	if(sym->flags & SymUniq)
   324  		return sym->def;
   325  	sym->flags |= SymUniq;
   326  	
   327  	savecurfn = curfn;
   328  	curfn = N;
   329  
   330  	xtype = nod(OTFUNC, N, N);
   331  	i = 0;
   332  	l = nil;
   333  	callargs = nil;
   334  	ddd = 0;
   335  	xfunc = nod(ODCLFUNC, N, N);
   336  	curfn = xfunc;
   337  	for(t = getinargx(t0)->type; t; t = t->down) {
   338  		snprint(namebuf, sizeof namebuf, "a%d", i++);
   339  		n = newname(lookup(namebuf));
   340  		n->class = PPARAM;
   341  		xfunc->dcl = list(xfunc->dcl, n);
   342  		callargs = list(callargs, n);
   343  		fld = nod(ODCLFIELD, n, typenod(t->type));
   344  		if(t->isddd) {
   345  			fld->isddd = 1;
   346  			ddd = 1;
   347  		}
   348  		l = list(l, fld);
   349  	}
   350  	xtype->list = l;
   351  	i = 0;
   352  	l = nil;
   353  	retargs = nil;
   354  	for(t = getoutargx(t0)->type; t; t = t->down) {
   355  		snprint(namebuf, sizeof namebuf, "r%d", i++);
   356  		n = newname(lookup(namebuf));
   357  		n->class = PPARAMOUT;
   358  		xfunc->dcl = list(xfunc->dcl, n);
   359  		retargs = list(retargs, n);
   360  		l = list(l, nod(ODCLFIELD, n, typenod(t->type)));
   361  	}
   362  	xtype->rlist = l;
   363  
   364  	xfunc->dupok = 1;
   365  	xfunc->nname = newname(sym);
   366  	xfunc->nname->sym->flags |= SymExported; // disable export
   367  	xfunc->nname->ntype = xtype;
   368  	xfunc->nname->defn = xfunc;
   369  	declare(xfunc->nname, PFUNC);
   370  
   371  	// Declare and initialize variable holding receiver.
   372  	body = nil;
   373  	xfunc->needctxt = 1;
   374  	cv = nod(OCLOSUREVAR, N, N);
   375  	cv->xoffset = widthptr;
   376  	cv->type = rcvrtype;
   377  	if(cv->type->align > widthptr)
   378  		cv->xoffset = cv->type->align;
   379  	ptr = nod(ONAME, N, N);
   380  	ptr->sym = lookup("rcvr");
   381  	ptr->class = PAUTO;
   382  	ptr->addable = 1;
   383  	ptr->ullman = 1;
   384  	ptr->used = 1;
   385  	ptr->curfn = xfunc;
   386  	xfunc->dcl = list(xfunc->dcl, ptr);
   387  	if(isptr[rcvrtype->etype] || isinter(rcvrtype)) {
   388  		ptr->ntype = typenod(rcvrtype);
   389  		body = list(body, nod(OAS, ptr, cv));
   390  	} else {
   391  		ptr->ntype = typenod(ptrto(rcvrtype));
   392  		body = list(body, nod(OAS, ptr, nod(OADDR, cv, N)));
   393  	}
   394  
   395  	call = nod(OCALL, nod(OXDOT, ptr, meth), N);
   396  	call->list = callargs;
   397  	call->isddd = ddd;
   398  	if(t0->outtuple == 0) {
   399  		body = list(body, call);
   400  	} else {
   401  		n = nod(OAS2, N, N);
   402  		n->list = retargs;
   403  		n->rlist = list1(call);
   404  		body = list(body, n);
   405  		n = nod(ORETURN, N, N);
   406  		body = list(body, n);
   407  	}
   408  
   409  	xfunc->nbody = body;
   410  
   411  	typecheck(&xfunc, Etop);
   412  	sym->def = xfunc;
   413  	xtop = list(xtop, xfunc);
   414  	curfn = savecurfn;
   415  
   416  	return xfunc;
   417  }
   418  
   419  Node*
   420  walkpartialcall(Node *n, NodeList **init)
   421  {
   422  	Node *clos, *typ;
   423  
   424  	// Create closure in the form of a composite literal.
   425  	// For x.M with receiver (x) type T, the generated code looks like:
   426  	//
   427  	//	clos = &struct{F uintptr; R T}{M.T·f, x}
   428  	//
   429  	// Like walkclosure above.
   430  
   431  	if(isinter(n->left->type)) {
   432  		// Trigger panic for method on nil interface now.
   433  		// Otherwise it happens in the wrapper and is confusing.
   434  		n->left = cheapexpr(n->left, init);
   435  		checknil(n->left, init);
   436  	}
   437  
   438  	typ = nod(OTSTRUCT, N, N);
   439  	typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
   440  	typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type)));
   441  
   442  	clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
   443  	clos->esc = n->esc;
   444  	clos->right->implicit = 1;
   445  	clos->list = list1(nod(OCFUNC, n->nname->nname, N));
   446  	clos->list = list(clos->list, n->left);
   447  
   448  	// Force type conversion from *struct to the func type.
   449  	clos = nod(OCONVNOP, clos, N);
   450  	clos->type = n->type;
   451  
   452  	typecheck(&clos, Erv);
   453  	// typecheck will insert a PTRLIT node under CONVNOP,
   454  	// tag it with escape analysis result.
   455  	clos->left->esc = n->esc;
   456  	// non-escaping temp to use, if any.
   457  	// orderexpr did not compute the type; fill it in now.
   458  	if(n->alloc != N) {
   459  		n->alloc->type = clos->left->left->type;
   460  		n->alloc->orig->type = n->alloc->type;
   461  		clos->left->right = n->alloc;
   462  		n->alloc = N;
   463  	}
   464  	walkexpr(&clos, init);
   465  
   466  	return clos;
   467  }