+class TimeLogger {
+ uint64_t mStart;
+ bool mRecord;
+ public:
+ TimeLogger(bool record = true)
+ : mStart(nanoseconds())
+ , mRecord(record)
+ { }
+
+ void log(const char *msg) {
+ if (mRecord) {
+ uint64_t end = nanoseconds();
+ _objc_inform("%.2f ms: %s", (end - mStart) / 1000000.0, msg);
+ mStart = nanoseconds();
+ }
+ }
+};
+
+enum { CacheLineSize = 64 };
+
+// StripedMap<T> is a map of void* -> T, sized appropriately
+// for cache-friendly lock striping.
+// For example, this may be used as StripedMap<spinlock_t>
+// or as StripedMap<SomeStruct> where SomeStruct stores a spin lock.
+template<typename T>
+class StripedMap {
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+ enum { StripeCount = 8 };
+#else
+ enum { StripeCount = 64 };
+#endif
+
+ struct PaddedT {
+ T value alignas(CacheLineSize);
+ };
+
+ PaddedT array[StripeCount];
+
+ static unsigned int indexForPointer(const void *p) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(p);
+ return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
+ }
+
+ public:
+ T& operator[] (const void *p) {
+ return array[indexForPointer(p)].value;
+ }
+ const T& operator[] (const void *p) const {
+ return const_cast<StripedMap<T>>(this)[p];
+ }
+
+ // Shortcuts for StripedMaps of locks.
+ void lockAll() {
+ for (unsigned int i = 0; i < StripeCount; i++) {
+ array[i].value.lock();
+ }
+ }
+
+ void unlockAll() {
+ for (unsigned int i = 0; i < StripeCount; i++) {
+ array[i].value.unlock();
+ }
+ }
+
+ void forceResetAll() {
+ for (unsigned int i = 0; i < StripeCount; i++) {
+ array[i].value.forceReset();
+ }
+ }
+
+ void defineLockOrder() {
+ for (unsigned int i = 1; i < StripeCount; i++) {
+ lockdebug_lock_precedes_lock(&array[i-1].value, &array[i].value);
+ }
+ }
+
+ void precedeLock(const void *newlock) {
+ // assumes defineLockOrder is also called
+ lockdebug_lock_precedes_lock(&array[StripeCount-1].value, newlock);
+ }
+
+ void succeedLock(const void *oldlock) {
+ // assumes defineLockOrder is also called
+ lockdebug_lock_precedes_lock(oldlock, &array[0].value);
+ }
+
+ const void *getLock(int i) {
+ if (i < StripeCount) return &array[i].value;
+ else return nil;
+ }
+
+#if DEBUG
+ StripedMap() {
+ // Verify alignment expectations.
+ uintptr_t base = (uintptr_t)&array[0].value;
+ uintptr_t delta = (uintptr_t)&array[1].value - base;
+ ASSERT(delta % CacheLineSize == 0);
+ ASSERT(base % CacheLineSize == 0);
+ }
+#else
+ constexpr StripedMap() {}
+#endif
+};
+
+
+// DisguisedPtr<T> acts like pointer type T*, except the
+// stored value is disguised to hide it from tools like `leaks`.
+// nil is disguised as itself so zero-filled memory works as expected,
+// which means 0x80..00 is also disguised as itself but we don't care.
+// Note that weak_entry_t knows about this encoding.
+template <typename T>
+class DisguisedPtr {
+ uintptr_t value;
+
+ static uintptr_t disguise(T* ptr) {
+ return -(uintptr_t)ptr;
+ }
+
+ static T* undisguise(uintptr_t val) {
+ return (T*)-val;
+ }
+
+ public:
+ DisguisedPtr() { }
+ DisguisedPtr(T* ptr)
+ : value(disguise(ptr)) { }
+ DisguisedPtr(const DisguisedPtr<T>& ptr)
+ : value(ptr.value) { }
+
+ DisguisedPtr<T>& operator = (T* rhs) {
+ value = disguise(rhs);
+ return *this;
+ }
+ DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {
+ value = rhs.value;
+ return *this;
+ }
+
+ operator T* () const {
+ return undisguise(value);
+ }
+ T* operator -> () const {
+ return undisguise(value);
+ }
+ T& operator * () const {
+ return *undisguise(value);
+ }
+ T& operator [] (size_t i) const {
+ return undisguise(value)[i];
+ }
+
+ // pointer arithmetic operators omitted
+ // because we don't currently use them anywhere
+};
+
+// fixme type id is weird and not identical to objc_object*
+static inline bool operator == (DisguisedPtr<objc_object> lhs, id rhs) {
+ return lhs == (objc_object *)rhs;
+}
+static inline bool operator != (DisguisedPtr<objc_object> lhs, id rhs) {
+ return lhs != (objc_object *)rhs;
+}
+
+
+// Storage for a thread-safe chained hook function.
+// get() returns the value for calling.
+// set() installs a new function and returns the old one for chaining.
+// More precisely, set() writes the old value to a variable supplied by
+// the caller. get() and set() use appropriate barriers so that the
+// old value is safely written to the variable before the new value is
+// called to use it.
+//
+// T1: store to old variable; store-release to hook variable
+// T2: load-acquire from hook variable; call it; called hook loads old variable
+
+template <typename Fn>
+class ChainedHookFunction {
+ std::atomic<Fn> hook{nil};
+
+public:
+ constexpr ChainedHookFunction(Fn f) : hook{f} { };
+
+ Fn get() {
+ return hook.load(std::memory_order_acquire);
+ }
+
+ void set(Fn newValue, Fn *oldVariable)
+ {
+ Fn oldValue = hook.load(std::memory_order_relaxed);
+ do {
+ *oldVariable = oldValue;
+ } while (!hook.compare_exchange_weak(oldValue, newValue,
+ std::memory_order_release,
+ std::memory_order_relaxed));
+ }
+};
+
+
+// A small vector for use as a global variable. Only supports appending and
+// iteration. Stores up to N elements inline, and multiple elements in a heap
+// allocation. There is no attempt to amortize reallocation cost; this is
+// intended to be used in situation where a small number of elements is
+// common, more might happen, and significantly more is very rare.
+//
+// This does not clean up its allocation, and thus cannot be used as a local
+// variable or member of something with limited lifetime.
+
+template <typename T, unsigned InlineCount>
+class GlobalSmallVector {
+ static_assert(std::is_pod<T>::value, "SmallVector requires POD types");
+
+protected:
+ unsigned count{0};
+ union {
+ T inlineElements[InlineCount];
+ T *elements{nullptr};
+ };
+
+public:
+ void append(const T &val) {
+ if (count < InlineCount) {
+ // We have space. Store the new value inline.
+ inlineElements[count] = val;
+ } else if (count == InlineCount) {
+ // Inline storage is full. Switch to a heap allocation.
+ T *newElements = (T *)malloc((count + 1) * sizeof(T));
+ memcpy(newElements, inlineElements, count * sizeof(T));
+ newElements[count] = val;
+ elements = newElements;
+ } else {
+ // Resize the heap allocation and append.
+ elements = (T *)realloc(elements, (count + 1) * sizeof(T));
+ elements[count] = val;
+ }
+ count++;
+ }
+
+ const T *begin() const {
+ return count <= InlineCount ? inlineElements : elements;
+ }
+
+ const T *end() const {
+ return begin() + count;
+ }
+};
+
+// A small vector that cleans up its internal memory allocation when destroyed.
+template <typename T, unsigned InlineCount>
+class SmallVector: public GlobalSmallVector<T, InlineCount> {
+public:
+ ~SmallVector() {
+ if (this->count > InlineCount)
+ free(this->elements);
+ }
+
+ template <unsigned OtherCount>
+ void initFrom(const GlobalSmallVector<T, OtherCount> &other) {
+ ASSERT(this->count == 0);
+ this->count = (unsigned)(other.end() - other.begin());
+ if (this->count > InlineCount) {
+ this->elements = (T *)memdup(other.begin(), this->count * sizeof(T));
+ } else {
+ memcpy(this->inlineElements, other.begin(), this->count * sizeof(T));
+ }
+ }
+};
+
+// Pointer hash function.
+// This is not a terrific hash, but it is fast
+// and not outrageously flawed for our purposes.
+
+// Based on principles from http://locklessinc.com/articles/fast_hash/
+// and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
+#if __LP64__
+static inline uint32_t ptr_hash(uint64_t key)
+{
+ key ^= key >> 4;
+ key *= 0x8a970be7488fda55;
+ key ^= __builtin_bswap64(key);
+ return (uint32_t)key;
+}
+#else
+static inline uint32_t ptr_hash(uint32_t key)
+{
+ key ^= key >> 4;
+ key *= 0x5052acdb;
+ key ^= __builtin_bswap32(key);
+ return key;
+}
+#endif
+
+/*
+ Higher-quality hash function. This is measurably slower in some workloads.
+#if __LP64__
+ uint32_t ptr_hash(uint64_t key)
+{
+ key -= __builtin_bswap64(key);
+ key *= 0x8a970be7488fda55;
+ key ^= __builtin_bswap64(key);
+ key *= 0x8a970be7488fda55;
+ key ^= __builtin_bswap64(key);
+ return (uint32_t)key;
+}
+#else
+static uint32_t ptr_hash(uint32_t key)
+{
+ key -= __builtin_bswap32(key);
+ key *= 0x5052acdb;
+ key ^= __builtin_bswap32(key);
+ key *= 0x5052acdb;
+ key ^= __builtin_bswap32(key);
+ return key;
+}
+#endif
+*/
+
+
+
+// Lock declarations
+#include "objc-locks.h"
+
+// Inlined parts of objc_object's implementation
+#include "objc-object.h"
+