: Traverse(traverse_expressions
| traverse_types),
exp_(exp), exports_(exports), imports_(imports),
- inline_fcn_worklist_(NULL)
+ inline_fcn_worklist_(NULL), exports_finalized_(false)
{ }
// Initial entry point; performs a walk to expand the exports set.
// Second entry point (called after the method above), to find
// all types referenced by exports.
void
- prepare_types();
+ prepare_types(const std::vector<Named_object*>& sorted_exports);
protected:
// Override of parent class method.
traverse_named_type(Named_type*);
private:
+
+ // Add a named object to the exports set (during expand_exports()).
+ // Returns TRUE if a new object was added to the exports set,
+ // FALSE otherwise.
+ bool
+ add_to_exports(Named_object*);
+
// The exporter.
Export* exp_;
// The set of named objects to export.
// Worklist of functions we are exporting with inline bodies that need
// to be checked.
std::vector<Named_object*>* inline_fcn_worklist_;
+ // Set to true if expand_exports() has been called and is complete.
+ bool exports_finalized_;
};
void
}
}
this->inline_fcn_worklist_ = NULL;
+ this->exports_finalized_ = true;
+}
+
+bool
+Collect_export_references::add_to_exports(Named_object* no)
+{
+ std::pair<Unordered_set(Named_object*)::iterator, bool> ins =
+ this->exports_->insert(no);
+ // If the export list has been finalized, then we should not be
+ // adding anything new to the exports set.
+ go_assert(!this->exports_finalized_ || !ins.second);
+ return ins.second;
}
int
if (var_package != NULL)
this->imports_->insert(var_package);
- this->exports_->insert(no);
+ this->add_to_exports(no);
no->var_value()->set_is_referenced_by_inline();
}
return TRAVERSE_CONTINUE;
if (this->inline_fcn_worklist_ != NULL)
{
- std::pair<Unordered_set(Named_object*)::iterator, bool> ins =
- this->exports_->insert(no);
+ bool added = this->add_to_exports(no);
if (no->is_function())
no->func_value()->set_is_referenced_by_inline();
- // If ins.second is false then this object was already in
+ // If 'added' is false then this object was already in
// exports_, in which case it was already added to
// check_inline_refs_ the first time we added it to exports_, so
// we don't need to add it again.
- if (ins.second
+ if (added
&& no->is_function()
&& no->func_value()->export_for_inlining())
this->inline_fcn_worklist_->push_back(no);
// exported inline function from another package).
void
-Collect_export_references::prepare_types()
+Collect_export_references::prepare_types(const std::vector<Named_object*>& sorted_exports)
{
// Iterate through the exported objects and traverse any types encountered.
- for (Unordered_set(Named_object*)::iterator p = this->exports_->begin();
- p != this->exports_->end();
+ for (std::vector<Named_object*>::const_iterator p = sorted_exports.begin();
+ p != sorted_exports.end();
++p)
{
Named_object* no = *p;
const std::map<std::string, Package*>& imports,
const std::string& import_init_fn,
const Import_init_set& imported_init_fns,
- const Bindings* bindings)
+ const Bindings* bindings,
+ Unordered_set(Named_object*)* functions_marked_inline)
{
// If there have been any errors so far, don't try to export
// anything. That way the export code doesn't have to worry about
// CHECK_INLINE_REFS is also on EXPORTS.
Unordered_set(Named_object*) exports;
std::vector<Named_object*> check_inline_refs;
+ check_inline_refs.reserve(functions_marked_inline->size());
+
+ // Add all functions/methods from the "marked inlined" set to the
+ // CHECK_INLINE_REFS worklist.
+ for (Unordered_set(Named_object*)::const_iterator p = functions_marked_inline->begin();
+ p != functions_marked_inline->end();
+ ++p)
+ check_inline_refs.push_back(*p);
for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
p != bindings->end_definitions();
++p)
{
if (should_export(*p))
- {
- exports.insert(*p);
-
- if ((*p)->is_function()
- && (*p)->func_value()->export_for_inlining())
- check_inline_refs.push_back(*p);
- else if ((*p)->is_type())
- {
- const Bindings* methods = (*p)->type_value()->local_methods();
- if (methods != NULL)
- {
- for (Bindings::const_definitions_iterator pm =
- methods->begin_definitions();
- pm != methods->end_definitions();
- ++pm)
- {
- Function* fn = (*pm)->func_value();
- if (fn->export_for_inlining())
- check_inline_refs.push_back(*pm);
- }
- }
- }
- }
+ exports.insert(*p);
}
for (Bindings::const_declarations_iterator p =
// Collect up the set of types mentioned in things we're exporting,
// and any packages that may be referred to indirectly.
- collect.prepare_types();
+ collect.prepare_types(sorted_exports);
// Assign indexes to all exported types and types referenced by
// things we're exporting. Return value is index of first non-exported
class Mark_inline_candidates : public Traverse
{
public:
- Mark_inline_candidates()
+ Mark_inline_candidates(Unordered_set(Named_object*)* marked)
: Traverse(traverse_functions
- | traverse_types)
+ | traverse_types),
+ marked_functions_(marked)
{ }
int
// budget is a heuristic. In the usual GCC spirit, we could
// consider setting this via a command line option.
const int budget_heuristic = 80;
+
+ // Set of named objects that are marked as inline candidates.
+ Unordered_set(Named_object*)* marked_functions_;
};
// Mark a function if it is an inline candidate.
Inline_within_budget iwb(&budget);
func->block()->traverse(&iwb);
if (budget >= 0)
- func->set_export_for_inlining();
+ {
+ func->set_export_for_inlining();
+ this->marked_functions_->insert(no);
+ }
return TRAVERSE_CONTINUE;
}
Inline_within_budget iwb(&budget);
func->block()->traverse(&iwb);
if (budget >= 0)
- func->set_export_for_inlining();
+ {
+ func->set_export_for_inlining();
+ this->marked_functions_->insert(no);
+ }
}
return TRAVERSE_CONTINUE;
}
// Mark any functions whose body should be exported for inlining by
// other packages.
- Mark_inline_candidates mic;
+ Unordered_set(Named_object*) marked_functions;
+ Mark_inline_candidates mic(&marked_functions);
this->traverse(&mic);
// For now we always stream to a section. Later we may want to
this->imports_,
init_fn_name,
this->imported_init_fns_,
- this->package_->bindings());
+ this->package_->bindings(),
+ &marked_functions);
if (!this->c_header_.empty() && !saw_errors())
this->write_c_header();