+ case iro_Start:
+ case iro_Alloc:
+ case iro_Load:
+ /* nothing: Die Operationen werden in free_ana_walker() selbst
+ * behandelt. */
+ break;
+
+ default:
+ assert(0 && "unexpected opcode or opcode not implemented");
+ break;
+ }
+ set_irn_link(node, NULL);
+}
+
+/**
+ * Called for predecessors nodes of "interesting" ones.
+ * Interesting ones include all nodes that can somehow make
+ * a method visible.
+ *
+ * If a method (or a set of methods in case of polymorph calls) gets visible,
+ * add it to the set of 'free' methods
+ *
+ * @param node the current visited node
+ * @param set the set of all free methods
+ */
+static void free_mark(ir_node *node, eset * set) {
+ int i;
+
+ if (get_irn_link(node) == MARK)
+ return; /* already visited */
+
+ set_irn_link(node, MARK);
+
+ switch (get_irn_opcode(node)) {
+ case iro_Sel: {
+ entity * ent = get_Sel_entity(node);
+ if (is_Method_type(get_entity_type(ent))) {
+ for (i = get_Sel_n_methods(node) - 1; i >= 0; --i) {
+ eset_insert(set, get_Sel_method(node, i));
+ }
+ }
+ break;
+ }
+ case iro_SymConst:
+ if (get_SymConst_kind(node) == symconst_addr_ent) {
+ entity * ent = get_SymConst_entity(node);
+ if (is_Method_type(get_entity_type(ent))) {
+ eset_insert(set, ent);
+ }
+ } else {
+ assert(get_SymConst_kind(node) == symconst_addr_name);
+ /* nothing: SymConst points to extern method */
+ }
+ break;
+
+ case iro_Phi:
+ for (i = get_Phi_n_preds(node) - 1; i >= 0; --i) {
+ free_mark(get_Phi_pred(node, i), set);
+ }
+ break;
+ case iro_Id:
+ free_mark(get_Id_pred(node), set);
+ break;
+ case iro_Proj:
+ free_mark_proj(get_Proj_pred(node), get_Proj_proj(node), set);
+ break;
+ default:
+ /* nothing: Wird unten behandelt! */
+ break;
+ }
+ set_irn_link(node, NULL);
+}
+
+/**
+ * post-walker. Find method addresses.
+ */
+static void free_ana_walker(ir_node *node, void *env) {
+ eset *set = env;
+ int i;
+
+ if (get_irn_link(node) == MARK) {
+ /* already visited */
+ return;
+ }
+ switch (get_irn_opcode(node)) {
+ /* special nodes */
+ case iro_Sel:
+ case iro_SymConst:
+ case iro_Const:
+ case iro_Phi:
+ case iro_Id:
+ case iro_Proj:
+ case iro_Tuple:
+ /* nothing */
+ break;
+ /* Sonderbehandlung, da der Funktionszeigereingang natürlich kein
+ * Verräter ist. */
+ case iro_Call:
+ set_irn_link(node, MARK);
+ for (i = get_Call_n_params(node) - 1; i >= 0; --i) {
+ ir_node *pred = get_Call_param(node, i);
+ if (mode_is_reference(get_irn_mode(pred))) {
+ free_mark(pred, set);
+ }
+ }
+ break;
+ /* other nodes: Alle anderen Knoten nehmen wir als Verräter an, bis
+ * jemand das Gegenteil implementiert. */
+ default:
+ set_irn_link(node, MARK);
+ for (i = get_irn_arity(node) - 1; i >= 0; --i) {
+ ir_node * pred = get_irn_n(node, i);
+ if (mode_is_reference(get_irn_mode(pred))) {
+ free_mark(pred, set);
+ }
+ }
+ break;
+ }
+ set_irn_link(node, NULL);
+}
+
+/**
+ * Add all method addresses in global initializers to the set.
+ *
+ * @note
+ * We do NOT check the type here, just it it's an entity address.
+ * The reason for this is code like:
+ *
+ * void *p = function;
+ *
+ * which is sometimes used to anchor functions.
+ */
+static void add_method_address(entity *ent, eset *set)
+{
+ ir_node *n;
+ type *tp;
+ int i;
+
+ /* do not check uninitialized values */
+ if (get_entity_variability(ent) == variability_uninitialized)
+ return;
+
+ if (is_atomic_entity(ent)) {
+ tp = get_entity_type(ent);
+
+ /* ignore methods: these of course reference it's address */
+ if (is_Method_type(tp))
+ return;