+ default:
+ assert(0 && "unexpected opcode or opcode not implemented");
+ break;
+ }
+ set_irn_link(node, NULL);
+}
+
+
+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);
+}
+
+
+static void free_ana_walker(ir_node * node, eset * set) {
+ int i;
+ if (get_irn_link(node) == MARK) {
+ /* bereits in einem Zyklus besucht. */
+ 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_arity(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);
+}
+
+/* Die Datenstrukturen für sel-Methoden (sel_methods) muß vor dem
+ * Aufruf von "get_free_methods" aufgebaut sein. Die (internen)
+ * SymConst(name)-Operationen müssen in passende SymConst(ent)-Operationen
+ * umgewandelt worden sein, d.h. SymConst-Operationen verweisen immer
+ * auf eine echt externe Methode. */
+static entity ** get_free_methods(void)
+{
+ eset * set = eset_create();
+ int i;
+ entity ** arr = NEW_ARR_F(entity *, 0);
+ entity * ent;
+
+ for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
+ ir_graph * irg = get_irp_irg(i);
+ entity * ent = get_irg_entity(irg);
+ /* insert "external visible" methods. */
+ if (get_entity_visibility(ent) != visibility_local) {
+ eset_insert(set, ent);
+ }
+ /* Finde alle Methoden die in dieser Methode extern sichtbar werden,
+ z.B. da die Adresse einer Methode abgespeichert wird. */
+ irg_walk_graph(irg, NULL, (irg_walk_func *) free_ana_walker, set);
+ }
+
+ /* insert sticky methods, too */
+ for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
+ entity * ent = get_irg_entity(get_irp_irg(i));
+ /* insert "external visible" methods. */
+ if (get_entity_stickyness (ent) == stickyness_sticky) {
+ eset_insert(set, ent);
+ }
+ }
+
+ /* Hauptprogramm ist auch dann frei, wenn es nicht "external
+ * visible" ist. */
+ if (get_irp_main_irg()) {
+ eset_insert(set, get_irg_entity(get_irp_main_irg()));
+ }
+ /* Wandle Menge in Feld um. Effizienter. */
+ for (ent = eset_first(set); ent; ent = eset_next(set)) {
+ ARR_APP1(entity *, arr, ent);
+ }
+ eset_destroy(set);
+
+ return arr;
+}