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
103
104
105 panic("compileCallback: argument size is larger than uintptr")
106 }
107 if k := t.Kind(); GOARCH != "386" && (k == abi.Float32 || k == abi.Float64) {
108
109
110
111
112
113
114
115 panic("compileCallback: float arguments not supported")
116 }
117
118 if t.Size_ == 0 {
119
120 p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_))
121 return
122 }
123
124
125
126
127
128
129
130
131
132 oldParts := p.parts
133 if p.tryRegAssignArg(t, 0) {
134
135
136
137
138 p.dstSpill = alignUp(p.dstSpill, uintptr(t.Align_))
139 p.dstSpill += t.Size_
140 } else {
141
142
143 p.parts = oldParts
144
145
146 p.dstStackSize = alignUp(p.dstStackSize, uintptr(t.Align_))
147
148
149
150
151
152 part := abiPart{
153 kind: abiPartStack,
154 srcStackOffset: p.srcStackSize,
155 dstStackOffset: p.dstStackSize,
156 len: t.Size_,
157 }
158
159 if len(p.parts) == 0 || !p.parts[len(p.parts)-1].tryMerge(part) {
160 p.parts = append(p.parts, part)
161 }
162
163 p.dstStackSize += t.Size_
164 }
165
166
167
168 p.srcStackSize += goarch.PtrSize
169 }
170
171
172
173
174
175
176
177 func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool {
178 switch k := t.Kind(); k {
179 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:
180
181 return p.assignReg(t.Size_, offset)
182 case abi.Int64, abi.Uint64:
183
184 if goarch.PtrSize == 8 {
185 return p.assignReg(t.Size_, offset)
186 }
187 case abi.Array:
188 at := (*arraytype)(unsafe.Pointer(t))
189 if at.Len == 1 {
190 return p.tryRegAssignArg(at.Elem, offset)
191 }
192 case abi.Struct:
193 st := (*structtype)(unsafe.Pointer(t))
194 for i := range st.Fields {
195 f := &st.Fields[i]
196 if !p.tryRegAssignArg(f.Typ, offset+f.Offset) {
197 return false
198 }
199 }
200 return true
201 }
202
203
204 panic("compileCallback: type " + toRType(t).string() + " is currently not supported for use in system callbacks")
205 }
206
207
208
209
210
211
212 func (p *abiDesc) assignReg(size, offset uintptr) bool {
213 if p.dstRegisters >= intArgRegs {
214 return false
215 }
216 p.parts = append(p.parts, abiPart{
217 kind: abiPartReg,
218 srcStackOffset: p.srcStackSize + offset,
219 dstRegister: p.dstRegisters,
220 len: size,
221 })
222 p.dstRegisters++
223 return true
224 }
225
226 type winCallbackKey struct {
227 fn *funcval
228 cdecl bool
229 }
230
231 func callbackasm()
232
233
234
235
236
237
238
239
240
241
242 func callbackasmAddr(i int) uintptr {
243 var entrySize int
244 switch GOARCH {
245 default:
246 panic("unsupported architecture")
247 case "386", "amd64":
248 entrySize = 5
249 case "arm", "arm64":
250
251
252 entrySize = 8
253 }
254 return abi.FuncPCABI0(callbackasm) + uintptr(i*entrySize)
255 }
256
257 const callbackMaxFrame = 64 * goarch.PtrSize
258
259
260
261
262
263
264
265
266
267 func compileCallback(fn eface, cdecl bool) (code uintptr) {
268 if GOARCH != "386" {
269
270 cdecl = false
271 }
272
273 if fn._type == nil || fn._type.Kind() != abi.Func {
274 panic("compileCallback: expected function with one uintptr-sized result")
275 }
276 ft := (*functype)(unsafe.Pointer(fn._type))
277
278
279 var abiMap abiDesc
280 for _, t := range ft.InSlice() {
281 abiMap.assignArg(t)
282 }
283
284
285 abiMap.dstStackSize = alignUp(abiMap.dstStackSize, goarch.PtrSize)
286 abiMap.retOffset = abiMap.dstStackSize
287
288 if len(ft.OutSlice()) != 1 {
289 panic("compileCallback: expected function with one uintptr-sized result")
290 }
291 if ft.OutSlice()[0].Size_ != goarch.PtrSize {
292 panic("compileCallback: expected function with one uintptr-sized result")
293 }
294 if k := ft.OutSlice()[0].Kind(); k == abi.Float32 || k == abi.Float64 {
295
296
297
298 panic("compileCallback: float results not supported")
299 }
300 if intArgRegs == 0 {
301
302
303
304 abiMap.dstStackSize += goarch.PtrSize
305 }
306
307
308
309 frameSize := alignUp(abiMap.dstStackSize, goarch.PtrSize)
310 frameSize += abiMap.dstSpill
311 if frameSize > callbackMaxFrame {
312 panic("compileCallback: function argument frame too large")
313 }
314
315
316
317 var retPop uintptr
318 if cdecl {
319 retPop = abiMap.srcStackSize
320 }
321
322 key := winCallbackKey{(*funcval)(fn.data), cdecl}
323
324 cbsLock()
325
326
327 if n, ok := cbs.index[key]; ok {
328 cbsUnlock()
329 return callbackasmAddr(n)
330 }
331
332
333 if cbs.index == nil {
334 cbs.index = make(map[winCallbackKey]int)
335 }
336 n := cbs.n
337 if n >= len(cbs.ctxt) {
338 cbsUnlock()
339 throw("too many callback functions")
340 }
341 c := winCallback{key.fn, retPop, abiMap}
342 cbs.ctxt[n] = c
343 cbs.index[key] = n
344 cbs.n++
345
346 cbsUnlock()
347 return callbackasmAddr(n)
348 }
349
350 type callbackArgs struct {
351 index uintptr
352
353
354
355
356
357
358
359
360
361
362
363 args unsafe.Pointer
364
365 result uintptr
366 retPop uintptr
367 }
368
369
370 func callbackWrap(a *callbackArgs) {
371 c := cbs.ctxt[a.index]
372 a.retPop = c.retPop
373
374
375 var regs abi.RegArgs
376 var frame [callbackMaxFrame]byte
377 goArgs := unsafe.Pointer(&frame)
378 for _, part := range c.abiMap.parts {
379 switch part.kind {
380 case abiPartStack:
381 memmove(add(goArgs, part.dstStackOffset), add(a.args, part.srcStackOffset), part.len)
382 case abiPartReg:
383 goReg := unsafe.Pointer(®s.Ints[part.dstRegister])
384 memmove(goReg, add(a.args, part.srcStackOffset), part.len)
385 default:
386 panic("bad ABI description")
387 }
388 }
389
390
391
392 frameSize := alignUp(c.abiMap.dstStackSize, goarch.PtrSize)
393 frameSize += c.abiMap.dstSpill
394
395
396
397 reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(frameSize), ®s)
398
399
400
401
402
403
404 if c.abiMap.dstStackSize != c.abiMap.retOffset {
405 a.result = *(*uintptr)(unsafe.Pointer(&frame[c.abiMap.retOffset]))
406 } else {
407 var zero int
408
409
410
411 a.result = regs.Ints[zero]
412 }
413 }
414
415
416
417
418
419
420
421
422
423 func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) {
424 if n > uintptr(len(args)) {
425 panic("syscall: n > len(args)")
426 }
427 if n > windows.MaxArgs {
428 panic("runtime: SyscallN has too many arguments")
429 }
430
431
432
433
434 c := &getg().m.winsyscall
435 c.Fn = fn
436 c.N = n
437 if c.N != 0 {
438 c.Args = uintptr(noescape(unsafe.Pointer(&args[0])))
439 }
440 cgocall(asmstdcallAddr, unsafe.Pointer(c))
441
442
443
444 c = &getg().m.winsyscall
445 return c.R1, c.R2, c.Err
446 }
447
View as plain text