Branch data Line data Source code
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 : 1562752 : runtime_function_type(Runtime_function_type bft)
93 : : {
94 : 1562752 : go_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES);
95 : 1562752 : Type* any = Type::make_pointer_type(Type::make_void_type());
96 : 1562752 : if (runtime_function_types[bft] == NULL)
97 : : {
98 : 29955 : const Location bloc = Linemap::predeclared_location();
99 : 29955 : Type* t;
100 : 29955 : switch (bft)
101 : : {
102 : 0 : default:
103 : 0 : case RFT_VOID:
104 : 0 : go_unreachable();
105 : :
106 : 1574 : case RFT_BOOL:
107 : 1574 : t = Type::make_boolean_type();
108 : 1574 : break;
109 : :
110 : 884 : case RFT_BOOLPTR:
111 : 884 : t = Type::make_pointer_type(Type::lookup_bool_type());
112 : 884 : break;
113 : :
114 : 3656 : case RFT_INT:
115 : 3656 : t = Type::lookup_integer_type("int");
116 : 3656 : break;
117 : :
118 : 628 : case RFT_UINT:
119 : 628 : t = Type::lookup_integer_type("uint");
120 : 628 : break;
121 : :
122 : 15 : case RFT_UINT8:
123 : 15 : t = Type::lookup_integer_type("uint8");
124 : 15 : break;
125 : :
126 : 2 : case RFT_UINT16:
127 : 2 : t = Type::lookup_integer_type("uint16");
128 : 2 : break;
129 : :
130 : 3384 : case RFT_INT32:
131 : 3384 : t = Type::lookup_integer_type("int32");
132 : 3384 : break;
133 : :
134 : 567 : case RFT_UINT32:
135 : 567 : t = Type::lookup_integer_type("uint32");
136 : 567 : break;
137 : :
138 : 383 : case RFT_INT64:
139 : 383 : t = Type::lookup_integer_type("int64");
140 : 383 : break;
141 : :
142 : 468 : case RFT_UINT64:
143 : 468 : t = Type::lookup_integer_type("uint64");
144 : 468 : break;
145 : :
146 : 305 : case RFT_RUNE:
147 : 305 : t = Type::lookup_integer_type("int32");
148 : 305 : break;
149 : :
150 : 3676 : case RFT_UINTPTR:
151 : 3676 : t = Type::lookup_integer_type("uintptr");
152 : 3676 : break;
153 : :
154 : 32 : case RFT_FLOAT64:
155 : 32 : t = Type::lookup_float_type("float64");
156 : 32 : break;
157 : :
158 : 0 : case RFT_COMPLEX64:
159 : 0 : t = Type::lookup_complex_type("complex64");
160 : 0 : break;
161 : :
162 : 16 : case RFT_COMPLEX128:
163 : 16 : t = Type::lookup_complex_type("complex128");
164 : 16 : break;
165 : :
166 : 1560 : case RFT_STRING:
167 : 1560 : t = Type::lookup_string_type();
168 : 1560 : break;
169 : :
170 : 3915 : case RFT_POINTER:
171 : 3915 : t = Type::make_pointer_type(Type::make_void_type());
172 : 3915 : break;
173 : :
174 : 1189 : case RFT_SLICE:
175 : 1189 : t = Type::make_array_type(any, NULL);
176 : 1189 : break;
177 : :
178 : 939 : case RFT_MAP:
179 : 939 : t = Type::make_map_type(any, any, bloc);
180 : 939 : break;
181 : :
182 : 453 : case RFT_CHAN:
183 : 453 : t = Type::make_channel_type(true, true, any);
184 : 453 : break;
185 : :
186 : 1087 : case RFT_IFACE:
187 : 1087 : {
188 : 1087 : Typed_identifier_list* methods = new Typed_identifier_list();
189 : 1087 : Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc);
190 : 1087 : methods->push_back(Typed_identifier("x", mtype, bloc));
191 : 1087 : Interface_type* it = Type::make_interface_type(methods, bloc);
192 : 1087 : it->finalize_methods();
193 : 1087 : t = it;
194 : : }
195 : 1087 : break;
196 : :
197 : 2337 : case RFT_EFACE:
198 : 2337 : t = Type::make_empty_interface_type(bloc);
199 : 2337 : break;
200 : :
201 : 2885 : case RFT_TYPE:
202 : 2885 : t = Type::make_type_descriptor_ptr_type();
203 : 2885 : break;
204 : :
205 : 0 : case RFT_ARRAY2STRING:
206 : 0 : {
207 : 0 : Array_type* at =
208 : 0 : Type::make_array_type(Type::make_string_type(),
209 : : Expression::make_integer_ul(2, NULL,
210 : : bloc));
211 : 0 : at->set_is_array_incomparable();
212 : 0 : t = at;
213 : : }
214 : 0 : break;
215 : :
216 : 0 : case RFT_ARRAY3STRING:
217 : 0 : {
218 : 0 : Array_type* at =
219 : 0 : Type::make_array_type(Type::make_string_type(),
220 : : Expression::make_integer_ul(3, NULL,
221 : : bloc));
222 : 0 : at->set_is_array_incomparable();
223 : 0 : t = at;
224 : : }
225 : 0 : break;
226 : :
227 : 0 : case RFT_ARRAY4STRING:
228 : 0 : {
229 : 0 : Array_type* at =
230 : 0 : Type::make_array_type(Type::make_string_type(),
231 : : Expression::make_integer_ul(4, NULL,
232 : : bloc));
233 : 0 : at->set_is_array_incomparable();
234 : 0 : t = at;
235 : : }
236 : 0 : break;
237 : :
238 : 0 : case RFT_ARRAY5STRING:
239 : 0 : {
240 : 0 : Array_type* at =
241 : 0 : Type::make_array_type(Type::make_string_type(),
242 : : Expression::make_integer_ul(5, NULL,
243 : : bloc));
244 : 0 : at->set_is_array_incomparable();
245 : 0 : t = at;
246 : : }
247 : 0 : break;
248 : : }
249 : :
250 : 29955 : runtime_function_types[bft] = t;
251 : : }
252 : :
253 : 1562752 : 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 : 1867348 : convert_to_runtime_function_type(Gogo* gogo, Runtime_function_type bft,
260 : : Expression* e, Location loc)
261 : : {
262 : 1867348 : switch (bft)
263 : : {
264 : 0 : default:
265 : 0 : case RFT_VOID:
266 : 0 : go_unreachable();
267 : :
268 : 1366077 : case RFT_BOOL:
269 : 1366077 : case RFT_BOOLPTR:
270 : 1366077 : case RFT_INT:
271 : 1366077 : case RFT_UINT:
272 : 1366077 : case RFT_UINT8:
273 : 1366077 : case RFT_UINT16:
274 : 1366077 : case RFT_INT32:
275 : 1366077 : case RFT_UINT32:
276 : 1366077 : case RFT_INT64:
277 : 1366077 : case RFT_UINT64:
278 : 1366077 : case RFT_UINTPTR:
279 : 1366077 : case RFT_RUNE:
280 : 1366077 : case RFT_FLOAT64:
281 : 1366077 : case RFT_COMPLEX64:
282 : 1366077 : case RFT_COMPLEX128:
283 : 1366077 : case RFT_STRING:
284 : 1366077 : case RFT_POINTER:
285 : 1366077 : {
286 : 1366077 : Type* t = runtime_function_type(bft);
287 : 1366077 : Type_context context(t, false);
288 : 1366077 : e->determine_type(gogo, &context);
289 : 1366077 : if (!Type::are_identical(t, e->type(), true, NULL))
290 : 584206 : e = Expression::make_cast(t, e, loc);
291 : 1366077 : return e;
292 : : }
293 : :
294 : 61894 : case RFT_SLICE:
295 : 61894 : case RFT_MAP:
296 : 61894 : case RFT_CHAN:
297 : 61894 : case RFT_IFACE:
298 : 61894 : case RFT_EFACE:
299 : 61894 : case RFT_ARRAY2STRING:
300 : 61894 : case RFT_ARRAY3STRING:
301 : 61894 : case RFT_ARRAY4STRING:
302 : 61894 : case RFT_ARRAY5STRING:
303 : 61894 : return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc);
304 : :
305 : 439377 : case RFT_TYPE:
306 : 439377 : go_assert(e->type() == Type::make_type_descriptor_ptr_type());
307 : : return e;
308 : : }
309 : : }
310 : :
311 : : // Convert all the types used for runtime functions to the backend
312 : : // representation.
313 : :
314 : : void
315 : 4646 : Runtime::convert_types(Gogo* gogo)
316 : : {
317 : 134734 : for (int i = 0; i < static_cast<int>(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i)
318 : : {
319 : 130088 : Type* t = runtime_function_types[i];
320 : 130088 : if (t != NULL && t->named_type() != NULL)
321 : : {
322 : 3185 : bool r = t->verify(gogo);
323 : 3185 : go_assert(r);
324 : 3185 : t->named_type()->convert(gogo);
325 : : }
326 : : }
327 : 4646 : }
328 : :
329 : : // The type used to define a runtime function.
330 : :
331 : : struct Runtime_function
332 : : {
333 : : // Function name.
334 : : const char* name;
335 : : // Parameter types. Never more than 6, as it happens. RFT_VOID if
336 : : // not used.
337 : : Runtime_function_type parameter_types[6];
338 : : // Result types. Never more than 2, as it happens. RFT_VOID if not
339 : : // used.
340 : : Runtime_function_type result_types[2];
341 : : };
342 : :
343 : : static const Runtime_function runtime_functions[] =
344 : : {
345 : :
346 : : #define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } ,
347 : :
348 : : #include "runtime.def"
349 : :
350 : : #undef DEF_GO_RUNTIME
351 : :
352 : : };
353 : :
354 : : static Named_object*
355 : : runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS];
356 : :
357 : : // Get the declaration of a runtime function.
358 : :
359 : : Named_object*
360 : 1070714 : Runtime::runtime_declaration(Function code)
361 : : {
362 : 1070714 : go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
363 : 1070714 : if (runtime_function_declarations[code] == NULL)
364 : : {
365 : 55366 : const Runtime_function* pb = &runtime_functions[code];
366 : :
367 : 55366 : Location bloc = Linemap::predeclared_location();
368 : :
369 : 55366 : Typed_identifier_list* param_types = NULL;
370 : 55366 : if (pb->parameter_types[0] != RFT_VOID)
371 : : {
372 : 48579 : param_types = new Typed_identifier_list();
373 : 48579 : for (unsigned int i = 0;
374 : 158175 : i < (sizeof(pb->parameter_types)
375 : : / sizeof (pb->parameter_types[0]));
376 : : i++)
377 : : {
378 : 158099 : if (pb->parameter_types[i] == RFT_VOID)
379 : : break;
380 : 109596 : Type* t = runtime_function_type(pb->parameter_types[i]);
381 : 109596 : param_types->push_back(Typed_identifier("", t, bloc));
382 : : }
383 : : }
384 : :
385 : 55366 : Typed_identifier_list* result_types = NULL;
386 : 55366 : if (pb->result_types[0] != RFT_VOID)
387 : : {
388 : 22797 : result_types = new Typed_identifier_list();
389 : 22797 : for (unsigned int i = 0;
390 : 47982 : i < sizeof(pb->result_types) / sizeof(pb->result_types[0]);
391 : : i++)
392 : : {
393 : 45594 : if (pb->result_types[i] == RFT_VOID)
394 : : break;
395 : 25185 : Type* t = runtime_function_type(pb->result_types[i]);
396 : 25185 : result_types->push_back(Typed_identifier("", t, bloc));
397 : : }
398 : : }
399 : :
400 : 55366 : Function_type* fntype = Type::make_function_type(NULL, param_types,
401 : : result_types, bloc);
402 : 55366 : const char* n = pb->name;
403 : 55366 : const char* n1 = strchr(n, '.');
404 : 55366 : if (n1 != NULL)
405 : 49015 : n = n1 + 1;
406 : 55366 : Named_object* no = Named_object::make_function_declaration(n, NULL,
407 : : fntype, bloc);
408 : 55366 : no->func_declaration_value()->set_asm_name(pb->name);
409 : :
410 : 55366 : runtime_function_declarations[code] = no;
411 : : }
412 : :
413 : 1070714 : return runtime_function_declarations[code];
414 : : }
415 : :
416 : : // Make a call to a runtime function.
417 : :
418 : : Call_expression*
419 : 1070714 : Runtime::make_call(Gogo* gogo, Runtime::Function code, Location loc,
420 : : int param_count, ...)
421 : : {
422 : 1070714 : go_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
423 : :
424 : 1070714 : const Runtime_function* pb = &runtime_functions[code];
425 : :
426 : 1070714 : go_assert(static_cast<size_t>(param_count)
427 : : <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0]));
428 : :
429 : 1070714 : Named_object* no = runtime_declaration(code);
430 : 1070714 : Expression* func = Expression::make_func_reference(no, NULL, loc);
431 : :
432 : 1070714 : Expression_list* args = new Expression_list();
433 : 1070714 : args->reserve(param_count);
434 : :
435 : 1070714 : va_list ap;
436 : 1070714 : va_start(ap, param_count);
437 : 2938062 : for (int i = 0; i < param_count; ++i)
438 : : {
439 : 1867348 : Expression* e = va_arg(ap, Expression*);
440 : 1867348 : Runtime_function_type rft = pb->parameter_types[i];
441 : 1867348 : args->push_back(convert_to_runtime_function_type(gogo, rft, e, loc));
442 : : }
443 : 1070714 : va_end(ap);
444 : :
445 : 1070714 : return Expression::make_call(func, args, false, loc);
446 : : }
447 : :
448 : : // Get the runtime code for a named builtin function. This is used as a helper
449 : : // when creating function references for call expressions. Every reference to
450 : : // a builtin runtime function should have the associated runtime code. If the
451 : : // name is ambiguous and can refer to many runtime codes, return
452 : : // NUMBER_OF_FUNCTIONS.
453 : :
454 : : Runtime::Function
455 : 1798461 : Runtime::name_to_code(const std::string& name)
456 : : {
457 : 1798461 : Function code = Runtime::NUMBER_OF_FUNCTIONS;
458 : :
459 : : // Look through the known names for a match.
460 : 307536831 : for (size_t i = 0; i < Runtime::NUMBER_OF_FUNCTIONS; i++)
461 : : {
462 : 305738370 : const char* runtime_function_name = runtime_functions[i].name;
463 : 305738370 : if (strcmp(runtime_function_name, name.c_str()) == 0)
464 : 73517 : code = static_cast<Runtime::Function>(i);
465 : : // The names in the table have "runtime." prefix. We may be
466 : : // called with a name without the prefix. Try matching
467 : : // without the prefix as well.
468 : 305738370 : if (strncmp(runtime_function_name, "runtime.", 8) == 0
469 : 305738370 : && strcmp(runtime_function_name + 8, name.c_str()) == 0)
470 : 997201 : code = static_cast<Runtime::Function>(i);
471 : : }
472 : 1798461 : return code;
473 : : }
|