Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ endif ()
set(TESTS
alias.m
alignTest.m
bitfield.m
AllocatePair.m
AssociatedObject.m
AssociatedObject2.m
Expand Down
15 changes: 12 additions & 3 deletions Test/IVarSuperclassOverlap.m
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,18 @@ int main(int argc, char *argv[])
assert(ivar_getOffset(c3) == baseSmallOffset + 4);
assert(ivar_getOffset(b1) == baseSmallOffset + 2);
assert(ivar_getOffset(b2) == baseSmallOffset + 2);
assert(ivar_getOffset(b3) == baseSmallOffset + 3);
assert(ivar_getOffset(b4) == baseSmallOffset + 3);
assert(ivar_getOffset(notBitfield) == baseSmallOffset + 4);
// These could be tighter, but the way that clang currently emits ivars for
// bitfields is a bit odd. Unfortunately, it sometimes adds a small
// displacement so that it can load individual words, but the metadata
// doesn't tell us anything about them. Fixing this would require using an
// extra metadata flag or similar to indicate that the size of the ivar is
// not the storage size.
assert((ivar_getOffset(b3) == baseSmallOffset + 3) ||
(ivar_getOffset(b3) == baseSmallOffset + 4));
assert((ivar_getOffset(b4) == baseSmallOffset + 3) ||
(ivar_getOffset(b4) == baseSmallOffset + 4));
assert((ivar_getOffset(notBitfield) == baseSmallOffset + 4) ||
(ivar_getOffset(notBitfield) == baseSmallOffset + 6));
#endif


Expand Down
57 changes: 57 additions & 0 deletions Test/bitfield.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include "stdio.h"
#include "Test.h"
#include "objc/runtime.h"
#include "objc/encoding.h"

@interface Bitfield : Test
{
unsigned short first;
unsigned isShip: 1,
isStation: 1;
unsigned y;
}

@end
@implementation Bitfield
- (BOOL)isShip { return isShip; }
- (BOOL)isStation { return isStation; }
- (void)setShip: (BOOL)aValue
{
isShip = aValue;
}
- (void)setStation: (BOOL)aValue
{
isStation = aValue;
}
- (void)setY: (int)anInt
{
y = anInt;
}
@end

static size_t offset(const char *ivar)
{
return ivar_getOffset(class_getInstanceVariable([Bitfield class], ivar));
}

static size_t size(const char *ivar)
{
return objc_sizeof_type(ivar_getTypeEncoding(class_getInstanceVariable([Bitfield class], ivar)));
}

int main(void)
{
Bitfield *bf = [Bitfield new];
assert(![bf isShip]);
assert(![bf isStation]);
[bf setShip: YES];
assert([bf isShip]);
assert(![bf isStation]);
[bf setStation: YES];
[bf setY: 0];
assert([bf isShip]);
assert([bf isStation]);
assert(offset("isShip") >= offset("first") + size("first"));
assert(offset("isShip") == offset("isStation"));
assert(offset("y") >= offset("isStation") + size("isStation"));
}
8 changes: 4 additions & 4 deletions ivar.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,25 @@ PRIVATE void objc_compute_ivar_offsets(Class class)
// that contains them. If we are in a bitfield, then we need
// to make sure that we don't add any displacement from the
// previous value.
if (*ivar->offset < last_offset + last_size)
if ((i != 0) && (*ivar->offset == last_offset))
{
*ivar->offset = last_computed_offset + (*ivar->offset - last_offset);
ivar_size = 0;
*ivar->offset = last_computed_offset;
continue;
}
last_offset = *ivar->offset;
*ivar->offset = next_ivar;
last_computed_offset = *ivar->offset;
next_ivar += ivar_size;
last_size = ivar->size;
size_t align = ivarGetAlign(ivar);
// If the alignment is insufficient, round it up.
if ((*ivar->offset + refcount_size) % align != 0)
{
long padding = align - ((*ivar->offset + refcount_size) % align);
*ivar->offset += padding;
class->instance_size += padding;
next_ivar += padding;
}
last_computed_offset = *ivar->offset;
assert((*ivar->offset + sizeof(uintptr_t)) % ivarGetAlign(ivar) == 0);
class->instance_size += ivar_size;
}
Expand Down