📄 class.c
字号:
/* We better not run out of stuff to make it unique. */ my_friendly_assert (path != NULL_TREE, 368); basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (path)); if (for_type == basetype) { /* If we run out of basetypes in the path, we have already found created a vtable with that name before, we now resort to tacking on _%d to distinguish them. */ int j = 2; i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1 + i + 1 + 3; buf1 = (char *) alloca (i); do { sprintf (buf1, "%s%c%s%c%d", TYPE_ASSEMBLER_NAME_STRING (basetype), joiner, buf2, joiner, j); buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT) + strlen (buf1) + 1); sprintf (buf, VTABLE_NAME_FORMAT, buf1); name = get_identifier (buf); /* If this name doesn't clash, then we can use it, otherwise we add something different to the name until it is unique. */ } while (++j <= 999 && IDENTIFIER_GLOBAL_VALUE (name)); /* Hey, they really like MI don't they? Increase the 3 above to 6, and the 999 to 999999. :-) */ my_friendly_assert (j <= 999, 369); break; } i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1 + i; new_buf2 = (char *) alloca (i); sprintf (new_buf2, "%s%c%s", TYPE_ASSEMBLER_NAME_STRING (basetype), joiner, buf2); buf2 = new_buf2; } new_decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (orig_decl)); /* Remember which class this vtable is really for. */ DECL_CONTEXT (new_decl) = for_type; DECL_ARTIFICIAL (new_decl) = 1; TREE_STATIC (new_decl) = 1; BINFO_VTABLE (binfo) = pushdecl_top_level (new_decl); DECL_VIRTUAL_P (new_decl) = 1;#ifndef WRITABLE_VTABLES /* Make them READONLY by default. (mrs) */ TREE_READONLY (new_decl) = 1;#endif DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl); /* Make fresh virtual list, so we can smash it later. */ BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo)); if (TREE_VIA_VIRTUAL (binfo)) { tree binfo1 = binfo_member (BINFO_TYPE (binfo), CLASSTYPE_VBASECLASSES (for_type)); /* XXX - This should never happen, if it does, the caller should ensure that the binfo is from for_type's binfos, not from any base type's. We can remove all this code after a while. */ if (binfo1 != binfo) warning ("internal inconsistency: binfo offset error for rtti"); offset = BINFO_OFFSET (binfo1); } else offset = BINFO_OFFSET (binfo); set_rtti_entry (BINFO_VIRTUALS (binfo), ssize_binop (MINUS_EXPR, integer_zero_node, offset), for_type);#ifdef GATHER_STATISTICS n_vtables += 1; n_vtable_elems += list_length (BINFO_VIRTUALS (binfo));#endif /* Set TREE_PUBLIC and TREE_EXTERN as appropriate. */ import_export_vtable (new_decl, for_type, 0); if (TREE_VIA_VIRTUAL (binfo)) my_friendly_assert (binfo == binfo_member (BINFO_TYPE (binfo), CLASSTYPE_VBASECLASSES (current_class_type)), 170); SET_BINFO_NEW_VTABLE_MARKED (binfo);}/* Return a new vtable for use in initialization of the BASE subobject of COMPLETE_TYPE. The vtable there goes into the vfield of the VBASEBASE virtual subobject. */static treeprepare_ctor_vtable (complete_type, base, vbasebase) tree complete_type, base, vbasebase;{ tree orig_decl = BINFO_VTABLE (vbasebase); tree name = get_vlist_vtable_id (base, vbasebase); tree new_decl; new_decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (orig_decl)); /* Remember which class this vtable is really for. */ DECL_CONTEXT (new_decl) = complete_type; DECL_ARTIFICIAL (new_decl) = 1; TREE_STATIC (new_decl) = 1; new_decl = pushdecl_top_level (new_decl); DECL_VIRTUAL_P (new_decl) = 1;#ifndef WRITABLE_VTABLES /* Make them READONLY by default. (mrs) */ TREE_READONLY (new_decl) = 1;#endif DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl);#ifdef GATHER_STATISTICS n_vtables += 1; n_vtable_elems += list_length (BINFO_VIRTUALS (binfo));#endif /* Set TREE_PUBLIC and TREE_EXTERN as appropriate. */ import_export_vtable (new_decl, complete_type, 0); return new_decl;}#if 0/* Access the virtual function table entry that logically contains BASE_FNDECL. VIRTUALS is the virtual function table's initializer. We can run off the end, when dealing with virtual destructors in MI situations, return NULL_TREE in that case. */static treeget_vtable_entry (virtuals, base_fndecl) tree virtuals, base_fndecl;{ unsigned HOST_WIDE_INT n = (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD ? (TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl)) & (((unsigned HOST_WIDE_INT)1<<(BITS_PER_WORD-1))-1)) : TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl)));#ifdef GATHER_STATISTICS n_vtable_searches += n;#endif while (n > 0 && virtuals) { --n; virtuals = TREE_CHAIN (virtuals); } return virtuals;}#endif/* Put new entry ENTRY into virtual function table initializer VIRTUALS. Also update DECL_VINDEX (FNDECL). */static voidmodify_vtable_entry (old_entry_in_list, new_entry, fndecl) tree old_entry_in_list, new_entry, fndecl;{ tree base_fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (old_entry_in_list)), 0);#ifdef NOTQUITE cp_warning ("replaced %D with %D", DECL_ASSEMBLER_NAME (base_fndecl), DECL_ASSEMBLER_NAME (fndecl));#endif TREE_VALUE (old_entry_in_list) = new_entry; /* Now assign virtual dispatch information, if unset. */ /* We can dispatch this, through any overridden base function. */ if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST) { DECL_VINDEX (fndecl) = DECL_VINDEX (base_fndecl); DECL_CONTEXT (fndecl) = DECL_CONTEXT (base_fndecl); }}/* Access the virtual function table entry N. VIRTUALS is the virtual function table's initializer. */static treeget_vtable_entry_n (virtuals, n) tree virtuals; unsigned HOST_WIDE_INT n;{ while (n > 0) { --n; virtuals = TREE_CHAIN (virtuals); } return virtuals;}/* Add a virtual function to all the appropriate vtables for the class T. DECL_VINDEX(X) should be error_mark_node, if we want to allocate a new slot in our table. If it is error_mark_node, we know that no other function from another vtable is overridden by X. HAS_VIRTUAL keeps track of how many virtuals there are in our main vtable for the type, and we build upon the PENDING_VIRTUALS list and return it. */static voidadd_virtual_function (pv, phv, has_virtual, fndecl, t) tree *pv, *phv; int *has_virtual; tree fndecl; tree t; /* Structure type. */{ tree pending_virtuals = *pv; tree pending_hard_virtuals = *phv; /* FUNCTION_TYPEs and OFFSET_TYPEs no longer freely convert to void *. Make such a conversion here. */ tree vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl); TREE_CONSTANT (vfn) = 1;#ifndef DUMB_USER if (current_class_type == 0) cp_warning ("internal problem, current_class_type is zero when adding `%D', please report", fndecl); if (current_class_type && t != current_class_type) cp_warning ("internal problem, current_class_type differs when adding `%D', please report", fndecl);#endif /* If the virtual function is a redefinition of a prior one, figure out in which base class the new definition goes, and if necessary, make a fresh virtual function table to hold that entry. */ if (DECL_VINDEX (fndecl) == error_mark_node) { tree entry; /* We remember that this was the base sub-object for rtti. */ CLASSTYPE_RTTI (t) = t; /* If we are using thunks, use two slots at the front, one for the offset pointer, one for the tdesc pointer. For ARM-style vtables, use the same slot for both. */ if (*has_virtual == 0 && ! CLASSTYPE_COM_INTERFACE (t)) { if (flag_vtable_thunks) *has_virtual = 2; else *has_virtual = 1; } /* Build a new INT_CST for this DECL_VINDEX. */ { static tree index_table[256]; tree idx; /* We skip a slot for the offset/tdesc entry. */ int i = (*has_virtual)++; if (i >= 256 || index_table[i] == 0) { idx = build_int_2 (i, 0); if (i < 256) index_table[i] = idx; } else idx = index_table[i]; /* Now assign virtual dispatch information. */ DECL_VINDEX (fndecl) = idx; DECL_CONTEXT (fndecl) = t; } entry = build_vtable_entry (integer_zero_node, vfn); pending_virtuals = tree_cons (DECL_VINDEX (fndecl), entry, pending_virtuals); } /* Might already be INTEGER_CST if declared twice in class. We will give error later or we've already given it. */ else if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST) { /* Need an entry in some other virtual function table. Deal with this after we have laid out our virtual base classes. */ pending_hard_virtuals = temp_tree_cons (fndecl, vfn, pending_hard_virtuals); } *pv = pending_virtuals; *phv = pending_hard_virtuals;}/* Obstack on which to build the vector of class methods. */struct obstack class_obstack;extern struct obstack *current_obstack;/* These are method vectors that were too small for the number of methods in some class, and so were abandoned. */static tree free_method_vecs;/* Returns a method vector with enough room for N methods. N should be a power of two. */static treemake_method_vec (n) int n;{ tree new_vec; tree* t; for (t = &free_method_vecs; *t; t = &(TREE_CHAIN (*t))) /* Note that we don't use >= n here because we don't want to allocate a very large vector where it isn't needed. */ if (TREE_VEC_LENGTH (*t) == n) { new_vec = *t; *t = TREE_CHAIN (new_vec); TREE_CHAIN (new_vec) = NULL_TREE; bzero ((PTR) &TREE_VEC_ELT (new_vec, 0), n * sizeof (tree)); return new_vec; } new_vec = make_tree_vec (n); return new_vec;}/* Free the method vector VEC. */static voidfree_method_vec (vec) tree vec;{ TREE_CHAIN (vec) = free_method_vecs; free_method_vecs = vec;}/* Add method METHOD to class TYPE. If non-NULL, FIELDS is the entry in the METHOD_VEC vector entry of the class type where the method should be added. */voidadd_method (type, fields, method) tree type, *fields, method;{ push_obstacks_nochange (); end_temporary_allocation (); /* Setting the DECL_CONTEXT and DECL_CLASS_CONTEXT here is probably redundant. */ DECL_CONTEXT (method) = type; DECL_CLASS_CONTEXT (method) = type; if (fields && *fields) *fields = build_overload (method, *fields); else { int len; int slot; tree method_vec; if (!CLASSTYPE_METHOD_VEC (type)) /* Make a new method vector. We start with 8 entries. We must allocate at least two (for constructors and destructors), and we're going to end up with an assignment operator at some point as well. We could use a TREE_LIST for now, and convert it to a TREE_VEC in finish_struct, but we would probably waste more memory making the links in the list than we would by over-allocating the size of the vector here. Furthermore, we would complicate all the code that expects this to be a vector. We keep a free list of vectors that we outgrew so that we don't really waste any memory. */ CLASSTYPE_METHOD_VEC (type) = make_method_vec (8); method_vec = CLASSTYPE_METHOD_VEC (type); len = TREE_VEC_LENGTH (method_vec); if (DECL_NAME (method) == constructor_name (type)) /* A new constructor or destructor. Constructors go in slot 0; destructors go in slot 1. */ slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0; else { /* See if we already have an entry with this name. */ for (slot = 2; slot < len; ++slot) if (!TREE_VEC_ELT (method_vec, slot) || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, slot))) == DECL_NAME (method))) break; if (slot == len) { /* We need a bigger method vector. */ tree new_vec = make_method_vec (2 * len); bcopy ((PTR) &TREE_VEC_ELT (method_vec, 0), (PTR) &TREE_VEC_ELT (new_vec, 0), len * sizeof (tree)); free_method_vec (method_vec); len = 2 * len; method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec; } if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot)) { /* Type conversion operators have to come before ordinary methods; add_conversions depends on this to speed up looking for conversion operators. So, if necessary, we slide some of the vector elements up. In theory, this makes this algorithm O(N^2) but we don't expect many conversion operators. */ for (slot = 2; slot < len; ++slot) { tree fn = TREE_VEC_ELT (method_vec, slot); if (!fn) /* There are no more entries in the vector, so we can insert the new conversion operator here. */ break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -