|
|
1.1 ! root 1: /* Garbage collection primitives for GNU C++. ! 2: Copyright (C) 1992 Free Software Foundation, Inc. ! 3: Contributed by Michael Tiemann ([email protected]) ! 4: ! 5: This file is part of GNU CC. ! 6: ! 7: GNU CC is free software; you can redistribute it and/or modify ! 8: it under the terms of the GNU General Public License as published by ! 9: the Free Software Foundation; either version 2, or (at your option) ! 10: any later version. ! 11: ! 12: GNU CC is distributed in the hope that it will be useful, ! 13: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 15: GNU General Public License for more details. ! 16: ! 17: You should have received a copy of the GNU General Public License ! 18: along with GNU CC; see the file COPYING. If not, write to ! 19: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 20: ! 21: ! 22: #include "config.h" ! 23: #include "tree.h" ! 24: #include "cp-tree.h" ! 25: #include "flags.h" ! 26: #include "assert.h" ! 27: #define NULL 0 ! 28: ! 29: extern tree build_t_desc_overload (); ! 30: ! 31: /* This is the function decl for the (pseudo-builtin) __gc_protect ! 32: function. Args are (class *value, int index); Returns value. */ ! 33: tree gc_protect_fndecl; ! 34: ! 35: /* This is the function decl for the (pseudo-builtin) __gc_unprotect ! 36: function. Args are (int index); void return. */ ! 37: tree gc_unprotect_fndecl; ! 38: ! 39: /* This is the function decl for the (pseudo-builtin) __gc_push ! 40: function. Args are (int length); void return. */ ! 41: tree gc_push_fndecl; ! 42: ! 43: /* This is the function decl for the (pseudo-builtin) __gc_pop ! 44: function. Args are void; void return. */ ! 45: tree gc_pop_fndecl; ! 46: ! 47: /* Special integers that are used to represent bits in gc-safe objects. */ ! 48: tree gc_nonobject; ! 49: tree gc_visible; ! 50: tree gc_white; ! 51: tree gc_offwhite; ! 52: tree gc_grey; ! 53: tree gc_black; ! 54: ! 55: /* Predicate that returns non-zero if TYPE needs some kind of ! 56: entry for the GC. Returns zero otherwise. */ ! 57: int ! 58: type_needs_gc_entry (type) ! 59: tree type; ! 60: { ! 61: tree ttype = type; ! 62: ! 63: if (! flag_gc || type == error_mark_node) ! 64: return 0; ! 65: ! 66: /* Aggregate types need gc entries if any of their members ! 67: need gc entries. */ ! 68: if (IS_AGGR_TYPE (type)) ! 69: { ! 70: tree binfos; ! 71: tree fields = TYPE_FIELDS (type); ! 72: int i; ! 73: ! 74: /* We don't care about certain pointers. Pointers ! 75: to virtual baseclasses are always up front. We also ! 76: cull out virtual function table pointers because it's ! 77: easy, and it simplifies the logic.*/ ! 78: while (fields ! 79: && (DECL_NAME (fields) == NULL_TREE ! 80: || VFIELD_NAME_P (DECL_NAME (fields)) ! 81: || VBASE_NAME_P (DECL_NAME (fields)) ! 82: || !strcmp (IDENTIFIER_POINTER (DECL_NAME (fields)), "__bits"))) ! 83: fields = TREE_CHAIN (fields); ! 84: ! 85: while (fields) ! 86: { ! 87: if (type_needs_gc_entry (TREE_TYPE (fields))) ! 88: return 1; ! 89: fields = TREE_CHAIN (fields); ! 90: } ! 91: ! 92: binfos = TYPE_BINFO_BASETYPES (type); ! 93: if (binfos) ! 94: for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--) ! 95: if (type_needs_gc_entry (BINFO_TYPE (TREE_VEC_ELT (binfos, i)))) ! 96: return 1; ! 97: ! 98: return 0; ! 99: } ! 100: ! 101: while (TREE_CODE (ttype) == ARRAY_TYPE ! 102: && TREE_CODE (TREE_TYPE (ttype)) == ARRAY_TYPE) ! 103: ttype = TREE_TYPE (ttype); ! 104: if ((TREE_CODE (ttype) == POINTER_TYPE ! 105: || TREE_CODE (ttype) == ARRAY_TYPE ! 106: || TREE_CODE (ttype) == REFERENCE_TYPE) ! 107: && IS_AGGR_TYPE (TREE_TYPE (ttype)) ! 108: && CLASSTYPE_DOSSIER (TREE_TYPE (ttype))) ! 109: return 1; ! 110: ! 111: return 0; ! 112: } ! 113: ! 114: /* Predicate that returns non-zero iff FROM is safe from the GC. ! 115: ! 116: If TO is nonzero, it means we know that FROM is being stored ! 117: in TO, which make make it safe. */ ! 118: int ! 119: value_safe_from_gc (to, from) ! 120: tree to, from; ! 121: { ! 122: /* First, return non-zero for easy cases: parameters, ! 123: static variables. */ ! 124: if (TREE_CODE (from) == PARM_DECL ! 125: || (TREE_CODE (from) == VAR_DECL ! 126: && TREE_STATIC (from))) ! 127: return 1; ! 128: ! 129: /* If something has its address taken, it cannot be ! 130: in the heap, so it doesn't need to be protected. */ ! 131: if (TREE_CODE (from) == ADDR_EXPR || TREE_REFERENCE_EXPR (from)) ! 132: return 1; ! 133: ! 134: /* If we are storing into a static variable, then what ! 135: we store will be safe from the gc. */ ! 136: if (to && TREE_CODE (to) == VAR_DECL ! 137: && TREE_STATIC (to)) ! 138: return 1; ! 139: ! 140: /* Now recurse on structure of FROM. */ ! 141: switch (TREE_CODE (from)) ! 142: { ! 143: case COMPONENT_REF: ! 144: /* These guys are special, and safe. */ ! 145: if (TREE_CODE (TREE_OPERAND (from, 1)) == FIELD_DECL ! 146: && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (from, 1))) ! 147: || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (from, 1))))) ! 148: return 1; ! 149: /* fall through... */ ! 150: case NOP_EXPR: ! 151: case CONVERT_EXPR: ! 152: case NON_LVALUE_EXPR: ! 153: case WITH_CLEANUP_EXPR: ! 154: case SAVE_EXPR: ! 155: case PREDECREMENT_EXPR: ! 156: case PREINCREMENT_EXPR: ! 157: case POSTDECREMENT_EXPR: ! 158: case POSTINCREMENT_EXPR: ! 159: if (value_safe_from_gc (to, TREE_OPERAND (from, 0))) ! 160: return 1; ! 161: break; ! 162: ! 163: case VAR_DECL: ! 164: case PARM_DECL: ! 165: /* We can safely pass these things as parameters to functions. */ ! 166: if (to == 0) ! 167: return 1; ! 168: ! 169: case ARRAY_REF: ! 170: case INDIRECT_REF: ! 171: case RESULT_DECL: ! 172: case OFFSET_REF: ! 173: case CALL_EXPR: ! 174: case METHOD_CALL_EXPR: ! 175: break; ! 176: ! 177: case COMPOUND_EXPR: ! 178: case TARGET_EXPR: ! 179: if (value_safe_from_gc (to, TREE_OPERAND (from, 1))) ! 180: return 1; ! 181: break; ! 182: ! 183: case COND_EXPR: ! 184: if (value_safe_from_gc (to, TREE_OPERAND (from, 1)) ! 185: && value_safe_from_gc (to, TREE_OPERAND (from, 2))) ! 186: return 1; ! 187: break; ! 188: ! 189: case PLUS_EXPR: ! 190: case MINUS_EXPR: ! 191: if ((type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 0))) ! 192: || value_safe_from_gc (to, TREE_OPERAND (from, 0))) ! 193: && (type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 1))) == 0 ! 194: || value_safe_from_gc (to, TREE_OPERAND (from, 1)))) ! 195: return 1; ! 196: break; ! 197: ! 198: case RTL_EXPR: ! 199: /* Every time we build an RTL_EXPR in the front-end, we must ! 200: ensure that everything in it is safe from the garbage collector. ! 201: ??? This has only been done for `build_new'. */ ! 202: return 1; ! 203: ! 204: default: ! 205: abort (); ! 206: } ! 207: ! 208: if (to == 0) ! 209: return 0; ! 210: ! 211: /* FROM wasn't safe. But other properties of TO might make it safe. */ ! 212: switch (TREE_CODE (to)) ! 213: { ! 214: case VAR_DECL: ! 215: case PARM_DECL: ! 216: /* We already culled out static VAR_DECLs above. */ ! 217: return 0; ! 218: ! 219: case COMPONENT_REF: ! 220: /* These guys are special, and safe. */ ! 221: if (TREE_CODE (TREE_OPERAND (to, 1)) == FIELD_DECL ! 222: && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (to, 1))) ! 223: || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (to, 1))))) ! 224: return 1; ! 225: /* fall through... */ ! 226: ! 227: case NOP_EXPR: ! 228: case NON_LVALUE_EXPR: ! 229: case WITH_CLEANUP_EXPR: ! 230: case SAVE_EXPR: ! 231: case PREDECREMENT_EXPR: ! 232: case PREINCREMENT_EXPR: ! 233: case POSTDECREMENT_EXPR: ! 234: case POSTINCREMENT_EXPR: ! 235: return value_safe_from_gc (TREE_OPERAND (to, 0), from); ! 236: ! 237: case COMPOUND_EXPR: ! 238: case TARGET_EXPR: ! 239: return value_safe_from_gc (TREE_OPERAND (to, 1), from); ! 240: ! 241: case COND_EXPR: ! 242: return (value_safe_from_gc (TREE_OPERAND (to, 1), from) ! 243: && value_safe_from_gc (TREE_OPERAND (to, 2), from)); ! 244: ! 245: case INDIRECT_REF: ! 246: case ARRAY_REF: ! 247: /* This used to be 0, but our current restricted model ! 248: allows this to be 1. We'll never get arrays this way. */ ! 249: return 1; ! 250: ! 251: default: ! 252: abort (); ! 253: } ! 254: ! 255: /* Catch-all case is that TO/FROM is not safe. */ ! 256: return 0; ! 257: } ! 258: ! 259: /* Function to build a static GC entry for DECL. TYPE is DECL's type. ! 260: ! 261: For objects of type `class *', this is just an entry in the ! 262: static vector __PTR_LIST__. ! 263: ! 264: For objects of type `class[]', this requires building an entry ! 265: in the static vector __ARR_LIST__. ! 266: ! 267: For aggregates, this records all fields of type `class *' ! 268: and `class[]' in the respective lists above. */ ! 269: void ! 270: build_static_gc_entry (decl, type) ! 271: tree decl; ! 272: tree type; ! 273: { ! 274: /* Now, figure out what sort of entry to build. */ ! 275: if (TREE_CODE (type) == POINTER_TYPE ! 276: || TREE_CODE (type) == REFERENCE_TYPE) ! 277: assemble_gc_entry (IDENTIFIER_POINTER (DECL_NAME (decl))); ! 278: else if (TREE_CODE (type) == RECORD_TYPE) ! 279: { ! 280: tree ref = get_temp_name (build_reference_type (type), 1); ! 281: DECL_INITIAL (ref) = build1 (ADDR_EXPR, TREE_TYPE (ref), decl); ! 282: TREE_CONSTANT (DECL_INITIAL (ref)) = 1; ! 283: finish_decl (ref, DECL_INITIAL (ref), 0, 0); ! 284: } ! 285: else ! 286: { ! 287: /* Not yet implemented. ! 288: ! 289: Cons up a static variable that holds address and length info ! 290: and add that to ___ARR_LIST__. */ ! 291: abort (); ! 292: } ! 293: } ! 294: ! 295: /* Protect FROM from the GC, assuming FROM is going to be ! 296: stored into TO. We handle three cases for TO here: ! 297: ! 298: case 1: TO is a stack variable. ! 299: case 2: TO is zero (which means it is a parameter). ! 300: case 3: TO is a return value. */ ! 301: ! 302: tree ! 303: protect_value_from_gc (to, from) ! 304: tree to, from; ! 305: { ! 306: if (to == 0) ! 307: { ! 308: tree cleanup; ! 309: ! 310: to = get_temp_regvar (TREE_TYPE (from), from); ! 311: ! 312: /* Convert from integer to list form since we'll use it twice. */ ! 313: DECL_GC_OFFSET (to) = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to)); ! 314: cleanup = build_function_call (gc_unprotect_fndecl, ! 315: DECL_GC_OFFSET (to)); ! 316: ! 317: if (! expand_decl_cleanup (to, cleanup)) ! 318: { ! 319: compiler_error ("cannot unprotect parameter in this scope"); ! 320: return error_mark_node; ! 321: } ! 322: } ! 323: ! 324: /* Should never need to protect a value that's headed for static storage. */ ! 325: if (TREE_STATIC (to)) ! 326: abort (); ! 327: ! 328: switch (TREE_CODE (to)) ! 329: { ! 330: case COMPONENT_REF: ! 331: case INDIRECT_REF: ! 332: return protect_value_from_gc (TREE_OPERAND (to, 0), from); ! 333: ! 334: case VAR_DECL: ! 335: case PARM_DECL: ! 336: { ! 337: tree rval; ! 338: if (DECL_GC_OFFSET (to) == NULL_TREE) ! 339: { ! 340: /* Because of a cast or a conversion, we might stick ! 341: a value into a variable that would not normally ! 342: have a GC entry. */ ! 343: DECL_GC_OFFSET (to) = size_int (++current_function_obstack_index); ! 344: } ! 345: ! 346: if (TREE_CODE (DECL_GC_OFFSET (to)) != TREE_LIST) ! 347: { ! 348: DECL_GC_OFFSET (to) ! 349: = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to)); ! 350: } ! 351: ! 352: current_function_obstack_usage = 1; ! 353: rval = build_function_call (gc_protect_fndecl, ! 354: tree_cons (NULL_TREE, from, ! 355: DECL_GC_OFFSET (to))); ! 356: TREE_TYPE (rval) = TREE_TYPE (from); ! 357: return rval; ! 358: } ! 359: } ! 360: ! 361: /* If we fall through the switch, assume we lost. */ ! 362: abort (); ! 363: /* NOTREACHED */ ! 364: return NULL_TREE; ! 365: } ! 366: ! 367: /* Given the expression EXP of type `class *', return the head ! 368: of the object pointed to by EXP. */ ! 369: tree ! 370: build_headof (exp) ! 371: tree exp; ! 372: { ! 373: tree type = TREE_TYPE (exp); ! 374: tree vptr, offset; ! 375: ! 376: if (TREE_CODE (type) != POINTER_TYPE) ! 377: { ! 378: error ("`headof' applied to non-pointer type"); ! 379: return error_mark_node; ! 380: } ! 381: ! 382: vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp); ! 383: offset = build_component_ref (build_array_ref (vptr, integer_one_node), ! 384: get_identifier (VTABLE_DELTA_NAME), ! 385: NULL_TREE, 0); ! 386: return build (PLUS_EXPR, class_star_type_node, exp, ! 387: convert (integer_type_node, offset)); ! 388: } ! 389: ! 390: /* Given the expression EXP of type `class *', return the ! 391: type descriptor for the object pointed to by EXP. */ ! 392: tree ! 393: build_classof (exp) ! 394: tree exp; ! 395: { ! 396: tree type = TREE_TYPE (exp); ! 397: tree vptr; ! 398: tree t_desc_entry; ! 399: ! 400: if (TREE_CODE (type) != POINTER_TYPE) ! 401: { ! 402: error ("`classof' applied to non-pointer type"); ! 403: return error_mark_node; ! 404: } ! 405: ! 406: vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp); ! 407: t_desc_entry = build_component_ref (build_array_ref (vptr, integer_one_node), ! 408: get_identifier (VTABLE_PFN_NAME), ! 409: NULL_TREE, 0); ! 410: TREE_TYPE (t_desc_entry) = TYPE_POINTER_TO (__t_desc_type_node); ! 411: return t_desc_entry; ! 412: } ! 413: ! 414: /* Build and initialize various sorts of descriptors. Every descriptor ! 415: node has a name associated with it (the name created by mangling). ! 416: For this reason, we use the identifier as our access to the __*_desc ! 417: nodes, instead of sticking them directly in the types. Otherwise we ! 418: would burden all built-in types (and pointer types) with slots that ! 419: we don't necessarily want to use. ! 420: ! 421: For each descriptor we build, we build a variable that contains ! 422: the descriptor's information. When we need this info at runtime, ! 423: all we need is access to these variables. ! 424: ! 425: Note: these constructors always return the address of the descriptor ! 426: info, since that is simplest for their mutual interaction. */ ! 427: ! 428: static tree ! 429: build_generic_desc (decl, elems) ! 430: tree decl; ! 431: tree elems; ! 432: { ! 433: tree init = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE, elems); ! 434: TREE_CONSTANT (init) = 1; ! 435: TREE_STATIC (init) = 1; ! 436: TREE_READONLY (init) = 1; ! 437: ! 438: DECL_INITIAL (decl) = init; ! 439: TREE_STATIC (decl) = 1; ! 440: layout_decl (decl, 0); ! 441: finish_decl (decl, init, 0, 0); ! 442: ! 443: return IDENTIFIER_AS_DESC (DECL_NAME (decl)); ! 444: } ! 445: ! 446: /* Build an initializer for a __t_desc node. So that we can take advantage ! 447: of recursion, we accept NULL for TYPE. ! 448: DEFINITION is greater than zero iff we must define the type descriptor ! 449: (as opposed to merely referencing it). 1 means treat according to ! 450: #pragma interface/#pragma implementation rules. 2 means define as ! 451: global and public, no matter what. */ ! 452: tree ! 453: build_t_desc (type, definition) ! 454: tree type; ! 455: int definition; ! 456: { ! 457: tree tdecl; ! 458: tree tname, name_string; ! 459: tree elems, fields; ! 460: tree parents, vbases, offsets, ivars, methods, target_type; ! 461: int method_count = 0, field_count = 0; ! 462: ! 463: if (type == NULL_TREE) ! 464: return NULL_TREE; ! 465: ! 466: tname = build_t_desc_overload (type); ! 467: if (IDENTIFIER_AS_DESC (tname) ! 468: && (!definition || TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname)))) ! 469: return IDENTIFIER_AS_DESC (tname); ! 470: ! 471: tdecl = lookup_name (tname, 0); ! 472: if (tdecl == NULL_TREE) ! 473: { ! 474: tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node); ! 475: TREE_EXTERNAL (tdecl) = 1; ! 476: TREE_PUBLIC (tdecl) = 1; ! 477: tdecl = pushdecl_top_level (tdecl); ! 478: } ! 479: /* If we previously defined it, return the defined result. */ ! 480: else if (definition && DECL_INITIAL (tdecl)) ! 481: return IDENTIFIER_AS_DESC (tname); ! 482: ! 483: if (definition) ! 484: { ! 485: tree taggr = type; ! 486: /* Let T* and T& be written only when T is written (if T is an aggr). ! 487: We do this for const, but not for volatile, since volatile ! 488: is rare and const is not. */ ! 489: if (!TYPE_VOLATILE (taggr) ! 490: && (TREE_CODE (taggr) == POINTER_TYPE ! 491: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 492: && IS_AGGR_TYPE (TREE_TYPE (taggr))) ! 493: taggr = TREE_TYPE (taggr); ! 494: ! 495: /* If we know that we don't need to write out this type's ! 496: vtable, then don't write out it's dossier. Somebody ! 497: else will take care of that. */ ! 498: if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr)) ! 499: { ! 500: if (CLASSTYPE_VTABLE_NEEDS_WRITING (taggr)) ! 501: { ! 502: TREE_PUBLIC (tdecl) = !(CLASSTYPE_INTERFACE_ONLY (taggr) ! 503: || CLASSTYPE_INTERFACE_UNKNOWN (taggr)); ! 504: TREE_STATIC (tdecl) = 1; ! 505: TREE_EXTERNAL (tdecl) = 0; ! 506: } ! 507: else ! 508: { ! 509: if (write_virtuals != 0) ! 510: TREE_PUBLIC (tdecl) = 1; ! 511: } ! 512: } ! 513: else ! 514: { ! 515: TREE_EXTERNAL (tdecl) = 0; ! 516: TREE_STATIC (tdecl) = 1; ! 517: TREE_PUBLIC (tdecl) = (definition > 1); ! 518: } ! 519: } ! 520: SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0)); ! 521: if (!definition || TREE_EXTERNAL (tdecl)) ! 522: { ! 523: /* That's it! */ ! 524: finish_decl (tdecl, 0, 0, 0); ! 525: return IDENTIFIER_AS_DESC (tname); ! 526: } ! 527: ! 528: /* Show that we are defining the t_desc for this type. */ ! 529: DECL_INITIAL (tdecl) = error_mark_node; ! 530: ! 531: parents = build_tree_list (NULL_TREE, integer_zero_node); ! 532: vbases = build_tree_list (NULL_TREE, integer_zero_node); ! 533: offsets = build_tree_list (NULL_TREE, integer_zero_node); ! 534: methods = NULL_TREE; ! 535: ivars = NULL_TREE; ! 536: ! 537: if (TYPE_LANG_SPECIFIC (type)) ! 538: { ! 539: int i = CLASSTYPE_N_BASECLASSES (type); ! 540: tree method_vec = CLASSTYPE_METHOD_VEC (type); ! 541: tree *meth, *end; ! 542: tree binfos = TYPE_BINFO_BASETYPES (type); ! 543: tree vb = CLASSTYPE_VBASECLASSES (type); ! 544: ! 545: while (--i >= 0) ! 546: parents = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (TREE_VEC_ELT (binfos, i)), 0), parents); ! 547: ! 548: while (vb) ! 549: { ! 550: vbases = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (vb), 0), vbases); ! 551: offsets = tree_cons (NULL_TREE, BINFO_OFFSET (vb), offsets); ! 552: vb = TREE_CHAIN (vb); ! 553: } ! 554: ! 555: if (method_vec) ! 556: for (meth = TREE_VEC_END (method_vec), ! 557: end = &TREE_VEC_ELT (method_vec, 0); meth-- != end; ) ! 558: if (*meth) ! 559: { ! 560: methods = tree_cons (NULL_TREE, build_m_desc (*meth), methods); ! 561: method_count++; ! 562: } ! 563: } ! 564: ! 565: if (IS_AGGR_TYPE (type)) ! 566: { ! 567: for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields)) ! 568: if (TREE_CODE (fields) == FIELD_DECL ! 569: || TREE_CODE (fields) == VAR_DECL) ! 570: { ! 571: ivars = tree_cons (NULL_TREE, build_i_desc (fields), ivars); ! 572: field_count++; ! 573: } ! 574: ivars = nreverse (ivars); ! 575: } ! 576: ! 577: parents = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), parents, 0); ! 578: vbases = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), vbases, 0); ! 579: offsets = finish_table (0, integer_type_node, offsets, 0); ! 580: methods = finish_table (0, __m_desc_type_node, methods, 0); ! 581: ivars = finish_table (0, __i_desc_type_node, ivars, 0); ! 582: if (TREE_TYPE (type)) ! 583: target_type = build_t_desc (TREE_TYPE (type), definition); ! 584: else ! 585: target_type = integer_zero_node; ! 586: ! 587: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); ! 588: ! 589: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 590: tree_cons (NULL_TREE, ! 591: TYPE_SIZE(type)? size_in_bytes(type) : integer_zero_node, ! 592: /* really should use bitfield initialization here. */ ! 593: tree_cons (NULL_TREE, integer_zero_node, ! 594: tree_cons (NULL_TREE, target_type, ! 595: tree_cons (NULL_TREE, build_int_2 (field_count, 2), ! 596: tree_cons (NULL_TREE, build_int_2 (method_count, 2), ! 597: tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, ivars, 0), ! 598: tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, methods, 0), ! 599: tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, parents, 0), ! 600: tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, vbases, 0), ! 601: build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, offsets, 0)))))))))))); ! 602: return build_generic_desc (tdecl, elems); ! 603: } ! 604: ! 605: /* Build an initializer for a __i_desc node. */ ! 606: tree ! 607: build_i_desc (decl) ! 608: tree decl; ! 609: { ! 610: tree elems, name_string; ! 611: tree taggr; ! 612: ! 613: name_string = DECL_NAME (decl); ! 614: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); ! 615: ! 616: /* Now decide whether this ivar should cause it's type to get ! 617: def'd or ref'd in this file. If the type we are looking at ! 618: has a proxy definition, we look at the proxy (i.e., a ! 619: `foo *' is equivalent to a `foo'). */ ! 620: taggr = TREE_TYPE (decl); ! 621: ! 622: if ((TREE_CODE (taggr) == POINTER_TYPE ! 623: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 624: && TYPE_VOLATILE (taggr) == 0) ! 625: taggr = TREE_TYPE (taggr); ! 626: ! 627: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 628: tree_cons (NULL_TREE, DECL_FIELD_BITPOS (decl), ! 629: build_tree_list (NULL_TREE, build_t_desc (TREE_TYPE (decl), ! 630: ! IS_AGGR_TYPE (taggr))))); ! 631: taggr = build (CONSTRUCTOR, __i_desc_type_node, NULL_TREE, elems); ! 632: TREE_CONSTANT (taggr) = 1; ! 633: TREE_STATIC (taggr) = 1; ! 634: TREE_READONLY (taggr) = 1; ! 635: return taggr; ! 636: } ! 637: ! 638: /* Build an initializer for a __m_desc node. */ ! 639: tree ! 640: build_m_desc (decl) ! 641: tree decl; ! 642: { ! 643: tree taggr, elems, name_string; ! 644: tree parm_count, req_count, vindex, vcontext; ! 645: tree parms; ! 646: int p_count, r_count; ! 647: tree parm_types = NULL_TREE; ! 648: ! 649: for (parms = TYPE_ARG_TYPES (TREE_TYPE (decl)), p_count = 0, r_count = 0; ! 650: parms != NULL_TREE; parms = TREE_CHAIN (parms), p_count++) ! 651: { ! 652: taggr = TREE_VALUE (parms); ! 653: if ((TREE_CODE (taggr) == POINTER_TYPE ! 654: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 655: && TYPE_VOLATILE (taggr) == 0) ! 656: taggr = TREE_TYPE (taggr); ! 657: ! 658: parm_types = tree_cons (NULL_TREE, build_t_desc (TREE_VALUE (parms), ! 659: ! IS_AGGR_TYPE (taggr)), ! 660: parm_types); ! 661: if (TREE_PURPOSE (parms) == NULL_TREE) ! 662: r_count++; ! 663: } ! 664: ! 665: parm_types = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), ! 666: nreverse (parm_types), 0); ! 667: parm_count = build_int_2 (p_count, 0); ! 668: req_count = build_int_2 (r_count, 0); ! 669: ! 670: if (DECL_VINDEX (decl)) ! 671: vindex = DECL_VINDEX (decl); ! 672: else ! 673: vindex = integer_zero_node; ! 674: if (DECL_CONTEXT (decl)) ! 675: vcontext = build_t_desc (DECL_CONTEXT (decl), 0); ! 676: else ! 677: vcontext = integer_zero_node; ! 678: name_string = DECL_NAME (decl); ! 679: if (name_string == NULL) ! 680: name_string = DECL_ASSEMBLER_NAME (decl); ! 681: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); ! 682: ! 683: /* Now decide whether the return type of this mvar ! 684: should cause it's type to get def'd or ref'd in this file. ! 685: If the type we are looking at has a proxy definition, ! 686: we look at the proxy (i.e., a `foo *' is equivalent to a `foo'). */ ! 687: taggr = TREE_TYPE (TREE_TYPE (decl)); ! 688: ! 689: if ((TREE_CODE (taggr) == POINTER_TYPE ! 690: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 691: && TYPE_VOLATILE (taggr) == 0) ! 692: taggr = TREE_TYPE (taggr); ! 693: ! 694: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 695: tree_cons (NULL_TREE, vindex, ! 696: tree_cons (NULL_TREE, vcontext, ! 697: tree_cons (NULL_TREE, build_t_desc (TREE_TYPE (TREE_TYPE (decl)), ! 698: ! IS_AGGR_TYPE (taggr)), ! 699: tree_cons (NULL_TREE, build_c_cast (TYPE_POINTER_TO (default_function_type), build_unary_op (ADDR_EXPR, decl, 0)), ! 700: tree_cons (NULL_TREE, parm_count, ! 701: tree_cons (NULL_TREE, req_count, ! 702: build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, parm_types, 0))))))))); ! 703: ! 704: taggr = build (CONSTRUCTOR, __m_desc_type_node, NULL_TREE, elems); ! 705: TREE_CONSTANT (taggr) = 1; ! 706: TREE_STATIC (taggr) = 1; ! 707: TREE_READONLY (taggr) = 1; ! 708: return taggr; ! 709: } ! 710: ! 711: /* Conditionally emit code to set up an unwind-protect for the ! 712: garbage collector. If this function doesn't do anything that involves ! 713: the garbage collector, then do nothing. Otherwise, call __gc_push ! 714: at the beginning and __gc_pop at the end. ! 715: ! 716: NOTE! The __gc_pop function must operate transparently, since ! 717: it comes where the logical return label lies. This means that ! 718: at runtime *it* must preserve any return value registers. */ ! 719: ! 720: void ! 721: expand_gc_prologue_and_epilogue () ! 722: { ! 723: extern tree maybe_gc_cleanup; ! 724: struct rtx_def *last_parm_insn, *mark; ! 725: extern struct rtx_def *get_last_insn (); ! 726: extern struct rtx_def *get_first_nonparm_insn (); ! 727: extern struct rtx_def *previous_insn (); ! 728: tree action; ! 729: ! 730: /* If we didn't need the obstack, don't cons any space. */ ! 731: if (current_function_obstack_index == 0 ! 732: || current_function_obstack_usage == 0) ! 733: return; ! 734: ! 735: mark = get_last_insn (); ! 736: last_parm_insn = get_first_nonparm_insn (); ! 737: if (last_parm_insn == 0) last_parm_insn = mark; ! 738: else last_parm_insn = previous_insn (last_parm_insn); ! 739: ! 740: action = build_function_call (gc_push_fndecl, ! 741: build_tree_list (NULL_TREE, size_int (++current_function_obstack_index))); ! 742: expand_expr_stmt (action); ! 743: ! 744: reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn); ! 745: ! 746: /* This will be expanded as a cleanup. */ ! 747: TREE_VALUE (maybe_gc_cleanup) ! 748: = build_function_call (gc_pop_fndecl, NULL_TREE); ! 749: } ! 750: ! 751: /* Some day we'll use this function as a call-back and clean ! 752: up all the unnecessary gc dribble that we otherwise create. */ ! 753: void ! 754: lang_expand_end_bindings (first, last) ! 755: struct rtx_def *first, *last; ! 756: { ! 757: } ! 758: ! 759: void ! 760: init_gc_processing () ! 761: { ! 762: tree parmtypes = hash_tree_chain (class_star_type_node, ! 763: hash_tree_chain (integer_type_node, NULL_TREE)); ! 764: gc_protect_fndecl = define_function ("__gc_protect", ! 765: build_function_type (class_star_type_node, parmtypes), ! 766: NOT_BUILT_IN, 0, 0); ! 767: ! 768: parmtypes = hash_tree_chain (integer_type_node, NULL_TREE); ! 769: gc_unprotect_fndecl = define_function ("__gc_unprotect", ! 770: build_function_type (void_type_node, parmtypes), ! 771: NOT_BUILT_IN, 0, 0); ! 772: ! 773: gc_push_fndecl = define_function ("__gc_push", ! 774: TREE_TYPE (gc_unprotect_fndecl), ! 775: NOT_BUILT_IN, 0, 0); ! 776: ! 777: gc_pop_fndecl = define_function ("__gc_pop", ! 778: build_function_type (void_type_node, ! 779: void_list_node), ! 780: NOT_BUILT_IN, 0, 0); ! 781: gc_nonobject = build_int_2 (0x80000000, 0); ! 782: gc_visible = build_int_2 (0x40000000, 0); ! 783: gc_white = integer_zero_node; ! 784: gc_offwhite = build_int_2 (0x10000000, 0); ! 785: gc_grey = build_int_2 (0x20000000, 0); ! 786: gc_black = build_int_2 (0x30000000, 0); ! 787: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.