mirror of
https://github.com/darlinghq/darling-objc4.git
synced 2024-11-23 04:09:46 +00:00
150 lines
5.0 KiB
C
150 lines
5.0 KiB
C
/*
|
|
* Copyright (c) 2010-2011 Apple Inc. All rights reserved.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_START@
|
|
*
|
|
* This file contains Original Code and/or Modifications of Original Code
|
|
* as defined in and that are subject to the Apple Public Source License
|
|
* Version 2.0 (the 'License'). You may not use this file except in
|
|
* compliance with the License. Please obtain a copy of the License at
|
|
* http://www.opensource.apple.com/apsl/ and read it before using this
|
|
* file.
|
|
*
|
|
* The Original Code and all software distributed under the License are
|
|
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
* Please see the License for the specific language governing rights and
|
|
* limitations under the License.
|
|
*
|
|
* @APPLE_LICENSE_HEADER_END@
|
|
*/
|
|
|
|
#ifndef _OBJC_WEAK_H_
|
|
#define _OBJC_WEAK_H_
|
|
|
|
#include <objc/objc.h>
|
|
#include "objc-config.h"
|
|
|
|
__BEGIN_DECLS
|
|
|
|
/*
|
|
The weak table is a hash table governed by a single spin lock.
|
|
An allocated blob of memory, most often an object, but under GC any such
|
|
allocation, may have its address stored in a __weak marked storage location
|
|
through use of compiler generated write-barriers or hand coded uses of the
|
|
register weak primitive. Associated with the registration can be a callback
|
|
block for the case when one of the allocated chunks of memory is reclaimed.
|
|
The table is hashed on the address of the allocated memory. When __weak
|
|
marked memory changes its reference, we count on the fact that we can still
|
|
see its previous reference.
|
|
|
|
So, in the hash table, indexed by the weakly referenced item, is a list of
|
|
all locations where this address is currently being stored.
|
|
|
|
For ARC, we also keep track of whether an arbitrary object is being
|
|
deallocated by briefly placing it in the table just prior to invoking
|
|
dealloc, and removing it via objc_clear_deallocating just prior to memory
|
|
reclamation.
|
|
|
|
*/
|
|
|
|
// The address of a __weak variable.
|
|
// These pointers are stored disguised so memory analysis tools
|
|
// don't see lots of interior pointers from the weak table into objects.
|
|
typedef DisguisedPtr<objc_object *> weak_referrer_t;
|
|
|
|
#if __LP64__
|
|
#define PTR_MINUS_2 62
|
|
#else
|
|
#define PTR_MINUS_2 30
|
|
#endif
|
|
|
|
/**
|
|
* The internal structure stored in the weak references table.
|
|
* It maintains and stores
|
|
* a hash set of weak references pointing to an object.
|
|
* If out_of_line_ness != REFERRERS_OUT_OF_LINE then the set
|
|
* is instead a small inline array.
|
|
*/
|
|
#define WEAK_INLINE_COUNT 4
|
|
|
|
// out_of_line_ness field overlaps with the low two bits of inline_referrers[1].
|
|
// inline_referrers[1] is a DisguisedPtr of a pointer-aligned address.
|
|
// The low two bits of a pointer-aligned DisguisedPtr will always be 0b00
|
|
// (disguised nil or 0x80..00) or 0b11 (any other address).
|
|
// Therefore out_of_line_ness == 0b10 is used to mark the out-of-line state.
|
|
#define REFERRERS_OUT_OF_LINE 2
|
|
|
|
struct weak_entry_t {
|
|
DisguisedPtr<objc_object> referent;
|
|
union {
|
|
struct {
|
|
weak_referrer_t *referrers;
|
|
uintptr_t out_of_line_ness : 2;
|
|
uintptr_t num_refs : PTR_MINUS_2;
|
|
uintptr_t mask;
|
|
uintptr_t max_hash_displacement;
|
|
};
|
|
struct {
|
|
// out_of_line_ness field is low bits of inline_referrers[1]
|
|
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
|
|
};
|
|
};
|
|
|
|
bool out_of_line() {
|
|
return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
|
|
}
|
|
|
|
weak_entry_t& operator=(const weak_entry_t& other) {
|
|
memcpy(this, &other, sizeof(other));
|
|
return *this;
|
|
}
|
|
|
|
weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
|
|
: referent(newReferent)
|
|
{
|
|
inline_referrers[0] = newReferrer;
|
|
for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
|
|
inline_referrers[i] = nil;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* The global weak references table. Stores object ids as keys,
|
|
* and weak_entry_t structs as their values.
|
|
*/
|
|
struct weak_table_t {
|
|
weak_entry_t *weak_entries;
|
|
size_t num_entries;
|
|
uintptr_t mask;
|
|
uintptr_t max_hash_displacement;
|
|
};
|
|
|
|
enum WeakRegisterDeallocatingOptions {
|
|
ReturnNilIfDeallocating,
|
|
CrashIfDeallocating,
|
|
DontCheckDeallocating
|
|
};
|
|
|
|
/// Adds an (object, weak pointer) pair to the weak table.
|
|
id weak_register_no_lock(weak_table_t *weak_table, id referent,
|
|
id *referrer, WeakRegisterDeallocatingOptions deallocatingOptions);
|
|
|
|
/// Removes an (object, weak pointer) pair from the weak table.
|
|
void weak_unregister_no_lock(weak_table_t *weak_table, id referent, id *referrer);
|
|
|
|
#if DEBUG
|
|
/// Returns true if an object is weakly referenced somewhere.
|
|
bool weak_is_registered_no_lock(weak_table_t *weak_table, id referent);
|
|
#endif
|
|
|
|
/// Called on object destruction. Sets all remaining weak pointers to nil.
|
|
void weak_clear_no_lock(weak_table_t *weak_table, id referent);
|
|
|
|
__END_DECLS
|
|
|
|
#endif /* _OBJC_WEAK_H_ */
|