]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/go/gofrontend/export.cc
compiler: add abstraction layer for sha1 checksums.
[thirdparty/gcc.git] / gcc / go / gofrontend / export.cc
CommitLineData
7a938933
ILT
1// export.cc -- Export declarations in Go frontend.
2
3// Copyright 2009 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"
7a938933 8
34144b6e 9#include "go-sha1.h"
76aa42d2 10#include "go-c.h"
7a938933
ILT
11
12#include "gogo.h"
13#include "types.h"
14#include "statements.h"
15#include "export.h"
16
17// This file handles exporting global declarations.
18
19// Class Export.
20
c0ccddb4 21const int Export::magic_len;
7a938933 22
c0ccddb4
ILT
23// Current version magic string.
24const char Export::cur_magic[Export::magic_len] =
25 {
26 'v', '2', ';', '\n'
27 };
7a938933 28
c0ccddb4
ILT
29// Magic string for previous version (still supported)
30const char Export::v1_magic[Export::magic_len] =
7a938933
ILT
31 {
32 'v', '1', ';', '\n'
33 };
34
c0ccddb4 35const int Export::checksum_len;
7a938933
ILT
36
37// Constructor.
38
39Export::Export(Stream* stream)
097b12fb 40 : stream_(stream), type_refs_(), type_index_(1), packages_()
7a938933 41{
34144b6e 42 go_assert(Export::checksum_len == Go_sha1_helper::checksum_len);
7a938933
ILT
43}
44
45// A functor to sort Named_object pointers by name.
46
47struct Sort_bindings
48{
49 bool
50 operator()(const Named_object* n1, const Named_object* n2) const
51 { return n1->name() < n2->name(); }
52};
53
54// Return true if we should export NO.
55
56static bool
57should_export(Named_object* no)
58{
59 // We only export objects which are locally defined.
60 if (no->package() != NULL)
61 return false;
62
63 // We don't export packages.
64 if (no->is_package())
65 return false;
66
67 // We don't export hidden names.
68 if (Gogo::is_hidden_name(no->name()))
69 return false;
70
71 // We don't export nested functions.
72 if (no->is_function() && no->func_value()->enclosing() != NULL)
73 return false;
74
75 // We don't export thunks.
76 if (no->is_function() && Gogo::is_thunk(no))
77 return false;
78
79 // Methods are exported with the type, not here.
80 if (no->is_function()
81 && no->func_value()->type()->is_method())
82 return false;
83 if (no->is_function_declaration()
84 && no->func_declaration_value()->type()->is_method())
85 return false;
86
87 // Don't export dummy global variables created for initializers when
88 // used with sinks.
89 if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.')
90 return false;
91
92 return true;
93}
94
95// Export those identifiers marked for exporting.
96
97void
98Export::export_globals(const std::string& package_name,
2e29434d 99 const std::string& prefix,
097b12fb 100 const std::string& pkgpath,
b4d216f6 101 const std::map<std::string, Package*>& packages,
f21f4773 102 const std::map<std::string, Package*>& imports,
7a938933 103 const std::string& import_init_fn,
c0ccddb4 104 const Import_init_set& imported_init_fns,
7a938933
ILT
105 const Bindings* bindings)
106{
107 // If there have been any errors so far, don't try to export
108 // anything. That way the export code doesn't have to worry about
109 // mismatched types or other confusions.
110 if (saw_errors())
111 return;
112
113 // Export the symbols in sorted order. That will reduce cases where
114 // irrelevant changes to the source code affect the exported
115 // interface.
116 std::vector<Named_object*> exports;
117 exports.reserve(bindings->size_definitions());
118
119 for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
120 p != bindings->end_definitions();
121 ++p)
122 if (should_export(*p))
123 exports.push_back(*p);
124
125 for (Bindings::const_declarations_iterator p =
126 bindings->begin_declarations();
127 p != bindings->end_declarations();
128 ++p)
129 {
130 // We export a function declaration as it may be implemented in
131 // supporting C code. We do not export type declarations.
132 if (p->second->is_function_declaration()
133 && should_export(p->second))
134 exports.push_back(p->second);
135 }
136
137 std::sort(exports.begin(), exports.end(), Sort_bindings());
138
139 // Although the export data is readable, at least this version is,
140 // it is conceptually a binary format. Start with a four byte
c0ccddb4
ILT
141 // version number.
142 this->write_bytes(Export::cur_magic, Export::magic_len);
7a938933
ILT
143
144 // The package name.
145 this->write_c_string("package ");
146 this->write_string(package_name);
147 this->write_c_string(";\n");
148
2e29434d
ILT
149 // The prefix or package path, used for all global symbols.
150 if (prefix.empty())
151 {
152 go_assert(!pkgpath.empty());
153 this->write_c_string("pkgpath ");
154 this->write_string(pkgpath);
155 }
156 else
157 {
158 this->write_c_string("prefix ");
159 this->write_string(prefix);
160 }
7a938933
ILT
161 this->write_c_string(";\n");
162
b4d216f6
ILT
163 this->write_packages(packages);
164
f21f4773
ILT
165 this->write_imports(imports);
166
c0ccddb4 167 this->write_imported_init_fns(package_name, import_init_fn,
7a938933
ILT
168 imported_init_fns);
169
170 // FIXME: It might be clever to add something about the processor
171 // and ABI being used, although ideally any problems in that area
172 // would be caught by the linker.
173
174 for (std::vector<Named_object*>::const_iterator p = exports.begin();
175 p != exports.end();
176 ++p)
177 (*p)->export_named_object(this);
178
179 std::string checksum = this->stream_->checksum();
180 std::string s = "checksum ";
181 for (std::string::const_iterator p = checksum.begin();
182 p != checksum.end();
183 ++p)
184 {
185 unsigned char c = *p;
186 unsigned int dig = c >> 4;
187 s += dig < 10 ? '0' + dig : 'A' + dig - 10;
188 dig = c & 0xf;
189 s += dig < 10 ? '0' + dig : 'A' + dig - 10;
190 }
191 s += ";\n";
192 this->stream_->write_checksum(s);
193}
194
b4d216f6
ILT
195// Sort packages.
196
197static bool
198packages_compare(const Package* a, const Package* b)
199{
200 return a->package_name() < b->package_name();
201}
202
203// Write out all the known packages whose pkgpath symbol is not a
204// simple transformation of the pkgpath, so that the importing code
205// can reliably know it.
206
207void
208Export::write_packages(const std::map<std::string, Package*>& packages)
209{
210 // Sort for consistent output.
211 std::vector<Package*> out;
212 for (std::map<std::string, Package*>::const_iterator p = packages.begin();
213 p != packages.end();
214 ++p)
215 {
216 if (p->second->pkgpath_symbol()
217 != Gogo::pkgpath_for_symbol(p->second->pkgpath()))
218 out.push_back(p->second);
219 }
220
221 std::sort(out.begin(), out.end(), packages_compare);
222
223 for (std::vector<Package*>::const_iterator p = out.begin();
224 p != out.end();
225 ++p)
226 {
227 this->write_c_string("package ");
228 this->write_string((*p)->package_name());
229 this->write_c_string(" ");
230 this->write_string((*p)->pkgpath());
231 this->write_c_string(" ");
232 this->write_string((*p)->pkgpath_symbol());
233 this->write_c_string(";\n");
234 }
235}
236
f21f4773
ILT
237// Sort imported packages.
238
239static bool
240import_compare(const std::pair<std::string, Package*>& a,
241 const std::pair<std::string, Package*>& b)
242{
243 return a.first < b.first;
244}
245
246// Write out the imported packages.
247
248void
249Export::write_imports(const std::map<std::string, Package*>& imports)
250{
251 // Sort the imports for more consistent output.
c0ccddb4 252 std::vector<std::pair<std::string, Package*> > sorted_imports;
f21f4773
ILT
253 for (std::map<std::string, Package*>::const_iterator p = imports.begin();
254 p != imports.end();
255 ++p)
c0ccddb4 256 sorted_imports.push_back(std::make_pair(p->first, p->second));
f21f4773 257
c0ccddb4 258 std::sort(sorted_imports.begin(), sorted_imports.end(), import_compare);
f21f4773
ILT
259
260 for (std::vector<std::pair<std::string, Package*> >::const_iterator p =
c0ccddb4
ILT
261 sorted_imports.begin();
262 p != sorted_imports.end();
f21f4773
ILT
263 ++p)
264 {
265 this->write_c_string("import ");
097b12fb 266 this->write_string(p->second->package_name());
f21f4773 267 this->write_c_string(" ");
097b12fb 268 this->write_string(p->second->pkgpath());
f21f4773
ILT
269 this->write_c_string(" \"");
270 this->write_string(p->first);
271 this->write_c_string("\";\n");
097b12fb
ILT
272
273 this->packages_.insert(p->second);
f21f4773
ILT
274 }
275}
276
c0ccddb4
ILT
277void
278Export::add_init_graph_edge(Init_graph* init_graph, unsigned src, unsigned sink)
279{
280 Init_graph::iterator it = init_graph->find(src);
281 if (it != init_graph->end())
282 it->second.insert(sink);
283 else
284 {
285 std::set<unsigned> succs;
286 succs.insert(sink);
287 (*init_graph)[src] = succs;
288 }
289}
290
291// Constructs the imported portion of the init graph, e.g. those
292// edges that we read from imported packages.
293
294void
295Export::populate_init_graph(Init_graph* init_graph,
296 const Import_init_set& imported_init_fns,
297 const std::map<std::string, unsigned>& init_idx)
298{
299 for (Import_init_set::const_iterator p = imported_init_fns.begin();
300 p != imported_init_fns.end();
301 ++p)
302 {
303 const Import_init* ii = *p;
304 std::map<std::string, unsigned>::const_iterator srcit =
305 init_idx.find(ii->init_name());
306 go_assert(srcit != init_idx.end());
307 unsigned src = srcit->second;
308 for (std::set<std::string>::const_iterator pci = ii->precursors().begin();
309 pci != ii->precursors().end();
310 ++pci)
311 {
312 std::map<std::string, unsigned>::const_iterator it =
313 init_idx.find(*pci);
314 go_assert(it != init_idx.end());
315 unsigned sink = it->second;
316 add_init_graph_edge(init_graph, src, sink);
317 }
318 }
319}
320
f21f4773
ILT
321// Write out the initialization functions which need to run for this
322// package.
7a938933
ILT
323
324void
c0ccddb4
ILT
325Export::write_imported_init_fns(const std::string& package_name,
326 const std::string& import_init_fn,
327 const Import_init_set& imported_init_fns)
7a938933 328{
c0ccddb4
ILT
329 if (import_init_fn.empty() && imported_init_fns.empty()) return;
330
331 // Maps a given init function to the its index in the exported "init" clause.
332 std::map<std::string, unsigned> init_idx;
7a938933 333
f21f4773 334 this->write_c_string("init");
7a938933
ILT
335
336 if (!import_init_fn.empty())
337 {
338 this->write_c_string(" ");
339 this->write_string(package_name);
340 this->write_c_string(" ");
341 this->write_string(import_init_fn);
c0ccddb4 342 init_idx[import_init_fn] = 0;
7a938933
ILT
343 }
344
c0ccddb4 345 if (imported_init_fns.empty())
7a938933 346 {
c0ccddb4
ILT
347 this->write_c_string(";\n");
348 return;
349 }
350
351 typedef std::map<int, std::vector<std::string> > level_map;
352 Init_graph init_graph;
353 level_map inits_at_level;
354
355 // Walk through the set of import inits (already sorted by
356 // init fcn name) and write them out to the exports.
357 for (Import_init_set::const_iterator p = imported_init_fns.begin();
358 p != imported_init_fns.end();
359 ++p)
360 {
361 const Import_init* ii = *p;
362 this->write_c_string(" ");
363 this->write_string(ii->package_name());
364 this->write_c_string(" ");
365 this->write_string(ii->init_name());
366
367 // Populate init_idx.
368 go_assert(init_idx.find(ii->init_name()) == init_idx.end());
369 unsigned idx = init_idx.size();
370 init_idx[ii->init_name()] = idx;
371
372 // If the init function has a non-negative priority value, this
373 // is an indication that it was referred to in an older version
374 // export data section (e.g. we read a legacy object
375 // file). Record such init fcns so that we can fix up the graph
376 // for them (handled later in this function).
377 if (ii->priority() > 0)
378 {
379 level_map::iterator it = inits_at_level.find(ii->priority());
380 if (it == inits_at_level.end())
381 {
382 std::vector<std::string> l;
383 l.push_back(ii->init_name());
384 inits_at_level[ii->priority()] = l;
385 }
386 else
387 it->second.push_back(ii->init_name());
388 }
389 }
390 this->write_c_string(";\n");
391
392 // Create the init graph. Start by populating the graph with
393 // all the edges we inherited from imported packages.
394 populate_init_graph(&init_graph, imported_init_fns, init_idx);
395
396 // Now add edges from the local init function to each of the
397 // imported fcns.
398 if (!import_init_fn.empty())
399 {
400 unsigned src = 0;
401 go_assert(init_idx[import_init_fn] == 0);
402 for (Import_init_set::const_iterator p = imported_init_fns.begin();
403 p != imported_init_fns.end();
404 ++p)
405 {
406 const Import_init* ii = *p;
407 unsigned sink = init_idx[ii->init_name()];
408 add_init_graph_edge(&init_graph, src, sink);
409 }
410 }
411
412 // In the scenario where one or more of the packages we imported
413 // was written with the legacy export data format, add dummy edges
414 // to capture the priority relationships. Here is a package import
415 // graph as an example:
416 //
417 // *A
418 // /|
419 // / |
420 // B *C
421 // /|
422 // / |
423 // *D *E
424 // | /|
425 // |/ |
426 // *F *G
427 //
428 // Let's suppose that the object for package "C" is from an old
429 // gccgo, e.g. it has the old export data format. All other
430 // packages are compiled with the new compiler and have the new
431 // format. Packages with *'s have init functions. The scenario is
432 // that we're compiling a package "A"; during this process we'll
433 // read the export data for "C". It should look something like
434 //
435 // init F F..import 1 G G..import 1 D D..import 2 E E..import 2;
436 //
437 // To capture this information and convey it to the consumers of
438 // "A", the code below adds edges to the graph from each priority K
439 // function to every priority K-1 function for appropriate values
440 // of K. This will potentially add more edges than we need (for
441 // example, an edge from D to G), but given that we don't expect
442 // to see large numbers of old objects, this will hopefully be OK.
443
444 if (inits_at_level.size() > 0)
445 {
446 for (level_map::reverse_iterator it = inits_at_level.rbegin();
447 it != inits_at_level.rend(); ++it)
448 {
449 int level = it->first;
450 if (level < 2) break;
451 const std::vector<std::string>& fcns_at_level = it->second;
452 for (std::vector<std::string>::const_iterator sit =
453 fcns_at_level.begin();
454 sit != fcns_at_level.end(); ++sit)
455 {
456 unsigned src = init_idx[*sit];
457 level_map::iterator it2 = inits_at_level.find(level - 1);
458 if (it2 != inits_at_level.end())
459 {
460 const std::vector<std::string> fcns_at_lm1 = it2->second;
461 for (std::vector<std::string>::const_iterator mit =
462 fcns_at_lm1.begin();
463 mit != fcns_at_lm1.end(); ++mit)
464 {
465 unsigned sink = init_idx[*mit];
466 add_init_graph_edge(&init_graph, src, sink);
467 }
468 }
469 }
470 }
471 }
472
473 // Write out the resulting graph.
474 this->write_c_string("init_graph");
475 for (Init_graph::const_iterator ki = init_graph.begin();
476 ki != init_graph.end(); ++ki)
477 {
478 unsigned src = ki->first;
479 const std::set<unsigned>& successors = ki->second;
480 for (std::set<unsigned>::const_iterator vi = successors.begin();
481 vi != successors.end(); ++vi)
7a938933
ILT
482 {
483 this->write_c_string(" ");
c0ccddb4
ILT
484 this->write_unsigned(src);
485 unsigned sink = (*vi);
7a938933 486 this->write_c_string(" ");
c0ccddb4 487 this->write_unsigned(sink);
7a938933
ILT
488 }
489 }
7a938933
ILT
490 this->write_c_string(";\n");
491}
492
b2c4b7b9
ILT
493// Write a name to the export stream.
494
495void
496Export::write_name(const std::string& name)
497{
498 if (name.empty())
499 this->write_c_string("?");
500 else
501 this->write_string(Gogo::message_name(name));
502}
503
c0ccddb4
ILT
504// Write an integer value to the export stream.
505
506void
507Export::write_int(int value)
508{
509 char buf[100];
510 snprintf(buf, sizeof buf, "%d", value);
511 this->write_c_string(buf);
512}
513
514// Write an integer value to the export stream.
515
516void
517Export::write_unsigned(unsigned value)
518{
519 char buf[100];
520 snprintf(buf, sizeof buf, "%u", value);
521 this->write_c_string(buf);
522}
523
7a938933
ILT
524// Export a type. We have to ensure that on import we create a single
525// Named_type node for each named type. We do this by keeping a hash
526// table mapping named types to reference numbers. The first time we
527// see a named type we assign it a reference number by making an entry
528// in the hash table. If we see it again, we just refer to the
529// reference number.
530
531// Named types are, of course, associated with packages. Note that we
532// may see a named type when importing one package, and then later see
533// the same named type when importing a different package. The home
534// package may or may not be imported during this compilation. The
535// reference number scheme has to get this all right. Basic approach
536// taken from "On the Linearization of Graphs and Writing Symbol
537// Files" by Robert Griesemer.
538
539void
540Export::write_type(const Type* type)
541{
542 // We don't want to assign a reference number to a forward
543 // declaration to a type which was defined later.
544 type = type->forwarded();
545
546 Type_refs::const_iterator p = this->type_refs_.find(type);
547 if (p != this->type_refs_.end())
548 {
549 // This type was already in the table.
550 int index = p->second;
26409c52 551 go_assert(index != 0);
7a938933
ILT
552 char buf[30];
553 snprintf(buf, sizeof buf, "<type %d>", index);
554 this->write_c_string(buf);
555 return;
556 }
557
558 const Named_type* named_type = type->named_type();
559 const Forward_declaration_type* forward = type->forward_declaration_type();
560
561 int index = this->type_index_;
562 ++this->type_index_;
563
564 char buf[30];
565 snprintf(buf, sizeof buf, "<type %d ", index);
566 this->write_c_string(buf);
567
568 if (named_type != NULL || forward != NULL)
569 {
570 const Named_object* named_object;
571 if (named_type != NULL)
572 {
573 // The builtin types should have been predefined.
8afa2bfb 574 go_assert(!Linemap::is_predeclared_location(named_type->location())
097b12fb 575 || (named_type->named_object()->package()->package_name()
7a938933
ILT
576 == "unsafe"));
577 named_object = named_type->named_object();
578 }
579 else
580 named_object = forward->named_object();
581
582 const Package* package = named_object->package();
583
584 std::string s = "\"";
585 if (package != NULL && !Gogo::is_hidden_name(named_object->name()))
586 {
097b12fb 587 s += package->pkgpath();
7a938933
ILT
588 s += '.';
589 }
590 s += named_object->name();
591 s += "\" ";
592 this->write_string(s);
593
097b12fb
ILT
594 // It is possible that this type was imported indirectly, and is
595 // not in a package in the import list. If we have not
596 // mentioned this package before, write out the package name
597 // here so that any package importing this one will know it.
598 if (package != NULL
599 && this->packages_.find(package) == this->packages_.end())
600 {
601 this->write_c_string("\"");
602 this->write_string(package->package_name());
603 this->packages_.insert(package);
604 this->write_c_string("\" ");
605 }
606
7a938933
ILT
607 // We must add a named type to the table now, since the
608 // definition of the type may refer to the named type via a
609 // pointer.
610 this->type_refs_[type] = index;
611 }
612
613 type->export_type(this);
614
615 this->write_c_string(">");
616
617 if (named_type == NULL)
618 this->type_refs_[type] = index;
619}
620
221b3e6c
ILT
621// Export escape note.
622
623void
624Export::write_escape(std::string* note)
625{
626 if (note != NULL && *note != "esc:0x0")
627 {
628 this->write_c_string(" ");
629 char buf[50];
630 go_assert(note->find("esc:") != std::string::npos);
631 snprintf(buf, sizeof buf, "<%s>", note->c_str());
632 this->write_c_string(buf);
633 }
634}
635
7a938933
ILT
636// Add the builtin types to the export table.
637
638void
639Export::register_builtin_types(Gogo* gogo)
640{
641 this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
642 this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
643 this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
644 this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
645 this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
646 this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
647 this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
648 this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
649 this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
650 this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
651 this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
652 this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
653 this->register_builtin_type(gogo, "int", BUILTIN_INT);
654 this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
655 this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
7a938933
ILT
656 this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
657 this->register_builtin_type(gogo, "string", BUILTIN_STRING);
e4118500 658 this->register_builtin_type(gogo, "error", BUILTIN_ERROR);
fb3f3aa2
ILT
659 this->register_builtin_type(gogo, "byte", BUILTIN_BYTE);
660 this->register_builtin_type(gogo, "rune", BUILTIN_RUNE);
7a938933
ILT
661}
662
663// Register one builtin type in the export table.
664
665void
666Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
667{
668 Named_object* named_object = gogo->lookup_global(name);
26409c52 669 go_assert(named_object != NULL && named_object->is_type());
7a938933
ILT
670 std::pair<Type_refs::iterator, bool> ins =
671 this->type_refs_.insert(std::make_pair(named_object->type_value(), code));
26409c52 672 go_assert(ins.second);
7a938933
ILT
673
674 // We also insert the underlying type. We can see the underlying
fb3f3aa2
ILT
675 // type at least for string and bool. We skip the type aliases byte
676 // and rune here.
677 if (code != BUILTIN_BYTE && code != BUILTIN_RUNE)
678 {
679 Type* real_type = named_object->type_value()->real_type();
680 ins = this->type_refs_.insert(std::make_pair(real_type, code));
681 go_assert(ins.second);
682 }
7a938933
ILT
683}
684
685// Class Export::Stream.
686
687Export::Stream::Stream()
688{
34144b6e
TM
689 this->sha1_helper_ = go_create_sha1_helper();
690 go_assert(this->sha1_helper_ != NULL);
7a938933
ILT
691}
692
693Export::Stream::~Stream()
694{
695}
696
697// Write bytes to the stream. This keeps a checksum of bytes as they
698// go by.
699
700void
701Export::Stream::write_and_sum_bytes(const char* bytes, size_t length)
702{
34144b6e 703 this->sha1_helper_->process_bytes(bytes, length);
7a938933
ILT
704 this->do_write(bytes, length);
705}
706
707// Get the checksum.
708
709std::string
710Export::Stream::checksum()
711{
34144b6e
TM
712 std::string rval = this->sha1_helper_->finish();
713 delete this->sha1_helper_;
714 return rval;
7a938933
ILT
715}
716
717// Write the checksum string to the export data.
718
719void
720Export::Stream::write_checksum(const std::string& s)
721{
722 this->do_write(s.data(), s.length());
723}
724
725// Class Stream_to_section.
726
727Stream_to_section::Stream_to_section()
7a938933
ILT
728{
729}
730
731// Write data to a section.
732
733void
734Stream_to_section::do_write(const char* bytes, size_t length)
735{
76aa42d2 736 go_write_export_data (bytes, length);
7a938933 737}