+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Representation of all program known entities.
+ * @author Martin Trapp, Christian Schaefer, Goetz Lindenmaier, Michael Beck
+ * @version $Id$
+ */
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "firm_common_t.h"
+
+#include "xmalloc.h"
+#include "entity_t.h"
+#include "array.h"
+#include "irtools.h"
+#include "irhooks.h"
+#include "irprintf.h"
+
+#include "irprog_t.h"
+#include "ircons.h"
+#include "tv_t.h"
+#include "irdump.h"
+#include "irgraph_t.h"
+#include "callgraph.h"
+#include "error.h"
+
+/*-----------------------------------------------------------------*/
+/** general **/
+/*-----------------------------------------------------------------*/
+
+ir_entity *unknown_entity = NULL;
+
+ir_entity *get_unknown_entity(void) { return unknown_entity; }
+
+/** The name of the unknown entity. */
+#define UNKNOWN_ENTITY_NAME "unknown_entity"
+
+/*-----------------------------------------------------------------*/
+/* ENTITY */
+/*-----------------------------------------------------------------*/
+
+/**
+ * Add an entity to it's already set owner type.
+ */
+static inline void insert_entity_in_owner(ir_entity *ent) {
+ ir_type *owner = ent->owner;
+ switch (get_type_tpop_code(owner)) {
+ case tpo_class:
+ add_class_member(owner, ent);
+ break;
+ case tpo_struct:
+ add_struct_member(owner, ent);
+ break;
+ case tpo_union:
+ add_union_member(owner, ent);
+ break;
+ case tpo_array:
+ set_array_element_entity(owner, ent);
+ break;
+ default:
+ panic("Unsupported type kind");
+ }
+} /* insert_entity_in_owner */
+
+/**
+ * Creates a new entity. This entity is NOT inserted in the owner type.
+ *
+ * @param db debug info for this entity
+ * @param owner the owner type of the new entity
+ * @param name the name of the new entity
+ * @param type the type of the new entity
+ *
+ * @return the new created entity
+ */
+static inline ir_entity *
+new_rd_entity(dbg_info *db, ir_type *owner, ident *name, ir_type *type)
+{
+ ir_entity *res;
+ ir_graph *rem;
+
+ assert(!id_contains_char(name, ' ') && "entity name should not contain spaces");
+
+ res = XMALLOCZ(ir_entity);
+
+ res->kind = k_entity;
+ res->name = name;
+ res->ld_name = NULL;
+ res->type = type;
+ res->owner = owner;
+
+ res->allocation = allocation_automatic;
+ res->visibility = visibility_local;
+ res->volatility = volatility_non_volatile;
+ res->align = align_is_aligned;
+ res->stickyness = stickyness_unsticky;
+ res->peculiarity = peculiarity_existent;
+ res->usage = ir_usage_unknown;
+ res->final = 0;
+ res->compiler_gen = 0;
+ res->backend_marked = 0;
+ res->offset = -1;
+ res->offset_bit_remainder = 0;
+ res->link = NULL;
+ res->repr_class = NULL;
+
+ if (is_Method_type(type)) {
+ symconst_symbol sym;
+ ir_mode *mode = is_Method_type(type) ? mode_P_code : mode_P_data;
+ sym.entity_p = res;
+ rem = current_ir_graph;
+ current_ir_graph = get_const_code_irg();
+ res->value = new_SymConst(mode, sym, symconst_addr_ent);
+ current_ir_graph = rem;
+ res->allocation = allocation_static;
+ res->variability = variability_constant;
+ res->attr.mtd_attr.irg_add_properties = mtp_property_inherited;
+ res->attr.mtd_attr.vtable_number = VTABLE_NUM_NOT_SET;
+ res->attr.mtd_attr.param_access = NULL;
+ res->attr.mtd_attr.param_weight = NULL;
+ res->attr.mtd_attr.irg = NULL;
+ } else if (is_compound_type(type)) {
+ res->variability = variability_uninitialized;
+ res->value = NULL;
+ res->attr.cmpd_attr.values = NULL;
+ res->attr.cmpd_attr.val_paths = NULL;
+ } else {
+ res->variability = variability_uninitialized;
+ res->value = NULL;
+ }
+
+ if (is_Class_type(owner)) {
+ res->overwrites = NEW_ARR_F(ir_entity *, 0);
+ res->overwrittenby = NEW_ARR_F(ir_entity *, 0);
+ } else {
+ res->overwrites = NULL;
+ res->overwrittenby = NULL;
+ }
+
+#ifdef DEBUG_libfirm
+ res->nr = get_irp_new_node_nr();
+#endif /* DEBUG_libfirm */
+
+ res->visit = 0;
+ set_entity_dbg_info(res, db);
+
+ return res;
+} /* new_rd_entity */
+
+ir_entity *
+new_d_entity(ir_type *owner, ident *name, ir_type *type, dbg_info *db) {
+ ir_entity *res;
+
+ assert(is_compound_type(owner));
+ res = new_rd_entity(db, owner, name, type);
+ /* Remember entity in it's owner. */
+ insert_entity_in_owner(res);
+
+ hook_new_entity(res);
+ return res;
+} /* new_d_entity */
+
+ir_entity *
+new_entity(ir_type *owner, ident *name, ir_type *type) {
+ return new_d_entity(owner, name, type, NULL);
+} /* new_entity */
+
+/**
+ * Free entity attributes.
+ *
+ * @param ent the entity
+ */
+static void free_entity_attrs(ir_entity *ent) {
+ int i;
+ if (get_type_tpop(get_entity_owner(ent)) == type_class) {
+ DEL_ARR_F(ent->overwrites); ent->overwrites = NULL;
+ DEL_ARR_F(ent->overwrittenby); ent->overwrittenby = NULL;
+ } else {
+ assert(ent->overwrites == NULL);
+ assert(ent->overwrittenby == NULL);
+ }
+ if (is_compound_entity(ent)) {
+ if (ent->has_initializer) {
+ /* TODO: free initializers */
+ } else {
+ if (ent->attr.cmpd_attr.val_paths) {
+ for (i = get_compound_ent_n_values(ent) - 1; i >= 0; --i)
+ if (ent->attr.cmpd_attr.val_paths[i]) {
+ /* free_compound_graph_path(ent->attr.cmpd_attr.val_paths[i]) ; * @@@ warum nich? */
+ /* Geht nich: wird mehrfach verwendet!!! ==> mehrfach frei gegeben. */
+ /* DEL_ARR_F(ent->attr.cmpd_attr.val_paths); */
+ }
+ ent->attr.cmpd_attr.val_paths = NULL;
+ }
+ if (ent->attr.cmpd_attr.values) {
+ /*DEL_ARR_F(ent->attr.cmpd_attr.values)*/;
+ }
+ ent->attr.cmpd_attr.values = NULL;
+ }
+ } else if (is_method_entity(ent)) {
+ if (ent->attr.mtd_attr.param_access) {
+ DEL_ARR_F(ent->attr.mtd_attr.param_access);
+ ent->attr.mtd_attr.param_access = NULL;
+ }
+ if (ent->attr.mtd_attr.param_weight) {
+ DEL_ARR_F(ent->attr.mtd_attr.param_weight);
+ ent->attr.mtd_attr.param_weight = NULL;
+ }
+ }
+} /* free_entity_attrs */
+
+/**
+ * Creates a deep copy of an entity.
+ */
+static ir_entity *deep_entity_copy(ir_entity *old)
+{
+ ir_entity *newe = XMALLOC(ir_entity);
+
+ *newe = *old;
+ if (is_compound_entity(old)) {
+ if (old->has_initializer) {
+ /* FIXME: the initializers are NOT copied */
+ } else {
+ newe->attr.cmpd_attr.values = NULL;
+ newe->attr.cmpd_attr.val_paths = NULL;
+ if (old->attr.cmpd_attr.values)
+ newe->attr.cmpd_attr.values = DUP_ARR_F(ir_node *, old->attr.cmpd_attr.values);
+
+ /* FIXME: the compound graph paths are NOT copied */
+ if (old->attr.cmpd_attr.val_paths)
+ newe->attr.cmpd_attr.val_paths = DUP_ARR_F(compound_graph_path *, old->attr.cmpd_attr.val_paths);
+ }
+ } else if (is_method_entity(old)) {
+ /* do NOT copy them, reanalyze. This might be the best solution */
+ newe->attr.mtd_attr.param_access = NULL;
+ newe->attr.mtd_attr.param_weight = NULL;
+ }
+
+#ifdef DEBUG_libfirm
+ newe->nr = get_irp_new_node_nr();
+#endif
+ return newe;
+}
+/*
+ * Copies the entity if the new_owner is different from the
+ * owner of the old entity, else returns the old entity.
+ */
+ir_entity *
+copy_entity_own(ir_entity *old, ir_type *new_owner) {
+ ir_entity *newe;
+ assert(is_entity(old));
+ assert(is_compound_type(new_owner));
+ assert(get_type_state(new_owner) != layout_fixed);
+
+ if (old->owner == new_owner)
+ return old;
+
+ /* create a deep copy so we are safe of aliasing and double-freeing. */
+ newe = deep_entity_copy(old);
+ newe->owner = new_owner;
+
+ if (is_Class_type(new_owner)) {
+ newe->overwrites = NEW_ARR_F(ir_entity *, 0);
+ newe->overwrittenby = NEW_ARR_F(ir_entity *, 0);
+ }
+
+ insert_entity_in_owner(newe);
+ return newe;
+} /* copy_entity_own */
+
+ir_entity *
+copy_entity_name(ir_entity *old, ident *new_name) {
+ ir_entity *newe;
+ assert(old && old->kind == k_entity);
+
+ if (old->name == new_name) return old;
+ newe = deep_entity_copy(old);
+ newe->name = new_name;
+ newe->ld_name = NULL;
+
+ if (is_Class_type(newe->owner)) {
+ newe->overwrites = DUP_ARR_F(ir_entity *, old->overwrites);
+ newe->overwrittenby = DUP_ARR_F(ir_entity *, old->overwrittenby);
+ }
+ insert_entity_in_owner(newe);
+
+ return newe;
+} /* copy_entity_name */