📄 cp-class.c
字号:
if (IS_AGGR_TYPE (TREE_TYPE (instance)) && (TREE_CODE (instance) == RESULT_DECL || TREE_CODE (instance) == PARM_DECL || TREE_CODE (instance) == VAR_DECL)) vtbl = TYPE_BINFO_VTABLE (basetype); else vtbl = build_indirect_ref (build_vfield_ref (instance, basetype), 0); } assemble_external (vtbl); aref = build_array_ref (vtbl, index); if (!building_cleanup && TREE_CODE (aref) == INDIRECT_REF) TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0)); *ptr_to_instptr = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr), *ptr_to_instptr, convert (integer_type_node, build_component_ref (aref, delta_name, 0, 0))); return build_component_ref (aref, pfn_name, 0, 0);}/* Set TREE_PUBLIC and/or TREE_EXTERN on the vtable DECL, based on TYPE and other static flags. Note that anything public is tagged TREE_PUBLIC, whether it's public in this file or in another one. */static voidimport_export_vtable (decl, type) tree decl, type;{ if (write_virtuals >= 2) { if (CLASSTYPE_INTERFACE_UNKNOWN (type) == 0) { TREE_PUBLIC (decl) = 1; DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type); } } else if (write_virtuals != 0) { TREE_PUBLIC (decl) = 1; if (write_virtuals < 0) DECL_EXTERNAL (decl) = 1; }}/* Build a virtual function for type TYPE. If BINFO is non-NULL, build the vtable starting with the initial approximation that it is the same as the one which is the head of the association list. */static treebuild_vtable (binfo, type) tree binfo, type;{ tree name = get_vtable_name (type); tree virtuals, decl; if (binfo) { virtuals = copy_list (BINFO_VIRTUALS (binfo)); decl = build_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo))); } else { virtuals = NULL_TREE; decl = build_decl (VAR_DECL, name, void_type_node); }#ifdef GATHER_STATISTICS n_vtables += 1; n_vtable_elems += list_length (virtuals);#endif /* Set TREE_PUBLIC and TREE_EXTERN as appropriate. */ import_export_vtable (decl, type); IDENTIFIER_GLOBAL_VALUE (name) = decl = pushdecl_top_level (decl); /* Initialize the association list for this type, based on our first approximation. */ TYPE_BINFO_VTABLE (type) = decl; TYPE_BINFO_VIRTUALS (type) = virtuals; TREE_STATIC (decl) = 1; DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node), DECL_ALIGN (decl)); if (binfo && write_virtuals >= 0) DECL_VIRTUAL_P (decl) = 1; /* Remember which class this vtable is really for. */ DECL_VPARENT (decl) = type; DECL_CONTEXT (decl) = type; binfo = TYPE_BINFO (type); SET_BINFO_VTABLE_PATH_MARKED (binfo); SET_BINFO_NEW_VTABLE_MARKED (binfo); return decl;}/* Give TYPE a new virtual function table which is initialized with a skeleton-copy of its original initialization. The only entry that changes is the `delta' entry, so we can really share a lot of structure. FOR_TYPE is the derived type which caused this table to be needed. BINFO is the type association which provided TYPE for FOR_TYPE. The way we update BASE_BINFO's vtable information is just to change the association information in FOR_TYPE's association list. */static voidprepare_fresh_vtable (binfo, base_binfo, for_type) tree binfo, base_binfo, for_type;{ tree basetype = BINFO_TYPE (binfo); tree orig_decl = BINFO_VTABLE (binfo); tree name = build_type_pathname (VTABLE_NAME_FORMAT, basetype, for_type); tree new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl)); tree path; int result; /* Remember which class this vtable is really for. */ DECL_VPARENT (new_decl) = BINFO_TYPE (base_binfo); DECL_CONTEXT (new_decl) = for_type; TREE_STATIC (new_decl) = 1; BINFO_VTABLE (binfo) = pushdecl_top_level (new_decl); DECL_VIRTUAL_P (new_decl) = 1; 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)); /* Install the value for `headof' if that's what we're doing. */ if (flag_dossier) TREE_VALUE (TREE_CHAIN (BINFO_VIRTUALS (binfo))) = build_vtable_entry (size_binop (MINUS_EXPR, integer_zero_node, BINFO_OFFSET (binfo)), FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (TREE_CHAIN (BINFO_VIRTUALS (binfo)))));#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); 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); SET_BINFO_VTABLE_PATH_MARKED (binfo); /* Mark all types between FOR_TYPE and TYPE as having been touched, so that if we change virtual function table entries, new vtables will be initialized. We may reach the virtual baseclass via ambiguous intervening baseclasses. This loop makes sure we get through to the actual baseclass we marked. Also, update the vtable entries to reflect the overrides of the top-most class (short of the top type). */ do { result = get_base_distance (basetype, for_type, 0, &path); for_type = path; while (path) { tree path_binfo = path; tree path_type = BINFO_TYPE (path); if (TREE_VIA_VIRTUAL (path)) path_binfo = binfo_member (path_type, CLASSTYPE_VBASECLASSES (current_class_type)); SET_BINFO_VTABLE_PATH_MARKED (path_binfo); if (BINFO_INHERITANCE_CHAIN (path) && CLASSTYPE_VFIELD (path_type) != NULL_TREE && (DECL_NAME (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))) == DECL_NAME (CLASSTYPE_VFIELD (path_type))) /* This is the baseclass just before the original FOR_TYPE. */ && BINFO_INHERITANCE_CHAIN (BINFO_INHERITANCE_CHAIN (path)) == NULL_TREE) { tree old_virtuals = TREE_CHAIN (BINFO_VIRTUALS (binfo)); tree new_virtuals = TREE_CHAIN (BINFO_VIRTUALS (path_binfo)); if (flag_dossier) { old_virtuals = TREE_CHAIN (old_virtuals); new_virtuals = TREE_CHAIN (new_virtuals); } while (old_virtuals) { TREE_VALUE (old_virtuals) = TREE_VALUE (new_virtuals); old_virtuals = TREE_CHAIN (old_virtuals); new_virtuals = TREE_CHAIN (new_virtuals); } } path = BINFO_INHERITANCE_CHAIN (path); } } while (result == -2);}/* Access the virtual function table entry that logically contains BASE_FNDECL. VIRTUALS is the virtual function table's initializer. */static treeget_vtable_entry (virtuals, base_fndecl) tree virtuals, base_fndecl;{ int i = (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD#ifdef VTABLE_USES_MASK && 0#endif ? (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 += i;#endif while (i > 0) { virtuals = TREE_CHAIN (virtuals); i -= 1; } return virtuals;}/* Put new entry ENTRY into virtual function table initializer VIRTUALS. The virtual function table is for type CONTEXT. Also update DECL_VINDEX (FNDECL). */static voidmodify_vtable_entry (old_entry_in_list, new_entry, fndecl, context) tree old_entry_in_list, new_entry, fndecl, context;{ tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (old_entry_in_list)); tree vindex; /* We can't put in the really right offset information here, since we have not yet laid out the class to take into account virtual base classes. */ TREE_VALUE (old_entry_in_list) = new_entry; vindex = DECL_VINDEX (TREE_OPERAND (base_pfn, 0)); if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST) DECL_VINDEX (fndecl) = vindex; else { if (! tree_int_cst_equal (DECL_VINDEX (fndecl), vindex)) { tree elts = CONSTRUCTOR_ELTS (new_entry); tree vfield = CLASSTYPE_VFIELD (context); if (! doing_hard_virtuals) { pending_hard_virtuals = tree_cons (fndecl, FNADDR_FROM_VTABLE_ENTRY (new_entry), pending_hard_virtuals); TREE_TYPE (pending_hard_virtuals) = TREE_OPERAND (base_pfn, 0); return; }#if 0 my_friendly_abort (3); /* Compute the relative offset of vtable we are really looking for. */ TREE_VALUE (elts) = size_binop (PLUS_EXPR, size_int (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (vfield))/* ??? This may be wrong. */ / BITS_PER_UNIT), TREE_VALUE (elts)); /* Say what index to use when we use that vtable. */#ifndef VTABLE_USES_MASK vindex = build_int_2 (TREE_INT_CST_LOW (vindex) & ~((unsigned HOST_WIDE_INT) 1 << (BITS_PER_WORD -1)), 0);#endif TREE_VALUE (TREE_CHAIN (elts)) = vindex;#endif } }}/* Modify virtual function tables in lattice topped by T to place FNDECL in tables which previously held BASE_FNDECL. PFN is just FNDECL wrapped in an ADDR_EXPR, so that it is suitable for placement directly into an initializer. All distinct virtual function tables that this type uses must be updated. */static voidmodify_vtable_entries (t, fndecl, base_fndecl, pfn) tree t; tree fndecl, base_fndecl, pfn;{ tree base_offset, offset; tree base_context = DECL_CLASS_CONTEXT (base_fndecl); tree context = DECL_CLASS_CONTEXT (fndecl); tree vfield = CLASSTYPE_VFIELD (t); tree vfields, vbases; DECL_CONTEXT (fndecl) = DECL_CONTEXT (base_fndecl); offset = integer_zero_node; if (context != t && TYPE_USES_COMPLEX_INHERITANCE (t)) { offset = virtual_offset (context, CLASSTYPE_VBASECLASSES (t), offset); if (offset == NULL_TREE) { tree binfo = binfo_value (context, t, 0); offset = BINFO_OFFSET (binfo); } } /* For each layer of base class (i.e., the first base class, and each virtual base class from that one), modify the virtual function table of the derived class to contain the new virtual function. A class has as many vfields as it has virtual base classes (total). */ for (vfields = CLASSTYPE_VFIELDS (t); vfields; vfields = TREE_CHAIN (vfields)) { int normal = 1; tree binfo, this_offset; tree base, path; /* Find the right base class for this derived class, call it BASE. */ base = VF_BASETYPE_VALUE (vfields); if (base != base_context) { /* If BASE_FNDECL is not contained in the vtable accessed by the vslot, don't try to modify the vtable. Virtual functions from virtual baseclasses are not in derived virtual function tables. This is an implementation decision; it keeps there from being a combinatorial explosion in the number of different vtables which must be maintained. */ /* In this case, we need to know whether BASE is derived from BASE_CONTEXT in any case, even the case where the derivation is ambiguous. */ int distance = get_base_distance (base, base_context, 0, 0); if (distance < 0 && distance != -2) continue; /* BASE_FNDECL is defined in a class derived from the base class owning this VFIELD. */ } /* Get the path starting from the deepest base class CONTEXT of T (i.e., first defn of BASE_FNDECL). */ get_base_distance (base_context, t, 0, &path); /* Get our best approximation of what to use for constructing the virtual function table for T. */ do { /* Walk from base toward derived, stopping at the most derived baseclass that matters. That baseclass is exactly the one which provides the vtable along the VFIELD spine, but no more. */ if (TREE_VIA_VIRTUAL (path)) { base = path; binfo = binfo_member (BINFO_TYPE (base), CLASSTYPE_VBASECLASSES (t)); break; } if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE || (BINFO_TYPE (BINFO_BASETYPE (BINFO_INHERITANCE_CHAIN (path), 0)) != BINFO_TYPE (path)) || BINFO_INHERITANCE_CHAIN (BINFO_INHERITANCE_CHAIN (path)) == NULL_TREE) { base = path; binfo = base; break; } path = BINFO_INHERITANCE_CHAIN (path); } while (1); /* Find the right offset for the this pointer based on the base class we just found. */ base_offset = BINFO_OFFSET (binfo); this_offset = size_binop (MINUS_EXPR, offset, base_offset); /* Make sure we can modify the derived association with immunity. */ if (TREE_USED (TYPE_BINFO (t))) TYPE_BINFO (t) = copy_binfo (TYPE_BINFO (t)); /* We call this case NORMAL iff this virtual function table pointer field has its storage reserved in this class. This is normally the case without virtual baseclasses or off-center multiple baseclasses. */ normal = (vfield != NULL_TREE && VF_BASETYPE_VALUE (vfields) == DECL_FCONTEXT (vfield) && (VF_BINFO_VALUE (vfields) == NULL_TREE || ! TREE_VIA_VIRTUAL (VF_BINFO_VALUE (vfields)))); if (normal && VF_BINFO_VALUE (vfields)) /* Everything looks normal so far...check that we are really working from VFIELD's basetype, and not some other appearance of that basetype in the lattice. */ normal = (VF_BINFO_VALUE (vfields) == get_binfo (VF_BASETYPE_VALUE (vfields), t, 0)); if (normal) { /* In this case, it is *type*'s vtable we are modifying. We start with the approximation that it's vtable is that
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -