| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- //
- // FLEXObjcInternal.mm
- // FLEX
- //
- // Created by Tanner Bennett on 11/1/18.
- //
- /*
- * Copyright (c) 2005-2007 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@
- */
- #import "FLEXObjcInternal.h"
- #import <objc/runtime.h>
- #import <malloc/malloc.h>
- #define ALWAYS_INLINE inline __attribute__((always_inline))
- #define NEVER_INLINE inline __attribute__((noinline))
- // The macros below are copied straight from
- // objc-internal.h, objc-private.h, objc-object.h, and objc-config.h with
- // as few modifications as possible. Changes are noted in boxed comments.
- // https://opensource.apple.com/source/objc4/objc4-723/
- // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-internal.h.auto.html
- // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-private.h.auto.html
- // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-config.h.auto.html
- // https://opensource.apple.com/source/objc4/objc4-723/runtime/objc-object.h.auto.html
- /////////////////////
- // objc-internal.h //
- /////////////////////
- #if TARGET_OS_OSX && __x86_64__
- // 64-bit Mac - tag bit is LSB
- # define OBJC_MSB_TAGGED_POINTERS 0
- #else
- // Everything else - tag bit is MSB
- # define OBJC_MSB_TAGGED_POINTERS 1
- #endif
- #define _OBJC_TAG_INDEX_MASK 0x7
- // array slot includes the tag bit itself
- #define _OBJC_TAG_SLOT_COUNT 16
- #define _OBJC_TAG_SLOT_MASK 0xf
- #define _OBJC_TAG_EXT_INDEX_MASK 0xff
- // array slot has no extra bits
- #define _OBJC_TAG_EXT_SLOT_COUNT 256
- #define _OBJC_TAG_EXT_SLOT_MASK 0xff
- #if OBJC_MSB_TAGGED_POINTERS
- # define _OBJC_TAG_MASK (1UL<<63)
- # define _OBJC_TAG_INDEX_SHIFT 60
- # define _OBJC_TAG_SLOT_SHIFT 60
- # define _OBJC_TAG_PAYLOAD_LSHIFT 4
- # define _OBJC_TAG_PAYLOAD_RSHIFT 4
- # define _OBJC_TAG_EXT_MASK (0xfUL<<60)
- # define _OBJC_TAG_EXT_INDEX_SHIFT 52
- # define _OBJC_TAG_EXT_SLOT_SHIFT 52
- # define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 12
- # define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
- #else
- # define _OBJC_TAG_MASK 1UL
- # define _OBJC_TAG_INDEX_SHIFT 1
- # define _OBJC_TAG_SLOT_SHIFT 0
- # define _OBJC_TAG_PAYLOAD_LSHIFT 0
- # define _OBJC_TAG_PAYLOAD_RSHIFT 4
- # define _OBJC_TAG_EXT_MASK 0xfUL
- # define _OBJC_TAG_EXT_INDEX_SHIFT 4
- # define _OBJC_TAG_EXT_SLOT_SHIFT 4
- # define _OBJC_TAG_EXT_PAYLOAD_LSHIFT 0
- # define _OBJC_TAG_EXT_PAYLOAD_RSHIFT 12
- #endif
- //////////////////////////////////////
- // originally _objc_isTaggedPointer //
- //////////////////////////////////////
- static BOOL flex_isTaggedPointer(const void *ptr)
- {
- return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
- }
- ///////////////////
- // objc-config.h //
- ///////////////////
- // Define SUPPORT_INDEXED_ISA=1 on platforms that store the class in the isa
- // field as an index into a class table.
- #if __ARM_ARCH_7K__ >= 2
- # define SUPPORT_INDEXED_ISA 1
- #else
- # define SUPPORT_INDEXED_ISA 0
- #endif
- // Define SUPPORT_PACKED_ISA=1 on platforms that store the class in the isa
- // field as a maskable pointer with other data around it.
- #if (!__LP64__ || TARGET_OS_WIN32 || TARGET_OS_SIMULATOR)
- # define SUPPORT_PACKED_ISA 0
- #else
- # define SUPPORT_PACKED_ISA 1
- #endif
- // Define SUPPORT_NONPOINTER_ISA=1 on any platform that may store something
- // in the isa field that is not a raw pointer.
- #if !SUPPORT_INDEXED_ISA && !SUPPORT_PACKED_ISA
- # define SUPPORT_NONPOINTER_ISA 0
- #else
- # define SUPPORT_NONPOINTER_ISA 1
- #endif
- ////////////////////
- // objc-private.h //
- ////////////////////
- union isa_t
- {
- isa_t() { }
- isa_t(uintptr_t value) : bits(value) { }
-
- Class cls;
- uintptr_t bits;
-
- #if SUPPORT_PACKED_ISA
-
- // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
- // nonpointer must be the LSB (fixme or get rid of it)
- // shiftcls must occupy the same bits that a real class pointer would
- // bits + RC_ONE is equivalent to extra_rc + 1
- // RC_HALF is the high bit of extra_rc (i.e. half of its range)
-
- // future expansion:
- // uintptr_t fast_rr : 1; // no r/r overrides
- // uintptr_t lock : 2; // lock for atomic property, @synch
- // uintptr_t extraBytes : 1; // allocated with extra bytes
-
- # if __arm64__
- # define ISA_MASK 0x0000000ffffffff8ULL
- # define ISA_MAGIC_MASK 0x000003f000000001ULL
- # define ISA_MAGIC_VALUE 0x000001a000000001ULL
- struct {
- uintptr_t nonpointer : 1;
- uintptr_t has_assoc : 1;
- uintptr_t has_cxx_dtor : 1;
- uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000
- uintptr_t magic : 6;
- uintptr_t weakly_referenced : 1;
- uintptr_t deallocating : 1;
- uintptr_t has_sidetable_rc : 1;
- uintptr_t extra_rc : 19;
- # define RC_ONE (1ULL<<45)
- # define RC_HALF (1ULL<<18)
- };
-
- # elif __x86_64__
- # define ISA_MASK 0x00007ffffffffff8ULL
- # define ISA_MAGIC_MASK 0x001f800000000001ULL
- # define ISA_MAGIC_VALUE 0x001d800000000001ULL
- struct {
- uintptr_t nonpointer : 1;
- uintptr_t has_assoc : 1;
- uintptr_t has_cxx_dtor : 1;
- uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
- uintptr_t magic : 6;
- uintptr_t weakly_referenced : 1;
- uintptr_t deallocating : 1;
- uintptr_t has_sidetable_rc : 1;
- uintptr_t extra_rc : 8;
- # define RC_ONE (1ULL<<56)
- # define RC_HALF (1ULL<<7)
- };
-
- # else
- # error unknown architecture for packed isa
- # endif
-
- // SUPPORT_PACKED_ISA
- #endif
-
-
- #if SUPPORT_INDEXED_ISA
-
- # if __ARM_ARCH_7K__ >= 2
-
- # define ISA_INDEX_IS_NPI 1
- # define ISA_INDEX_MASK 0x0001FFFC
- # define ISA_INDEX_SHIFT 2
- # define ISA_INDEX_BITS 15
- # define ISA_INDEX_COUNT (1 << ISA_INDEX_BITS)
- # define ISA_INDEX_MAGIC_MASK 0x001E0001
- # define ISA_INDEX_MAGIC_VALUE 0x001C0001
- struct {
- uintptr_t nonpointer : 1;
- uintptr_t has_assoc : 1;
- uintptr_t indexcls : 15;
- uintptr_t magic : 4;
- uintptr_t has_cxx_dtor : 1;
- uintptr_t weakly_referenced : 1;
- uintptr_t deallocating : 1;
- uintptr_t has_sidetable_rc : 1;
- uintptr_t extra_rc : 7;
- # define RC_ONE (1ULL<<25)
- # define RC_HALF (1ULL<<6)
- };
-
- # else
- # error unknown architecture for indexed isa
- # endif
-
- // SUPPORT_INDEXED_ISA
- #endif
-
- };
- ///////////////////
- // objc-object.h //
- ///////////////////
- ////////////////////////////////////////////////
- // originally objc_object::isExtTaggedPointer //
- ////////////////////////////////////////////////
- static BOOL flex_isExtTaggedPointer(const void *ptr)
- {
- return ((uintptr_t)ptr & _OBJC_TAG_EXT_MASK) == _OBJC_TAG_EXT_MASK;
- }
- struct flex_objc_object {
- isa_t isa;
- };
- //////////////////////////////////////////////////////////
- // Returns nil on platforms without nonpointer isa. //
- // Supporting those platforms would be too complicated //
- // for such a niche feature anyway. - @NSExceptional //
- // //
- // Code modified from objc_object::ISA() on 11/04/18 //
- //////////////////////////////////////////////////////////
- static id flex_getIsa(const flex_objc_object *object) {
- #if SUPPORT_NONPOINTER_ISA
- if (object->isa.nonpointer) {
- return object_getClass((__bridge id)object);
- }
- return (__bridge Class)(void *)object->isa.bits;
- #else
- return nil;
- #endif
- }
- /////////////////////////////////////
- // FLEXObjectInternal //
- // No Apple code beyond this point //
- /////////////////////////////////////
- extern "C" {
- /// Assumes memory is valid and readable.
- /// https://blog.timac.org/2016/1124-testing-if-an-arbitrary-pointer-is-a-valid-objective-c-object/
- BOOL FLEXPointerIsValidObjcObject(const void * ptr)
- {
- uintptr_t pointer = (uintptr_t)ptr;
-
- if (!ptr) {
- return NO;
- }
-
- // Tagged pointers have 0x1 set, no other valid pointers do
- // objc-internal.h -> _objc_isTaggedPointer()
- if (flex_isTaggedPointer(ptr) || flex_isExtTaggedPointer(ptr)) {
- return YES;
- }
-
- // Check pointer alignment
- if ((pointer % sizeof(uintptr_t)) != 0) {
- return NO;
- }
-
- // From LLDB:
- // Pointers in a class_t will only have bits 0 through 46 set,
- // so if any pointer has bits 47 through 63 high, we know that this is not a valid isa
- // http://llvm.org/svn/llvm-project/lldb/trunk/examples/summaries/cocoa/objc_runtime.py
- if ((pointer & 0xFFFF800000000000) != 0) {
- return NO;
- }
-
- // http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html :
- if (flex_getIsa((const flex_objc_object *)ptr)) {
- return YES;
- }
-
- return NO;
- }
-
- }
|