From 645617dd9cc3c19827574555f31df9787af63ed0 Mon Sep 17 00:00:00 2001 From: Jean-Charles BERTIN Date: Sun, 22 Nov 2020 18:48:47 +0100 Subject: [PATCH 1/5] Added support for fast class lookup. --- JSONKit.m | 62 +++++++++++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/JSONKit.m b/JSONKit.m index fb9fe39..f733a7d 100644 --- a/JSONKit.m +++ b/JSONKit.m @@ -234,6 +234,18 @@ The code in isValidCodePoint() is derived from the ICU code in # define JK_SUPPORT_MSB_TAGGED_POINTERS 1 #endif +#define JK_STATIC_CLASS_REF(CLASSNAME) ((Class)&OBJC_CLASS_$_ ## CLASSNAME) +#if __OBJC2__ +#define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME +#else +#define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME __asm(".objc_class_name_" # CLASSNAME) +#endif + +JK_DECLARE_STATIC_CLASS_REF(NSString); +JK_DECLARE_STATIC_CLASS_REF(NSNumber); +JK_DECLARE_STATIC_CLASS_REF(NSDictionary); +JK_DECLARE_STATIC_CLASS_REF(NSArray); +JK_DECLARE_STATIC_CLASS_REF(NSNull); @class JKArray, JKDictionaryEnumerator, JKDictionary; @@ -359,7 +371,6 @@ The code in isValidCodePoint() is derived from the ICU code in typedef struct JKConstPtrRange JKConstPtrRange; typedef struct JKRange JKRange; typedef struct JKManagedBuffer JKManagedBuffer; -typedef struct JKFastClassLookup JKFastClassLookup; #if JK_SUPPORT_TAGGED_POINTERS typedef struct JKFastTagLookup JKFastTagLookup; #endif @@ -466,14 +477,6 @@ The code in isValidCodePoint() is derived from the ICU code in BOOL mutableCollections; }; -struct JKFastClassLookup { - void *stringClass; - void *numberClass; - void *arrayClass; - void *dictionaryClass; - void *nullClass; -}; - #if JK_SUPPORT_TAGGED_POINTERS struct JKFastTagLookup { uintptr_t stringClass; @@ -494,7 +497,6 @@ The code in isValidCodePoint() is derived from the ICU code in JKManagedBuffer utf8ConversionBuffer; JKManagedBuffer stringBuffer; size_t atIndex; - JKFastClassLookup fastClassLookup; #if JK_SUPPORT_TAGGED_POINTERS JKFastTagLookup fastTagLookup; #endif @@ -2621,29 +2623,20 @@ JK_STATIC_INLINE int jk_object_class(JKEncodeState *encodeState, id object) { else if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.arrayClass)) { return(JKClassArray); } else if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.nullClass)) { return(JKClassNull); } 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_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { encodeState->fastTagLookup.stringClass = objectTag; return(JKClassString); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNumber)])) { encodeState->fastTagLookup.numberClass = objectTag; return(JKClassNumber); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSDictionary)])) { encodeState->fastTagLookup.dictionaryClass = objectTag; return(JKClassDictionary); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSArray)])) { encodeState->fastTagLookup.arrayClass = objectTag; return(JKClassArray); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNull)])) { encodeState->fastTagLookup.nullClass = objectTag; return(JKClassNull); } } } else { #endif - 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); } - 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); } - else if(JK_EXPECT_T([object isKindOfClass:[NSDictionary class]])) { encodeState->fastClassLookup.dictionaryClass = objectISA; return(JKClassDictionary); } - 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); } - } + if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { return(JKClassString); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNumber)])) { return(JKClassNumber); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSDictionary)])) { return(JKClassDictionary); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSArray)])) { return(JKClassArray); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNull)])) { return(JKClassNull); } #if JK_SUPPORT_TAGGED_POINTERS } #endif @@ -2656,14 +2649,11 @@ JK_STATIC_INLINE BOOL jk_object_is_string(JKEncodeState *encodeState, id 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); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { encodeState->fastTagLookup.stringClass = objectTag; return(YES); } } else { #endif - 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([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { return(YES); } #if JK_SUPPORT_TAGGED_POINTERS } #endif @@ -2963,8 +2953,8 @@ - (id)serializeObject:(id)object options:(JKSerializeOptionFlags)optionFlags enc unsigned char stackUTF8Buffer[JK_UTF8BUFFER_SIZE] JK_ALIGNED(64); jk_managedBuffer_setToStackBuffer(&encodeState->utf8ConversionBuffer, stackUTF8Buffer, sizeof(stackUTF8Buffer)); - if(((encodeOption & JKEncodeOptionCollectionObj) != 0UL) && (([object isKindOfClass:[NSArray class]] == NO) && ([object isKindOfClass:[NSDictionary class]] == NO))) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSArray or NSDictionary.", NSStringFromClass([object class])); goto errorExit; } - if(((encodeOption & JKEncodeOptionStringObj) != 0UL) && ([object isKindOfClass:[NSString class]] == NO)) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSString.", NSStringFromClass([object class])); goto errorExit; } + if(((encodeOption & JKEncodeOptionCollectionObj) != 0UL) && (([object isKindOfClass:JK_STATIC_CLASS_REF(NSArray)] == NO) && ([object isKindOfClass:JK_STATIC_CLASS_REF(NSDictionary)] == NO))) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSArray or NSDictionary.", NSStringFromClass([object class])); goto errorExit; } + if(((encodeOption & JKEncodeOptionStringObj) != 0UL) && ([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)] == NO)) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSString.", NSStringFromClass([object class])); goto errorExit; } if(jk_encode_add_atom_to_buffer(encodeState, object) == 0) { BOOL stackBuffer = ((encodeState->stringBuffer.flags & JKManagedBufferMustFree) == 0UL) ? YES : NO; From 7f2d333c92e7b0496d3ec972b8627df2f02d4b38 Mon Sep 17 00:00:00 2001 From: Jean-Charles BERTIN Date: Sun, 22 Nov 2020 18:49:23 +0100 Subject: [PATCH 2/5] Minor cleanup. --- JSONKit.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/JSONKit.m b/JSONKit.m index f733a7d..967cfb5 100644 --- a/JSONKit.m +++ b/JSONKit.m @@ -234,11 +234,11 @@ The code in isValidCodePoint() is derived from the ICU code in # define JK_SUPPORT_MSB_TAGGED_POINTERS 1 #endif -#define JK_STATIC_CLASS_REF(CLASSNAME) ((Class)&OBJC_CLASS_$_ ## CLASSNAME) +#define JK_STATIC_CLASS_REF(CLASSNAME) ((Class)&OBJC_CLASS_$_ ## CLASSNAME) #if __OBJC2__ -#define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME +# define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME #else -#define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME __asm(".objc_class_name_" # CLASSNAME) +# define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME __asm(".objc_class_name_" # CLASSNAME) #endif JK_DECLARE_STATIC_CLASS_REF(NSString); @@ -2648,12 +2648,12 @@ 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:JK_STATIC_CLASS_REF(NSString)])) { encodeState->fastTagLookup.stringClass = objectTag; return(YES); } + if(JK_EXPECT_T(objectTag == encodeState->fastTagLookup.stringClass)) { return(YES); } + else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { encodeState->fastTagLookup.stringClass = objectTag; return(YES); } } else { #endif - if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { return(YES); } + if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { return(YES); } #if JK_SUPPORT_TAGGED_POINTERS } #endif @@ -2954,7 +2954,7 @@ - (id)serializeObject:(id)object options:(JKSerializeOptionFlags)optionFlags enc jk_managedBuffer_setToStackBuffer(&encodeState->utf8ConversionBuffer, stackUTF8Buffer, sizeof(stackUTF8Buffer)); if(((encodeOption & JKEncodeOptionCollectionObj) != 0UL) && (([object isKindOfClass:JK_STATIC_CLASS_REF(NSArray)] == NO) && ([object isKindOfClass:JK_STATIC_CLASS_REF(NSDictionary)] == NO))) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSArray or NSDictionary.", NSStringFromClass([object class])); goto errorExit; } - if(((encodeOption & JKEncodeOptionStringObj) != 0UL) && ([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)] == NO)) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSString.", NSStringFromClass([object class])); goto errorExit; } + if(((encodeOption & JKEncodeOptionStringObj) != 0UL) && ([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)] == NO)) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSString.", NSStringFromClass([object class])); goto errorExit; } if(jk_encode_add_atom_to_buffer(encodeState, object) == 0) { BOOL stackBuffer = ((encodeState->stringBuffer.flags & JKManagedBufferMustFree) == 0UL) ? YES : NO; From 44e5ba4ad9857ac079955822c1dd4b89d6d6daa8 Mon Sep 17 00:00:00 2001 From: Jean-Charles BERTIN Date: Sun, 22 Nov 2020 18:50:06 +0100 Subject: [PATCH 3/5] Fixed tagged pointers for Apple Silicon, iOS 14.0, watchOS 7.0 and tvOS 14.0. --- JSONKit.m | 53 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/JSONKit.m b/JSONKit.m index 967cfb5..12b4a40 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 @@ -228,12 +230,24 @@ The code in isValidCodePoint() is derived from the ICU code in # define JK_SUPPORT_TAGGED_POINTERS 1 #endif -#if !JK_SUPPORT_TAGGED_POINTERS || !TARGET_OS_IPHONE +#if !JK_SUPPORT_TAGGED_POINTERS || ((TARGET_OS_OSX || TARGET_OS_MACCATALYST) && __x86_64__) # define JK_SUPPORT_MSB_TAGGED_POINTERS 0 #else # define JK_SUPPORT_MSB_TAGGED_POINTERS 1 #endif +#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_SPLIT_TAGGED_POINTERS 1 +#endif + #define JK_STATIC_CLASS_REF(CLASSNAME) ((Class)&OBJC_CLASS_$_ ## CLASSNAME) #if __OBJC2__ # define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME @@ -481,9 +495,6 @@ The code in isValidCodePoint() is derived from the ICU code in struct JKFastTagLookup { uintptr_t stringClass; uintptr_t numberClass; - uintptr_t arrayClass; - uintptr_t dictionaryClass; - uintptr_t nullClass; }; #endif @@ -2593,8 +2604,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 @@ -2602,10 +2612,29 @@ 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 @@ -2619,15 +2648,9 @@ JK_STATIC_INLINE int jk_object_class(JKEncodeState *encodeState, id 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); } else { if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { encodeState->fastTagLookup.stringClass = objectTag; return(JKClassString); } else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNumber)])) { encodeState->fastTagLookup.numberClass = objectTag; return(JKClassNumber); } - else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSDictionary)])) { encodeState->fastTagLookup.dictionaryClass = objectTag; return(JKClassDictionary); } - else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSArray)])) { encodeState->fastTagLookup.arrayClass = objectTag; return(JKClassArray); } - else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNull)])) { encodeState->fastTagLookup.nullClass = objectTag; return(JKClassNull); } } } else { From 5a906ed926c21711ecc5b4f548e2406af8febf8b Mon Sep 17 00:00:00 2001 From: Jean-Charles BERTIN Date: Sun, 22 Nov 2020 18:50:39 +0100 Subject: [PATCH 4/5] Revert fast class lookup for the old objc runtime. --- JSONKit.m | 139 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 93 insertions(+), 46 deletions(-) diff --git a/JSONKit.m b/JSONKit.m index 12b4a40..d694573 100644 --- a/JSONKit.m +++ b/JSONKit.m @@ -224,42 +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_OSX || TARGET_OS_MACCATALYST) && __x86_64__) -# 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)])) -#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_SPLIT_TAGGED_POINTERS 1 -#endif - -#define JK_STATIC_CLASS_REF(CLASSNAME) ((Class)&OBJC_CLASS_$_ ## CLASSNAME) -#if __OBJC2__ -# define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME -#else -# define JK_DECLARE_STATIC_CLASS_REF(CLASSNAME) extern void OBJC_CLASS_$_ ## CLASSNAME __asm(".objc_class_name_" # CLASSNAME) -#endif - -JK_DECLARE_STATIC_CLASS_REF(NSString); -JK_DECLARE_STATIC_CLASS_REF(NSNumber); -JK_DECLARE_STATIC_CLASS_REF(NSDictionary); -JK_DECLARE_STATIC_CLASS_REF(NSArray); -JK_DECLARE_STATIC_CLASS_REF(NSNull); +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; @@ -385,6 +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 @@ -491,6 +500,16 @@ The code in isValidCodePoint() is derived from the ICU code in BOOL mutableCollections; }; +#if !JK_MODERN_RUNTIME +struct JKFastClassLookup { + void *stringClass; + void *numberClass; + void *arrayClass; + void *dictionaryClass; + void *nullClass; +}; +#endif + #if JK_SUPPORT_TAGGED_POINTERS struct JKFastTagLookup { uintptr_t stringClass; @@ -508,6 +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 @@ -2624,6 +2646,7 @@ static uintptr_t jk_get_msb_tagged_pointer_tag(const void *objectPtr) { } 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; } @@ -2646,20 +2669,37 @@ 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); } + 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:JK_STATIC_CLASS_REF(NSString)])) { encodeState->fastTagLookup.stringClass = objectTag; return(JKClassString); } - else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNumber)])) { encodeState->fastTagLookup.numberClass = objectTag; return(JKClassNumber); } + 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_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { return(JKClassString); } - else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNumber)])) { return(JKClassNumber); } - else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSDictionary)])) { return(JKClassDictionary); } - else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSArray)])) { return(JKClassArray); } - else if(JK_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSNull)])) { return(JKClassNull); } +#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); } + 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); } + else if(JK_EXPECT_T([object isKindOfClass:[NSDictionary class]])) { encodeState->fastClassLookup.dictionaryClass = objectISA; return(JKClassDictionary); } + 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 @@ -2671,12 +2711,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:JK_STATIC_CLASS_REF(NSString)])) { 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_EXPECT_T([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)])) { return(YES); } +#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); } +#endif #if JK_SUPPORT_TAGGED_POINTERS } #endif @@ -2976,8 +3023,8 @@ - (id)serializeObject:(id)object options:(JKSerializeOptionFlags)optionFlags enc unsigned char stackUTF8Buffer[JK_UTF8BUFFER_SIZE] JK_ALIGNED(64); jk_managedBuffer_setToStackBuffer(&encodeState->utf8ConversionBuffer, stackUTF8Buffer, sizeof(stackUTF8Buffer)); - if(((encodeOption & JKEncodeOptionCollectionObj) != 0UL) && (([object isKindOfClass:JK_STATIC_CLASS_REF(NSArray)] == NO) && ([object isKindOfClass:JK_STATIC_CLASS_REF(NSDictionary)] == NO))) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSArray or NSDictionary.", NSStringFromClass([object class])); goto errorExit; } - if(((encodeOption & JKEncodeOptionStringObj) != 0UL) && ([object isKindOfClass:JK_STATIC_CLASS_REF(NSString)] == NO)) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSString.", NSStringFromClass([object class])); goto errorExit; } + if(((encodeOption & JKEncodeOptionCollectionObj) != 0UL) && (([object isKindOfClass:[NSArray class]] == NO) && ([object isKindOfClass:[NSDictionary class]] == NO))) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSArray or NSDictionary.", NSStringFromClass([object class])); goto errorExit; } + if(((encodeOption & JKEncodeOptionStringObj) != 0UL) && ([object isKindOfClass:[NSString class]] == NO)) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSString.", NSStringFromClass([object class])); goto errorExit; } if(jk_encode_add_atom_to_buffer(encodeState, object) == 0) { BOOL stackBuffer = ((encodeState->stringBuffer.flags & JKManagedBufferMustFree) == 0UL) ? YES : NO; From 76c192894cad738d0e24e188e979eba279947b01 Mon Sep 17 00:00:00 2001 From: Jean-Charles BERTIN Date: Sun, 22 Nov 2020 18:51:13 +0100 Subject: [PATCH 5/5] Fixed deprecated -getObjects:andKeys: method for JKDictionary class. --- JSONKit.m | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/JSONKit.m b/JSONKit.m index d694573..2841258 100644 --- a/JSONKit.m +++ b/JSONKit.m @@ -1098,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