+
+
+#include <adt/pmap.h>
+#include "typerep.h"
+
+DEBUG_ONLY(static firm_dbg_module_t *dbgcall = NULL;)
+
+/** Maps method types to cloned method types. */
+static pmap *mtp_map;
+
+/**
+ * Clone a method type if not already cloned.
+ */
+static ir_type *clone_type_and_cache(ir_type *tp) {
+ static ident *prefix = NULL;
+ ir_type *res;
+ pmap_entry *e = pmap_find(mtp_map, tp);
+
+ if (e)
+ return e->value;
+
+ if (prefix == NULL)
+ prefix = new_id_from_chars("C", 1);
+
+ res = clone_type_method(tp, prefix);
+ pmap_insert(mtp_map, tp, res);
+ DB((dbgcall, LEVEL_2, "cloned type %+F into %+F\n", tp, res));
+
+ return res;
+} /* clone_type_and_cache */
+
+/**
+ * Copy the calling conventions from the entities to the call type.
+ */
+static void update_calls_to_private(ir_node *call, void *env) {
+ (void) env;
+ if (is_Call(call)) {
+ ir_node *ptr = get_Call_ptr(call);
+
+ if (is_SymConst(ptr)) {
+ ir_entity *ent = get_SymConst_entity(ptr);
+ ir_type *ctp = get_Call_type(call);
+
+ if (get_entity_additional_properties(ent) & mtp_property_private) {
+ if ((get_method_additional_properties(ctp) & mtp_property_private) == 0) {
+ ctp = clone_type_and_cache(ctp);
+ set_method_additional_property(ctp, mtp_property_private);
+ set_Call_type(call, ctp);
+ DB((dbgcall, LEVEL_1, "changed call to private method %+F\n", ent));
+ }
+ }
+ }
+ }
+} /* update_calls_to_private */
+
+/* Mark all private methods, i.e. those of which all call sites are known. */
+void mark_private_methods(void) {
+ int i;
+ int changed = 0;
+
+ FIRM_DBG_REGISTER(dbgcall, "firm.opt.cc");
+
+ assure_irp_globals_address_taken_computed();
+
+ mtp_map = pmap_create();
+
+ /* first step: change the calling conventions of the local non-escaped entities */
+ for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
+ ir_graph *irg = get_irp_irg(i);
+ ir_entity *ent = get_irg_entity(irg);
+ ir_address_taken_state state = get_entity_address_taken(ent);
+
+ if (get_entity_visibility(ent) == visibility_local &&
+ state == ir_address_not_taken) {
+ ir_type *mtp = get_entity_type(ent);
+
+ set_entity_additional_property(ent, mtp_property_private);
+ DB((dbgcall, LEVEL_1, "found private method %+F\n", ent));
+ if ((get_method_additional_properties(mtp) & mtp_property_private) == 0) {
+ /* need a new type */
+ mtp = clone_type_and_cache(mtp);
+ set_entity_type(ent, mtp);
+ set_method_additional_property(mtp, mtp_property_private);
+ changed = 1;
+ }
+ }
+ }
+
+ if (changed)
+ all_irg_walk(NULL, update_calls_to_private, NULL);
+
+ pmap_destroy(mtp_map);
+} /* mark_private_methods */