| // Copyright 2009 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 "runtime.h" |
| |
| #pragma textflag 7 |
| // func closure(siz int32, |
| // fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy, |
| // arg0, arg1, arg2 *ptr) (func(xxx) yyy) |
| void |
| runtime·closure(int32 siz, byte *fn, byte *arg0) |
| { |
| byte *p, *q, **ret; |
| int32 i, n; |
| int32 pcrel; |
| |
| if(siz < 0 || siz%4 != 0) |
| runtime·throw("bad closure size"); |
| |
| ret = (byte**)((byte*)&arg0 + siz); |
| |
| if(siz > 100) { |
| // TODO(rsc): implement stack growth preamble? |
| runtime·throw("closure too big"); |
| } |
| |
| // compute size of new fn. |
| // must match code laid out below. |
| n = 6+5+2+1; // SUBL MOVL MOVL CLD |
| if(siz <= 4*4) |
| n += 1*siz/4; // MOVSL MOVSL... |
| else |
| n += 6+2; // MOVL REP MOVSL |
| n += 5; // CALL |
| n += 6+1; // ADDL RET |
| |
| // store args aligned after code, so gc can find them. |
| n += siz; |
| if(n%4) |
| n += 4 - n%4; |
| |
| p = runtime·mal(n); |
| *ret = p; |
| q = p + n - siz; |
| |
| if(siz > 0) { |
| runtime·mcpy(q, (byte*)&arg0, siz); |
| |
| // SUBL $siz, SP |
| *p++ = 0x81; |
| *p++ = 0xec; |
| *(uint32*)p = siz; |
| p += 4; |
| |
| // MOVL $q, SI |
| *p++ = 0xbe; |
| *(byte**)p = q; |
| p += 4; |
| |
| // MOVL SP, DI |
| *p++ = 0x89; |
| *p++ = 0xe7; |
| |
| // CLD |
| *p++ = 0xfc; |
| |
| if(siz <= 4*4) { |
| for(i=0; i<siz; i+=4) { |
| // MOVSL |
| *p++ = 0xa5; |
| } |
| } else { |
| // MOVL $(siz/4), CX [32-bit immediate siz/4] |
| *p++ = 0xc7; |
| *p++ = 0xc1; |
| *(uint32*)p = siz/4; |
| p += 4; |
| |
| // REP; MOVSL |
| *p++ = 0xf3; |
| *p++ = 0xa5; |
| } |
| } |
| |
| // call fn |
| pcrel = fn - (p+5); |
| // direct call with pc-relative offset |
| // CALL fn |
| *p++ = 0xe8; |
| *(int32*)p = pcrel; |
| p += 4; |
| |
| // ADDL $siz, SP |
| *p++ = 0x81; |
| *p++ = 0xc4; |
| *(uint32*)p = siz; |
| p += 4; |
| |
| // RET |
| *p++ = 0xc3; |
| |
| if(p > q) |
| runtime·throw("bad math in sys.closure"); |
| } |