github.com/golang/gofrontend@v0.0.0-20240429183944-60f985a78526/libgo/runtime/go-reflect-call.c (about)

     1  /* go-reflect-call.c -- call reflection support for Go.
     2  
     3     Copyright 2009 The Go Authors. All rights reserved.
     4     Use of this source code is governed by a BSD-style
     5     license that can be found in the LICENSE file.  */
     6  
     7  #include <stdio.h>
     8  #include <stdint.h>
     9  #include <stdlib.h>
    10  
    11  #include "runtime.h"
    12  #include "go-assert.h"
    13  
    14  #ifdef USE_LIBFFI
    15  #include "ffi.h"
    16  #endif
    17  
    18  #if defined(USE_LIBFFI) && FFI_GO_CLOSURES
    19  
    20  /* The functions in this file are only called from reflect_call.  As
    21     reflect_call calls a libffi function, which will be compiled
    22     without -fsplit-stack, it will always run with a large stack.  */
    23  
    24  static size_t go_results_size (const struct functype *)
    25    __attribute__ ((no_split_stack));
    26  static void go_set_results (const struct functype *, unsigned char *, void **)
    27    __attribute__ ((no_split_stack));
    28  
    29  /* Get the total size required for the result parameters of a
    30     function.  */
    31  
    32  static size_t
    33  go_results_size (const struct functype *func)
    34  {
    35    int count;
    36    const struct _type **types;
    37    size_t off;
    38    size_t maxalign;
    39    int i;
    40  
    41    count = func->out.__count;
    42    if (count == 0)
    43      return 0;
    44  
    45    types = (const struct _type **) func->out.__values;
    46  
    47    /* A single integer return value is always promoted to a full word.
    48       There is similar code below and in libgo/go/reflect/makefunc_ffi.go.*/
    49    if (count == 1)
    50      {
    51        switch (types[0]->kind & kindMask)
    52  	{
    53  	case kindBool:
    54  	case kindInt8:
    55  	case kindInt16:
    56  	case kindInt32:
    57  	case kindUint8:
    58  	case kindUint16:
    59  	case kindUint32:
    60  	  return sizeof (ffi_arg);
    61  
    62  	default:
    63  	  break;
    64  	}
    65      }
    66  
    67    off = 0;
    68    maxalign = 0;
    69    for (i = 0; i < count; ++i)
    70      {
    71        size_t align;
    72  
    73        align = types[i]->fieldAlign;
    74        if (align > maxalign)
    75  	maxalign = align;
    76        off = (off + align - 1) & ~ (align - 1);
    77        off += types[i]->size;
    78      }
    79  
    80    off = (off + maxalign - 1) & ~ (maxalign - 1);
    81  
    82    // The libffi library doesn't understand a struct with no fields.
    83    // We generate a struct with a single field of type void.  When used
    84    // as a return value, libffi will think that requires a byte.
    85    if (off == 0)
    86      off = 1;
    87  
    88    return off;
    89  }
    90  
    91  /* Copy the results of calling a function via FFI from CALL_RESULT
    92     into the addresses in RESULTS.  */
    93  
    94  static void
    95  go_set_results (const struct functype *func, unsigned char *call_result,
    96  		void **results)
    97  {
    98    int count;
    99    const struct _type **types;
   100    size_t off;
   101    int i;
   102  
   103    count = func->out.__count;
   104    if (count == 0)
   105      return;
   106  
   107    types = (const struct _type **) func->out.__values;
   108  
   109    /* A single integer return value is always promoted to a full word.
   110       There is similar code above and in libgo/go/reflect/makefunc_ffi.go.*/
   111    if (count == 1)
   112      {
   113        switch (types[0]->kind & kindMask)
   114  	{
   115  	case kindBool:
   116  	case kindInt8:
   117  	case kindInt16:
   118  	case kindInt32:
   119  	case kindUint8:
   120  	case kindUint16:
   121  	case kindUint32:
   122  	  {
   123  	    union
   124  	    {
   125  	      unsigned char buf[sizeof (ffi_arg)];
   126  	      ffi_arg v;
   127  	    } u;
   128  	    ffi_arg v;
   129  
   130  	    __builtin_memcpy (&u.buf, call_result, sizeof (ffi_arg));
   131  	    v = u.v;
   132  
   133  	    switch (types[0]->size)
   134  	      {
   135  	      case 1:
   136  		{
   137  		  uint8_t b;
   138  
   139  		  b = (uint8_t) v;
   140  		  __builtin_memcpy (results[0], &b, 1);
   141  		}
   142  		break;
   143  
   144  	      case 2:
   145  		{
   146  		  uint16_t s;
   147  
   148  		  s = (uint16_t) v;
   149  		  __builtin_memcpy (results[0], &s, 2);
   150  		}
   151  		break;
   152  
   153  	      case 4:
   154  		{
   155  		  uint32_t w;
   156  
   157  		  w = (uint32_t) v;
   158  		  __builtin_memcpy (results[0], &w, 4);
   159  		}
   160  		break;
   161  
   162  	      case 8:
   163  		{
   164  		  uint64_t d;
   165  
   166  		  d = (uint64_t) v;
   167  		  __builtin_memcpy (results[0], &d, 8);
   168  		}
   169  		break;
   170  
   171  	      default:
   172  		abort ();
   173  	      }
   174  	  }
   175  	  return;
   176  
   177  	default:
   178  	  break;
   179  	}
   180      }
   181  
   182    off = 0;
   183    for (i = 0; i < count; ++i)
   184      {
   185        size_t align;
   186        size_t size;
   187  
   188        align = types[i]->fieldAlign;
   189        size = types[i]->size;
   190        off = (off + align - 1) & ~ (align - 1);
   191        __builtin_memcpy (results[i], call_result + off, size);
   192        off += size;
   193      }
   194  }
   195  
   196  /* The code that converts the Go type to an FFI type is written in Go,
   197     so that it can allocate Go heap memory.  */
   198  extern void ffiFuncToCIF(const struct functype*, _Bool, _Bool, ffi_cif*)
   199    __asm__ ("runtime.ffiFuncToCIF");
   200  
   201  /* Call a function.  The type of the function is FUNC_TYPE, and the
   202     closure is FUNC_VAL.  PARAMS is an array of parameter addresses.
   203     RESULTS is an array of result addresses.
   204  
   205     If IS_INTERFACE is true this is a call to an interface method and
   206     the first argument is the receiver, which is always a pointer.
   207     This argument, the receiver, is not described in FUNC_TYPE.
   208  
   209     If IS_METHOD is true this is a call to a method expression.  The
   210     first argument is the receiver.  It is described in FUNC_TYPE, but
   211     regardless of FUNC_TYPE, it is passed as a pointer.  */
   212  
   213  void
   214  reflect_call (const struct functype *func_type, FuncVal *func_val,
   215  	      _Bool is_interface, _Bool is_method, void **params,
   216  	      void **results)
   217  {
   218    ffi_cif cif;
   219    unsigned char *call_result;
   220  
   221    __go_assert ((func_type->typ.kind & kindMask) == kindFunc);
   222    ffiFuncToCIF (func_type, is_interface, is_method, &cif);
   223  
   224    call_result = (unsigned char *) malloc (go_results_size (func_type));
   225  
   226    ffi_call_go (&cif, (void (*)(void)) func_val->fn, call_result, params,
   227  	       func_val);
   228  
   229    /* Some day we may need to free result values if RESULTS is
   230       NULL.  */
   231    if (results != NULL)
   232      go_set_results (func_type, call_result, results);
   233  
   234    free (call_result);
   235  }
   236  
   237  #else /* !defined(USE_LIBFFI) */
   238  
   239  void
   240  reflect_call (const struct functype *func_type __attribute__ ((unused)),
   241  	      FuncVal *func_val __attribute__ ((unused)),
   242  	      _Bool is_interface __attribute__ ((unused)),
   243  	      _Bool is_method __attribute__ ((unused)),
   244  	      void **params __attribute__ ((unused)),
   245  	      void **results __attribute__ ((unused)))
   246  {
   247    /* Without FFI there is nothing we can do.  */
   248    runtime_throw("libgo built without FFI does not support "
   249  		"reflect.Call or runtime.SetFinalizer");
   250  }
   251  
   252  #endif /* !defined(USE_LIBFFI) */