// runtime.cc -- runtime functions called by generated code // Copyright 2011 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 "go-system.h" #include "gogo.h" #include "types.h" #include "expressions.h" #include "runtime.h" // The frontend generates calls to various runtime functions. They // are implemented in libgo/runtime. This is how the runtime // functions are represented in the frontend. Note that there is // currently nothing which ensures that the compiler's understanding // of the runtime function matches the actual implementation in // libgo/runtime. // Parameter and result types used by runtime functions. enum Runtime_function_type { // General indicator that value is not used. RFT_VOID, // Go untyped bool, C type _Bool. RFT_BOOL, // Go type *bool, C type _Bool*. RFT_BOOLPTR, // Go type int, C type intgo. RFT_INT, // Go type int32, C type int32_t. RFT_INT32, // Go type int64, C type int64_t. RFT_INT64, // Go type uint64, C type uint64_t. RFT_UINT64, // Go type uintptr, C type uintptr_t. RFT_UINTPTR, // Go type rune, C type int32_t. RFT_RUNE, // Go type float64, C type double. RFT_FLOAT64, // Go type complex64, C type __complex float. RFT_COMPLEX64, // Go type complex128, C type __complex double. RFT_COMPLEX128, // Go type string, C type struct __go_string. RFT_STRING, // Go type unsafe.Pointer, C type "void *". RFT_POINTER, // Go type []any, C type struct __go_open_array. RFT_SLICE, // Go type map[any]any, C type struct __go_map *. RFT_MAP, // Go type chan any, C type struct __go_channel *. RFT_CHAN, // Go type non-empty interface, C type struct __go_interface. RFT_IFACE, // Go type interface{}, C type struct __go_empty_interface. RFT_EFACE, // Go type func(unsafe.Pointer), C type void (*) (void *). RFT_FUNC_PTR, // Pointer to Go type descriptor. RFT_TYPE, // [2]string. RFT_ARRAY2STRING, // [3]string. RFT_ARRAY3STRING, // [4]string. RFT_ARRAY4STRING, // [5]string. RFT_ARRAY5STRING, NUMBER_OF_RUNTIME_FUNCTION_TYPES }; // The Type structures for the runtime function types. static Type* runtime_function_types[NUMBER_OF_RUNTIME_FUNCTION_TYPES]; // Get the Type for a Runtime_function_type code. static Type* runtime_function_type(Runtime_function_type bft) { go_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES); Type* any = Type::make_pointer_type(Type::make_void_type()); if (runtime_function_types[bft] == NULL) { const Location bloc = Linemap::predeclared_location(); Type* t; switch (bft) { default: case RFT_VOID: go_unreachable(); case RFT_BOOL: t = Type::make_boolean_type(); break; case RFT_BOOLPTR: t = Type::make_pointer_type(Type::lookup_bool_type()); break; case RFT_INT: t = Type::lookup_integer_type("int"); break; case RFT_INT32: t = Type::lookup_integer_type("int32"); break; case RFT_INT64: t = Type::lookup_integer_type("int64"); break; case RFT_UINT64: t = Type::lookup_integer_type("uint64"); break; case RFT_RUNE: t = Type::lookup_integer_type("int32"); break; case RFT_UINTPTR: t = Type::lookup_integer_type("uintptr"); break; case RFT_FLOAT64: t = Type::lookup_float_type("float64"); break; case RFT_COMPLEX64: t = Type::lookup_complex_type("complex64"); break; case RFT_COMPLEX128: t = Type::lookup_complex_type("complex128"); break; case RFT_STRING: t = Type::lookup_string_type(); break; case RFT_POINTER: t = Type::make_pointer_type(Type::make_void_type()); break; case RFT_SLICE: t = Type::make_array_type(any, NULL); break; case RFT_MAP: t = Type::make_map_type(any, any, bloc); break; case RFT_CHAN: t = Type::make_channel_type(true, true, any); break; case RFT_IFACE: { Typed_identifier_list* methods = new Typed_identifier_list(); Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc); methods->push_back(Typed_identifier("x", mtype, bloc)); Interface_type* it = Type::make_interface_type(methods, bloc); it->finalize_methods(); t = it; } break; case RFT_EFACE: t = Type::make_empty_interface_type(bloc); break; case RFT_FUNC_PTR: { Typed_identifier_list* param_types = new Typed_identifier_list(); Type* ptrtype = runtime_function_type(RFT_POINTER); param_types->push_back(Typed_identifier("", ptrtype, bloc)); t = Type::make_function_type(NULL, param_types, NULL, bloc); } break; case RFT_TYPE: t = Type::make_type_descriptor_ptr_type(); break; case RFT_ARRAY2STRING: { Array_type* at = Type::make_array_type(Type::make_string_type(), Expression::make_integer_ul(2, NULL, bloc)); at->set_is_array_incomparable(); t = at; } break; case RFT_ARRAY3STRING: { Array_type* at = Type::make_array_type(Type::make_string_type(), Expression::make_integer_ul(3, NULL, bloc)); at->set_is_array_incomparable(); t = at; } break; case RFT_ARRAY4STRING: { Array_type* at = Type::make_array_type(Type::make_string_type(), Expression::make_integer_ul(4, NULL, bloc)); at->set_is_array_incomparable(); t = at; } break; case RFT_ARRAY5STRING: { Array_type* at = Type::make_array_type(Type::make_string_type(), Expression::make_integer_ul(5, NULL, bloc)); at->set_is_array_incomparable(); t = at; } break; } runtime_function_types[bft] = t; } return runtime_function_types[bft]; } // Convert an expression to the type to pass to a runtime function. static Expression* convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, Location loc) { switch (bft) { default: case RFT_VOID: go_unreachable(); case RFT_BOOL: case RFT_BOOLPTR: case RFT_INT: case RFT_INT32: case RFT_INT64: case RFT_UINT64: case RFT_UINTPTR: case RFT_RUNE: case RFT_FLOAT64: case RFT_COMPLEX64: case RFT_COMPLEX128: case RFT_STRING: case RFT_POINTER: case RFT_FUNC_PTR: { Type* t = runtime_function_type(bft); if (!Type::are_identical(t, e->type(), true, NULL)) e = Expression::make_cast(t, e, loc); return e; } case RFT_SLICE: case RFT_MAP: case RFT_CHAN: case RFT_IFACE: case RFT_EFACE: case RFT_ARRAY2STRING: case RFT_ARRAY3STRING: case RFT_ARRAY4STRING: case RFT_ARRAY5STRING: return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc); case RFT_TYPE: go_assert(e->type() == Type::make_type_descriptor_ptr_type()); return e; } } // Convert all the types used for runtime functions to the backend // representation. void Runtime::convert_types(Gogo* gogo) { for (int i = 0; i < static_cast(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i) { Type* t = runtime_function_types[i]; if (t != NULL && t->named_type() != NULL) { bool r = t->verify(); go_assert(r); t->named_type()->convert(gogo); } } } // The type used to define a runtime function. struct Runtime_function { // Function name. const char* name; // Parameter types. Never more than 6, as it happens. RFT_VOID if // not used. Runtime_function_type parameter_types[6]; // Result types. Never more than 2, as it happens. RFT_VOID if not // used. Runtime_function_type result_types[2]; }; static const Runtime_function runtime_functions[] = { #define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } , #include "runtime.def" #undef DEF_GO_RUNTIME }; static Named_object* runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS]; // Get the declaration of a runtime function. Named_object* Runtime::runtime_declaration(Function code) { go_assert(code < Runtime::NUMBER_OF_FUNCTIONS); if (runtime_function_declarations[code] == NULL) { const Runtime_function* pb = &runtime_functions[code]; Location bloc = Linemap::predeclared_location(); Typed_identifier_list* param_types = NULL; if (pb->parameter_types[0] != RFT_VOID) { param_types = new Typed_identifier_list(); for (unsigned int i = 0; i < (sizeof(pb->parameter_types) / sizeof (pb->parameter_types[0])); i++) { if (pb->parameter_types[i] == RFT_VOID) break; Type* t = runtime_function_type(pb->parameter_types[i]); param_types->push_back(Typed_identifier("", t, bloc)); } } Typed_identifier_list* result_types = NULL; if (pb->result_types[0] != RFT_VOID) { result_types = new Typed_identifier_list(); for (unsigned int i = 0; i < sizeof(pb->result_types) / sizeof(pb->result_types[0]); i++) { if (pb->result_types[i] == RFT_VOID) break; Type* t = runtime_function_type(pb->result_types[i]); result_types->push_back(Typed_identifier("", t, bloc)); } } Function_type* fntype = Type::make_function_type(NULL, param_types, result_types, bloc); const char* n = pb->name; const char* n1 = strchr(n, '.'); if (n1 != NULL) n = n1 + 1; Named_object* no = Named_object::make_function_declaration(n, NULL, fntype, bloc); no->func_declaration_value()->set_asm_name(pb->name); runtime_function_declarations[code] = no; } return runtime_function_declarations[code]; } // Make a call to a runtime function. Call_expression* Runtime::make_call(Runtime::Function code, Location loc, int param_count, ...) { go_assert(code < Runtime::NUMBER_OF_FUNCTIONS); const Runtime_function* pb = &runtime_functions[code]; go_assert(static_cast(param_count) <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0])); Named_object* no = runtime_declaration(code); Expression* func = Expression::make_func_reference(no, NULL, loc); Expression_list* args = new Expression_list(); args->reserve(param_count); va_list ap; va_start(ap, param_count); for (int i = 0; i < param_count; ++i) { Expression* e = va_arg(ap, Expression*); Runtime_function_type rft = pb->parameter_types[i]; args->push_back(convert_to_runtime_function_type(rft, e, loc)); } va_end(ap); return Expression::make_call(func, args, false, loc); } // Get the runtime code for a named builtin function. This is used as a helper // when creating function references for call expressions. Every reference to // a builtin runtime function should have the associated runtime code. If the // name is ambiguous and can refer to many runtime codes, return // NUMBER_OF_FUNCTIONS. Runtime::Function Runtime::name_to_code(const std::string& name) { Function code = Runtime::NUMBER_OF_FUNCTIONS; // Aliases seen in function declaration code. // TODO(cmang): Add other aliases. if (name == "new") code = Runtime::NEW; else if (name == "close") code = Runtime::CLOSE; else if (name == "copy") code = Runtime::SLICECOPY; else if (name == "append") code = Runtime::GROWSLICE; else if (name == "delete") code = Runtime::MAPDELETE; else { // Look through the known names for a match. for (size_t i = 0; i < Runtime::NUMBER_OF_FUNCTIONS; i++) { if (strcmp(runtime_functions[i].name, name.c_str()) == 0) code = static_cast(i); } } return code; }