3 Star 0 Fork 0

Gitee 极速下载 / gnustep-objective-c-runtime

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/gnustep/libobjc2
克隆/下载
legacy.c 12.80 KB
一键复制 编辑 原始数据 按行查看 历史
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "objc/runtime.h"
#include "objc/encoding.h"
#include "legacy.h"
#include "properties.h"
#include "class.h"
#include "loader.h"
PRIVATE size_t lengthOfTypeEncoding(const char *types);
enum objc_class_flags_gsv1
{
/** This class structure represents a class. */
objc_class_flag_class_gsv1 = (1<<0),
/** This class structure represents a metaclass. */
objc_class_flag_meta_gsv1 = (1<<1),
/**
* The class uses the new, Objective-C 2, runtime ABI. This ABI defines an
* ABI version field inside the class, and so will be used for all
* subsequent versions that retain some degree of compatibility.
*/
objc_class_flag_new_abi_gsv1 = (1<<4)
};
static inline BOOL objc_test_class_flag_gsv1(struct objc_class_gsv1 *aClass,
enum objc_class_flags_gsv1 flag)
{
return (aClass->info & (unsigned long)flag) == (unsigned long)flag;
}
/**
* Checks the version of a class. Return values are:
* 0. Legacy GCC ABI compatible class.
* 1. First release of GNUstep ABI.
* 2. Second release of the GNUstep ABI, adds strong / weak ivar bitmaps.
* 3. Third release of the GNUstep ABI. Many cleanups.
*/
static inline int objc_get_class_version_gsv1(struct objc_class_gsv1 *aClass)
{
if (!objc_test_class_flag_gsv1(aClass, objc_class_flag_new_abi_gsv1))
{
return 0;
}
return aClass->abi_version + 1;
}
static objc_ivar_ownership ownershipForIvar(struct objc_class_gsv1 *cls, int idx)
{
if (objc_get_class_version_gsv1(cls) < 2)
{
return ownership_unsafe;
}
if (objc_bitfield_test(cls->strong_pointers, idx))
{
return ownership_strong;
}
if (objc_bitfield_test(cls->weak_pointers, idx))
{
return ownership_weak;
}
return ownership_unsafe;
}
static struct objc_ivar_list *upgradeIvarList(struct objc_class_gsv1 *cls)
{
struct objc_ivar_list_gcc *l = cls->ivars;
if (l == NULL)
{
return NULL;
}
struct objc_ivar_list *n = calloc(1, sizeof(struct objc_ivar_list) +
l->count*sizeof(struct objc_ivar));
n->size = sizeof(struct objc_ivar);
n->count = l->count;
for (int i=0 ; i<l->count ; i++)
{
BOOL isBitfield = NO;
int bitfieldSize = 0;
int nextOffset;
// Bitfields have the same offset, but should have their size set to
// the size of the bitfield. We calculate the size of the bitfield by
// looking for the next ivar after the current one that has a different
// offset.
if (i+1 < l->count)
{
nextOffset = l->ivar_list[i+1].offset;
if (l->ivar_list[i].offset == l->ivar_list[i+1].offset)
{
isBitfield = YES;
for (int j=i+2 ; j<l->count ; j++)
{
if (l->ivar_list[i].offset != l->ivar_list[j].offset)
{
bitfieldSize = l->ivar_list[j].offset - l->ivar_list[i].offset;
break;
}
}
if (bitfieldSize == 0)
{
bitfieldSize = cls->instance_size - l->ivar_list[i].offset;
}
}
}
else
{
nextOffset = cls->instance_size;
}
if (nextOffset < 0)
{
nextOffset = -nextOffset;
}
const char *type = l->ivar_list[i].type;
int size = nextOffset - l->ivar_list[i].offset;
n->ivar_list[i].name = l->ivar_list[i].name;
n->ivar_list[i].type = type;
n->ivar_list[i].size = isBitfield ? bitfieldSize : size;
if (objc_test_class_flag_gsv1(cls, objc_class_flag_new_abi_gsv1))
{
n->ivar_list[i].offset = cls->ivar_offsets[i];
}
else
{
n->ivar_list[i].offset = &l->ivar_list[i].offset;
}
ivarSetAlign(&n->ivar_list[i], ((type == NULL) || type[0] == 0) ? __alignof__(void*) : objc_alignof_type(type));
if (type[0] == '\0')
{
ivarSetAlign(&n->ivar_list[i], size);
}
ivarSetOwnership(&n->ivar_list[i], ownershipForIvar(cls, i));
}
return n;
}
static struct objc_method_list *upgradeMethodList(struct objc_method_list_gcc *old)
{
if (old == NULL)
{
return NULL;
}
if (old->count == 0)
{
return NULL;
}
struct objc_method_list *l = calloc(sizeof(struct objc_method_list) + old->count * sizeof(struct objc_method), 1);
l->count = old->count;
if (old->next)
{
l->next = upgradeMethodList(old->next);
}
l->size = sizeof(struct objc_method);
for (int i=0 ; i<old->count ; i++)
{
l->methods[i].imp = old->methods[i].imp;
l->methods[i].selector = old->methods[i].selector;
l->methods[i].types = old->methods[i].types;
}
return l;
}
static inline BOOL checkAttribute(char field, int attr)
{
return (field & attr) == attr;
}
static void upgradeProperty(struct objc_property *n, struct objc_property_gsv1 *o)
{
char *typeEncoding;
ptrdiff_t typeSize;
if (o->name[0] == '\0')
{
n->name = o->name + o->name[1];
n->attributes = o->name + 2;
// If we have an attribute string, then it will contain a more accurate
// version of the types than we'll find in the getter (qualifiers such
// as _Atomic and volatile may be dropped)
assert(n->attributes[0] == 'T');
const char *type_start = &n->attributes[1];
const char *type_end = strchr(type_start, ',');
if (type_end == NULL)
{
type_end = type_start + strlen(type_start);
}
typeSize = type_end - type_start;
typeEncoding = malloc(typeSize + 1);
memcpy(typeEncoding, type_start, typeSize);
typeEncoding[typeSize] = 0;
}
else
{
typeSize = (ptrdiff_t)lengthOfTypeEncoding(o->getter_types);
typeEncoding = malloc(typeSize + 1);
memcpy(typeEncoding, o->getter_types, typeSize);
typeEncoding[typeSize] = 0;
}
n->type = typeEncoding;
if (o->getter_name)
{
n->getter = sel_registerTypedName_np(o->getter_name, o->getter_types);
}
if (o->setter_name)
{
n->setter = sel_registerTypedName_np(o->setter_name, o->setter_types);
}
if (o->name[0] == '\0')
{
return;
}
n->name = o->name;
const char *name = o->name;
size_t nameSize = (NULL == name) ? 0 : strlen(name);
// Encoding is T{type},V{name}, so 4 bytes for the "T,V" that we always
// need. We also need two bytes for the leading null and the length.
size_t encodingSize = typeSize + nameSize + 6;
char flags[20];
size_t i = 0;
// Flags that are a comma then a character
if (checkAttribute(o->attributes, OBJC_PR_readonly))
{
flags[i++] = ',';
flags[i++] = 'R';
}
if (checkAttribute(o->attributes, OBJC_PR_retain))
{
flags[i++] = ',';
flags[i++] = '&';
}
if (checkAttribute(o->attributes, OBJC_PR_copy))
{
flags[i++] = ',';
flags[i++] = 'C';
}
if (checkAttribute(o->attributes2, OBJC_PR_weak))
{
flags[i++] = ',';
flags[i++] = 'W';
}
if (checkAttribute(o->attributes2, OBJC_PR_dynamic))
{
flags[i++] = ',';
flags[i++] = 'D';
}
if ((o->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
{
flags[i++] = ',';
flags[i++] = 'N';
}
encodingSize += i;
flags[i] = '\0';
size_t setterLength = 0;
size_t getterLength = 0;
if ((o->attributes & OBJC_PR_getter) == OBJC_PR_getter)
{
getterLength = strlen(o->getter_name);
encodingSize += 2 + getterLength;
}
if ((o->attributes & OBJC_PR_setter) == OBJC_PR_setter)
{
setterLength = strlen(o->setter_name);
encodingSize += 2 + setterLength;
}
unsigned char *encoding = malloc(encodingSize);
// Set the leading 0 and the offset of the name
unsigned char *insert = encoding;
BOOL needsComma = NO;
*(insert++) = 0;
*(insert++) = 0;
// Set the type encoding
*(insert++) = 'T';
memcpy(insert, typeEncoding, typeSize);
insert += typeSize;
needsComma = YES;
// Set the flags
memcpy(insert, flags, i);
insert += i;
if ((o->attributes & OBJC_PR_getter) == OBJC_PR_getter)
{
if (needsComma)
{
*(insert++) = ',';
}
i++;
needsComma = YES;
*(insert++) = 'G';
memcpy(insert, o->getter_name, getterLength);
insert += getterLength;
}
if ((o->attributes & OBJC_PR_setter) == OBJC_PR_setter)
{
if (needsComma)
{
*(insert++) = ',';
}
i++;
needsComma = YES;
*(insert++) = 'S';
memcpy(insert, o->setter_name, setterLength);
insert += setterLength;
}
if (needsComma)
{
*(insert++) = ',';
}
*(insert++) = 'V';
memcpy(insert, name, nameSize);
insert += nameSize;
*(insert++) = '\0';
n->attributes = (const char*)encoding;
}
static struct objc_property_list *upgradePropertyList(struct objc_property_list_gsv1 *l)
{
if (l == NULL)
{
return NULL;
}
size_t data_size = l->count * sizeof(struct objc_property);
struct objc_property_list *n = calloc(1, sizeof(struct objc_property_list) + data_size);
n->count = l->count;
n->size = sizeof(struct objc_property);
for (int i=0 ; i<l->count ; i++)
{
upgradeProperty(&n->properties[i], &l->properties[i]);
}
return n;
}
static int legacy_key;
PRIVATE struct objc_class_gsv1* objc_legacy_class_for_class(Class cls)
{
return (struct objc_class_gsv1*)objc_getAssociatedObject((id)cls, &legacy_key);
}
PRIVATE Class objc_upgrade_class(struct objc_class_gsv1 *oldClass)
{
Class cls = calloc(sizeof(struct objc_class), 1);
cls->isa = oldClass->isa;
// super_class is left nil and we upgrade it later.
cls->name = oldClass->name;
cls->version = oldClass->version;
cls->info = objc_class_flag_meta;
cls->instance_size = oldClass->instance_size;
cls->ivars = upgradeIvarList(oldClass);
cls->methods = upgradeMethodList(oldClass->methods);
cls->protocols = oldClass->protocols;
cls->abi_version = oldClass->abi_version;
cls->properties = upgradePropertyList(oldClass->properties);
objc_register_selectors_from_class(cls);
if (!objc_test_class_flag_gsv1(oldClass, objc_class_flag_meta_gsv1))
{
cls->info = 0;
cls->isa = objc_upgrade_class((struct objc_class_gsv1*)cls->isa);
objc_setAssociatedObject((id)cls, &legacy_key, (id)oldClass, OBJC_ASSOCIATION_ASSIGN);
}
else
{
cls->instance_size = sizeof(struct objc_class);
}
return cls;
}
PRIVATE struct objc_category *objc_upgrade_category(struct objc_category_gcc *old)
{
struct objc_category *cat = calloc(1, sizeof(struct objc_category));
memcpy(cat, old, sizeof(struct objc_category_gcc));
cat->instance_methods = upgradeMethodList(old->instance_methods);
cat->class_methods = upgradeMethodList(old->class_methods);
if (cat->instance_methods != NULL)
{
objc_register_selectors_from_list(cat->instance_methods);
}
if (cat->class_methods != NULL)
{
objc_register_selectors_from_list(cat->class_methods);
}
for (int i=0 ; i<cat->protocols->count ; i++)
{
objc_init_protocols(cat->protocols);
}
return cat;
}
static struct objc_protocol_method_description_list*
upgrade_protocol_method_list_gcc(struct objc_protocol_method_description_list_gcc *l)
{
if ((l == NULL) || (l->count == 0))
{
return NULL;
}
struct objc_protocol_method_description_list *n =
malloc(sizeof(struct objc_protocol_method_description_list) +
l->count * sizeof(struct objc_protocol_method_description));
n->count = l->count;
n->size = sizeof(struct objc_protocol_method_description);
for (int i=0 ; i<n->count ; i++)
{
n->methods[i].selector = sel_registerTypedName_np(l->methods[i].name, l->methods[i].types);
n->methods[i].types = l->methods[i].types;
}
return n;
}
PRIVATE struct objc_protocol *objc_upgrade_protocol_gcc(struct objc_protocol_gcc *p)
{
// If the protocol has already been upgraded, the don't try to upgrade it twice.
if (p->isa == objc_getClass("ProtocolGCC"))
{
return objc_getProtocol(p->name);
}
p->isa = objc_getClass("ProtocolGCC");
Protocol *proto =
(Protocol*)class_createInstance((Class)objc_getClass("Protocol"),
sizeof(struct objc_protocol) - sizeof(id));
proto->name = p->name;
// Aliasing of this between the new and old structures means that when this
// returns these will all be updated.
proto->protocol_list = p->protocol_list;
proto->instance_methods = upgrade_protocol_method_list_gcc(p->instance_methods);
proto->class_methods = upgrade_protocol_method_list_gcc(p->class_methods);
assert(proto->isa);
return proto;
}
PRIVATE struct objc_protocol *objc_upgrade_protocol_gsv1(struct objc_protocol_gsv1 *p)
{
// If the protocol has already been upgraded, the don't try to upgrade it twice.
if (p->isa == objc_getClass("ProtocolGSv1"))
{
return objc_getProtocol(p->name);
}
Protocol *n =
(Protocol*)class_createInstance((Class)objc_getClass("Protocol"),
sizeof(struct objc_protocol) - sizeof(id));
n->instance_methods = upgrade_protocol_method_list_gcc(p->instance_methods);
// Aliasing of this between the new and old structures means that when this
// returns these will all be updated.
n->name = p->name;
n->protocol_list = p->protocol_list;
n->class_methods = upgrade_protocol_method_list_gcc(p->class_methods);
n->properties = upgradePropertyList(p->properties);
n->optional_properties = upgradePropertyList(p->optional_properties);
n->isa = objc_getClass("Protocol");
// We do in-place upgrading of these, because they might be referenced
// directly
p->instance_methods = (struct objc_protocol_method_description_list_gcc*)n->instance_methods;
p->class_methods = (struct objc_protocol_method_description_list_gcc*)n->class_methods;
p->properties = (struct objc_property_list_gsv1*)n->properties;
p->optional_properties = (struct objc_property_list_gsv1*)n->optional_properties;
p->isa = objc_getClass("ProtocolGSv1");
assert(p->isa);
return n;
}
C/C++
1
https://gitee.com/mirrors/gnustep-objective-c-runtime.git
git@gitee.com:mirrors/gnustep-objective-c-runtime.git
mirrors
gnustep-objective-c-runtime
gnustep-objective-c-runtime
master

搜索帮助