blob: 9301d87d2e3fd075ce4fee991787cfe2ab42a8ba [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// Copyright 2012 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
5package gc
6
7import (
8 "fmt"
9 "strings"
10)
11
12// The racewalk pass modifies the code tree for the function as follows:
13//
14// 1. It inserts a call to racefuncenter at the beginning of each function.
15// 2. It inserts a call to racefuncexit at the end of each function.
16// 3. It inserts a call to raceread before each memory read.
17// 4. It inserts a call to racewrite before each memory write.
18//
19// The rewriting is not yet complete. Certain nodes are not rewritten
20// but should be.
21
22// TODO(dvyukov): do not instrument initialization as writes:
23// a := make([]int, 10)
24
25// Do not instrument the following packages at all,
26// at best instrumentation would cause infinite recursion.
27var omit_pkgs = []string{"runtime", "runtime/race"}
28
29// Only insert racefuncenter/racefuncexit into the following packages.
30// Memory accesses in the packages are either uninteresting or will cause false positives.
31var noinst_pkgs = []string{"sync", "sync/atomic"}
32
Russ Coxdc7b54b2015-02-17 22:13:49 -050033func ispkgin(pkgs []string) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -050034 if myimportpath != "" {
Russ Cox382b44e2015-02-23 16:07:24 -050035 for i := 0; i < len(pkgs); i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -050036 if myimportpath == pkgs[i] {
Russ Coxdc7b54b2015-02-17 22:13:49 -050037 return true
Russ Cox8c195bd2015-02-13 14:40:36 -050038 }
39 }
40 }
41
Russ Coxdc7b54b2015-02-17 22:13:49 -050042 return false
Russ Cox8c195bd2015-02-13 14:40:36 -050043}
44
Russ Cox75d77952015-07-22 15:31:54 -040045// TODO(rsc): Remove. Put //go:norace on forkAndExecInChild instead.
Russ Coxdc7b54b2015-02-17 22:13:49 -050046func isforkfunc(fn *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -050047 // Special case for syscall.forkAndExecInChild.
48 // In the child, this function must not acquire any locks, because
49 // they might have been locked at the time of the fork. This means
50 // no rescheduling, no malloc calls, and no new stack segments.
51 // Race instrumentation does all of the above.
Russ Coxbd4fff62015-05-27 10:42:55 -040052 return myimportpath != "" && myimportpath == "syscall" && fn.Func.Nname.Sym.Name == "forkAndExecInChild"
Russ Cox8c195bd2015-02-13 14:40:36 -050053}
54
55func racewalk(fn *Node) {
Russ Cox75d77952015-07-22 15:31:54 -040056 if ispkgin(omit_pkgs) || isforkfunc(fn) || fn.Func.Norace {
Russ Cox8c195bd2015-02-13 14:40:36 -050057 return
58 }
59
Russ Coxdc7b54b2015-02-17 22:13:49 -050060 if !ispkgin(noinst_pkgs) {
Russ Cox8c195bd2015-02-13 14:40:36 -050061 racewalklist(fn.Nbody, nil)
62
63 // nothing interesting for race detector in fn->enter
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070064 racewalklist(fn.Func.Exit, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -050065 }
66
67 // nodpc is the PC of the caller as extracted by
68 // getcallerpc. We use -widthptr(FP) for x86.
69 // BUG: this will not work on arm.
Russ Cox382b44e2015-02-23 16:07:24 -050070 nodpc := Nod(OXXX, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -050071
72 *nodpc = *nodfp
73 nodpc.Type = Types[TUINTPTR]
74 nodpc.Xoffset = int64(-Widthptr)
Russ Cox382b44e2015-02-23 16:07:24 -050075 nd := mkcall("racefuncenter", nil, nil, nodpc)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070076 fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
Russ Cox8c195bd2015-02-13 14:40:36 -050077 nd = mkcall("racefuncexit", nil, nil)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070078 fn.Func.Exit = list(fn.Func.Exit, nd)
Russ Cox8c195bd2015-02-13 14:40:36 -050079
80 if Debug['W'] != 0 {
Russ Coxbd4fff62015-05-27 10:42:55 -040081 s := fmt.Sprintf("after racewalk %v", fn.Func.Nname.Sym)
Russ Cox8c195bd2015-02-13 14:40:36 -050082 dumplist(s, fn.Nbody)
Russ Coxbd4fff62015-05-27 10:42:55 -040083 s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070084 dumplist(s, fn.Func.Enter)
Russ Coxbd4fff62015-05-27 10:42:55 -040085 s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
Josh Bleecher Snyder3ed9e4c2015-03-25 19:33:01 -070086 dumplist(s, fn.Func.Exit)
Russ Cox8c195bd2015-02-13 14:40:36 -050087 }
88}
89
90func racewalklist(l *NodeList, init **NodeList) {
91 var instr *NodeList
92
93 for ; l != nil; l = l.Next {
94 instr = nil
95 racewalknode(&l.N, &instr, 0, 0)
96 if init == nil {
97 l.N.Ninit = concat(l.N.Ninit, instr)
98 } else {
99 *init = concat(*init, instr)
100 }
101 }
102}
103
104// walkexpr and walkstmt combined
105// walks the tree and adds calls to the
106// instrumentation code to top-level (statement) nodes' init
107func racewalknode(np **Node, init **NodeList, wr int, skip int) {
Russ Cox382b44e2015-02-23 16:07:24 -0500108 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500109
110 if n == nil {
111 return
112 }
113
114 if Debug['w'] > 1 {
115 Dump("racewalk-before", n)
116 }
117 setlineno(n)
118 if init == nil {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200119 Fatalf("racewalk: bad init list")
Russ Cox8c195bd2015-02-13 14:40:36 -0500120 }
121 if init == &n.Ninit {
122 // If init == &n->ninit and n->ninit is non-nil,
123 // racewalknode might append it to itself.
124 // nil it out and handle it separately before putting it back.
Russ Cox382b44e2015-02-23 16:07:24 -0500125 l := n.Ninit
Russ Cox8c195bd2015-02-13 14:40:36 -0500126
127 n.Ninit = nil
128 racewalklist(l, nil)
129 racewalknode(&n, &l, wr, skip) // recurse with nil n->ninit
130 appendinit(&n, l)
131 *np = n
132 return
133 }
134
135 racewalklist(n.Ninit, nil)
136
137 switch n.Op {
138 default:
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200139 Fatalf("racewalk: unknown node type %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500140
Russ Cox0ad4f8b2015-04-17 00:25:10 -0400141 case OAS, OASWB, OAS2FUNC:
Russ Cox8c195bd2015-02-13 14:40:36 -0500142 racewalknode(&n.Left, init, 1, 0)
143 racewalknode(&n.Right, init, 0, 0)
144 goto ret
145
146 // can't matter
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700147 case OCFUNC, OVARKILL:
Russ Cox8c195bd2015-02-13 14:40:36 -0500148 goto ret
149
150 case OBLOCK:
Russ Cox3b6e86f2015-06-29 15:17:14 -0400151 var out *NodeList
152 for l := n.List; l != nil; l = l.Next {
153 switch l.N.Op {
154 case OCALLFUNC, OCALLMETH, OCALLINTER:
155 racewalknode(&l.N, &out, 0, 0)
156 out = list(out, l.N)
157 // Scan past OAS nodes copying results off stack.
158 // Those must not be instrumented, because the
159 // instrumentation calls will smash the results.
160 // The assignments are to temporaries, so they cannot
161 // be involved in races and need not be instrumented.
162 for l.Next != nil && l.Next.N.Op == OAS && iscallret(l.Next.N.Right) {
163 l = l.Next
164 out = list(out, l.N)
165 }
166 default:
167 racewalknode(&l.N, &out, 0, 0)
168 out = list(out, l.N)
169 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500170 }
Russ Cox3b6e86f2015-06-29 15:17:14 -0400171 n.List = out
Russ Cox8c195bd2015-02-13 14:40:36 -0500172 goto ret
173
174 case ODEFER:
175 racewalknode(&n.Left, init, 0, 0)
176 goto ret
177
178 case OPROC:
179 racewalknode(&n.Left, init, 0, 0)
180 goto ret
181
182 case OCALLINTER:
183 racewalknode(&n.Left, init, 0, 0)
184 goto ret
185
186 // Instrument dst argument of runtime.writebarrier* calls
187 // as we do not instrument runtime code.
188 // typedslicecopy is instrumented in runtime.
189 case OCALLFUNC:
Russ Cox8c195bd2015-02-13 14:40:36 -0500190 racewalknode(&n.Left, init, 0, 0)
191 goto ret
192
193 case ONOT,
194 OMINUS,
195 OPLUS,
196 OREAL,
197 OIMAG,
Shenghou Ma8b2503d2015-04-03 15:58:18 -0400198 OCOM,
199 OSQRT:
Russ Cox8c195bd2015-02-13 14:40:36 -0500200 racewalknode(&n.Left, init, wr, 0)
201 goto ret
202
203 case ODOTINTER:
204 racewalknode(&n.Left, init, 0, 0)
205 goto ret
206
207 case ODOT:
208 racewalknode(&n.Left, init, 0, 1)
209 callinstr(&n, init, wr, skip)
210 goto ret
211
212 case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
213 racewalknode(&n.Left, init, 0, 0)
214
215 callinstr(&n, init, wr, skip)
216 goto ret
217
218 case OIND: // *p
219 racewalknode(&n.Left, init, 0, 0)
220
221 callinstr(&n, init, wr, skip)
222 goto ret
223
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700224 case OSPTR, OLEN, OCAP:
Russ Cox8c195bd2015-02-13 14:40:36 -0500225 racewalknode(&n.Left, init, 0, 0)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500226 if Istype(n.Left.Type, TMAP) {
Russ Cox382b44e2015-02-23 16:07:24 -0500227 n1 := Nod(OCONVNOP, n.Left, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500228 n1.Type = Ptrto(Types[TUINT8])
229 n1 = Nod(OIND, n1, nil)
230 typecheck(&n1, Erv)
231 callinstr(&n1, init, 0, skip)
232 }
233
234 goto ret
235
236 case OLSH,
237 ORSH,
238 OLROT,
239 OAND,
240 OANDNOT,
241 OOR,
242 OXOR,
243 OSUB,
244 OMUL,
245 OHMUL,
246 OEQ,
247 ONE,
248 OLT,
249 OLE,
250 OGE,
251 OGT,
252 OADD,
253 OCOMPLEX:
254 racewalknode(&n.Left, init, wr, 0)
255 racewalknode(&n.Right, init, wr, 0)
256 goto ret
257
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700258 case OANDAND, OOROR:
Russ Cox8c195bd2015-02-13 14:40:36 -0500259 racewalknode(&n.Left, init, wr, 0)
260
261 // walk has ensured the node has moved to a location where
262 // side effects are safe.
263 // n->right may not be executed,
264 // so instrumentation goes to n->right->ninit, not init.
265 racewalknode(&n.Right, &n.Right.Ninit, wr, 0)
266
267 goto ret
268
269 case ONAME:
270 callinstr(&n, init, wr, skip)
271 goto ret
272
273 case OCONV:
274 racewalknode(&n.Left, init, wr, 0)
275 goto ret
276
277 case OCONVNOP:
278 racewalknode(&n.Left, init, wr, 0)
279 goto ret
280
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700281 case ODIV, OMOD:
Russ Cox8c195bd2015-02-13 14:40:36 -0500282 racewalknode(&n.Left, init, wr, 0)
283 racewalknode(&n.Right, init, wr, 0)
284 goto ret
285
286 case OINDEX:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500287 if !Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500288 racewalknode(&n.Left, init, 0, 0)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500289 } else if !islvalue(n.Left) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500290 // index of unaddressable array, like Map[k][i].
291 racewalknode(&n.Left, init, wr, 0)
292
293 racewalknode(&n.Right, init, 0, 0)
294 goto ret
295 }
296
297 racewalknode(&n.Right, init, 0, 0)
298 if n.Left.Type.Etype != TSTRING {
299 callinstr(&n, init, wr, skip)
300 }
301 goto ret
302
Dmitry Vyukovcd0a8ed2015-06-24 19:25:51 +0200303 case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
Russ Coxd4472792015-05-06 12:35:53 -0400304 racewalknode(&n.Left, init, 0, 0)
Dmitry Vyukovcd0a8ed2015-06-24 19:25:51 +0200305 racewalknode(&n.Right, init, 0, 0)
306 goto ret
307
308 case OKEY:
309 racewalknode(&n.Left, init, 0, 0)
310 racewalknode(&n.Right, init, 0, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500311 goto ret
312
313 case OADDR:
314 racewalknode(&n.Left, init, 0, 1)
315 goto ret
316
317 // n->left is Type* which is not interesting.
318 case OEFACE:
319 racewalknode(&n.Right, init, 0, 0)
320
321 goto ret
322
323 case OITAB:
324 racewalknode(&n.Left, init, 0, 0)
325 goto ret
326
327 // should not appear in AST by now
328 case OSEND,
329 ORECV,
330 OCLOSE,
331 ONEW,
332 OXCASE,
333 OXFALL,
334 OCASE,
335 OPANIC,
336 ORECOVER,
337 OCONVIFACE,
338 OCMPIFACE,
339 OMAKECHAN,
340 OMAKEMAP,
341 OMAKESLICE,
342 OCALL,
343 OCOPY,
344 OAPPEND,
345 ORUNESTR,
346 OARRAYBYTESTR,
347 OARRAYRUNESTR,
348 OSTRARRAYBYTE,
349 OSTRARRAYRUNE,
350 OINDEXMAP,
351 // lowered to call
352 OCMPSTR,
353 OADDSTR,
354 ODOTTYPE,
355 ODOTTYPE2,
356 OAS2DOTTYPE,
357 OCALLPART,
358 // lowered to PTRLIT
359 OCLOSURE, // lowered to PTRLIT
360 ORANGE, // lowered to ordinary for loop
361 OARRAYLIT, // lowered to assignments
362 OMAPLIT,
363 OSTRUCTLIT,
364 OAS2,
365 OAS2RECV,
366 OAS2MAPR,
367 OASOP:
368 Yyerror("racewalk: %v must be lowered by now", Oconv(int(n.Op), 0))
369
370 goto ret
371
372 // impossible nodes: only appear in backend.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700373 case ORROTC, OEXTEND:
Russ Cox8c195bd2015-02-13 14:40:36 -0500374 Yyerror("racewalk: %v cannot exist now", Oconv(int(n.Op), 0))
Dmitry Vyukov08c43482015-04-09 10:08:29 +0300375 goto ret
Russ Cox8c195bd2015-02-13 14:40:36 -0500376
Dmitry Vyukov08c43482015-04-09 10:08:29 +0300377 case OGETG:
378 Yyerror("racewalk: OGETG can happen only in runtime which we don't instrument")
Russ Cox8c195bd2015-02-13 14:40:36 -0500379 goto ret
380
Russ Coxffef1802015-05-22 01:16:52 -0400381 case OFOR:
Russ Cox66be1482015-05-26 21:30:20 -0400382 if n.Left != nil {
383 racewalknode(&n.Left, &n.Left.Ninit, 0, 0)
384 }
Russ Coxffef1802015-05-22 01:16:52 -0400385 if n.Right != nil {
386 racewalknode(&n.Right, &n.Right.Ninit, 0, 0)
387 }
388 goto ret
389
Russ Cox66be1482015-05-26 21:30:20 -0400390 case OIF, OSWITCH:
391 if n.Left != nil {
392 racewalknode(&n.Left, &n.Left.Ninit, 0, 0)
393 }
394 goto ret
395
396 // just do generic traversal
397 case OCALLMETH,
Russ Cox8c195bd2015-02-13 14:40:36 -0500398 ORETURN,
399 ORETJMP,
Russ Cox8c195bd2015-02-13 14:40:36 -0500400 OSELECT,
401 OEMPTY,
402 OBREAK,
403 OCONTINUE,
404 OFALL,
405 OGOTO,
406 OLABEL:
407 goto ret
408
409 // does not require instrumentation
410 case OPRINT, // don't bother instrumenting it
411 OPRINTN, // don't bother instrumenting it
412 OCHECKNIL, // always followed by a read.
413 OPARAM, // it appears only in fn->exit to copy heap params back
414 OCLOSUREVAR, // immutable pointer to captured variable
415 ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT)
416 OINDREG, // at this stage, only n(SP) nodes from nodarg
417 ODCL, // declarations (without value) cannot be races
418 ODCLCONST,
419 ODCLTYPE,
420 OTYPE,
421 ONONAME,
422 OLITERAL,
Dmitry Vyukovcd0a8ed2015-06-24 19:25:51 +0200423 OTYPESW: // ignored by code generation, do not instrument.
Russ Cox8c195bd2015-02-13 14:40:36 -0500424 goto ret
425 }
426
427ret:
428 if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
429 racewalklist(n.List, init)
430 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500431 racewalklist(n.Nbody, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500432 racewalklist(n.Rlist, nil)
433 *np = n
434}
435
Russ Coxdc7b54b2015-02-17 22:13:49 -0500436func isartificial(n *Node) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500437 // compiler-emitted artificial things that we do not want to instrument,
438 // cant' possibly participate in a data race.
439 if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
440 if n.Sym.Name == "_" {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500441 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500442 }
443
444 // autotmp's are always local
445 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500446 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500447 }
448
449 // statictmp's are read-only
450 if strings.HasPrefix(n.Sym.Name, "statictmp_") {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500451 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500452 }
453
454 // go.itab is accessed only by the compiler and runtime (assume safe)
455 if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500456 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500457 }
458 }
459
Russ Coxdc7b54b2015-02-17 22:13:49 -0500460 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500461}
462
Russ Coxdc7b54b2015-02-17 22:13:49 -0500463func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500464 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500465
466 //print("callinstr for %+N [ %O ] etype=%E class=%d\n",
467 // n, n->op, n->type ? n->type->etype : -1, n->class);
468
469 if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500470 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500471 }
Russ Cox382b44e2015-02-23 16:07:24 -0500472 t := n.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500473 if isartificial(n) {
474 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500475 }
476
Russ Cox382b44e2015-02-23 16:07:24 -0500477 b := outervalue(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500478
479 // it skips e.g. stores to ... parameter array
Russ Coxdc7b54b2015-02-17 22:13:49 -0500480 if isartificial(b) {
481 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500482 }
Josh Bleecher Snyder102b8062015-03-27 12:00:07 -0700483 class := b.Class
Russ Cox8c195bd2015-02-13 14:40:36 -0500484
485 // BUG: we _may_ want to instrument PAUTO sometimes
486 // e.g. if we've got a local variable/method receiver
487 // that has got a pointer inside. Whether it points to
488 // the heap or not is impossible to know at compile time
489 if (class&PHEAP != 0) || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
Russ Cox382b44e2015-02-23 16:07:24 -0500490 hascalls := 0
Russ Cox8c195bd2015-02-13 14:40:36 -0500491 foreach(n, hascallspred, &hascalls)
492 if hascalls != 0 {
493 n = detachexpr(n, init)
494 *np = n
495 }
496
David Chase05d8f1d2015-05-22 22:01:01 -0400497 n = treecopy(n, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500498 makeaddable(n)
Russ Cox382b44e2015-02-23 16:07:24 -0500499 var f *Node
Russ Coxdc7b54b2015-02-17 22:13:49 -0500500 if t.Etype == TSTRUCT || Isfixedarray(t) {
Russ Cox382b44e2015-02-23 16:07:24 -0500501 name := "racereadrange"
Russ Cox8c195bd2015-02-13 14:40:36 -0500502 if wr != 0 {
503 name = "racewriterange"
504 }
505 f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width))
506 } else {
Russ Cox382b44e2015-02-23 16:07:24 -0500507 name := "raceread"
Russ Cox8c195bd2015-02-13 14:40:36 -0500508 if wr != 0 {
509 name = "racewrite"
510 }
511 f = mkcall(name, nil, init, uintptraddr(n))
512 }
513
514 *init = list(*init, f)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500515 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500516 }
517
Russ Coxdc7b54b2015-02-17 22:13:49 -0500518 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500519}
520
521// makeaddable returns a node whose memory location is the
522// same as n, but which is addressable in the Go language
523// sense.
524// This is different from functions like cheapexpr that may make
525// a copy of their argument.
526func makeaddable(n *Node) {
527 // The arguments to uintptraddr technically have an address but
528 // may not be addressable in the Go sense: for example, in the case
529 // of T(v).Field where T is a struct type and v is
530 // an addressable value.
531 switch n.Op {
532 case OINDEX:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500533 if Isfixedarray(n.Left.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500534 makeaddable(n.Left)
535 }
536
537 // Turn T(v).Field into v.Field
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700538 case ODOT, OXDOT:
Russ Cox8c195bd2015-02-13 14:40:36 -0500539 if n.Left.Op == OCONVNOP {
540 n.Left = n.Left.Left
541 }
542 makeaddable(n.Left)
543
544 // nothing to do
545 case ODOTPTR:
546 fallthrough
547 default:
548 break
549 }
550}
551
552func uintptraddr(n *Node) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -0500553 r := Nod(OADDR, n, nil)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500554 r.Bounded = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500555 r = conv(r, Types[TUNSAFEPTR])
556 r = conv(r, Types[TUINTPTR])
557 return r
558}
559
560func detachexpr(n *Node, init **NodeList) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -0500561 addr := Nod(OADDR, n, nil)
562 l := temp(Ptrto(n.Type))
563 as := Nod(OAS, l, addr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500564 typecheck(&as, Etop)
565 walkexpr(&as, init)
566 *init = list(*init, as)
Russ Cox382b44e2015-02-23 16:07:24 -0500567 ind := Nod(OIND, l, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500568 typecheck(&ind, Erv)
569 walkexpr(&ind, init)
570 return ind
571}
572
573func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
574 if n != nil {
575 f(n, c)
576 }
577}
578
579func foreachlist(l *NodeList, f func(*Node, interface{}), c interface{}) {
580 for ; l != nil; l = l.Next {
581 foreachnode(l.N, f, c)
582 }
583}
584
585func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
586 foreachlist(n.Ninit, f, c)
587 foreachnode(n.Left, f, c)
588 foreachnode(n.Right, f, c)
589 foreachlist(n.List, f, c)
Russ Cox8c195bd2015-02-13 14:40:36 -0500590 foreachlist(n.Nbody, f, c)
Russ Cox8c195bd2015-02-13 14:40:36 -0500591 foreachlist(n.Rlist, f, c)
592}
593
594func hascallspred(n *Node, c interface{}) {
595 switch n.Op {
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700596 case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
Russ Cox8c195bd2015-02-13 14:40:36 -0500597 (*c.(*int))++
598 }
599}
600
Keith Randallcd5b1442015-03-11 12:58:47 -0700601// appendinit is like addinit in subr.go
Russ Cox8c195bd2015-02-13 14:40:36 -0500602// but appends rather than prepends.
603func appendinit(np **Node, init *NodeList) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500604 if init == nil {
605 return
606 }
607
Russ Cox382b44e2015-02-23 16:07:24 -0500608 n := *np
Russ Cox8c195bd2015-02-13 14:40:36 -0500609 switch n.Op {
610 // There may be multiple refs to this node;
611 // introduce OCONVNOP to hold init list.
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -0700612 case ONAME, OLITERAL:
Russ Cox8c195bd2015-02-13 14:40:36 -0500613 n = Nod(OCONVNOP, n, nil)
614
615 n.Type = n.Left.Type
616 n.Typecheck = 1
617 *np = n
618 }
619
620 n.Ninit = concat(n.Ninit, init)
621 n.Ullman = UINF
622}