~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/runtime/closure_amd64.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
#include "runtime.h"
6
 
 
7
 
#pragma textflag 7
8
 
// func closure(siz int32,
9
 
//      fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
10
 
//      arg0, arg1, arg2 *ptr) (func(xxx) yyy)
11
 
void
12
 
runtime·closure(int32 siz, byte *fn, byte *arg0)
13
 
{
14
 
        byte *p, *q, **ret;
15
 
        int32 i, n;
16
 
        int64 pcrel;
17
 
 
18
 
        if(siz < 0 || siz%8 != 0)
19
 
                runtime·throw("bad closure size");
20
 
 
21
 
        ret = (byte**)((byte*)&arg0 + siz);
22
 
 
23
 
        if(siz > 100) {
24
 
                // TODO(rsc): implement stack growth preamble?
25
 
                runtime·throw("closure too big");
26
 
        }
27
 
 
28
 
        // compute size of new fn.
29
 
        // must match code laid out below.
30
 
        n = 7+10+3;     // SUBQ MOVQ MOVQ
31
 
        if(siz <= 4*8)
32
 
                n += 2*siz/8;   // MOVSQ MOVSQ...
33
 
        else
34
 
                n += 7+3;       // MOVQ REP MOVSQ
35
 
        n += 12;        // CALL worst case; sometimes only 5
36
 
        n += 7+1;       // ADDQ RET
37
 
 
38
 
        // store args aligned after code, so gc can find them.
39
 
        n += siz;
40
 
        if(n%8)
41
 
                n += 8 - n%8;
42
 
 
43
 
        p = runtime·mal(n);
44
 
        *ret = p;
45
 
        q = p + n - siz;
46
 
 
47
 
        if(siz > 0) {
48
 
                runtime·memmove(q, (byte*)&arg0, siz);
49
 
 
50
 
                // SUBQ $siz, SP
51
 
                *p++ = 0x48;
52
 
                *p++ = 0x81;
53
 
                *p++ = 0xec;
54
 
                *(uint32*)p = siz;
55
 
                p += 4;
56
 
 
57
 
                // MOVQ $q, SI
58
 
                *p++ = 0x48;
59
 
                *p++ = 0xbe;
60
 
                *(byte**)p = q;
61
 
                p += 8;
62
 
 
63
 
                // MOVQ SP, DI
64
 
                *p++ = 0x48;
65
 
                *p++ = 0x89;
66
 
                *p++ = 0xe7;
67
 
 
68
 
                if(siz <= 4*8) {
69
 
                        for(i=0; i<siz; i+=8) {
70
 
                                // MOVSQ
71
 
                                *p++ = 0x48;
72
 
                                *p++ = 0xa5;
73
 
                        }
74
 
                } else {
75
 
                        // MOVQ $(siz/8), CX  [32-bit immediate siz/8]
76
 
                        *p++ = 0x48;
77
 
                        *p++ = 0xc7;
78
 
                        *p++ = 0xc1;
79
 
                        *(uint32*)p = siz/8;
80
 
                        p += 4;
81
 
 
82
 
                        // REP; MOVSQ
83
 
                        *p++ = 0xf3;
84
 
                        *p++ = 0x48;
85
 
                        *p++ = 0xa5;
86
 
                }
87
 
        }
88
 
 
89
 
        // call fn
90
 
        pcrel = fn - (p+5);
91
 
        if((int32)pcrel == pcrel) {
92
 
                // can use direct call with pc-relative offset
93
 
                // CALL fn
94
 
                *p++ = 0xe8;
95
 
                *(int32*)p = pcrel;
96
 
                p += 4;
97
 
        } else {
98
 
                // MOVQ $fn, CX  [64-bit immediate fn]
99
 
                *p++ = 0x48;
100
 
                *p++ = 0xb9;
101
 
                *(byte**)p = fn;
102
 
                p += 8;
103
 
 
104
 
                // CALL *CX
105
 
                *p++ = 0xff;
106
 
                *p++ = 0xd1;
107
 
        }
108
 
 
109
 
        // ADDQ $siz, SP
110
 
        *p++ = 0x48;
111
 
        *p++ = 0x81;
112
 
        *p++ = 0xc4;
113
 
        *(uint32*)p = siz;
114
 
        p += 4;
115
 
 
116
 
        // RET
117
 
        *p++ = 0xc3;
118
 
 
119
 
        if(p > q)
120
 
                runtime·throw("bad math in sys.closure");
121
 
}
122
 
 
123