github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/go/runtime.cc (about)

     1  // runtime.cc -- runtime functions called by generated code
     2  
     3  // Copyright 2011 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 "go-system.h"
     8  
     9  #include "gogo.h"
    10  #include "types.h"
    11  #include "expressions.h"
    12  #include "runtime.h"
    13  
    14  // The frontend generates calls to various runtime functions.  They
    15  // are implemented in libgo/runtime.  This is how the runtime
    16  // functions are represented in the frontend.  Note that there is
    17  // currently nothing which ensures that the compiler's understanding
    18  // of the runtime function matches the actual implementation in
    19  // libgo/runtime.
    20  
    21  // Parameter and result types used by runtime functions.
    22  
    23  enum Runtime_function_type
    24  {
    25    // General indicator that value is not used.
    26    RFT_VOID,
    27    // Go untyped bool, C type _Bool.
    28    RFT_BOOL,
    29    // Go type *bool, C type _Bool*.
    30    RFT_BOOLPTR,
    31    // Go type int, C type intgo.
    32    RFT_INT,
    33    // Go type uint, C type uintgo.
    34    RFT_UINT,
    35    // Go type uint8, C type uint8_t.
    36    RFT_UINT8,
    37    // Go type uint16, C type uint16_t.
    38    RFT_UINT16,
    39    // Go type int32, C type int32_t.
    40    RFT_INT32,
    41    // Go type uint32, C type uint32_t.
    42    RFT_UINT32,
    43    // Go type int64, C type int64_t.
    44    RFT_INT64,
    45    // Go type uint64, C type uint64_t.
    46    RFT_UINT64,
    47    // Go type uintptr, C type uintptr_t.
    48    RFT_UINTPTR,
    49    // Go type rune, C type int32_t.
    50    RFT_RUNE,
    51    // Go type float64, C type double.
    52    RFT_FLOAT64,
    53    // Go type complex64, C type __complex float.
    54    RFT_COMPLEX64,
    55    // Go type complex128, C type __complex double.
    56    RFT_COMPLEX128,
    57    // Go type string, C type struct __go_string.
    58    RFT_STRING,
    59    // Go type unsafe.Pointer, C type "void *".
    60    RFT_POINTER,
    61    // Go type []any, C type struct __go_open_array.
    62    RFT_SLICE,
    63    // Go type map[any]any, C type struct __go_map *.
    64    RFT_MAP,
    65    // Go type chan any, C type struct __go_channel *.
    66    RFT_CHAN,
    67    // Go type non-empty interface, C type struct __go_interface.
    68    RFT_IFACE,
    69    // Go type interface{}, C type struct __go_empty_interface.
    70    RFT_EFACE,
    71    // Pointer to Go type descriptor.
    72    RFT_TYPE,
    73    // [2]string.
    74    RFT_ARRAY2STRING,
    75    // [3]string.
    76    RFT_ARRAY3STRING,
    77    // [4]string.
    78    RFT_ARRAY4STRING,
    79    // [5]string.
    80    RFT_ARRAY5STRING,
    81  
    82    NUMBER_OF_RUNTIME_FUNCTION_TYPES
    83  };
    84  
    85  // The Type structures for the runtime function types.
    86  
    87  static Type* runtime_function_types[NUMBER_OF_RUNTIME_FUNCTION_TYPES];
    88  
    89  // Get the Type for a Runtime_function_type code.
    90  
    91  static Type*
    92  runtime_function_type(Runtime_function_type bft)
    93  {
    94    go_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES);
    95    Type* any = Type::make_pointer_type(Type::make_void_type());
    96    if (runtime_function_types[bft] == NULL)
    97      {
    98        const Location bloc = Linemap::predeclared_location();
    99        Type* t;
   100        switch (bft)
   101  	{
   102  	default:
   103  	case RFT_VOID:
   104  	  go_unreachable();
   105  
   106  	case RFT_BOOL:
   107  	  t = Type::make_boolean_type();
   108  	  break;
   109  
   110  	case RFT_BOOLPTR:
   111  	  t = Type::make_pointer_type(Type::lookup_bool_type());
   112  	  break;
   113  
   114  	case RFT_INT:
   115  	  t = Type::lookup_integer_type("int");
   116  	  break;
   117  
   118  	case RFT_UINT:
   119  	  t = Type::lookup_integer_type("uint");
   120  	  break;
   121  
   122  	case RFT_UINT8:
   123  	  t = Type::lookup_integer_type("uint8");
   124  	  break;
   125  
   126  	case RFT_UINT16:
   127  	  t = Type::lookup_integer_type("uint16");
   128  	  break;
   129  
   130  	case RFT_INT32:
   131  	  t = Type::lookup_integer_type("int32");
   132  	  break;
   133  
   134  	case RFT_UINT32:
   135  	  t = Type::lookup_integer_type("uint32");
   136  	  break;
   137  
   138  	case RFT_INT64:
   139  	  t = Type::lookup_integer_type("int64");
   140  	  break;
   141  
   142  	case RFT_UINT64:
   143  	  t = Type::lookup_integer_type("uint64");
   144  	  break;
   145  
   146  	case RFT_RUNE:
   147  	  t = Type::lookup_integer_type("int32");
   148  	  break;
   149  
   150  	case RFT_UINTPTR:
   151  	  t = Type::lookup_integer_type("uintptr");
   152  	  break;
   153  
   154  	case RFT_FLOAT64:
   155  	  t = Type::lookup_float_type("float64");
   156  	  break;
   157  
   158  	case RFT_COMPLEX64:
   159  	  t = Type::lookup_complex_type("complex64");
   160  	  break;
   161  
   162  	case RFT_COMPLEX128:
   163  	  t = Type::lookup_complex_type("complex128");
   164  	  break;
   165  
   166  	case RFT_STRING:
   167  	  t = Type::lookup_string_type();
   168  	  break;
   169  
   170  	case RFT_POINTER:
   171  	  t = Type::make_pointer_type(Type::make_void_type());
   172  	  break;
   173  
   174  	case RFT_SLICE:
   175  	  t = Type::make_array_type(any, NULL);
   176  	  break;
   177  
   178  	case RFT_MAP:
   179  	  t = Type::make_map_type(any, any, bloc);
   180  	  break;
   181  
   182  	case RFT_CHAN:
   183  	  t = Type::make_channel_type(true, true, any);
   184  	  break;
   185  
   186  	case RFT_IFACE:
   187  	  {
   188  	    Typed_identifier_list* methods = new Typed_identifier_list();
   189  	    Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc);
   190  	    methods->push_back(Typed_identifier("x", mtype, bloc));
   191  	    Interface_type* it = Type::make_interface_type(methods, bloc);
   192  	    it->finalize_methods();
   193  	    t = it;
   194  	  }
   195  	  break;
   196  
   197  	case RFT_EFACE:
   198  	  t = Type::make_empty_interface_type(bloc);
   199  	  break;
   200  
   201  	case RFT_TYPE:
   202  	  t = Type::make_type_descriptor_ptr_type();
   203  	  break;
   204  
   205  	case RFT_ARRAY2STRING:
   206  	  {
   207  	    Array_type* at =
   208  	      Type::make_array_type(Type::make_string_type(),
   209  				    Expression::make_integer_ul(2, NULL,
   210  								bloc));
   211  	    at->set_is_array_incomparable();
   212  	    t = at;
   213  	  }
   214  	  break;
   215  
   216  	case RFT_ARRAY3STRING:
   217  	  {
   218  	    Array_type* at =
   219  	      Type::make_array_type(Type::make_string_type(),
   220  				    Expression::make_integer_ul(3, NULL,
   221  								bloc));
   222  	    at->set_is_array_incomparable();
   223  	    t = at;
   224  	  }
   225  	  break;
   226  
   227  	case RFT_ARRAY4STRING:
   228  	  {
   229  	    Array_type* at =
   230  	      Type::make_array_type(Type::make_string_type(),
   231  				    Expression::make_integer_ul(4, NULL,
   232  								bloc));
   233  	    at->set_is_array_incomparable();
   234  	    t = at;
   235  	  }
   236  	  break;
   237  
   238  	case RFT_ARRAY5STRING:
   239  	  {
   240  	    Array_type* at =
   241  	      Type::make_array_type(Type::make_string_type(),
   242  				    Expression::make_integer_ul(5, NULL,
   243  								bloc));
   244  	    at->set_is_array_incomparable();
   245  	    t = at;
   246  	  }
   247  	  break;
   248  	}
   249  
   250        runtime_function_types[bft] = t;
   251      }
   252  
   253    return runtime_function_types[bft];
   254  }
   255  
   256  // Convert an expression to the type to pass to a runtime function.
   257  
   258  static Expression*
   259  convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
   260  				 Location loc)
   261  {
   262    switch (bft)
   263      {
   264      default:
   265      case RFT_VOID:
   266        go_unreachable();
   267  
   268      case RFT_BOOL:
   269      case RFT_BOOLPTR:
   270      case RFT_INT:
   271      case RFT_UINT:
   272      case RFT_UINT8:
   273      case RFT_UINT16:
   274      case RFT_INT32:
   275      case RFT_UINT32:
   276      case RFT_INT64:
   277      case RFT_UINT64:
   278      case RFT_UINTPTR:
   279      case RFT_RUNE:
   280      case RFT_FLOAT64:
   281      case RFT_COMPLEX64:
   282      case RFT_COMPLEX128:
   283      case RFT_STRING:
   284      case RFT_POINTER:
   285        {
   286  	Type* t = runtime_function_type(bft);
   287  	if (!Type::are_identical(t, e->type(), true, NULL))
   288  	  e = Expression::make_cast(t, e, loc);
   289  	return e;
   290        }
   291  
   292      case RFT_SLICE:
   293      case RFT_MAP:
   294      case RFT_CHAN:
   295      case RFT_IFACE:
   296      case RFT_EFACE:
   297      case RFT_ARRAY2STRING:
   298      case RFT_ARRAY3STRING:
   299      case RFT_ARRAY4STRING:
   300      case RFT_ARRAY5STRING:
   301        return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc);
   302  
   303      case RFT_TYPE:
   304        go_assert(e->type() == Type::make_type_descriptor_ptr_type());
   305        return e;
   306      }
   307  }
   308  
   309  // Convert all the types used for runtime functions to the backend
   310  // representation.
   311  
   312  void
   313  Runtime::convert_types(Gogo* gogo)
   314  {
   315    for (int i = 0; i < static_cast<int>(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i)
   316      {
   317        Type* t = runtime_function_types[i];
   318        if (t != NULL && t->named_type() != NULL)
   319  	{
   320  	  bool r = t->verify();
   321  	  go_assert(r);
   322  	  t->named_type()->convert(gogo);
   323  	}
   324      }
   325  }
   326  
   327  // The type used to define a runtime function.
   328  
   329  struct Runtime_function
   330  {
   331    // Function name.
   332    const char* name;
   333    // Parameter types.  Never more than 6, as it happens.  RFT_VOID if
   334    // not used.
   335    Runtime_function_type parameter_types[6];
   336    // Result types.  Never more than 2, as it happens.  RFT_VOID if not
   337    // used.
   338    Runtime_function_type result_types[2];
   339  };
   340  
   341  static const Runtime_function runtime_functions[] =
   342  {
   343  
   344  #define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } ,
   345  
   346  #include "runtime.def"
   347  
   348  #undef DEF_GO_RUNTIME
   349  
   350  };
   351  
   352  static Named_object*
   353  runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS];
   354  
   355  // Get the declaration of a runtime function.
   356  
   357  Named_object*
   358  Runtime::runtime_declaration(Function code)
   359  {
   360    go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
   361    if (runtime_function_declarations[code] == NULL)
   362      {
   363        const Runtime_function* pb = &runtime_functions[code];
   364  
   365        Location bloc = Linemap::predeclared_location();
   366  
   367        Typed_identifier_list* param_types = NULL;
   368        if (pb->parameter_types[0] != RFT_VOID)
   369  	{
   370  	  param_types = new Typed_identifier_list();
   371  	  for (unsigned int i = 0;
   372  	       i < (sizeof(pb->parameter_types)
   373  		    / sizeof (pb->parameter_types[0]));
   374  	       i++)
   375  	    {
   376  	      if (pb->parameter_types[i] == RFT_VOID)
   377  		break;
   378  	      Type* t = runtime_function_type(pb->parameter_types[i]);
   379  	      param_types->push_back(Typed_identifier("", t, bloc));
   380  	    }
   381  	}
   382  
   383        Typed_identifier_list* result_types = NULL;
   384        if (pb->result_types[0] != RFT_VOID)
   385  	{
   386  	  result_types = new Typed_identifier_list();
   387  	  for (unsigned int i = 0;
   388  	       i < sizeof(pb->result_types) / sizeof(pb->result_types[0]);
   389  	       i++)
   390  	    {
   391  	      if (pb->result_types[i] == RFT_VOID)
   392  		break;
   393  	      Type* t = runtime_function_type(pb->result_types[i]);
   394  	      result_types->push_back(Typed_identifier("", t, bloc));
   395  	    }
   396  	}
   397  
   398        Function_type* fntype = Type::make_function_type(NULL, param_types,
   399  						       result_types, bloc);
   400        const char* n = pb->name;
   401        const char* n1 = strchr(n, '.');
   402        if (n1 != NULL)
   403  	n = n1 + 1;
   404        Named_object* no = Named_object::make_function_declaration(n, NULL,
   405  								 fntype, bloc);
   406        no->func_declaration_value()->set_asm_name(pb->name);
   407  
   408        runtime_function_declarations[code] = no;
   409      }
   410  
   411    return runtime_function_declarations[code];
   412  }
   413  
   414  // Make a call to a runtime function.
   415  
   416  Call_expression*
   417  Runtime::make_call(Runtime::Function code, Location loc,
   418  		   int param_count, ...)
   419  {
   420    go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
   421  
   422    const Runtime_function* pb = &runtime_functions[code];
   423  
   424    go_assert(static_cast<size_t>(param_count)
   425  	     <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0]));
   426  
   427    Named_object* no = runtime_declaration(code);
   428    Expression* func = Expression::make_func_reference(no, NULL, loc);
   429  
   430    Expression_list* args = new Expression_list();
   431    args->reserve(param_count);
   432  
   433    va_list ap;
   434    va_start(ap, param_count);
   435    for (int i = 0; i < param_count; ++i)
   436      {
   437        Expression* e = va_arg(ap, Expression*);
   438        Runtime_function_type rft = pb->parameter_types[i];
   439        args->push_back(convert_to_runtime_function_type(rft, e, loc));
   440      }
   441    va_end(ap);
   442  
   443    return Expression::make_call(func, args, false, loc);
   444  }
   445  
   446  // Get the runtime code for a named builtin function.  This is used as a helper
   447  // when creating function references for call expressions.  Every reference to
   448  // a builtin runtime function should have the associated runtime code.  If the
   449  // name is ambiguous and can refer to many runtime codes, return
   450  // NUMBER_OF_FUNCTIONS.
   451  
   452  Runtime::Function
   453  Runtime::name_to_code(const std::string& name)
   454  {
   455    Function code = Runtime::NUMBER_OF_FUNCTIONS;
   456  
   457    // Look through the known names for a match.
   458    for (size_t i = 0; i < Runtime::NUMBER_OF_FUNCTIONS; i++)
   459      {
   460        const char* runtime_function_name = runtime_functions[i].name;
   461        if (strcmp(runtime_function_name, name.c_str()) == 0)
   462          code = static_cast<Runtime::Function>(i);
   463        // The names in the table have "runtime." prefix. We may be
   464        // called with a name without the prefix. Try matching
   465        // without the prefix as well.
   466        if (strncmp(runtime_function_name, "runtime.", 8) == 0
   467            && strcmp(runtime_function_name + 8, name.c_str()) == 0)
   468          code = static_cast<Runtime::Function>(i);
   469      }
   470    return code;
   471  }