Source file
src/runtime/syscall_windows.go
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/goarch"
10 "internal/runtime/syscall/windows"
11 "unsafe"
12 )
13
14
15 var cbs struct {
16 lock mutex
17 ctxt [cb_max]winCallback
18 index map[winCallbackKey]int
19 n int
20 }
21
22 func cbsLock() {
23 lock(&cbs.lock)
24
25
26
27
28 if raceenabled && mainStarted {
29 raceacquire(unsafe.Pointer(&cbs.lock))
30 }
31 }
32
33 func cbsUnlock() {
34 if raceenabled && mainStarted {
35 racerelease(unsafe.Pointer(&cbs.lock))
36 }
37 unlock(&cbs.lock)
38 }
39
40
41 type winCallback struct {
42 fn *funcval
43 retPop uintptr
44 abiMap abiDesc
45 }
46
47
48 type abiPartKind int
49
50 const (
51 abiPartBad abiPartKind = iota
52 abiPartStack
53 abiPartReg
54 )
55
56
57 type abiPart struct {
58 kind abiPartKind
59 srcStackOffset uintptr
60 dstStackOffset uintptr
61 dstRegister int
62 len uintptr
63 }
64
65 func (a *abiPart) tryMerge(b abiPart) bool {
66 if a.kind != abiPartStack || b.kind != abiPartStack {
67 return false
68 }
69 if a.srcStackOffset+a.len == b.srcStackOffset && a.dstStackOffset+a.len == b.dstStackOffset {
70 a.len += b.len
71 return true
72 }
73 return false
74 }
75
76
77
78
79
80
81 type abiDesc struct {
82 parts []abiPart
83
84 srcStackSize uintptr
85 dstStackSize uintptr
86 dstSpill uintptr
87 dstRegisters int
88
89
90
91 retOffset uintptr
92 }
93
94 func (p *abiDesc) assignArg(t *_type) {
95 if t.Size_ > goarch.PtrSize {
96
97
98
99
100
101
102 panic("compileCallback: argument size is larger than uintptr")
103 }
104 if k := t.Kind(); GOARCH != "386" && (k == abi.Float32 || k == abi.Float64) {
105
106
107
108
109
110 panic("compileCallback: float arguments not supported")
111 }
112
113 if t.Size_ == 0 {
114
115 p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_))
116 return
117 }
118
119
120
121
122
123
124
125
126
127 oldParts := p.parts
128 if p.tryRegAssignArg(t, 0) {
129
130
131
132
133 p.dstSpill = alignUp(p.dstSpill, uintptr(t.Align_))
134 p.dstSpill += t.Size_
135 } else {
136
137
138 p.parts = oldParts
139
140
141 p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_))
142
143
144
145
146
147 part := abiPart{
148 kind: abiPartStack,
149 srcStackOffset: p.srcStackSize,
150 dstStackOffset: p.dstStackSize,
151 len: t.Size_,
152 }
153
154 if len(p.parts) == 0 || !p.parts[len(p.parts)-1].tryMerge(part) {
155 p.parts = append(p.parts, part)
156 }
157
158 p.dstStackSize += t.Size_
159 }
160
161
162
163 p.srcStackSize += goarch.PtrSize
164 }
165
166
167
168
169
170
171
172 func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool {
173 switch k := t.Kind(); k {
174 case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uintptr, abi.Pointer, abi.UnsafePointer:
175
176 return p.assignReg(t.Size_, offset)
177 case abi.Int64, abi.Uint64:
178
179 if goarch.PtrSize == 8 {
180 return p.assignReg(t.Size_, offset)
181 }
182 case abi.Array:
183 at := (*arraytype)(unsafe.Pointer(t))
184 if at.Len == 1 {
185 return p.tryRegAssignArg(at.Elem, offset)
186 }
187 case abi.Struct:
188 st := (*structtype)(unsafe.Pointer(t))
189 for i := range st.Fields {
190 f := &st.Fields[i]
191 if !p.tryRegAssignArg(f.Typ, offset+f.Offset) {
192 return false
193 }
194 }
195 return true
196 }
197
198
199 panic("compileCallback: type " + toRType(t).string() + " is currently not supported for use in system callbacks")
200 }
201
202
203
204
205
206
207 func (p *abiDesc) assignReg(size, offset uintptr) bool {
208 if p.dstRegisters >= intArgRegs {
209 return false
210 }
211 p.parts = append(p.parts, abiPart{
212 kind: abiPartReg,
213 srcStackOffset: p.srcStackSize + offset,
214 dstRegister: p.dstRegisters,
215 len: size,
216 })
217 p.dstRegisters++
218 return true
219 }
220
221 type winCallbackKey struct {
222 fn *funcval
223 cdecl bool
224 }
225
226 func callbackasm()
227
228
229
230
231
232
233
234
235
236
237 func callbackasmAddr(i int) uintptr {
238 var entrySize int
239 switch GOARCH {
240 default:
241 panic("unsupported architecture")
242 case "386", "amd64":
243 entrySize = 5
244 case "arm64":
245
246
247 entrySize = 8
248 }
249 return abi.FuncPCABI0(callbackasm) + uintptr(i*entrySize)
250 }
251
252 const callbackMaxFrame = 64 * goarch.PtrSize
253
254
255
256
257
258
259
260
261
262 func compileCallback(fn eface, cdecl bool) (code uintptr) {
263 if GOARCH != "386" {
264
265 cdecl = false
266 }
267
268 if fn._type == nil || fn._type.Kind() != abi.Func {
269 panic("compileCallback: expected function with one uintptr-sized result")
270 }
271 ft := (*functype)(unsafe.Pointer(fn._type))
272
273
274 var abiMap abiDesc
275 for _, t := range ft.InSlice() {
276 abiMap.assignArg(t)
277 }
278
279
280 abiMap.dstStackSize = alignUp(abiMap.dstStackSize, goarch.PtrSize)
281 abiMap.retOffset = abiMap.dstStackSize
282
283 if len(ft.OutSlice()) != 1 {
284 panic("compileCallback: expected function with one uintptr-sized result")
285 }
286 if ft.OutSlice()[0].Size_ != goarch.PtrSize {
287 panic("compileCallback: expected function with one uintptr-sized result")
288 }
289 if k := ft.OutSlice()[0].Kind(); k == abi.Float32 || k == abi.Float64 {
290
291
292
293 panic("compileCallback: float results not supported")
294 }
295 if intArgRegs == 0 {
296
297
298
299 abiMap.dstStackSize += goarch.PtrSize
300 }
301
302
303
304 frameSize := alignUp(abiMap.dstStackSize, goarch.PtrSize)
305 frameSize += abiMap.dstSpill
306 if frameSize > callbackMaxFrame {
307 panic("compileCallback: function argument frame too large")
308 }
309
310
311
312 var retPop uintptr
313 if cdecl {
314 retPop = abiMap.srcStackSize
315 }
316
317 key := winCallbackKey{(*funcval)(fn.data), cdecl}
318
319 cbsLock()
320
321
322 if n, ok := cbs.index[key]; ok {
323 cbsUnlock()
324 return callbackasmAddr(n)
325 }
326
327
328 if cbs.index == nil {
329 cbs.index = make(map[winCallbackKey]int)
330 }
331 n := cbs.n
332 if n >= len(cbs.ctxt) {
333 cbsUnlock()
334 throw("too many callback functions")
335 }
336 c := winCallback{key.fn, retPop, abiMap}
337 cbs.ctxt[n] = c
338 cbs.index[key] = n
339 cbs.n++
340
341 cbsUnlock()
342 return callbackasmAddr(n)
343 }
344
345 type callbackArgs struct {
346 index uintptr
347
348
349
350
351
352
353
354 args unsafe.Pointer
355
356 result uintptr
357 retPop uintptr
358 }
359
360
361 func callbackWrap(a *callbackArgs) {
362 c := cbs.ctxt[a.index]
363 a.retPop = c.retPop
364
365
366 var regs abi.RegArgs
367 var frame [callbackMaxFrame]byte
368 goArgs := unsafe.Pointer(&frame)
369 for _, part := range c.abiMap.parts {
370 switch part.kind {
371 case abiPartStack:
372 memmove(add(goArgs, part.dstStackOffset), add(a.args, part.srcStackOffset), part.len)
373 case abiPartReg:
374 goReg := unsafe.Pointer(®s.Ints[part.dstRegister])
375 memmove(goReg, add(a.args, part.srcStackOffset), part.len)
376 default:
377 panic("bad ABI description")
378 }
379 }
380
381
382
383 frameSize := alignUp(c.abiMap.dstStackSize, goarch.PtrSize)
384 frameSize += c.abiMap.dstSpill
385
386
387
388 reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(frameSize), ®s)
389
390
391
392
393
394
395 if c.abiMap.dstStackSize != c.abiMap.retOffset {
396 a.result = *(*uintptr)(unsafe.Pointer(&frame[c.abiMap.retOffset]))
397 } else {
398 var zero int
399
400
401
402 a.result = regs.Ints[zero]
403 }
404 }
405
406
407
408
409
410
411
412
413
414 func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
415 if n > uintptr(len(args)) {
416 panic("syscall: n > len(args)")
417 }
418 if n > windows.MaxArgs {
419 panic("runtime: SyscallN has too many arguments")
420 }
421
422
423
424
425 c := &getg().m.winsyscall
426 c.Fn = fn
427 c.N = n
428 if c.N != 0 {
429 c.Args = uintptr(noescape(unsafe.Pointer(&args[0])))
430 }
431 cgocall(asmstdcallAddr, unsafe.Pointer(c))
432
433
434
435 c = &getg().m.winsyscall
436 return c.R1, c.R2, c.Err
437 }
438
View as plain text