Annotation of gcc/cp-gc.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.