summaryrefslogtreecommitdiff
path: root/libgo/go/reflect/makefunc_ffi_c.c
blob: d3935eb0b73175b909f96c53662648f6c9f7caf1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// 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.

#include "runtime.h"
#include "go-type.h"
#include "go-panic.h"

#ifdef USE_LIBFFI

#include "ffi.h"

#if FFI_GO_CLOSURES
#define USE_LIBFFI_CLOSURES
#endif

#endif /* defined(USE_LIBFFI) */

/* Declare C functions with the names used to call from Go.  */

void makeFuncFFI(void *cif, void *impl)
  __asm__ (GOSYM_PREFIX "reflect.makeFuncFFI");

#ifdef USE_LIBFFI_CLOSURES

/* The function that we pass to ffi_prep_closure_loc.  This calls the Go
   function ffiCall with the pointer to the arguments, the results area,
   and the closure structure.  */

void FFICallbackGo(void *result, void **args, ffi_go_closure *closure)
  __asm__ (GOSYM_PREFIX "reflect.FFICallbackGo");

static void ffi_callback (ffi_cif *, void *, void **, void *)
  __asm__ ("reflect.ffi_callback");

static void
ffi_callback (ffi_cif* cif __attribute__ ((unused)), void *results,
	      void **args, void *closure)
{
  Location locs[8];
  int n;
  int i;

  /* This function is called from some series of FFI closure functions
     called by a Go function.  We want to see whether the caller of
     the closure functions can recover.  Look up the stack and skip
     the FFI functions.  */
  n = runtime_callers (1, &locs[0], sizeof locs / sizeof locs[0], true);
  for (i = 0; i < n; i++)
    {
      const byte *name;

      if (locs[i].function.len == 0)
	continue;
      if (locs[i].function.len < 4)
	break;
      name = locs[i].function.str;
      if (name[0] != 'f' || name[1] != 'f' || name[2] != 'i' || name[3] != '_')
	break;
    }
  if (i < n)
    __go_makefunc_ffi_can_recover (locs + i, n - i);

  FFICallbackGo(results, args, closure);

  if (i < n)
    __go_makefunc_returning ();
}

/* Allocate an FFI closure and arrange to call ffi_callback.  */

void
makeFuncFFI(void *cif, void *impl)
{
  ffi_prep_go_closure(impl, (ffi_cif*)cif, ffi_callback);
}

#else /* !defined(USE_LIBFFI_CLOSURES) */

void
makeFuncFFI(void *cif __attribute__ ((unused)),
	    void *impl __attribute__ ((unused)))
{
  runtime_panicstring ("libgo built without FFI does not support "
		       "reflect.MakeFunc");
}

#endif