Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't rely on load order for built-in classes. #294

Merged
merged 1 commit into from
Oct 22, 2024
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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ set(libobjc_OBJCXX_SRCS
)
set(libobjc_OBJC_SRCS
NSBlocks.m
Protocol2.m
associate.m
blocks_runtime_np.m
properties.m)
set(libobjc_C_SRCS
alias_table.c
block_to_imp.c
builtin_classes.c
caps.c
category_loader.c
class_table.c
Expand Down
45 changes: 0 additions & 45 deletions Protocol2.m

This file was deleted.

2 changes: 1 addition & 1 deletion Test/PropertyIntrospectionTest2_arc.m
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ static BOOL testPropertyForProperty_alt(objc_property_t p,
attrsList = property_copyAttributeList(p, NULL);
OPT_ASSERT(0 != attrsList);
objc_property_attribute_t *ra;
for (attrsCount = 0, ra = attrsList; (ra->name != NULL) && (attrsCount < size); attrsCount++, ra++) {}
for (attrsCount = 0, ra = attrsList; (attrsCount < size) && (ra->name != NULL) ; attrsCount++, ra++) {}
OPT_ASSERT(attrsCount == size);
free(attrsList);
for (unsigned int index=0; index<size; index++) {
Expand Down
106 changes: 106 additions & 0 deletions builtin_classes.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "protocol.h"
#include "class.h"
#include "method.h"
#include "loader.h"

OBJC_PUBLIC struct objc_class _OBJC_CLASS_Object;

static struct objc_class _OBJC_METACLASS_Object = {
.isa = NULL,
.name = "Object",
.info = objc_class_flag_meta,
};
OBJC_PUBLIC struct objc_class _OBJC_CLASS_Object = {
.isa = &_OBJC_METACLASS_Object,
.super_class = NULL,
.name = "Object",
};

static struct objc_class _OBJC_METACLASS_Protocol = {
.isa = &_OBJC_METACLASS_Object,
.super_class = &_OBJC_METACLASS_Object,
.name = "Protocol",
.info = objc_class_flag_meta,
};
static struct objc_class _OBJC_METACLASS_ProtocolGCC = {
.isa = &_OBJC_METACLASS_Object,
.super_class = &_OBJC_METACLASS_Object,
.name = "ProtocolGCC",
.info = objc_class_flag_meta,
};
static struct objc_class _OBJC_METACLASS_ProtocolGSv1 = {
.isa = &_OBJC_METACLASS_Object,
.super_class = &_OBJC_METACLASS_Object,
.name = "ProtocolGSv2",
.info = objc_class_flag_meta,
};
static struct objc_class _OBJC_METACLASS___IncompleteProtocol = {
.isa = &_OBJC_METACLASS_Object,
.super_class = &_OBJC_METACLASS_Object,
.name = "ProtocolGCC",
.info = objc_class_flag_meta,
};

OBJC_PUBLIC struct objc_class _OBJC_CLASS_Protocol = {
.isa = &_OBJC_METACLASS_Protocol,
.super_class = &_OBJC_CLASS_Object,
.name = "Protocol",
.info = objc_class_flag_permanent_instances,
};

OBJC_PUBLIC struct objc_class _OBJC_CLASS_ProtocolGCC = {
.isa = &_OBJC_METACLASS_ProtocolGCC,
.super_class = &_OBJC_CLASS_Protocol,
.name = "ProtocolGCC",
.info = objc_class_flag_permanent_instances,
};

OBJC_PUBLIC struct objc_class _OBJC_CLASS___IncompleteProtocol = {
.isa = &_OBJC_METACLASS_Protocol,
.super_class = &_OBJC_CLASS_Protocol,
.name = "__IncompleteProtocol",
.info = objc_class_flag_permanent_instances,
};

OBJC_PUBLIC struct objc_class _OBJC_CLASS_ProtocolGSv1 = {
.isa = &_OBJC_METACLASS_Protocol,
.super_class = &_OBJC_CLASS_Protocol,
.name = "ProtocolGSv1",
.info = objc_class_flag_permanent_instances,
};

#ifdef OLDABI_COMPAT
static struct objc_class _OBJC_METACLASS___ObjC_Protocol_Holder_Ugly_Hack = {
.isa = NULL,
.name = "__ObjC_Protocol_Holder_Ugly_Hack",
.info = objc_class_flag_meta,
};
OBJC_PUBLIC struct objc_class _OBJC_CLASS__ObjC_Protocol_Holder_Ugly_Hack = {
.isa = &_OBJC_METACLASS___ObjC_Protocol_Holder_Ugly_Hack,
.super_class = NULL,
.name = "__ObjC_Protocol_Holder_Ugly_Hack",
};
#endif

PRIVATE void init_builtin_classes(void)
{
// Load the classes that are compiled into the runtime.
objc_load_class(&_OBJC_CLASS_Object);
objc_load_class(&_OBJC_CLASS_Protocol);
objc_load_class(&_OBJC_CLASS_ProtocolGCC);
objc_load_class(&_OBJC_CLASS_ProtocolGSv1);
objc_load_class(&_OBJC_CLASS___IncompleteProtocol);
objc_resolve_class(&_OBJC_CLASS_Object);
objc_resolve_class(&_OBJC_CLASS_Protocol);
objc_resolve_class(&_OBJC_CLASS_ProtocolGCC);
objc_resolve_class(&_OBJC_CLASS_ProtocolGSv1);
objc_resolve_class(&_OBJC_CLASS___IncompleteProtocol);
// Fix up the sizes of the various protocol classes that we will use.
_OBJC_CLASS_Object.instance_size = sizeof(void*);
_OBJC_CLASS_Protocol.instance_size = sizeof(struct objc_protocol);
_OBJC_CLASS___IncompleteProtocol.instance_size = sizeof(struct objc_protocol);
hmelder marked this conversation as resolved.
Show resolved Hide resolved
#ifdef OLDABI_COMPAT
objc_load_class(&_OBJC_CLASS__ObjC_Protocol_Holder_Ugly_Hack);
objc_resolve_class(&_OBJC_CLASS__ObjC_Protocol_Holder_Ugly_Hack);
#endif
}
2 changes: 2 additions & 0 deletions class.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,8 @@ void freeIvarLists(Class aClass);
*/
void freeMethodLists(Class aClass);

void objc_load_class(struct objc_class *cls);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
1 change: 1 addition & 0 deletions class_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ PRIVATE Class class_table_next(void **e)
(struct class_table_internal_table_enumerator**)e);
}

PRIVATE BOOL objc_resolve_class(Class cls);
PRIVATE void init_class_tables(void)
{
class_table_internal_initialize(&class_table, 4096);
Expand Down
17 changes: 8 additions & 9 deletions legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "objc/encoding.h"
#include "legacy.h"
#include "properties.h"
#include "protocol.h"
#include "class.h"
#include "loader.h"

Expand Down Expand Up @@ -411,14 +412,13 @@ upgrade_protocol_method_list_gcc(struct objc_protocol_method_description_list_gc
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"))
if (p->isa == (id)&_OBJC_CLASS_ProtocolGCC)
{
return objc_getProtocol(p->name);
}
p->isa = objc_getClass("ProtocolGCC");
p->isa = (id)&_OBJC_CLASS_ProtocolGCC;
Protocol *proto =
(Protocol*)class_createInstance((Class)objc_getClass("Protocol"),
sizeof(struct objc_protocol) - sizeof(id));
(Protocol*)class_createInstance(&_OBJC_CLASS_Protocol, 0);
proto->name = p->name;
// Aliasing of this between the new and old structures means that when this
// returns these will all be updated.
Expand All @@ -432,13 +432,12 @@ PRIVATE struct objc_protocol *objc_upgrade_protocol_gcc(struct objc_protocol_gcc
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"))
if (p->isa == (id)&_OBJC_CLASS_ProtocolGSv1)
{
return objc_getProtocol(p->name);
}
Protocol *n =
(Protocol*)class_createInstance((Class)objc_getClass("Protocol"),
sizeof(struct objc_protocol) - sizeof(id));
(Protocol*)class_createInstance(&_OBJC_CLASS_Protocol, 0);
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.
Expand All @@ -447,14 +446,14 @@ PRIVATE struct objc_protocol *objc_upgrade_protocol_gsv1(struct objc_protocol_gs
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");
n->isa = (id)&_OBJC_CLASS_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");
p->isa = (id)&_OBJC_CLASS_ProtocolGSv1;
assert(p->isa);
return n;
}
Expand Down
32 changes: 7 additions & 25 deletions loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,6 @@
PRIVATE mutex_t runtime_mutex;
LEGACY void *__objc_runtime_mutex = &runtime_mutex;

void init_alias_table(void);
void init_arc(void);
void init_class_tables(void);
void init_dispatch_tables(void);
void init_gc(void);
void init_protocol_table(void);
void init_selector_tables(void);
void init_trampolines(void);
void init_early_blocks(void);
void objc_send_load_message(Class class);

void log_selector_memory_usage(void);

static void log_memory_stats(void)
Expand All @@ -46,20 +35,11 @@ __attribute__((weak)) void (*dispatch_end_thread_4GC)(void);
__attribute__((weak)) void *(*_dispatch_begin_NSAutoReleasePool)(void);
__attribute__((weak)) void (*_dispatch_end_NSAutoReleasePool)(void *);

__attribute__((used))
static void link_protos(void)
{
link_protocol_classes();
}

static void init_runtime(void)
{
static BOOL first_run = YES;
if (first_run)
{
#if ENABLE_GC
init_gc();
#endif
// Create the main runtime lock. This is not safe in theory, but in
// practice the first time that this function is called will be in the
// loader, from the main thread. Future loaders may run concurrently,
Expand All @@ -80,6 +60,7 @@ static void init_runtime(void)
init_early_blocks();
init_arc();
init_trampolines();
init_builtin_classes();
first_run = NO;
if (getenv("LIBOBJC_MEMORY_PROFILE"))
{
Expand Down Expand Up @@ -253,22 +234,23 @@ OBJC_PUBLIC void __objc_load(struct objc_init *init)
assert(p);
*proto = p;
}
int classesLoaded = 0;
for (Class *cls = init->cls_begin ; cls < init->cls_end ; cls++)
{
if (*cls == NULL)
{
continue;
}
// As a special case, allow using legacy ABI code with a new runtime.
if (isFirstLoad && (strcmp((*cls)->name, "Protocol") == 0))
{
CurrentABI = UnknownABI;
}
#ifdef DEBUG_LOADING
fprintf(stderr, "Loading class %s\n", (*cls)->name);
#endif
objc_load_class(*cls);
}
if (isFirstLoad && (classesLoaded == 0))
{
// As a special case, allow using legacy ABI code with a new runtime.
CurrentABI = UnknownABI;
}
#if 0
// We currently don't do anything with these pointers. They exist to
// provide a level of indirection that will permit us to completely change
Expand Down
59 changes: 59 additions & 0 deletions loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,63 @@ void objc_init_statics(struct objc_static_instance_list *statics);
*/
void objc_init_buffered_statics(void);

/**
* Initialise built-in classes (Object and Protocol). This must be called
* after `init_class_tables`.
*/
void init_builtin_classes(void);

/**
* Initialise the aliases table.
*/
void init_alias_table(void);

/**
* Initialise the automatic reference counting system.
*/
void init_arc(void);

/**
* Initialise the class tables.
*/
void init_class_tables(void);

/**
* Initialise the dispatch table machinery.
*/
void init_dispatch_tables(void);

/**
* Initialise the protocol tables.
*/
void init_protocol_table(void);

/**
* Initialise the selector tables.
*/
void init_selector_tables(void);

/**
* Initialise the trampolines for using blocks as methods.
*/
void init_trampolines(void);

/**
* Send +load messages to a class if required.
*/
void objc_send_load_message(Class cls);

/**
* Resolve a class (populate its superclass and sibling class links). Returns
* YES if the class can be resolved, NO otherwise. Classes cannot be resolved
* unless their superclasses have all been resolved.
*/
BOOL objc_resolve_class(Class cls);

/**
* Initialise the block classes.
*/
void init_early_blocks(void);


#endif //__OBJC_LOADER_H_INCLUDED
1 change: 1 addition & 0 deletions method.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#pragma once
#include <assert.h>

/**
Expand Down
Loading
Loading