OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [boehm-gc/] [gcc_support.c] - Blame information for rev 772

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 721 jeremybenn
/***************************************************************************
2
 
3
Interface between g++ and Boehm GC
4
 
5
    Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
6
 
7
    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8
    OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
9
 
10
    Permission is hereby granted to copy this code for any purpose,
11
    provided the above notices are retained on all copies.
12
 
13
    Last modified on Sun Jul 16 23:21:14 PDT 1995 by ellis
14
 
15
This module provides runtime support for implementing the
16
Ellis/Detlefs GC proposal, "Safe, Efficient Garbage Collection for
17
C++", within g++, using its -fgc-keyword extension.  It defines
18
versions of __builtin_new, __builtin_new_gc, __builtin_vec_new,
19
__builtin_vec_new_gc, __builtin_delete, and __builtin_vec_delete that
20
invoke the Bohem GC.  It also implements the WeakPointer.h interface.
21
 
22
This module assumes the following configuration options of the Boehm GC:
23
 
24
    -DALL_INTERIOR_POINTERS
25
    -DDONT_ADD_BYTE_AT_END
26
 
27
This module adds its own required padding to the end of objects to
28
support C/C++ "one-past-the-object" pointer semantics.
29
 
30
****************************************************************************/
31
 
32
#include <stddef.h>
33
#include "gc.h"
34
 
35
#if defined(__STDC__) 
36
#   define PROTO( args ) args
37
#else
38
#    define PROTO( args ) ()
39
#    endif
40
 
41
#define BITSPERBYTE 8     
42
    /* What's the portable way to do this? */
43
 
44
 
45
typedef void (*vfp) PROTO(( void ));
46
extern vfp __new_handler;
47
extern void __default_new_handler PROTO(( void ));
48
 
49
 
50
/* A destructor_proc is the compiler generated procedure representing a
51
C++ destructor.  The "flag" argument is a hidden argument following some
52
compiler convention. */
53
 
54
typedef (*destructor_proc) PROTO(( void* this, int flag ));
55
 
56
 
57
/***************************************************************************
58
 
59
A BI_header is the header the compiler adds to the front of
60
new-allocated arrays of objects with destructors.  The header is
61
padded out to a double, because that's what the compiler does to
62
ensure proper alignment of array elements on some architectures.
63
 
64
int NUM_ARRAY_ELEMENTS (void* o)
65
    returns the number of array elements for array object o.
66
 
67
char* FIRST_ELEMENT_P (void* o)
68
    returns the address of the first element of array object o.
69
 
70
***************************************************************************/
71
 
72
typedef struct BI_header {
73
    int nelts;
74
    char padding [sizeof( double ) - sizeof( int )];
75
        /* Better way to do this? */
76
} BI_header;
77
 
78
#define NUM_ARRAY_ELEMENTS( o ) \
79
  (((BI_header*) o)->nelts)
80
 
81
#define FIRST_ELEMENT_P( o ) \
82
  ((char*) o + sizeof( BI_header ))
83
 
84
 
85
/***************************************************************************
86
 
87
The __builtin_new routines add a descriptor word to the end of each
88
object.   The descriptor serves two purposes.
89
 
90
First, the descriptor acts as padding, implementing C/C++ pointer
91
semantics.  C and C++ allow a valid array pointer to be incremented
92
one past the end of an object.  The extra padding ensures that the
93
collector will recognize that such a pointer points to the object and
94
not the next object in memory.
95
 
96
Second, the descriptor stores three extra pieces of information,
97
whether an object has a registered finalizer (destructor), whether it
98
may have any weak pointers referencing it, and for collectible arrays,
99
the element size of the array.  The element size is required for the
100
array's finalizer to iterate through the elements of the array.  (An
101
alternative design would have the compiler generate a finalizer
102
procedure for each different array type.  But given the overhead of
103
finalization, there isn't any efficiency to be gained by that.)
104
 
105
The descriptor must be added to non-collectible as well as collectible
106
objects, since the Ellis/Detlefs proposal allows "pointer to gc T" to
107
be assigned to a "pointer to T", which could then be deleted.  Thus,
108
__builtin_delete must determine at runtime whether an object is
109
collectible, whether it has weak pointers referencing it, and whether
110
it may have a finalizer that needs unregistering.  Though
111
GC_REGISTER_FINALIZER doesn't care if you ask it to unregister a
112
finalizer for an object that doesn't have one, it is a non-trivial
113
procedure that does a hash look-up, etc.  The descriptor trades a
114
little extra space for a significant increase in time on the fast path
115
through delete.  (A similar argument applies to
116
GC_UNREGISTER_DISAPPEARING_LINK).
117
 
118
For non-array types, the space for the descriptor could be shrunk to a
119
single byte for storing the "has finalizer" flag.  But this would save
120
space only on arrays of char (whose size is not a multiple of the word
121
size) and structs whose largest member is less than a word in size
122
(very infrequent).  And it would require that programmers actually
123
remember to call "delete[]" instead of "delete" (which they should,
124
but there are probably lots of buggy programs out there).  For the
125
moment, the space savings seems not worthwhile, especially considering
126
that the Boehm GC is already quite space competitive with other
127
malloc's.
128
 
129
 
130
Given a pointer o to the base of an object:
131
 
132
Descriptor* DESCRIPTOR (void* o)
133
     returns a pointer to the descriptor for o.
134
 
135
The implementation of descriptors relies on the fact that the GC
136
implementation allocates objects in units of the machine's natural
137
word size (e.g. 32 bits on a SPARC, 64 bits on an Alpha).
138
 
139
**************************************************************************/
140
 
