29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
|
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
-
-
+
+
-
+
+
-
-
+
+
+
-
+
-
-
+
+
+
-
+
-
-
+
+
-
-
+
+
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
+
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
+
+
-
+
-
+
-
-
+
+
-
+
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
|
Class isa;
}
+ (bool)resolveClassMethod: (SEL)selector;
+ (bool)resolveInstanceMethod: (SEL)selector;
@end
static IMP forward_handler = (IMP)0;
static IMP forward_handler_stret = (IMP)0;
static IMP forwardHandler = (IMP)0;
static IMP stretForwardHandler = (IMP)0;
static IMP
common_method_not_found(id obj, SEL sel, IMP (*lookup)(id, SEL), IMP forward)
commonMethodNotFound(id object, SEL selector, IMP (*lookup)(id, SEL),
IMP forward)
{
/*
* obj might be a dummy object (see class_getMethodImplementation), so
* don't access obj directly unless it's a class!
* object might be a dummy object (see class_getMethodImplementation),
* so don't access object directly unless it's a class!
*/
bool isClass =
bool is_class = object_getClass(obj)->info & OBJC_CLASS_INFO_METACLASS;
object_getClass(object)->info & OBJC_CLASS_INFO_METACLASS;
if (!(object_getClass(obj)->info & OBJC_CLASS_INFO_INITIALIZED)) {
Class cls = (is_class ? (Class)obj : object_getClass(obj));
if (!(object_getClass(object)->info & OBJC_CLASS_INFO_INITIALIZED)) {
Class cls = (isClass
? (Class)object : object_getClass(object));
objc_initialize_class(cls);
if (!(cls->info & OBJC_CLASS_INFO_SETUP))
OBJC_ERROR("Could not dispatch message for incomplete "
"class %s!", cls->name);
/*
* We don't need to handle the case that super was called.
* The reason for this is that a call to super is not possible
* before a message to the class has been sent and it thus has
* been initialized together with its superclasses.
*/
return lookup(obj, sel);
return lookup(object, selector);
}
/* Try resolveClassMethod: / resolveInstanceMethod: */
if (class_isMetaClass(object_getClass(obj))) {
Class cls = object_getClass(obj);
if (class_isMetaClass(object_getClass(object))) {
Class cls = object_getClass(object);
if (class_respondsToSelector(cls,
@selector(resolveClassMethod:)) &&
[obj resolveClassMethod: sel]) {
if (!class_respondsToSelector(cls, sel))
[object resolveClassMethod: selector]) {
if (!class_respondsToSelector(cls, selector))
OBJC_ERROR("[%s resolveClassMethod: %s] "
"returned true without adding the method!",
class_getName(obj), sel_getName(sel));
class_getName(object),
sel_getName(selector));
return lookup(obj, sel);
return lookup(object, selector);
}
} else {
Class cls = object_getClass(obj);
Class metacls = object_getClass(cls);
Class cls = object_getClass(object);
Class metaclass = object_getClass(cls);
if (class_respondsToSelector(metacls,
if (class_respondsToSelector(metaclass,
@selector(resolveInstanceMethod:)) &&
[cls resolveInstanceMethod: sel]) {
if (!class_respondsToSelector(cls, sel))
[cls resolveInstanceMethod: selector]) {
if (!class_respondsToSelector(cls, selector))
OBJC_ERROR("[%s resolveInstanceMethod: %s] "
"returned true without adding the method!",
class_getName(object_getClass(obj)),
sel_getName(sel));
class_getName(object_getClass(object)),
sel_getName(selector));
return lookup(obj, sel);
return lookup(object, selector);
}
}
if (forward != (IMP)0)
return forward;
OBJC_ERROR("Selector %c[%s] is not implemented for class %s!",
(is_class ? '+' : '-'), sel_getName(sel), object_getClassName(obj));
(isClass ? '+' : '-'), sel_getName(selector),
object_getClassName(object));
}
IMP
objc_method_not_found(id obj, SEL sel)
objc_method_not_found(id object, SEL selector)
{
return common_method_not_found(obj, sel, objc_msg_lookup,
forward_handler);
return commonMethodNotFound(object, selector, objc_msg_lookup,
forwardHandler);
}
IMP
objc_method_not_found_stret(id obj, SEL sel)
objc_method_not_found_stret(id object, SEL selector)
{
return common_method_not_found(obj, sel, objc_msg_lookup_stret,
forward_handler_stret);
return commonMethodNotFound(object, selector, objc_msg_lookup_stret,
stretForwardHandler);
}
void
objc_setForwardHandler(IMP forward, IMP forward_stret)
objc_setForwardHandler(IMP forward, IMP stretForward)
{
forward_handler = forward;
forward_handler_stret = forward_stret;
forwardHandler = forward;
stretForwardHandler = stretForward;
}
bool
class_respondsToSelector(Class cls, SEL sel)
class_respondsToSelector(Class cls, SEL selector)
{
if (cls == Nil)
return false;
return (objc_dtable_get(cls->dtable, (uint32_t)sel->uid) != (IMP)0);
return (objc_dtable_get(cls->DTable,
(uint32_t)selector->UID) != (IMP)0);
}
#ifndef OF_ASM_LOOKUP
static id
nil_method(id self, SEL _cmd)
nilMethod(id self, SEL _cmd)
{
return nil;
}
static OF_INLINE IMP
common_lookup(id obj, SEL sel, IMP (*not_found)(id, SEL))
commonLookup(id object, SEL selector, IMP (*notFound)(id, SEL))
{
IMP imp;
if (obj == nil)
return (IMP)nil_method;
if (object == nil)
return (IMP)nilMethod;
imp = objc_dtable_get(object_getClass(obj)->dtable, (uint32_t)sel->uid);
imp = objc_dtable_get(object_getClass(object)->DTable,
(uint32_t)selector->UID);
if (imp == (IMP)0)
return not_found(obj, sel);
return notFound(object, selector);
return imp;
}
IMP
objc_msg_lookup(id obj, SEL sel)
objc_msg_lookup(id object, SEL selector)
{
return common_lookup(obj, sel, objc_method_not_found);
return commonLookup(object, selector, objc_method_not_found);
}
IMP
objc_msg_lookup_stret(id obj, SEL sel)
objc_msg_lookup_stret(id object, SEL selector)
{
return common_lookup(obj, sel, objc_method_not_found_stret);
return commonLookup(object, selector, objc_method_not_found_stret);
}
static OF_INLINE IMP
common_lookup_super(struct objc_super *super, SEL sel,
IMP (*not_found)(id, SEL))
commonSuperLookup(struct objc_super *super, SEL selector,
IMP (*notFound)(id, SEL))
{
IMP imp;
if (super->self == nil)
return (IMP)nil_method;
return (IMP)nilMethod;
imp = objc_dtable_get(super->cls->dtable, (uint32_t)sel->uid);
imp = objc_dtable_get(super->cls->DTable, (uint32_t)selector->UID);
if (imp == (IMP)0)
return not_found(super->self, sel);
return notFound(super->self, selector);
return imp;
}
IMP
objc_msg_lookup_super(struct objc_super *super, SEL sel)
objc_msg_lookup_super(struct objc_super *super, SEL selector)
{
return common_lookup_super(super, sel, objc_method_not_found);
return commonSuperLookup(super, selector, objc_method_not_found);
}
IMP
objc_msg_lookup_super_stret(struct objc_super *super, SEL sel)
objc_msg_lookup_super_stret(struct objc_super *super, SEL selector)
{
return common_lookup_super(super, sel, objc_method_not_found_stret);
return commonSuperLookup(super, selector, objc_method_not_found_stret);
}
#endif
|