mirror of
https://github.com/golang/go
synced 2024-11-26 20:11:26 -07:00
runtime: do not generate code during runtime in windows NewCallback
Update #5494 R=golang-dev, minux.ma, rsc, iant CC=golang-dev https://golang.org/cl/10368043
This commit is contained in:
parent
ecdbcaf449
commit
05a5de30f0
1
src/cmd/dist/a.h
vendored
1
src/cmd/dist/a.h
vendored
@ -94,6 +94,7 @@ void mkenam(char*, char*);
|
|||||||
|
|
||||||
// buildruntime.c
|
// buildruntime.c
|
||||||
void mkzasm(char*, char*);
|
void mkzasm(char*, char*);
|
||||||
|
void mkzsys(char*, char*);
|
||||||
void mkzgoarch(char*, char*);
|
void mkzgoarch(char*, char*);
|
||||||
void mkzgoos(char*, char*);
|
void mkzgoos(char*, char*);
|
||||||
void mkzruntimedefs(char*, char*);
|
void mkzruntimedefs(char*, char*);
|
||||||
|
2
src/cmd/dist/build.c
vendored
2
src/cmd/dist/build.c
vendored
@ -528,6 +528,7 @@ static struct {
|
|||||||
}},
|
}},
|
||||||
{"pkg/runtime", {
|
{"pkg/runtime", {
|
||||||
"zasm_$GOOS_$GOARCH.h",
|
"zasm_$GOOS_$GOARCH.h",
|
||||||
|
"zsys_$GOOS_$GOARCH.s",
|
||||||
"zgoarch_$GOARCH.go",
|
"zgoarch_$GOARCH.go",
|
||||||
"zgoos_$GOOS.go",
|
"zgoos_$GOOS.go",
|
||||||
"zruntime_defs_$GOOS_$GOARCH.go",
|
"zruntime_defs_$GOOS_$GOARCH.go",
|
||||||
@ -552,6 +553,7 @@ static struct {
|
|||||||
{"opnames.h", gcopnames},
|
{"opnames.h", gcopnames},
|
||||||
{"enam.c", mkenam},
|
{"enam.c", mkenam},
|
||||||
{"zasm_", mkzasm},
|
{"zasm_", mkzasm},
|
||||||
|
{"zsys_", mkzsys},
|
||||||
{"zgoarch_", mkzgoarch},
|
{"zgoarch_", mkzgoarch},
|
||||||
{"zgoos_", mkzgoos},
|
{"zgoos_", mkzgoos},
|
||||||
{"zruntime_defs_", mkzruntimedefs},
|
{"zruntime_defs_", mkzruntimedefs},
|
||||||
|
44
src/cmd/dist/buildruntime.c
vendored
44
src/cmd/dist/buildruntime.c
vendored
@ -178,6 +178,8 @@ static struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAXWINCB 2000 /* maximum number of windows callbacks allowed */
|
||||||
|
|
||||||
// mkzasm writes zasm_$GOOS_$GOARCH.h,
|
// mkzasm writes zasm_$GOOS_$GOARCH.h,
|
||||||
// which contains struct offsets for use by
|
// which contains struct offsets for use by
|
||||||
// assembly files. It also writes a copy to the work space
|
// assembly files. It also writes a copy to the work space
|
||||||
@ -249,6 +251,8 @@ ok:
|
|||||||
aggr = "gobuf";
|
aggr = "gobuf";
|
||||||
else if(streq(fields.p[1], "WinCall"))
|
else if(streq(fields.p[1], "WinCall"))
|
||||||
aggr = "wincall";
|
aggr = "wincall";
|
||||||
|
else if(streq(fields.p[1], "WinCallbackContext"))
|
||||||
|
aggr = "cbctxt";
|
||||||
else if(streq(fields.p[1], "SEH"))
|
else if(streq(fields.p[1], "SEH"))
|
||||||
aggr = "seh";
|
aggr = "seh";
|
||||||
}
|
}
|
||||||
@ -263,6 +267,11 @@ ok:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some #defines that are used for .c files.
|
||||||
|
if(streq(goos, "windows")) {
|
||||||
|
bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB));
|
||||||
|
}
|
||||||
|
|
||||||
// Write both to file and to workdir/zasm_GOOS_GOARCH.h.
|
// Write both to file and to workdir/zasm_GOOS_GOARCH.h.
|
||||||
writefile(&out, file, 0);
|
writefile(&out, file, 0);
|
||||||
writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0);
|
writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0);
|
||||||
@ -275,6 +284,41 @@ ok:
|
|||||||
vfree(&fields);
|
vfree(&fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mkzsys writes zsys_$GOOS_$GOARCH.h,
|
||||||
|
// which contains arch or os specific asm code.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
mkzsys(char *dir, char *file)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Buf out;
|
||||||
|
|
||||||
|
USED(dir);
|
||||||
|
|
||||||
|
binit(&out);
|
||||||
|
|
||||||
|
bwritestr(&out, "// auto generated by go tool dist\n\n");
|
||||||
|
if(streq(goos, "windows")) {
|
||||||
|
bwritef(&out,
|
||||||
|
"// runtime·callbackasm is called by external code to\n"
|
||||||
|
"// execute Go implemented callback function. It is not\n"
|
||||||
|
"// called from the start, instead runtime·compilecallback\n"
|
||||||
|
"// always returns address into runtime·callbackasm offset\n"
|
||||||
|
"// appropriately so different callbacks start with different\n"
|
||||||
|
"// CALL instruction in runtime·callbackasm. This determines\n"
|
||||||
|
"// which Go callback function is executed later on.\n"
|
||||||
|
"TEXT runtime·callbackasm(SB),7,$0\n");
|
||||||
|
for(i=0; i<MAXWINCB; i++) {
|
||||||
|
bwritef(&out, "\tCALL\truntime·callbackasm1(SB)\n");
|
||||||
|
}
|
||||||
|
bwritef(&out, "\tRET\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
writefile(&out, file, 0);
|
||||||
|
|
||||||
|
bfree(&out);
|
||||||
|
}
|
||||||
|
|
||||||
static char *runtimedefs[] = {
|
static char *runtimedefs[] = {
|
||||||
"proc.c",
|
"proc.c",
|
||||||
"iface.c",
|
"iface.c",
|
||||||
|
@ -7,24 +7,19 @@
|
|||||||
#include "typekind.h"
|
#include "typekind.h"
|
||||||
#include "defs_GOOS_GOARCH.h"
|
#include "defs_GOOS_GOARCH.h"
|
||||||
#include "os_GOOS.h"
|
#include "os_GOOS.h"
|
||||||
|
#include "zasm_GOOS_GOARCH.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;
|
typedef struct Callbacks Callbacks;
|
||||||
struct Callbacks {
|
struct Callbacks {
|
||||||
Lock;
|
Lock;
|
||||||
Callback* link;
|
WinCallbackContext* ctxt[cb_max];
|
||||||
int32 n;
|
int32 n;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Callbacks cbs;
|
static Callbacks cbs;
|
||||||
|
|
||||||
|
WinCallbackContext** runtime·cbctxts; // to simplify access to cbs.ctxt in sys_windows_*.s
|
||||||
|
|
||||||
// Call back from windows dll into go.
|
// Call back from windows dll into go.
|
||||||
byte *
|
byte *
|
||||||
runtime·compilecallback(Eface fn, bool cleanstack)
|
runtime·compilecallback(Eface fn, bool cleanstack)
|
||||||
@ -32,8 +27,7 @@ runtime·compilecallback(Eface fn, bool cleanstack)
|
|||||||
FuncType *ft;
|
FuncType *ft;
|
||||||
Type *t;
|
Type *t;
|
||||||
int32 argsize, i, n;
|
int32 argsize, i, n;
|
||||||
byte *p;
|
WinCallbackContext *c;
|
||||||
Callback *c;
|
|
||||||
|
|
||||||
if(fn.type == nil || fn.type->kind != KindFunc)
|
if(fn.type == nil || fn.type->kind != KindFunc)
|
||||||
runtime·panicstring("compilecallback: not a function");
|
runtime·panicstring("compilecallback: not a function");
|
||||||
@ -50,59 +44,33 @@ runtime·compilecallback(Eface fn, bool cleanstack)
|
|||||||
argsize += sizeof(uintptr);
|
argsize += sizeof(uintptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute size of new fn.
|
|
||||||
// must match code laid out below.
|
|
||||||
n = 1+4; // MOVL fn, AX
|
|
||||||
n += 1+4; // MOVL argsize, DX
|
|
||||||
n += 1+4; // MOVL callbackasm, CX
|
|
||||||
n += 2; // CALL CX
|
|
||||||
n += 1; // RET
|
|
||||||
if(cleanstack && argsize!=0)
|
|
||||||
n += 2; // ... argsize
|
|
||||||
|
|
||||||
runtime·lock(&cbs);
|
runtime·lock(&cbs);
|
||||||
for(c = cbs.link; c != nil; c = c->link) {
|
if(runtime·cbctxts == nil)
|
||||||
if(c->gobody == fn.data) {
|
runtime·cbctxts = &(cbs.ctxt[0]);
|
||||||
|
n = cbs.n;
|
||||||
|
for(i=0; i<n; i++) {
|
||||||
|
if(cbs.ctxt[i]->gobody == fn.data) {
|
||||||
runtime·unlock(&cbs);
|
runtime·unlock(&cbs);
|
||||||
return &c->asmbody;
|
// 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(cbs.n >= 2000)
|
if(n >= cb_max)
|
||||||
runtime·throw("too many callback functions");
|
runtime·throw("too many callback functions");
|
||||||
c = runtime·mal(sizeof *c + n);
|
c = runtime·mal(sizeof *c);
|
||||||
c->gobody = fn.data;
|
c->gobody = fn.data;
|
||||||
c->link = cbs.link;
|
c->argsize = argsize;
|
||||||
cbs.link = c;
|
if(cleanstack && argsize!=0)
|
||||||
|
c->restorestack = argsize;
|
||||||
|
else
|
||||||
|
c->restorestack = 0;
|
||||||
|
cbs.ctxt[n] = c;
|
||||||
cbs.n++;
|
cbs.n++;
|
||||||
runtime·unlock(&cbs);
|
runtime·unlock(&cbs);
|
||||||
|
|
||||||
p = &c->asmbody;
|
// as before
|
||||||
|
return (byte*)runtime·callbackasm + n * 5;
|
||||||
// MOVL fn, AX
|
|
||||||
*p++ = 0xb8;
|
|
||||||
*(uint32*)p = (uint32)(fn.data);
|
|
||||||
p += 4;
|
|
||||||
|
|
||||||
// MOVL argsize, DX
|
|
||||||
*p++ = 0xba;
|
|
||||||
*(uint32*)p = argsize;
|
|
||||||
p += 4;
|
|
||||||
|
|
||||||
// MOVL callbackasm, CX
|
|
||||||
*p++ = 0xb9;
|
|
||||||
*(uint32*)p = (uint32)runtime·callbackasm;
|
|
||||||
p += 4;
|
|
||||||
|
|
||||||
// CALL CX
|
|
||||||
*p++ = 0xff;
|
|
||||||
*p++ = 0xd1;
|
|
||||||
|
|
||||||
// RET argsize?
|
|
||||||
if(cleanstack && argsize!=0) {
|
|
||||||
*p++ = 0xc2;
|
|
||||||
*(uint16*)p = argsize;
|
|
||||||
} else
|
|
||||||
*p = 0xc3;
|
|
||||||
|
|
||||||
return &c->asmbody;
|
|
||||||
}
|
}
|
@ -1,105 +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"
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
@ -78,6 +78,7 @@ typedef struct Complex64 Complex64;
|
|||||||
typedef struct Complex128 Complex128;
|
typedef struct Complex128 Complex128;
|
||||||
typedef struct WinCall WinCall;
|
typedef struct WinCall WinCall;
|
||||||
typedef struct SEH SEH;
|
typedef struct SEH SEH;
|
||||||
|
typedef struct WinCallbackContext WinCallbackContext;
|
||||||
typedef struct Timers Timers;
|
typedef struct Timers Timers;
|
||||||
typedef struct Timer Timer;
|
typedef struct Timer Timer;
|
||||||
typedef struct GCStats GCStats;
|
typedef struct GCStats GCStats;
|
||||||
@ -444,6 +445,13 @@ struct SEH
|
|||||||
void* prev;
|
void* prev;
|
||||||
void* handler;
|
void* handler;
|
||||||
};
|
};
|
||||||
|
// describes how to handle callback
|
||||||
|
struct WinCallbackContext
|
||||||
|
{
|
||||||
|
void* gobody; // Go function to call
|
||||||
|
uintptr argsize; // callback arguments size (in bytes)
|
||||||
|
uintptr restorestack; // adjust stack on return by (in bytes) (386 only)
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef GOOS_windows
|
#ifdef GOOS_windows
|
||||||
enum {
|
enum {
|
||||||
|
@ -164,19 +164,16 @@ TEXT runtime·externalthreadhandler(SB),7,$0
|
|||||||
POPL BP
|
POPL BP
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// Called from dynamic function created by ../thread.c compilecallback,
|
GLOBL runtime·cbctxts(SB), $4
|
||||||
// running on Windows stack (not Go stack).
|
|
||||||
// BX, BP, SI, DI registers and DF flag are preserved
|
TEXT runtime·callbackasm1+0(SB),7,$0
|
||||||
// as required by windows callback convention.
|
MOVL 0(SP), AX // will use to find our callback context
|
||||||
// AX = address of go func we need to call
|
|
||||||
// DX = total size of arguments
|
// remove return address from stack, we are not returning there
|
||||||
//
|
ADDL $4, SP
|
||||||
TEXT runtime·callbackasm+0(SB),7,$0
|
|
||||||
// preserve whatever's at the memory location that
|
// address to callback parameters into CX
|
||||||
// the callback will use to store the return value
|
LEAL 4(SP), CX
|
||||||
LEAL 8(SP), CX
|
|
||||||
PUSHL 0(CX)(DX*1)
|
|
||||||
ADDL $4, DX // extend argsize by size of return value
|
|
||||||
|
|
||||||
// save registers as required for windows callback
|
// save registers as required for windows callback
|
||||||
PUSHL DI
|
PUSHL DI
|
||||||
@ -189,19 +186,51 @@ TEXT runtime·callbackasm+0(SB),7,$0
|
|||||||
PUSHL 0(FS)
|
PUSHL 0(FS)
|
||||||
MOVL SP, 0(FS)
|
MOVL SP, 0(FS)
|
||||||
|
|
||||||
// callback parameters
|
// determine index into runtime·cbctxts table
|
||||||
PUSHL DX
|
SUBL $runtime·callbackasm(SB), AX
|
||||||
PUSHL CX
|
MOVL $0, DX
|
||||||
PUSHL AX
|
MOVL $5, BX // divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
|
||||||
|
DIVL BX,
|
||||||
|
|
||||||
|
// find correspondent runtime·cbctxts table entry
|
||||||
|
MOVL runtime·cbctxts(SB), BX
|
||||||
|
MOVL -4(BX)(AX*4), BX
|
||||||
|
|
||||||
|
// extract callback context
|
||||||
|
MOVL cbctxt_gobody(BX), AX
|
||||||
|
MOVL cbctxt_argsize(BX), DX
|
||||||
|
|
||||||
|
// preserve whatever's at the memory location that
|
||||||
|
// the callback will use to store the return value
|
||||||
|
PUSHL 0(CX)(DX*1)
|
||||||
|
|
||||||
|
// extend argsize by size of return value
|
||||||
|
ADDL $4, DX
|
||||||
|
|
||||||
|
// remember how to restore stack on return
|
||||||
|
MOVL cbctxt_restorestack(BX), BX
|
||||||
|
PUSHL BX
|
||||||
|
|
||||||
|
// call target Go function
|
||||||
|
PUSHL DX // argsize (including return value)
|
||||||
|
PUSHL CX // callback parameters
|
||||||
|
PUSHL AX // address of target Go function
|
||||||
CLD
|
CLD
|
||||||
|
|
||||||
CALL runtime·cgocallback_gofunc(SB)
|
CALL runtime·cgocallback_gofunc(SB)
|
||||||
|
|
||||||
POPL AX
|
POPL AX
|
||||||
POPL CX
|
POPL CX
|
||||||
POPL DX
|
POPL DX
|
||||||
|
|
||||||
|
// how to restore stack on return
|
||||||
|
POPL BX
|
||||||
|
|
||||||
|
// return value into AX (as per Windows spec)
|
||||||
|
// and restore previously preserved value
|
||||||
|
MOVL -4(CX)(DX*1), AX
|
||||||
|
POPL -4(CX)(DX*1)
|
||||||
|
|
||||||
|
MOVL BX, CX // cannot use BX anymore
|
||||||
|
|
||||||
// pop SEH frame
|
// pop SEH frame
|
||||||
POPL 0(FS)
|
POPL 0(FS)
|
||||||
POPL BX
|
POPL BX
|
||||||
@ -212,10 +241,13 @@ TEXT runtime·callbackasm+0(SB),7,$0
|
|||||||
POPL SI
|
POPL SI
|
||||||
POPL DI
|
POPL DI
|
||||||
|
|
||||||
|
// remove callback parameters before return (as per Windows spec)
|
||||||
|
POPL DX
|
||||||
|
ADDL CX, SP
|
||||||
|
PUSHL DX
|
||||||
|
|
||||||
CLD
|
CLD
|
||||||
|
|
||||||
MOVL -4(CX)(DX*1), AX
|
|
||||||
POPL -4(CX)(DX*1)
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// void tstart(M *newm);
|
// void tstart(M *newm);
|
||||||
|
@ -196,32 +196,37 @@ TEXT runtime·externalthreadhandler(SB),7,$0
|
|||||||
POPQ BP
|
POPQ BP
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// Continuation of thunk function created for each callback by ../thread.c compilecallback,
|
GLOBL runtime·cbctxts(SB), $8
|
||||||
// runs on Windows stack (not Go stack).
|
|
||||||
// Thunk code designed to have minimal size for it is copied many (up to thousands) times.
|
TEXT runtime·callbackasm1(SB),7,$0
|
||||||
//
|
|
||||||
// thunk:
|
|
||||||
// MOVQ $fn, AX
|
|
||||||
// PUSHQ AX
|
|
||||||
// MOVQ $argsize, AX
|
|
||||||
// PUSHQ AX
|
|
||||||
// MOVQ $runtime·callbackasm, AX
|
|
||||||
// JMP AX
|
|
||||||
TEXT runtime·callbackasm(SB),7,$0
|
|
||||||
// Construct args vector for cgocallback().
|
// Construct args vector for cgocallback().
|
||||||
// By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9
|
// By windows/amd64 calling convention first 4 args are in CX, DX, R8, R9
|
||||||
// args from the 5th on are on the stack.
|
// args from the 5th on are on the stack.
|
||||||
// In any case, even if function has 0,1,2,3,4 args, there is reserved
|
// In any case, even if function has 0,1,2,3,4 args, there is reserved
|
||||||
// but uninitialized "shadow space" for the first 4 args.
|
// but uninitialized "shadow space" for the first 4 args.
|
||||||
// The values are in registers.
|
// The values are in registers.
|
||||||
MOVQ CX, (24+0)(SP)
|
MOVQ CX, (16+0)(SP)
|
||||||
MOVQ DX, (24+8)(SP)
|
MOVQ DX, (16+8)(SP)
|
||||||
MOVQ R8, (24+16)(SP)
|
MOVQ R8, (16+16)(SP)
|
||||||
MOVQ R9, (24+24)(SP)
|
MOVQ R9, (16+24)(SP)
|
||||||
// 6l does not accept writing POPQs here issuing a warning "unbalanced PUSH/POP"
|
|
||||||
MOVQ 0(SP), DX // POPQ DX
|
// remove return address from stack, we are not returning there
|
||||||
MOVQ 8(SP), AX // POPQ AX
|
MOVQ 0(SP), AX
|
||||||
ADDQ $16, SP
|
ADDQ $8, SP
|
||||||
|
|
||||||
|
// determine index into runtime·cbctxts table
|
||||||
|
SUBQ $runtime·callbackasm(SB), AX
|
||||||
|
MOVQ $0, DX
|
||||||
|
MOVQ $5, CX // divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
|
||||||
|
DIVL CX,
|
||||||
|
|
||||||
|
// find correspondent runtime·cbctxts table entry
|
||||||
|
MOVQ runtime·cbctxts(SB), CX
|
||||||
|
MOVQ -8(CX)(AX*8), AX
|
||||||
|
|
||||||
|
// extract callback context
|
||||||
|
MOVQ cbctxt_argsize(AX), DX
|
||||||
|
MOVQ cbctxt_gobody(AX), AX
|
||||||
|
|
||||||
// preserve whatever's at the memory location that
|
// preserve whatever's at the memory location that
|
||||||
// the callback will use to store the return value
|
// the callback will use to store the return value
|
||||||
@ -231,8 +236,6 @@ TEXT runtime·callbackasm(SB),7,$0
|
|||||||
|
|
||||||
// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
|
// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
|
||||||
// as required by windows callback convention.
|
// as required by windows callback convention.
|
||||||
// 6l does not allow writing many PUSHQs here issuing a warning "nosplit stack overflow"
|
|
||||||
// the warning has no sense as this code uses os thread stack
|
|
||||||
PUSHFQ
|
PUSHFQ
|
||||||
SUBQ $64, SP
|
SUBQ $64, SP
|
||||||
MOVQ DI, 56(SP)
|
MOVQ DI, 56(SP)
|
||||||
@ -247,9 +250,9 @@ TEXT runtime·callbackasm(SB),7,$0
|
|||||||
// prepare call stack. use SUBQ to hide from stack frame checks
|
// prepare call stack. use SUBQ to hide from stack frame checks
|
||||||
// cgocallback(Go func, void *frame, uintptr framesize)
|
// cgocallback(Go func, void *frame, uintptr framesize)
|
||||||
SUBQ $24, SP
|
SUBQ $24, SP
|
||||||
MOVQ DX, 16(SP) // uintptr framesize
|
MOVQ DX, 16(SP) // argsize (including return value)
|
||||||
MOVQ CX, 8(SP) // void *frame
|
MOVQ CX, 8(SP) // callback parameters
|
||||||
MOVQ AX, 0(SP) // Go func
|
MOVQ AX, 0(SP) // address of target Go function
|
||||||
CLD
|
CLD
|
||||||
CALL runtime·cgocallback_gofunc(SB)
|
CALL runtime·cgocallback_gofunc(SB)
|
||||||
MOVQ 0(SP), AX
|
MOVQ 0(SP), AX
|
||||||
@ -258,7 +261,6 @@ TEXT runtime·callbackasm(SB),7,$0
|
|||||||
ADDQ $24, SP
|
ADDQ $24, SP
|
||||||
|
|
||||||
// restore registers as required for windows callback
|
// restore registers as required for windows callback
|
||||||
// 6l does not allow writing many POPs here issuing a warning "nosplit stack overflow"
|
|
||||||
MOVQ 0(SP), R15
|
MOVQ 0(SP), R15
|
||||||
MOVQ 8(SP), R14
|
MOVQ 8(SP), R14
|
||||||
MOVQ 16(SP), R13
|
MOVQ 16(SP), R13
|
||||||
|
Loading…
Reference in New Issue
Block a user