OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [runtime/] [go-reflect-call.c] - Rev 818

Go to most recent revision | Compare with Previous | Blame | View Log

/* go-reflect-call.c -- call reflection support for Go.
 
   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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>
 
#include "config.h"
 
#include "go-alloc.h"
#include "go-assert.h"
#include "go-type.h"
#include "runtime.h"
 
#ifdef USE_LIBFFI
 
#include "ffi.h"
 
/* The functions in this file are only called from reflect_call.  As
   reflect_call calls a libffi function, which will be compiled
   without -fsplit-stack, it will always run with a large stack.  */
 
static ffi_type *go_array_to_ffi (const struct __go_array_type *)
  __attribute__ ((no_split_stack));
static ffi_type *go_slice_to_ffi (const struct __go_slice_type *)
  __attribute__ ((no_split_stack));
static ffi_type *go_struct_to_ffi (const struct __go_struct_type *)
  __attribute__ ((no_split_stack));
static ffi_type *go_string_to_ffi (void) __attribute__ ((no_split_stack));
static ffi_type *go_interface_to_ffi (void) __attribute__ ((no_split_stack));
static ffi_type *go_complex_to_ffi (ffi_type *)
  __attribute__ ((no_split_stack));
static ffi_type *go_type_to_ffi (const struct __go_type_descriptor *)
  __attribute__ ((no_split_stack));
static ffi_type *go_func_return_ffi (const struct __go_func_type *)
  __attribute__ ((no_split_stack));
static void go_func_to_cif (const struct __go_func_type *, _Bool, _Bool,
			    ffi_cif *)
  __attribute__ ((no_split_stack));
static size_t go_results_size (const struct __go_func_type *)
  __attribute__ ((no_split_stack));
static void go_set_results (const struct __go_func_type *, unsigned char *,
			    void **)
  __attribute__ ((no_split_stack));
 
/* Return an ffi_type for a Go array type.  The libffi library does
   not have any builtin support for passing arrays as values.  We work
   around this by pretending that the array is a struct.  */
 
static ffi_type *
go_array_to_ffi (const struct __go_array_type *descriptor)
{
  ffi_type *ret;
  uintptr_t len;
  ffi_type *element;
  uintptr_t i;
 
  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
  ret->type = FFI_TYPE_STRUCT;
  len = descriptor->__len;
  ret->elements = (ffi_type **) __go_alloc ((len + 1) * sizeof (ffi_type *));
  element = go_type_to_ffi (descriptor->__element_type);
  for (i = 0; i < len; ++i)
    ret->elements[i] = element;
  ret->elements[len] = NULL;
  return ret;
}
 
/* Return an ffi_type for a Go slice type.  This describes the
   __go_open_array type defines in array.h.  */
 
static ffi_type *
go_slice_to_ffi (
    const struct __go_slice_type *descriptor __attribute__ ((unused)))
{
  ffi_type *ret;
 
  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
  ret->type = FFI_TYPE_STRUCT;
  ret->elements = (ffi_type **) __go_alloc (4 * sizeof (ffi_type *));
  ret->elements[0] = &ffi_type_pointer;
  ret->elements[1] = &ffi_type_sint;
  ret->elements[2] = &ffi_type_sint;
  ret->elements[3] = NULL;
  return ret;
}
 
/* Return an ffi_type for a Go struct type.  */
 
static ffi_type *
go_struct_to_ffi (const struct __go_struct_type *descriptor)
{
  ffi_type *ret;
  int field_count;
  const struct __go_struct_field *fields;
  int i;
 
  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
  ret->type = FFI_TYPE_STRUCT;
  field_count = descriptor->__fields.__count;
  fields = (const struct __go_struct_field *) descriptor->__fields.__values;
  ret->elements = (ffi_type **) __go_alloc ((field_count + 1)
					    * sizeof (ffi_type *));
  for (i = 0; i < field_count; ++i)
    ret->elements[i] = go_type_to_ffi (fields[i].__type);
  ret->elements[field_count] = NULL;
  return ret;
}
 
/* Return an ffi_type for a Go string type.  This describes the
   __go_string struct.  */
 
static ffi_type *
go_string_to_ffi (void)
{
  ffi_type *ret;
 
  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
  ret->type = FFI_TYPE_STRUCT;
  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
  ret->elements[0] = &ffi_type_pointer;
  ret->elements[1] = &ffi_type_sint;
  ret->elements[2] = NULL;
  return ret;
}
 
/* Return an ffi_type for a Go interface type.  This describes the
   __go_interface and __go_empty_interface structs.  */
 
static ffi_type *
go_interface_to_ffi (void)
{
  ffi_type *ret;
 
  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
  ret->type = FFI_TYPE_STRUCT;
  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
  ret->elements[0] = &ffi_type_pointer;
  ret->elements[1] = &ffi_type_pointer;
  ret->elements[2] = NULL;
  return ret;
}
 
/* Return an ffi_type for a Go complex type.  */
 
