|
|
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: if (flag_vtable_thunks) ! 388: abort(); ! 389: ! 390: vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp); ! 391: offset = build_component_ref (build_array_ref (vptr, integer_one_node), ! 392: get_identifier (VTABLE_DELTA_NAME), ! 393: NULL_TREE, 0); ! 394: return build (PLUS_EXPR, class_star_type_node, exp, ! 395: convert (integer_type_node, offset)); ! 396: } ! 397: ! 398: /* Given the expression EXP of type `class *', return the ! 399: type descriptor for the object pointed to by EXP. */ ! 400: tree ! 401: build_classof (exp) ! 402: tree exp; ! 403: { ! 404: tree type = TREE_TYPE (exp); ! 405: tree vptr; ! 406: tree t_desc_entry; ! 407: ! 408: if (TREE_CODE (type) != POINTER_TYPE) ! 409: { ! 410: error ("`classof' applied to non-pointer type"); ! 411: return error_mark_node; ! 412: } ! 413: ! 414: vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp); ! 415: t_desc_entry = build_component_ref (build_array_ref (vptr, integer_one_node), ! 416: get_identifier (VTABLE_PFN_NAME), ! 417: NULL_TREE, 0); ! 418: TREE_TYPE (t_desc_entry) = TYPE_POINTER_TO (__t_desc_type_node); ! 419: return t_desc_entry; ! 420: } ! 421: ! 422: /* Return the Type_info node associated with the expression EXP. If EXP is ! 423: a reference to a polymorphic class, return the dynamic type; otherwise ! 424: return the static type of the expression. */ ! 425: tree ! 426: build_typeid (exp) ! 427: tree exp; ! 428: { ! 429: tree type; ! 430: ! 431: if (exp == error_mark_node) ! 432: return error_mark_node; ! 433: ! 434: type = TREE_TYPE (exp); ! 435: ! 436: /* if b is an instance of B, typeid(b) == typeid(B). Do this before ! 437: reference trickiness. */ ! 438: if (TREE_CODE (exp) == VAR_DECL && TREE_CODE (type) == RECORD_TYPE) ! 439: return get_typeid (type); ! 440: ! 441: /* Apply trivial conversion T -> T& for dereferenced ptrs. */ ! 442: if (TREE_CODE (type) == RECORD_TYPE) ! 443: type = build_reference_type (type); ! 444: ! 445: /* If exp is a reference to polymorphic type, get the real Type_info. */ ! 446: if (TREE_CODE (type) == REFERENCE_TYPE && TYPE_VIRTUAL_P (TREE_TYPE (type))) ! 447: { ! 448: /* build reference to Type_info from vtable. */ ! 449: ! 450: sorry ("finding Type_info for an object"); ! 451: return error_mark_node; ! 452: } ! 453: ! 454: /* otherwise return the Type_info for the static type of the expr. */ ! 455: return get_typeid (type); ! 456: } ! 457: ! 458: /* Return the Type_info object for TYPE, creating it if necessary. */ ! 459: tree ! 460: get_typeid (type) ! 461: tree type; ! 462: { ! 463: if (type == error_mark_node) ! 464: return error_mark_node; ! 465: ! 466: /* Is it useful (and/or correct) to have different typeids for `T &' ! 467: and `T'? */ ! 468: if (TREE_CODE (type) == REFERENCE_TYPE) ! 469: type = TREE_TYPE (type); ! 470: ! 471: /* build reference to static Type_info */ ! 472: #if 1 ! 473: sorry ("finding Type_info for a type"); ! 474: return error_mark_node; ! 475: #else ! 476: register tree t = TYPE_TINFO (type); ! 477: ! 478: if (t) ! 479: return t; ! 480: ! 481: /* ... */ ! 482: ! 483: #endif ! 484: } ! 485: ! 486: /* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working ! 487: paper. */ ! 488: tree ! 489: build_dynamic_cast (type, expr) ! 490: tree type, expr; ! 491: { ! 492: enum tree_code tc = TREE_CODE (type); ! 493: tree exprtype = TREE_TYPE (expr); ! 494: enum tree_code ec = TREE_CODE (exprtype); ! 495: tree retval; ! 496: ! 497: if (type == error_mark_node || expr == error_mark_node) ! 498: return error_mark_node; ! 499: ! 500: switch (tc) ! 501: { ! 502: case POINTER_TYPE: ! 503: if (TREE_TYPE (type) == void_type_node) ! 504: break; ! 505: /* else fall through */ ! 506: case REFERENCE_TYPE: ! 507: if (TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE ! 508: && TYPE_SIZE (TREE_TYPE (type)) != NULL_TREE) ! 509: break; ! 510: /* else fall through */ ! 511: default: ! 512: cp_error ("`%#T' is not a valid type argument for dynamic_cast", type); ! 513: error ("(must be either pointer or reference to defined class or void *)"); ! 514: return error_mark_node; ! 515: } ! 516: ! 517: /* Apply trivial conversion T -> T& for dereferenced ptrs. */ ! 518: if (ec == RECORD_TYPE) ! 519: { ! 520: exprtype = build_reference_type (exprtype); ! 521: ec = REFERENCE_TYPE; ! 522: } ! 523: ! 524: /* the TREE_CODE of exprtype must match that of type. */ ! 525: if (ec != tc) ! 526: { ! 527: cp_error ("`%E' (of type `%#T') fails to be of %s type", expr, exprtype, ! 528: tc == POINTER_TYPE ? "pointer" : "reference"); ! 529: return error_mark_node; ! 530: } ! 531: ! 532: /* If *type is an unambiguous accessible base class of *exprtype, ! 533: convert statically. */ ! 534: { ! 535: int distance; ! 536: tree path; ! 537: ! 538: distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1, ! 539: &path); ! 540: if (distance >= 0) ! 541: return build_vbase_path (PLUS_EXPR, type, expr, path, 0); ! 542: } ! 543: ! 544: /* Otherwise *exprtype must be a polymorphic class (have a vtbl). */ ! 545: if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype))) ! 546: { ! 547: /* if TYPE is `void *', return pointer to complete object. */ ! 548: if (tc == POINTER_TYPE && TREE_TYPE (type) == void_type_node) ! 549: { ! 550: /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b. */ ! 551: if (TREE_CODE (expr) == ADDR_EXPR ! 552: && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL ! 553: && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE) ! 554: return build1 (NOP_EXPR, type, expr); ! 555: ! 556: sorry ("finding pointer to complete object"); ! 557: return build1 (NOP_EXPR, type, expr); ! 558: } ! 559: else ! 560: { ! 561: tree retval; ! 562: ! 563: /* If we got here, we can't convert statically. Therefore, ! 564: dynamic_cast<D&>(b) (b an object) cannot succeed. */ ! 565: if (ec == REFERENCE_TYPE) ! 566: { ! 567: if (TREE_CODE (expr) == VAR_DECL ! 568: && TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE) ! 569: { ! 570: cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed", ! 571: expr, type); ! 572: /* cplus_expand_throw (Bad_cast_node); */ ! 573: sorry ("throwing Bad_cast"); ! 574: return error_mark_node; ! 575: } ! 576: } ! 577: /* Ditto for dynamic_cast<D*>(&b). */ ! 578: else if (TREE_CODE (expr) == ADDR_EXPR) ! 579: { ! 580: tree op = TREE_OPERAND (expr, 0); ! 581: if (TREE_CODE (op) == VAR_DECL ! 582: && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE) ! 583: { ! 584: cp_warning ("dynamic_cast of `%E' to `%#T' can never succeed", ! 585: expr, type); ! 586: retval = build_int_2 (0, 0); ! 587: TREE_TYPE (retval) = type; ! 588: return retval; ! 589: } ! 590: } ! 591: /* Build run-time conversion. */ ! 592: sorry ("run-time type conversion"); ! 593: retval = build_int_2 (0, 0); ! 594: TREE_TYPE (retval) = type; ! 595: return retval; ! 596: } ! 597: } ! 598: ! 599: cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'", ! 600: expr, exprtype, type); ! 601: return error_mark_node; ! 602: } ! 603: ! 604: /* Build and initialize various sorts of descriptors. Every descriptor ! 605: node has a name associated with it (the name created by mangling). ! 606: For this reason, we use the identifier as our access to the __*_desc ! 607: nodes, instead of sticking them directly in the types. Otherwise we ! 608: would burden all built-in types (and pointer types) with slots that ! 609: we don't necessarily want to use. ! 610: ! 611: For each descriptor we build, we build a variable that contains ! 612: the descriptor's information. When we need this info at runtime, ! 613: all we need is access to these variables. ! 614: ! 615: Note: these constructors always return the address of the descriptor ! 616: info, since that is simplest for their mutual interaction. */ ! 617: ! 618: static tree ! 619: build_generic_desc (decl, elems) ! 620: tree decl; ! 621: tree elems; ! 622: { ! 623: tree init = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE, elems); ! 624: TREE_CONSTANT (init) = 1; ! 625: TREE_STATIC (init) = 1; ! 626: TREE_READONLY (init) = 1; ! 627: ! 628: DECL_INITIAL (decl) = init; ! 629: TREE_STATIC (decl) = 1; ! 630: layout_decl (decl, 0); ! 631: finish_decl (decl, init, 0, 0); ! 632: ! 633: return IDENTIFIER_AS_DESC (DECL_NAME (decl)); ! 634: } ! 635: ! 636: /* Build an initializer for a __t_desc node. So that we can take advantage ! 637: of recursion, we accept NULL for TYPE. ! 638: DEFINITION is greater than zero iff we must define the type descriptor ! 639: (as opposed to merely referencing it). 1 means treat according to ! 640: #pragma interface/#pragma implementation rules. 2 means define as ! 641: global and public, no matter what. */ ! 642: tree ! 643: build_t_desc (type, definition) ! 644: tree type; ! 645: int definition; ! 646: { ! 647: tree tdecl; ! 648: tree tname, name_string; ! 649: tree elems, fields; ! 650: tree parents, vbases, offsets, ivars, methods, target_type; ! 651: int method_count = 0, field_count = 0; ! 652: ! 653: if (type == NULL_TREE) ! 654: return NULL_TREE; ! 655: ! 656: tname = build_t_desc_overload (type); ! 657: if (IDENTIFIER_AS_DESC (tname) ! 658: && (!definition || TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname)))) ! 659: return IDENTIFIER_AS_DESC (tname); ! 660: ! 661: tdecl = lookup_name (tname, 0); ! 662: if (tdecl == NULL_TREE) ! 663: { ! 664: tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node); ! 665: DECL_EXTERNAL (tdecl) = 1; ! 666: TREE_PUBLIC (tdecl) = 1; ! 667: tdecl = pushdecl_top_level (tdecl); ! 668: } ! 669: /* If we previously defined it, return the defined result. */ ! 670: else if (definition && DECL_INITIAL (tdecl)) ! 671: return IDENTIFIER_AS_DESC (tname); ! 672: ! 673: if (definition) ! 674: { ! 675: tree taggr = type; ! 676: /* Let T* and T& be written only when T is written (if T is an aggr). ! 677: We do this for const, but not for volatile, since volatile ! 678: is rare and const is not. */ ! 679: if (!TYPE_VOLATILE (taggr) ! 680: && (TREE_CODE (taggr) == POINTER_TYPE ! 681: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 682: && IS_AGGR_TYPE (TREE_TYPE (taggr))) ! 683: taggr = TREE_TYPE (taggr); ! 684: ! 685: /* If we know that we don't need to write out this type's ! 686: vtable, then don't write out it's dossier. Somebody ! 687: else will take care of that. */ ! 688: if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr)) ! 689: { ! 690: if (CLASSTYPE_VTABLE_NEEDS_WRITING (taggr)) ! 691: { ! 692: TREE_PUBLIC (tdecl) = ! CLASSTYPE_INTERFACE_ONLY (taggr) ! 693: && CLASSTYPE_INTERFACE_KNOWN (taggr); ! 694: TREE_STATIC (tdecl) = 1; ! 695: DECL_EXTERNAL (tdecl) = 0; ! 696: } ! 697: else ! 698: { ! 699: if (write_virtuals != 0) ! 700: TREE_PUBLIC (tdecl) = 1; ! 701: } ! 702: } ! 703: else ! 704: { ! 705: DECL_EXTERNAL (tdecl) = 0; ! 706: TREE_STATIC (tdecl) = 1; ! 707: TREE_PUBLIC (tdecl) = (definition > 1); ! 708: } ! 709: } ! 710: SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0)); ! 711: if (!definition || DECL_EXTERNAL (tdecl)) ! 712: { ! 713: /* That's it! */ ! 714: finish_decl (tdecl, 0, 0, 0); ! 715: return IDENTIFIER_AS_DESC (tname); ! 716: } ! 717: ! 718: /* Show that we are defining the t_desc for this type. */ ! 719: DECL_INITIAL (tdecl) = error_mark_node; ! 720: ! 721: parents = build_tree_list (NULL_TREE, integer_zero_node); ! 722: vbases = build_tree_list (NULL_TREE, integer_zero_node); ! 723: offsets = build_tree_list (NULL_TREE, integer_zero_node); ! 724: methods = NULL_TREE; ! 725: ivars = NULL_TREE; ! 726: ! 727: if (TYPE_LANG_SPECIFIC (type)) ! 728: { ! 729: int i = CLASSTYPE_N_BASECLASSES (type); ! 730: tree method_vec = CLASSTYPE_METHOD_VEC (type); ! 731: tree *meth, *end; ! 732: tree binfos = TYPE_BINFO_BASETYPES (type); ! 733: tree vb = CLASSTYPE_VBASECLASSES (type); ! 734: ! 735: while (--i >= 0) ! 736: parents = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (TREE_VEC_ELT (binfos, i)), 0), parents); ! 737: ! 738: while (vb) ! 739: { ! 740: vbases = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (vb), 0), vbases); ! 741: offsets = tree_cons (NULL_TREE, BINFO_OFFSET (vb), offsets); ! 742: vb = TREE_CHAIN (vb); ! 743: } ! 744: ! 745: if (method_vec) ! 746: for (meth = TREE_VEC_END (method_vec), ! 747: end = &TREE_VEC_ELT (method_vec, 0); meth-- != end; ) ! 748: if (*meth) ! 749: { ! 750: methods = tree_cons (NULL_TREE, build_m_desc (*meth), methods); ! 751: method_count++; ! 752: } ! 753: } ! 754: ! 755: if (IS_AGGR_TYPE (type)) ! 756: { ! 757: for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields)) ! 758: if (TREE_CODE (fields) == FIELD_DECL ! 759: || TREE_CODE (fields) == VAR_DECL) ! 760: { ! 761: ivars = tree_cons (NULL_TREE, build_i_desc (fields), ivars); ! 762: field_count++; ! 763: } ! 764: ivars = nreverse (ivars); ! 765: } ! 766: ! 767: parents = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), parents, 0); ! 768: vbases = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), vbases, 0); ! 769: offsets = finish_table (0, integer_type_node, offsets, 0); ! 770: if (methods == NULL_TREE) ! 771: methods = null_pointer_node; ! 772: else ! 773: methods = build_unary_op (ADDR_EXPR, ! 774: finish_table (0, __m_desc_type_node, methods, 0), ! 775: 0); ! 776: if (ivars == NULL_TREE) ! 777: ivars = null_pointer_node; ! 778: else ! 779: ivars = build_unary_op (ADDR_EXPR, ! 780: finish_table (0, __i_desc_type_node, ivars, 0), ! 781: 0); ! 782: if (TREE_TYPE (type)) ! 783: target_type = build_t_desc (TREE_TYPE (type), definition); ! 784: else ! 785: target_type = integer_zero_node; ! 786: ! 787: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname))); ! 788: ! 789: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 790: tree_cons (NULL_TREE, ! 791: TYPE_SIZE(type)? size_in_bytes(type) : integer_zero_node, ! 792: /* really should use bitfield initialization here. */ ! 793: tree_cons (NULL_TREE, integer_zero_node, ! 794: tree_cons (NULL_TREE, target_type, ! 795: tree_cons (NULL_TREE, build_int_2 (field_count, 2), ! 796: tree_cons (NULL_TREE, build_int_2 (method_count, 2), ! 797: tree_cons (NULL_TREE, ivars, ! 798: tree_cons (NULL_TREE, methods, ! 799: tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, parents, 0), ! 800: tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, vbases, 0), ! 801: build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, offsets, 0)))))))))))); ! 802: return build_generic_desc (tdecl, elems); ! 803: } ! 804: ! 805: /* Build an initializer for a __i_desc node. */ ! 806: tree ! 807: build_i_desc (decl) ! 808: tree decl; ! 809: { ! 810: tree elems, name_string; ! 811: tree taggr; ! 812: ! 813: name_string = DECL_NAME (decl); ! 814: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); ! 815: ! 816: /* Now decide whether this ivar should cause it's type to get ! 817: def'd or ref'd in this file. If the type we are looking at ! 818: has a proxy definition, we look at the proxy (i.e., a ! 819: `foo *' is equivalent to a `foo'). */ ! 820: taggr = TREE_TYPE (decl); ! 821: ! 822: if ((TREE_CODE (taggr) == POINTER_TYPE ! 823: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 824: && TYPE_VOLATILE (taggr) == 0) ! 825: taggr = TREE_TYPE (taggr); ! 826: ! 827: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 828: tree_cons (NULL_TREE, DECL_FIELD_BITPOS (decl), ! 829: build_tree_list (NULL_TREE, build_t_desc (TREE_TYPE (decl), ! 830: ! IS_AGGR_TYPE (taggr))))); ! 831: taggr = build (CONSTRUCTOR, __i_desc_type_node, NULL_TREE, elems); ! 832: TREE_CONSTANT (taggr) = 1; ! 833: TREE_STATIC (taggr) = 1; ! 834: TREE_READONLY (taggr) = 1; ! 835: return taggr; ! 836: } ! 837: ! 838: /* Build an initializer for a __m_desc node. */ ! 839: tree ! 840: build_m_desc (decl) ! 841: tree decl; ! 842: { ! 843: tree taggr, elems, name_string; ! 844: tree parm_count, req_count, vindex, vcontext; ! 845: tree parms; ! 846: int p_count, r_count; ! 847: tree parm_types = NULL_TREE; ! 848: ! 849: for (parms = TYPE_ARG_TYPES (TREE_TYPE (decl)), p_count = 0, r_count = 0; ! 850: parms != NULL_TREE; parms = TREE_CHAIN (parms), p_count++) ! 851: { ! 852: taggr = TREE_VALUE (parms); ! 853: if ((TREE_CODE (taggr) == POINTER_TYPE ! 854: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 855: && TYPE_VOLATILE (taggr) == 0) ! 856: taggr = TREE_TYPE (taggr); ! 857: ! 858: parm_types = tree_cons (NULL_TREE, build_t_desc (TREE_VALUE (parms), ! 859: ! IS_AGGR_TYPE (taggr)), ! 860: parm_types); ! 861: if (TREE_PURPOSE (parms) == NULL_TREE) ! 862: r_count++; ! 863: } ! 864: ! 865: parm_types = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), ! 866: nreverse (parm_types), 0); ! 867: parm_count = build_int_2 (p_count, 0); ! 868: req_count = build_int_2 (r_count, 0); ! 869: ! 870: if (DECL_VINDEX (decl)) ! 871: vindex = DECL_VINDEX (decl); ! 872: else ! 873: vindex = integer_zero_node; ! 874: if (DECL_CONTEXT (decl) ! 875: && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't') ! 876: vcontext = build_t_desc (DECL_CONTEXT (decl), 0); ! 877: else ! 878: vcontext = integer_zero_node; ! 879: name_string = DECL_NAME (decl); ! 880: if (name_string == NULL) ! 881: name_string = DECL_ASSEMBLER_NAME (decl); ! 882: name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string))); ! 883: ! 884: /* Now decide whether the return type of this mvar ! 885: should cause it's type to get def'd or ref'd in this file. ! 886: If the type we are looking at has a proxy definition, ! 887: we look at the proxy (i.e., a `foo *' is equivalent to a `foo'). */ ! 888: taggr = TREE_TYPE (TREE_TYPE (decl)); ! 889: ! 890: if ((TREE_CODE (taggr) == POINTER_TYPE ! 891: || TREE_CODE (taggr) == REFERENCE_TYPE) ! 892: && TYPE_VOLATILE (taggr) == 0) ! 893: taggr = TREE_TYPE (taggr); ! 894: ! 895: elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0), ! 896: tree_cons (NULL_TREE, vindex, ! 897: tree_cons (NULL_TREE, vcontext, ! 898: tree_cons (NULL_TREE, build_t_desc (TREE_TYPE (TREE_TYPE (decl)), ! 899: ! IS_AGGR_TYPE (taggr)), ! 900: tree_cons (NULL_TREE, build_c_cast (TYPE_POINTER_TO (default_function_type), build_unary_op (ADDR_EXPR, decl, 0)), ! 901: tree_cons (NULL_TREE, parm_count, ! 902: tree_cons (NULL_TREE, req_count, ! 903: build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, parm_types, 0))))))))); ! 904: ! 905: taggr = build (CONSTRUCTOR, __m_desc_type_node, NULL_TREE, elems); ! 906: TREE_CONSTANT (taggr) = 1; ! 907: TREE_STATIC (taggr) = 1; ! 908: TREE_READONLY (taggr) = 1; ! 909: return taggr; ! 910: } ! 911: ! 912: /* Conditionally emit code to set up an unwind-protect for the ! 913: garbage collector. If this function doesn't do anything that involves ! 914: the garbage collector, then do nothing. Otherwise, call __gc_push ! 915: at the beginning and __gc_pop at the end. ! 916: ! 917: NOTE! The __gc_pop function must operate transparently, since ! 918: it comes where the logical return label lies. This means that ! 919: at runtime *it* must preserve any return value registers. */ ! 920: ! 921: void ! 922: expand_gc_prologue_and_epilogue () ! 923: { ! 924: extern tree maybe_gc_cleanup; ! 925: struct rtx_def *last_parm_insn, *mark; ! 926: extern struct rtx_def *get_last_insn (); ! 927: extern struct rtx_def *get_first_nonparm_insn (); ! 928: extern struct rtx_def *previous_insn (); ! 929: tree action; ! 930: ! 931: /* If we didn't need the obstack, don't cons any space. */ ! 932: if (current_function_obstack_index == 0 ! 933: || current_function_obstack_usage == 0) ! 934: return; ! 935: ! 936: mark = get_last_insn (); ! 937: last_parm_insn = get_first_nonparm_insn (); ! 938: if (last_parm_insn == 0) last_parm_insn = mark; ! 939: else last_parm_insn = previous_insn (last_parm_insn); ! 940: ! 941: action = build_function_call (gc_push_fndecl, ! 942: build_tree_list (NULL_TREE, size_int (++current_function_obstack_index))); ! 943: expand_expr_stmt (action); ! 944: ! 945: reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn); ! 946: ! 947: /* This will be expanded as a cleanup. */ ! 948: TREE_VALUE (maybe_gc_cleanup) ! 949: = build_function_call (gc_pop_fndecl, NULL_TREE); ! 950: } ! 951: ! 952: /* Some day we'll use this function as a call-back and clean ! 953: up all the unnecessary gc dribble that we otherwise create. */ ! 954: void ! 955: lang_expand_end_bindings (first, last) ! 956: struct rtx_def *first, *last; ! 957: { ! 958: } ! 959: ! 960: void ! 961: init_gc_processing () ! 962: { ! 963: tree parmtypes = hash_tree_chain (class_star_type_node, ! 964: hash_tree_chain (integer_type_node, NULL_TREE)); ! 965: gc_protect_fndecl = define_function ("__gc_protect", ! 966: build_function_type (class_star_type_node, parmtypes), ! 967: NOT_BUILT_IN, 0, 0); ! 968: ! 969: parmtypes = hash_tree_chain (integer_type_node, NULL_TREE); ! 970: gc_unprotect_fndecl = define_function ("__gc_unprotect", ! 971: build_function_type (void_type_node, parmtypes), ! 972: NOT_BUILT_IN, 0, 0); ! 973: ! 974: gc_push_fndecl = define_function ("__gc_push", ! 975: TREE_TYPE (gc_unprotect_fndecl), ! 976: NOT_BUILT_IN, 0, 0); ! 977: ! 978: gc_pop_fndecl = define_function ("__gc_pop", ! 979: build_function_type (void_type_node, ! 980: void_list_node), ! 981: NOT_BUILT_IN, 0, 0); ! 982: gc_nonobject = build_int_2 (0x80000000, 0); ! 983: gc_visible = build_int_2 (0x40000000, 0); ! 984: gc_white = integer_zero_node; ! 985: gc_offwhite = build_int_2 (0x10000000, 0); ! 986: gc_grey = build_int_2 (0x20000000, 0); ! 987: gc_black = build_int_2 (0x30000000, 0); ! 988: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.