|
|
1.1 ! root 1: /* Garbage collection primitives for GNU C++. ! 2: Copyright (C) 1992, 1993 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: ! 27: #undef NULL ! 28: #define NULL 0 ! 29: ! 30: extern tree define_function (); ! 31: extern tree build_t_desc_overload (); ! 32: ! 33: /* This is the function decl for the (pseudo-builtin) __gc_protect ! 34: function. Args are (class *value, int index); Returns value. */ ! 35: tree gc_protect_fndecl; ! 36: ! 37: /* This is the function decl for the (pseudo-builtin) __gc_unprotect ! 38: function. Args are (int index); void return. */ ! 39: tree gc_unprotect_fndecl; ! 40: ! 41: /* This is the function decl for the (pseudo-builtin) __gc_push ! 42: function. Args are (int length); void return. */ ! 43: tree gc_push_fndecl; ! 44: ! 45: /* This is the function decl for the (pseudo-builtin) __gc_pop ! 46: function. Args are void; void return. */ ! 47: tree gc_pop_fndecl; ! 48: ! 49: /* Special integers that are used to represent bits in gc-safe objects. */ ! 50: tree gc_nonobject; ! 51: tree gc_visible; ! 52: tree gc_white; ! 53: tree gc_offwhite; ! 54: tree gc_grey; ! 55: tree gc_black; ! 56: ! 57: /* in c-common.c */ ! 58: extern tree combine_strings PROTO((tree)); ! 59: ! 60: /* Predicate that returns non-zero if TYPE needs some kind of ! 61: entry for the GC. Returns zero otherwise. */ ! 62: int ! 63: type_needs_gc_entry (type) ! 64: tree type; ! 65: { ! 66: tree ttype = type; ! 67: ! 68: if (! flag_gc || type == error_mark_node) ! 69: return 0; ! 70: ! 71: /* Aggregate types need gc entries if any of their members ! 72: need gc entries. */ ! 73: if (IS_AGGR_TYPE (type)) ! 74: { ! 75: tree binfos; ! 76: tree fields = TYPE_FIELDS (type); ! 77: int i; ! 78: ! 79: /* We don't care about certain pointers. Pointers ! 80: to virtual baseclasses are always up front. We also ! 81: cull out virtual function table pointers because it's ! 82: easy, and it simplifies the logic.*/ ! 83: while (fields ! 84: && (DECL_NAME (fields) == NULL_TREE ! 85: || VFIELD_NAME_P (DECL_NAME (fields)) ! 86: || VBASE_NAME_P (DECL_NAME (fields)) ! 87: || !strcmp (IDENTIFIER_POINTER (DECL_NAME (fields)), "__bits"))) ! 88: fields = TREE_CHAIN (fields); ! 89: ! 90: while (fields) ! 91: { ! 92: if (type_needs_gc_entry (TREE_TYPE (fields))) ! 93: return 1; ! 94: fields = TREE_CHAIN (fields); ! 95: } ! 96: ! 97: binfos = TYPE_BINFO_BASETYPES (type); ! 98: if (binfos) ! 99: for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--) ! 100: if (type_needs_gc_entry (BINFO_TYPE (TREE_VEC_ELT (binfos, i)))) ! 101: return 1; ! 102: ! 103: return 0; ! 104: } ! 105: ! 106: while (TREE_CODE (ttype) == ARRAY_TYPE ! 107: && TREE_CODE (TREE_TYPE (ttype)) == ARRAY_TYPE) ! 108: ttype = TREE_TYPE (ttype); ! 109: if ((TREE_CODE (ttype) == POINTER_TYPE ! 110: || TREE_CODE (ttype) == ARRAY_TYPE ! 111: || TREE_CODE (ttype) == REFERENCE_TYPE) ! 112: && IS_AGGR_TYPE (TREE_TYPE (ttype)) ! 113: && CLASSTYPE_DOSSIER (TREE_TYPE (ttype))) ! 114: return 1; ! 115: ! 116: return 0; ! 117: } ! 118: ! 119: /* Predicate that returns non-zero iff FROM is safe from the GC. ! 120: ! 121: If TO is nonzero, it means we know that FROM is being stored ! 122: in TO, which make make it safe. */ ! 123: int ! 124: value_safe_from_gc (to, from) ! 125: tree to, from; ! 126: { ! 127: /* First, return non-zero for easy cases: parameters, ! 128: static variables. */ ! 129: if (TREE_CODE (from) == PARM_DECL ! 130: || (TREE_CODE (from) == VAR_DECL ! 131: && TREE_STATIC (from))) ! 132: return 1; ! 133: ! 134: /* If something has its address taken, it cannot be ! 135: in the heap, so it doesn't need to be protected. */ ! 136: if (TREE_CODE (from) == ADDR_EXPR || TREE_REFERENCE_EXPR (from)) ! 137: return 1; ! 138: ! 139: /* If we are storing into a static variable, then what ! 140: we store will be safe from the gc. */ ! 141: if (to && TREE_CODE (to) == VAR_DECL ! 142: && TREE_STATIC (to)) ! 143: return 1; ! 144: ! 145: /* Now recurse on structure of FROM. */ ! 146: switch (TREE_CODE (from)) ! 147: { ! 148: case COMPONENT_REF: ! 149: /* These guys are special, and safe. */ ! 150: if (TREE_CODE (TREE_OPERAND (from, 1)) == FIELD_DECL ! 151: && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (from, 1))) ! 152: || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (from, 1))))) ! 153: return 1; ! 154: /* fall through... */ ! 155: case NOP_EXPR: ! 156: case CONVERT_EXPR: ! 157: case NON_LVALUE_EXPR: ! 158: case WITH_CLEANUP_EXPR: ! 159: case SAVE_EXPR: ! 160: case PREDECREMENT_EXPR: ! 161: case PREINCREMENT_EXPR: ! 162: case POSTDECREMENT_EXPR: ! 163: case POSTINCREMENT_EXPR: ! 164: if (value_safe_from_gc (to, TREE_OPERAND (from, 0))) ! 165: return 1; ! 166: break; ! 167: ! 168: case VAR_DECL: ! 169: case PARM_DECL: ! 170: /* We can safely pass these things as parameters to functions. */ ! 171: if (to == 0) ! 172: return 1; ! 173: ! 174: case ARRAY_REF: ! 175: case INDIRECT_REF: ! 176: case RESULT_DECL: ! 177: case OFFSET_REF: ! 178: case CALL_EXPR: ! 179: case METHOD_CALL_EXPR: ! 180: break; ! 181: ! 182: case COMPOUND_EXPR: ! 183: case TARGET_EXPR: ! 184: if (value_safe_from_gc (to, TREE_OPERAND (from, 1))) ! 185: return 1; ! 186: break; ! 187: ! 188: case COND_EXPR: ! 189: if (value_safe_from_gc (to, TREE_OPERAND (from, 1)) ! 190: && value_safe_from_gc (to, TREE_OPERAND (from, 2))) ! 191: return 1; ! 192: break; ! 193: ! 194: case PLUS_EXPR: ! 195: case MINUS_EXPR: ! 196: if ((type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 0))) ! 197: || value_safe_from_gc (to, TREE_OPERAND (from, 0))) ! 198: && (type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 1))) == 0 ! 199: || value_safe_from_gc (to, TREE_OPERAND (from, 1)))) ! 200: return 1; ! 201: break; ! 202: ! 203: case RTL_EXPR: ! 204: /* Every time we build an RTL_EXPR in the front-end, we must ! 205: ensure that everything in it is safe from the garbage collector. ! 206: ??? This has only been done for `build_new'. */ ! 207: return 1; ! 208: ! 209: default: ! 210: my_friendly_abort (41); ! 211: } ! 212: ! 213: if (to == 0) ! 214: return 0; ! 215: ! 216: /* FROM wasn't safe. But other properties of TO might make it safe. */ ! 217: switch (TREE_CODE (to)) ! 218: { ! 219: case VAR_DECL: ! 220: case PARM_DECL: ! 221: /* We already culled out static VAR_DECLs above. */ ! 222: return 0; ! 223: ! 224: case COMPONENT_REF: ! 225: /* These guys are special, and safe. */ ! 226: if (TREE_CODE (TREE_OPERAND (to, 1)) == FIELD_DECL ! 227: && (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (to, 1))) ! 228: || VBASE_NAME_P (DECL_NAME (TREE_OPERAND (to, 1))))) ! 229: return 1; ! 230: /* fall through... */ ! 231: ! 232: case NOP_EXPR: ! 233: case NON_LVALUE_EXPR: ! 234: case WITH_CLEANUP_EXPR: ! 235: case SAVE_EXPR: ! 236: case PREDECREMENT_EXPR: ! 237: case PREINCREMENT_EXPR: ! 238: case POSTDECREMENT_EXPR: ! 239: case POSTINCREMENT_EXPR: ! 240: return value_safe_from_gc (TREE_OPERAND (to, 0), from); ! 241: ! 242: case COMPOUND_EXPR: ! 243: case TARGET_EXPR: ! 244: return value_safe_from_gc (TREE_OPERAND (to, 1), from); ! 245: ! 246: case COND_EXPR: ! 247: return (value_safe_from_gc (TREE_OPERAND (to, 1), from) ! 248: && value_safe_from_gc (TREE_OPERAND (to, 2), from)); ! 249: ! 250: case INDIRECT_REF: ! 251: case ARRAY_REF: ! 252: /* This used to be 0, but our current restricted model ! 253: allows this to be 1. We'll never get arrays this way. */ ! 254: return 1; ! 255: ! 256: default: ! 257: my_friendly_abort (42); ! 258: } ! 259: ! 260: /* Catch-all case is that TO/FROM is not safe. */ ! 261: return 0; ! 262: } ! 263: ! 264: /* Function to build a static GC entry for DECL. TYPE is DECL's type. ! 265: ! 266: For objects of type `class *', this is just an entry in the ! 267: static vector __PTR_LIST__. ! 268: ! 269: For objects of type `class[]', this requires building an entry ! 270: in the static vector __ARR_LIST__. ! 271: ! 272: For aggregates, this records all fields of type `class *' ! 273: and `class[]' in the respective lists above. */ ! 274: void ! 275: build_static_gc_entry (decl, type) ! 276: tree decl; ! 277: tree type; ! 278: { ! 279: /* Now, figure out what sort of entry to build. */ ! 280: if (TREE_CODE (type) == POINTER_TYPE ! 281: || TREE_CODE (type) == REFERENCE_TYPE) ! 282: assemble_gc_entry (IDENTIFIER_POINTER (DECL_NAME (decl))); ! 283: else if (TREE_CODE (type) == RECORD_TYPE) ! 284: { ! 285: tree ref = get_temp_name (build_reference_type (type), 1); ! 286: DECL_INITIAL (ref) = build1 (ADDR_EXPR, TREE_TYPE (ref), decl); ! 287: TREE_CONSTANT (DECL_INITIAL (ref)) = 1; ! 288: finish_decl (ref, DECL_INITIAL (ref), 0, 0); ! 289: } ! 290: else ! 291: { ! 292: /* Not yet implemented. ! 293: ! 294: Cons up a static variable that holds address and length info ! 295: and add that to ___ARR_LIST__. */ ! 296: my_friendly_abort (43); ! 297: } ! 298: } ! 299: ! 300: /* Protect FROM from the GC, assuming FROM is going to be ! 301: stored into TO. We handle three cases for TO here: ! 302: ! 303: case 1: TO is a stack variable. ! 304: case 2: TO is zero (which means it is a parameter). ! 305: case 3: TO is a return value. */ ! 306: ! 307: tree ! 308: protect_value_from_gc (to, from) ! 309: tree to, from; ! 310: { ! 311: if (to == 0) ! 312: { ! 313: tree cleanup; ! 314: ! 315: to = get_temp_regvar (TREE_TYPE (from), from); ! 316: ! 317: /* Convert from integer to list form since we'll use it twice. */ ! 318: DECL_GC_OFFSET (to) = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to)); ! 319: cleanup = build_function_call (gc_unprotect_fndecl, ! 320: DECL_GC_OFFSET (to)); ! 321: ! 322: if (! expand_decl_cleanup (to, cleanup)) ! 323: { ! 324: compiler_error ("cannot unprotect parameter in this scope"); ! 325: return error_mark_node; ! 326: } ! 327: } ! 328: ! 329: /* Should never need to protect a value that's headed for static storage. */ ! 330: if (TREE_STATIC (to)) ! 331: my_friendly_abort (44); ! 332: ! 333: switch (TREE_CODE (to)) ! 334: { ! 335: case COMPONENT_REF: ! 336: case INDIRECT_REF: ! 337: return protect_value_from_gc (TREE_OPERAND (to, 0), from); ! 338: ! 339: case VAR_DECL: ! 340: case PARM_DECL: ! 341: { ! 342: tree rval; ! 343: if (DECL_GC_OFFSET (to) == NULL_TREE) ! 344: { ! 345: /* Because of a cast or a conversion, we might stick ! 346: a value into a variable that would not normally ! 347: have a GC entry. */ ! 348: DECL_GC_OFFSET (to) = size_int (++current_function_obstack_index); ! 349: } ! 350: ! 351: if (TREE_CODE (DECL_GC_OFFSET (to)) != TREE_LIST) ! 352: { ! 353: DECL_GC_OFFSET (to) ! 354: = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to)); ! 355: } ! 356: ! 357: current_function_obstack_usage = 1; ! 358: rval = build_function_call (gc_protect_fndecl, ! 359: tree_cons (NULL_TREE, from, ! 360: DECL_GC_OFFSET (to))); ! 361: TREE_TYPE (rval) = TREE_TYPE (from); ! 362: return rval; ! 363: } ! 364: } ! 365: ! 366: /* If we fall through the switch, assume we lost. */ ! 367: my_friendly_abort (45); ! 368: /* NOTREACHED */ ! 369: return NULL_TREE; ! 370: } ! 371: ! 372: /* Given the expression EXP of type `class *', return the head ! 373: of the object pointed to by EXP. */ ! 374: tree ! 375: build_headof (exp) ! 376: tree exp; ! 377: { ! 378: tree type = TREE_TYPE (exp); ! 379: tree vptr, offset; ! 380: ! 381: if (TREE_CODE (type) != POINTER_TYPE) ! 382: { ! 383: error ("`headof' applied to non-pointer type"); ! 384: return error_mark_node; ! 385: } ! 386: ! 387: vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp); ! 388: offset = build_component_ref (build_array_ref (vptr, integer_one_node), ! 389: get_identifier (VTABLE_DELTA_NAME), ! 390: NULL_TREE, 0); ! 391: return build (PLUS_EXPR, class_star_type_node, exp, ! 392: convert (integer_type_node, offset)); ! 393: } ! 394: ! 395: /* Given the expression EXP of type `class *', return the ! 396: type descriptor for the object pointed to by EXP. */ ! 397: tree ! 398: build_classof (exp) ! 399: tree exp; ! 400: { ! 401: tree type = TREE_TYPE (exp); ! 402: tree vptr; ! 403: tree t_desc_entry; ! 404: ! 405: if (TREE_CODE (type) != POINTER_TYPE) ! 406: { ! 407: error ("`classof' applied to non-pointer type"); ! 408: return error_mark_node; ! 409: } ! 410: ! 411: vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp); ! 412: t_desc_entry = build_component_ref (build_array_ref (vptr, integer_one_node), ! 413: get_identifier (VTABLE_PFN_NAME), ! 414: NULL_TREE, 0); ! 415: TREE_TYPE (t_desc_entry) = TYPE_POINTER_TO (__t_desc_type_node); ! 416: return t_desc_entry; ! 417: } ! 418: ! 419: /* Return the Type_info node associated with the expression EXP. If EXP is ! 420: a reference to a polymorphic class, return the dynamic type; otherwise ! 421: return the static type of the expression. */ ! 422: tree ! 423: build_typeid (exp) ! 424: tree exp; ! 425: { ! 426: tree type; ! 427: ! 428: if (exp == error_mark_node) ! 429: return error_mark_node; ! 430: ! 431: type = TREE_TYPE (exp); ! 432: ! 433: /* if b is an instance of B, typeid(b) == typeid(B). Do this before ! 434: reference trickiness. */ ! 435: if (TREE_CODE (exp) == VAR_DECL && TREE_CODE (type) == RECORD_TYPE) ! 436: return get_typeid (type); ! 437: ! 438: /* Apply trivial conversion T -> T& for dereferenced ptrs. */ ! 439: if (TREE_CODE (type) == RECORD_TYPE) ! 440: type = build_reference_type (type); ! 441: ! 442: /* If exp is a reference to polymorphic type, get the real Type_info. */ ! 443: if (TREE_CODE (type) == REFERENCE_TYPE && TYPE_VIRTUAL_P (TREE_TYPE (type))) ! 444: { ! 445: /* build reference to Type_info from vtable. */ ! 446: ! 447: sorry ("finding Type_info for an object"); ! 448: return error_mark_node; ! 449: } ! 450: ! 451: /* otherwise return the Type_info for the static type of the expr. */ ! 452: return get_typeid (type); ! 453: } ! 454: ! 455: /* Return the Type_info object for TYPE, creating it if necessary. */ ! 456: tree ! 457: get_typeid (type) ! 458: tree type; ! 459: { ! 460: if (type == error_mark_node) ! 461: return error_mark_node; ! 462: ! 463: /* Is it useful (and/or correct) to have different typeids for `T &' ! 464: and `T'? */ ! 465: if (TREE_CODE (type) == REFERENCE_TYPE) ! 466: type = TREE_TYPE (type); ! 467: ! 468: /* build reference to static Type_info */ ! 469: #if 1 ! 470: sorry ("finding Type_info for a type"); ! 471: return error_mark_node; ! 472: #else ! 473: register tree t = TYPE_TINFO (type); ! 474: ! 475: if (t) ! 476: return t; ! 477: ! 478: /* ... */ ! 479: ! 480: #endif ! 481: } ! 482: ! 483: /* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working ! 484: paper. */ ! 485: tree ! 486: build_dynamic_cast (type, expr) ! 487: tree type, expr; ! 488: { ! 489: enum tree_code tc = TREE_CODE (type); ! 490: tree exprtype = TREE_TYPE (expr); ! 491: enum tree_code ec = TREE_CODE (exprtype); ! 492: tree retval; ! 493: ! 494: if (type == error_mark_node || expr == error_mark_node) ! 495: return error_mark_node; ! 496: ! 497: switch (tc) ! 498: { ! 499: case POINTER_TYPE: ! 500: if (TREE_TYPE (type) == void_type_node) ! 501: break; ! 502: /* else fall through */ ! 503: case REFERENCE_TYPE: ! 504: if (TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE ! 505: && TYPE_SIZE (TREE_TYPE (type)) != NULL_TREE) ! 506: break; ! 507: /* else fall through */ ! 508: default: ! 509: cp_error ("`%#T' is not a valid type argument for dynamic_cast", type); ! 510: error ("(must be either pointer or reference to defined class or void *)"); ! 511: return error_mark_node; ! 512: } ! 513: ! 514: /* Apply trivial conversion T -> T& for dereferenced ptrs. */ ! 515: if (ec == RECORD_TYPE) ! 516: { ! 517: exprtype = build_reference_type (exprtype); ! 518: ec = REFERENCE_TYPE; ! 519: } ! 520: ! 521: /* the TREE_CODE of exprtype must match that of type. */ ! 522: if (ec != tc) ! 523: { ! 524: cp_error ("`%E' (of type `%#T') fails to be of %s type", expr, exprtype, ! 525: tc == POINTER_TYPE ? "pointer" : "reference"); ! 526: return error_mark_node; ! 527: } ! 528: ! 529: /* If *type is an unambiguous accessible base class of *exprtype, ! 530: convert statically. */ ! 531: { ! 532: int distance; ! 533: tree path; ! 534: ! 535: distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1, ! 536: &path); ! 537: if (distance >= 0) ! 538: return build_vbase_path (PLUS_EXPR, type, expr, path, 0); ! 539: } ! 540: ! 541: /* Otherwise *exprtype must be a polymorphic class (have a vtbl). */ ! 542: if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype))) ! 543: { ! 544: /* if TYPE is `void *', return pointer to complete object. */ ! 545: if (tc == POINTER_TYPE && TREE_TYPE (type) == void_type_node) ! 546: { ! 547: /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b. */ ! 548: if (TREE_CODE (expr) == ADDR_EXPR ! 549: && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL ! 550: && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE) ! 551: return build1 (NOP_EXPR, type, expr); ! 552: ! 553: sorry ("finding pointer to complete object"); ! 554: return build1 (NOP_EXPR, type, expr); ! 555: } ! 556: else ! 557: { ! 558: tree retval; ! 559: ! 560: /* If we got here, we can't convert statically. Therefore, ! 561: dynamic_cast<D&>(b) (b an object) cannot succeed. */ ! 562: if (ec == REFERENCE_TYPE) ! 563: { ! 564: if (TREE_CODE (expr) == VAR_DECL ! 565: && TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE) ! 566: { ! 567: cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed", ! 568: expr, type); ! 569: /* cplus_expand_throw (Bad_cast_node); */ ! 570: sorry ("throwing Bad_cast"); ! 571: return error_mark_node; ! 572: } ! 573: } ! 574: /* Ditto for dynamic_cast<D*>(&b). */ ! 575: else if (TREE_CODE (expr) == ADDR_EXPR) ! 576: { ! 577: tree op = TREE_OPERAND (expr, 0); ! 578: if (TREE_CODE (op) == VAR_DECL ! 579: && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE) ! 580: { ! 581: cp_warning ("dynamic_cast of `%E' to `%#T' can never succeed", ! 582: expr, type); ! 583: retval = build_int_2 (0, 0); ! 584: TREE_TYPE (retval) = type; ! 585: return retval; ! 586: } ! 587: } ! 588: /* Build run-time conversion. */ ! 589: sorry ("run-time type conversion"); ! 590: retval = build_int_2 (0, 0); ! 591: TREE_TYPE (retval) = type; ! 592: return retval; ! 593: } ! 594: } ! 595: ! 596: cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'", ! 597: expr, exprtype, type); ! 598: return error_mark_node; ! 599: } ! 600: ! 601: /* Build and initialize various sorts of descriptors. Every descriptor ! 602: node has a name associated with it (the name created by mangling). ! 603: For this reason, we use the identifier as our access to the __*_desc ! 604: nodes, instead of sticking them directly in the types. Otherwise we ! 605: would burden all built-in types (and pointer types) with slots that ! 606: we don't necessarily want to use. ! 607: ! 608: For each descriptor we build, we build a variable that contains ! 609: the descriptor's information. When we need this info at runtime, ! 610: all we need is access to these variables. ! 611: ! 612: Note: these constructors always return the address of the descriptor ! 613: info, since that is simplest for their mutual interaction. */ ! 614: ! 615: static tree ! 616: build_generic_desc (decl, elems) ! 617: tree decl; ! 618: tree elems; ! 619: { ! 620: tree init = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE, elems); ! 621: TREE_CONSTANT (init) = 1; ! 622: TREE_STATIC (init) = 1; ! 623: TREE_READONLY (init) = 1; ! 624: ! 625: DECL_INITIAL (decl) = init; ! 626: TREE_STATIC (decl) = 1; ! 627: layout_decl (decl, 0); ! 628: finish_decl (decl, init, 0, 0); ! 629: ! 630: return IDENTIFIER_AS_DESC (DECL_NAME (decl)); ! 631: } ! 632: ! 633: /* Build an initializer for a __t_desc node. So that we can take advantage ! 634: of recursion, we accept NULL for TYPE. ! 635: DEFINITION is greater than zero iff we must define the type descriptor ! 636: (as opposed to merely referencing it). 1 means treat according to ! 637: #pragma interface/#pragma implementation rules. 2 means define as ! 638: global and public, no matter what. */ ! 639: tree ! 640: build_t_desc (type, definition) ! 641: tree type; ! 642: int definition; ! 643: { ! 644: tree tdecl; ! 645: tree tname, name_string; ! 646: tree elems, fields; ! 647: tree parents, vbases, offsets, ivars, methods, target_type; ! 648: int method_count = 0, field_count = 0; ! 649: ! 650: if (type == NULL_TREE) ! 651: return NULL_TREE; ! 652: ! 653: tname = build_t_desc_overload (type); ! 654: if (IDENTIFIER_AS_DESC (tname) ! 655: && (!definition || TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname)))) ! 656: return IDENTIFIER_AS_DESC (tname); ! 657: ! 658: tdecl = lookup_name (tname, 0); ! 659: if (tdecl == NULL_TREE) ! 660: { ! 661: tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node); ! 662: DECL_EXTERNAL (tdecl) = 1; ! 663: TREE_PUBLIC (tdecl) = 1; ! 664: tdecl = pushdecl_top_level (tdecl); ! 665: } ! 666: /* If we previously defined it, return the defined result. */ ! 667: else if (definition && DECL_INITIAL (tdecl)) ! 668: return IDENTIFIER_AS_DESC (tname); ! 669: ! 670: if (definition) ! 671: { ! 672: tree taggr = type; ! 673: /* Let T* and T& be written only when T is written (if T is an aggr). ! 674: We do this for const, but not for volatile, since volatile ! 675: is rare and const is not. */ ! 676: if (!TYPE_VOLATILE (taggr) ! 677: && (TREE_CODE (taggr) == POINTER_TYPE ! 678: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 679: && IS_AGGR_TYPE (TREE_TYPE (taggr))) ! 680: taggr = TREE_TYPE (taggr); ! 681: ! 682: /* If we know that we don't need to write out this type's ! 683: vtable, then don't write out it's dossier. Somebody ! 684: else will take care of that. */ ! 685: if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr)) ! 686: { ! 687: if (CLASSTYPE_VTABLE_NEEDS_WRITING (taggr)) ! 688: { ! 689: TREE_PUBLIC (tdecl) = ! CLASSTYPE_INTERFACE_ONLY (taggr) ! 690: && CLASSTYPE_INTERFACE_KNOWN (taggr); ! 691: TREE_STATIC (tdecl) = 1; ! 692: DECL_EXTERNAL (tdecl) = 0; ! 693: } ! 694: else ! 695: { ! 696: if (write_virtuals != 0) ! 697: TREE_PUBLIC (tdecl) = 1; ! 698: } ! 699: } ! 700: else ! 701: { ! 702: DECL_EXTERNAL (tdecl) = 0; ! 703: TREE_STATIC (tdecl) = 1; ! 704: TREE_PUBLIC (tdecl) = (definition > 1); ! 705: } ! 706: } ! 707: SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0)); ! 708: if (!definition || DECL_EXTERNAL (tdecl)) ! 709: { ! 710: /* That's it! */ ! 711: finish_decl (tdecl, 0, 0, 0); ! 712: return IDENTIFIER_AS_DESC (tname); ! 713: } ! 714: ! 715: /* Show that we are defining the t_desc for this type. */ ! 716: DECL_INITIAL (tdecl) = error_mark_node; ! 717: ! 718: parents = build_tree_list (NULL_TREE, integer_zero_node); ! 719: vbases = build_tree_list (NULL_TREE, integer_zero_node); ! 720: offsets = build_tree_list (NULL_TREE, integer_zero_node); ! 721: methods = NULL_TREE; ! 722: ivars = NULL_TREE; ! 723: ! 724: if (TYPE_LANG_SPECIFIC (type)) ! 725: { ! 726: int i = CLASSTYPE_N_BASECLASSES (type); ! 727: tree method_vec = CLASSTYPE_METHOD_VEC (type); ! 728: tree *meth, *end; ! 729: tree binfos = TYPE_BINFO_BASETYPES (type); ! 730: tree vb = CLASSTYPE_VBASECLASSES (type); ! 731: ! 732: while (--i >= 0) ! 733: parents = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (TREE_VEC_ELT (binfos, i)), 0), parents); ! 734: ! 735: while (vb) ! 736: { ! 737: vbases = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (vb), 0), vbases); ! 738: offsets = tree_cons (NULL_TREE, BINFO_OFFSET (vb), offsets); ! 739: vb = TREE_CHAIN (vb); ! 740: } ! 741: ! 742: if (method_vec) ! 743: for (meth = TREE_VEC_END (method_vec), ! 744: end = &TREE_VEC_ELT (method_vec, 0); meth-- != end; ) ! 745: if (*meth) ! 746: { ! 747: methods = tree_cons (NULL_TREE, build_m_desc (*meth), methods); ! 748: method_count++; ! 749: } ! 750: } ! 751: ! 752: if (IS_AGGR_TYPE (type)) ! 753: { ! 754: for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields)) ! 755: if (TREE_CODE (fields) == FIELD_DECL ! 756: || TREE_CODE (fields) == VAR_DECL) ! 757: { ! 758: ivars = tree_cons (NULL_TREE, build_i_desc (fields), ivars); ! 759: field_count++; ! 760: } ! 761: ivars = nreverse (ivars); ! 762: } ! 763: ! 764: parents = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), parents, 0); ! 765: vbases = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), vbases, 0); ! 766: offsets = finish_table (0, integer_type_node, offsets, 0); ! 767: if (methods == NULL_TREE) ! 768: methods = null_pointer_node; ! 769: else ! 770: methods = build_unary_op (ADDR_EXPR, ! 771: finish_table (0, __m_desc_type_node, methods, 0), ! 772: 0); ! 773: if (ivars == NULL_TREE) ! 774: ivars = null_pointer_node; ! 775: else ! 776: ivars = build_unary_op (ADDR_EXPR, ! 777: finish_table (0, __i_desc_type_node, ivars, 0), ! 778: 0); ! 779: if (TREE_TYPE (type)) ! 780: target_type = build_t_desc (TREE_TYPE (type), definition); ! 781: else ! 782: target_type = integer_zero_node; ! 783: ! 784: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); ! 785: ! 786: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 787: tree_cons (NULL_TREE, ! 788: TYPE_SIZE(type)? size_in_bytes(type) : integer_zero_node, ! 789: /* really should use bitfield initialization here. */ ! 790: tree_cons (NULL_TREE, integer_zero_node, ! 791: tree_cons (NULL_TREE, target_type, ! 792: tree_cons (NULL_TREE, build_int_2 (field_count, 2), ! 793: tree_cons (NULL_TREE, build_int_2 (method_count, 2), ! 794: tree_cons (NULL_TREE, ivars, ! 795: tree_cons (NULL_TREE, methods, ! 796: tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, parents, 0), ! 797: tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, vbases, 0), ! 798: build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, offsets, 0)))))))))))); ! 799: return build_generic_desc (tdecl, elems); ! 800: } ! 801: ! 802: /* Build an initializer for a __i_desc node. */ ! 803: tree ! 804: build_i_desc (decl) ! 805: tree decl; ! 806: { ! 807: tree elems, name_string; ! 808: tree taggr; ! 809: ! 810: name_string = DECL_NAME (decl); ! 811: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); ! 812: ! 813: /* Now decide whether this ivar should cause it's type to get ! 814: def'd or ref'd in this file. If the type we are looking at ! 815: has a proxy definition, we look at the proxy (i.e., a ! 816: `foo *' is equivalent to a `foo'). */ ! 817: taggr = TREE_TYPE (decl); ! 818: ! 819: if ((TREE_CODE (taggr) == POINTER_TYPE ! 820: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 821: && TYPE_VOLATILE (taggr) == 0) ! 822: taggr = TREE_TYPE (taggr); ! 823: ! 824: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 825: tree_cons (NULL_TREE, DECL_FIELD_BITPOS (decl), ! 826: build_tree_list (NULL_TREE, build_t_desc (TREE_TYPE (decl), ! 827: ! IS_AGGR_TYPE (taggr))))); ! 828: taggr = build (CONSTRUCTOR, __i_desc_type_node, NULL_TREE, elems); ! 829: TREE_CONSTANT (taggr) = 1; ! 830: TREE_STATIC (taggr) = 1; ! 831: TREE_READONLY (taggr) = 1; ! 832: return taggr; ! 833: } ! 834: ! 835: /* Build an initializer for a __m_desc node. */ ! 836: tree ! 837: build_m_desc (decl) ! 838: tree decl; ! 839: { ! 840: tree taggr, elems, name_string; ! 841: tree parm_count, req_count, vindex, vcontext; ! 842: tree parms; ! 843: int p_count, r_count; ! 844: tree parm_types = NULL_TREE; ! 845: ! 846: for (parms = TYPE_ARG_TYPES (TREE_TYPE (decl)), p_count = 0, r_count = 0; ! 847: parms != NULL_TREE; parms = TREE_CHAIN (parms), p_count++) ! 848: { ! 849: taggr = TREE_VALUE (parms); ! 850: if ((TREE_CODE (taggr) == POINTER_TYPE ! 851: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 852: && TYPE_VOLATILE (taggr) == 0) ! 853: taggr = TREE_TYPE (taggr); ! 854: ! 855: parm_types = tree_cons (NULL_TREE, build_t_desc (TREE_VALUE (parms), ! 856: ! IS_AGGR_TYPE (taggr)), ! 857: parm_types); ! 858: if (TREE_PURPOSE (parms) == NULL_TREE) ! 859: r_count++; ! 860: } ! 861: ! 862: parm_types = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), ! 863: nreverse (parm_types), 0); ! 864: parm_count = build_int_2 (p_count, 0); ! 865: req_count = build_int_2 (r_count, 0); ! 866: ! 867: if (DECL_VINDEX (decl)) ! 868: vindex = DECL_VINDEX (decl); ! 869: else ! 870: vindex = integer_zero_node; ! 871: if (DECL_CONTEXT (decl) ! 872: && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't') ! 873: vcontext = build_t_desc (DECL_CONTEXT (decl), 0); ! 874: else ! 875: vcontext = integer_zero_node; ! 876: name_string = DECL_NAME (decl); ! 877: if (name_string == NULL) ! 878: name_string = DECL_ASSEMBLER_NAME (decl); ! 879: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); ! 880: ! 881: /* Now decide whether the return type of this mvar ! 882: should cause it's type to get def'd or ref'd in this file. ! 883: If the type we are looking at has a proxy definition, ! 884: we look at the proxy (i.e., a `foo *' is equivalent to a `foo'). */ ! 885: taggr = TREE_TYPE (TREE_TYPE (decl)); ! 886: ! 887: if ((TREE_CODE (taggr) == POINTER_TYPE ! 888: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 889: && TYPE_VOLATILE (taggr) == 0) ! 890: taggr = TREE_TYPE (taggr); ! 891: ! 892: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 893: tree_cons (NULL_TREE, vindex, ! 894: tree_cons (NULL_TREE, vcontext, ! 895: tree_cons (NULL_TREE, build_t_desc (TREE_TYPE (TREE_TYPE (decl)), ! 896: ! IS_AGGR_TYPE (taggr)), ! 897: tree_cons (NULL_TREE, build_c_cast (TYPE_POINTER_TO (default_function_type), build_unary_op (ADDR_EXPR, decl, 0)), ! 898: tree_cons (NULL_TREE, parm_count, ! 899: tree_cons (NULL_TREE, req_count, ! 900: build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, parm_types, 0))))))))); ! 901: ! 902: taggr = build (CONSTRUCTOR, __m_desc_type_node, NULL_TREE, elems); ! 903: TREE_CONSTANT (taggr) = 1; ! 904: TREE_STATIC (taggr) = 1; ! 905: TREE_READONLY (taggr) = 1; ! 906: return taggr; ! 907: } ! 908: ! 909: /* Conditionally emit code to set up an unwind-protect for the ! 910: garbage collector. If this function doesn't do anything that involves ! 911: the garbage collector, then do nothing. Otherwise, call __gc_push ! 912: at the beginning and __gc_pop at the end. ! 913: ! 914: NOTE! The __gc_pop function must operate transparently, since ! 915: it comes where the logical return label lies. This means that ! 916: at runtime *it* must preserve any return value registers. */ ! 917: ! 918: void ! 919: expand_gc_prologue_and_epilogue () ! 920: { ! 921: extern tree maybe_gc_cleanup; ! 922: struct rtx_def *last_parm_insn, *mark; ! 923: extern struct rtx_def *get_last_insn (); ! 924: extern struct rtx_def *get_first_nonparm_insn (); ! 925: extern struct rtx_def *previous_insn (); ! 926: tree action; ! 927: ! 928: /* If we didn't need the obstack, don't cons any space. */ ! 929: if (current_function_obstack_index == 0 ! 930: || current_function_obstack_usage == 0) ! 931: return; ! 932: ! 933: mark = get_last_insn (); ! 934: last_parm_insn = get_first_nonparm_insn (); ! 935: if (last_parm_insn == 0) last_parm_insn = mark; ! 936: else last_parm_insn = previous_insn (last_parm_insn); ! 937: ! 938: action = build_function_call (gc_push_fndecl, ! 939: build_tree_list (NULL_TREE, size_int (++current_function_obstack_index))); ! 940: expand_expr_stmt (action); ! 941: ! 942: reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn); ! 943: ! 944: /* This will be expanded as a cleanup. */ ! 945: TREE_VALUE (maybe_gc_cleanup) ! 946: = build_function_call (gc_pop_fndecl, NULL_TREE); ! 947: } ! 948: ! 949: /* Some day we'll use this function as a call-back and clean ! 950: up all the unnecessary gc dribble that we otherwise create. */ ! 951: void ! 952: lang_expand_end_bindings (first, last) ! 953: struct rtx_def *first, *last; ! 954: { ! 955: } ! 956: ! 957: void ! 958: init_gc_processing () ! 959: { ! 960: tree parmtypes = hash_tree_chain (class_star_type_node, ! 961: hash_tree_chain (integer_type_node, NULL_TREE)); ! 962: gc_protect_fndecl = define_function ("__gc_protect", ! 963: build_function_type (class_star_type_node, parmtypes), ! 964: NOT_BUILT_IN, 0, 0); ! 965: ! 966: parmtypes = hash_tree_chain (integer_type_node, NULL_TREE); ! 967: gc_unprotect_fndecl = define_function ("__gc_unprotect", ! 968: build_function_type (void_type_node, parmtypes), ! 969: NOT_BUILT_IN, 0, 0); ! 970: ! 971: gc_push_fndecl = define_function ("__gc_push", ! 972: TREE_TYPE (gc_unprotect_fndecl), ! 973: NOT_BUILT_IN, 0, 0); ! 974: ! 975: gc_pop_fndecl = define_function ("__gc_pop", ! 976: build_function_type (void_type_node, ! 977: void_list_node), ! 978: NOT_BUILT_IN, 0, 0); ! 979: gc_nonobject = build_int_2 (0x80000000, 0); ! 980: gc_visible = build_int_2 (0x40000000, 0); ! 981: gc_white = integer_zero_node; ! 982: gc_offwhite = build_int_2 (0x10000000, 0); ! 983: gc_grey = build_int_2 (0x20000000, 0); ! 984: gc_black = build_int_2 (0x30000000, 0); ! 985: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.