diff --git a/JSONKit.m b/JSONKit.m index fb9fe39..2841258 100644 --- a/JSONKit.m +++ b/JSONKit.m @@ -109,6 +109,8 @@ The code in isValidCodePoint() is derived from the ICU code in #import "JSONKit.h" +#include + //#include #include #include @@ -222,18 +224,48 @@ The code in isValidCodePoint() is derived from the ICU code in #define JK_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) JK_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__)) #endif // defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3) -#if !(__OBJC2__ && __LP64__) -# define JK_SUPPORT_TAGGED_POINTERS 0 +#if defined (__OBJC2__) && __OBJC2__ +#define JK_MODERN_RUNTIME 1 +#else // defined (__OBJC2__) && __OBJC2__ +#define JK_MODERN_RUNTIME 0 +#endif // defined (__OBJC2__) && __OBJC2__ + +#if !(JK_MODERN_RUNTIME && __LP64__) +#define JK_SUPPORT_TAGGED_POINTERS 0 +#else // !(JK_MODERN_RUNTIME && __LP64__) +#define JK_SUPPORT_TAGGED_POINTERS 1 +#endif // !(JK_MODERN_RUNTIME && __LP64__) + +#if !JK_SUPPORT_TAGGED_POINTERS || ((TARGET_OS_OSX || TARGET_OS_MACCATALYST) && __x86_64__) +#define JK_SUPPORT_MSB_TAGGED_POINTERS 0 +#else // !JK_SUPPORT_TAGGED_POINTERS || ((TARGET_OS_OSX || TARGET_OS_MACCATALYST) && __x86_64__) +#define JK_SUPPORT_MSB_TAGGED_POINTERS 1 +#endif // !JK_SUPPORT_TAGGED_POINTERS || ((TARGET_OS_OSX || TARGET_OS_MACCATALYST) && __x86_64__) + +#if !JK_SUPPORT_MSB_TAGGED_POINTERS || \ + (defined (__IPHONE_OS_VERSION_MIN_REQUIRED) && \ + (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_14_0)) || \ + (defined (__WATCH_OS_VERSION_MIN_REQUIRED) && \ + (__WATCH_OS_VERSION_MIN_REQUIRED < __WATCHOS_7_0)) || \ + (defined (__TV_OS_VERSION_MIN_REQUIRED) && \ + (__TV_OS_VERSION_MIN_REQUIRED < __TVOS_14_0)) +#define JK_SUPPORT_SPLIT_TAGGED_POINTERS 0 #else -# define JK_SUPPORT_TAGGED_POINTERS 1 +#define JK_SUPPORT_SPLIT_TAGGED_POINTERS 1 #endif -#if !JK_SUPPORT_TAGGED_POINTERS || !TARGET_OS_IPHONE -# define JK_SUPPORT_MSB_TAGGED_POINTERS 0 -#else -# define JK_SUPPORT_MSB_TAGGED_POINTERS 1 -#endif +#if JK_MODERN_RUNTIME +#define JK_DECLARE_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME +#define JK_FAST_CLASS_REF(CLASSNAME) (Class)&OBJC_CLASS_$_ ## CLASSNAME +#define JK_FAST_CLASS_MATCH(OBJ, CLASSNAME) (JK_EXPECT_T(object_getClass(OBJ) == JK_FAST_CLASS_REF(CLASSNAME)) || \ + JK_EXPECT_T([OBJ isKindOfClass:JK_FAST_CLASS_REF(CLASSNAME)])) +JK_DECLARE_CLASS_REF(NSString); +JK_DECLARE_CLASS_REF(NSNumber); +JK_DECLARE_CLASS_REF(NSDictionary); +JK_DECLARE_CLASS_REF(NSArray); +JK_DECLARE_CLASS_REF(NSNull); +#endif // JK_MODERN_RUNTIME @class JKArray, JKDictionaryEnumerator, JKDictionary; @@ -359,7 +391,9 @@ The code in isValidCodePoint() is derived from the ICU code in typedef struct JKConstPtrRange JKConstPtrRange; typedef struct JKRange JKRange; typedef struct JKManagedBuffer JKManagedBuffer; +#if !JK_MODERN_RUNTIME typedef struct JKFastClassLookup JKFastClassLookup; +#endif #if JK_SUPPORT_TAGGED_POINTERS typedef struct JKFastTagLookup JKFastTagLookup; #endif @@ -466,6 +500,7 @@ The code in isValidCodePoint() is derived from the ICU code in BOOL mutableCollections; }; +#if !JK_MODERN_RUNTIME struct JKFastClassLookup { void *stringClass; void *numberClass; @@ -473,14 +508,12 @@ The code in isValidCodePoint() is derived from the ICU code in void *dictionaryClass; void *nullClass; }; +#endif #if JK_SUPPORT_TAGGED_POINTERS struct JKFastTagLookup { uintptr_t stringClass; uintptr_t numberClass; - uintptr_t arrayClass; - uintptr_t dictionaryClass; - uintptr_t nullClass; }; #endif @@ -494,7 +527,9 @@ The code in isValidCodePoint() is derived from the ICU code in JKManagedBuffer utf8ConversionBuffer; JKManagedBuffer stringBuffer; size_t atIndex; +#if !JK_MODERN_RUNTIME JKFastClassLookup fastClassLookup; +#endif #if JK_SUPPORT_TAGGED_POINTERS JKFastTagLookup fastTagLookup; #endif @@ -1063,18 +1098,26 @@ - (id)objectForKey:(id)aKey return((entryForKey != NULL) ? entryForKey->object : NULL); } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (void)getObjects:(id *)objects andKeys:(id *)keys +#pragma clang diagnostic pop { - NSParameterAssert((entry != NULL) && (count <= capacity)); - NSUInteger atEntry = 0UL; NSUInteger arrayIdx = 0UL; - for(atEntry = 0UL; atEntry < capacity; atEntry++) { - if(JK_EXPECT_T(entry[atEntry].key != NULL)) { - NSCParameterAssert((entry[atEntry].object != NULL) && (arrayIdx < count)); - if(JK_EXPECT_T(keys != NULL)) { keys[arrayIdx] = entry[atEntry].key; } - if(JK_EXPECT_T(objects != NULL)) { objects[arrayIdx] = entry[atEntry].object; } - arrayIdx++; + return [self getObjects:objects andKeys:keys count:count]; +} + +- (void)getObjects:(id *)objects andKeys:(id *)keys count:(NSUInteger)arrayCount +{ + NSParameterAssert((entry != NULL) && (count <= capacity) && (arrayCount <= count)); + NSUInteger atEntry = 0UL; NSUInteger arrayIdx = 0UL; + for(atEntry = 0UL; atEntry < capacity && arrayIdx < arrayCount; atEntry++) { + if(JK_EXPECT_T(entry[atEntry].key != NULL)) { + NSCParameterAssert((entry[atEntry].object != NULL) && (arrayIdx < count)); + if(JK_EXPECT_T(keys != NULL)) { keys[arrayIdx] = entry[atEntry].key; } + if(JK_EXPECT_T(objects != NULL)) { objects[arrayIdx] = entry[atEntry].object; } + arrayIdx++; + } } - } } - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len @@ -2591,8 +2634,7 @@ JK_STATIC_INLINE JKHash jk_encode_object_hash(const void *objectPtr) { // XXX XXX XXX XXX #if JK_SUPPORT_TAGGED_POINTERS -JK_STATIC_INLINE BOOL jk_is_tagged_pointer(const void *objectPtr) -{ +JK_STATIC_INLINE BOOL jk_is_tagged_pointer(const void *objectPtr) { #if JK_SUPPORT_MSB_TAGGED_POINTERS return(((intptr_t)objectPtr) < 0); #else @@ -2600,10 +2642,30 @@ JK_STATIC_INLINE BOOL jk_is_tagged_pointer(const void *objectPtr) #endif } -JK_STATIC_INLINE uintptr_t jk_get_tagged_pointer_tag(const void *objectPtr) -{ -#if JK_SUPPORT_MSB_TAGGED_POINTERS +#if !JK_SUPPORT_SPLIT_TAGGED_POINTERS && JK_SUPPORT_MSB_TAGGED_POINTERS +typedef uintptr_t (*jk_get_tagged_pointer_tag_t)(const void *objectPtr); + +static uintptr_t jk_get_split_tagged_pointer_tag(const void *objectPtr) { + return(((uintptr_t)objectPtr) & 0x07); +} + +static uintptr_t jk_get_msb_tagged_pointer_tag(const void *objectPtr) { return(((uintptr_t)objectPtr) >> 60); +} + +static jk_get_tagged_pointer_tag_t jk_get_tagged_pointer_tag_func; + +static __attribute__((constructor)) void jk_get_tagged_pointer_tag_init(void) { + if(@available(iOS 14.0, watchOS 7.0, tvOS 14.0, *)) { jk_get_tagged_pointer_tag_func = jk_get_split_tagged_pointer_tag; } + else { jk_get_tagged_pointer_tag_func = jk_get_msb_tagged_pointer_tag; } +} +#endif + +JK_STATIC_INLINE uintptr_t jk_get_tagged_pointer_tag(const void *objectPtr) { +#if JK_SUPPORT_SPLIT_TAGGED_POINTERS + return(((uintptr_t)objectPtr) & 0x07); +#elif JK_SUPPORT_MSB_TAGGED_POINTERS + return jk_get_tagged_pointer_tag_func(objectPtr); #else return(((uintptr_t)objectPtr) & 0x0F); #endif @@ -2615,28 +2677,29 @@ JK_STATIC_INLINE int jk_object_class(JKEncodeState *encodeState, id object) { if(jk_is_tagged_pointer(object)) { uintptr_t objectTag = jk_get_tagged_pointer_tag(object); - if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.stringClass)) { return(JKClassString); } - else if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.numberClass)) { return(JKClassNumber); } - else if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.dictionaryClass)) { return(JKClassDictionary); } - else if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.arrayClass)) { return(JKClassArray); } - else if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.nullClass)) { return(JKClassNull); } + if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.stringClass)) { return(JKClassString); } + else if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.numberClass)) { return(JKClassNumber); } else { - if(JK_EXPECT_T([object isKindOfClass:[NSString class]])) { encodeState->fastTagLookup.stringClass = objectTag; return(JKClassString); } - else if(JK_EXPECT_T([object isKindOfClass:[NSNumber class]])) { encodeState->fastTagLookup.numberClass = objectTag; return(JKClassNumber); } - else if(JK_EXPECT_T([object isKindOfClass:[NSDictionary class]])) { encodeState->fastTagLookup.dictionaryClass = objectTag; return(JKClassDictionary); } - else if(JK_EXPECT_T([object isKindOfClass:[NSArray class]])) { encodeState->fastTagLookup.arrayClass = objectTag; return(JKClassArray); } - else if(JK_EXPECT_T([object isKindOfClass:[NSNull class]])) { encodeState->fastTagLookup.nullClass = objectTag; return(JKClassNull); } + if(JK_FAST_CLASS_MATCH(object, NSString)) { encodeState->fastTagLookup.stringClass = objectTag; return(JKClassString); } + else if(JK_FAST_CLASS_MATCH(object, NSNumber)) { encodeState->fastTagLookup.numberClass = objectTag; return(JKClassNumber); } } } else { #endif +#if JK_MODERN_RUNTIME + if(JK_FAST_CLASS_MATCH(object, NSString)) { return(JKClassString); } + else if(JK_FAST_CLASS_MATCH(object, NSNumber)) { return(JKClassNumber); } + else if(JK_FAST_CLASS_MATCH(object, NSDictionary)) { return(JKClassDictionary); } + else if(JK_FAST_CLASS_MATCH(object, NSArray)) { return(JKClassArray); } + else if(JK_FAST_CLASS_MATCH(object, NSNull)) { return(JKClassNull); } +#else void *objectISA = *((void **)object); - if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.stringClass)) { return(JKClassString); } - else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.numberClass)) { return(JKClassNumber); } - else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.dictionaryClass)) { return(JKClassDictionary); } - else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.arrayClass)) { return(JKClassArray); } - else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.nullClass)) { return(JKClassNull); } + if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.stringClass)) { return(JKClassString); } + else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.numberClass)) { return(JKClassNumber); } + else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.dictionaryClass)) { return(JKClassDictionary); } + else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.arrayClass)) { return(JKClassArray); } + else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.nullClass)) { return(JKClassNull); } else { if(JK_EXPECT_T([object isKindOfClass:[NSString class]])) { encodeState->fastClassLookup.stringClass = objectISA; return(JKClassString); } else if(JK_EXPECT_T([object isKindOfClass:[NSNumber class]])) { encodeState->fastClassLookup.numberClass = objectISA; return(JKClassNumber); } @@ -2644,6 +2707,7 @@ JK_STATIC_INLINE int jk_object_class(JKEncodeState *encodeState, id object) { else if(JK_EXPECT_T([object isKindOfClass:[NSArray class]])) { encodeState->fastClassLookup.arrayClass = objectISA; return(JKClassArray); } else if(JK_EXPECT_T([object isKindOfClass:[NSNull class]])) { encodeState->fastClassLookup.nullClass = objectISA; return(JKClassNull); } } +#endif #if JK_SUPPORT_TAGGED_POINTERS } #endif @@ -2655,15 +2719,19 @@ JK_STATIC_INLINE BOOL jk_object_is_string(JKEncodeState *encodeState, id object) if(jk_is_tagged_pointer(object)) { uintptr_t objectTag = jk_get_tagged_pointer_tag(object); - if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.stringClass)) { return(YES); } - else if(JK_EXPECT_T([object isKindOfClass:[NSString class]])) { encodeState->fastTagLookup.stringClass = objectTag; return(YES); } + if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.stringClass)) { return(YES); } + else if(JK_FAST_CLASS_MATCH(object, NSString)) { encodeState->fastTagLookup.stringClass = objectTag; return(YES); } } else { #endif +#if JK_MODERN_RUNTIME + if(JK_FAST_CLASS_MATCH(object, NSString)) { return(YES); } +#else void *objectISA = *((void **)object); - if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.stringClass)) { return(YES); } - else if(JK_EXPECT_T([object isKindOfClass:[NSString class]])) { encodeState->fastClassLookup.stringClass = objectISA; return(YES); } + if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.stringClass)) { return(YES); } + else if(JK_EXPECT_T([object isKindOfClass:[NSString class]])) { encodeState->fastClassLookup.stringClass = objectISA; return(YES); } +#endif #if JK_SUPPORT_TAGGED_POINTERS } #endif