Mercurial > hg > CbC > CbC_gcc
comparison gcc/go/gofrontend/export.cc @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
4 // Use of this source code is governed by a BSD-style | 4 // Use of this source code is governed by a BSD-style |
5 // license that can be found in the LICENSE file. | 5 // license that can be found in the LICENSE file. |
6 | 6 |
7 #include "go-system.h" | 7 #include "go-system.h" |
8 | 8 |
9 #include "go-c.h" | |
10 #include "go-diagnostics.h" | |
9 #include "go-sha1.h" | 11 #include "go-sha1.h" |
10 #include "go-c.h" | |
11 | |
12 #include "gogo.h" | 12 #include "gogo.h" |
13 #include "types.h" | 13 #include "types.h" |
14 #include "expressions.h" | |
14 #include "statements.h" | 15 #include "statements.h" |
15 #include "export.h" | 16 #include "export.h" |
16 | |
17 #include "go-linemap.h" | 17 #include "go-linemap.h" |
18 #include "backend.h" | 18 #include "backend.h" |
19 | 19 |
20 // This file handles exporting global declarations. | 20 // This file handles exporting global declarations. |
21 | 21 |
39 'v', '2', ';', '\n' | 39 'v', '2', ';', '\n' |
40 }; | 40 }; |
41 | 41 |
42 const int Export::checksum_len; | 42 const int Export::checksum_len; |
43 | 43 |
44 // Constructor. | |
45 | |
46 Export::Export(Stream* stream) | |
47 : stream_(stream), type_index_(1), packages_() | |
48 { | |
49 go_assert(Export::checksum_len == Go_sha1_helper::checksum_len); | |
50 } | |
51 | |
52 // Type hash table operations, treating aliases as distinct. | 44 // Type hash table operations, treating aliases as distinct. |
53 | 45 |
54 class Type_hash_alias_identical | 46 class Type_hash_alias_identical |
55 { | 47 { |
56 public: | 48 public: |
58 operator()(const Type* type) const | 50 operator()(const Type* type) const |
59 { | 51 { |
60 return type->hash_for_method(NULL, | 52 return type->hash_for_method(NULL, |
61 (Type::COMPARE_ERRORS | 53 (Type::COMPARE_ERRORS |
62 | Type::COMPARE_TAGS | 54 | Type::COMPARE_TAGS |
55 | Type::COMPARE_EMBEDDED_INTERFACES | |
63 | Type::COMPARE_ALIASES)); | 56 | Type::COMPARE_ALIASES)); |
64 } | 57 } |
65 }; | 58 }; |
66 | 59 |
67 class Type_alias_identical | 60 class Type_alias_identical |
71 operator()(const Type* t1, const Type* t2) const | 64 operator()(const Type* t1, const Type* t2) const |
72 { | 65 { |
73 return Type::are_identical(t1, t2, | 66 return Type::are_identical(t1, t2, |
74 (Type::COMPARE_ERRORS | 67 (Type::COMPARE_ERRORS |
75 | Type::COMPARE_TAGS | 68 | Type::COMPARE_TAGS |
69 | Type::COMPARE_EMBEDDED_INTERFACES | |
76 | Type::COMPARE_ALIASES), | 70 | Type::COMPARE_ALIASES), |
77 NULL); | 71 NULL); |
78 } | 72 } |
79 }; | 73 }; |
80 | 74 |
81 // Mapping from Type objects to a constant index. This would be nicer | 75 // Mapping from Type objects to a constant index. |
82 // as a field in Export, but then export.h would have to #include | |
83 // types.h. | |
84 | |
85 typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical, | 76 typedef Unordered_map_hash(const Type*, int, Type_hash_alias_identical, |
86 Type_alias_identical) Type_refs; | 77 Type_alias_identical) Type_refs; |
87 | 78 |
88 static Type_refs type_refs; | 79 // Implementation object for class Export. Hidden implementation avoids |
89 | 80 // having to #include types.h in export.h, or use a static map. |
90 // A functor to sort Named_object pointers by name. | 81 |
91 | 82 struct Export_impl { |
92 struct Sort_bindings | 83 Type_refs type_refs; |
93 { | |
94 bool | |
95 operator()(const Named_object* n1, const Named_object* n2) const | |
96 { return n1->name() < n2->name(); } | |
97 }; | 84 }; |
98 | 85 |
99 // Return true if we should export NO. | 86 // Constructor. |
100 | 87 |
101 static bool | 88 Export::Export(Stream* stream) |
102 should_export(Named_object* no) | 89 : stream_(stream), type_index_(1), packages_(), impl_(new Export_impl) |
103 { | 90 { |
104 // We only export objects which are locally defined. | 91 go_assert(Export::checksum_len == Go_sha1_helper::checksum_len); |
105 if (no->package() != NULL) | 92 } |
106 return false; | 93 |
107 | 94 // Destructor. |
108 // We don't export packages. | 95 |
109 if (no->is_package()) | 96 Export::~Export() |
110 return false; | 97 { |
111 | 98 delete this->impl_; |
112 // We don't export hidden names. | 99 } |
113 if (Gogo::is_hidden_name(no->name())) | 100 |
114 return false; | 101 // A traversal class to collect functions and global variables |
115 | 102 // referenced by inlined functions, and also to gather up |
116 // We don't export various special functions. | 103 // referenced types that need to be included in the exports. |
117 if (Gogo::is_special_name(no->name())) | 104 |
118 return false; | 105 class Collect_export_references : public Traverse |
119 | |
120 // Methods are exported with the type, not here. | |
121 if (no->is_function() | |
122 && no->func_value()->type()->is_method()) | |
123 return false; | |
124 if (no->is_function_declaration() | |
125 && no->func_declaration_value()->type()->is_method()) | |
126 return false; | |
127 | |
128 // Don't export dummy global variables created for initializers when | |
129 // used with sinks. | |
130 if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.') | |
131 return false; | |
132 | |
133 return true; | |
134 } | |
135 | |
136 // Export those identifiers marked for exporting. | |
137 | |
138 void | |
139 Export::export_globals(const std::string& package_name, | |
140 const std::string& prefix, | |
141 const std::string& pkgpath, | |
142 const std::map<std::string, Package*>& packages, | |
143 const std::map<std::string, Package*>& imports, | |
144 const std::string& import_init_fn, | |
145 const Import_init_set& imported_init_fns, | |
146 const Bindings* bindings) | |
147 { | |
148 // If there have been any errors so far, don't try to export | |
149 // anything. That way the export code doesn't have to worry about | |
150 // mismatched types or other confusions. | |
151 if (saw_errors()) | |
152 return; | |
153 | |
154 // Export the symbols in sorted order. That will reduce cases where | |
155 // irrelevant changes to the source code affect the exported | |
156 // interface. | |
157 std::vector<Named_object*> exports; | |
158 exports.reserve(bindings->size_definitions()); | |
159 | |
160 for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); | |
161 p != bindings->end_definitions(); | |
162 ++p) | |
163 if (should_export(*p)) | |
164 exports.push_back(*p); | |
165 | |
166 for (Bindings::const_declarations_iterator p = | |
167 bindings->begin_declarations(); | |
168 p != bindings->end_declarations(); | |
169 ++p) | |
170 { | |
171 // We export a function declaration as it may be implemented in | |
172 // supporting C code. We do not export type declarations. | |
173 if (p->second->is_function_declaration() | |
174 && should_export(p->second)) | |
175 exports.push_back(p->second); | |
176 } | |
177 | |
178 std::sort(exports.begin(), exports.end(), Sort_bindings()); | |
179 | |
180 // Assign indexes to all exported types and types referenced by | |
181 // exported types, and collect all packages mentioned. | |
182 Unordered_set(const Package*) type_imports; | |
183 int unexported_type_index = this->prepare_types(&exports, &type_imports); | |
184 | |
185 // Although the export data is readable, at least this version is, | |
186 // it is conceptually a binary format. Start with a four byte | |
187 // version number. | |
188 this->write_bytes(Export::cur_magic, Export::magic_len); | |
189 | |
190 // The package name. | |
191 this->write_c_string("package "); | |
192 this->write_string(package_name); | |
193 this->write_c_string("\n"); | |
194 | |
195 // The prefix or package path, used for all global symbols. | |
196 if (prefix.empty()) | |
197 { | |
198 go_assert(!pkgpath.empty()); | |
199 this->write_c_string("pkgpath "); | |
200 this->write_string(pkgpath); | |
201 } | |
202 else | |
203 { | |
204 this->write_c_string("prefix "); | |
205 this->write_string(prefix); | |
206 } | |
207 this->write_c_string("\n"); | |
208 | |
209 this->write_packages(packages); | |
210 | |
211 this->write_imports(imports, type_imports); | |
212 | |
213 this->write_imported_init_fns(package_name, import_init_fn, | |
214 imported_init_fns); | |
215 | |
216 // FIXME: It might be clever to add something about the processor | |
217 // and ABI being used, although ideally any problems in that area | |
218 // would be caught by the linker. | |
219 | |
220 // Write out all the types, both exported and not. | |
221 this->write_types(unexported_type_index); | |
222 | |
223 // Write out the non-type export data. | |
224 for (std::vector<Named_object*>::const_iterator p = exports.begin(); | |
225 p != exports.end(); | |
226 ++p) | |
227 { | |
228 if (!(*p)->is_type()) | |
229 (*p)->export_named_object(this); | |
230 } | |
231 | |
232 std::string checksum = this->stream_->checksum(); | |
233 std::string s = "checksum "; | |
234 for (std::string::const_iterator p = checksum.begin(); | |
235 p != checksum.end(); | |
236 ++p) | |
237 { | |
238 unsigned char c = *p; | |
239 unsigned int dig = c >> 4; | |
240 s += dig < 10 ? '0' + dig : 'A' + dig - 10; | |
241 dig = c & 0xf; | |
242 s += dig < 10 ? '0' + dig : 'A' + dig - 10; | |
243 } | |
244 s += "\n"; | |
245 this->stream_->write_checksum(s); | |
246 } | |
247 | |
248 // Traversal class to find referenced types. | |
249 | |
250 class Find_types_to_prepare : public Traverse | |
251 { | 106 { |
252 public: | 107 public: |
253 Find_types_to_prepare(Export* exp, | 108 Collect_export_references(Export* exp, |
254 Unordered_set(const Package*)* imports) | 109 Unordered_set(Named_object*)* exports, |
255 : Traverse(traverse_types), | 110 Unordered_set(const Package*)* imports) |
256 exp_(exp), imports_(imports) | 111 : Traverse(traverse_expressions |
112 | traverse_types), | |
113 exp_(exp), exports_(exports), imports_(imports), | |
114 inline_fcn_worklist_(NULL), exports_finalized_(false) | |
257 { } | 115 { } |
258 | 116 |
117 // Initial entry point; performs a walk to expand the exports set. | |
118 void | |
119 expand_exports(std::vector<Named_object*>* inlinable_functions); | |
120 | |
121 // Second entry point (called after the method above), to find | |
122 // all types referenced by exports. | |
123 void | |
124 prepare_types(const std::vector<Named_object*>& sorted_exports); | |
125 | |
126 protected: | |
127 // Override of parent class method. | |
128 int | |
129 expression(Expression**); | |
130 | |
131 // Override of parent class method. | |
259 int | 132 int |
260 type(Type* type); | 133 type(Type* type); |
261 | 134 |
262 // Traverse the components of a function type. | 135 // Traverse the components of a function type. |
263 void | 136 void |
264 traverse_function(Function_type*); | 137 traverse_function_type(Function_type*); |
265 | 138 |
266 // Traverse the methods of a named type, and register its package. | 139 // Traverse the methods of a named type, and register its package. |
267 void | 140 void |
268 traverse_named_type(Named_type*); | 141 traverse_named_type(Named_type*); |
269 | 142 |
270 private: | 143 private: |
271 // Exporters. | 144 |
145 // Add a named object to the exports set (during expand_exports()). | |
146 // Returns TRUE if a new object was added to the exports set, | |
147 // FALSE otherwise. | |
148 bool | |
149 add_to_exports(Named_object*); | |
150 | |
151 // The exporter. | |
272 Export* exp_; | 152 Export* exp_; |
273 // List of packages we are building. | 153 // The set of named objects to export. |
154 Unordered_set(Named_object*)* exports_; | |
155 // Set containing all directly and indirectly imported packages. | |
274 Unordered_set(const Package*)* imports_; | 156 Unordered_set(const Package*)* imports_; |
157 // Functions we've already traversed and don't need to visit again. | |
158 Unordered_set(Named_object*) checked_functions_; | |
159 // Worklist of functions we are exporting with inline bodies that need | |
160 // to be checked. | |
161 std::vector<Named_object*>* inline_fcn_worklist_; | |
162 // Set to true if expand_exports() has been called and is complete. | |
163 bool exports_finalized_; | |
275 }; | 164 }; |
276 | 165 |
277 // Set type index of referenced type, record package imports, and make | 166 void |
278 // sure we traverse methods of named types. | 167 Collect_export_references::expand_exports(std::vector<Named_object*>* fcns) |
168 { | |
169 this->inline_fcn_worklist_ = fcns; | |
170 while (!this->inline_fcn_worklist_->empty()) | |
171 { | |
172 Named_object* no = this->inline_fcn_worklist_->back(); | |
173 this->inline_fcn_worklist_->pop_back(); | |
174 std::pair<Unordered_set(Named_object*)::iterator, bool> ins = | |
175 this->checked_functions_.insert(no); | |
176 if (ins.second) | |
177 { | |
178 // This traversal may add new objects to this->exports_ and new | |
179 // functions to this->inline_fcn_worklist_. | |
180 no->func_value()->block()->traverse(this); | |
181 } | |
182 } | |
183 this->inline_fcn_worklist_ = NULL; | |
184 this->exports_finalized_ = true; | |
185 } | |
186 | |
187 bool | |
188 Collect_export_references::add_to_exports(Named_object* no) | |
189 { | |
190 std::pair<Unordered_set(Named_object*)::iterator, bool> ins = | |
191 this->exports_->insert(no); | |
192 // If the export list has been finalized, then we should not be | |
193 // adding anything new to the exports set. | |
194 go_assert(!this->exports_finalized_ || !ins.second); | |
195 return ins.second; | |
196 } | |
279 | 197 |
280 int | 198 int |
281 Find_types_to_prepare::type(Type* type) | 199 Collect_export_references::expression(Expression** pexpr) |
200 { | |
201 const Expression* expr = *pexpr; | |
202 | |
203 const Var_expression* ve = expr->var_expression(); | |
204 if (ve != NULL) | |
205 { | |
206 Named_object* no = ve->named_object(); | |
207 if (no->is_variable() && no->var_value()->is_global()) | |
208 { | |
209 const Package* var_package = no->package(); | |
210 if (var_package != NULL) | |
211 this->imports_->insert(var_package); | |
212 | |
213 this->add_to_exports(no); | |
214 no->var_value()->set_is_referenced_by_inline(); | |
215 } | |
216 return TRAVERSE_CONTINUE; | |
217 } | |
218 | |
219 const Func_expression* fe = expr->func_expression(); | |
220 if (fe != NULL) | |
221 { | |
222 Named_object* no = fe->named_object(); | |
223 | |
224 const Package* func_package = fe->named_object()->package(); | |
225 if (func_package != NULL) | |
226 this->imports_->insert(func_package); | |
227 | |
228 if (no->is_function_declaration() | |
229 && no->func_declaration_value()->type()->is_builtin()) | |
230 return TRAVERSE_CONTINUE; | |
231 | |
232 if (this->inline_fcn_worklist_ != NULL) | |
233 { | |
234 bool added = this->add_to_exports(no); | |
235 | |
236 if (no->is_function()) | |
237 no->func_value()->set_is_referenced_by_inline(); | |
238 | |
239 // If 'added' is false then this object was already in | |
240 // exports_, in which case it was already added to | |
241 // check_inline_refs_ the first time we added it to exports_, so | |
242 // we don't need to add it again. | |
243 if (added | |
244 && no->is_function() | |
245 && no->func_value()->export_for_inlining()) | |
246 this->inline_fcn_worklist_->push_back(no); | |
247 } | |
248 | |
249 return TRAVERSE_CONTINUE; | |
250 } | |
251 | |
252 const Named_object* nco = expr->named_constant(); | |
253 if (nco != 0) | |
254 { | |
255 const Named_constant *nc = nco->const_value(); | |
256 Type::traverse(nc->type(), this); | |
257 return TRAVERSE_CONTINUE; | |
258 } | |
259 | |
260 return TRAVERSE_CONTINUE; | |
261 } | |
262 | |
263 // Collect up the set of types mentioned in things we're exporting, and collect | |
264 // all the packages encountered during type traversal, to make sure we can | |
265 // declare things referered to indirectly (for example, in the body of an | |
266 // exported inline function from another package). | |
267 | |
268 void | |
269 Collect_export_references::prepare_types(const std::vector<Named_object*>& sorted_exports) | |
270 { | |
271 // Iterate through the exported objects and traverse any types encountered. | |
272 for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin(); | |
273 p != sorted_exports.end(); | |
274 ++p) | |
275 { | |
276 Named_object* no = *p; | |
277 switch (no->classification()) | |
278 { | |
279 case Named_object::NAMED_OBJECT_CONST: | |
280 { | |
281 Type* t = no->const_value()->type(); | |
282 if (t != NULL && !t->is_abstract()) | |
283 Type::traverse(t, this); | |
284 } | |
285 break; | |
286 | |
287 case Named_object::NAMED_OBJECT_TYPE: | |
288 Type::traverse(no->type_value()->real_type(), this); | |
289 this->traverse_named_type(no->type_value()); | |
290 break; | |
291 | |
292 case Named_object::NAMED_OBJECT_VAR: | |
293 Type::traverse(no->var_value()->type(), this); | |
294 break; | |
295 | |
296 case Named_object::NAMED_OBJECT_FUNC: | |
297 { | |
298 Function* fn = no->func_value(); | |
299 this->traverse_function_type(fn->type()); | |
300 if (fn->export_for_inlining()) | |
301 fn->block()->traverse(this); | |
302 } | |
303 break; | |
304 | |
305 case Named_object::NAMED_OBJECT_FUNC_DECLARATION: | |
306 this->traverse_function_type(no->func_declaration_value()->type()); | |
307 break; | |
308 | |
309 default: | |
310 // We shouldn't see anything else. If we do we'll give an | |
311 // error later when we try to actually export it. | |
312 break; | |
313 } | |
314 } | |
315 } | |
316 | |
317 // Record referenced type, record package imports, and make sure we traverse | |
318 // methods of named types. | |
319 | |
320 int | |
321 Collect_export_references::type(Type* type) | |
282 { | 322 { |
283 // Skip forwarders; don't try to give them a type index. | 323 // Skip forwarders; don't try to give them a type index. |
284 if (type->forward_declaration_type() != NULL) | 324 if (type->forward_declaration_type() != NULL) |
285 return TRAVERSE_CONTINUE; | 325 return TRAVERSE_CONTINUE; |
286 | 326 |
288 // unsafe.Pointer. The void type is not itself exported, because | 328 // unsafe.Pointer. The void type is not itself exported, because |
289 // Pointer_type::do_export checks for it. | 329 // Pointer_type::do_export checks for it. |
290 if (type->is_void_type()) | 330 if (type->is_void_type()) |
291 return TRAVERSE_SKIP_COMPONENTS; | 331 return TRAVERSE_SKIP_COMPONENTS; |
292 | 332 |
293 if (!this->exp_->set_type_index(type)) | 333 // Skip the nil type, turns up in function bodies. |
334 if (type->is_nil_type()) | |
335 return TRAVERSE_SKIP_COMPONENTS; | |
336 | |
337 // Skip abstract types. We should never see these in real code, | |
338 // only in things like const declarations. | |
339 if (type->is_abstract()) | |
340 return TRAVERSE_SKIP_COMPONENTS; | |
341 | |
342 // For interfaces make sure that embedded methods are sorted, since the | |
343 // comparison function we use for indexing types relies on it (this call has | |
344 // to happen before the record_type call below). | |
345 if (type->classification() == Type::TYPE_INTERFACE) | |
346 { | |
347 Interface_type* it = type->interface_type(); | |
348 if (it != NULL) | |
349 it->sort_embedded(); | |
350 } | |
351 | |
352 if (!this->exp_->record_type(type)) | |
294 { | 353 { |
295 // We've already seen this type. | 354 // We've already seen this type. |
296 return TRAVERSE_SKIP_COMPONENTS; | 355 return TRAVERSE_SKIP_COMPONENTS; |
297 } | 356 } |
298 | 357 |
313 ++p) | 372 ++p) |
314 { | 373 { |
315 if (p->name().empty()) | 374 if (p->name().empty()) |
316 Type::traverse(p->type(), this); | 375 Type::traverse(p->type(), this); |
317 else | 376 else |
318 this->traverse_function(p->type()->function_type()); | 377 this->traverse_function_type(p->type()->function_type()); |
319 } | 378 } |
320 } | 379 } |
321 return TRAVERSE_SKIP_COMPONENTS; | 380 return TRAVERSE_SKIP_COMPONENTS; |
322 } | 381 } |
323 | 382 |
326 this->traverse_named_type(nt); | 385 this->traverse_named_type(nt); |
327 | 386 |
328 return TRAVERSE_CONTINUE; | 387 return TRAVERSE_CONTINUE; |
329 } | 388 } |
330 | 389 |
390 void | |
391 Collect_export_references::traverse_named_type(Named_type* nt) | |
392 { | |
393 const Package* package = nt->named_object()->package(); | |
394 if (package != NULL) | |
395 this->imports_->insert(package); | |
396 | |
397 // We have to traverse the methods of named types, because we are | |
398 // going to export them. This is not done by ordinary type | |
399 // traversal. | |
400 const Bindings* methods = nt->local_methods(); | |
401 if (methods != NULL) | |
402 { | |
403 for (Bindings::const_definitions_iterator pm = | |
404 methods->begin_definitions(); | |
405 pm != methods->end_definitions(); | |
406 ++pm) | |
407 { | |
408 Function* fn = (*pm)->func_value(); | |
409 this->traverse_function_type(fn->type()); | |
410 if (fn->export_for_inlining()) | |
411 fn->block()->traverse(this); | |
412 } | |
413 | |
414 for (Bindings::const_declarations_iterator pm = | |
415 methods->begin_declarations(); | |
416 pm != methods->end_declarations(); | |
417 ++pm) | |
418 { | |
419 Named_object* mno = pm->second; | |
420 if (mno->is_function_declaration()) | |
421 this->traverse_function_type(mno->func_declaration_value()->type()); | |
422 } | |
423 } | |
424 } | |
425 | |
331 // Traverse the types in a function type. We don't need the function | 426 // Traverse the types in a function type. We don't need the function |
332 // type itself, just the receiver, parameter, and result types. | 427 // type itself, just the receiver, parameter, and result types. |
333 | 428 |
334 void | 429 void |
335 Find_types_to_prepare::traverse_function(Function_type* type) | 430 Collect_export_references::traverse_function_type(Function_type* type) |
336 { | 431 { |
337 go_assert(type != NULL); | 432 go_assert(type != NULL); |
338 if (this->remember_type(type)) | 433 if (this->remember_type(type)) |
339 return; | 434 return; |
340 const Typed_identifier* receiver = type->receiver(); | 435 const Typed_identifier* receiver = type->receiver(); |
346 const Typed_identifier_list* results = type->results(); | 441 const Typed_identifier_list* results = type->results(); |
347 if (results != NULL) | 442 if (results != NULL) |
348 results->traverse(this); | 443 results->traverse(this); |
349 } | 444 } |
350 | 445 |
351 // Traverse the methods of a named type, and record its package. | 446 // Return true if we should export NO. |
352 | 447 |
353 void | 448 static bool |
354 Find_types_to_prepare::traverse_named_type(Named_type* nt) | 449 should_export(Named_object* no) |
355 { | 450 { |
356 const Package* package = nt->named_object()->package(); | 451 // We only export objects which are locally defined. |
357 if (package != NULL) | 452 if (no->package() != NULL) |
358 this->imports_->insert(package); | 453 return false; |
359 | 454 |
360 // We have to traverse the methods of named types, because we are | 455 // We don't export packages. |
361 // going to export them. This is not done by ordinary type | 456 if (no->is_package()) |
362 // traversal. | 457 return false; |
363 const Bindings* methods = nt->local_methods(); | 458 |
364 if (methods != NULL) | 459 // We don't export hidden names. |
365 { | 460 if (Gogo::is_hidden_name(no->name())) |
366 for (Bindings::const_definitions_iterator pm = | 461 return false; |
367 methods->begin_definitions(); | 462 |
368 pm != methods->end_definitions(); | 463 // We don't export various special functions. |
369 ++pm) | 464 if (Gogo::is_special_name(no->name())) |
370 this->traverse_function((*pm)->func_value()->type()); | 465 return false; |
371 | 466 |
372 for (Bindings::const_declarations_iterator pm = | 467 // Methods are exported with the type, not here. |
373 methods->begin_declarations(); | 468 if (no->is_function() |
374 pm != methods->end_declarations(); | 469 && no->func_value()->type()->is_method()) |
375 ++pm) | 470 return false; |
376 { | 471 if (no->is_function_declaration() |
377 Named_object* mno = pm->second; | 472 && no->func_declaration_value()->type()->is_method()) |
378 if (mno->is_function_declaration()) | 473 return false; |
379 this->traverse_function(mno->func_declaration_value()->type()); | 474 |
380 } | 475 // Don't export dummy global variables created for initializers when |
381 } | 476 // used with sinks. |
382 } | 477 if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.') |
383 | 478 return false; |
384 // Prepare to export types by assigning a type index to every exported | 479 |
385 // type and every type referenced by an exported type. Also collect | 480 return true; |
386 // all the packages we see in types, so that if we refer to any types | 481 } |
387 // from indirectly imported packages we can tell the importer about | 482 |
388 // the package. This returns the number of exported types. | 483 // A functor to sort Named_object pointers by name. |
484 | |
485 struct Sort_bindings | |
486 { | |
487 bool | |
488 operator()(const Named_object* n1, const Named_object* n2) const | |
489 { | |
490 if (n1->package() != n2->package()) | |
491 { | |
492 if (n1->package() == NULL) | |
493 return true; | |
494 if (n2->package() == NULL) | |
495 return false; | |
496 return n1->package()->pkgpath() < n2->package()->pkgpath(); | |
497 } | |
498 | |
499 return n1->name() < n2->name(); | |
500 } | |
501 }; | |
502 | |
503 // A functor to sort types for export. | |
504 | |
505 struct Sort_types | |
506 { | |
507 bool | |
508 operator()(const Type* t1, const Type* t2) const | |
509 { | |
510 const Named_type* nt1 = t1->named_type(); | |
511 const Named_type* nt2 = t2->named_type(); | |
512 if (nt1 != NULL) | |
513 { | |
514 if (nt2 != NULL) | |
515 { | |
516 Sort_bindings sb; | |
517 return sb(nt1->named_object(), nt2->named_object()); | |
518 } | |
519 else | |
520 return true; | |
521 } | |
522 else if (nt2 != NULL) | |
523 return false; | |
524 if (t1->classification() != t2->classification()) | |
525 return t1->classification() < t2->classification(); | |
526 Gogo* gogo = go_get_gogo(); | |
527 return gogo->type_descriptor_name(t1, NULL).compare(gogo->type_descriptor_name(t2, NULL)) < 0; | |
528 } | |
529 }; | |
530 | |
531 // Export those identifiers marked for exporting. | |
532 | |
533 void | |
534 Export::export_globals(const std::string& package_name, | |
535 const std::string& prefix, | |
536 const std::string& pkgpath, | |
537 const std::map<std::string, Package*>& packages, | |
538 const std::map<std::string, Package*>& imports, | |
539 const std::string& import_init_fn, | |
540 const Import_init_set& imported_init_fns, | |
541 const Bindings* bindings, | |
542 Unordered_set(Named_object*)* functions_marked_inline) | |
543 { | |
544 // If there have been any errors so far, don't try to export | |
545 // anything. That way the export code doesn't have to worry about | |
546 // mismatched types or other confusions. | |
547 if (saw_errors()) | |
548 return; | |
549 | |
550 // EXPORTS is the set of objects to export. CHECK_INLINE_REFS is a | |
551 // list of exported function with inline bodies that need to be | |
552 // checked for references to other objects. Every function on | |
553 // CHECK_INLINE_REFS is also on EXPORTS. | |
554 Unordered_set(Named_object*) exports; | |
555 std::vector<Named_object*> check_inline_refs; | |
556 check_inline_refs.reserve(functions_marked_inline->size()); | |
557 | |
558 // Add all functions/methods from the "marked inlined" set to the | |
559 // CHECK_INLINE_REFS worklist. | |
560 for (Unordered_set(Named_object*)::const_iterator p = functions_marked_inline->begin(); | |
561 p != functions_marked_inline->end(); | |
562 ++p) | |
563 check_inline_refs.push_back(*p); | |
564 | |
565 for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); | |
566 p != bindings->end_definitions(); | |
567 ++p) | |
568 { | |
569 if (should_export(*p)) | |
570 exports.insert(*p); | |
571 } | |
572 | |
573 for (Bindings::const_declarations_iterator p = | |
574 bindings->begin_declarations(); | |
575 p != bindings->end_declarations(); | |
576 ++p) | |
577 { | |
578 // We export a function declaration as it may be implemented in | |
579 // supporting C code. We do not export type declarations. | |
580 if (p->second->is_function_declaration() | |
581 && should_export(p->second)) | |
582 exports.insert(p->second); | |
583 } | |
584 | |
585 // Track all imported packages mentioned in export data. | |
586 Unordered_set(const Package*) all_imports; | |
587 | |
588 Collect_export_references collect(this, &exports, &all_imports); | |
589 | |
590 // Walk the set of inlinable routine bodies collected above. This | |
591 // can potentially expand the exports set. | |
592 collect.expand_exports(&check_inline_refs); | |
593 | |
594 // Export the symbols in sorted order. That will reduce cases where | |
595 // irrelevant changes to the source code affect the exported | |
596 // interface. | |
597 std::vector<Named_object*> sorted_exports; | |
598 sorted_exports.reserve(exports.size()); | |
599 | |
600 for (Unordered_set(Named_object*)::const_iterator p = exports.begin(); | |
601 p != exports.end(); | |
602 ++p) | |
603 { | |
604 sorted_exports.push_back(*p); | |
605 | |
606 const Package* pkg = (*p)->package(); | |
607 if (pkg != NULL) | |
608 all_imports.insert(pkg); | |
609 } | |
610 | |
611 std::sort(sorted_exports.begin(), sorted_exports.end(), Sort_bindings()); | |
612 | |
613 // Collect up the set of types mentioned in things we're exporting, | |
614 // and any packages that may be referred to indirectly. | |
615 collect.prepare_types(sorted_exports); | |
616 | |
617 // Assign indexes to all exported types and types referenced by | |
618 // things we're exporting. Return value is index of first non-exported | |
619 // type. | |
620 int unexported_type_index = this->assign_type_indices(sorted_exports); | |
621 | |
622 // Although the export data is readable, at least this version is, | |
623 // it is conceptually a binary format. Start with a four byte | |
624 // version number. | |
625 this->write_bytes(Export::cur_magic, Export::magic_len); | |
626 | |
627 // The package name. | |
628 this->write_c_string("package "); | |
629 this->write_string(package_name); | |
630 this->write_c_string("\n"); | |
631 | |
632 // The prefix or package path, used for all global symbols. | |
633 if (prefix.empty()) | |
634 { | |
635 go_assert(!pkgpath.empty()); | |
636 this->write_c_string("pkgpath "); | |
637 this->write_string(pkgpath); | |
638 } | |
639 else | |
640 { | |
641 this->write_c_string("prefix "); | |
642 this->write_string(prefix); | |
643 } | |
644 this->write_c_string("\n"); | |
645 | |
646 this->write_packages(packages); | |
647 | |
648 this->write_imports(imports, all_imports); | |
649 | |
650 this->write_imported_init_fns(package_name, import_init_fn, | |
651 imported_init_fns); | |
652 | |
653 // FIXME: It might be clever to add something about the processor | |
654 // and ABI being used, although ideally any problems in that area | |
655 // would be caught by the linker. | |
656 | |
657 // Write out all the types, both exported and not. | |
658 this->write_types(unexported_type_index); | |
659 | |
660 // Write out the non-type export data. | |
661 for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin(); | |
662 p != sorted_exports.end(); | |
663 ++p) | |
664 { | |
665 if (!(*p)->is_type()) | |
666 (*p)->export_named_object(this); | |
667 } | |
668 | |
669 std::string checksum = this->stream_->checksum(); | |
670 std::string s = "checksum "; | |
671 for (std::string::const_iterator p = checksum.begin(); | |
672 p != checksum.end(); | |
673 ++p) | |
674 { | |
675 unsigned char c = *p; | |
676 unsigned int dig = c >> 4; | |
677 s += dig < 10 ? '0' + dig : 'A' + dig - 10; | |
678 dig = c & 0xf; | |
679 s += dig < 10 ? '0' + dig : 'A' + dig - 10; | |
680 } | |
681 s += "\n"; | |
682 this->stream_->write_checksum(s); | |
683 } | |
684 | |
685 // Record a type in the "to be indexed" set. Return true if the type | |
686 // was not already in the set, false otherwise. | |
687 | |
688 bool | |
689 Export::record_type(Type* type) | |
690 { | |
691 type = type->forwarded(); | |
692 | |
693 std::pair<Type_refs::iterator, bool> ins = | |
694 this->impl_->type_refs.insert(std::make_pair(type, 0)); | |
695 if (!ins.second) | |
696 { | |
697 // We've already seen this type. | |
698 return false; | |
699 } | |
700 ins.first->second = 0; | |
701 | |
702 return true; | |
703 } | |
704 | |
705 // Assign the specified type an index. | |
706 | |
707 void | |
708 Export::set_type_index(const Type* type) | |
709 { | |
710 type = type->forwarded(); | |
711 std::pair<Type_refs::iterator, bool> ins = | |
712 this->impl_->type_refs.insert(std::make_pair(type, 0)); | |
713 go_assert(!ins.second); | |
714 int index = this->type_index_; | |
715 ++this->type_index_; | |
716 go_assert(ins.first->second == 0); | |
717 ins.first->second = index; | |
718 } | |
719 | |
720 // This helper assigns type indices to all types mentioned directly or | |
721 // indirectly in the things we're exporting. Actual exported types are given | |
722 // indices according to where the appear on the sorted exports list; all other | |
723 // types appear afterwards. Return value is the total number of exported types | |
724 // plus 1, e.g. the index of the 1st non-exported type. | |
389 | 725 |
390 int | 726 int |
391 Export::prepare_types(const std::vector<Named_object*>* exports, | 727 Export::assign_type_indices(const std::vector<Named_object*>& sorted_exports) |
392 Unordered_set(const Package*)* imports) | |
393 { | 728 { |
394 // Assign indexes to all the exported types. | 729 // Assign indexes to all the exported types. |
395 for (std::vector<Named_object*>::const_iterator p = exports->begin(); | 730 for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin(); |
396 p != exports->end(); | 731 p != sorted_exports.end(); |
397 ++p) | 732 ++p) |
398 { | 733 { |
399 if (!(*p)->is_type()) | 734 if (!(*p)->is_type()) |
400 continue; | 735 continue; |
736 Interface_type* it = (*p)->type_value()->interface_type(); | |
737 if (it != NULL) | |
738 it->sort_embedded(); | |
739 this->record_type((*p)->type_value()); | |
401 this->set_type_index((*p)->type_value()); | 740 this->set_type_index((*p)->type_value()); |
402 } | 741 } |
403 | |
404 int ret = this->type_index_; | 742 int ret = this->type_index_; |
405 | 743 |
406 // Use a single instance of the traversal class because traversal | 744 // Collect export-referenced, non-builtin types. |
407 // classes keep track of which types they've already seen. That | 745 std::vector<const Type*> types; |
408 // lets us avoid type reference loops. | 746 types.reserve(this->impl_->type_refs.size()); |
409 Find_types_to_prepare find(this, imports); | 747 for (Type_refs::const_iterator p = this->impl_->type_refs.begin(); |
410 | 748 p != this->impl_->type_refs.end(); |
411 // Traverse all the exported objects and assign indexes to all types. | 749 ++p) |
412 for (std::vector<Named_object*>::const_iterator p = exports->begin(); | 750 { |
413 p != exports->end(); | 751 const Type* t = p->first; |
414 ++p) | 752 if (p->second != 0) |
415 { | 753 continue; |
416 Named_object* no = *p; | 754 types.push_back(t); |
417 switch (no->classification()) | 755 } |
418 { | 756 |
419 case Named_object::NAMED_OBJECT_CONST: | 757 // Sort the types. |
420 { | 758 std::sort(types.begin(), types.end(), Sort_types()); |
421 Type* t = no->const_value()->type(); | 759 |
422 if (t != NULL && !t->is_abstract()) | 760 // Assign numbers to the sorted list. |
423 Type::traverse(t, &find); | 761 for (std::vector<const Type *>::const_iterator p = types.begin(); |
424 } | 762 p != types.end(); |
425 break; | 763 ++p) |
426 | 764 this->set_type_index((*p)); |
427 case Named_object::NAMED_OBJECT_TYPE: | |
428 Type::traverse(no->type_value()->real_type(), &find); | |
429 find.traverse_named_type(no->type_value()); | |
430 break; | |
431 | |
432 case Named_object::NAMED_OBJECT_VAR: | |
433 Type::traverse(no->var_value()->type(), &find); | |
434 break; | |
435 | |
436 case Named_object::NAMED_OBJECT_FUNC: | |
437 find.traverse_function(no->func_value()->type()); | |
438 break; | |
439 | |
440 case Named_object::NAMED_OBJECT_FUNC_DECLARATION: | |
441 find.traverse_function(no->func_declaration_value()->type()); | |
442 break; | |
443 | |
444 default: | |
445 // We shouldn't see anything else. If we do we'll give an | |
446 // error later when we try to actually export it. | |
447 break; | |
448 } | |
449 } | |
450 | 765 |
451 return ret; | 766 return ret; |
452 } | |
453 | |
454 // Give a type an index if it doesn't already have one. Return true | |
455 // if we set the type index, false if it was already known. | |
456 | |
457 bool | |
458 Export::set_type_index(Type* type) | |
459 { | |
460 type = type->forwarded(); | |
461 | |
462 std::pair<Type_refs::iterator, bool> ins = | |
463 type_refs.insert(std::make_pair(type, 0)); | |
464 if (!ins.second) | |
465 { | |
466 // We've already seen this type. | |
467 return false; | |
468 } | |
469 | |
470 int index = this->type_index_; | |
471 ++this->type_index_; | |
472 ins.first->second = index; | |
473 | |
474 return true; | |
475 } | 767 } |
476 | 768 |
477 // Sort packages. | 769 // Sort packages. |
478 | 770 |
479 static bool | 771 static bool |
480 packages_compare(const Package* a, const Package* b) | 772 packages_compare(const Package* a, const Package* b) |
481 { | 773 { |
482 return a->package_name() < b->package_name(); | 774 if (a->package_name() < b->package_name()) |
775 return true; | |
776 else if (a->package_name() > b->package_name()) | |
777 return false; | |
778 | |
779 if (a->pkgpath() < b->pkgpath()) | |
780 return true; | |
781 else if (a->pkgpath() > b->pkgpath()) | |
782 return false; | |
783 | |
784 // In principle if we get here then a == b. Try to do something sensible | |
785 // even if the import information is inconsistent. | |
786 if (a->pkgpath_symbol() < b->pkgpath_symbol()) | |
787 return true; | |
788 else if (a->pkgpath_symbol() > b->pkgpath_symbol()) | |
789 return false; | |
790 | |
791 return a < b; | |
483 } | 792 } |
484 | 793 |
485 // Write out all the known packages whose pkgpath symbol is not a | 794 // Write out all the known packages whose pkgpath symbol is not a |
486 // simple transformation of the pkgpath, so that the importing code | 795 // simple transformation of the pkgpath, so that the importing code |
487 // can reliably know it. | 796 // can reliably know it. |
527 | 836 |
528 // Write out the imported packages. | 837 // Write out the imported packages. |
529 | 838 |
530 void | 839 void |
531 Export::write_imports(const std::map<std::string, Package*>& imports, | 840 Export::write_imports(const std::map<std::string, Package*>& imports, |
532 const Unordered_set(const Package*)& type_imports) | 841 const Unordered_set(const Package*)& all_imports) |
533 { | 842 { |
534 // Sort the imports for more consistent output. | 843 // Sort the imports for more consistent output. |
535 Unordered_set(const Package*) seen; | 844 Unordered_set(const Package*) seen; |
536 std::vector<std::pair<std::string, Package*> > sorted_imports; | 845 std::vector<std::pair<std::string, Package*> > sorted_imports; |
537 for (std::map<std::string, Package*>::const_iterator p = imports.begin(); | 846 for (std::map<std::string, Package*>::const_iterator p = imports.begin(); |
542 seen.insert(p->second); | 851 seen.insert(p->second); |
543 } | 852 } |
544 | 853 |
545 std::sort(sorted_imports.begin(), sorted_imports.end(), import_compare); | 854 std::sort(sorted_imports.begin(), sorted_imports.end(), import_compare); |
546 | 855 |
856 int package_index = 1; | |
547 for (std::vector<std::pair<std::string, Package*> >::const_iterator p = | 857 for (std::vector<std::pair<std::string, Package*> >::const_iterator p = |
548 sorted_imports.begin(); | 858 sorted_imports.begin(); |
549 p != sorted_imports.end(); | 859 p != sorted_imports.end(); |
550 ++p) | 860 ++p) |
551 { | 861 { |
555 this->write_string(p->second->pkgpath()); | 865 this->write_string(p->second->pkgpath()); |
556 this->write_c_string(" \""); | 866 this->write_c_string(" \""); |
557 this->write_string(p->first); | 867 this->write_string(p->first); |
558 this->write_c_string("\"\n"); | 868 this->write_c_string("\"\n"); |
559 | 869 |
560 this->packages_.insert(p->second); | 870 this->packages_[p->second] = package_index; |
871 package_index++; | |
561 } | 872 } |
562 | 873 |
563 // Write out a separate list of indirectly imported packages. | 874 // Write out a separate list of indirectly imported packages. |
564 std::vector<const Package*> indirect_imports; | 875 std::vector<const Package*> indirect_imports; |
565 for (Unordered_set(const Package*)::const_iterator p = | 876 for (Unordered_set(const Package*)::const_iterator p = |
566 type_imports.begin(); | 877 all_imports.begin(); |
567 p != type_imports.end(); | 878 p != all_imports.end(); |
568 ++p) | 879 ++p) |
569 { | 880 { |
570 if (seen.find(*p) == seen.end()) | 881 if (seen.find(*p) == seen.end()) |
571 indirect_imports.push_back(*p); | 882 indirect_imports.push_back(*p); |
572 } | 883 } |
582 this->write_c_string("indirectimport "); | 893 this->write_c_string("indirectimport "); |
583 this->write_string((*p)->package_name()); | 894 this->write_string((*p)->package_name()); |
584 this->write_c_string(" "); | 895 this->write_c_string(" "); |
585 this->write_string((*p)->pkgpath()); | 896 this->write_string((*p)->pkgpath()); |
586 this->write_c_string("\n"); | 897 this->write_c_string("\n"); |
898 | |
899 this->packages_[*p] = package_index; | |
900 package_index++; | |
587 } | 901 } |
588 } | 902 } |
589 | 903 |
590 void | 904 void |
591 Export::add_init_graph_edge(Init_graph* init_graph, unsigned src, unsigned sink) | 905 Export::add_init_graph_edge(Init_graph* init_graph, unsigned src, unsigned sink) |
612 for (Import_init_set::const_iterator p = imported_init_fns.begin(); | 926 for (Import_init_set::const_iterator p = imported_init_fns.begin(); |
613 p != imported_init_fns.end(); | 927 p != imported_init_fns.end(); |
614 ++p) | 928 ++p) |
615 { | 929 { |
616 const Import_init* ii = *p; | 930 const Import_init* ii = *p; |
931 if (ii->is_dummy()) | |
932 continue; | |
617 std::map<std::string, unsigned>::const_iterator srcit = | 933 std::map<std::string, unsigned>::const_iterator srcit = |
618 init_idx.find(ii->init_name()); | 934 init_idx.find(ii->init_name()); |
619 go_assert(srcit != init_idx.end()); | 935 go_assert(srcit != init_idx.end()); |
620 unsigned src = srcit->second; | 936 unsigned src = srcit->second; |
621 for (std::set<std::string>::const_iterator pci = ii->precursors().begin(); | 937 for (std::set<std::string>::const_iterator pci = ii->precursors().begin(); |
710 // all the edges we inherited from imported packages. | 1026 // all the edges we inherited from imported packages. |
711 populate_init_graph(&init_graph, imported_init_fns, init_idx); | 1027 populate_init_graph(&init_graph, imported_init_fns, init_idx); |
712 | 1028 |
713 // Now add edges from the local init function to each of the | 1029 // Now add edges from the local init function to each of the |
714 // imported fcns. | 1030 // imported fcns. |
715 if (!import_init_fn.empty()) | 1031 if (!import_init_fn.empty() && import_init_fn[0] != '~') |
716 { | 1032 { |
717 unsigned src = 0; | 1033 unsigned src = 0; |
718 go_assert(init_idx[import_init_fn] == 0); | 1034 go_assert(init_idx[import_init_fn] == 0); |
719 for (Import_init_set::const_iterator p = imported_init_fns.begin(); | 1035 for (Import_init_set::const_iterator p = imported_init_fns.begin(); |
720 p != imported_init_fns.end(); | 1036 p != imported_init_fns.end(); |
721 ++p) | 1037 ++p) |
722 { | 1038 { |
723 const Import_init* ii = *p; | 1039 const Import_init* ii = *p; |
1040 if (ii->is_dummy()) | |
1041 continue; | |
724 unsigned sink = init_idx[ii->init_name()]; | 1042 unsigned sink = init_idx[ii->init_name()]; |
725 add_init_graph_edge(&init_graph, src, sink); | 1043 add_init_graph_edge(&init_graph, src, sink); |
726 } | 1044 } |
727 } | 1045 } |
728 | 1046 |
812 void | 1130 void |
813 Export::write_types(int unexported_type_index) | 1131 Export::write_types(int unexported_type_index) |
814 { | 1132 { |
815 // Map from type index to type. | 1133 // Map from type index to type. |
816 std::vector<const Type*> types(static_cast<size_t>(this->type_index_)); | 1134 std::vector<const Type*> types(static_cast<size_t>(this->type_index_)); |
817 for (Type_refs::const_iterator p = type_refs.begin(); | 1135 for (Type_refs::const_iterator p = this->impl_->type_refs.begin(); |
818 p != type_refs.end(); | 1136 p != this->impl_->type_refs.end(); |
819 ++p) | 1137 ++p) |
820 { | 1138 { |
821 if (p->second >= 0) | 1139 if (p->second >= 0) |
822 types.at(p->second) = p->first; | 1140 types.at(p->second) = p->first; |
823 } | 1141 } |
911 Export::write_name(const std::string& name) | 1229 Export::write_name(const std::string& name) |
912 { | 1230 { |
913 if (name.empty()) | 1231 if (name.empty()) |
914 this->write_c_string("?"); | 1232 this->write_c_string("?"); |
915 else | 1233 else |
916 this->write_string(Gogo::message_name(name)); | 1234 this->write_string(Gogo::unpack_hidden_name(name)); |
917 } | 1235 } |
918 | 1236 |
919 // Write an integer value to the export stream. | 1237 // Write an integer value to the export stream. |
920 | 1238 |
921 void | 1239 void |
934 char buf[100]; | 1252 char buf[100]; |
935 snprintf(buf, sizeof buf, "%u", value); | 1253 snprintf(buf, sizeof buf, "%u", value); |
936 this->write_c_string(buf); | 1254 this->write_c_string(buf); |
937 } | 1255 } |
938 | 1256 |
939 // Export a type. | 1257 // Return the index of a package. |
940 | 1258 |
941 void | 1259 int |
942 Export::write_type(const Type* type) | 1260 Export::package_index(const Package* pkg) const |
943 { | 1261 { |
944 type = type->forwarded(); | 1262 Unordered_map(const Package *, int)::const_iterator p = |
945 Type_refs::const_iterator p = type_refs.find(type); | 1263 this->packages_.find(pkg); |
946 go_assert(p != type_refs.end()); | 1264 go_assert(p != this->packages_.end()); |
947 int index = p->second; | 1265 int index = p->second; |
948 go_assert(index != 0); | 1266 go_assert(index != 0); |
1267 return index; | |
1268 } | |
1269 | |
1270 // Return the index of a type. | |
1271 | |
1272 int | |
1273 Export::type_index(const Type* type) | |
1274 { | |
1275 type = type->forwarded(); | |
1276 Type_refs::const_iterator p = this->impl_->type_refs.find(type); | |
1277 go_assert(p != this->impl_->type_refs.end()); | |
1278 int index = p->second; | |
1279 go_assert(index != 0); | |
1280 return index; | |
1281 } | |
1282 | |
1283 // Export a type. | |
1284 | |
1285 void | |
1286 Export::write_type(const Type* type) | |
1287 { | |
1288 int index = this->type_index(type); | |
949 char buf[30]; | 1289 char buf[30]; |
950 snprintf(buf, sizeof buf, "<type %d>", index); | 1290 snprintf(buf, sizeof buf, "<type %d>", index); |
951 this->write_c_string(buf); | 1291 this->write_c_string(buf); |
1292 } | |
1293 | |
1294 // Export a type to a function body. | |
1295 | |
1296 void | |
1297 Export::write_type_to(const Type* type, Export_function_body* efb) | |
1298 { | |
1299 int index = this->type_index(type); | |
1300 char buf[30]; | |
1301 snprintf(buf, sizeof buf, "<type %d>", index); | |
1302 efb->write_c_string(buf); | |
952 } | 1303 } |
953 | 1304 |
954 // Export escape note. | 1305 // Export escape note. |
955 | 1306 |
956 void | 1307 void |
999 Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code) | 1350 Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code) |
1000 { | 1351 { |
1001 Named_object* named_object = gogo->lookup_global(name); | 1352 Named_object* named_object = gogo->lookup_global(name); |
1002 go_assert(named_object != NULL && named_object->is_type()); | 1353 go_assert(named_object != NULL && named_object->is_type()); |
1003 std::pair<Type_refs::iterator, bool> ins = | 1354 std::pair<Type_refs::iterator, bool> ins = |
1004 type_refs.insert(std::make_pair(named_object->type_value(), code)); | 1355 this->impl_->type_refs.insert(std::make_pair(named_object->type_value(), code)); |
1005 go_assert(ins.second); | 1356 go_assert(ins.second); |
1006 | 1357 |
1007 // We also insert the underlying type. We can see the underlying | 1358 // We also insert the underlying type. We can see the underlying |
1008 // type at least for string and bool. It's OK if this insert | 1359 // type at least for string and bool. It's OK if this insert |
1009 // fails--we expect duplications here, and it doesn't matter when | 1360 // fails--we expect duplications here, and it doesn't matter when |
1010 // they occur. | 1361 // they occur. |
1011 Type* real_type = named_object->type_value()->real_type(); | 1362 Type* real_type = named_object->type_value()->real_type(); |
1012 type_refs.insert(std::make_pair(real_type, code)); | 1363 this->impl_->type_refs.insert(std::make_pair(real_type, code)); |
1013 } | 1364 } |
1014 | 1365 |
1015 // Class Export::Stream. | 1366 // Class Export::Stream. |
1016 | 1367 |
1017 Export::Stream::Stream() | 1368 Export::Stream::Stream() |
1064 void | 1415 void |
1065 Stream_to_section::do_write(const char* bytes, size_t length) | 1416 Stream_to_section::do_write(const char* bytes, size_t length) |
1066 { | 1417 { |
1067 this->backend_->write_export_data (bytes, length); | 1418 this->backend_->write_export_data (bytes, length); |
1068 } | 1419 } |
1420 | |
1421 // Class Export_function_body. | |
1422 | |
1423 // Record a temporary statement. | |
1424 | |
1425 unsigned int | |
1426 Export_function_body::record_temporary(const Temporary_statement* temp) | |
1427 { | |
1428 unsigned int ret = this->next_temporary_index_; | |
1429 if (ret > 0x7fffffff) | |
1430 go_error_at(temp->location(), | |
1431 "too many temporary statements in export data"); | |
1432 ++this->next_temporary_index_; | |
1433 std::pair<const Temporary_statement*, unsigned int> val(temp, ret); | |
1434 std::pair<Unordered_map(const Temporary_statement*, unsigned int)::iterator, | |
1435 bool> ins = this->temporary_indexes_.insert(val); | |
1436 go_assert(ins.second); | |
1437 return ret; | |
1438 } | |
1439 | |
1440 // Return the index of a temporary statement. | |
1441 | |
1442 unsigned int | |
1443 Export_function_body::temporary_index(const Temporary_statement* temp) | |
1444 { | |
1445 Unordered_map(const Temporary_statement*, unsigned int)::const_iterator p = | |
1446 this->temporary_indexes_.find(temp); | |
1447 go_assert(p != this->temporary_indexes_.end()); | |
1448 return p->second; | |
1449 } | |
1450 | |
1451 // Return the index of an unnamed label. If it doesn't already have | |
1452 // an index, give it one. | |
1453 | |
1454 unsigned int | |
1455 Export_function_body::unnamed_label_index(const Unnamed_label* label) | |
1456 { | |
1457 unsigned int next = this->next_label_index_; | |
1458 std::pair<const Unnamed_label*, unsigned int> val(label, next); | |
1459 std::pair<Unordered_map(const Unnamed_label*, unsigned int)::iterator, | |
1460 bool> ins = | |
1461 this->label_indexes_.insert(val); | |
1462 if (!ins.second) | |
1463 return ins.first->second; | |
1464 else | |
1465 { | |
1466 if (next > 0x7fffffff) | |
1467 go_error_at(label->location(), | |
1468 "too many unnamed labels in export data"); | |
1469 ++this->next_label_index_; | |
1470 return next; | |
1471 } | |
1472 } |