xref: /netbsd-src/external/gpl3/gcc.old/dist/libobjc/accessors.m (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
136ac495dSmrg/* GNU Objective C Runtime accessors functions
2*8feb0f0bSmrg   Copyright (C) 2010-2020 Free Software Foundation, Inc.
336ac495dSmrg   Contributed by Nicola Pero
436ac495dSmrg
536ac495dSmrgThis file is part of GCC.
636ac495dSmrg
736ac495dSmrgGCC is free software; you can redistribute it and/or modify it under the
836ac495dSmrgterms of the GNU General Public License as published by the Free Software
936ac495dSmrgFoundation; either version 3, or (at your option) any later version.
1036ac495dSmrg
1136ac495dSmrgGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1236ac495dSmrgWARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1336ac495dSmrgFOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
1436ac495dSmrgdetails.
1536ac495dSmrg
1636ac495dSmrgUnder Section 7 of GPL version 3, you are granted additional
1736ac495dSmrgpermissions described in the GCC Runtime Library Exception, version
1836ac495dSmrg3.1, as published by the Free Software Foundation.
1936ac495dSmrg
2036ac495dSmrgYou should have received a copy of the GNU General Public License and
2136ac495dSmrga copy of the GCC Runtime Library Exception along with this program;
2236ac495dSmrgsee the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
2336ac495dSmrg<http://www.gnu.org/licenses/>.  */
2436ac495dSmrg
2536ac495dSmrg#include "objc-private/common.h"
2636ac495dSmrg#include "objc/objc.h"
2736ac495dSmrg#include "objc/thr.h"
2836ac495dSmrg#include <string.h>                    /* For memcpy */
2936ac495dSmrg
3036ac495dSmrg/* This file contains functions that the compiler uses when
3136ac495dSmrg   synthesizing accessors (getters/setters) for properties.  The
3236ac495dSmrg   functions are part of the ABI, but are meant to be used by the
3336ac495dSmrg   compiler and not by users; for this reason, they are not declared
3436ac495dSmrg   in public header files.  The compiler automatically generates
3536ac495dSmrg   declarations for these functions.  */
3636ac495dSmrg
3736ac495dSmrg/* Properties can be "atomic", which requires protecting them from
3836ac495dSmrg   concurrency issues using a lock.  Unfortunately, we can't have a
3936ac495dSmrg   lock for each property, so we'll go with a small pool of locks.
4036ac495dSmrg   Any time a property is accessed in an "atomic" way, we pick a
4136ac495dSmrg   random lock from the pool (random, but always the same one for the
4236ac495dSmrg   same property of the same object) and use it to protect access to
4336ac495dSmrg   the property.
4436ac495dSmrg
4536ac495dSmrg   The size of the pool is currently 16.  A bigger pool can help
4636ac495dSmrg   reduce contention, ie, reduce the chances that two threads,
4736ac495dSmrg   operating on unrelated properties, will have to wait for each other
4836ac495dSmrg   because the properties use the same lock.  16 seems big enough at
4936ac495dSmrg   the moment.  */
5036ac495dSmrg#define ACCESSORS_NUMBER_OF_LOCKS 16
5136ac495dSmrg
5236ac495dSmrg#define ACCESSORS_HASH(POINTER) ((((size_t)POINTER >> 8) ^ (size_t)POINTER) & (ACCESSORS_NUMBER_OF_LOCKS - 1))
5336ac495dSmrg
5436ac495dSmrgstatic objc_mutex_t accessors_locks[ACCESSORS_NUMBER_OF_LOCKS];
5536ac495dSmrg
5636ac495dSmrg/* This is called at startup to setup the locks.  */
5736ac495dSmrgvoid
5836ac495dSmrg__objc_accessors_init (void)
5936ac495dSmrg{
6036ac495dSmrg  int i;
6136ac495dSmrg
6236ac495dSmrg  for (i = 0; i < ACCESSORS_NUMBER_OF_LOCKS; i++)
6336ac495dSmrg    accessors_locks[i] = objc_mutex_allocate ();
6436ac495dSmrg}
6536ac495dSmrg
6636ac495dSmrg/* The property accessors automatically call various methods from the
6736ac495dSmrg   Foundation library (eg, GNUstep-base).  These methods are not
6836ac495dSmrg   implemented here, but we need to declare them so we can compile the
6936ac495dSmrg   runtime.  The Foundation library will need to provide
7036ac495dSmrg   implementations of these methods (most likely in the root class,
7136ac495dSmrg   eg, NSObject) as the accessors only work with objects of classes
7236ac495dSmrg   that implement these methods.  */
7336ac495dSmrg@interface _libobjcNSObject
7436ac495dSmrg- (id) copyWithZone: (void *)zone;
7536ac495dSmrg- (id) mutableCopyWithZone: (void *)zone;
7636ac495dSmrg@end
7736ac495dSmrg#define COPY(X)         [((_libobjcNSObject *)(X)) copyWithZone: NULL]
7836ac495dSmrg#define MUTABLE_COPY(X) [((_libobjcNSObject *)(X)) mutableCopyWithZone: NULL]
7936ac495dSmrg
8036ac495dSmrg
8136ac495dSmrg#if OBJC_WITH_GC
8236ac495dSmrg
8336ac495dSmrg#  define AUTORELEASE(X)  (X)
8436ac495dSmrg#  define RELEASE(X)
8536ac495dSmrg#  define RETAIN(X)       (X)
8636ac495dSmrg
8736ac495dSmrg#else
8836ac495dSmrg
8936ac495dSmrg@interface _libobjcNSObject (RetainReleaseMethods)
9036ac495dSmrg- (id) autorelease;
9136ac495dSmrg- (oneway void) release;
9236ac495dSmrg- (id) retain;
9336ac495dSmrg@end
9436ac495dSmrg#  define AUTORELEASE(X)  [((_libobjcNSObject *)(X)) autorelease]
9536ac495dSmrg#  define RELEASE(X)      [((_libobjcNSObject *)(X)) release]
9636ac495dSmrg#  define RETAIN(X)       [((_libobjcNSObject *)(X)) retain]
9736ac495dSmrg
9836ac495dSmrg#endif
9936ac495dSmrg
10036ac495dSmrg/* The compiler uses this function when implementing some synthesized
10136ac495dSmrg   getters for properties of type 'id'.  */
10236ac495dSmrgid
10336ac495dSmrgobjc_getProperty (id self, SEL __attribute__((unused)) _cmd, ptrdiff_t offset, BOOL is_atomic)
10436ac495dSmrg{
10536ac495dSmrg  if (self != nil)
10636ac495dSmrg    {
10736ac495dSmrg      id *pointer_to_ivar = (id *)((char *)self + offset);
10836ac495dSmrg
10936ac495dSmrg
11036ac495dSmrg      if (is_atomic == NO)
11136ac495dSmrg	{
11236ac495dSmrg	  /* Note that in this case, we do not RETAIN/AUTORELEASE the
11336ac495dSmrg	     returned value.  The programmer should do it if it is
11436ac495dSmrg	     needed.  Since access is non-atomic, other threads can be
11536ac495dSmrg	     ignored and the caller has full control of what happens
11636ac495dSmrg	     to the object and whether it needs to be RETAINed or not,
11736ac495dSmrg	     so it makes sense to leave the decision to him/her.  This
11836ac495dSmrg	     is also what the Apple/NeXT runtime does.  */
11936ac495dSmrg	  return *pointer_to_ivar;
12036ac495dSmrg	}
12136ac495dSmrg      else
12236ac495dSmrg	{
12336ac495dSmrg	  objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (pointer_to_ivar)];
12436ac495dSmrg	  id result;
12536ac495dSmrg
12636ac495dSmrg	  objc_mutex_lock (lock);
12736ac495dSmrg	  result = RETAIN (*(pointer_to_ivar));
12836ac495dSmrg	  objc_mutex_unlock (lock);
12936ac495dSmrg
13036ac495dSmrg	  return AUTORELEASE (result);
13136ac495dSmrg	}
13236ac495dSmrg    }
13336ac495dSmrg
13436ac495dSmrg  return nil;
13536ac495dSmrg}
13636ac495dSmrg
13736ac495dSmrg/* The compiler uses this function when implementing some synthesized
13836ac495dSmrg   setters for properties of type 'id'.
13936ac495dSmrg
14036ac495dSmrg   PS: Note how 'should_copy' is declared 'BOOL' but then actually
14136ac495dSmrg   takes values from 0 to 2.  This hack was introduced by Apple; we
14236ac495dSmrg   do the same for compatibility reasons.  */
14336ac495dSmrgvoid
14436ac495dSmrgobjc_setProperty (id self, SEL __attribute__((unused)) _cmd, ptrdiff_t offset, id new_value, BOOL is_atomic, BOOL should_copy)
14536ac495dSmrg{
14636ac495dSmrg  if (self != nil)
14736ac495dSmrg    {
14836ac495dSmrg      id *pointer_to_ivar = (id *)((char *)self + offset);
14936ac495dSmrg      id retained_value;
15036ac495dSmrg#if !OBJC_WITH_GC
15136ac495dSmrg      id old_value;
15236ac495dSmrg#endif
15336ac495dSmrg
15436ac495dSmrg      switch (should_copy)
15536ac495dSmrg	{
15636ac495dSmrg	case 0: /* retain */
15736ac495dSmrg	  {
15836ac495dSmrg	    if (*pointer_to_ivar == new_value)
15936ac495dSmrg	      return;
16036ac495dSmrg	    retained_value = RETAIN (new_value);
16136ac495dSmrg	    break;
16236ac495dSmrg	  }
16336ac495dSmrg	case 2: /* mutable copy */
16436ac495dSmrg	  {
16536ac495dSmrg	    retained_value = MUTABLE_COPY (new_value);
16636ac495dSmrg	    break;
16736ac495dSmrg	  }
16836ac495dSmrg	case 1: /* copy */
16936ac495dSmrg	default:
17036ac495dSmrg	  {
17136ac495dSmrg	    retained_value = COPY (new_value);
17236ac495dSmrg	    break;
17336ac495dSmrg	  }
17436ac495dSmrg	}
17536ac495dSmrg
17636ac495dSmrg      if (is_atomic == NO)
17736ac495dSmrg	{
17836ac495dSmrg#if !OBJC_WITH_GC
17936ac495dSmrg	  old_value = *pointer_to_ivar;
18036ac495dSmrg#endif
18136ac495dSmrg	  *pointer_to_ivar = retained_value;
18236ac495dSmrg	}
18336ac495dSmrg      else
18436ac495dSmrg	{
18536ac495dSmrg	  objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (pointer_to_ivar)];
18636ac495dSmrg
18736ac495dSmrg	  objc_mutex_lock (lock);
18836ac495dSmrg#if !OBJC_WITH_GC
18936ac495dSmrg	  old_value = *pointer_to_ivar;
19036ac495dSmrg#endif
19136ac495dSmrg	  *pointer_to_ivar = retained_value;
19236ac495dSmrg	  objc_mutex_unlock (lock);
19336ac495dSmrg	}
19436ac495dSmrg#if !OBJC_WITH_GC
19536ac495dSmrg      RELEASE (old_value);
19636ac495dSmrg#endif
19736ac495dSmrg    }
19836ac495dSmrg}
19936ac495dSmrg
20036ac495dSmrg/* The compiler uses this function when implementing some synthesized
20136ac495dSmrg   getters for properties of arbitrary C types.  The data is just
20236ac495dSmrg   copied.  Compatibility Note: this function does not exist in the
20336ac495dSmrg   Apple/NeXT runtime.  */
20436ac495dSmrgvoid
20536ac495dSmrgobjc_getPropertyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong)
20636ac495dSmrg{
20736ac495dSmrg  if (is_atomic == NO)
20836ac495dSmrg    memcpy (destination, source, size);
20936ac495dSmrg  else
21036ac495dSmrg    {
21136ac495dSmrg      objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (source)];
21236ac495dSmrg
21336ac495dSmrg      objc_mutex_lock (lock);
21436ac495dSmrg      memcpy (destination, source, size);
21536ac495dSmrg      objc_mutex_unlock (lock);
21636ac495dSmrg    }
21736ac495dSmrg}
21836ac495dSmrg
21936ac495dSmrg/* The compiler uses this function when implementing some synthesized
22036ac495dSmrg   setters for properties of arbitrary C types.  The data is just
22136ac495dSmrg   copied.  Compatibility Note: this function does not exist in the
22236ac495dSmrg   Apple/NeXT runtime.  */
22336ac495dSmrgvoid
22436ac495dSmrgobjc_setPropertyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong)
22536ac495dSmrg{
22636ac495dSmrg  if (is_atomic == NO)
22736ac495dSmrg    memcpy (destination, source, size);
22836ac495dSmrg  else
22936ac495dSmrg    {
23036ac495dSmrg      objc_mutex_t lock = accessors_locks[ACCESSORS_HASH (destination)];
23136ac495dSmrg
23236ac495dSmrg      objc_mutex_lock (lock);
23336ac495dSmrg      memcpy (destination, source, size);
23436ac495dSmrg      objc_mutex_unlock (lock);
23536ac495dSmrg    }
23636ac495dSmrg}
23736ac495dSmrg
23836ac495dSmrg/* This is the function that the Apple/NeXT runtime has instead of
23936ac495dSmrg   objc_getPropertyStruct and objc_setPropertyStruct.  We include it
24036ac495dSmrg   for API compatibility (just for people who may have used
24136ac495dSmrg   objc_copyStruct on the NeXT runtime thinking it was a public API);
24236ac495dSmrg   the compiler never generates calls to it with the GNU runtime.
24336ac495dSmrg   This function is clumsy because it requires two locks instead of
24436ac495dSmrg   one.  */
24536ac495dSmrgvoid
24636ac495dSmrgobjc_copyStruct (void *destination, const void *source, ptrdiff_t size, BOOL is_atomic, BOOL __attribute__((unused)) has_strong)
24736ac495dSmrg{
24836ac495dSmrg  if (is_atomic == NO)
24936ac495dSmrg    memcpy (destination, source, size);
25036ac495dSmrg  else
25136ac495dSmrg    {
25236ac495dSmrg      /* We don't know which one is the property, so we have to lock
25336ac495dSmrg	 both.  One of them is most likely a temporary buffer in the
25436ac495dSmrg	 local stack and we really wouldn't want to lock it (our
25536ac495dSmrg	 objc_getPropertyStruct and objc_setPropertyStruct functions
25636ac495dSmrg	 don't lock it).  Note that if we're locking more than one
25736ac495dSmrg	 accessor lock at once, we need to always lock them in the
25836ac495dSmrg	 same order to avoid deadlocks.  */
25936ac495dSmrg      objc_mutex_t first_lock;
26036ac495dSmrg      objc_mutex_t second_lock;
26136ac495dSmrg
26236ac495dSmrg      if (ACCESSORS_HASH (source) == ACCESSORS_HASH (destination))
26336ac495dSmrg	{
26436ac495dSmrg	  /* A lucky collision.  */
26536ac495dSmrg	  first_lock = accessors_locks[ACCESSORS_HASH (source)];
26636ac495dSmrg	  objc_mutex_lock (first_lock);
26736ac495dSmrg	  memcpy (destination, source, size);
26836ac495dSmrg	  objc_mutex_unlock (first_lock);
26936ac495dSmrg	  return;
27036ac495dSmrg	}
27136ac495dSmrg
27236ac495dSmrg      if (ACCESSORS_HASH (source) > ACCESSORS_HASH (destination))
27336ac495dSmrg	{
27436ac495dSmrg	  first_lock = accessors_locks[ACCESSORS_HASH (source)];
27536ac495dSmrg	  second_lock = accessors_locks[ACCESSORS_HASH (destination)];
27636ac495dSmrg	}
27736ac495dSmrg      else
27836ac495dSmrg	{
27936ac495dSmrg	  first_lock = accessors_locks[ACCESSORS_HASH (destination)];
28036ac495dSmrg	  second_lock = accessors_locks[ACCESSORS_HASH (source)];
28136ac495dSmrg	}
28236ac495dSmrg
28336ac495dSmrg      objc_mutex_lock (first_lock);
28436ac495dSmrg      objc_mutex_lock (second_lock);
28536ac495dSmrg      memcpy (destination, source, size);
28636ac495dSmrg      objc_mutex_unlock (second_lock);
28736ac495dSmrg      objc_mutex_unlock (first_lock);
28836ac495dSmrg    }
28936ac495dSmrg}
290