]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-layout.m
objc4-371.1.tar.gz
[apple/objc4.git] / runtime / objc-layout.m
1 /*
2 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdlib.h>
25 #include <assert.h>
26
27 #import "objc-private.h"
28
29 /**********************************************************************
30 * Object Layouts.
31 *
32 * Layouts are used by the garbage collector to identify references from
33 * the object to other objects.
34 *
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.
41 *
42 * Example;
43 *
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)
50 * end
51 *
52 **********************************************************************/
53
54
55 /**********************************************************************
56 * generate_layout_bytes
57 *
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.
61 *
62 **********************************************************************/
63 #define NIBBLE_MAX 0xf
64 static long generate_layout_bytes(long skip, long run, unsigned char *layout) {
65 // number of bytes added
66 long count = 0;
67
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;
72
73 // another byte added
74 count++;
75
76 // decrement skip by nibble maximum
77 skip -= NIBBLE_MAX;
78 }
79
80 // add remaining skip and run (modulo nibble size) if layout is not NULL
81 if (layout) *layout++ = (skip << 4) | (run % NIBBLE_MAX);
82
83 // another byte added
84 count++;
85
86
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;
91
92 // another byte added
93 count++;
94
95 // decrement run by nibble maximum
96 run -= NIBBLE_MAX;
97 }
98
99 // return number of bytes added
100 return count;
101 }
102
103
104 /**********************************************************************
105 * scan_bits_for_layout
106 *
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.
110 *
111 **********************************************************************/
112 static unsigned char *compress_layout(const uint8_t *bits, size_t bitmap_bits, BOOL weak)
113 {
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
118 BOOL all_set = YES;
119 BOOL none_set = YES;
120
121 unsigned char *layout = _calloc_internal(bitmap_bits + 1, 1);
122
123 // iterate through bits in bits array
124 long i;
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;
128
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);
133
134 // reset counts
135 skip = 0; run = 0;
136 }
137
138 // record the skip or run
139 if (bit) run++, none_set = NO;
140 else skip++, all_set = NO;
141
142 // track state of last bit
143 last_bit = bit;
144 }
145
146 // Record last skip and run, if any.
147 if (skip || run) count += generate_layout_bytes(skip, run, layout + count);
148
149 // insert terminating byte
150 layout[count] = '\0';
151 count++;
152
153 // return result
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
159 } else {
160 result = (unsigned char *)_strdup_internal((char *)layout);
161 }
162 _free_internal(layout);
163 return result;
164 }
165
166
167 static void set_bits(layout_bitmap bits, size_t which, size_t count)
168 {
169 // fixme optimize for byte/word at a time
170 size_t bit;
171 for (bit = which; bit < which + count && bit < bits.bitCount; bit++) {
172 bits.bits[bit/8] |= 1 << (bit % 8);
173 }
174 if (bit == bits.bitCount && bit < which + count) {
175 // couldn't fit full type in bitmap
176 _objc_fatal("layout bitmap too short");
177 }
178 }
179
180 static void clear_bits(layout_bitmap bits, size_t which, size_t count)
181 {
182 // fixme optimize for byte/word at a time
183 size_t bit;
184 for (bit = which; bit < which + count && bit < bits.bitCount; bit++) {
185 bits.bits[bit/8] &= ~(1 << (bit % 8));
186 }
187 if (bit == bits.bitCount && bit < which + count) {
188 // couldn't fit full type in bitmap
189 _objc_fatal("layout bitmap too short");
190 }
191 }
192
193 static void move_bits(layout_bitmap bits, size_t src, size_t dst,
194 size_t count)
195 {
196 // fixme optimize for byte/word at a time
197 // Copy backwards in case of overlap
198 assert(dst >= src);
199 while (count--) {
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);
204 } else {
205 bits.bits[dstbit/8] &= ~(1 << (dstbit % 8));
206 }
207 }
208 }
209
210 // emacs autoindent hack - it doesn't like the loop in set_bits/clear_bits
211 #if 0
212 } }
213 #endif
214
215
216 static void decompress_layout(const unsigned char *layout_string, layout_bitmap bits)
217 {
218 unsigned char c;
219 size_t bit = 0;
220 while ((c = *layout_string++)) {
221 unsigned char skip = (c & 0xf0) >> 4;
222 unsigned char scan = (c & 0x0f);
223 bit += skip;
224 set_bits(bits, bit, scan);
225 bit += scan;
226 }
227 }
228
229
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)
242 {
243 layout_bitmap result;
244 size_t words = instanceSize / sizeof(id);
245 size_t bitmap_bytes = (words+7)/8;
246
247 result.bits = _calloc_internal(bitmap_bytes, 1);
248 result.weak = weak;
249 result.bitCount = words;
250 result.bitsAllocated = bitmap_bytes * 8;
251 assert(bits->bitsAllocated % 8 == 0);
252
253 if (!layout_string) {
254 if (!weak) {
255 // NULL ivar layout means all-scanned
256 // (but only up to layoutStringSize instance size)
257 set_bits(result, 0, layoutStringInstanceSize/sizeof(id));
258 } else {
259 // NULL weak layout means none-weak.
260 }
261 } else {
262 decompress_layout(layout_string, result);
263 }
264
265 return result;
266 }
267
268 __private_extern__ void
269 layout_bitmap_free(layout_bitmap bits)
270 {
271 if (bits.bits) _free_internal(bits.bits);
272 }
273
274 __private_extern__ const unsigned char *
275 layout_string_create(layout_bitmap bits)
276 {
277 return compress_layout(bits.bits, bits.bitCount, bits.weak);
278 }
279
280
281 __private_extern__ void
282 layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset)
283 {
284 // fixme only handles id and array of id
285 size_t bit = offset / sizeof(id);
286
287 if (!type) return;
288 if (type[0] == '@') {
289 set_bits(bits, bit, 1);
290 } else if (type[0] == '[') {
291 char *t;
292 unsigned long count = strtoul(type+1, &t, 10);
293 if (t && t[0] == '@') {
294 set_bits(bits, bit, count);
295 }
296 } else if (strchr(type, '@')) {
297 _objc_inform("warning: failing to set GC layout for '%s'\n", type);
298 }
299 }
300
301
302
303 /***********************************************************************
304 * layout_bitmap_grow
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)
310 {
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);
317 }
318 assert(bits->bitsAllocated % 8 == 0);
319 }
320
321
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.
328 * newPos >= oldPos.
329 **********************************************************************/
330 __private_extern__ void
331 layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos)
332 {
333 if (oldPos >= newPos) _objc_fatal("layout bitmap sliding backwards");
334
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
340 }
341
342
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)
353 {
354 if (dst.bitCount < src.bitCount) _objc_fatal("layout bitmap too short");
355
356 BOOL changed = NO;
357 size_t oldSrcBitCount = oldSrcInstanceSize / sizeof(id);
358
359 // fixme optimize for byte/word at a time
360 size_t bit;
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))
365 : 0;
366 if (dstset != srcset) {
367 changed = YES;
368 if (srcset) {
369 dst.bits[bit/8] |= 1 << (bit % 8);
370 } else {
371 dst.bits[bit/8] &= ~(1 << (bit % 8));
372 }
373 }
374 }
375
376 return changed;
377 }
378
379
380 #if 0
381 // The code below may be useful when interpreting ivar types more precisely.
382
383 /**********************************************************************
384 * mark_offset_for_layout
385 *
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.
389 *
390 **********************************************************************/
391 static void mark_offset_for_layout(long offset, long bits_size, unsigned char *bits) {
392 // references are ignored if bits is NULL
393 if (bits) {
394 long slot = offset / sizeof(long);
395
396 // determine byte index using (offset / 8 bits per byte)
397 long i_byte = slot >> 3;
398
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);
403 } else {
404 // offset not within instance size
405 _objc_inform ("layout - offset exceeds instance size");
406 }
407 }
408 }
409
410 /**********************************************************************
411 * skip_ivar_type_name
412 *
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
415 * string.
416 *
417 **********************************************************************/
418 static char *skip_ivar_type_name(char *type) {
419 // current character
420 char ch;
421
422 // if there is an open quote
423 if (*type == '\"') {
424 // skip quote
425 type++;
426
427 // while no closing quote
428 while ((ch = *type) != '\"') {
429 // if end of string return end of string
430 if (!ch) return type;
431
432 // skip character
433 type++;
434 }
435
436 // skip closing quote
437 type++;
438 }
439
440 // return remaining string
441 return type;
442 }
443
444
445 /**********************************************************************
446 * skip_ivar_struct_name
447 *
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.
450 *
451 **********************************************************************/
452 static char *skip_ivar_struct_name(char *type) {
453 // get first character
454 char ch = *type;
455
456 if (ch == _C_UNDEF) {
457 // skip undefined name
458 type++;
459 } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_') {
460 // if alphabetic
461
462 // scan alphanumerics
463 do {
464 // next character
465 ch = *++type;
466 } while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' || (ch >= '0' && ch <= '9'));
467 } else {
468 // no struct name present
469 return type;
470 }
471
472 // skip equals sign
473 if (*type == '=') type++;
474
475 return type;
476 }
477
478
479 /**********************************************************************
480 * scan_basic_ivar_type
481 *
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
485 * string.
486 *
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
491 *is_reference = NO;
492
493 // get the first character (advancing string)
494 const char *full_type = type;
495 char ch = *type++;
496
497 // GCC 4 uses for const type*.
498 if (ch == _C_CONST) ch = *type++;
499
500 // act on first character
501 switch (ch) {
502 case _C_ID: {
503 // ID type
504
505 // skip over optional class name
506 type = skip_ivar_type_name(type);
507
508 // size and alignment of an id type
509 *size = sizeof(id);
510 *alignment = __alignof(id);
511
512 // is a reference type
513 *is_reference = YES;
514 break;
515 }
516 case _C_PTR: {
517 // C pointer type
518
519 // skip underlying type
520 long ignored_offset;
521 type = scan_ivar_type_for_layout(type, 0, 0, NULL, &ignored_offset);
522
523 // size and alignment of a generic pointer type
524 *size = sizeof(void *);
525 *alignment = __alignof(void *);
526
527 // is a reference type
528 *is_reference = YES;
529 break;
530 }
531 case _C_CHARPTR: {
532 // C string
533
534 // size and alignment of a char pointer type
535 *size = sizeof(char *);
536 *alignment = __alignof(char *);
537
538 // is a reference type
539 *is_reference = YES;
540 break;
541 }
542 case _C_CLASS:
543 case _C_SEL: {
544 // classes and selectors are ignored for now
545 *size = sizeof(void *);
546 *alignment = __alignof(void *);
547 break;
548 }
549 case _C_CHR:
550 case _C_UCHR: {
551 // char and unsigned char
552 *size = sizeof(char);
553 *alignment = __alignof(char);
554 break;
555 }
556 case _C_SHT:
557 case _C_USHT: {
558 // short and unsigned short
559 *size = sizeof(short);
560 *alignment = __alignof(short);
561 break;
562 }
563 case _C_ATOM:
564 case _C_INT:
565 case _C_UINT: {
566 // int and unsigned int
567 *size = sizeof(int);
568 *alignment = __alignof(int);
569 break;
570 }
571 case _C_LNG:
572 case _C_ULNG: {
573 // long and unsigned long
574 *size = sizeof(long);
575 *alignment = __alignof(long);
576 break;
577 }
578 case _C_LNG_LNG:
579 case _C_ULNG_LNG: {
580 // long long and unsigned long long
581 *size = sizeof(long long);
582 *alignment = __alignof(long long);
583 break;
584 }
585 case _C_VECTOR: {
586 // vector
587 *size = 16;
588 *alignment = 16;
589 break;
590 }
591 case _C_FLT: {
592 // float
593 *size = sizeof(float);
594 *alignment = __alignof(float);
595 break;
596 }
597 case _C_DBL: {
598 // double
599 *size = sizeof(double);
600 *alignment = __alignof(double);
601 break;
602 }
603 case _C_BFLD: {
604 // bit field
605
606 // get number of bits in bit field (advance type string)
607 long lng = strtol(type, &type, 10);
608
609 // while next type is a bit field
610 while (*type == _C_BFLD) {
611 // skip over _C_BFLD
612 type++;
613
614 // get next bit field length
615 long next_lng = strtol(type, &type, 10);
616
617 // if spans next word then align to next word
618 if ((lng & ~31) != ((lng + next_lng) & ~31)) lng = (lng + 31) & ~31;
619
620 // increment running length
621 lng += next_lng;
622
623 // skip over potential field name
624 type = skip_ivar_type_name(type);
625 }
626
627 // determine number of bytes bits represent
628 *size = (lng + 7) / 8;
629
630 // byte alignment
631 *alignment = __alignof(char);
632 break;
633 }
634 case _C_BOOL: {
635 // double
636 *size = sizeof(BOOL);
637 *alignment = __alignof(BOOL);
638 break;
639 }
640 case _C_VOID: {
641 // skip void types
642 *size = 0;
643 *alignment = __alignof(char);
644 break;
645 }
646 case _C_UNDEF: {
647 *size = 0;
648 *alignment = __alignof(char);
649 break;
650 }
651 default: {
652 // unhandled type
653 _objc_fatal("unrecognized character \'%c\' in ivar type: \"%s\"", ch, full_type);
654 }
655 }
656
657 return type;
658 }
659
660
661 /**********************************************************************
662 * scan_ivar_type_for_layout
663 *
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.
668 *
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
674
675 // get the first character
676 char ch = *type;
677
678 // GCC 4 uses for const type*.
679 if (ch == _C_CONST) ch = *++type;
680
681 // act on first character
682 switch (ch) {
683 case _C_ARY_B: {
684 // array type
685
686 // get the array length
687 long lng = strtol(type + 1, &type, 10);
688
689 // next type will be where to advance the type string once the array is processed
690 char *next_type = type;
691
692 // repeat the next type x lng
693 if (!lng) {
694 next_type = scan_ivar_type_for_layout(type, 0, 0, NULL, &offset);
695 } else {
696 while (lng--) {
697 // repeatedly scan the same type
698 next_type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &offset);
699 }
700 }
701
702 // advance the type now
703 type = next_type;
704
705 // after the end of the array
706 *next_offset = offset;
707
708 // advance over closing bracket
709 if (*type == _C_ARY_E) type++;
710 else _objc_inform("missing \'%c\' in ivar type.", _C_ARY_E);
711
712 break;
713 }
714 case _C_UNION_B: {
715 // union type
716
717 // skip over possible union name
718 type = skip_ivar_struct_name(type + 1);
719
720 // need to accumulate the maximum element offset
721 long max_offset = 0;
722
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);
727
728 // scan type
729 long union_offset;
730 type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &union_offset);
731
732 // adjust the maximum element offset
733 if (max_offset < union_offset) max_offset = union_offset;
734 }
735
736 // after the largest element
737 *next_offset = max_offset;
738
739 // advance over closing paren
740 if (ch == _C_UNION_E) {
741 type++;
742 } else {
743 _objc_inform("missing \'%c\' in ivar type", _C_UNION_E);
744 }
745
746 break;
747 }
748 case _C_STRUCT_B: {
749 // struct type
750
751 // skip over possible struct name
752 type = skip_ivar_struct_name(type + 1);
753
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);
758
759 // scan type
760 type = scan_ivar_type_for_layout(type, offset, bits_size, bits, &offset);
761 }
762
763 // after the end of the struct
764 *next_offset = offset;
765
766 // advance over closing brace
767 if (ch == _C_STRUCT_E) type++;
768 else _objc_inform("missing \'%c\' in ivar type", _C_STRUCT_E);
769
770 break;
771 }
772 default: {
773 // basic type
774
775 // scan type
776 type = scan_basic_ivar_type(type, &size, &alignment, &is_reference);
777
778 // create alignment mask
779 alignment--;
780
781 // align offset
782 offset = (offset + alignment) & ~alignment;
783
784 // if is a reference then mark in the bit map
785 if (is_reference) mark_offset_for_layout(offset, bits_size, bits);
786
787 // after the basic type
788 *next_offset = offset + size;
789 break;
790 }
791 }
792
793 // return remainder of type string
794 return type;
795 }
796
797 #endif