141
typedef struct Descriptor {
142
    unsigned has_weak_pointers: 1;
143
    unsigned has_finalizer: 1;
144
    unsigned element_size: BITSPERBYTE * sizeof( unsigned ) - 2;
145
} Descriptor;
146
 
147
#define DESCRIPTOR( o ) \
148
  ((Descriptor*) ((char*)(o) + GC_size( o ) - sizeof( Descriptor )))
149
 
150
 
151
/**************************************************************************
152
 
153
Implementations of global operator new() and operator delete()
154
 
155
***************************************************************************/
156
 
157
 
158
void* __builtin_new( size )
159
    size_t size;
160
    /*
161
    For non-gc non-array types, the compiler generates calls to
162
    __builtin_new, which allocates non-collected storage via
163
    GC_MALLOC_UNCOLLECTABLE.  This ensures that the non-collected
164
    storage will be part of the collector's root set, required by the
165
    Ellis/Detlefs semantics. */
166
{
167
    vfp handler = __new_handler ? __new_handler : __default_new_handler;
168
 
169
    while (1) {
170
        void* o = GC_MALLOC_UNCOLLECTABLE( size + sizeof( Descriptor ) );
171
        if (o != 0) return o;
172
        (*handler) ();}}
173
 
174
 
175
void* __builtin_vec_new( size )
176
    size_t size;
177
    /*
178
    For non-gc array types, the compiler generates calls to
179
    __builtin_vec_new. */
180
{
181
    return __builtin_new( size );}
182
 
183
 
184
void* __builtin_new_gc( size )
185
    size_t size;
186
    /*
187
    For gc non-array types, the compiler generates calls to
188
    __builtin_new_gc, which allocates collected storage via
189
    GC_MALLOC. */
190
{
191
    vfp handler = __new_handler ? __new_handler : __default_new_handler;
192
 
193
    while (1) {
194
        void* o = GC_MALLOC( size + sizeof( Descriptor ) );
195
        if (o != 0) return o;
196
        (*handler) ();}}
197
 
198
 
199
void* __builtin_new_gc_a( size )
200
    size_t size;
201
    /*
202
    For non-pointer-containing gc non-array types, the compiler
203
    generates calls to __builtin_new_gc_a, which allocates collected
204
    storage via GC_MALLOC_ATOMIC. */
205
{
206
    vfp handler = __new_handler ? __new_handler : __default_new_handler;
207
 
208
    while (1) {
209
        void* o = GC_MALLOC_ATOMIC( size + sizeof( Descriptor ) );
210
        if (o != 0) return o;
211
        (*handler) ();}}
212
 
213
 
214
void* __builtin_vec_new_gc( size )
215
    size_t size;
216
    /*
217
    For gc array types, the compiler generates calls to
218
    __builtin_vec_new_gc. */
219
{
220
    return __builtin_new_gc( size );}
221
 
222
 
223
void* __builtin_vec_new_gc_a( size )
224
    size_t size;
225
    /*
226
    For non-pointer-containing gc array types, the compiler generates
227
    calls to __builtin_vec_new_gc_a. */
228
{
229
    return __builtin_new_gc_a( size );}
230
 
231
 
232
static void call_destructor( o, data )
233
    void* o;
234
    void* data;
235
    /*
236
    call_destructor is the GC finalizer proc registered for non-array
237
    gc objects with destructors.  Its client data is the destructor
238
    proc, which it calls with the magic integer 2, a special flag
239
    obeying the compiler convention for destructors. */
240
{
241
    ((destructor_proc) data)( o, 2 );}
242
 
243
 
244
void* __builtin_new_gc_dtor( o, d )
245
    void* o;