static ffi_type *
go_complex_to_ffi (ffi_type *float_type)
{
  ffi_type *ret;
 
  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
  ret->type = FFI_TYPE_STRUCT;
  ret->elements = (ffi_type **) __go_alloc (3 * sizeof (ffi_type *));
  ret->elements[0] = float_type;
  ret->elements[1] = float_type;
  ret->elements[2] = NULL;
  return ret;
}
 
/* Return an ffi_type for a type described by a
   __go_type_descriptor.  */
 
static ffi_type *
go_type_to_ffi (const struct __go_type_descriptor *descriptor)
{
  switch (descriptor->__code & GO_CODE_MASK)
    {
    case GO_BOOL:
      if (sizeof (_Bool) == 1)
	return &ffi_type_uint8;
      else if (sizeof (_Bool) == sizeof (int))
	return &ffi_type_uint;
      abort ();
    case GO_FLOAT32:
      if (sizeof (float) == 4)
	return &ffi_type_float;
      abort ();
    case GO_FLOAT64:
      if (sizeof (double) == 8)
	return &ffi_type_double;
      abort ();
    case GO_COMPLEX64:
      if (sizeof (float) == 4)
	return go_complex_to_ffi (&ffi_type_float);
      abort ();
    case GO_COMPLEX128:
      if (sizeof (double) == 8)
	return go_complex_to_ffi (&ffi_type_double);
      abort ();
    case GO_INT16:
      return &ffi_type_sint16;
    case GO_INT32:
      return &ffi_type_sint32;
    case GO_INT64:
      return &ffi_type_sint64;
    case GO_INT8:
      return &ffi_type_sint8;
    case GO_INT:
      return &ffi_type_sint;
    case GO_UINT16:
      return &ffi_type_uint16;
    case GO_UINT32:
      return &ffi_type_uint32;
    case GO_UINT64:
      return &ffi_type_uint64;
    case GO_UINT8:
      return &ffi_type_uint8;
    case GO_UINT:
      return &ffi_type_uint;
    case GO_UINTPTR:
      if (sizeof (void *) == 2)
	return &ffi_type_uint16;
      else if (sizeof (void *) == 4)
	return &ffi_type_uint32;
      else if (sizeof (void *) == 8)
	return &ffi_type_uint64;
      abort ();
    case GO_ARRAY:
      return go_array_to_ffi ((const struct __go_array_type *) descriptor);
    case GO_SLICE:
      return go_slice_to_ffi ((const struct __go_slice_type *) descriptor);
    case GO_STRUCT:
      return go_struct_to_ffi ((const struct __go_struct_type *) descriptor);
    case GO_STRING:
      return go_string_to_ffi ();
    case GO_INTERFACE:
      return go_interface_to_ffi ();
    case GO_CHAN:
    case GO_FUNC:
    case GO_MAP:
    case GO_PTR:
    case GO_UNSAFE_POINTER:
      /* These types are always pointers, and for FFI purposes nothing
	 else matters.  */
      return &ffi_type_pointer;
    default:
      abort ();
    }
}
 
/* Return the return type for a function, given the number of out
   parameters and their types.  */
 
static ffi_type *
go_func_return_ffi (const struct __go_func_type *func)
{
  int count;
  const struct __go_type_descriptor **types;
  ffi_type *ret;
  int i;
 
  count = func->__out.__count;
  if (count == 0)
    return &ffi_type_void;
 
  types = (const struct __go_type_descriptor **) func->__out.__values;
 
  if (count == 1)
    return go_type_to_ffi (types[0]);
 
  ret = (ffi_type *) __go_alloc (sizeof (ffi_type));
  ret->type = FFI_TYPE_STRUCT;
  ret->elements = (ffi_type **) __go_alloc ((count + 1) * sizeof (ffi_type *));
  for (i = 0; i < count; ++i)
    ret->elements[i] = go_type_to_ffi (types[i]);
  ret->elements[count] = NULL;
  return ret;
}
 
/* Build an ffi_cif structure for a function described by a
   __go_func_type structure.  */
 
static void
go_func_to_cif (const struct __go_func_type *func, _Bool is_interface,
		_Bool is_method, ffi_cif *cif)
{
  int num_params;
  const struct __go_type_descriptor **in_types;
  size_t num_args;
  ffi_type **args;
  int off;
  int i;
  ffi_type *rettype;
  ffi_status status;
 
  num_params = func->__in.__count;
  in_types = ((const struct __go_type_descriptor **)
	      func->__in.__values);
 
  num_args = num_params + (is_interface ? 1 : 0);
  args = (ffi_type **) __go_alloc (num_args * sizeof (ffi_type *));
  i = 0;
  off = 0;
  if (is_interface)
    {
      args[0] = &ffi_type_pointer;
      off = 1;
    }
  else if (is_method)
    {
      args[0] = &ffi_type_pointer;
      i = 1;
    }
  for (; i < num_params; ++i)
    args[i + off] = go_type_to_ffi (in_types[i]);
 
  rettype = go_func_return_ffi (func);
 
  status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, num_args, rettype, args);
  __go_assert (status == FFI_OK);
}
 
