2 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 #import "objc-private.h"
29 /**********************************************************************
32 * Layouts are used by the garbage collector to identify references from
33 * the object to other objects.
35 * Layout information is in the form of a '\0' terminated byte string.
36 * Each byte contains a word skip count in the high nibble and a
37 * consecutive references count in the low nibble. Counts that exceed 15 are
38 * continued in the succeeding byte with a zero in the opposite nibble.
39 * Objects that should be scanned conservatively will have a NULL layout.
40 * Objects that have no references have a empty byte string.
44 * For a class with pointers at offsets 4,12, 16, 32-128
45 * the layout is { 0x11, 0x12, 0x3f, 0x0a, 0x00 } or
46 * skip 1 - 1 reference (4)
47 * skip 1 - 2 references (12, 16)
48 * skip 3 - 15 references (32-88)
49 * no skip - 10 references (92-128)
52 **********************************************************************/
55 /**********************************************************************
56 * generate_layout_bytes
58 * Generates the layout bytes representing the specified skip and run.
59 * If layout is NULL the can be used to determine the number of bytes added
60 * to the layout. Returns number of bytes added.
62 **********************************************************************/
63 #define NIBBLE_MAX 0xf
64 static long generate_layout_bytes(long skip, long run, unsigned char *layout) {
65 // number of bytes added
68 // if the skip is greater what can be put in a nibble
69 while (skip > NIBBLE_MAX) {
70 // add a skip with no run if layout is not NULL
71 if (layout) *layout++ = NIBBLE_MAX << 4;
76 // decrement skip by nibble maximum
80 // add remaining skip and run (modulo nibble size) if layout is not NULL
81 if (layout) *layout++ = (skip << 4) | (run % NIBBLE_MAX);
87 // if the run is greater what can be put in a nibble
88 while (run > NIBBLE_MAX) {
89 // add a run with no skip if layout is not NULL
90 if (layout) *layout++ = NIBBLE_MAX;
95 // decrement run by nibble maximum
99 // return number of bytes added
104 /**********************************************************************
105 * scan_bits_for_layout
107 * Generate the layout from the bit map. If layout is NULL then can be used to
108 * determine the size of the layout. Returns size of layout array in bytes
109 * including the '\0' terminator.
111 **********************************************************************/
112 static unsigned char *compress_layout(const uint8_t *bits, size_t bitmap_bits, BOOL weak)
114 long count = 0; // number of bytes generated
115 long skip = 0; // number of slots to skip to get to next references
116 long run = 0; // number of consecutive references
117 long last_bit = 0; // state of last bit encountered
121 unsigned char *layout = _calloc_internal(bitmap_bits + 1, 1);
123 // iterate through bits in bits array
125 for (i = 0; i < bitmap_bits; i++) {
126 // determine next bit, 0 = not a reference, 1 indicates a reference
127 long bit = (bits[i/8] >> (i % 8)) & 1;
129 // if not a reference and last bit was a reference then record skip and run
130 if (!bit && last_bit) {
131 // record skip and run
132 count += generate_layout_bytes(skip, run, layout + count);
138 // record the skip or run
139 if (bit) run++, none_set = NO;
140 else skip++, all_set = NO;
142 // track state of last bit
146 // Record last skip and run, if any.
147 if (skip || run) count += generate_layout_bytes(skip, run, layout + count);
149 // insert terminating byte
150 layout[count] = '\0';
154 unsigned char *result;
155 if (none_set && weak) {
156 result = NULL; // NULL weak layout means none-weak
157 } else if (all_set && !weak) {
158 result = NULL; // NULL ivar layout means all-scanned
160 result = (unsigned char *)_strdup_internal((char *)layout);
162 _free_internal(layout);
167 static void set_bits(layout_bitmap bits, size_t which, size_t count)
169 // fixme optimize for byte/word at a time
171 for (bit = which; bit < which + count && bit < bits.bitCount; bit++) {
172 bits.bits[bit/8] |= 1 << (bit % 8);
174 if (bit == bits.bitCount && bit < which + count) {
175 // couldn't fit full type in bitmap
176 _objc_fatal("layout bitmap too short");
180 static void clear_bits(layout_bitmap bits, size_t which, size_t count)
182 // fixme optimize for byte/word at a time
184 for (bit = which; bit < which + count && bit < bits.bitCount; bit++) {
185 bits.bits[bit/8] &= ~(1 << (bit % 8));
187 if (bit == bits.bitCount && bit < which + count) {
188 // couldn't fit full type in bitmap
189 _objc_fatal("layout bitmap too short");
193 static void move_bits(layout_bitmap bits, size_t src, size_t dst,
196 // fixme optimize for byte/word at a time
197 // Copy backwards in case of overlap
200 size_t srcbit = src + count;
201 size_t dstbit = dst + count;
202 if (bits.bits[srcbit/8] & (1 << (srcbit % 8))) {
203 bits.bits[dstbit/8] |= 1 << (dstbit % 8);
205 bits.bits[dstbit/8] &= ~(1 << (dstbit % 8));
210 // emacs autoindent hack - it doesn't like the loop in set_bits/clear_bits
216 static void decompress_layout(const unsigned char *layout_string, layout_bitmap bits)
220 while ((c = *layout_string++)) {
221 unsigned char skip = (c & 0xf0) >> 4;
222 unsigned char scan = (c & 0x0f);
224 set_bits(bits, bit, scan);
230 /***********************************************************************
231 * layout_bitmap_create
232 * Allocate a layout bitmap.
233 * The new bitmap spans the given instance size bytes.
234 * The start of the bitmap is filled from the given layout string (which
235 * spans an instance size of layoutStringSize); the rest is zero-filled.
236 * The returned bitmap must be freed with layout_bitmap_free().
237 **********************************************************************/
238 __private_extern__ layout_bitmap
239 layout_bitmap_create(const unsigned char *layout_string,
240 size_t layoutStringInstanceSize,
241 size_t instanceSize, BOOL weak)
243 layout_bitmap result;
244 size_t words = instanceSize / sizeof(id);
245 size_t bitmap_bytes = (words+7)/8;
247 result.bits = _calloc_internal(bitmap_bytes, 1);
249 result.bitCount = words;
250 result.bitsAllocated = bitmap_bytes * 8;
251 assert(bits->bitsAllocated % 8 == 0);
253 if (!layout_string) {
255 // NULL ivar layout means all-scanned
256 // (but only up to layoutStringSize instance size)
257 set_bits(result, 0, layoutStringInstanceSize/sizeof(id));
259 // NULL weak layout means none-weak.
262 decompress_layout(layout_string, result);
268 __private_extern__ void
269 layout_bitmap_free(layout_bitmap bits)
271 if (bits.bits) _free_internal(bits.bits);
274 __private_extern__ const unsigned char *
275 layout_string_create(layout_bitmap bits)
277 return compress_layout(bits.bits, bits.bitCount, bits.weak);
281 __private_extern__ void
282 layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset)
284 // fixme only handles id and array of id
285 size_t bit = offset / sizeof(id);
288 if (type[0] == '@') {
289 set_bits(bits, bit, 1);
290 } else if (type[0] == '[') {
292 unsigned long count = strtoul(type+1, &t, 10);
293 if (t && t[0] == '@') {
294 set_bits(bits, bit, count);
296 } else if (strchr(type, '@')) {
297 _objc_inform("warning: failing to set GC layout for '%s'\n", type);
303 /***********************************************************************
305 * Expand a layout bitmap to span newCount bits.
306 * The new bits are undefined.
307 **********************************************************************/
308 __private_extern__ void
309 layout_bitmap_grow(layout_bitmap *bits, size_t newCount)
311 if (bits->bitCount >= newCount) return;
312 size_t addition = newCount - bits->bitCount;
313 bits->bitCount = newCount;
314 if (bits->bitCount > bits->bitsAllocated) {
315 bits->bitsAllocated += bits->bitsAllocated + (addition+7)/8;
316 bits->bits = _realloc_internal(bits->bits, bits->bitsAllocated);
318 assert(bits->bitsAllocated % 8 == 0);
322 /***********************************************************************
323 * layout_bitmap_slide
324 * Slide the end of a layout bitmap farther from the start.
325 * Slides bits [oldPos, bits.bitCount) to [newPos, bits.bitCount+newPos-oldPos)
326 * Bits [oldPos, newPos) are zero-filled.
327 * The bitmap is expanded and bitCount updated if necessary.
329 **********************************************************************/
330 __private_extern__ void
331 layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos)
333 if (oldPos >= newPos) _objc_fatal("layout bitmap sliding backwards");
335 size_t shift = newPos - oldPos;
336 size_t count = bits->bitCount - oldPos;
337 layout_bitmap_grow(bits, bits->bitCount + shift);
338 move_bits(*bits, oldPos, newPos, count); // slide
339 clear_bits(*bits, oldPos, shift); // zero-fill
343 /***********************************************************************
344 * layout_bitmap_splat
345 * Pastes the contents of bitmap src to the start of bitmap dst.
346 * dst bits between the end of src and oldSrcInstanceSize are zeroed.
347 * dst must be at least as long as src.
348 * Returns YES if any of dst's bits were changed.
349 **********************************************************************/
350 __private_extern__ BOOL
351 layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
352 size_t oldSrcInstanceSize)
354 if (dst.bitCount < src.bitCount) _objc_fatal("layout bitmap too short");
357 size_t oldSrcBitCount = oldSrcInstanceSize / sizeof(id);
359 // fixme optimize for byte/word at a time
361 for (bit = 0; bit < oldSrcBitCount; bit++) {
362 int dstset = dst.bits[bit/8] & (1 << (bit % 8));
363 int srcset = (bit < src.bitCount)
364 ? src.bits[bit/8] & (1 << (bit % 8))
366 if (dstset != srcset) {
369 dst.bits[bit/8] |= 1 << (bit % 8);
371 dst.bits[bit/8] &= ~(1 << (bit % 8));
381 // The code below may be useful when interpreting ivar types more precisely.
383 /**********************************************************************
384 * mark_offset_for_layout
386 * Marks the appropriate bit in the bits array cooresponding to a the
387 * offset of a reference. If we are scanning a nested pointer structure
388 * then the bits array will be NULL then this function does nothing.
390 **********************************************************************/
391 static void mark_offset_for_layout(long offset, long bits_size, unsigned char *bits) {
392 // references are ignored if bits is NULL
394 long slot = offset / sizeof(long);
396 // determine byte index using (offset / 8 bits per byte)
397 long i_byte = slot >> 3;
399 // if the byte index is valid
400 if (i_byte < bits_size) {
401 // set the (offset / 8 bits per byte)th bit
402 bits[i_byte] |= 1 << (slot & 7);
404 // offset not within instance size
405 _objc_inform ("layout - offset exceeds instance size");
410 /**********************************************************************
411 * skip_ivar_type_name
413 * Skip over the name of a field/class in an ivar type string. Names
414 * are in the form of a double-quoted string. Returns the remaining
417 **********************************************************************/
418 static char *skip_ivar_type_name(char *type) {
422 // if there is an open quote
427 // while no closing quote
428 while ((ch = *type) != '\"') {
429 // if end of string return end of string
430 if (!ch) return type;
436 // skip closing quote
440 // return remaining string
445 /**********************************************************************
446 * skip_ivar_struct_name
448 * Skip over the name of a struct in an ivar type string. Names
449 * may be followed by an equals sign. Returns the remaining string.
451 **********************************************************************/
452 static char *skip_ivar_struct_name(char *type) {
453 // get first character
456 if (ch == _C_UNDEF) {
457 // skip undefined name
459 } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_') {
462 // scan alphanumerics
466 } while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' || (ch >= '0' && ch <= '9'));
468 // no struct name present
473 if (*type == '=') type++;
479 /**********************************************************************
480 * scan_basic_ivar_type
482 * Determines the size and alignment of a basic ivar type. If the basic
483 * type is a possible reference to another garbage collected type the
484 * is_reference is set to true (false otherwise.) Returns the remaining
487 **********************************************************************/
488 static char *scan_ivar_type_for_layout(char *type, long offset, long bits_size, unsigned char *bits, long *next_offset);
489 static char *scan_basic_ivar_type(char *type, long *size, long *alignment, BOOL *is_reference) {
490 // assume it is a non-reference type
493 // get the first character (advancing string)
494 const char *full_type = type;
497 // GCC 4 uses for const type*.
498 if (ch == _C_CONST) ch = *type++;
500 // act on first character
505 // skip over optional class name
506 type = skip_ivar_type_name(type);
508 // size and alignment of an id type
510 *alignment = __alignof(id);
512 // is a reference type
519 // skip underlying type
521 type = scan_ivar_type_for_layout(type, 0, 0, NULL, &ignored_offset);
523 // size and alignment of a generic pointer type
524 *size = sizeof(void *);
525 *alignment = __alignof(void *);
527 // is a reference type
534 // size and alignment of a char pointer type
535 *size = sizeof(char *);
536 *alignment = __alignof(char *);
538 // is a reference type
544 // classes and selectors are ignored for now
545 *size = sizeof(void *);
546 *alignment = __alignof(void *);
551 // char and unsigned char
552 *size = sizeof(char);
553 *alignment = __alignof(char);
558 // short and unsigned short
559 *size = sizeof(short);
560 *alignment = __alignof(short);
566 // int and unsigned int
568 *alignment = __alignof(int);
573 // long and unsigned long
574 *size = sizeof(long);
575 *alignment = __alignof(long);
580 // long long and unsigned long long
581 *size = sizeof(long long);
582 *alignment = __alignof(long long);
593 *size = sizeof(float);
594 *alignment = __alignof(float);
599 *size = sizeof(double);
600 *alignment = __alignof(double);
606 // get number of bits in bit field (advance type string)
607 long lng = strtol(type, &type, 10);
609 // while next type is a bit field
610 while (*type == _C_BFLD) {
614 // get next bit field length
615 long next_lng = strtol(type, &type, 10);
617 // if spans next word then align to next word
618 if ((lng & ~31) != ((lng + next_lng) & ~31)) lng = (lng + 31) & ~31;
620 // increment running length
623 // skip over potential field name
624 type = skip_ivar_type_name(type);
627 // determine number of bytes bits represent
628 *size = (lng + 7) / 8;
631 *alignment = __alignof(char);
636 *size = sizeof(BOOL);
637 *alignment = __alignof(BOOL);
643 *alignment = __alignof(char);
648 *alignment = __alignof(char);
653 _objc_fatal("unrecognized character \'%c\' in ivar type: \"%s\"", ch, full_type);
661 /**********************************************************************
662 * scan_ivar_type_for_layout
664 * Scan an ivar type string looking for references. The offset indicates
665 * where the ivar begins. bits is a byte array of size bits_size used to
666 * contain the references bit map. next_offset is the offset beyond the
667 * ivar. Returns the remaining string.
669 **********************************************************************/
670 static char *scan_ivar_type_for_layout(char *type, long offset, long bits_size, unsigned char *bits, long *next_offset) {
671 long size; // size of a basic type
672 long alignment; // alignment of the basic type
673 BOOL is_reference; // true if the type indicates a reference to a garbage collected object
675 // get the first character
678 // GCC 4 uses for const type*.
679 if (ch == _C_CONST) ch = *++type;
681 // act on first character
686 // get the array length
687 long lng = strtol(type + 1, &type, 10);
689 // next type will be where to advance the type string once the array is processed
690 char *next_type = type;
692 // repeat the next type x lng
694 next_type = scan_ivar_type_for_layout(type, 0, 0, NULL, &offset);
697 // repeatedly scan the same type
698 next_type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &offset);
702 // advance the type now
705 // after the end of the array
706 *next_offset = offset;
708 // advance over closing bracket
709 if (*type == _C_ARY_E) type++;
710 else _objc_inform("missing \'%c\' in ivar type.", _C_ARY_E);
717 // skip over possible union name
718 type = skip_ivar_struct_name(type + 1);
720 // need to accumulate the maximum element offset
723 // while not closing paren
724 while ((ch = *type) && ch != _C_UNION_E) {
725 // skip over potential field name
726 type = skip_ivar_type_name(type);
730 type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &union_offset);
732 // adjust the maximum element offset
733 if (max_offset < union_offset) max_offset = union_offset;
736 // after the largest element
737 *next_offset = max_offset;
739 // advance over closing paren
740 if (ch == _C_UNION_E) {
743 _objc_inform("missing \'%c\' in ivar type", _C_UNION_E);
751 // skip over possible struct name
752 type = skip_ivar_struct_name(type + 1);
754 // while not closing brace
755 while ((ch = *type) && ch != _C_STRUCT_E) {
756 // skip over potential field name
757 type = skip_ivar_type_name(type);
760 type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &offset);
763 // after the end of the struct
764 *next_offset = offset;
766 // advance over closing brace
767 if (ch == _C_STRUCT_E) type++;
768 else _objc_inform("missing \'%c\' in ivar type", _C_STRUCT_E);
776 type = scan_basic_ivar_type(type, &size, &alignment, &is_reference);
778 // create alignment mask
782 offset = (offset + alignment) & ~alignment;
784 // if is a reference then mark in the bit map
785 if (is_reference) mark_offset_for_layout(offset, bits_size, bits);
787 // after the basic type
788 *next_offset = offset + size;
793 // return remainder of type string