Home | History | Annotate | Download | only in runtime
      1 // 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 
      5 package runtime
      6 
      7 import (
      8 	"unsafe"
      9 )
     10 
     11 type callbacks struct {
     12 	lock mutex
     13 	ctxt [cb_max]*wincallbackcontext
     14 	n    int
     15 }
     16 
     17 func (c *wincallbackcontext) isCleanstack() bool {
     18 	return c.cleanstack
     19 }
     20 
     21 func (c *wincallbackcontext) setCleanstack(cleanstack bool) {
     22 	c.cleanstack = cleanstack
     23 }
     24 
     25 var (
     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.
     38 func callbackasmAddr(i int) uintptr {
     39 	return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5)))
     40 }
     41 
     42 //go:linkname compileCallback syscall.compileCallback
     43 func compileCallback(fn eface, cleanstack bool) (code uintptr) {
     44 	if fn._type == nil || (fn._type.kind&kindMask) != kindFunc {
     45 		panic("compileCallback: not a function")
     46 	}
     47 	ft := (*functype)(unsafe.Pointer(fn._type))
     48 	if ft.out.len != 1 {
     49 		panic("compileCallback: function must have one output parameter")
     50 	}
     51 	uintptrSize := unsafe.Sizeof(uintptr(0))
     52 	if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize {
     53 		panic("compileCallback: output parameter size is wrong")
     54 	}
     55 	argsize := uintptr(0)
     56 	for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] {
     57 		if (*t).size > uintptrSize {
     58 			panic("compileCallback: input parameter size is wrong")
     59 		}
     60 		argsize += uintptrSize
     61 	}
     62 
     63 	lock(&cbs.lock)
     64 	defer unlock(&cbs.lock)
     65 
     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 {
     73 		throw("too many callback functions")
     74 	}
     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 }
     90 
     91 //go:linkname syscall_loadlibrary syscall.loadlibrary
     92 //go:nosplit
     93 func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
     94 	c := &getg().m.syscall
     95 	c.fn = getLoadLibrary()
     96 	c.n = 1
     97 	c.args = uintptr(noescape(unsafe.Pointer(&filename)))
     98 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
     99 	handle = c.r1
    100 	if handle == 0 {
    101 		err = c.err
    102 	}
    103 	return
    104 }
    105 
    106 //go:linkname syscall_getprocaddress syscall.getprocaddress
    107 //go:nosplit
    108 func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
    109 	c := &getg().m.syscall
    110 	c.fn = getGetProcAddress()
    111 	c.n = 2
    112 	c.args = uintptr(noescape(unsafe.Pointer(&handle)))
    113 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    114 	outhandle = c.r1
    115 	if outhandle == 0 {
    116 		err = c.err
    117 	}
    118 	return
    119 }
    120 
    121 //go:linkname syscall_Syscall syscall.Syscall
    122 //go:nosplit
    123 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
    124 	c := &getg().m.syscall
    125 	c.fn = fn
    126 	c.n = nargs
    127 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    128 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    129 	return c.r1, c.r2, c.err
    130 }
    131 
    132 //go:linkname syscall_Syscall6 syscall.Syscall6
    133 //go:nosplit
    134 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
    135 	c := &getg().m.syscall
    136 	c.fn = fn
    137 	c.n = nargs
    138 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    139 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    140 	return c.r1, c.r2, c.err
    141 }
    142 
    143 //go:linkname syscall_Syscall9 syscall.Syscall9
    144 //go:nosplit
    145 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
    146 	c := &getg().m.syscall
    147 	c.fn = fn
    148 	c.n = nargs
    149 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    150 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    151 	return c.r1, c.r2, c.err
    152 }
    153 
    154 //go:linkname syscall_Syscall12 syscall.Syscall12
    155 //go:nosplit
    156 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
    157 	c := &getg().m.syscall
    158 	c.fn = fn
    159 	c.n = nargs
    160 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    161 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    162 	return c.r1, c.r2, c.err
    163 }
    164 
    165 //go:linkname syscall_Syscall15 syscall.Syscall15
    166 //go:nosplit
    167 func 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 	c := &getg().m.syscall
    169 	c.fn = fn
    170 	c.n = nargs
    171 	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
    172 	cgocall(asmstdcallAddr, unsafe.Pointer(c))
    173 	return c.r1, c.r2, c.err
    174 }
    175