mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
Attempt to link in ObjC2 compatibility code if we have an older runtime.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@29670 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
7cc69dfaae
commit
073595b9e9
11 changed files with 1246 additions and 863 deletions
|
@ -23,8 +23,8 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#import "objc/blocks_runtime.h"
|
||||
#import "objc/runtime.h"
|
||||
#import "blocks_runtime.h"
|
||||
#import "runtime.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -38,47 +38,47 @@
|
|||
|
||||
// Descriptor attributes
|
||||
enum {
|
||||
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
|
||||
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
|
||||
BLOCK_IS_GLOBAL = (1 << 28),
|
||||
BLOCK_HAS_DESCRIPTOR = (1 << 29), // interim until complete world build is accomplished
|
||||
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
|
||||
BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
|
||||
BLOCK_IS_GLOBAL = (1 << 28),
|
||||
BLOCK_HAS_DESCRIPTOR = (1 << 29), // interim until complete world build is accomplished
|
||||
};
|
||||
|
||||
// _Block_object_assign() and _Block_object_dispose() flag helpers.
|
||||
enum {
|
||||
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
|
||||
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
|
||||
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
|
||||
|
||||
BLOCK_FIELD_IS_WEAK = 16, // declared __weak
|
||||
|
||||
BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
|
||||
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
|
||||
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
|
||||
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
|
||||
|
||||
BLOCK_FIELD_IS_WEAK = 16, // declared __weak
|
||||
|
||||
BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
|
||||
};
|
||||
|
||||
// Helper structure
|
||||
struct psy_block_literal {
|
||||
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(void *, ...);
|
||||
struct {
|
||||
unsigned long int reserved; // NULL
|
||||
unsigned long int size; // sizeof(struct Block_literal_1)
|
||||
// optional helper functions
|
||||
void (*copy_helper)(void *dst, void *src);
|
||||
void (*dispose_helper)(void *src);
|
||||
} *descriptor;
|
||||
const char *types;
|
||||
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(void *, ...);
|
||||
struct {
|
||||
unsigned long int reserved; // NULL
|
||||
unsigned long int size; // sizeof(struct Block_literal_1)
|
||||
// optional helper functions
|
||||
void (*copy_helper)(void *dst, void *src);
|
||||
void (*dispose_helper)(void *src);
|
||||
} *descriptor;
|
||||
const char *types;
|
||||
};
|
||||
|
||||
// Helper structure
|
||||
struct psy_block_byref_obj {
|
||||
void *isa; // uninitialized
|
||||
struct psy_block_byref_obj *forwarding;
|
||||
int flags; //refcount;
|
||||
int size;
|
||||
void (*byref_keep)(struct psy_block_byref_obj *dst, struct psy_block_byref_obj *src);
|
||||
void (*byref_dispose)(struct psy_block_byref_obj *);
|
||||
void *isa; // uninitialized
|
||||
struct psy_block_byref_obj *forwarding;
|
||||
int flags; //refcount;
|
||||
int size;
|
||||
void (*byref_keep)(struct psy_block_byref_obj *dst, struct psy_block_byref_obj *src);
|
||||
void (*byref_dispose)(struct psy_block_byref_obj *);
|
||||
};
|
||||
|
||||
/* Certain field types require runtime assistance when being copied to the
|
||||
|
@ -88,53 +88,58 @@ struct psy_block_byref_obj {
|
|||
* the other choices which are mutually exclusive. Only in a Block copy helper
|
||||
* will one see BLOCK_FIELD_IS_BYREF.
|
||||
*/
|
||||
void _Block_object_assign(void *destAddr, void *object, const int flags)
|
||||
void
|
||||
_Block_object_assign(void *destAddr, void *object, const int flags)
|
||||
{
|
||||
//printf("Copying %x to %x with flags %x\n", object, destAddr, flags);
|
||||
// FIXME: Needs to be implemented
|
||||
if(flags & BLOCK_FIELD_IS_WEAK)
|
||||
//printf("Copying %x to %x with flags %x\n", object, destAddr, flags);
|
||||
// FIXME: Needs to be implemented
|
||||
if (flags & BLOCK_FIELD_IS_WEAK)
|
||||
{
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if(flags & BLOCK_FIELD_IS_BYREF)
|
||||
if (flags & BLOCK_FIELD_IS_BYREF)
|
||||
{
|
||||
struct psy_block_byref_obj *src = object;
|
||||
struct psy_block_byref_obj **dst = destAddr;
|
||||
struct psy_block_byref_obj *src = object;
|
||||
struct psy_block_byref_obj **dst = destAddr;
|
||||
|
||||
/* I followed Apple's specs saying byref's "flags" field should
|
||||
* represent the refcount but it still contains real flag, so this
|
||||
* is a little hack...
|
||||
*/
|
||||
if((src->flags & ~BLOCK_HAS_COPY_DISPOSE) == 0)
|
||||
/* I followed Apple's specs saying byref's "flags" field should
|
||||
* represent the refcount but it still contains real flag, so this
|
||||
* is a little hack...
|
||||
*/
|
||||
if ((src->flags & ~BLOCK_HAS_COPY_DISPOSE) == 0)
|
||||
{
|
||||
*dst = malloc(src->size);
|
||||
memcpy(*dst, src, src->size);
|
||||
if (src->forwarding == src)
|
||||
{
|
||||
(*dst)->forwarding = *dst;
|
||||
}
|
||||
if(src->size >= sizeof(struct psy_block_byref_obj))
|
||||
{
|
||||
src->byref_keep(*dst, src);
|
||||
}
|
||||
*dst = malloc(src->size);
|
||||
memcpy(*dst, src, src->size);
|
||||
if (src->forwarding == src)
|
||||
{
|
||||
(*dst)->forwarding = *dst;
|
||||
}
|
||||
if (src->size >= sizeof(struct psy_block_byref_obj))
|
||||
{
|
||||
src->byref_keep(*dst, src);
|
||||
}
|
||||
}
|
||||
else *dst = src;
|
||||
else
|
||||
{
|
||||
*dst = src;
|
||||
}
|
||||
|
||||
(*dst)->flags++;
|
||||
(*dst)->flags++;
|
||||
}
|
||||
else if((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK)
|
||||
else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK)
|
||||
{
|
||||
struct psy_block_literal *src = object;
|
||||
struct psy_block_literal **dst = destAddr;
|
||||
struct psy_block_literal *src = object;
|
||||
struct psy_block_literal **dst = destAddr;
|
||||
|
||||
*dst = Block_copy(src);
|
||||
*dst = Block_copy(src);
|
||||
}
|
||||
else if((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT)
|
||||
else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT)
|
||||
{
|
||||
id src = object;
|
||||
id *dst = destAddr;
|
||||
*dst = [src retain];
|
||||
id src = object;
|
||||
id *dst = destAddr;
|
||||
|
||||
*dst = [src retain];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,103 +150,113 @@ void _Block_object_assign(void *destAddr, void *object, const int flags)
|
|||
* The same flags used in the copy helper should be used for each call
|
||||
* generated to this function:
|
||||
*/
|
||||
void _Block_object_dispose(void *object, const int flags)
|
||||
void
|
||||
_Block_object_dispose(void *object, const int flags)
|
||||
{
|
||||
// FIXME: Needs to be implemented
|
||||
if(flags & BLOCK_FIELD_IS_WEAK)
|
||||
// FIXME: Needs to be implemented
|
||||
if (flags & BLOCK_FIELD_IS_WEAK)
|
||||
{
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if(flags & BLOCK_FIELD_IS_BYREF)
|
||||
if (flags & BLOCK_FIELD_IS_BYREF)
|
||||
{
|
||||
struct psy_block_byref_obj *src = object;
|
||||
|
||||
src->flags--;
|
||||
if((src->flags & ~BLOCK_HAS_COPY_DISPOSE) == 0)
|
||||
struct psy_block_byref_obj *src = object;
|
||||
|
||||
src->flags--;
|
||||
if ((src->flags & ~BLOCK_HAS_COPY_DISPOSE) == 0)
|
||||
{
|
||||
if(src->size >= sizeof(struct psy_block_byref_obj))
|
||||
src->byref_dispose(src);
|
||||
if (src->size >= sizeof(struct psy_block_byref_obj))
|
||||
src->byref_dispose(src);
|
||||
|
||||
free(src);
|
||||
free(src);
|
||||
}
|
||||
}
|
||||
else if((flags & ~BLOCK_BYREF_CALLER) == BLOCK_FIELD_IS_BLOCK)
|
||||
else if ((flags & ~BLOCK_BYREF_CALLER) == BLOCK_FIELD_IS_BLOCK)
|
||||
{
|
||||
struct psy_block_literal *src = object;
|
||||
Block_release(src);
|
||||
struct psy_block_literal *src = object;
|
||||
Block_release(src);
|
||||
}
|
||||
else if((flags & ~BLOCK_BYREF_CALLER) == BLOCK_FIELD_IS_OBJECT)
|
||||
else if ((flags & ~BLOCK_BYREF_CALLER) == BLOCK_FIELD_IS_OBJECT)
|
||||
{
|
||||
id src = object;
|
||||
[src release];
|
||||
id src = object;
|
||||
[src release];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct StackBlockClass {
|
||||
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(void *, ...);
|
||||
struct {
|
||||
unsigned long int reserved; // NULL
|
||||
unsigned long int size; // sizeof(struct Block_literal_1)
|
||||
// optional helper functions
|
||||
void (*copy_helper)(void *dst, void *src);
|
||||
void (*dispose_helper)(void *src);
|
||||
} *descriptor;
|
||||
const char *types;
|
||||
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
|
||||
int flags;
|
||||
int reserved;
|
||||
void (*invoke)(void *, ...);
|
||||
struct {
|
||||
unsigned long int reserved; // NULL
|
||||
unsigned long int size; // sizeof(struct Block_literal_1)
|
||||
// optional helper functions
|
||||
void (*copy_helper)(void *dst, void *src);
|
||||
void (*dispose_helper)(void *src);
|
||||
} *descriptor;
|
||||
const char *types;
|
||||
};
|
||||
|
||||
|
||||
// Copy a block to the heap if it's still on the stack or increments its retain count.
|
||||
void *_Block_copy(void *src)
|
||||
/* Copy a block to the heap if it's still on the stack or
|
||||
* increments its retain count.
|
||||
*/
|
||||
void *
|
||||
_Block_copy(void *src)
|
||||
{
|
||||
struct StackBlockClass *self = src;
|
||||
struct StackBlockClass *ret = self;
|
||||
struct StackBlockClass *self = src;
|
||||
struct StackBlockClass *ret = self;
|
||||
|
||||
extern void _NSConcreteStackBlock __attribute__((weak));
|
||||
extern void _NSConcreteStackBlock __attribute__((weak));
|
||||
|
||||
// If the block is Global, there's no need to copy it on the heap.
|
||||
if(self->isa == &_NSConcreteStackBlock && self->flags & BLOCK_HAS_DESCRIPTOR)
|
||||
// If the block is Global, there's no need to copy it on the heap.
|
||||
if (self->isa == &_NSConcreteStackBlock
|
||||
&& self->flags & BLOCK_HAS_DESCRIPTOR)
|
||||
{
|
||||
if(self->reserved == 0)
|
||||
if (self->reserved == 0)
|
||||
{
|
||||
ret = malloc(self->descriptor->size);
|
||||
memcpy(ret, self, self->descriptor->size);
|
||||
if(self->flags & BLOCK_HAS_COPY_DISPOSE)
|
||||
self->descriptor->copy_helper(ret, self);
|
||||
memcpy(self, ret, self->descriptor->size);
|
||||
ret = malloc(self->descriptor->size);
|
||||
memcpy(ret, self, self->descriptor->size);
|
||||
if (self->flags & BLOCK_HAS_COPY_DISPOSE)
|
||||
self->descriptor->copy_helper(ret, self);
|
||||
memcpy(self, ret, self->descriptor->size);
|
||||
}
|
||||
ret->reserved++;
|
||||
ret->reserved++;
|
||||
}
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Release a block and frees the memory when the retain count hits zero.
|
||||
void _Block_release(void *src)
|
||||
void
|
||||
_Block_release(void *src)
|
||||
{
|
||||
struct StackBlockClass *self = src;
|
||||
struct StackBlockClass *self = src;
|
||||
|
||||
extern void _NSConcreteStackBlock __attribute__((weak));
|
||||
extern void _NSConcreteStackBlock __attribute__((weak));
|
||||
|
||||
if(self->isa == &_NSConcreteStackBlock && // A Global block doesn't need to be released
|
||||
self->flags & BLOCK_HAS_DESCRIPTOR && // Should always be true...
|
||||
self->reserved > 0) // If false, then it's not allocated on the heap, we won't release auto memory !
|
||||
if (self->isa == &_NSConcreteStackBlock
|
||||
// A Global block doesn't need to be released
|
||||
&& self->flags & BLOCK_HAS_DESCRIPTOR
|
||||
// Should always be true...
|
||||
&& self->reserved > 0)
|
||||
// If false, then it's not allocated on the heap, we won't release auto memory !
|
||||
{
|
||||
self->reserved--;
|
||||
if(self->reserved == 0)
|
||||
self->reserved--;
|
||||
if (self->reserved == 0)
|
||||
{
|
||||
if(self->flags & BLOCK_HAS_COPY_DISPOSE)
|
||||
self->descriptor->dispose_helper(self);
|
||||
free(self);
|
||||
if (self->flags & BLOCK_HAS_COPY_DISPOSE)
|
||||
self->descriptor->dispose_helper(self);
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *_Block_get_types(void *blk)
|
||||
const char *
|
||||
_Block_get_types(void *blk)
|
||||
{
|
||||
struct psy_block_literal *block = blk;
|
||||
return block->types;
|
||||
struct psy_block_literal *block = blk;
|
||||
return block->types;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue