📄 class.c
字号:
treebuild_vfn_ref (ptr_to_instptr, instance, idx) tree *ptr_to_instptr, instance; tree idx;{ extern int building_cleanup; tree vtbl, aref; tree basetype = TREE_TYPE (instance); if (TREE_CODE (basetype) == REFERENCE_TYPE) basetype = TREE_TYPE (basetype); if (instance == C_C_D) vtbl = build_indirect_ref (build_vfield_ref (instance, basetype), NULL_PTR); else { if (optimize) { /* Try to figure out what a reference refers to, and access its virtual function table directly. */ tree ref = NULL_TREE; if (TREE_CODE (instance) == INDIRECT_REF && TREE_CODE (TREE_TYPE (TREE_OPERAND (instance, 0))) == REFERENCE_TYPE) ref = TREE_OPERAND (instance, 0); else if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE) ref = instance; if (ref && TREE_CODE (ref) == VAR_DECL && DECL_INITIAL (ref)) { tree init = DECL_INITIAL (ref); while (TREE_CODE (init) == NOP_EXPR || TREE_CODE (init) == NON_LVALUE_EXPR) init = TREE_OPERAND (init, 0); if (TREE_CODE (init) == ADDR_EXPR) { init = TREE_OPERAND (init, 0); if (IS_AGGR_TYPE (TREE_TYPE (init)) && (TREE_CODE (init) == PARM_DECL || TREE_CODE (init) == VAR_DECL)) instance = init; } } } 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), NULL_PTR); } assemble_external (vtbl); aref = build_array_ref (vtbl, idx); /* Save the intermediate result in a SAVE_EXPR so we don't have to compute each component of the virtual function pointer twice. */ if (!building_cleanup && TREE_CODE (aref) == INDIRECT_REF) TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0)); if (flag_vtable_thunks) return aref; else { if (ptr_to_instptr) *ptr_to_instptr = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr), *ptr_to_instptr, convert (ptrdiff_type_node, build_component_ref (aref, delta_identifier, 0, 0))); return build_component_ref (aref, pfn_identifier, 0, 0); }}/* Return the name of the virtual function table (as an IDENTIFIER_NODE) for the given TYPE. */static treeget_vtable_name (type) tree type;{ tree type_id = build_typename_overload (type); char *buf = (char *)alloca (strlen (VTABLE_NAME_FORMAT) + IDENTIFIER_LENGTH (type_id) + 2); char *ptr = IDENTIFIER_POINTER (type_id); int i; for (i = 0; ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) ;#if 0 /* We don't take off the numbers; prepare_fresh_vtable uses the DECL_ASSEMBLER_NAME for the type, which includes the number in `3foo'. If we were to pull them off here, we'd end up with something like `_vt.foo.3bar', instead of a uniform definition. */ while (ptr[i] >= '0' && ptr[i] <= '9') i += 1;#endif sprintf (buf, VTABLE_NAME_FORMAT, ptr+i); return get_identifier (buf);}/* 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, 0); 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;#ifndef WRITABLE_VTABLES /* Make them READONLY by default. (mrs) */ TREE_READONLY (decl) = 1;#endif /* At one time the vtable info was grabbed 2 words at a time. This fails on sparc unless you have 8-byte alignment. (tiemann) */ DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node), DECL_ALIGN (decl)); /* Why is this conditional? (mrs) */ if (binfo && write_virtuals >= 0) DECL_VIRTUAL_P (decl) = 1; DECL_CONTEXT (decl) = type; binfo = TYPE_BINFO (type); SET_BINFO_NEW_VTABLE_MARKED (binfo); return decl;}/* Given a base type PARENT, and a derived type TYPE, build a name which distinguishes exactly the PARENT member of TYPE's type. FORMAT is a string which controls how sprintf formats the name we have generated. For example, given class A; class B; class C : A, B; it is possible to distinguish "A" from "C's A". And given class L; class A : L; class B : L; class C : A, B; it is possible to distinguish "L" from "A's L", and also from "C's L from A". Make sure to use the DECL_ASSEMBLER_NAME of the TYPE_NAME of the type, as template have DECL_NAMEs like: X<int>, whereas the DECL_ASSEMBLER_NAME is set to be something the assembler can handle. */static treebuild_type_pathname (format, parent, type) char *format; tree parent, type;{ extern struct obstack temporary_obstack; char *first, *base, *name; int i; tree id; parent = TYPE_MAIN_VARIANT (parent); /* Remember where to cut the obstack to. */ first = obstack_base (&temporary_obstack); /* Put on TYPE+PARENT. */ obstack_grow (&temporary_obstack, TYPE_ASSEMBLER_NAME_STRING (type), TYPE_ASSEMBLER_NAME_LENGTH (type));#ifdef JOINER obstack_1grow (&temporary_obstack, JOINER);#else obstack_1grow (&temporary_obstack, '_');#endif obstack_grow0 (&temporary_obstack, TYPE_ASSEMBLER_NAME_STRING (parent), TYPE_ASSEMBLER_NAME_LENGTH (parent)); i = obstack_object_size (&temporary_obstack); base = obstack_base (&temporary_obstack); obstack_finish (&temporary_obstack); /* Put on FORMAT+TYPE+PARENT. */ obstack_blank (&temporary_obstack, strlen (format) + i + 1); name = obstack_base (&temporary_obstack); sprintf (name, format, base); id = get_identifier (name); obstack_free (&temporary_obstack, first); return id;}/* Update the rtti info for this class. */static voidset_rtti_entry (virtuals, offset, type) tree virtuals, offset, type;{ if (! flag_vtable_thunks) TREE_VALUE (virtuals) = build_vtable_entry (offset, (flag_rtti ? build_t_desc (type, 0) : integer_zero_node)); else { tree vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, offset); TREE_CONSTANT (vfn) = 1; TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, vfn); /* The second slot is for the tdesc pointer when thunks are used. */ vfn = flag_rtti ? build_t_desc (type, 0) : integer_zero_node; vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, vfn); TREE_CONSTANT (vfn) = 1; TREE_VALUE (TREE_CHAIN (virtuals)) = build_vtable_entry (integer_zero_node, vfn); }}/* 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. */static voidprepare_fresh_vtable (binfo, for_type) tree binfo, for_type;{ tree basetype = BINFO_TYPE (binfo); tree orig_decl = BINFO_VTABLE (binfo); /* This name is too simplistic. We can have multiple basetypes for for_type, and we really want different names. (mrs) */ 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, offset; int result; /* Remember which class this vtable is really for. */ 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;#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)) offset = BINFO_OFFSET (binfo_member (BINFO_TYPE (binfo), CLASSTYPE_VBASECLASSES (for_type))); else offset = BINFO_OFFSET (binfo); set_rtti_entry (BINFO_VIRTUALS (binfo), size_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);}/* 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;}/* 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 i. 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 treeadd_virtual_function (pending_virtuals, has_virtual, fndecl, t) tree pending_virtuals; int *has_virtual; tree fndecl; tree t; /* Structure type. */{ /* 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; if (flag_rtti && *has_virtual == 0) { /* CLASSTYPE_RTTI is only used as a Boolean (NULL or not). */ CLASSTYPE_RTTI (t) = integer_one_node; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -