Make the reference count always odd to make it possible to distinguish it from a vtable

This commit is contained in:
Michal Moskal 2015-10-25 08:30:05 -07:00
parent 5df59c2f7e
commit 11c99d0b84
6 changed files with 59 additions and 45 deletions

View File

@ -5,6 +5,7 @@
struct StringData : RefCounted
{
uint16_t len;
char data[0];
};
@ -275,7 +276,7 @@ class ManagedString
*/
const char *toCharArray() const
{
if (ptr->refcnt == 0) panic(243);
ptr->isReadOnly(); // this performs sanity checks on refCount
return ptr->data;
}
@ -293,7 +294,7 @@ class ManagedString
*/
int16_t length() const
{
return ptr->size;
return ptr->len;
}
/**

View File

@ -6,7 +6,9 @@
struct ImageData : RefCounted
{
uint8_t data[0];
uint8_t width; // Width in pixels
uint8_t height; // Height in pixels
uint8_t data[0]; // 2D array representing the bitmap image
};
/**
@ -18,7 +20,6 @@ struct ImageData : RefCounted
class MicroBitImage
{
ImageData *ptr; // Pointer to payload data
// Width/height (in pixels) are in high/low byte of ptr->size
/**

View File

@ -11,24 +11,12 @@ struct RefCounted
{
public:
/**
* Number of outstanding references. Should never be zero (object should be deleted then).
* The high 15 bits hold the number of outstanding references. The lowest bit is always 1
* to make sure it doesn't look like vtable.
* Should never be even or one (object should be deleted then).
* When it's set to 0xffff, it means the object sits in flash and should not be counted.
*/
uint16_t refcnt;
/**
* For strings this is length. For images this is both width and length (8 bit each).
* A value of 0xffff indicates that this is in fact an instance of VirtualRefCounted
* and therefore when the reference count reaches zero, the virtual destructor
* should be called.
*/
union {
uint16_t size;
struct {
uint8_t width;
uint8_t height;
};
};
uint16_t refCount;
/** Increment reference count. */
void incr();
@ -36,6 +24,11 @@ public:
/** Decrement reference count. */
void decr();
/** Initializes for one outstanding reference. */
void init();
/** Checks if the object sits in flash memory. */
bool isReadOnly();
};
#endif

View File

@ -26,8 +26,8 @@ void ManagedString::initString(const char *str)
// We assume the string is sane, and null terminated.
int len = strlen(str);
ptr = (StringData *) malloc(4+len+1);
ptr->size = len;
ptr->refcnt = 1;
ptr->init();
ptr->len = len;
memcpy(ptr->data, str, len+1);
}
@ -96,8 +96,8 @@ ManagedString::ManagedString(const ManagedString &s1, const ManagedString &s2)
// Create a new buffer for holding the new string data.
ptr = (StringData*) malloc(4+len+1);
ptr->size = len;
ptr->refcnt = 1;
ptr->init();
ptr->len = len;
// Enter the data, and terminate the string.
memcpy(ptr->data, s1.toCharArray(), s1.length());
@ -132,9 +132,9 @@ ManagedString::ManagedString(const char *str, const int16_t length)
// Allocate a new buffer, and create a NULL terminated string.
ptr = (StringData*) malloc(4+length+1);
ptr->init();
// Store the length of the new string
ptr->size = length;
ptr->refcnt = 1;
ptr->len = length;
memcpy(ptr->data, str, length);
ptr->data[length] = 0;
}
@ -331,8 +331,6 @@ ManagedString ManagedString::substring(int16_t start, int16_t length)
*/
ManagedString ManagedString::operator+ (ManagedString& s)
{
//printf("add(%d,%d)\n", this->length(), s.length()); uBit.sleep(100);
// If the other string is empty, nothing to do!
if(s.length() == 0)
return *this;

View File

@ -218,9 +218,9 @@ void MicroBitImage::init(const int16_t x, const int16_t y, const uint8_t *bitmap
// Create a copy of the array
ptr = (ImageData*)malloc(4 + x * y);
ptr->init();
ptr->width = x;
ptr->height = y;
ptr->refcnt = 1;
// create a linear buffer to represent the image. We could use a jagged/2D array here, but experimentation
// showed this had a negative effect on memory management (heap fragmentation etc).
@ -283,7 +283,7 @@ bool MicroBitImage::operator== (const MicroBitImage& i)
if (ptr == i.ptr)
return true;
else
return (ptr->size == i.ptr->size && (memcmp(getBitmap(), i.ptr->data, getSize())==0));
return (ptr->width == i.ptr->width && ptr->height == i.ptr->height && (memcmp(getBitmap(), i.ptr->data, getSize())==0));
}

View File

@ -1,27 +1,48 @@
#include "mbed.h"
#include "MicroBit.h"
void RefCounted::init()
{
// Initialize to one reference (lowest bit set to 1)
refCount = 3;
}
static inline bool isReadOnlyInline(RefCounted *t)
{
uint32_t refCount = t->refCount;
if (refCount == 0xffff)
return true; // object in flash
// Do some sanity checking while we're here
if (refCount == 1)
uBit.panic(30); // object should have been deleted
if ((refCount & 1) == 0)
uBit.panic(31); // refCount doesn't look right
// Not read only
return false;
}
bool RefCounted::isReadOnly()
{
return isReadOnlyInline(this);
}
void RefCounted::incr()
{
if (refcnt == 0xffff)
return;
if (refcnt == 0)
uBit.panic(30);
refcnt++;
if (!isReadOnlyInline(this))
refCount += 2;
}
void RefCounted::decr()
{
if (refcnt == 0xffff)
if (isReadOnlyInline(this))
return;
if (refcnt == 0)
uBit.panic(31);
refcnt--;
if (refcnt == 0) {
// size of 0xffff indicates a class with a virtual destructor
if (size == 0xffff)
uBit.panic(32);
else
free(this);
refCount -= 2;
if (refCount == 2) {
free(this);
}
}