Improve protocol method metadata.

Methods now include a selector and extended type encoding, rather than a
method name and lgacy type encoding.  Older ones are auto-upgraded.

Expose the extended type encoding via a function that JavaScriptCore
expects to exist.
main
David Chisnall 8 years ago
parent 65b34a196f
commit ab84589b5d

@ -20,6 +20,7 @@ set(TESTS
ManyManySelectors.m
NestedExceptions.m
PropertyAttributeTest.m
ProtocolExtendedProperties.m
PropertyIntrospectionTest.m
PropertyIntrospectionTest2_arc.m
ProtocolCreation.m
@ -82,9 +83,9 @@ function(addtest_flags TEST_NAME FLAGS TEST_SOURCE)
endfunction(addtest_flags)
function(addtest_variants TEST TEST_SOURCE LEGACY)
addtest_flags(${TEST} "-O0 -fobjc-runtime=gnustep-2.0 -UNDEBUG" "${TEST_SOURCE}")
addtest_flags(${TEST} "-O0 -fobjc-runtime=gnustep-2.0 -UNDEBUG -DGS_RUNTIME_V2" "${TEST_SOURCE}")
target_sources(${TEST} PRIVATE $<TARGET_OBJECTS:test_runtime>)
addtest_flags("${TEST}_optimised" "-O3 -fobjc-runtime=gnustep-2.0 -UNDEBUG" "${TEST_SOURCE}")
addtest_flags("${TEST}_optimised" "-O3 -fobjc-runtime=gnustep-2.0 -UNDEBUG -DGS_RUNTIME_V2" "${TEST_SOURCE}")
target_sources("${TEST}_optimised" PRIVATE $<TARGET_OBJECTS:test_runtime>)
if (LEGACY)
addtest_flags("${TEST}_legacy" "-O0 -fobjc-runtime=gnustep-1.7 -UNDEBUG" "${TEST_SOURCE}")

@ -0,0 +1,19 @@
#include "Test.h"
#include <string.h>
@class NSString;
@protocol Foo
- (NSString*)aMethod: (void(^)(int))aBlock;
@end
int main(void)
{
const char *encoding = _protocol_getMethodTypeEncoding(@protocol(Foo), @selector(aMethod:), YES, YES);
#ifdef GS_RUNTIME_V2
// We expect something like this (LP64): @"NSString"24@0:8@?<v@?i>16
assert(strstr(encoding, "@\"NSString\"") == encoding);
assert(strstr(encoding, "@?<v@?i>") != NULL);
#else
assert(strstr(encoding, "@?") != NULL);
#endif
}

@ -283,6 +283,26 @@ PRIVATE struct objc_category *objc_upgrade_category(struct objc_category_legacy
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.
@ -297,8 +317,8 @@ PRIVATE struct objc_protocol *objc_upgrade_protocol_gcc(struct objc_protocol_gcc
proto->name = p->name;
// Aliasing this means that when this returns these will all be updated.
proto->protocol_list = p->protocol_list;
proto->instance_methods = p->instance_methods;
proto->class_methods = p->class_methods;
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;
}
@ -310,14 +330,12 @@ PRIVATE struct objc_protocol *objc_upgrade_protocol_gsv1(struct objc_protocol_gs
{
return (struct objc_protocol*)p;
}
if (p->properties)
{
p->properties = (struct objc_property_list_gsv1*)upgradePropertyList(p->properties);
}
if (p->optional_properties)
{
p->optional_properties = (struct objc_property_list_gsv1*)upgradePropertyList(p->optional_properties);
}
// We do in-place upgrading of these, because they might be referenced
// directly
p->instance_methods = (struct objc_protocol_method_description_list_gcc*)upgrade_protocol_method_list_gcc(p->instance_methods);
p->class_methods = (struct objc_protocol_method_description_list_gcc*)upgrade_protocol_method_list_gcc(p->class_methods);
p->properties = (struct objc_property_list_gsv1*)upgradePropertyList(p->properties);
p->optional_properties = (struct objc_property_list_gsv1*)upgradePropertyList(p->optional_properties);
p->isa = objc_getClass("Protocol");
assert(p->isa);
return (struct objc_protocol*)p;

@ -8,14 +8,11 @@ struct objc_method
*/
IMP imp;
/**
* Selector used to send messages to this method. The type encoding of
* this method should match the types field.
* Selector used to send messages to this method.
*/
SEL selector;
/**
* The type encoding for this selector. Used only for introspection, and
* only required because of the stupid selector handling in the old GNU
* runtime. In future, this field may be reused for something else.
* The extended type encoding for this method.
*/
const char *types;
};

@ -740,6 +740,16 @@ Protocol *__unsafe_unretained*objc_copyProtocolList(unsigned int *outCount);
struct objc_method_description protocol_getMethodDescription(Protocol *p,
SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod);
/**
* Returns the extended type encoding of the specified method.
*
* Note: This function is used by JavaScriptCore but is not public in Apple's
* implementation and so its semantics may change in the future and this
* runtime may diverge from Apple's.
*/
const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL aSel,
BOOL isRequiredMethod, BOOL isInstanceMethod);
/**
* Returns the name of the specified protocol.
*/

@ -316,12 +316,12 @@ BOOL class_conformsToProtocol(Class cls, Protocol *protocol)
return NO;
}
static struct objc_method_description_list *
static struct objc_protocol_method_description_list *
get_method_list(Protocol *p,
BOOL isRequiredMethod,
BOOL isInstanceMethod)
{
struct objc_method_description_list *list;
struct objc_protocol_method_description_list *list;
if (isRequiredMethod)
{
if (isInstanceMethod)
@ -353,7 +353,7 @@ struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count)
{
if ((NULL == p) || (NULL == count)){ return NULL; }
struct objc_method_description_list *list =
struct objc_protocol_method_description_list *list =
get_method_list(p, isRequiredMethod, isInstanceMethod);
*count = 0;
if (NULL == list || list->count == 0) { return NULL; }
@ -363,9 +363,8 @@ struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
calloc(sizeof(struct objc_method_description), list->count);
for (int i=0 ; i < (list->count) ; i++)
{
out[i].name = sel_registerTypedName_np(list->methods[i].name,
list->methods[i].types);
out[i].types = list->methods[i].types;
out[i].name = list->methods[i].selector;
out[i].types = sel_getType_np(list->methods[i].selector);
}
return out;
}
@ -461,34 +460,61 @@ objc_property_t protocol_getProperty(Protocol *p,
return NULL;
}
struct objc_method_description
protocol_getMethodDescription(Protocol *p,
SEL aSel,
BOOL isRequiredMethod,
BOOL isInstanceMethod)
static struct objc_protocol_method_description *
get_method_description(Protocol *p,
SEL aSel,
BOOL isRequiredMethod,
BOOL isInstanceMethod)
{
struct objc_method_description d = {0,0};
struct objc_method_description_list *list =
struct objc_protocol_method_description_list *list =
get_method_list(p, isRequiredMethod, isInstanceMethod);
if (NULL == list)
{
return d;
return NULL;
}
// TODO: We could make this much more efficient if
for (int i=0 ; i<list->count ; i++)
{
SEL s = sel_registerTypedName_np(list->methods[i].name, 0);
SEL s = list->methods[i].selector;
if (sel_isEqual(s, aSel))
{
d.name = s;
d.types = list->methods[i].types;
break;
return &list->methods[i];
}
}
return NULL;
}
struct objc_method_description
protocol_getMethodDescription(Protocol *p,
SEL aSel,
BOOL isRequiredMethod,
BOOL isInstanceMethod)
{
struct objc_method_description d = {0,0};
struct objc_protocol_method_description *m =
get_method_description(p, aSel, isRequiredMethod, isInstanceMethod);
if (m != NULL)
{
SEL s = m->selector;
d.name = s;
d.types = sel_getType_np(s);
}
return d;
}
const char *_protocol_getMethodTypeEncoding(Protocol *p,
SEL aSel,
BOOL isRequiredMethod,
BOOL isInstanceMethod)
{
struct objc_protocol_method_description *m =
get_method_description(p, aSel, isRequiredMethod, isInstanceMethod);
if (m != NULL)
{
return m->types;
}
return NULL;
}
const char *protocol_getName(Protocol *p)
{
@ -569,7 +595,7 @@ void protocol_addMethodDescription(Protocol *aProtocol,
{
if ((NULL == aProtocol) || (NULL == name) || (NULL == types)) { return; }
if (incompleteProtocolClass() != aProtocol->isa) { return; }
struct objc_method_description_list **listPtr;
struct objc_protocol_method_description_list **listPtr;
if (isInstanceMethod)
{
if (isRequiredMethod)
@ -594,19 +620,22 @@ void protocol_addMethodDescription(Protocol *aProtocol,
}
if (NULL == *listPtr)
{
*listPtr = calloc(1, sizeof(struct objc_method_description_list) + sizeof(struct objc_method_description));
// FIXME: Factor this out, we do the same thing in multiple places.
*listPtr = calloc(1, sizeof(struct objc_protocol_method_description_list) +
sizeof(struct objc_protocol_method_description));
(*listPtr)->count = 1;
(*listPtr)->size = sizeof(struct objc_protocol_method_description);
}
else
{
(*listPtr)->count++;
*listPtr = realloc(*listPtr, sizeof(struct objc_method_description_list) +
sizeof(struct objc_method_description) * (*listPtr)->count);
*listPtr = realloc(*listPtr, sizeof(struct objc_protocol_method_description_list) +
sizeof(struct objc_protocol_method_description) * (*listPtr)->count);
}
struct objc_method_description_list *list = *listPtr;
struct objc_protocol_method_description_list *list = *listPtr;
int index = list->count-1;
list->methods[index].name = sel_getName(name);
list->methods[index].types= types;
list->methods[index].selector = sel_registerTypedName_np(sel_getName(name), types);
list->methods[index].types = types;
}
void protocol_addProtocol(Protocol *aProtocol, Protocol *addition)
{

@ -4,7 +4,7 @@
#include "selector.h"
#include <stdlib.h>
struct objc_method_description_list
struct objc_protocol_method_description_list_gcc
{
/**
* Number of method descriptions in this list.
@ -18,6 +18,37 @@ struct objc_method_description_list
struct objc_selector methods[];
};
/**
* A description of a method in a protocol.
*/
struct objc_protocol_method_description
{
/**
* The selector for this method, includes traditional type encoding.
*/
SEL selector;
/**
* The extended type encoding.
*/
const char *types;
};
struct objc_protocol_method_description_list
{
/**
* Number of method descriptions in this list.
*/
int count;
/**
* Size of `struct objc_method_description`
*/
int size;
/**
* Methods in this list. `count` elements long.
*/
struct objc_protocol_method_description methods[];
};
struct objc_protocol
{
/**
@ -26,16 +57,16 @@ struct objc_protocol
id isa;
char *name;
struct objc_protocol_list *protocol_list;
struct objc_method_description_list *instance_methods;
struct objc_method_description_list *class_methods;
struct objc_protocol_method_description_list *instance_methods;
struct objc_protocol_method_description_list *class_methods;
/**
* Instance methods that are declared as optional for this protocol.
*/
struct objc_method_description_list *optional_instance_methods;
struct objc_protocol_method_description_list *optional_instance_methods;
/**
* Class methods that are declared as optional for this protocol.
*/
struct objc_method_description_list *optional_class_methods;
struct objc_protocol_method_description_list *optional_class_methods;
/**
* Properties that are required by this protocol.
*/
@ -63,11 +94,11 @@ struct objc_protocol_gcc
/**
* List of instance methods required by this protocol.
*/
struct objc_method_description_list *instance_methods;
struct objc_protocol_method_description_list_gcc *instance_methods;
/**
* List of class methods required by this protocol.
*/
struct objc_method_description_list *class_methods;
struct objc_protocol_method_description_list_gcc *class_methods;
};
struct objc_protocol_gsv1
@ -78,16 +109,16 @@ struct objc_protocol_gsv1
id isa;
char *name;
struct objc_protocol_list *protocol_list;
struct objc_method_description_list *instance_methods;
struct objc_method_description_list *class_methods;
struct objc_protocol_method_description_list_gcc *instance_methods;
struct objc_protocol_method_description_list_gcc *class_methods;
/**
* Instance methods that are declared as optional for this protocol.
*/
struct objc_method_description_list *optional_instance_methods;
struct objc_protocol_method_description_list_gcc *optional_instance_methods;
/**
* Class methods that are declared as optional for this protocol.
*/
struct objc_method_description_list *optional_class_methods;
struct objc_protocol_method_description_list_gcc *optional_class_methods;
/**
* Properties that are required by this protocol.
*/

Loading…
Cancel
Save