LEFT | RIGHT |
(no file at all) | |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #undef EXTERN | 5 #undef EXTERN |
6 #define EXTERN | 6 #define EXTERN |
7 #include <u.h> | 7 #include <u.h> |
8 #include <libc.h> | 8 #include <libc.h> |
9 #include "gg.h" | 9 #include "gg.h" |
10 #include "opt.h" | 10 #include "opt.h" |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 * call f | 168 * call f |
169 * proc=-1 normal call but no return | 169 * proc=-1 normal call but no return |
170 * proc=0 normal call | 170 * proc=0 normal call |
171 * proc=1 goroutine run in new proc | 171 * proc=1 goroutine run in new proc |
172 * proc=2 defer call save away stack | 172 * proc=2 defer call save away stack |
173 * proc=3 normal call to C pointer (not Go func value) | 173 * proc=3 normal call to C pointer (not Go func value) |
174 */ | 174 */ |
175 void | 175 void |
176 ginscall(Node *f, int proc) | 176 ginscall(Node *f, int proc) |
177 { | 177 { |
| 178 ginscall1(f, nil, proc); |
| 179 } |
| 180 |
| 181 void |
| 182 ginscall1(Node *f, Node *defertmp, int proc) |
| 183 { |
178 int32 arg; | 184 int32 arg; |
179 Prog *p; | 185 Prog *p; |
180 Node reg, con; | 186 Node reg, con; |
181 Node r1; | 187 Node r1; |
| 188 Type *t; |
182 | 189 |
183 if(f->type != T) | 190 if(f->type != T) |
184 setmaxarg(f->type); | 191 setmaxarg(f->type); |
| 192 |
| 193 if(defertmp != nil) { |
| 194 t = typ(TARRAY); |
| 195 t->type = types[TUINTPTR]; |
| 196 t->bound = 5 + (f->type->argwid+widthptr-1)/widthptr; |
| 197 if(widthptr == 4) |
| 198 t->bound++; |
| 199 defertmp->type = t; |
| 200 } |
185 | 201 |
186 arg = -1; | 202 arg = -1; |
187 // Most functions have a fixed-size argument block, so traceback uses th
at during unwind. | 203 // Most functions have a fixed-size argument block, so traceback uses th
at during unwind. |
188 // Not all, though: there are some variadic functions in package runtime
, | 204 // Not all, though: there are some variadic functions in package runtime
, |
189 // and for those we emit call-specific metadata recorded by caller. | 205 // and for those we emit call-specific metadata recorded by caller. |
190 // Reflect generates functions with variable argsize (see reflect.method
ValueCall/makeFuncStub), | 206 // Reflect generates functions with variable argsize (see reflect.method
ValueCall/makeFuncStub), |
191 // so we do this for all indirect calls as well. | 207 // so we do this for all indirect calls as well. |
192 if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtim
epkg) || proc == 1 || proc == 2)) { | 208 if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtim
epkg) || proc == 1 || proc == 2)) { |
193 arg = f->type->argwid; | 209 arg = f->type->argwid; |
194 if(proc == 1 || proc == 2) | 210 if(proc == 1 || proc == 2) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 reg.op = OREGISTER; | 249 reg.op = OREGISTER; |
234 gins(ACALL, ®, &r1); | 250 gins(ACALL, ®, &r1); |
235 break; | 251 break; |
236 ········ | 252 ········ |
237 case 3: // normal call of c function pointer | 253 case 3: // normal call of c function pointer |
238 gins(ACALL, N, f); | 254 gins(ACALL, N, f); |
239 break; | 255 break; |
240 | 256 |
241 case 1: // call in new proc (go) | 257 case 1: // call in new proc (go) |
242 case 2: // deferred call (defer) | 258 case 2: // deferred call (defer) |
| 259 defertmp = nil; |
243 nodconst(&con, types[TINT64], argsize(f->type)); | 260 nodconst(&con, types[TINT64], argsize(f->type)); |
244 if(widthptr == 4) { | 261 if(widthptr == 4) { |
245 nodreg(&r1, types[TINT32], D_CX); | 262 nodreg(&r1, types[TINT32], D_CX); |
246 gmove(f, &r1); | 263 gmove(f, &r1); |
247 nodreg(®, types[TINT64], D_CX); | 264 nodreg(®, types[TINT64], D_CX); |
248 nodconst(&r1, types[TINT64], 32); | 265 nodconst(&r1, types[TINT64], 32); |
249 gins(ASHLQ, &r1, ®); | 266 gins(ASHLQ, &r1, ®); |
250 gins(AORQ, &con, ®); | 267 gins(AORQ, &con, ®); |
251 gins(APUSHQ, ®, N); | 268 gins(APUSHQ, ®, N); |
252 } else { | 269 } else { |
253 nodreg(®, types[TINT64], D_CX); | 270 nodreg(®, types[TINT64], D_CX); |
254 gmove(f, ®); | 271 gmove(f, ®); |
255 gins(APUSHQ, ®, N); | 272 gins(APUSHQ, ®, N); |
256 gins(APUSHQ, &con, N); | 273 gins(APUSHQ, &con, N); |
| 274 if(defertmp != nil) { |
| 275 gins(ALEAQ, defertmp, ®); |
| 276 gins(APUSHQ, ®, N); |
| 277 } |
257 } | 278 } |
258 if(proc == 1) | 279 if(proc == 1) |
259 ginscall(newproc, 0); | 280 ginscall(newproc, 0); |
260 else { | 281 else { |
261 if(!hasdefer) | 282 if(!hasdefer) |
262 fatal("hasdefer=0 but has defer"); | 283 fatal("hasdefer=0 but has defer"); |
263 » » » ginscall(deferproc, 0); | 284 » » » if(defertmp != nil) |
| 285 » » » » ginscall(deferproc1, 0); |
| 286 » » » else |
| 287 » » » » ginscall(deferproc, 0); |
264 } | 288 } |
265 nodreg(®, types[TINT64], D_CX); | 289 nodreg(®, types[TINT64], D_CX); |
266 gins(APOPQ, N, ®); | 290 gins(APOPQ, N, ®); |
267 if(widthptr == 8) | 291 if(widthptr == 8) |
| 292 gins(APOPQ, N, ®); |
| 293 if(defertmp != nil) |
268 gins(APOPQ, N, ®); | 294 gins(APOPQ, N, ®); |
269 if(proc == 2) { | 295 if(proc == 2) { |
270 nodreg(®, types[TINT64], D_AX); | 296 nodreg(®, types[TINT64], D_AX); |
271 gins(ATESTQ, ®, ®); | 297 gins(ATESTQ, ®, ®); |
272 p = gbranch(AJEQ, T, +1); | 298 p = gbranch(AJEQ, T, +1); |
273 cgen_ret(N); | 299 cgen_ret(N); |
274 patch(p, pc); | 300 patch(p, pc); |
275 } | 301 } |
276 break; | 302 break; |
277 } | 303 } |
278 | 304 |
279 if(arg != -1) | 305 if(arg != -1) |
280 gargsize(-1); | 306 gargsize(-1); |
281 } | 307 } |
282 | 308 |
283 /* | 309 /* |
284 * n is call to interface method. | 310 * n is call to interface method. |
285 * generate res = n. | 311 * generate res = n. |
286 */ | 312 */ |
287 void | 313 void |
288 cgen_callinter(Node *n, Node *res, int proc) | 314 cgen_callinter(Node *n, Node *res, Node *tmp, int proc) |
289 { | 315 { |
290 Node *i, *f; | 316 Node *i, *f; |
291 Node tmpi, nodi, nodo, nodr, nodsp; | 317 Node tmpi, nodi, nodo, nodr, nodsp; |
292 | 318 |
293 i = n->left; | 319 i = n->left; |
294 if(i->op != ODOTINTER) | 320 if(i->op != ODOTINTER) |
295 fatal("cgen_callinter: not ODOTINTER %O", i->op); | 321 fatal("cgen_callinter: not ODOTINTER %O", i->op); |
296 | 322 |
297 f = i->right; // field | 323 f = i->right; // field |
298 if(f->op != ONAME) | 324 if(f->op != ONAME) |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 if(proc == 0) { | 358 if(proc == 0) { |
333 // plain call: use direct c function pointer - more efficient | 359 // plain call: use direct c function pointer - more efficient |
334 cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f] | 360 cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f] |
335 proc = 3; | 361 proc = 3; |
336 } else { | 362 } else { |
337 // go/defer. generate go func value. | 363 // go/defer. generate go func value. |
338 gins(ALEAQ, &nodo, &nodr); // REG = &(32+offset(REG)) -- i.
tab->fun[f] | 364 gins(ALEAQ, &nodo, &nodr); // REG = &(32+offset(REG)) -- i.
tab->fun[f] |
339 } | 365 } |
340 | 366 |
341 nodr.type = n->left->type; | 367 nodr.type = n->left->type; |
342 » ginscall(&nodr, proc); | 368 » ginscall1(&nodr, tmp, proc); |
343 | 369 |
344 regfree(&nodr); | 370 regfree(&nodr); |
345 regfree(&nodo); | 371 regfree(&nodo); |
346 } | 372 } |
347 | 373 |
348 /* | 374 /* |
349 * generate function call; | 375 * generate function call; |
350 * proc=0 normal call | 376 * proc=0 normal call |
351 * proc=1 goroutine run in new proc | 377 * proc=1 goroutine run in new proc |
352 * proc=2 defer call save away stack | 378 * proc=2 defer call save away stack |
353 */ | 379 */ |
354 void | 380 void |
355 cgen_call(Node *n, int proc) | 381 cgen_call(Node *n, Node *tmp, int proc) |
356 { | 382 { |
357 Type *t; | 383 Type *t; |
358 Node nod, afun; | 384 Node nod, afun; |
359 | 385 |
360 if(n == N) | 386 if(n == N) |
361 return; | 387 return; |
362 | 388 |
363 if(n->left->ullman >= UINF) { | 389 if(n->left->ullman >= UINF) { |
364 // if name involves a fn call | 390 // if name involves a fn call |
365 // precompute the address of the fn | 391 // precompute the address of the fn |
366 tempname(&afun, types[tptr]); | 392 tempname(&afun, types[tptr]); |
367 cgen(n->left, &afun); | 393 cgen(n->left, &afun); |
368 } | 394 } |
369 | 395 |
370 genlist(n->list); // assign the args | 396 genlist(n->list); // assign the args |
371 t = n->left->type; | 397 t = n->left->type; |
372 | 398 |
373 // call tempname pointer | 399 // call tempname pointer |
374 if(n->left->ullman >= UINF) { | 400 if(n->left->ullman >= UINF) { |
375 regalloc(&nod, types[tptr], N); | 401 regalloc(&nod, types[tptr], N); |
376 cgen_as(&nod, &afun); | 402 cgen_as(&nod, &afun); |
377 nod.type = t; | 403 nod.type = t; |
378 » » ginscall(&nod, proc); | 404 » » ginscall1(&nod, tmp, proc); |
379 regfree(&nod); | 405 regfree(&nod); |
380 return; | 406 return; |
381 } | 407 } |
382 | 408 |
383 // call pointer | 409 // call pointer |
384 if(n->left->op != ONAME || n->left->class != PFUNC) { | 410 if(n->left->op != ONAME || n->left->class != PFUNC) { |
385 regalloc(&nod, types[tptr], N); | 411 regalloc(&nod, types[tptr], N); |
386 cgen_as(&nod, n->left); | 412 cgen_as(&nod, n->left); |
387 nod.type = t; | 413 nod.type = t; |
388 » » ginscall(&nod, proc); | 414 » » ginscall1(&nod, tmp, proc); |
389 regfree(&nod); | 415 regfree(&nod); |
390 return; | 416 return; |
391 } | 417 } |
392 | 418 |
393 // call direct | 419 // call direct |
394 n->left->method = 1; | 420 n->left->method = 1; |
395 » ginscall(n->left, proc); | 421 » ginscall1(n->left, tmp, proc); |
396 } | 422 } |
397 | 423 |
398 /* | 424 /* |
399 * call to n has already been generated. | 425 * call to n has already been generated. |
400 * generate: | 426 * generate: |
401 * res = return value from call. | 427 * res = return value from call. |
402 */ | 428 */ |
403 void | 429 void |
404 cgen_callret(Node *n, Node *res) | 430 cgen_callret(Node *n, Node *res) |
405 { | 431 { |
(...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1210 // which will be shorter to encode than plain 0. | 1236 // which will be shorter to encode than plain 0. |
1211 p2->as = AMOVL; | 1237 p2->as = AMOVL; |
1212 p2->from.type = D_AX; | 1238 p2->from.type = D_AX; |
1213 if(regtyp(&p->from)) | 1239 if(regtyp(&p->from)) |
1214 p2->to.type = p->from.type + D_INDIR; | 1240 p2->to.type = p->from.type + D_INDIR; |
1215 else | 1241 else |
1216 p2->to.type = D_INDIR+D_NONE; | 1242 p2->to.type = D_INDIR+D_NONE; |
1217 p2->to.offset = 0; | 1243 p2->to.offset = 0; |
1218 } | 1244 } |
1219 } | 1245 } |
LEFT | RIGHT |