diff options
Diffstat (limited to 'src/pkg/runtime/callback_windows_amd64.c')
-rw-r--r-- | src/pkg/runtime/callback_windows_amd64.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/pkg/runtime/callback_windows_amd64.c b/src/pkg/runtime/callback_windows_amd64.c new file mode 100644 index 000000000..99d7cb9e3 --- /dev/null +++ b/src/pkg/runtime/callback_windows_amd64.c @@ -0,0 +1,104 @@ +// 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 "defs_GOOS_GOARCH.h" +#include "os_GOOS.h" + +// Will keep all callbacks in a linked list, so they don't get garbage collected. +typedef struct Callback Callback; +struct Callback { + Callback* link; + void* gobody; + byte asmbody; +}; + +typedef struct Callbacks Callbacks; +struct Callbacks { + Lock; + Callback* link; + int32 n; +}; + +static Callbacks cbs; + +// Call back from windows dll into go. +byte * +runtime·compilecallback(Eface fn, bool /*cleanstack*/) +{ + FuncType *ft; + Type *t; + int32 argsize, i, n; + byte *p; + Callback *c; + + if(fn.type == nil || fn.type->kind != 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); + } + + // compute size of new fn. + // must match code laid out below. + n = 2+8+1; // MOVQ fn, AX / PUSHQ AX + n += 2+8+1; // MOVQ argsize, AX / PUSHQ AX + n += 2+8; // MOVQ callbackasm, AX + n += 2; // JMP AX + + runtime·lock(&cbs); + for(c = cbs.link; c != nil; c = c->link) { + if(c->gobody == fn.data) { + runtime·unlock(&cbs); + return &c->asmbody; + } + } + if(cbs.n >= 2000) + runtime·throw("too many callback functions"); + c = runtime·mal(sizeof *c + n); + c->gobody = fn.data; + c->link = cbs.link; + cbs.link = c; + cbs.n++; + runtime·unlock(&cbs); + + p = &c->asmbody; + + // MOVQ fn, AX + *p++ = 0x48; + *p++ = 0xb8; + *(uint64*)p = (uint64)fn.data; + p += 8; + // PUSH AX + *p++ = 0x50; + + // MOVQ argsize, AX + *p++ = 0x48; + *p++ = 0xb8; + *(uint64*)p = argsize; + p += 8; + // PUSH AX + *p++ = 0x50; + + // MOVQ callbackasm, AX + *p++ = 0x48; + *p++ = 0xb8; + *(uint64*)p = (uint64)runtime·callbackasm; + p += 8; + + // JMP AX + *p++ = 0xFF; + *p = 0xE0; + + return &c->asmbody; +} |