]>
Commit | Line | Data |
---|---|---|
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 | 21 | const int Export::magic_len; |
7a938933 | 22 | |
c0ccddb4 ILT |
23 | // Current version magic string. |
24 | const 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) |
30 | const char Export::v1_magic[Export::magic_len] = | |
7a938933 ILT |
31 | { |
32 | 'v', '1', ';', '\n' | |
33 | }; | |
34 | ||
c0ccddb4 | 35 | const int Export::checksum_len; |
7a938933 ILT |
36 | |
37 | // Constructor. | |
38 | ||
39 | Export::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 | ||
47 | struct 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 | ||
56 | static bool | |
57 | should_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 | ||
97 | void | |
98 | Export::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 | ||
197 | static bool | |
198 | packages_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 | ||
207 | void | |
208 | Export::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 | ||
239 | static bool | |
240 | import_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 | ||
248 | void | |
249 | Export::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 |
277 | void |
278 | Export::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 | ||
294 | void | |
295 | Export::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 | |
324 | void | |
c0ccddb4 ILT |
325 | Export::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 | ||
495 | void | |
496 | Export::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 | ||
506 | void | |
507 | Export::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 | ||
516 | void | |
517 | Export::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 | ||
539 | void | |
540 | Export::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 | ||
623 | void | |
624 | Export::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 | ||
638 | void | |
639 | Export::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 | ||
665 | void | |
666 | Export::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 | ||
687 | Export::Stream::Stream() | |
688 | { | |
34144b6e TM |
689 | this->sha1_helper_ = go_create_sha1_helper(); |
690 | go_assert(this->sha1_helper_ != NULL); | |
7a938933 ILT |
691 | } |
692 | ||
693 | Export::Stream::~Stream() | |
694 | { | |
695 | } | |
696 | ||
697 | // Write bytes to the stream. This keeps a checksum of bytes as they | |
698 | // go by. | |
699 | ||
700 | void | |
701 | Export::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 | ||
709 | std::string | |
710 | Export::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 | ||
719 | void | |
720 | Export::Stream::write_checksum(const std::string& s) | |
721 | { | |
722 | this->do_write(s.data(), s.length()); | |
723 | } | |
724 | ||
725 | // Class Stream_to_section. | |
726 | ||
727 | Stream_to_section::Stream_to_section() | |
7a938933 ILT |
728 | { |
729 | } | |
730 | ||
731 | // Write data to a section. | |
732 | ||
733 | void | |
734 | Stream_to_section::do_write(const char* bytes, size_t length) | |
735 | { | |
76aa42d2 | 736 | go_write_export_data (bytes, length); |
7a938933 | 737 | } |