runtime: convert NewCallback and NewCallbackCDecl to Go
LGTM=khr
R=khr, remyoudompheng
CC=golang-codereviews
https://golang.org/cl/132820043
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 2900a27..54c84b4 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -384,8 +384,9 @@
" iface struct{}; eface struct{}; interfacetype struct{}; itab struct{};" +
" mcache struct{}; bucket struct{}; sudog struct{}; g struct{};" +
" hchan struct{}; chantype struct{}; waitq struct{};" +
- " note struct{};" +
- ")"
+ " note struct{}; wincallbackcontext struct{};" +
+ "); " +
+ "const ( cb_max = 2000 )"
f, err = parser.ParseFile(fset, filename, src, 0)
if err != nil {
log.Fatalf("incorrect generated file: %s", err)
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
index b16b575..5daa314 100644
--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -402,6 +402,11 @@
bwritestr(&out, p);
}
+
+ // Some windows specific const.
+ if(streq(goos, "windows")) {
+ bwritestr(&out, bprintf(&b, "const cb_max = %d\n", MAXWINCB));
+ }
writefile(&out, file, 0);
diff --git a/src/pkg/runtime/callback_windows.c b/src/pkg/runtime/callback_windows.c
deleted file mode 100644
index 5c6975a..0000000
--- a/src/pkg/runtime/callback_windows.c
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "runtime.h"
-#include "type.h"
-#include "typekind.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "zasm_GOOS_GOARCH.h"
-
-typedef struct Callbacks Callbacks;
-struct Callbacks {
- Lock lock;
- WinCallbackContext* ctxt[cb_max];
- int32 n;
-};
-
-static Callbacks cbs;
-
-WinCallbackContext** runtime·cbctxts; // to simplify access to cbs.ctxt in sys_windows_*.s
-
-// Call back from windows dll into go.
-byte *
-runtime·compilecallback(Eface fn, bool cleanstack)
-{
- FuncType *ft;
- Type *t;
- int32 argsize, i, n;
- WinCallbackContext *c;
-
- if(fn.type == nil || (fn.type->kind&KindMask) != KindFunc)
- runtime·panicstring("compilecallback: not a function");
- ft = (FuncType*)fn.type;
- if(ft->out.len != 1)
- runtime·panicstring("compilecallback: function must have one output parameter");
- if(((Type**)ft->out.array)[0]->size != sizeof(uintptr))
- runtime·panicstring("compilecallback: output parameter size is wrong");
- argsize = 0;
- for(i=0; i<ft->in.len; i++) {
- t = ((Type**)ft->in.array)[i];
- if(t->size > sizeof(uintptr))
- runtime·panicstring("compilecallback: input parameter size is wrong");
- argsize += sizeof(uintptr);
- }
-
- runtime·lock(&cbs.lock);
- if(runtime·cbctxts == nil)
- runtime·cbctxts = &(cbs.ctxt[0]);
- n = cbs.n;
- for(i=0; i<n; i++) {
- if(cbs.ctxt[i]->gobody == fn.data && cbs.ctxt[i]->cleanstack == cleanstack) {
- runtime·unlock(&cbs.lock);
- // runtime·callbackasm is just a series of CALL instructions
- // (each is 5 bytes long), and we want callback to arrive at
- // correspondent call instruction instead of start of
- // runtime·callbackasm.
- return (byte*)runtime·callbackasm + i * 5;
- }
- }
- if(n >= cb_max)
- runtime·throw("too many callback functions");
- c = runtime·mallocgc(sizeof *c, nil, 0);
- c->gobody = fn.data;
- c->argsize = argsize;
- c->cleanstack = cleanstack;
- if(cleanstack && argsize!=0)
- c->restorestack = argsize;
- else
- c->restorestack = 0;
- cbs.ctxt[n] = c;
- cbs.n++;
- runtime·unlock(&cbs.lock);
-
- // as before
- return (byte*)runtime·callbackasm + n * 5;
-}
diff --git a/src/pkg/runtime/syscall_windows.go b/src/pkg/runtime/syscall_windows.go
new file mode 100644
index 0000000..272db62
--- /dev/null
+++ b/src/pkg/runtime/syscall_windows.go
@@ -0,0 +1,92 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "unsafe"
+)
+
+type callbacks struct {
+ lock
+ ctxt [cb_max]*wincallbackcontext
+ n int
+}
+
+func (c *wincallbackcontext) isCleanstack() bool {
+ return c.cleanstack == 1
+}
+
+func (c *wincallbackcontext) setCleanstack(cleanstack bool) {
+ if cleanstack {
+ c.cleanstack = 1
+ } else {
+ c.cleanstack = 0
+ }
+}
+
+var (
+ cbs callbacks
+ cbctxts **wincallbackcontext = &cbs.ctxt[0] // to simplify access to cbs.ctxt in sys_windows_*.s
+
+ callbackasm byte // type isn't really byte, it's code in runtime
+)
+
+// callbackasmAddr returns address of runtime.callbackasm
+// function adjusted by i.
+// runtime.callbackasm is just a series of CALL instructions
+// (each is 5 bytes long), and we want callback to arrive at
+// correspondent call instruction instead of start of
+// runtime.callbackasm.
+func callbackasmAddr(i int) uintptr {
+ return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5)))
+}
+
+func compileCallback(fn eface, cleanstack bool) (code uintptr) {
+ if fn._type == nil || (fn._type.kind&kindMask) != kindFunc {
+ panic("compilecallback: not a function")
+ }
+ ft := (*functype)(unsafe.Pointer(fn._type))
+ if len(ft.out) != 1 {
+ panic("compilecallback: function must have one output parameter")
+ }
+ uintptrSize := uint(unsafe.Sizeof(uintptr(0)))
+ if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize {
+ panic("compilecallback: output parameter size is wrong")
+ }
+ argsize := uint(0)
+ for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] {
+ if (*t).size != uintptrSize {
+ panic("compilecallback: input parameter size is wrong")
+ }
+ argsize += uintptrSize
+ }
+
+ golock(&cbs.lock)
+ defer gounlock(&cbs.lock)
+
+ n := cbs.n
+ for i := 0; i < n; i++ {
+ if cbs.ctxt[i].gobody == fn.data && cbs.ctxt[i].isCleanstack() == cleanstack {
+ return callbackasmAddr(i)
+ }
+ }
+ if n >= cb_max {
+ gothrow("too many callback functions")
+ }
+
+ c := new(wincallbackcontext)
+ c.gobody = fn.data
+ c.argsize = argsize
+ c.setCleanstack(cleanstack)
+ if cleanstack && argsize != 0 {
+ c.restorestack = argsize
+ } else {
+ c.restorestack = 0
+ }
+ cbs.ctxt[n] = c
+ cbs.n++
+
+ return callbackasmAddr(n)
+}
diff --git a/src/pkg/runtime/syscall_windows.goc b/src/pkg/runtime/syscall_windows.goc
index 5282453..a1665c3 100644
--- a/src/pkg/runtime/syscall_windows.goc
+++ b/src/pkg/runtime/syscall_windows.goc
@@ -36,14 +36,6 @@
err = 0;
}
-func NewCallback(fn Eface) (code uintptr) {
- code = (uintptr)runtime·compilecallback(fn, true);
-}
-
-func NewCallbackCDecl(fn Eface) (code uintptr) {
- code = (uintptr)runtime·compilecallback(fn, false);
-}
-
func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
LibCall c;
diff --git a/src/pkg/syscall/asm_windows.s b/src/pkg/syscall/asm_windows.s
new file mode 100644
index 0000000..abb6641
--- /dev/null
+++ b/src/pkg/syscall/asm_windows.s
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for Windows are implemented in ../runtime/syscall_windows.goc
+//
+
+#include "textflag.h"
+
+// func compileCallback(fn interface{}, cleanstack bool) uintptr
+TEXT ·compileCallback(SB),NOSPLIT,$0
+ JMP runtime·compileCallback(SB)
diff --git a/src/pkg/syscall/asm_windows_386.s b/src/pkg/syscall/asm_windows_386.s
deleted file mode 100644
index 8b52fa9..0000000
--- a/src/pkg/syscall/asm_windows_386.s
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//
-// System calls for 386, Windows are implemented in ../runtime/syscall_windows.goc
-//
diff --git a/src/pkg/syscall/asm_windows_amd64.s b/src/pkg/syscall/asm_windows_amd64.s
deleted file mode 100644
index 5813404..0000000
--- a/src/pkg/syscall/asm_windows_amd64.s
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//
-// System calls for amd64, Windows are implemented in ../runtime/syscall_windows.goc
-//
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 32a7aed..bda8214 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -105,12 +105,22 @@
return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
}
+// Implemented in asm_windows.s
+func compileCallback(fn interface{}, cleanstack bool) uintptr
+
// Converts a Go function to a function pointer conforming
-// to the stdcall or cdecl calling convention. This is useful when
+// to the stdcall calling convention. This is useful when
// interoperating with Windows code requiring callbacks.
-// Implemented in ../runtime/syscall_windows.goc
-func NewCallback(fn interface{}) uintptr
-func NewCallbackCDecl(fn interface{}) uintptr
+func NewCallback(fn interface{}) uintptr {
+ return compileCallback(fn, true)
+}
+
+// Converts a Go function to a function pointer conforming
+// to the cdecl calling convention. This is useful when
+// interoperating with Windows code requiring callbacks.
+func NewCallbackCDecl(fn interface{}) uintptr {
+ return compileCallback(fn, false)
+}
// windows api calls