📄 class.c
字号:
Note that the index (DELTA2) in the virtual function table is always 0. */static treebuild_vtable_entry (delta, pfn) tree delta, pfn;{ if (flag_vtable_thunks) { HOST_WIDE_INT idelta = TREE_INT_CST_LOW (delta); if (idelta && ! DECL_ABSTRACT_VIRTUAL_P (TREE_OPERAND (pfn, 0))) { pfn = build1 (ADDR_EXPR, vtable_entry_type, make_thunk (pfn, idelta)); TREE_READONLY (pfn) = 1; TREE_CONSTANT (pfn) = 1; }#ifdef GATHER_STATISTICS n_vtable_entries += 1;#endif return pfn; } else { extern int flag_huge_objects; tree elems = expr_tree_cons (NULL_TREE, delta, expr_tree_cons (NULL_TREE, integer_zero_node, build_expr_list (NULL_TREE, pfn))); tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems); /* DELTA used to be constructed by `size_int' and/or size_binop, which caused overflow problems when it was negative. That should be fixed now. */ if (! int_fits_type_p (delta, delta_type_node)) { if (flag_huge_objects) sorry ("object size exceeds built-in limit for virtual function table implementation"); else sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects"); } TREE_CONSTANT (entry) = 1; TREE_STATIC (entry) = 1; TREE_READONLY (entry) = 1;#ifdef GATHER_STATISTICS n_vtable_entries += 1;#endif return entry; }}/* We want to give the assembler the vtable identifier as well as the offset to the function pointer. So we generate __asm__ __volatile__ (".vtable_entry %c0, %c1" : : "s"(&class_vtable), "i"((long)&vtbl[idx].pfn - (long)&vtbl[0])); */static voidbuild_vtable_entry_ref (basetype, vtbl, idx) tree basetype, vtbl, idx;{ static char asm_stmt[] = ".vtable_entry %c0, %c1"; tree s, i, i2; s = build_unary_op (ADDR_EXPR, TYPE_BINFO_VTABLE (basetype), 0); s = build_tree_list (build_string (1, "s"), s); i = build_array_ref (vtbl, idx); if (!flag_vtable_thunks) i = build_component_ref (i, pfn_identifier, vtable_entry_type, 0); i = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i, 0)); i2 = build_array_ref (vtbl, build_int_2(0,0)); i2 = build_c_cast (ptrdiff_type_node, build_unary_op (ADDR_EXPR, i2, 0)); i = build_binary_op (MINUS_EXPR, i, i2); i = build_tree_list (build_string (1, "i"), i); expand_asm_operands (build_string (sizeof(asm_stmt)-1, asm_stmt), NULL_TREE, chainon (s, i), NULL_TREE, 1, NULL, 0);}/* Given an object INSTANCE, return an expression which yields the virtual function vtable element corresponding to INDEX. There are many special cases for INSTANCE which we take care of here, mainly to avoid creating extra tree nodes when we don't have to. */treebuild_vtbl_ref (instance, idx) tree instance, idx;{ tree vtbl, aref; tree basetype = TREE_TYPE (instance); if (TREE_CODE (basetype) == REFERENCE_TYPE) basetype = TREE_TYPE (basetype); if (instance == current_class_ref) vtbl = build_vfield_ref (instance, basetype); 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_vfield_ref (instance, basetype); } assemble_external (vtbl); if (flag_vtable_gc) build_vtable_entry_ref (basetype, vtbl, idx); aref = build_array_ref (vtbl, idx); return aref;}/* Given an object INSTANCE, return an expression which yields the virtual function corresponding to INDEX. There are many special cases for INSTANCE which we take care of here, mainly to avoid creating extra tree nodes when we don't have to. */treebuild_vfn_ref (ptr_to_instptr, instance, idx) tree *ptr_to_instptr, instance; tree idx;{ tree aref = build_vtbl_ref (instance, idx); /* When using thunks, there is no extra delta, and we get the pfn directly. */ if (flag_vtable_thunks) return aref; if (ptr_to_instptr) { /* Save the intermediate result in a SAVE_EXPR so we don't have to compute each component of the virtual function pointer twice. */ if (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, cp_convert (ptrdiff_type_node, build_component_ref (aref, delta_identifier, NULL_TREE, 0))); } return build_component_ref (aref, pfn_identifier, NULL_TREE, 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); const 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);}/* Return the offset to the main vtable for a given base BINFO. */treeget_vfield_offset (binfo) tree binfo;{ tree tmp = size_binop (FLOOR_DIV_EXPR, DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))), size_int (BITS_PER_UNIT)); tmp = convert (sizetype, tmp); return size_binop (PLUS_EXPR, tmp, BINFO_OFFSET (binfo));}/* Get the offset to the start of the original binfo that we derived this binfo from. If we find TYPE first, return the offset only that far. The shortened search is useful because the this pointer on method calling is expected to point to a DECL_CONTEXT (fndecl) object, and not a baseclass of it. */static treeget_derived_offset (binfo, type) tree binfo, type;{ tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo))); tree offset2; int i; while (BINFO_BASETYPES (binfo) && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1) { tree binfos = BINFO_BASETYPES (binfo); if (BINFO_TYPE (binfo) == type) break; binfo = TREE_VEC_ELT (binfos, i); } offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo))); return size_binop (MINUS_EXPR, offset1, offset2);}/* Update the rtti info for this class. */static voidset_rtti_entry (virtuals, offset, type) tree virtuals, offset, type;{ tree vfn; if (CLASSTYPE_COM_INTERFACE (type)) return; if (flag_rtti) vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, get_tinfo_fn_unused (type)); else vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, size_zero_node); TREE_CONSTANT (vfn) = 1; if (! flag_vtable_thunks) TREE_VALUE (virtuals) = build_vtable_entry (offset, vfn); else { tree voff = build1 (NOP_EXPR, vfunc_ptr_type_node, offset); TREE_CONSTANT (voff) = 1; TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, voff); /* The second slot is for the tdesc pointer when thunks are used. */ TREE_VALUE (TREE_CHAIN (virtuals)) = build_vtable_entry (integer_zero_node, vfn); }}/* 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) { tree offset; virtuals = copy_list (BINFO_VIRTUALS (binfo)); decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo))); /* Now do rtti stuff. */ offset = get_derived_offset (TYPE_BINFO (type), NULL_TREE); offset = ssize_binop (MINUS_EXPR, integer_zero_node, offset); set_rtti_entry (virtuals, offset, type); } else { virtuals = NULL_TREE; decl = build_lang_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); decl = pushdecl_top_level (decl); SET_IDENTIFIER_GLOBAL_VALUE (name, decl); /* Initialize the association list for this type, based on our first approximation. */ TYPE_BINFO_VTABLE (type) = decl; TYPE_BINFO_VIRTUALS (type) = virtuals; DECL_ARTIFICIAL (decl) = 1; 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)); DECL_VIRTUAL_P (decl) = 1; DECL_CONTEXT (decl) = type; binfo = TYPE_BINFO (type); SET_BINFO_NEW_VTABLE_MARKED (binfo); return decl;}extern tree signed_size_zero_node;/* 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 order in which vtables are built (by calling this function) for an object must remain the same, otherwise a binary incompatibility can result. */static voidprepare_fresh_vtable (binfo, for_type) tree binfo, for_type;{ tree basetype; tree orig_decl = BINFO_VTABLE (binfo); tree name; tree new_decl; tree offset; tree path = binfo; char *buf, *buf2; char joiner = '_'; int i;#ifdef JOINER joiner = JOINER;#endif basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (binfo)); buf2 = TYPE_ASSEMBLER_NAME_STRING (basetype); i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1; /* We know that the vtable that we are going to create doesn't exist yet in the global namespace, and when we finish, it will be pushed into the global namespace. In complex MI hierarchies, we have to loop while the name we are thinking of adding is globally defined, adding more name components to the vtable name as we loop, until the name is unique. This is because in complex MI cases, we might have the same base more than once. This means that the order in which this function is called for vtables must remain the same, otherwise binary compatibility can be compromised. */ while (1) { char *buf1 = (char *) alloca (TYPE_ASSEMBLER_NAME_LENGTH (for_type) + 1 + i); char *new_buf2; sprintf (buf1, "%s%c%s", TYPE_ASSEMBLER_NAME_STRING (for_type), joiner, buf2); 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 more to the name until it is unique. */ if (! IDENTIFIER_GLOBAL_VALUE (name)) break; /* Set values for next loop through, if the name isn't unique. */ path = BINFO_INHERITANCE_CHAIN (path);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -