blob: cd8b8847bde1426bdcb7f780b41d0add939f713e [file] [log] [blame]
Alex Brainman38ce5992014-08-25 15:59:13 +10001// Copyright 2014 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 runtime
6
7import (
8 "unsafe"
9)
10
11type callbacks struct {
Russ Coxfee7c692014-08-27 23:41:10 -040012 lock mutex
Alex Brainman38ce5992014-08-25 15:59:13 +100013 ctxt [cb_max]*wincallbackcontext
14 n int
15}
16
17func (c *wincallbackcontext) isCleanstack() bool {
Russ Coxd21638b2014-08-27 21:59:49 -040018 return c.cleanstack
Alex Brainman38ce5992014-08-25 15:59:13 +100019}
20
21func (c *wincallbackcontext) setCleanstack(cleanstack bool) {
Russ Coxd21638b2014-08-27 21:59:49 -040022 c.cleanstack = cleanstack
Alex Brainman38ce5992014-08-25 15:59:13 +100023}
24
25var (
26 cbs callbacks
27 cbctxts **wincallbackcontext = &cbs.ctxt[0] // to simplify access to cbs.ctxt in sys_windows_*.s
28
29 callbackasm byte // type isn't really byte, it's code in runtime
30)
31
32// callbackasmAddr returns address of runtime.callbackasm
33// function adjusted by i.
34// runtime.callbackasm is just a series of CALL instructions
35// (each is 5 bytes long), and we want callback to arrive at
36// correspondent call instruction instead of start of
37// runtime.callbackasm.
38func callbackasmAddr(i int) uintptr {
39 return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5)))
40}
41
Alex Brainman20dce042014-12-23 15:33:51 +110042//go:linkname compileCallback syscall.compileCallback
Alex Brainman38ce5992014-08-25 15:59:13 +100043func compileCallback(fn eface, cleanstack bool) (code uintptr) {
44 if fn._type == nil || (fn._type.kind&kindMask) != kindFunc {
Alex Brainmanab4578a2014-11-20 12:24:03 +110045 panic("compileCallback: not a function")
Alex Brainman38ce5992014-08-25 15:59:13 +100046 }
47 ft := (*functype)(unsafe.Pointer(fn._type))
Alex Brainmanab4578a2014-11-20 12:24:03 +110048 if ft.out.len != 1 {
49 panic("compileCallback: function must have one output parameter")
Alex Brainman38ce5992014-08-25 15:59:13 +100050 }
Russ Coxd21638b2014-08-27 21:59:49 -040051 uintptrSize := unsafe.Sizeof(uintptr(0))
Alex Brainmanab4578a2014-11-20 12:24:03 +110052 if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize {
53 panic("compileCallback: output parameter size is wrong")
Alex Brainman38ce5992014-08-25 15:59:13 +100054 }
Russ Coxd21638b2014-08-27 21:59:49 -040055 argsize := uintptr(0)
Alex Brainmanab4578a2014-11-20 12:24:03 +110056 for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] {
Alex Brainman5d5312c2014-09-15 12:58:28 +100057 if (*t).size > uintptrSize {
Alex Brainmanab4578a2014-11-20 12:24:03 +110058 panic("compileCallback: input parameter size is wrong")
Alex Brainman38ce5992014-08-25 15:59:13 +100059 }
60 argsize += uintptrSize
61 }
62
Russ Cox8ecb9a72014-08-27 23:32:49 -040063 lock(&cbs.lock)
64 defer unlock(&cbs.lock)
Alex Brainman38ce5992014-08-25 15:59:13 +100065
66 n := cbs.n
67 for i := 0; i < n; i++ {
68 if cbs.ctxt[i].gobody == fn.data && cbs.ctxt[i].isCleanstack() == cleanstack {
69 return callbackasmAddr(i)
70 }
71 }
72 if n >= cb_max {
Keith Randallb2a950b2014-12-27 20:58:00 -080073 throw("too many callback functions")
Alex Brainman38ce5992014-08-25 15:59:13 +100074 }
75
76 c := new(wincallbackcontext)
77 c.gobody = fn.data
78 c.argsize = argsize
79 c.setCleanstack(cleanstack)
80 if cleanstack && argsize != 0 {
81 c.restorestack = argsize
82 } else {
83 c.restorestack = 0
84 }
85 cbs.ctxt[n] = c
86 cbs.n++
87
88 return callbackasmAddr(n)
89}
Russ Cox2eccf0d2014-09-14 21:25:44 -040090
Alex Brainman20dce042014-12-23 15:33:51 +110091//go:linkname syscall_loadlibrary syscall.loadlibrary
Russ Cox2eccf0d2014-09-14 21:25:44 -040092//go:nosplit
93func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
94 var c libcall
95 c.fn = getLoadLibrary()
96 c.n = 1
97 c.args = uintptr(unsafe.Pointer(&filename))
98 cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
99 handle = c.r1
100 if handle == 0 {
101 err = c.err
102 }
103 return
104}
105
Alex Brainman20dce042014-12-23 15:33:51 +1100106//go:linkname syscall_getprocaddress syscall.getprocaddress
Russ Cox2eccf0d2014-09-14 21:25:44 -0400107//go:nosplit
108func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
109 var c libcall
110 c.fn = getGetProcAddress()
111 c.n = 2
112 c.args = uintptr(unsafe.Pointer(&handle))
113 cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
114 outhandle = c.r1
115 if outhandle == 0 {
116 err = c.err
117 }
118 return
119}
120
Alex Brainman20dce042014-12-23 15:33:51 +1100121//go:linkname syscall_Syscall syscall.Syscall
Russ Cox2eccf0d2014-09-14 21:25:44 -0400122//go:nosplit
123func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
124 var c libcall
125 c.fn = fn
126 c.n = nargs
127 c.args = uintptr(unsafe.Pointer(&a1))
128 cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
129 return c.r1, c.r2, c.err
130}
131
Alex Brainman20dce042014-12-23 15:33:51 +1100132//go:linkname syscall_Syscall6 syscall.Syscall6
Russ Cox2eccf0d2014-09-14 21:25:44 -0400133//go:nosplit
134func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
135 var c libcall
136 c.fn = fn
137 c.n = nargs
138 c.args = uintptr(unsafe.Pointer(&a1))
139 cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
140 return c.r1, c.r2, c.err
141}
142
Alex Brainman20dce042014-12-23 15:33:51 +1100143//go:linkname syscall_Syscall9 syscall.Syscall9
Russ Cox2eccf0d2014-09-14 21:25:44 -0400144//go:nosplit
145func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
146 var c libcall
147 c.fn = fn
148 c.n = nargs
149 c.args = uintptr(unsafe.Pointer(&a1))
150 cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
151 return c.r1, c.r2, c.err
152}
153
Alex Brainman20dce042014-12-23 15:33:51 +1100154//go:linkname syscall_Syscall12 syscall.Syscall12
Russ Cox2eccf0d2014-09-14 21:25:44 -0400155//go:nosplit
156func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
157 var c libcall
158 c.fn = fn
159 c.n = nargs
160 c.args = uintptr(unsafe.Pointer(&a1))
161 cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
162 return c.r1, c.r2, c.err
163}
164
Alex Brainman20dce042014-12-23 15:33:51 +1100165//go:linkname syscall_Syscall15 syscall.Syscall15
Russ Cox2eccf0d2014-09-14 21:25:44 -0400166//go:nosplit
167func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
168 var c libcall
169 c.fn = fn
170 c.n = nargs
171 c.args = uintptr(unsafe.Pointer(&a1))
172 cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
173 return c.r1, c.r2, c.err
174}