246
    destructor_proc d;
247
    /*
248
    The compiler generates a call to __builtin_new_gc_dtor to register
249
    the destructor "d" of a non-array gc object "o" as a GC finalizer.
250
    The destructor is registered via
251
    GC_REGISTER_FINALIZER_IGNORE_SELF, which causes the collector to
252
    ignore pointers from the object to itself when determining when
253
    the object can be finalized.  This is necessary due to the self
254
    pointers used in the internal representation of multiply-inherited
255
    objects. */
256
{
257
    Descriptor* desc = DESCRIPTOR( o );
258
 
259
    GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_destructor, d, 0, 0 );
260
    desc->has_finalizer = 1;}
261
 
262
 
263
static void call_array_destructor( o, data )
264
    void* o;
265
    void* data;
266
    /*
267
    call_array_destructor is the GC finalizer proc registered for gc
268
    array objects whose elements have destructors. Its client data is
269
    the destructor proc.  It iterates through the elements of the
270
    array in reverse order, calling the destructor on each. */
271
{
272
    int num = NUM_ARRAY_ELEMENTS( o );
273
    Descriptor* desc = DESCRIPTOR( o );
274
    size_t size = desc->element_size;
275
    char* first_p = FIRST_ELEMENT_P( o );
276
    char* p = first_p + (num - 1) * size;
277
 
278
    if (num > 0) {
279
        while (1) {
280
            ((destructor_proc) data)( p, 2 );
281
            if (p == first_p) break;
282
            p -= size;}}}
283
 
284
 
285
void* __builtin_vec_new_gc_dtor( first_elem, d, element_size )
286
    void* first_elem;
287
    destructor_proc d;
288
    size_t element_size;
289
    /*
290
    The compiler generates a call to __builtin_vec_new_gc_dtor to
291
    register the destructor "d" of a gc array object as a GC
292
    finalizer.  "first_elem" points to the first element of the array,
293
    *not* the beginning of the object (this makes the generated call
294
    to this function smaller).  The elements of the array are of size
295
    "element_size".  The destructor is registered as in
296
    _builtin_new_gc_dtor. */
297
{
298
    void* o = (char*) first_elem - sizeof( BI_header );
299
    Descriptor* desc = DESCRIPTOR( o );
300
 
301
    GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_array_destructor, d, 0, 0 );
302
    desc->element_size = element_size;
303
    desc->has_finalizer = 1;}
304
 
305
 
306
void __builtin_delete( o )
307
    void* o;
308
    /*
309
    The compiler generates calls to __builtin_delete for operator
310
    delete().  The GC currently requires that any registered
311
    finalizers be unregistered before explicitly freeing an object.
312
    If the object has any weak pointers referencing it, we can't
313
    actually free it now. */
314
{
315
  if (o != 0) {
316
      Descriptor* desc = DESCRIPTOR( o );
317
      if (desc->has_finalizer) GC_REGISTER_FINALIZER( o, 0, 0, 0, 0 );
318
      if (! desc->has_weak_pointers) GC_FREE( o );}}
319
 
320
 
321
void __builtin_vec_delete( o )
322
    void* o;
323
    /*
324
    The compiler generates calls to __builitn_vec_delete for operator
325
    delete[](). */
326
{
327
  __builtin_delete( o );}
328
 
329
 
330
/**************************************************************************
331
 
332
Implementations of the template class WeakPointer from WeakPointer.h
333
 
334
***************************************************************************/
335
 
336
typedef struct WeakPointer {
337
    void* pointer;
338
} WeakPointer;
339
 
340
 
341
void* _WeakPointer_New( t )
342
    void* t;
343
{
344
    if (t == 0) {
345
        return 0;}
346
    else {
347
        void* base = GC_base( t );
348
        WeakPointer* wp =
349
            (WeakPointer*) GC_MALLOC_ATOMIC( sizeof( WeakPointer ) );
350
        Descriptor* desc = DESCRIPTOR( base );
351
 
352
        wp->pointer = t;
353
        desc->has_weak_pointers = 1;
354
        GC_general_register_disappearing_link( &wp->pointer, base );
355
        return wp;}}
356
 
357
 
358
static void* PointerWithLock( wp )
359
    WeakPointer* wp;
360
{
361
    if (wp == 0 || wp->pointer == 0) {
362
      return 0;}
363
    else {
364
        return (void*) wp->pointer;}}
365
 
366
 
367
void* _WeakPointer_Pointer( wp )
368
    WeakPointer* wp;
369
{
370
    return (void*) GC_call_with_alloc_lock( PointerWithLock, wp );}
371
 
372
 
373
typedef struct EqualClosure {
374
    WeakPointer* wp1;
375
    WeakPointer* wp2;
376
} EqualClosure;
377
 
378
 
379
static void* EqualWithLock( ec )
380
    EqualClosure* ec;
381
{
382
    if (ec->wp1 == 0 || ec->wp2 == 0) {
383
        return (void*) (ec->wp1 == ec->wp2);}
384
    else {
385
      return (void*) (ec->wp1->pointer == ec->wp2->pointer);}}
386
 
387
 
388
int _WeakPointer_Equal( wp1,  wp2 )
389
    WeakPointer* wp1;
390
    WeakPointer* wp2;
391
{
392
    EqualClosure ec;
393
 
394
    ec.wp1 = wp1;
395
    ec.wp2 = wp2;
396
    return (int) GC_call_with_alloc_lock( EqualWithLock, &ec );}
397
 
398
 
399
int _WeakPointer_Hash( wp )
400
    WeakPointer* wp;
401
{
402
    return (int) _WeakPointer_Pointer( wp );}
403
 
404
 
405
/**************************************************************************
406
 
407
Implementations of the template class CleanUp from WeakPointer.h
408
 
409
***************************************************************************/
410
 
411
typedef struct Closure {
412
    void (*c) PROTO(( void* d, void* t ));
413
    ptrdiff_t t_offset;
414
    void* d;
415
} Closure;
416
 
417
 
418
static void _CleanUp_CallClosure( obj, data )
419
    void* obj;
420
    void* data;
421
{
422
    Closure* closure = (Closure*) data;
423
    closure->c( closure->d, (char*) obj + closure->t_offset );}
424
 
425
 
426
void _CleanUp_Set( t, c, d )
427
    void* t;
428
    void (*c) PROTO(( void* d, void* t ));
429
    void* d;
430
{
431
    void* base = GC_base( t );
432
    Descriptor* desc = DESCRIPTOR( t );
433
 
434
    if (c == 0) {
435
        GC_REGISTER_FINALIZER_IGNORE_SELF( base, 0, 0, 0, 0 );
436
        desc->has_finalizer = 0;}
437
    else {
438
        Closure* closure = (Closure*) GC_MALLOC( sizeof( Closure ) );
439
        closure->c = c;
440
        closure->t_offset = (char*) t - (char*) base;
441
        closure->d = d;
442
        GC_REGISTER_FINALIZER_IGNORE_SELF( base, _CleanUp_CallClosure,
443
                                           closure, 0, 0 );
444
        desc->has_finalizer = 1;}}
445
 
446
 
447
void _CleanUp_Call( t )
448
    void* t;
449
{
450
      /* ? Aren't we supposed to deactivate weak pointers to t too?
451
         Why? */
452
    void* base = GC_base( t );
453
    void* d;
454
    GC_finalization_proc f;
455
 
456
    GC_REGISTER_FINALIZER( base, 0, 0, &f, &d );
457
    f( base, d );}
458
 
459
 
460
typedef struct QueueElem {
461
    void* o;
462
    GC_finalization_proc f;
463
    void* d;
464
    struct QueueElem* next;
465
} QueueElem;
466
 
467
 
468
void* _CleanUp_Queue_NewHead()
469
{
470
    return GC_MALLOC( sizeof( QueueElem ) );}
471
 
472
 
473
static void _CleanUp_Queue_Enqueue( obj, data )
474
    void* obj;
475
    void* data;
476
{
477
    QueueElem* q = (QueueElem*) data;
478
    QueueElem* head = q->next;
479
 
480
    q->o = obj;
481
    q->next = head->next;
482
    head->next = q;}
483
 
484
 
485
void _CleanUp_Queue_Set( h, t )
486
    void* h;
487
    void* t;
488
{
489
    QueueElem* head = (QueueElem*) h;
490
    void* base = GC_base( t );
491
    void* d;
492
    GC_finalization_proc f;
493
    QueueElem* q = (QueueElem*) GC_MALLOC( sizeof( QueueElem ) );
494
 
495
    GC_REGISTER_FINALIZER( base, _CleanUp_Queue_Enqueue, q, &f, &d );
496
    q->f = f;
497
    q->d = d;
498
    q->next = head;}
499
 
500
 
501
int _CleanUp_Queue_Call( h )
502
    void* h;
503
{
504
    QueueElem* head = (QueueElem*) h;
505
    QueueElem* q = head->next;
506
 
507
    if (q == 0) {
508
        return 0;}
509
    else {
510
        head->next = q->next;
511
        q->next = 0;
512
        if (q->f != 0) q->f( q->o, q->d );
513
        return 1;}}
514
 
515
 
516
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.