aboutsummaryrefslogtreecommitdiffstats
path: root/gc/obj_map.c
blob: 82ebf311983c07307c76fdf866a0c57730dbbfb1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* 
 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
 * Copyright (c) 1991, 1992 by Xerox Corporation.  All rights reserved.
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose,  provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */
/* Boehm, October 9, 1995 1:09 pm PDT */
  
/* Routines for maintaining maps describing heap block
 * layouts for various object sizes.  Allows fast pointer validity checks
 * and fast location of object start locations on machines (such as SPARC)
 * with slow division.
 */
 
# include "gc_priv.h"

char * GC_invalid_map = 0;

/* Invalidate the object map associated with a block.	Free blocks	*/
/* are identified by invalid maps.					*/
void GC_invalidate_map(hhdr)
hdr *hhdr;
{
    register int displ;
    
    if (GC_invalid_map == 0) {
        GC_invalid_map = GC_scratch_alloc(MAP_SIZE);
        if (GC_invalid_map == 0) {
            GC_err_printf0(
            	"Cant initialize GC_invalid_map: insufficient memory\n");
            EXIT();
        }
        for (displ = 0; displ < HBLKSIZE; displ++) {
            MAP_ENTRY(GC_invalid_map, displ) = OBJ_INVALID;
        }
    }
    hhdr -> hb_map = GC_invalid_map;
}

/* Consider pointers that are offset bytes displaced from the beginning */
/* of an object to be valid.                                            */

# if defined(__STDC__) || defined(__cplusplus)
    void GC_register_displacement(GC_word offset)
# else
    void GC_register_displacement(offset) 
    GC_word offset;
# endif
{
# ifndef ALL_INTERIOR_POINTERS
    DCL_LOCK_STATE;
    
    DISABLE_SIGNALS();
    LOCK();
    GC_register_displacement_inner(offset);
    UNLOCK();
    ENABLE_SIGNALS();
# endif
}

void GC_register_displacement_inner(offset) 
word offset;
{
# ifndef ALL_INTERIOR_POINTERS
    register unsigned i;
    
    if (offset > MAX_OFFSET) {
        ABORT("Bad argument to GC_register_displacement");
    }
    if (!GC_valid_offsets[offset]) {
      GC_valid_offsets[offset] = TRUE;
      GC_modws_valid_offsets[offset % sizeof(word)] = TRUE;
      for (i = 0; i <= MAXOBJSZ; i++) {
          if (GC_obj_map[i] != 0) {
             if (i == 0) {
               GC_obj_map[i][offset + HDR_BYTES] = (char)BYTES_TO_WORDS(offset);
             } else {
               register unsigned j;
               register unsigned lb = WORDS_TO_BYTES(i);
               
               if (offset < lb) {
                 for (j = offset + HDR_BYTES; j < HBLKSIZE; j += lb) {
                   GC_obj_map[i][j] = (char)BYTES_TO_WORDS(offset);
                 }
               }
             }
          }
      }
    }
# endif
}


/* Add a heap block map for objects of size sz to obj_map.	*/
/* Return FALSE on failure.					*/
GC_bool GC_add_map_entry(sz)
word sz;
{
    register unsigned obj_start;
    register unsigned displ;
    register char * new_map;
    
    if (sz > MAXOBJSZ) sz = 0;
    if (GC_obj_map[sz] != 0) {
        return(TRUE);
    }
    new_map = GC_scratch_alloc(MAP_SIZE);
    if (new_map == 0) return(FALSE);
#   ifdef PRINTSTATS
        GC_printf1("Adding block map for size %lu\n", (unsigned long)sz);
#   endif
    for (displ = 0; displ < HBLKSIZE; displ++) {
        MAP_ENTRY(new_map,displ) = OBJ_INVALID;
    }
    if (sz == 0) {
        for(displ = 0; displ <= MAX_OFFSET; displ++) {
            if (OFFSET_VALID(displ)) {
                MAP_ENTRY(new_map,displ+HDR_BYTES) = BYTES_TO_WORDS(displ);
            }
        }
    } else {
        for (obj_start = HDR_BYTES;
             obj_start + WORDS_TO_BYTES(sz) <= HBLKSIZE;
             obj_start += WORDS_TO_BYTES(sz)) {
             for (displ = 0; displ < WORDS_TO_BYTES(sz); displ++) {
                 if (OFFSET_VALID(displ)) {
                     MAP_ENTRY(new_map, obj_start + displ) =
                     				BYTES_TO_WORDS(displ);
                 }
             }
        }
    }
    GC_obj_map[sz] = new_map;
    return(TRUE);
}