blob: 70d3f708d3265fab60b042bb442e8b98b7a2c95a [file] [log] [blame]
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001// 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
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08007#include "go-system.h"
Ian Lance Taylor3f5435d2011-05-27 15:31:49 -07008
Ian Lance Taylor3f5435d2011-05-27 15:31:49 -07009#include "go-c.h"
Ian Lance Taylor015785b2019-05-10 07:40:30 -070010#include "go-diagnostics.h"
11#include "go-sha1.h"
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080012#include "gogo.h"
13#include "types.h"
Ian Lance Taylor37a47e42019-05-17 14:22:41 -070014#include "expressions.h"
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080015#include "statements.h"
16#include "export.h"
Than McIntoshcc602352017-02-06 11:12:12 -050017#include "go-linemap.h"
18#include "backend.h"
19
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080020// This file handles exporting global declarations.
21
22// Class Export.
23
Than McIntosh0e505f52016-08-12 10:23:27 -040024const int Export::magic_len;
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080025
Than McIntosh0e505f52016-08-12 10:23:27 -040026// Current version magic string.
27const char Export::cur_magic[Export::magic_len] =
28 {
Ian Lance Taylor0494dc52018-07-19 15:32:29 -070029 'v', '3', ';', '\n'
Than McIntosh0e505f52016-08-12 10:23:27 -040030 };
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080031
Ian Lance Taylor0494dc52018-07-19 15:32:29 -070032// Magic strings for previous versions (still supported).
Than McIntosh0e505f52016-08-12 10:23:27 -040033const char Export::v1_magic[Export::magic_len] =
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080034 {
35 'v', '1', ';', '\n'
36 };
Ian Lance Taylor0494dc52018-07-19 15:32:29 -070037const char Export::v2_magic[Export::magic_len] =
38 {
39 'v', '2', ';', '\n'
40 };
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080041
Than McIntosh0e505f52016-08-12 10:23:27 -040042const int Export::checksum_len;
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080043
Ian Lance Taylor6db7e352018-10-17 16:28:15 -070044// Type hash table operations, treating aliases as distinct.
45
46class Type_hash_alias_identical
47{
48 public:
49 unsigned int
50 operator()(const Type* type) const
51 {
52 return type->hash_for_method(NULL,
53 (Type::COMPARE_ERRORS
54 | Type::COMPARE_TAGS
Than McIntosh946aa5a2019-03-11 09:57:01 -040055 | Type::COMPARE_EMBEDDED_INTERFACES
Ian Lance Taylor6db7e352018-10-17 16:28:15 -070056 | Type::COMPARE_ALIASES));
57 }
58};
59
60class Type_alias_identical
61{
62 public:
63 bool
64 operator()(const Type* t1, const Type* t2) const
65 {
66 return Type::are_identical(t1, t2,
67 (Type::COMPARE_ERRORS
68 | Type::COMPARE_TAGS
Than McIntosh946aa5a2019-03-11 09:57:01 -040069 | Type::COMPARE_EMBEDDED_INTERFACES
Ian Lance Taylor6db7e352018-10-17 16:28:15 -070070 | Type::COMPARE_ALIASES),
71 NULL);
72 }
73};
74
Than McIntosh1e042a42019-06-27 11:27:10 -040075// Mapping from Type objects to a constant index.
Ian Lance Taylor6db7e352018-10-17 16:28:15 -070076typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical,
Than McIntosh1e042a42019-06-27 11:27:10 -040077 Type_alias_identical) Type_refs;
Ian Lance Taylor6db7e352018-10-17 16:28:15 -070078
Than McIntosh1e042a42019-06-27 11:27:10 -040079// Implementation object for class Export. Hidden implementation avoids
80// having to #include types.h in export.h, or use a static map.
81
82struct Export_impl {
83 Type_refs type_refs;
84};
85
86// Constructor.
87
88Export::Export(Stream* stream)
89 : stream_(stream), type_index_(1), packages_(), impl_(new Export_impl)
90{
91 go_assert(Export::checksum_len == Go_sha1_helper::checksum_len);
92}
93
94// Destructor.
95
96Export::~Export()
97{
98 delete this->impl_;
99}
Ian Lance Taylor6db7e352018-10-17 16:28:15 -0700100
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700101// A traversal class to collect functions and global variables
Than McIntoshaebd2d62019-06-25 18:53:09 -0400102// referenced by inlined functions, and also to gather up
103// referenced types that need to be included in the exports.
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700104
Than McIntoshaebd2d62019-06-25 18:53:09 -0400105class Collect_export_references : public Traverse
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700106{
107 public:
Than McIntoshaebd2d62019-06-25 18:53:09 -0400108 Collect_export_references(Export* exp,
Ian Lance Taylord5d51242021-08-06 12:01:04 -0700109 const std::map<std::string, Package*>& packages,
Than McIntoshaebd2d62019-06-25 18:53:09 -0400110 Unordered_set(Named_object*)* exports,
111 Unordered_set(const Package*)* imports)
112 : Traverse(traverse_expressions
113 | traverse_types),
Ian Lance Taylord5d51242021-08-06 12:01:04 -0700114 exp_(exp), packages_(packages), exports_(exports), imports_(imports),
Than McIntosh19ed7222019-07-12 10:42:48 -0400115 inline_fcn_worklist_(NULL), exports_finalized_(false)
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700116 { }
117
Than McIntoshaebd2d62019-06-25 18:53:09 -0400118 // Initial entry point; performs a walk to expand the exports set.
119 void
120 expand_exports(std::vector<Named_object*>* inlinable_functions);
121
122 // Second entry point (called after the method above), to find
123 // all types referenced by exports.
124 void
Than McIntosh19ed7222019-07-12 10:42:48 -0400125 prepare_types(const std::vector<Named_object*>& sorted_exports);
Than McIntoshaebd2d62019-06-25 18:53:09 -0400126
127 protected:
128 // Override of parent class method.
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700129 int
130 expression(Expression**);
131
Than McIntoshaebd2d62019-06-25 18:53:09 -0400132 // Override of parent class method.
133 int
134 type(Type* type);
135
136 // Traverse the components of a function type.
137 void
138 traverse_function_type(Function_type*);
139
140 // Traverse the methods of a named type, and register its package.
141 void
142 traverse_named_type(Named_type*);
143
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700144 private:
Than McIntosh19ed7222019-07-12 10:42:48 -0400145
146 // Add a named object to the exports set (during expand_exports()).
147 // Returns TRUE if a new object was added to the exports set,
148 // FALSE otherwise.
149 bool
150 add_to_exports(Named_object*);
151
Than McIntoshaebd2d62019-06-25 18:53:09 -0400152 // The exporter.
153 Export* exp_;
Ian Lance Taylord5d51242021-08-06 12:01:04 -0700154 // The list of packages known to this compilation.
155 const std::map<std::string, Package*>& packages_;
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700156 // The set of named objects to export.
157 Unordered_set(Named_object*)* exports_;
Than McIntoshaebd2d62019-06-25 18:53:09 -0400158 // Set containing all directly and indirectly imported packages.
159 Unordered_set(const Package*)* imports_;
160 // Functions we've already traversed and don't need to visit again.
161 Unordered_set(Named_object*) checked_functions_;
162 // Worklist of functions we are exporting with inline bodies that need
163 // to be checked.
164 std::vector<Named_object*>* inline_fcn_worklist_;
Than McIntosh19ed7222019-07-12 10:42:48 -0400165 // Set to true if expand_exports() has been called and is complete.
166 bool exports_finalized_;
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700167};
168
Than McIntoshaebd2d62019-06-25 18:53:09 -0400169void
170Collect_export_references::expand_exports(std::vector<Named_object*>* fcns)
171{
172 this->inline_fcn_worklist_ = fcns;
173 while (!this->inline_fcn_worklist_->empty())
174 {
175 Named_object* no = this->inline_fcn_worklist_->back();
176 this->inline_fcn_worklist_->pop_back();
177 std::pair<Unordered_set(Named_object*)::iterator, bool> ins =
178 this->checked_functions_.insert(no);
179 if (ins.second)
180 {
181 // This traversal may add new objects to this->exports_ and new
182 // functions to this->inline_fcn_worklist_.
183 no->func_value()->block()->traverse(this);
184 }
185 }
186 this->inline_fcn_worklist_ = NULL;
Than McIntosh19ed7222019-07-12 10:42:48 -0400187 this->exports_finalized_ = true;
188}
189
190bool
191Collect_export_references::add_to_exports(Named_object* no)
192{
193 std::pair<Unordered_set(Named_object*)::iterator, bool> ins =
194 this->exports_->insert(no);
195 // If the export list has been finalized, then we should not be
196 // adding anything new to the exports set.
197 go_assert(!this->exports_finalized_ || !ins.second);
198 return ins.second;
Than McIntoshaebd2d62019-06-25 18:53:09 -0400199}
200
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700201int
Than McIntoshaebd2d62019-06-25 18:53:09 -0400202Collect_export_references::expression(Expression** pexpr)
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700203{
204 const Expression* expr = *pexpr;
205
206 const Var_expression* ve = expr->var_expression();
207 if (ve != NULL)
208 {
209 Named_object* no = ve->named_object();
210 if (no->is_variable() && no->var_value()->is_global())
211 {
Than McIntoshaebd2d62019-06-25 18:53:09 -0400212 const Package* var_package = no->package();
213 if (var_package != NULL)
214 this->imports_->insert(var_package);
215
Than McIntosh19ed7222019-07-12 10:42:48 -0400216 this->add_to_exports(no);
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700217 no->var_value()->set_is_referenced_by_inline();
218 }
219 return TRAVERSE_CONTINUE;
220 }
221
222 const Func_expression* fe = expr->func_expression();
223 if (fe != NULL)
224 {
225 Named_object* no = fe->named_object();
Ian Lance Taylor2609f9b2019-06-04 22:22:47 -0700226
Than McIntoshaebd2d62019-06-25 18:53:09 -0400227 const Package* func_package = fe->named_object()->package();
228 if (func_package != NULL)
229 this->imports_->insert(func_package);
230
Ian Lance Taylor2609f9b2019-06-04 22:22:47 -0700231 if (no->is_function_declaration()
232 && no->func_declaration_value()->type()->is_builtin())
233 return TRAVERSE_CONTINUE;
234
Than McIntoshaebd2d62019-06-25 18:53:09 -0400235 if (this->inline_fcn_worklist_ != NULL)
236 {
Than McIntosh19ed7222019-07-12 10:42:48 -0400237 bool added = this->add_to_exports(no);
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700238
Than McIntoshaebd2d62019-06-25 18:53:09 -0400239 if (no->is_function())
240 no->func_value()->set_is_referenced_by_inline();
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700241
Than McIntosh19ed7222019-07-12 10:42:48 -0400242 // If 'added' is false then this object was already in
Than McIntoshaebd2d62019-06-25 18:53:09 -0400243 // exports_, in which case it was already added to
244 // check_inline_refs_ the first time we added it to exports_, so
245 // we don't need to add it again.
Than McIntosh19ed7222019-07-12 10:42:48 -0400246 if (added
Than McIntoshaebd2d62019-06-25 18:53:09 -0400247 && no->is_function()
248 && no->func_value()->export_for_inlining())
249 this->inline_fcn_worklist_->push_back(no);
250 }
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700251
252 return TRAVERSE_CONTINUE;
253 }
254
Than McIntoshddfb8452019-09-30 08:34:56 -0400255 const Named_object* nco = expr->named_constant();
Than McIntosh1e2d98b2019-10-14 09:02:24 -0400256 if (nco != 0)
Than McIntoshddfb8452019-09-30 08:34:56 -0400257 {
258 const Named_constant *nc = nco->const_value();
259 Type::traverse(nc->type(), this);
260 return TRAVERSE_CONTINUE;
261 }
262
Ian Lance Taylord5d51242021-08-06 12:01:04 -0700263 const Call_expression* call = expr->call_expression();
264 if (call != NULL)
265 {
266 const Builtin_call_expression* bce = call->builtin_call_expression();
267 if (bce != NULL
268 && (bce->code() == Builtin_call_expression::BUILTIN_ADD
269 || bce->code() == Builtin_call_expression::BUILTIN_SLICE))
270 {
271 // This is a reference to unsafe.Add or unsafe.Slice. Make
272 // sure we list the "unsafe" package in the imports and give
273 // it a package index.
274 const std::map<std::string, Package*>::const_iterator p =
275 this->packages_.find("unsafe");
276 go_assert(p != this->packages_.end());
277 this->imports_->insert(p->second);
278 }
279 }
280
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700281 return TRAVERSE_CONTINUE;
282}
283
Than McIntoshaebd2d62019-06-25 18:53:09 -0400284// Collect up the set of types mentioned in things we're exporting, and collect
285// all the packages encountered during type traversal, to make sure we can
286// declare things referered to indirectly (for example, in the body of an
287// exported inline function from another package).
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800288
Than McIntoshaebd2d62019-06-25 18:53:09 -0400289void
Than McIntosh19ed7222019-07-12 10:42:48 -0400290Collect_export_references::prepare_types(const std::vector<Named_object*>& sorted_exports)
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800291{
Than McIntoshaebd2d62019-06-25 18:53:09 -0400292 // Iterate through the exported objects and traverse any types encountered.
Than McIntosh19ed7222019-07-12 10:42:48 -0400293 for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin();
294 p != sorted_exports.end();
Than McIntoshaebd2d62019-06-25 18:53:09 -0400295 ++p)
296 {
297 Named_object* no = *p;
298 switch (no->classification())
299 {
300 case Named_object::NAMED_OBJECT_CONST:
301 {
302 Type* t = no->const_value()->type();
303 if (t != NULL && !t->is_abstract())
304 Type::traverse(t, this);
305 }
306 break;
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700307
Than McIntoshaebd2d62019-06-25 18:53:09 -0400308 case Named_object::NAMED_OBJECT_TYPE:
309 Type::traverse(no->type_value()->real_type(), this);
310 this->traverse_named_type(no->type_value());
311 break;
312
313 case Named_object::NAMED_OBJECT_VAR:
314 Type::traverse(no->var_value()->type(), this);
315 break;
316
317 case Named_object::NAMED_OBJECT_FUNC:
318 {
319 Function* fn = no->func_value();
320 this->traverse_function_type(fn->type());
321 if (fn->export_for_inlining())
322 fn->block()->traverse(this);
323 }
324 break;
325
326 case Named_object::NAMED_OBJECT_FUNC_DECLARATION:
327 this->traverse_function_type(no->func_declaration_value()->type());
328 break;
329
330 default:
331 // We shouldn't see anything else. If we do we'll give an
332 // error later when we try to actually export it.
333 break;
334 }
335 }
336}
337
338// Record referenced type, record package imports, and make sure we traverse
339// methods of named types.
340
341int
342Collect_export_references::type(Type* type)
343{
344 // Skip forwarders; don't try to give them a type index.
345 if (type->forward_declaration_type() != NULL)
346 return TRAVERSE_CONTINUE;
347
348 // Skip the void type, which we'll see when exporting
349 // unsafe.Pointer. The void type is not itself exported, because
350 // Pointer_type::do_export checks for it.
351 if (type->is_void_type())
352 return TRAVERSE_SKIP_COMPONENTS;
353
Than McIntoshddfb8452019-09-30 08:34:56 -0400354 // Skip the nil type, turns up in function bodies.
355 if (type->is_nil_type())
356 return TRAVERSE_SKIP_COMPONENTS;
357
Than McIntoshaebd2d62019-06-25 18:53:09 -0400358 // Skip abstract types. We should never see these in real code,
359 // only in things like const declarations.
360 if (type->is_abstract())
361 return TRAVERSE_SKIP_COMPONENTS;
362
Than McIntoshaebd2d62019-06-25 18:53:09 -0400363 if (!this->exp_->record_type(type))
364 {
365 // We've already seen this type.
366 return TRAVERSE_SKIP_COMPONENTS;
367 }
368
369 // At this stage of compilation traversing interface types traverses
370 // the final list of methods, but we export the locally defined
371 // methods. If there is an embedded interface type we need to make
372 // sure to export that. Check classification, rather than calling
373 // the interface_type method, because we want to handle named types
374 // below.
375 if (type->classification() == Type::TYPE_INTERFACE)
376 {
377 Interface_type* it = type->interface_type();
378 const Typed_identifier_list* methods = it->local_methods();
379 if (methods != NULL)
380 {
381 for (Typed_identifier_list::const_iterator p = methods->begin();
382 p != methods->end();
383 ++p)
384 {
385 if (p->name().empty())
386 Type::traverse(p->type(), this);
387 else
388 this->traverse_function_type(p->type()->function_type());
389 }
390 }
391 return TRAVERSE_SKIP_COMPONENTS;
392 }
393
394 Named_type* nt = type->named_type();
395 if (nt != NULL)
396 this->traverse_named_type(nt);
397
398 return TRAVERSE_CONTINUE;
399}
400
401void
402Collect_export_references::traverse_named_type(Named_type* nt)
403{
404 const Package* package = nt->named_object()->package();
405 if (package != NULL)
406 this->imports_->insert(package);
407
408 // We have to traverse the methods of named types, because we are
409 // going to export them. This is not done by ordinary type
410 // traversal.
411 const Bindings* methods = nt->local_methods();
412 if (methods != NULL)
413 {
414 for (Bindings::const_definitions_iterator pm =
415 methods->begin_definitions();
416 pm != methods->end_definitions();
417 ++pm)
418 {
419 Function* fn = (*pm)->func_value();
420 this->traverse_function_type(fn->type());
421 if (fn->export_for_inlining())
422 fn->block()->traverse(this);
423 }
424
425 for (Bindings::const_declarations_iterator pm =
426 methods->begin_declarations();
427 pm != methods->end_declarations();
428 ++pm)
429 {
430 Named_object* mno = pm->second;
431 if (mno->is_function_declaration())
432 this->traverse_function_type(mno->func_declaration_value()->type());
433 }
434 }
435}
436
437// Traverse the types in a function type. We don't need the function
438// type itself, just the receiver, parameter, and result types.
439
440void
441Collect_export_references::traverse_function_type(Function_type* type)
442{
443 go_assert(type != NULL);
444 if (this->remember_type(type))
445 return;
446 const Typed_identifier* receiver = type->receiver();
447 if (receiver != NULL)
448 Type::traverse(receiver->type(), this);
449 const Typed_identifier_list* parameters = type->parameters();
450 if (parameters != NULL)
451 parameters->traverse(this);
452 const Typed_identifier_list* results = type->results();
453 if (results != NULL)
454 results->traverse(this);
455}
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800456
457// Return true if we should export NO.
458
459static bool
460should_export(Named_object* no)
461{
462 // We only export objects which are locally defined.
463 if (no->package() != NULL)
464 return false;
465
466 // We don't export packages.
467 if (no->is_package())
468 return false;
469
470 // We don't export hidden names.
471 if (Gogo::is_hidden_name(no->name()))
472 return false;
473
Ian Lance Taylore1dc92a2018-10-18 16:15:45 -0700474 // We don't export various special functions.
Ian Lance Taylorb483d0e2020-11-16 20:06:53 -0800475 if (Gogo::special_name_pos(no->name()) != std::string::npos)
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800476 return false;
477
478 // Methods are exported with the type, not here.
479 if (no->is_function()
480 && no->func_value()->type()->is_method())
481 return false;
482 if (no->is_function_declaration()
483 && no->func_declaration_value()->type()->is_method())
484 return false;
485
486 // Don't export dummy global variables created for initializers when
487 // used with sinks.
488 if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.')
489 return false;
490
491 return true;
492}
493
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700494// Compare Typed_identifier_list's.
495
496static int
497compare_til(const Typed_identifier_list*, const Typed_identifier_list*);
498
Than McIntoshaebd2d62019-06-25 18:53:09 -0400499// A functor to sort Named_object pointers by name.
500
501struct Sort_bindings
502{
503 bool
504 operator()(const Named_object* n1, const Named_object* n2) const
505 {
506 if (n1->package() != n2->package())
507 {
508 if (n1->package() == NULL)
509 return true;
510 if (n2->package() == NULL)
511 return false;
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700512
513 // Make sure we don't see the same pkgpath twice.
514 const std::string& p1(n1->package()->pkgpath());
515 const std::string& p2(n2->package()->pkgpath());
516 go_assert(p1 != p2);
517
518 return p1 < p2;
Than McIntoshaebd2d62019-06-25 18:53:09 -0400519 }
520
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700521 if (n1->name() != n2->name())
522 return n1->name() < n2->name();
523
524 // We shouldn't see the same name twice, but it can happen for
525 // nested type names.
526
527 go_assert(n1->is_type() && n2->is_type());
528
529 unsigned int ind1;
530 const Named_object* g1 = n1->type_value()->in_function(&ind1);
531 unsigned int ind2;
532 const Named_object* g2 = n2->type_value()->in_function(&ind2);
533
534 if (g1 == NULL)
535 {
536 go_assert(g2 != NULL);
537 return true;
538 }
539 else if (g2 == NULL)
540 return false;
541 else if (g1 == g2)
542 {
543 go_assert(ind1 != ind2);
544 return ind1 < ind2;
545 }
546 else if ((g1->package() != g2->package()) || (g1->name() != g2->name()))
547 return Sort_bindings()(g1, g2);
548 else
549 {
550 // This case can happen if g1 or g2 is a method.
551 if (g1 != NULL && g1->func_value()->is_method())
552 {
553 const Typed_identifier* r = g1->func_value()->type()->receiver();
554 g1 = r->type()->named_type()->named_object();
555 }
556 if (g2 != NULL && g2->func_value()->is_method())
557 {
558 const Typed_identifier* r = g2->func_value()->type()->receiver();
559 g2 = r->type()->named_type()->named_object();
560 }
561 return Sort_bindings()(g1, g2);
562 }
Than McIntoshaebd2d62019-06-25 18:53:09 -0400563 }
564};
565
566// A functor to sort types for export.
567
568struct Sort_types
569{
570 bool
571 operator()(const Type* t1, const Type* t2) const
572 {
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700573 t1 = t1->forwarded();
574 t2 = t2->forwarded();
575
Than McIntoshaebd2d62019-06-25 18:53:09 -0400576 const Named_type* nt1 = t1->named_type();
577 const Named_type* nt2 = t2->named_type();
578 if (nt1 != NULL)
579 {
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700580 if (nt2 != NULL)
581 {
582 Sort_bindings sb;
583 return sb(nt1->named_object(), nt2->named_object());
584 }
585 else
586 return true;
Than McIntoshaebd2d62019-06-25 18:53:09 -0400587 }
588 else if (nt2 != NULL)
589 return false;
590 if (t1->classification() != t2->classification())
591 return t1->classification() < t2->classification();
592 Gogo* gogo = go_get_gogo();
Ian Lance Taylorb483d0e2020-11-16 20:06:53 -0800593 Backend_name b1;
594 gogo->type_descriptor_backend_name(t1, NULL, &b1);
595 Backend_name b2;
596 gogo->type_descriptor_backend_name(t2, NULL, &b2);
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700597
598 std::string n1 = b1.name();
599 std::string n2 = b2.name();
600 if (n1 != n2)
601 return n1 < n2;
602
603 // We should never see equal types here. If we do, we may not
604 // generate an identical output file for identical input. But the
605 // backend names can be equal because we want to treat aliases
606 // differently while type_descriptor_backend_name does not. In
607 // that case we need to traverse the type elements.
608
609 // t1 == t2 in case std::sort compares elements to themselves.
610 if (t1 == t2)
611 return false;
612
613 Sort_types sort;
614 Type_alias_identical identical;
615 go_assert(!identical(t1, t2));
616
617 switch (t1->classification())
618 {
619 case Type::TYPE_ERROR:
620 return false;
621
622 case Type::TYPE_VOID:
623 case Type::TYPE_BOOLEAN:
624 case Type::TYPE_INTEGER:
625 case Type::TYPE_FLOAT:
626 case Type::TYPE_COMPLEX:
627 case Type::TYPE_STRING:
628 case Type::TYPE_SINK:
629 case Type::TYPE_NIL:
630 case Type::TYPE_CALL_MULTIPLE_RESULT:
631 case Type::TYPE_NAMED:
632 case Type::TYPE_FORWARD:
633 default:
634 go_unreachable();
635
636 case Type::TYPE_FUNCTION:
637 {
638 const Function_type* ft1 = t1->function_type();
639 const Function_type* ft2 = t2->function_type();
640 const Typed_identifier* r1 = ft1->receiver();
641 const Typed_identifier* r2 = ft2->receiver();
642 if (r1 == NULL)
643 go_assert(r2 == NULL);
644 else
645 {
646 go_assert(r2 != NULL);
647 const Type* rt1 = r1->type()->forwarded();
648 const Type* rt2 = r2->type()->forwarded();
649 if (!identical(rt1, rt2))
650 return sort(rt1, rt2);
651 }
652
653 const Typed_identifier_list* p1 = ft1->parameters();
654 const Typed_identifier_list* p2 = ft2->parameters();
655 if (p1 == NULL || p1->empty())
656 go_assert(p2 == NULL || p2->empty());
657 else
658 {
659 go_assert(p2 != NULL && !p2->empty());
660 int i = compare_til(p1, p2);
661 if (i < 0)
662 return false;
663 else if (i > 0)
664 return true;
665 }
666
667 p1 = ft1->results();
668 p2 = ft2->results();
669 if (p1 == NULL || p1->empty())
670 go_assert(p2 == NULL || p2->empty());
671 else
672 {
673 go_assert(p2 != NULL && !p2->empty());
674 int i = compare_til(p1, p2);
675 if (i < 0)
676 return false;
677 else if (i > 0)
678 return true;
679 }
680
681 go_unreachable();
682 }
683
684 case Type::TYPE_POINTER:
685 {
686 const Type* p1 = t1->points_to()->forwarded();
687 const Type* p2 = t2->points_to()->forwarded();
688 go_assert(!identical(p1, p2));
689 return sort(p1, p2);
690 }
691
692 case Type::TYPE_STRUCT:
693 {
694 const Struct_type* s1 = t1->struct_type();
695 const Struct_type* s2 = t2->struct_type();
696 const Struct_field_list* f1 = s1->fields();
697 const Struct_field_list* f2 = s2->fields();
698 go_assert(f1 != NULL && f2 != NULL);
699 Struct_field_list::const_iterator p1 = f1->begin();
700 Struct_field_list::const_iterator p2 = f2->begin();
701 for (; p2 != f2->end(); ++p1, ++p2)
702 {
703 go_assert(p1 != f1->end());
704 go_assert(p1->field_name() == p2->field_name());
705 go_assert(p1->is_anonymous() == p2->is_anonymous());
706 const Type* ft1 = p1->type()->forwarded();
707 const Type* ft2 = p2->type()->forwarded();
708 if (!identical(ft1, ft2))
709 return sort(ft1, ft2);
710 }
711 go_assert(p1 == f1->end());
712 go_unreachable();
713 }
714
715 case Type::TYPE_ARRAY:
716 {
717 const Type* e1 = t1->array_type()->element_type()->forwarded();
718 const Type* e2 = t2->array_type()->element_type()->forwarded();
719 go_assert(!identical(e1, e2));
720 return sort(e1, e2);
721 }
722
723 case Type::TYPE_MAP:
724 {
725 const Map_type* m1 = t1->map_type();
726 const Map_type* m2 = t2->map_type();
727 const Type* k1 = m1->key_type()->forwarded();
728 const Type* k2 = m2->key_type()->forwarded();
729 if (!identical(k1, k2))
730 return sort(k1, k2);
731 const Type* v1 = m1->val_type()->forwarded();
732 const Type* v2 = m2->val_type()->forwarded();
733 go_assert(!identical(v1, v2));
734 return sort(v1, v2);
735 }
736
737 case Type::TYPE_CHANNEL:
738 {
739 const Type* e1 = t1->channel_type()->element_type()->forwarded();
740 const Type* e2 = t2->channel_type()->element_type()->forwarded();
741 go_assert(!identical(e1, e2));
742 return sort(e1, e2);
743 }
744
745 case Type::TYPE_INTERFACE:
746 {
747 const Interface_type* it1 = t1->interface_type();
748 const Interface_type* it2 = t2->interface_type();
749 const Typed_identifier_list* m1 = it1->local_methods();
750 const Typed_identifier_list* m2 = it2->local_methods();
751
752 // We know the full method lists are the same, because the
753 // mangled type names were the same, but here we are looking
754 // at the local method lists, which include embedded
755 // interfaces, and we can have an embedded empty interface.
756 if (m1 == NULL || m1->empty())
757 {
758 go_assert(m2 != NULL && !m2->empty());
759 return true;
760 }
761 else if (m2 == NULL || m2->empty())
762 {
763 go_assert(m1 != NULL && !m1->empty());
764 return false;
765 }
766
767 int i = compare_til(m1, m2);
768 if (i < 0)
769 return false;
770 else if (i > 0)
771 return true;
772 else
773 go_unreachable();
774 }
775 }
Than McIntoshaebd2d62019-06-25 18:53:09 -0400776 }
777};
778
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700779// Compare Typed_identifier_list's with Sort_types, returning -1, 0, +1.
780
781static int
782compare_til(
783 const Typed_identifier_list* til1,
784 const Typed_identifier_list* til2)
785{
786 Type_alias_identical identical;
787 Sort_types sort;
788 Typed_identifier_list::const_iterator p1 = til1->begin();
789 Typed_identifier_list::const_iterator p2 = til2->begin();
790 for (; p2 != til2->end(); ++p1, ++p2)
791 {
792 if (p1 == til1->end())
793 return -1;
794 const Type* t1 = p1->type()->forwarded();
795 const Type* t2 = p2->type()->forwarded();
796 if (!identical(t1, t2))
797 {
798 if (sort(t1, t2))
799 return -1;
800 else
801 return +1;
802 }
803 }
804 if (p1 != til1->end())
805 return +1;
806 return 0;
807}
808
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800809// Export those identifiers marked for exporting.
810
811void
812Export::export_globals(const std::string& package_name,
Ian Lance Taylorc0295932015-01-29 16:35:18 -0800813 const std::string& prefix,
Ian Lance Taylor4832fd62012-05-09 13:50:49 -0700814 const std::string& pkgpath,
Ian Lance Taylor0c90c642015-01-30 07:56:16 -0800815 const std::map<std::string, Package*>& packages,
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -0800816 const std::map<std::string, Package*>& imports,
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800817 const std::string& import_init_fn,
Than McIntosh0e505f52016-08-12 10:23:27 -0400818 const Import_init_set& imported_init_fns,
Than McIntosh19ed7222019-07-12 10:42:48 -0400819 const Bindings* bindings,
820 Unordered_set(Named_object*)* functions_marked_inline)
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800821{
822 // If there have been any errors so far, don't try to export
823 // anything. That way the export code doesn't have to worry about
824 // mismatched types or other confusions.
Ian Lance Taylor4ab7af22010-02-04 21:25:40 -0800825 if (saw_errors())
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800826 return;
827
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700828 // EXPORTS is the set of objects to export. CHECK_INLINE_REFS is a
829 // list of exported function with inline bodies that need to be
830 // checked for references to other objects. Every function on
831 // CHECK_INLINE_REFS is also on EXPORTS.
832 Unordered_set(Named_object*) exports;
833 std::vector<Named_object*> check_inline_refs;
Than McIntosh19ed7222019-07-12 10:42:48 -0400834 check_inline_refs.reserve(functions_marked_inline->size());
835
836 // Add all functions/methods from the "marked inlined" set to the
837 // CHECK_INLINE_REFS worklist.
838 for (Unordered_set(Named_object*)::const_iterator p = functions_marked_inline->begin();
839 p != functions_marked_inline->end();
840 ++p)
841 check_inline_refs.push_back(*p);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800842
843 for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
844 p != bindings->end_definitions();
845 ++p)
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700846 {
847 if (should_export(*p))
Than McIntosh19ed7222019-07-12 10:42:48 -0400848 exports.insert(*p);
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700849 }
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800850
851 for (Bindings::const_declarations_iterator p =
852 bindings->begin_declarations();
853 p != bindings->end_declarations();
854 ++p)
855 {
856 // We export a function declaration as it may be implemented in
857 // supporting C code. We do not export type declarations.
858 if (p->second->is_function_declaration()
859 && should_export(p->second))
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700860 exports.insert(p->second);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800861 }
862
Ian Lance Taylor2609f9b2019-06-04 22:22:47 -0700863 // Track all imported packages mentioned in export data.
864 Unordered_set(const Package*) all_imports;
865
Ian Lance Taylord5d51242021-08-06 12:01:04 -0700866 Collect_export_references collect(this, packages, &exports, &all_imports);
Than McIntoshaebd2d62019-06-25 18:53:09 -0400867
868 // Walk the set of inlinable routine bodies collected above. This
869 // can potentially expand the exports set.
870 collect.expand_exports(&check_inline_refs);
871
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700872 // Export the symbols in sorted order. That will reduce cases where
873 // irrelevant changes to the source code affect the exported
874 // interface.
875 std::vector<Named_object*> sorted_exports;
876 sorted_exports.reserve(exports.size());
877
878 for (Unordered_set(Named_object*)::const_iterator p = exports.begin();
879 p != exports.end();
880 ++p)
Ian Lance Taylor2609f9b2019-06-04 22:22:47 -0700881 {
882 sorted_exports.push_back(*p);
883
884 const Package* pkg = (*p)->package();
885 if (pkg != NULL)
886 all_imports.insert(pkg);
887 }
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700888
889 std::sort(sorted_exports.begin(), sorted_exports.end(), Sort_bindings());
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800890
Than McIntoshaebd2d62019-06-25 18:53:09 -0400891 // Collect up the set of types mentioned in things we're exporting,
892 // and any packages that may be referred to indirectly.
Than McIntosh19ed7222019-07-12 10:42:48 -0400893 collect.prepare_types(sorted_exports);
Than McIntoshaebd2d62019-06-25 18:53:09 -0400894
Ian Lance Taylor6db7e352018-10-17 16:28:15 -0700895 // Assign indexes to all exported types and types referenced by
Than McIntoshaebd2d62019-06-25 18:53:09 -0400896 // things we're exporting. Return value is index of first non-exported
897 // type.
898 int unexported_type_index = this->assign_type_indices(sorted_exports);
Ian Lance Taylor9c985ce2018-10-05 10:09:07 -0700899
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800900 // Although the export data is readable, at least this version is,
901 // it is conceptually a binary format. Start with a four byte
Than McIntosh0e505f52016-08-12 10:23:27 -0400902 // version number.
903 this->write_bytes(Export::cur_magic, Export::magic_len);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800904
905 // The package name.
906 this->write_c_string("package ");
907 this->write_string(package_name);
Ian Lance Taylor0494dc52018-07-19 15:32:29 -0700908 this->write_c_string("\n");
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800909
Ian Lance Taylorc0295932015-01-29 16:35:18 -0800910 // The prefix or package path, used for all global symbols.
911 if (prefix.empty())
912 {
913 go_assert(!pkgpath.empty());
914 this->write_c_string("pkgpath ");
915 this->write_string(pkgpath);
916 }
917 else
918 {
919 this->write_c_string("prefix ");
920 this->write_string(prefix);
921 }
Ian Lance Taylor0494dc52018-07-19 15:32:29 -0700922 this->write_c_string("\n");
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800923
Ian Lance Taylor0c90c642015-01-30 07:56:16 -0800924 this->write_packages(packages);
925
Ian Lance Taylor2609f9b2019-06-04 22:22:47 -0700926 this->write_imports(imports, all_imports);
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -0800927
Than McIntosh0e505f52016-08-12 10:23:27 -0400928 this->write_imported_init_fns(package_name, import_init_fn,
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800929 imported_init_fns);
930
931 // FIXME: It might be clever to add something about the processor
932 // and ABI being used, although ideally any problems in that area
933 // would be caught by the linker.
934
Ian Lance Taylor6db7e352018-10-17 16:28:15 -0700935 // Write out all the types, both exported and not.
936 this->write_types(unexported_type_index);
937
938 // Write out the non-type export data.
Ian Lance Taylor37a47e42019-05-17 14:22:41 -0700939 for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin();
940 p != sorted_exports.end();
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800941 ++p)
Ian Lance Taylor6db7e352018-10-17 16:28:15 -0700942 {
943 if (!(*p)->is_type())
944 (*p)->export_named_object(this);
945 }
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800946
947 std::string checksum = this->stream_->checksum();
948 std::string s = "checksum ";
949 for (std::string::const_iterator p = checksum.begin();
950 p != checksum.end();
951 ++p)
952 {
953 unsigned char c = *p;
954 unsigned int dig = c >> 4;
955 s += dig < 10 ? '0' + dig : 'A' + dig - 10;
956 dig = c & 0xf;
957 s += dig < 10 ? '0' + dig : 'A' + dig - 10;
958 }
Ian Lance Taylor0494dc52018-07-19 15:32:29 -0700959 s += "\n";
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800960 this->stream_->write_checksum(s);
961}
962
Than McIntoshaebd2d62019-06-25 18:53:09 -0400963// Record a type in the "to be indexed" set. Return true if the type
964// was not already in the set, false otherwise.
Ian Lance Taylor6db7e352018-10-17 16:28:15 -0700965
966bool
Than McIntoshaebd2d62019-06-25 18:53:09 -0400967Export::record_type(Type* type)
Ian Lance Taylor6db7e352018-10-17 16:28:15 -0700968{
969 type = type->forwarded();
Ian Lance Taylor6db7e352018-10-17 16:28:15 -0700970 std::pair<Type_refs::iterator, bool> ins =
Than McIntosh1e042a42019-06-27 11:27:10 -0400971 this->impl_->type_refs.insert(std::make_pair(type, 0));
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700972 return ins.second;
Ian Lance Taylor9c985ce2018-10-05 10:09:07 -0700973}
974
Than McIntoshaebd2d62019-06-25 18:53:09 -0400975// Assign the specified type an index.
976
977void
978Export::set_type_index(const Type* type)
979{
980 type = type->forwarded();
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700981 Type_refs::iterator p = this->impl_->type_refs.find(type);
982 go_assert(p != this->impl_->type_refs.end());
Than McIntoshaebd2d62019-06-25 18:53:09 -0400983 int index = this->type_index_;
984 ++this->type_index_;
Ian Lance Taylorf5bc28a2022-05-11 19:23:01 -0700985 go_assert(p->second == 0);
986 p->second = index;
Than McIntoshaebd2d62019-06-25 18:53:09 -0400987}
988
989// This helper assigns type indices to all types mentioned directly or
990// indirectly in the things we're exporting. Actual exported types are given
991// indices according to where the appear on the sorted exports list; all other
992// types appear afterwards. Return value is the total number of exported types
993// plus 1, e.g. the index of the 1st non-exported type.
994
995int
996Export::assign_type_indices(const std::vector<Named_object*>& sorted_exports)
997{
998 // Assign indexes to all the exported types.
999 for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin();
1000 p != sorted_exports.end();
1001 ++p)
1002 {
1003 if (!(*p)->is_type())
1004 continue;
Than McIntoshaebd2d62019-06-25 18:53:09 -04001005 this->record_type((*p)->type_value());
1006 this->set_type_index((*p)->type_value());
1007 }
1008 int ret = this->type_index_;
1009
1010 // Collect export-referenced, non-builtin types.
1011 std::vector<const Type*> types;
1012 types.reserve(this->impl_->type_refs.size());
1013 for (Type_refs::const_iterator p = this->impl_->type_refs.begin();
1014 p != this->impl_->type_refs.end();
1015 ++p)
1016 {
1017 const Type* t = p->first;
1018 if (p->second != 0)
1019 continue;
1020 types.push_back(t);
1021 }
1022
1023 // Sort the types.
1024 std::sort(types.begin(), types.end(), Sort_types());
1025
1026 // Assign numbers to the sorted list.
1027 for (std::vector<const Type *>::const_iterator p = types.begin();
1028 p != types.end();
1029 ++p)
1030 this->set_type_index((*p));
1031
1032 return ret;
1033}
1034
Ian Lance Taylor0c90c642015-01-30 07:56:16 -08001035// Sort packages.
1036
1037static bool
1038packages_compare(const Package* a, const Package* b)
1039{
Ian Lance Taylor88224872019-04-08 17:26:29 -07001040 if (a->package_name() < b->package_name())
1041 return true;
1042 else if (a->package_name() > b->package_name())
1043 return false;
1044
1045 if (a->pkgpath() < b->pkgpath())
1046 return true;
1047 else if (a->pkgpath() > b->pkgpath())
1048 return false;
1049
1050 // In principle if we get here then a == b. Try to do something sensible
1051 // even if the import information is inconsistent.
1052 if (a->pkgpath_symbol() < b->pkgpath_symbol())
1053 return true;
1054 else if (a->pkgpath_symbol() > b->pkgpath_symbol())
1055 return false;
1056
1057 return a < b;
Ian Lance Taylor0c90c642015-01-30 07:56:16 -08001058}
1059
1060// Write out all the known packages whose pkgpath symbol is not a
1061// simple transformation of the pkgpath, so that the importing code
1062// can reliably know it.
1063
1064void
1065Export::write_packages(const std::map<std::string, Package*>& packages)
1066{
1067 // Sort for consistent output.
1068 std::vector<Package*> out;
1069 for (std::map<std::string, Package*>::const_iterator p = packages.begin();
1070 p != packages.end();
1071 ++p)
1072 {
1073 if (p->second->pkgpath_symbol()
1074 != Gogo::pkgpath_for_symbol(p->second->pkgpath()))
1075 out.push_back(p->second);
1076 }
1077
1078 std::sort(out.begin(), out.end(), packages_compare);
1079
1080 for (std::vector<Package*>::const_iterator p = out.begin();
1081 p != out.end();
1082 ++p)
1083 {
1084 this->write_c_string("package ");
1085 this->write_string((*p)->package_name());
1086 this->write_c_string(" ");
1087 this->write_string((*p)->pkgpath());
1088 this->write_c_string(" ");
1089 this->write_string((*p)->pkgpath_symbol());
Ian Lance Taylor0494dc52018-07-19 15:32:29 -07001090 this->write_c_string("\n");
Ian Lance Taylor0c90c642015-01-30 07:56:16 -08001091 }
1092}
1093
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001094// Sort imported packages.
1095
1096static bool
1097import_compare(const std::pair<std::string, Package*>& a,
1098 const std::pair<std::string, Package*>& b)
1099{
1100 return a.first < b.first;
1101}
1102
1103// Write out the imported packages.
1104
1105void
Ian Lance Taylor9c985ce2018-10-05 10:09:07 -07001106Export::write_imports(const std::map<std::string, Package*>& imports,
Ian Lance Taylor2609f9b2019-06-04 22:22:47 -07001107 const Unordered_set(const Package*)& all_imports)
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001108{
1109 // Sort the imports for more consistent output.
Ian Lance Taylor9c985ce2018-10-05 10:09:07 -07001110 Unordered_set(const Package*) seen;
Than McIntosh0e505f52016-08-12 10:23:27 -04001111 std::vector<std::pair<std::string, Package*> > sorted_imports;
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001112 for (std::map<std::string, Package*>::const_iterator p = imports.begin();
1113 p != imports.end();
1114 ++p)
Ian Lance Taylor9c985ce2018-10-05 10:09:07 -07001115 {
1116 sorted_imports.push_back(std::make_pair(p->first, p->second));
1117 seen.insert(p->second);
1118 }
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001119
Than McIntosh0e505f52016-08-12 10:23:27 -04001120 std::sort(sorted_imports.begin(), sorted_imports.end(), import_compare);
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001121
Ian Lance Taylor37a47e42019-05-17 14:22:41 -07001122 int package_index = 1;
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001123 for (std::vector<std::pair<std::string, Package*> >::const_iterator p =
Than McIntosh0e505f52016-08-12 10:23:27 -04001124 sorted_imports.begin();
1125 p != sorted_imports.end();
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001126 ++p)
1127 {
1128 this->write_c_string("import ");
Ian Lance Taylor4832fd62012-05-09 13:50:49 -07001129 this->write_string(p->second->package_name());
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001130 this->write_c_string(" ");
Ian Lance Taylor4832fd62012-05-09 13:50:49 -07001131 this->write_string(p->second->pkgpath());
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001132 this->write_c_string(" \"");
1133 this->write_string(p->first);
Ian Lance Taylor0494dc52018-07-19 15:32:29 -07001134 this->write_c_string("\"\n");
Ian Lance Taylor4832fd62012-05-09 13:50:49 -07001135
Ian Lance Taylor37a47e42019-05-17 14:22:41 -07001136 this->packages_[p->second] = package_index;
1137 package_index++;
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001138 }
Ian Lance Taylor9c985ce2018-10-05 10:09:07 -07001139
1140 // Write out a separate list of indirectly imported packages.
1141 std::vector<const Package*> indirect_imports;
1142 for (Unordered_set(const Package*)::const_iterator p =
Ian Lance Taylor2609f9b2019-06-04 22:22:47 -07001143 all_imports.begin();
1144 p != all_imports.end();
Ian Lance Taylor9c985ce2018-10-05 10:09:07 -07001145 ++p)
1146 {
1147 if (seen.find(*p) == seen.end())
1148 indirect_imports.push_back(*p);
1149 }
1150
1151 std::sort(indirect_imports.begin(), indirect_imports.end(),
1152 packages_compare);
1153
1154 for (std::vector<const Package*>::const_iterator p =
1155 indirect_imports.begin();
1156 p != indirect_imports.end();
1157 ++p)
1158 {
1159 this->write_c_string("indirectimport ");
1160 this->write_string((*p)->package_name());
1161 this->write_c_string(" ");
1162 this->write_string((*p)->pkgpath());
1163 this->write_c_string("\n");
Ian Lance Taylor37a47e42019-05-17 14:22:41 -07001164
1165 this->packages_[*p] = package_index;
1166 package_index++;
Ian Lance Taylor9c985ce2018-10-05 10:09:07 -07001167 }
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001168}
1169
Than McIntosh0e505f52016-08-12 10:23:27 -04001170void
1171Export::add_init_graph_edge(Init_graph* init_graph, unsigned src, unsigned sink)
1172{
1173 Init_graph::iterator it = init_graph->find(src);
1174 if (it != init_graph->end())
1175 it->second.insert(sink);
1176 else
1177 {
1178 std::set<unsigned> succs;
1179 succs.insert(sink);
1180 (*init_graph)[src] = succs;
1181 }
1182}
1183
1184// Constructs the imported portion of the init graph, e.g. those
1185// edges that we read from imported packages.
1186
1187void
1188Export::populate_init_graph(Init_graph* init_graph,
1189 const Import_init_set& imported_init_fns,
1190 const std::map<std::string, unsigned>& init_idx)
1191{
1192 for (Import_init_set::const_iterator p = imported_init_fns.begin();
1193 p != imported_init_fns.end();
1194 ++p)
1195 {
1196 const Import_init* ii = *p;
Cherry Zhangae7d7e02019-07-02 15:05:45 -04001197 if (ii->is_dummy())
1198 continue;
Than McIntosh0e505f52016-08-12 10:23:27 -04001199 std::map<std::string, unsigned>::const_iterator srcit =
1200 init_idx.find(ii->init_name());
1201 go_assert(srcit != init_idx.end());
1202 unsigned src = srcit->second;
1203 for (std::set<std::string>::const_iterator pci = ii->precursors().begin();
1204 pci != ii->precursors().end();
1205 ++pci)
1206 {
1207 std::map<std::string, unsigned>::const_iterator it =
1208 init_idx.find(*pci);
1209 go_assert(it != init_idx.end());
1210 unsigned sink = it->second;
1211 add_init_graph_edge(init_graph, src, sink);
1212 }
1213 }
1214}
1215
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001216// Write out the initialization functions which need to run for this
1217// package.
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001218
1219void
Than McIntosh0e505f52016-08-12 10:23:27 -04001220Export::write_imported_init_fns(const std::string& package_name,
1221 const std::string& import_init_fn,
1222 const Import_init_set& imported_init_fns)
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001223{
Than McIntosh0e505f52016-08-12 10:23:27 -04001224 if (import_init_fn.empty() && imported_init_fns.empty()) return;
1225
1226 // Maps a given init function to the its index in the exported "init" clause.
1227 std::map<std::string, unsigned> init_idx;
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001228
Ian Lance Taylor5f856ba2012-02-17 15:19:05 -08001229 this->write_c_string("init");
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001230
1231 if (!import_init_fn.empty())
1232 {
1233 this->write_c_string(" ");
1234 this->write_string(package_name);
1235 this->write_c_string(" ");
1236 this->write_string(import_init_fn);
Than McIntosh0e505f52016-08-12 10:23:27 -04001237 init_idx[import_init_fn] = 0;
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001238 }
1239
Than McIntosh0e505f52016-08-12 10:23:27 -04001240 if (imported_init_fns.empty())
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001241 {
Ian Lance Taylor0494dc52018-07-19 15:32:29 -07001242 this->write_c_string("\n");
Than McIntosh0e505f52016-08-12 10:23:27 -04001243 return;
1244 }
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001245
Than McIntosh0e505f52016-08-12 10:23:27 -04001246 typedef std::map<int, std::vector<std::string> > level_map;
1247 Init_graph init_graph;
1248 level_map inits_at_level;
1249
1250 // Walk through the set of import inits (already sorted by
1251 // init fcn name) and write them out to the exports.
1252 for (Import_init_set::const_iterator p = imported_init_fns.begin();
1253 p != imported_init_fns.end();
1254 ++p)
1255 {
1256 const Import_init* ii = *p;
Ian Lance Taylor7b0ddaa2017-03-23 09:57:01 -07001257
1258 if (ii->init_name() == import_init_fn)
1259 continue;
1260
Than McIntosh0e505f52016-08-12 10:23:27 -04001261 this->write_c_string(" ");
1262 this->write_string(ii->package_name());
1263 this->write_c_string(" ");
1264 this->write_string(ii->init_name());
1265
1266 // Populate init_idx.
1267 go_assert(init_idx.find(ii->init_name()) == init_idx.end());
1268 unsigned idx = init_idx.size();
1269 init_idx[ii->init_name()] = idx;
1270
1271 // If the init function has a non-negative priority value, this
1272 // is an indication that it was referred to in an older version
1273 // export data section (e.g. we read a legacy object
1274 // file). Record such init fcns so that we can fix up the graph
1275 // for them (handled later in this function).
1276 if (ii->priority() > 0)
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001277 {
Than McIntosh0e505f52016-08-12 10:23:27 -04001278 level_map::iterator it = inits_at_level.find(ii->priority());
1279 if (it == inits_at_level.end())
1280 {
1281 std::vector<std::string> l;
1282 l.push_back(ii->init_name());
1283 inits_at_level[ii->priority()] = l;
1284 }
1285 else
1286 it->second.push_back(ii->init_name());
1287 }
1288 }
Ian Lance Taylor0494dc52018-07-19 15:32:29 -07001289 this->write_c_string("\n");
Than McIntosh0e505f52016-08-12 10:23:27 -04001290
1291 // Create the init graph. Start by populating the graph with
1292 // all the edges we inherited from imported packages.
1293 populate_init_graph(&init_graph, imported_init_fns, init_idx);
1294
1295 // Now add edges from the local init function to each of the
1296 // imported fcns.
Cherry Zhangae7d7e02019-07-02 15:05:45 -04001297 if (!import_init_fn.empty() && import_init_fn[0] != '~')
Than McIntosh0e505f52016-08-12 10:23:27 -04001298 {
1299 unsigned src = 0;
1300 go_assert(init_idx[import_init_fn] == 0);
1301 for (Import_init_set::const_iterator p = imported_init_fns.begin();
1302 p != imported_init_fns.end();
1303 ++p)
1304 {
1305 const Import_init* ii = *p;
Cherry Zhangae7d7e02019-07-02 15:05:45 -04001306 if (ii->is_dummy())
1307 continue;
Than McIntosh0e505f52016-08-12 10:23:27 -04001308 unsigned sink = init_idx[ii->init_name()];
1309 add_init_graph_edge(&init_graph, src, sink);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001310 }
1311 }
1312
Than McIntosh0e505f52016-08-12 10:23:27 -04001313 // In the scenario where one or more of the packages we imported
1314 // was written with the legacy export data format, add dummy edges
1315 // to capture the priority relationships. Here is a package import
1316 // graph as an example:
1317 //
1318 // *A
1319 // /|
1320 // / |
1321 // B *C
1322 // /|
1323 // / |
1324 // *D *E
1325 // | /|
1326 // |/ |
1327 // *F *G
1328 //
1329 // Let's suppose that the object for package "C" is from an old
1330 // gccgo, e.g. it has the old export data format. All other
1331 // packages are compiled with the new compiler and have the new
1332 // format. Packages with *'s have init functions. The scenario is
1333 // that we're compiling a package "A"; during this process we'll
1334 // read the export data for "C". It should look something like
1335 //
1336 // init F F..import 1 G G..import 1 D D..import 2 E E..import 2;
1337 //
1338 // To capture this information and convey it to the consumers of
1339 // "A", the code below adds edges to the graph from each priority K
1340 // function to every priority K-1 function for appropriate values
1341 // of K. This will potentially add more edges than we need (for
1342 // example, an edge from D to G), but given that we don't expect
1343 // to see large numbers of old objects, this will hopefully be OK.
1344
1345 if (inits_at_level.size() > 0)
1346 {
1347 for (level_map::reverse_iterator it = inits_at_level.rbegin();
1348 it != inits_at_level.rend(); ++it)
1349 {
1350 int level = it->first;
1351 if (level < 2) break;
1352 const std::vector<std::string>& fcns_at_level = it->second;
1353 for (std::vector<std::string>::const_iterator sit =
1354 fcns_at_level.begin();
1355 sit != fcns_at_level.end(); ++sit)
1356 {
1357 unsigned src = init_idx[*sit];
1358 level_map::iterator it2 = inits_at_level.find(level - 1);
1359 if (it2 != inits_at_level.end())
1360 {
1361 const std::vector<std::string> fcns_at_lm1 = it2->second;
1362 for (std::vector<std::string>::const_iterator mit =
1363 fcns_at_lm1.begin();
1364 mit != fcns_at_lm1.end(); ++mit)
1365 {
1366 unsigned sink = init_idx[*mit];
1367 add_init_graph_edge(&init_graph, src, sink);
1368 }
1369 }
1370 }
1371 }
1372 }
1373
1374 // Write out the resulting graph.
1375 this->write_c_string("init_graph");
1376 for (Init_graph::const_iterator ki = init_graph.begin();
1377 ki != init_graph.end(); ++ki)
1378 {
1379 unsigned src = ki->first;
1380 const std::set<unsigned>& successors = ki->second;
1381 for (std::set<unsigned>::const_iterator vi = successors.begin();
1382 vi != successors.end(); ++vi)
1383 {
1384 this->write_c_string(" ");
1385 this->write_unsigned(src);
1386 unsigned sink = (*vi);
1387 this->write_c_string(" ");
1388 this->write_unsigned(sink);
1389 }
1390 }
Ian Lance Taylor0494dc52018-07-19 15:32:29 -07001391 this->write_c_string("\n");
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001392}
1393
Ian Lance Taylor6db7e352018-10-17 16:28:15 -07001394// Write the types to the export stream.
1395
1396void
1397Export::write_types(int unexported_type_index)
1398{
1399 // Map from type index to type.
1400 std::vector<const Type*> types(static_cast<size_t>(this->type_index_));
Than McIntosh1e042a42019-06-27 11:27:10 -04001401 for (Type_refs::const_iterator p = this->impl_->type_refs.begin();
1402 p != this->impl_->type_refs.end();
Ian Lance Taylor6db7e352018-10-17 16:28:15 -07001403 ++p)
1404 {
1405 if (p->second >= 0)
1406 types.at(p->second) = p->first;
1407 }
1408
1409 // Write the type information to a buffer.
1410 Stream_to_string type_data;
1411 Export::Stream* orig_stream = this->stream_;
1412 this->stream_ = &type_data;
1413
1414 std::vector<size_t> type_sizes(static_cast<size_t>(this->type_index_));
1415 type_sizes[0] = 0;
1416
1417 // Start at 1 because type index 0 is not used.
1418 size_t start_size = 0;
1419 for (int i = 1; i < this->type_index_; ++i)
1420 {
1421 this->write_type_definition(types[i], i);
1422
1423 size_t cur_size = type_data.string().size();
1424 type_sizes[i] = cur_size - start_size;
1425 start_size = cur_size;
1426 }
1427
1428 // Back to original stream.
1429 this->stream_ = orig_stream;
1430
1431 // The line "types MAXP1 EXPORTEDP1 SIZES..." appears before the
1432 // types. MAXP1 is one more than the maximum type index used; that
1433 // is, it is the size of the array we need to allocate to hold all
1434 // the values. Indexes 1 up to but not including EXPORTEDP1 are the
1435 // exported types. The other types are not exported. SIZES... is a
1436 // list of MAXP1-1 entries listing the size of the type definition
1437 // for each type, starting at index 1.
1438 char buf[100];
1439 snprintf(buf, sizeof buf, "types %d %d", this->type_index_,
1440 unexported_type_index);
1441 this->write_c_string(buf);
1442
1443 // Start at 1 because type index 0 is not used.
1444 for (int i = 1; i < this->type_index_; ++i)
1445 {
1446 snprintf(buf, sizeof buf, " %lu",
1447 static_cast<unsigned long>(type_sizes[i]));
1448 this->write_c_string(buf);
1449 }
1450 this->write_c_string("\n");
1451 this->write_string(type_data.string());
1452}
1453
1454// Write a single type to the export stream.
1455
1456void
1457Export::write_type_definition(const Type* type, int index)
1458{
1459 this->write_c_string("type ");
1460
1461 char buf[30];
1462 snprintf(buf, sizeof buf, "%d ", index);
1463 this->write_c_string(buf);
1464
1465 const Named_type* nt = type->named_type();
1466 if (nt != NULL)
1467 {
1468 const Named_object* no = nt->named_object();
1469 const Package* package = no->package();
1470
1471 this->write_c_string("\"");
1472 if (package != NULL && !Gogo::is_hidden_name(no->name()))
1473 {
1474 this->write_string(package->pkgpath());
1475 this->write_c_string(".");
1476 }
1477 this->write_string(nt->named_object()->name());
1478 this->write_c_string("\" ");
1479
Ian Lance Taylor957591b2020-10-26 16:48:03 -07001480 if (!nt->in_heap())
1481 this->write_c_string("notinheap ");
1482
Ian Lance Taylor6db7e352018-10-17 16:28:15 -07001483 if (nt->is_alias())
1484 this->write_c_string("= ");
1485 }
1486
1487 type->export_type(this);
1488
1489 // Type::export_type will print a newline for a named type, but not
1490 // otherwise.
1491 if (nt == NULL)
1492 this->write_c_string("\n");
1493}
1494
Ian Lance Taylorb0a43562012-02-17 14:33:15 -08001495// Write a name to the export stream.
1496
1497void
1498Export::write_name(const std::string& name)
1499{
1500 if (name.empty())
1501 this->write_c_string("?");
1502 else
Ian Lance Taylorf9d1bfb2020-01-09 07:48:57 -08001503 this->write_string(Gogo::unpack_hidden_name(name));
Ian Lance Taylorb0a43562012-02-17 14:33:15 -08001504}
1505
Than McIntosh0e505f52016-08-12 10:23:27 -04001506// Write an integer value to the export stream.
1507
1508void
1509Export::write_int(int value)
1510{
1511 char buf[100];
1512 snprintf(buf, sizeof buf, "%d", value);
1513 this->write_c_string(buf);
1514}
1515
1516// Write an integer value to the export stream.
1517
1518void
1519Export::write_unsigned(unsigned value)
1520{
1521 char buf[100];
1522 snprintf(buf, sizeof buf, "%u", value);
1523 this->write_c_string(buf);
1524}
1525
Ian Lance Taylor37a47e42019-05-17 14:22:41 -07001526// Return the index of a package.
1527
1528int
1529Export::package_index(const Package* pkg) const
1530{
1531 Unordered_map(const Package *, int)::const_iterator p =
1532 this->packages_.find(pkg);
1533 go_assert(p != this->packages_.end());
1534 int index = p->second;
1535 go_assert(index != 0);
1536 return index;
1537}
1538
Ian Lance Taylord5d51242021-08-06 12:01:04 -07001539// Return the index of the "unsafe" package.
1540
1541int
1542Export::unsafe_package_index() const
1543{
1544 for (Unordered_map(const Package*, int)::const_iterator p =
1545 this->packages_.begin();
1546 p != this->packages_.end();
1547 ++p)
1548 {
1549 if (p->first->pkgpath() == "unsafe")
1550 {
1551 go_assert(p->second != 0);
1552 return p->second;
1553 }
1554 }
1555 go_unreachable();
1556}
1557
Ian Lance Taylordb524022018-11-07 07:12:34 -08001558// Return the index of a type.
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001559
Ian Lance Taylordb524022018-11-07 07:12:34 -08001560int
1561Export::type_index(const Type* type)
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001562{
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001563 type = type->forwarded();
Than McIntosh1e042a42019-06-27 11:27:10 -04001564 Type_refs::const_iterator p = this->impl_->type_refs.find(type);
1565 go_assert(p != this->impl_->type_refs.end());
Ian Lance Taylor6db7e352018-10-17 16:28:15 -07001566 int index = p->second;
1567 go_assert(index != 0);
Ian Lance Taylordb524022018-11-07 07:12:34 -08001568 return index;
1569}
1570
1571// Export a type.
1572
1573void
1574Export::write_type(const Type* type)
1575{
1576 int index = this->type_index(type);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001577 char buf[30];
Ian Lance Taylor6db7e352018-10-17 16:28:15 -07001578 snprintf(buf, sizeof buf, "<type %d>", index);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001579 this->write_c_string(buf);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001580}
1581
Ian Lance Taylordb524022018-11-07 07:12:34 -08001582// Export a type to a function body.
1583
1584void
1585Export::write_type_to(const Type* type, Export_function_body* efb)
1586{
1587 int index = this->type_index(type);
1588 char buf[30];
1589 snprintf(buf, sizeof buf, "<type %d>", index);
1590 efb->write_c_string(buf);
1591}
1592
Chris Manghane5ea5c072016-04-22 09:54:33 -07001593// Export escape note.
1594
1595void
1596Export::write_escape(std::string* note)
1597{
1598 if (note != NULL && *note != "esc:0x0")
1599 {
1600 this->write_c_string(" ");
1601 char buf[50];
1602 go_assert(note->find("esc:") != std::string::npos);
1603 snprintf(buf, sizeof buf, "<%s>", note->c_str());
1604 this->write_c_string(buf);
1605 }
1606}
1607
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001608// Add the builtin types to the export table.
1609
1610void
1611Export::register_builtin_types(Gogo* gogo)
1612{
1613 this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
1614 this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
1615 this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
1616 this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
1617 this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
1618 this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
1619 this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
1620 this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
1621 this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
1622 this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
Ian Lance Taylor0f6655d2010-03-10 14:52:12 -08001623 this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
1624 this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001625 this->register_builtin_type(gogo, "int", BUILTIN_INT);
1626 this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
1627 this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001628 this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
1629 this->register_builtin_type(gogo, "string", BUILTIN_STRING);
Rémy Oudompheng77a5b0f2011-12-01 10:55:24 -08001630 this->register_builtin_type(gogo, "error", BUILTIN_ERROR);
Ian Lance Taylor39f9f652012-01-21 13:23:31 -08001631 this->register_builtin_type(gogo, "byte", BUILTIN_BYTE);
1632 this->register_builtin_type(gogo, "rune", BUILTIN_RUNE);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001633}
1634
1635// Register one builtin type in the export table.
1636
1637void
1638Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
1639{
1640 Named_object* named_object = gogo->lookup_global(name);
Evan Shawcafc2f72011-04-21 15:51:28 -07001641 go_assert(named_object != NULL && named_object->is_type());
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001642 std::pair<Type_refs::iterator, bool> ins =
Than McIntosh1e042a42019-06-27 11:27:10 -04001643 this->impl_->type_refs.insert(std::make_pair(named_object->type_value(), code));
Evan Shawcafc2f72011-04-21 15:51:28 -07001644 go_assert(ins.second);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001645
1646 // We also insert the underlying type. We can see the underlying
Ian Lance Taylor6db7e352018-10-17 16:28:15 -07001647 // type at least for string and bool. It's OK if this insert
1648 // fails--we expect duplications here, and it doesn't matter when
1649 // they occur.
1650 Type* real_type = named_object->type_value()->real_type();
Than McIntosh1e042a42019-06-27 11:27:10 -04001651 this->impl_->type_refs.insert(std::make_pair(real_type, code));
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001652}
1653
1654// Class Export::Stream.
1655
1656Export::Stream::Stream()
1657{
Than McIntosh2022ddc2016-09-08 15:45:56 -04001658 this->sha1_helper_ = go_create_sha1_helper();
1659 go_assert(this->sha1_helper_ != NULL);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001660}
1661
1662Export::Stream::~Stream()
1663{
1664}
1665
1666// Write bytes to the stream. This keeps a checksum of bytes as they
1667// go by.
1668
1669void
1670Export::Stream::write_and_sum_bytes(const char* bytes, size_t length)
1671{
Than McIntosh2022ddc2016-09-08 15:45:56 -04001672 this->sha1_helper_->process_bytes(bytes, length);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001673 this->do_write(bytes, length);
1674}
1675
1676// Get the checksum.
1677
1678std::string
1679Export::Stream::checksum()
1680{
Than McIntosh2022ddc2016-09-08 15:45:56 -04001681 std::string rval = this->sha1_helper_->finish();
1682 delete this->sha1_helper_;
1683 return rval;
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001684}
1685
1686// Write the checksum string to the export data.
1687
1688void
1689Export::Stream::write_checksum(const std::string& s)
1690{
1691 this->do_write(s.data(), s.length());
1692}
1693
1694// Class Stream_to_section.
1695
Than McIntoshcc602352017-02-06 11:12:12 -05001696Stream_to_section::Stream_to_section(Backend* backend)
1697 : backend_(backend)
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001698{
1699}
1700
1701// Write data to a section.
1702
1703void
1704Stream_to_section::do_write(const char* bytes, size_t length)
1705{
Than McIntoshcc602352017-02-06 11:12:12 -05001706 this->backend_->write_export_data (bytes, length);
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08001707}
Ian Lance Taylor015785b2019-05-10 07:40:30 -07001708
1709// Class Export_function_body.
1710
1711// Record a temporary statement.
1712
1713unsigned int
1714Export_function_body::record_temporary(const Temporary_statement* temp)
1715{
1716 unsigned int ret = this->next_temporary_index_;
1717 if (ret > 0x7fffffff)
1718 go_error_at(temp->location(),
1719 "too many temporary statements in export data");
1720 ++this->next_temporary_index_;
1721 std::pair<const Temporary_statement*, unsigned int> val(temp, ret);
1722 std::pair<Unordered_map(const Temporary_statement*, unsigned int)::iterator,
1723 bool> ins = this->temporary_indexes_.insert(val);
1724 go_assert(ins.second);
1725 return ret;
1726}
1727
1728// Return the index of a temporary statement.
1729
1730unsigned int
1731Export_function_body::temporary_index(const Temporary_statement* temp)
1732{
1733 Unordered_map(const Temporary_statement*, unsigned int)::const_iterator p =
1734 this->temporary_indexes_.find(temp);
1735 go_assert(p != this->temporary_indexes_.end());
1736 return p->second;
1737}
Ian Lance Taylor11d96c362019-06-06 16:09:58 -07001738
1739// Return the index of an unnamed label. If it doesn't already have
1740// an index, give it one.
1741
1742unsigned int
1743Export_function_body::unnamed_label_index(const Unnamed_label* label)
1744{
1745 unsigned int next = this->next_label_index_;
1746 std::pair<const Unnamed_label*, unsigned int> val(label, next);
1747 std::pair<Unordered_map(const Unnamed_label*, unsigned int)::iterator,
1748 bool> ins =
1749 this->label_indexes_.insert(val);
1750 if (!ins.second)
1751 return ins.first->second;
1752 else
1753 {
1754 if (next > 0x7fffffff)
1755 go_error_at(label->location(),
1756 "too many unnamed labels in export data");
1757 ++this->next_label_index_;
1758 return next;
1759 }
1760}