From patchwork Sat Oct 8 17:53:37 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicola Pero X-Patchwork-Id: 118563 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id B5543B6FA2 for ; Sun, 9 Oct 2011 04:54:03 +1100 (EST) Received: (qmail 7311 invoked by alias); 8 Oct 2011 17:54:01 -0000 Received: (qmail 7296 invoked by uid 22791); 8 Oct 2011 17:53:59 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, TW_BJ X-Spam-Check-By: sourceware.org Received: from fencepost.gnu.org (HELO fencepost.gnu.org) (140.186.70.10) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 08 Oct 2011 17:53:45 +0000 Received: from eggs.gnu.org ([140.186.70.92]:56153) by fencepost.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1RCb5k-00041D-FF for gcc-patches@gnu.org; Sat, 08 Oct 2011 13:53:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RCb5j-00017R-3X for gcc-patches@gnu.org; Sat, 08 Oct 2011 13:53:44 -0400 Received: from smtp191.iad.emailsrvr.com ([207.97.245.191]:48837) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RCb5j-000174-0Z for gcc-patches@gnu.org; Sat, 08 Oct 2011 13:53:43 -0400 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp39.relay.iad1a.emailsrvr.com (SMTP Server) with ESMTP id E00F39836C for ; Sat, 8 Oct 2011 13:53:40 -0400 (EDT) Received: by smtp39.relay.iad1a.emailsrvr.com (Authenticated sender: nicola.pero-AT-meta-innovation.com) with ESMTPSA id 4CB159836B for ; Sat, 8 Oct 2011 13:53:40 -0400 (EDT) From: Nicola Pero Subject: Patch for PR libobjc/50428 ("Consider changing semantics of +initialize so that it is inherited") Date: Sat, 8 Oct 2011 18:53:37 +0100 Message-Id: <6285556D-C008-4F35-A5B0-8717EE3F378A@meta-innovation.com> To: gcc-patches@gnu.org Mime-Version: 1.0 (Apple Message framework v1084) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 207.97.245.191 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch implements the change discussed in libobjc/50428. Traditionally, the Apple runtime "inherits" +initialize, meaning that if a class doesn't implement it, but the superclass does, the superclass's implementation gets executed the first time a method of the class is invoked. Instead, the GNU runtime traditionally doesn't "inherit" +initialize, meaning in that situation, no +initialize is executed. The idea is that with the GNU runtime you wouldn't have to worry about protecting your +initialize against multiple executions. But, in practice, people seem to protect +initialize methods all the same even with the GNU runtime, and they supply the following two explanations of why: * It is generally considered good practice to protect +initialize methods against multiple exclusions because it allows the code to run without changes with the Apple/NeXT runtime. * The runtime doesn't prevent programmers from invoking +initialize directly. You are not supposed to do it, but some beginners do, which is why a number of frameworks (including GNUstep) protect all +initialize methods against multiple executions all the same even when using the GNU runtime and even ignoring the existence of the Apple/NeXT runtime (!!). Because of these two reasons, it seems that everyone's really protecting their +initialize methods against multiple executions all the same! So the difference in behaviour between the GNU runtime and the Apple/NeXT one is not really helping anyone; but it makes it harder to port code written for the Apple/NeXT runtime to the GNU runtime. Programmers writing code for the Apple/NeXT runtime assume that +initialize methods are "inherited", so they may write code which expects such methods to be called multiple times, once per subclass. That code would compile on the GNU runtime but not work. Fixing the code so that it works with both runtimes is not necessarily trivial in some situations, for example if the classes are dynamically created at runtime. So the difference in behaviour is not really helping anyone, but it's making life hard for some people who are porting software to run on the GNU runtime. This patch (originally submitted by Richard Frith-Macdonald in a private email, and revised by me) changes the behaviour of the GNU runtime to match the one of the Apple/NeXT one. This makes it easier to port software to use the GNU runtime. A testcase is included; I tested the patch on an Apple Mac OS X 10.6.8, making sure that the testcase behaves in the same way with the Apple/NeXT and GNU runtimes. Committed to trunk. Thanks PS: This change absolutely deserves a mention in the GCC 4.7 release notes. But I'll work on the release notes separately, once we are in stage 2 or so. :-) Index: gcc/doc/objc.texi =================================================================== --- gcc/doc/objc.texi (revision 179710) +++ gcc/doc/objc.texi (working copy) @@ -635,7 +635,8 @@ following class does this: + (void)initialize @{ - class_ivar_set_gcinvisible (self, "weakPointer", YES); + if (self == objc_lookUpClass ("WeakPointer")) + class_ivar_set_gcinvisible (self, "weakPointer", YES); @} - initWithPointer:(const void*)p Index: gcc/ChangeLog =================================================================== --- gcc/ChangeLog (revision 179710) +++ gcc/ChangeLog (working copy) @@ -1,3 +1,9 @@ +2011-10-08 Nicola Pero + + PR libobjc/50428 + * doc/objc.texi (Garbage Collection): Updated example to protect + +initialize against execution in subclasses. + 2011-10-07 Richard Henderson * doc/extend.texi (__builtin_shuffle): Improve the description to Index: gcc/testsuite/ChangeLog =================================================================== --- gcc/testsuite/ChangeLog (revision 179710) +++ gcc/testsuite/ChangeLog (working copy) @@ -1,3 +1,8 @@ +2011-10-08 Nicola Pero + + PR libobjc/50428 + * objc/execute/initialize-1.m: New test. + 2011-10-08 Paul Thomas PR fortran/47844 Index: gcc/testsuite/objc/execute/initialize-1.m =================================================================== --- gcc/testsuite/objc/execute/initialize-1.m (revision 0) +++ gcc/testsuite/objc/execute/initialize-1.m (revision 0) @@ -0,0 +1,47 @@ +/* Contributed by Nicola Pero - Sat 8 Oct 2011 16:47:48 BST */ +#include + +/* Test that if a class has no +initialize method, the superclass + implementation is called. */ + +static int class_variable = 0; + +@interface TestClass +{ + Class isa; +} ++ (void) initialize; ++ (int) classVariable; +@end + +@implementation TestClass ++ (void) initialize +{ + class_variable++; +} ++ (int) classVariable +{ + return class_variable; +} +@end + +@interface TestSubClass : TestClass +@end + +@implementation TestSubClass +@end + +int main (void) +{ + if ([TestClass classVariable] != 1) + { + abort (); + } + + if ([TestSubClass classVariable] != 2) + { + abort (); + } + + return 0; +} Index: libobjc/sendmsg.c =================================================================== --- libobjc/sendmsg.c (revision 179710) +++ libobjc/sendmsg.c (working copy) @@ -516,34 +516,13 @@ __objc_send_initialize (Class class) { SEL op = sel_registerName ("initialize"); - IMP imp = 0; - struct objc_method_list * method_list = class->class_pointer->methods; - - while (method_list) + struct objc_method *method = search_for_method_in_hierarchy (class->class_pointer, + op); + + if (method) { - int i; - struct objc_method * method; - - for (i = 0; i < method_list->method_count; i++) - { - method = &(method_list->method_list[i]); - if (method->method_name - && method->method_name->sel_id == op->sel_id) - { - imp = method->method_imp; - break; - } - } - - if (imp) - break; - - method_list = method_list->method_next; - } - if (imp) - { DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name); - (*imp) ((id) class, op); + (*method->method_imp) ((id)class, op); DEBUG_PRINTF (" end of [%s +initialize]\n", class->name); } #ifdef DEBUG Index: libobjc/ChangeLog =================================================================== --- libobjc/ChangeLog (revision 179710) +++ libobjc/ChangeLog (working copy) @@ -1,3 +1,14 @@ +2011-10-08 Richard Frith-Macdonald + Nicola Pero + + PR libobjc/50428 + * sendmsg.c (__objc_send_initialize): If a class does not have an + +initialize method, search for an +initialize method in the + superclass and in the ancestor classes and execute the first one + that is found. This makes the GNU runtime behave in the same way + as the Apple/NeXT runtime with respect to +initialize methods and + subclassing. + 2011-08-06 Nicola Pero PR libobjc/50002