111
|
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,
|
145
|
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,
|
111
|
39 // Go type int32, C type int32_t.
|
|
40 RFT_INT32,
|
145
|
41 // Go type uint32, C type uint32_t.
|
|
42 RFT_UINT32,
|
111
|
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
|
145
|
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
|
111
|
130 case RFT_INT32:
|
|
131 t = Type::lookup_integer_type("int32");
|
|
132 break;
|
|
133
|
145
|
134 case RFT_UINT32:
|
|
135 t = Type::lookup_integer_type("uint32");
|
|
136 break;
|
|
137
|
111
|
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:
|
145
|
271 case RFT_UINT:
|
|
272 case RFT_UINT8:
|
|
273 case RFT_UINT16:
|
111
|
274 case RFT_INT32:
|
145
|
275 case RFT_UINT32:
|
111
|
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
|
131
|
457 // Look through the known names for a match.
|
|
458 for (size_t i = 0; i < Runtime::NUMBER_OF_FUNCTIONS; i++)
|
111
|
459 {
|
131
|
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);
|
111
|
469 }
|
|
470 return code;
|
|
471 }
|