diff options
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/special/load-category-1.h | 20 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/special/load-category-1.m | 40 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/special/load-category-1a.m | 22 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/special/special.exp | 29 | ||||
-rw-r--r-- | libobjc/ChangeLog | 12 | ||||
-rw-r--r-- | libobjc/init.c | 77 |
7 files changed, 184 insertions, 24 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5f597a97b3f..007baf400b9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com> + + PR libobjc/16110 + * objc.dg/special/special.exp: Added new test. + * objc.dg/special/load-category-1.m: New. + * objc.dg/special/load-category-1a.m: New. + * objc.dg/special/load-category-1.h: New. + 2010-12-21 Steven Bosscher <steven@gcc.gnu.org> PR middle-end/45310 diff --git a/gcc/testsuite/objc.dg/special/load-category-1.h b/gcc/testsuite/objc.dg/special/load-category-1.h new file mode 100644 index 00000000000..7810487dfe4 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-1.h @@ -0,0 +1,20 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ + +/* Test that +load works when a category is defined in a different + module than the main class. */ + +/* This function should be called any time +load is invoked, so we can + keep the count. */ +extern int increase_load_count (void); + +@interface TestClass1 +{ + id isa; +} +@end + +@interface TestClass2 +{ + id isa; +} +@end diff --git a/gcc/testsuite/objc.dg/special/load-category-1.m b/gcc/testsuite/objc.dg/special/load-category-1.m new file mode 100644 index 00000000000..bfd6373d2b8 --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-1.m @@ -0,0 +1,40 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ +/* { dg-do run } */ +/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +#include "load-category-1.h" + +@implementation TestClass1 ++ initialize { return self; } ++ load +{ + increase_load_count (); +} +@end + +@implementation TestClass2 (Category) ++ load +{ + increase_load_count (); +} +@end + + +static int load_count = 0; + +int increase_load_count (void) +{ + load_count++; +} + +int main (void) +{ + if (load_count != 4) + abort (); + + return 0; +} diff --git a/gcc/testsuite/objc.dg/special/load-category-1a.m b/gcc/testsuite/objc.dg/special/load-category-1a.m new file mode 100644 index 00000000000..f516e7dfa3d --- /dev/null +++ b/gcc/testsuite/objc.dg/special/load-category-1a.m @@ -0,0 +1,22 @@ +/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */ + +#include <stdlib.h> +#include <objc/objc.h> +#include <objc/runtime.h> + +#include "load-category-1.h" + +@implementation TestClass2 ++ initialize { return self; } ++ load +{ + increase_load_count (); +} +@end + +@implementation TestClass1 (Category) ++ load +{ + increase_load_count (); +} +@end diff --git a/gcc/testsuite/objc.dg/special/special.exp b/gcc/testsuite/objc.dg/special/special.exp index fdc90ecc6b5..dd443808c05 100644 --- a/gcc/testsuite/objc.dg/special/special.exp +++ b/gcc/testsuite/objc.dg/special/special.exp @@ -1,5 +1,5 @@ # GCC Objective-C testsuite that uses the `dg.exp' driver. -# Copyright (C) 1997, 2001, 2007 Free Software Foundation, Inc. +# Copyright (C) 1997, 2001, 2007, 2010 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -56,6 +56,33 @@ if ![string match "" $lines] then { } } +# +# load-category-1 test +# +# This test is similar to the one above. We compile load-category-1.m +# and load-category-1a.m, link them together, and execute the result. +set add_flags "additional_flags=-I${srcdir}/../../libobjc" +lappend add_flags "additional_flags=-fgnu-runtime" +set lines [objc_target_compile "$srcdir/$subdir/load-category-1a.m" "load-category-1a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "load-category-1a.o" +} else { + dg-runtest "$srcdir/$subdir/load-category-1.m" "load-category-1a.o" "-I${srcdir}/../../libobjc -fgnu-runtime" + file delete load-category-1a.o +} + +if [istarget "*-*-darwin*" ] { +set add_flags "" +lappend add_flags "additional_flags=-fnext-runtime" +set lines [objc_target_compile "$srcdir/$subdir/load-category-1a.m" "load-category-1a.o" object $add_flags ] +if ![string match "" $lines] then { + fail "load-category-1a.o" +} else { + dg-runtest "$srcdir/$subdir/load-category-1.m" "load-category-1a.o" "-fnext-runtime" + file delete load-category-1a.o +} +} + # All done. dg-finish diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index 56bfe2e9afb..3cebc765202 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,5 +1,17 @@ 2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com> + PR libobjc/16110 + * init.c (__objc_send_message_in_list): Renamed to + __objc_send_load_using_method_list. Do not take an 'op' argument. + Register the 'load' selector if needed. + (__objc_send_load): Do not register the 'load' selector. Updated + call to __objc_send_message_in_list. + (__objc_create_classes_tree): Add the class of any claimed + category that was loaded in the module to the list of classes for + which we try to execute +load. + +2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com> + * objc-private/common.h: When DEBUG is defined, include <stdio.h>. Updated comments. * init.c (__objc_tree_insert_class): Use %p, not %x, when printing diff --git a/libobjc/init.c b/libobjc/init.c index 3c64f5bb7ed..d4d7abb4f46 100644 --- a/libobjc/init.c +++ b/libobjc/init.c @@ -44,8 +44,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define OBJC_VERSION 8 #define PROTOCOL_VERSION 2 -/* This list contains all modules currently loaded into the - runtime. */ +/* This list contains modules currently loaded into the runtime and + for which the +load method has not been called yet. */ static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */ /* This list contains all proto_list's not yet assigned class @@ -359,37 +359,49 @@ __objc_tree_print (objc_class_tree *tree, int level) #endif /* Walks on a linked list of methods in the reverse order and executes - all the methods corresponding to `op' selector. Walking in the - reverse order assures the +load of class is executed first and then - +load of categories because of the way in which categories are - added to the class methods. */ + all the methods corresponding to the `+load' selector. Walking in + the reverse order assures the +load of class is executed first and + then +load of categories because of the way in which categories are + added to the class methods. This function needs to be called with + the objc_runtime_mutex locked. */ static void -__objc_send_message_in_list (struct objc_method_list *method_list, Class class, SEL op) +__objc_send_load_using_method_list (struct objc_method_list *method_list, Class class) { + static SEL load_selector = 0; int i; - if (! method_list) + if (!method_list) return; - /* First execute the `op' message in the following method lists. */ - __objc_send_message_in_list (method_list->method_next, class, op); + /* This needs no lock protection because we are called with the + objc_runtime_mutex locked. */ + if (!load_selector) + load_selector = sel_registerName ("load"); + + /* method_list is a linked list of method lists; since we're + executing in reverse order, we need to do the next list before we + do this one. */ + __objc_send_load_using_method_list (method_list->method_next, class); /* Search the method list. */ for (i = 0; i < method_list->method_count; i++) { struct objc_method *mth = &method_list->method_list[i]; - if (mth->method_name && sel_eq (mth->method_name, op) + /* We are searching for +load methods that we haven't executed + yet. */ + if (mth->method_name && sel_eq (mth->method_name, load_selector) && ! objc_hash_is_key_in_hash (__objc_load_methods, mth->method_imp)) { - /* Add this method into the +load hash table. */ + /* Add this method into the +load hash table, so we won't + execute it again next time. */ objc_hash_add (&__objc_load_methods, mth->method_imp, mth->method_imp); DEBUG_PRINTF ("sending +load in class: %s\n", class->name); - /* The method was found and wasn't previously executed. */ + /* Call +load. */ (*mth->method_imp) ((id)class, mth->method_name); break; @@ -397,18 +409,16 @@ __objc_send_message_in_list (struct objc_method_list *method_list, Class class, } } +/* This function needs to be called with the objc_runtime_mutex + locked. */ static void __objc_send_load (objc_class_tree *tree, int level __attribute__ ((__unused__))) { - static SEL load_sel = 0; Class class = tree->class; struct objc_method_list *method_list = class->class_pointer->methods; - if (! load_sel) - load_sel = sel_registerName ("load"); - - __objc_send_message_in_list (method_list, class, load_sel); + __objc_send_load_using_method_list (method_list, class); } static void @@ -580,8 +590,8 @@ __objc_exec_class (struct objc_module *module) previous_constructors = 1; } - /* Save the module pointer for later processing. (not currently - used). */ + /* Save the module pointer so that later we remember to call +load + on all classes and categories on it. */ objc_mutex_lock (__objc_runtime_mutex); __objc_module_list = list_cons (module, __objc_module_list); @@ -717,14 +727,16 @@ __objc_exec_class (struct objc_module *module) objc_mutex_unlock (__objc_runtime_mutex); } +/* This function needs to be called with the objc_runtime_mutex + locked. */ static void objc_send_load (void) { - if (! __objc_module_list) + if (!__objc_module_list) return; /* Try to find out if all the classes loaded so far also have their - superclasses known to the runtime. We suppose that the objects + superclasses known to the runtime. We suppose that the objects that are allocated in the +load method are in general of a class declared in the same module. */ if (unresolved_classes) @@ -742,7 +754,7 @@ objc_send_load (void) /* If we still have classes for whom we don't have yet their super classes known to the runtime we don't send the +load - messages. */ + messages yet. */ if (unresolved_classes) return; } @@ -791,6 +803,25 @@ __objc_create_classes_tree (struct objc_module *module) objc_tree_insert_class (class); } + + /* Now iterate over "claimed" categories too (ie, categories that + extend a class that has already been loaded by the runtime), and + insert them in the classes tree hiearchy too. Otherwise, if you + add a category, its +load method would not be called if the class + is already loaded in the runtime. It the category is + "unclaimed", ie, we haven't loaded the main class yet, postpone + sending +load as we want to execute +load from the class before + we execute the one from the category. */ + for (i = 0; i < symtab->cat_def_cnt; ++i) + { + struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt]; + Class class = objc_getClass (category->class_name); + + /* If the class for the category exists then append its + methods. */ + if (class) + objc_tree_insert_class (class); + } } static void |