/* Get the total size required for the result parameters of a
   function.  */
 
static size_t
go_results_size (const struct __go_func_type *func)
{
  int count;
  const struct __go_type_descriptor **types;
  size_t off;
  size_t maxalign;
  int i;
 
  count = func->__out.__count;
  if (count == 0)
    return 0;
 
  types = (const struct __go_type_descriptor **) func->__out.__values;
 
  /* A single integer return value is always promoted to a full
     word.  */
  if (count == 1)
    {
      switch (types[0]->__code & GO_CODE_MASK)
	{
	case GO_BOOL:
	case GO_INT8:
	case GO_INT16:
	case GO_INT32:
	case GO_UINT8:
	case GO_UINT16:
	case GO_UINT32:
	case GO_INT:
	case GO_UINT:
	  return sizeof (ffi_arg);
 
	default:
	  break;
	}
    }
 
  off = 0;
  maxalign = 0;
  for (i = 0; i < count; ++i)
    {
      size_t align;
 
      align = types[i]->__field_align;
      if (align > maxalign)
	maxalign = align;
      off = (off + align - 1) & ~ (align - 1);
      off += types[i]->__size;
    }
 
  off = (off + maxalign - 1) & ~ (maxalign - 1);
 
  return off;
}
 
/* Copy the results of calling a function via FFI from CALL_RESULT
   into the addresses in RESULTS.  */
 
static void
go_set_results (const struct __go_func_type *func, unsigned char *call_result,
		void **results)
{
  int count;
  const struct __go_type_descriptor **types;
  size_t off;
  int i;
 
  count = func->__out.__count;
  if (count == 0)
    return;
 
  types = (const struct __go_type_descriptor **) func->__out.__values;
 
  /* A single integer return value is always promoted to a full
     word.  */
  if (count == 1)
    {
      switch (types[0]->__code & GO_CODE_MASK)
	{
	case GO_BOOL:
	case GO_INT8:
	case GO_INT16:
	case GO_INT32:
	case GO_UINT8:
	case GO_UINT16:
	case GO_UINT32:
	case GO_INT:
	case GO_UINT:
	  {
	    union
	    {
	      unsigned char buf[sizeof (ffi_arg)];
	      ffi_arg v;
	    } u;
	    ffi_arg v;
 
	    __builtin_memcpy (&u.buf, call_result, sizeof (ffi_arg));
	    v = u.v;
 
	    switch (types[0]->__size)
	      {
	      case 1:
		{
		  uint8_t b;
 
		  b = (uint8_t) v;
		  __builtin_memcpy (results[0], &b, 1);
		}
		break;
 
	      case 2:
		{
		  uint16_t s;
 
		  s = (uint16_t) v;
		  __builtin_memcpy (results[0], &s, 2);
		}
		break;
 
	      case 4:
		{
		  uint32_t w;
 
		  w = (uint32_t) v;
		  __builtin_memcpy (results[0], &w, 4);
		}
		break;
 
	      case 8:
		{
		  uint64_t d;
 
		  d = (uint64_t) v;
		  __builtin_memcpy (results[0], &d, 8);
		}
		break;
 
	      default:
		abort ();
	      }
	  }
	  return;
 
	default:
	  break;
	}
    }
 
  off = 0;
  for (i = 0; i < count; ++i)
    {
      size_t align;
      size_t size;
 
      align = types[i]->__field_align;
      size = types[i]->__size;
      off = (off + align - 1) & ~ (align - 1);
      __builtin_memcpy (results[i], call_result + off, size);
      off += size;
    }
}
 
/* Call a function.  The type of the function is FUNC_TYPE, and the
   address is FUNC_ADDR.  PARAMS is an array of parameter addresses.
   RESULTS is an array of result addresses.  */
 
void
reflect_call (const struct __go_func_type *func_type, const void *func_addr,
	      _Bool is_interface, _Bool is_method, void **params,
	      void **results)
{
  ffi_cif cif;
  unsigned char *call_result;
 
  __go_assert ((func_type->__common.__code & GO_CODE_MASK) == GO_FUNC);
  go_func_to_cif (func_type, is_interface, is_method, &cif);
 
  call_result = (unsigned char *) malloc (go_results_size (func_type));
 
  ffi_call (&cif, func_addr, call_result, params);
 
  /* Some day we may need to free result values if RESULTS is
     NULL.  */
  if (results != NULL)
    go_set_results (func_type, call_result, results);
 
  free (call_result);
}
 
#else /* !defined(USE_LIBFFI) */
 
void
reflect_call (const struct __go_func_type *func_type __attribute__ ((unused)),
	      const void *func_addr __attribute__ ((unused)),
	      _Bool is_interface __attribute__ ((unused)),
	      _Bool is_method __attribute__ ((unused)),
	      void **params __attribute__ ((unused)),
	      void **results __attribute__ ((unused)))
{
  /* Without FFI there is nothing we can do.  */
  runtime_throw("libgo built without FFI does not support "
		"reflect.Call or runtime.SetFinalizer");
}
 
#endif /* !defined(USE_LIBFFI) */
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.