Commit c07499dc by Nicola Pero Committed by Nicola Pero

In libobjc/: 2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>

In libobjc/:
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.
	
In gcc/testsuite/:
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.

From-SVN: r168122
parent c8613835
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> 2010-12-21 Steven Bosscher <steven@gcc.gnu.org>
PR middle-end/45310 PR middle-end/45310
......
/* 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
/* 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;
}
/* 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
# GCC Objective-C testsuite that uses the `dg.exp' driver. # 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 # 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 # it under the terms of the GNU General Public License as published by
...@@ -56,6 +56,33 @@ if ![string match "" $lines] then { ...@@ -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. # All done.
dg-finish dg-finish
2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com> 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>. * objc-private/common.h: When DEBUG is defined, include <stdio.h>.
Updated comments. Updated comments.
* init.c (__objc_tree_insert_class): Use %p, not %x, when printing * init.c (__objc_tree_insert_class): Use %p, not %x, when printing
......
...@@ -44,8 +44,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -44,8 +44,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define OBJC_VERSION 8 #define OBJC_VERSION 8
#define PROTOCOL_VERSION 2 #define PROTOCOL_VERSION 2
/* This list contains all modules currently loaded into the /* This list contains modules currently loaded into the runtime and
runtime. */ for which the +load method has not been called yet. */
static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */ static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */
/* This list contains all proto_list's not yet assigned class /* This list contains all proto_list's not yet assigned class
...@@ -359,37 +359,49 @@ __objc_tree_print (objc_class_tree *tree, int level) ...@@ -359,37 +359,49 @@ __objc_tree_print (objc_class_tree *tree, int level)
#endif #endif
/* Walks on a linked list of methods in the reverse order and executes /* Walks on a linked list of methods in the reverse order and executes
all the methods corresponding to `op' selector. Walking in the all the methods corresponding to the `+load' selector. Walking in
reverse order assures the +load of class is executed first and then the reverse order assures the +load of class is executed first and
+load of categories because of the way in which categories are then +load of categories because of the way in which categories are
added to the class methods. */ added to the class methods. This function needs to be called with
the objc_runtime_mutex locked. */
static void 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; int i;
if (! method_list) if (!method_list)
return; return;
/* First execute the `op' message in the following method lists. */ /* This needs no lock protection because we are called with the
__objc_send_message_in_list (method_list->method_next, class, op); 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. */ /* Search the method list. */
for (i = 0; i < method_list->method_count; i++) for (i = 0; i < method_list->method_count; i++)
{ {
struct objc_method *mth = &method_list->method_list[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)) && ! 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, objc_hash_add (&__objc_load_methods,
mth->method_imp, mth->method_imp,
mth->method_imp); mth->method_imp);
DEBUG_PRINTF ("sending +load in class: %s\n", class->name); 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); (*mth->method_imp) ((id)class, mth->method_name);
break; break;
...@@ -397,18 +409,16 @@ __objc_send_message_in_list (struct objc_method_list *method_list, Class class, ...@@ -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 static void
__objc_send_load (objc_class_tree *tree, __objc_send_load (objc_class_tree *tree,
int level __attribute__ ((__unused__))) int level __attribute__ ((__unused__)))
{ {
static SEL load_sel = 0;
Class class = tree->class; Class class = tree->class;
struct objc_method_list *method_list = class->class_pointer->methods; struct objc_method_list *method_list = class->class_pointer->methods;
if (! load_sel) __objc_send_load_using_method_list (method_list, class);
load_sel = sel_registerName ("load");
__objc_send_message_in_list (method_list, class, load_sel);
} }
static void static void
...@@ -580,8 +590,8 @@ __objc_exec_class (struct objc_module *module) ...@@ -580,8 +590,8 @@ __objc_exec_class (struct objc_module *module)
previous_constructors = 1; previous_constructors = 1;
} }
/* Save the module pointer for later processing. (not currently /* Save the module pointer so that later we remember to call +load
used). */ on all classes and categories on it. */
objc_mutex_lock (__objc_runtime_mutex); objc_mutex_lock (__objc_runtime_mutex);
__objc_module_list = list_cons (module, __objc_module_list); __objc_module_list = list_cons (module, __objc_module_list);
...@@ -717,10 +727,12 @@ __objc_exec_class (struct objc_module *module) ...@@ -717,10 +727,12 @@ __objc_exec_class (struct objc_module *module)
objc_mutex_unlock (__objc_runtime_mutex); objc_mutex_unlock (__objc_runtime_mutex);
} }
/* This function needs to be called with the objc_runtime_mutex
locked. */
static void static void
objc_send_load (void) objc_send_load (void)
{ {
if (! __objc_module_list) if (!__objc_module_list)
return; return;
/* Try to find out if all the classes loaded so far also have their /* Try to find out if all the classes loaded so far also have their
...@@ -742,7 +754,7 @@ objc_send_load (void) ...@@ -742,7 +754,7 @@ objc_send_load (void)
/* If we still have classes for whom we don't have yet their /* 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 super classes known to the runtime we don't send the +load
messages. */ messages yet. */
if (unresolved_classes) if (unresolved_classes)
return; return;
} }
...@@ -791,6 +803,25 @@ __objc_create_classes_tree (struct objc_module *module) ...@@ -791,6 +803,25 @@ __objc_create_classes_tree (struct objc_module *module)
objc_tree_insert_class (class); 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 static void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment