diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 2cd660f06..53ab65437 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -2627,6 +2627,7 @@ GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREPROCESSOR_DEFINITIONS = "PROFILE=1"; INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; diff --git a/InstrumentsTemplates/SystemTrace.tracetemplate b/InstrumentsTemplates/SystemTrace.tracetemplate new file mode 100644 index 000000000..48cc3e6ae Binary files /dev/null and b/InstrumentsTemplates/SystemTrace.tracetemplate differ diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index 519f0ecda..68b4c3468 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -1675,7 +1675,7 @@ - (ASCellNodeBlock)dataController:(ASDataController *)dataController nodeBlockAt if (node.interactionDelegate == nil) { node.interactionDelegate = strongSelf; } - if (_inverted) { + if (strongSelf.inverted) { node.transform = CATransform3DMakeScale(1, -1, 1) ; } return node; diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index e866548d5..781862fe6 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -957,9 +957,25 @@ - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize restrictedToSize:(ASLayoutElementSize)size relativeToParentSize:(CGSize)parentSize { + // Use a pthread specific to mark when this method is called re-entrant on same thread. + // We only want one calculateLayout signpost interval per thread. + // This is fast enough to do it unconditionally. + auto key = ASPthreadStaticKey(NULL); + BOOL isRootCall = (pthread_getspecific(key) == NULL); + if (isRootCall) { + pthread_setspecific(key, kCFBooleanTrue); + ASSignpostStart(ASSignpostCalculateLayout); + } + ASSizeRange styleAndParentSize = ASLayoutElementSizeResolve(self.style.size, parentSize); const ASSizeRange resolvedRange = ASSizeRangeIntersect(constrainedSize, styleAndParentSize); - return [self calculateLayoutThatFits:resolvedRange]; + ASLayout *result = [self calculateLayoutThatFits:resolvedRange]; + + if (isRootCall) { + pthread_setspecific(key, NULL); + ASSignpostEnd(ASSignpostCalculateLayout); + } + return result; } - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize diff --git a/Source/ASRunLoopQueue.mm b/Source/ASRunLoopQueue.mm index 7597e47d2..e45ac0999 100644 --- a/Source/ASRunLoopQueue.mm +++ b/Source/ASRunLoopQueue.mm @@ -19,7 +19,7 @@ #import #import #import - +#import #import #import #import @@ -78,16 +78,20 @@ - (void)threadMain return; } // The scope below is entered while already locked. @autorelease is crucial here; see PR 2890. + NSInteger count; @autoreleasepool { #if ASRunLoopQueueLoggingEnabled NSLog(@"ASDeallocQueue Processing: %lu objects destroyed", weakSelf->_queue.size()); #endif // Sometimes we release 10,000 objects at a time. Don't hold the lock while releasing. std::deque currentQueue = weakSelf->_queue; + count = currentQueue.size(); + ASSignpostStartCustom(ASSignpostDeallocQueueDrain, self, count); weakSelf->_queue = std::deque(); weakSelf->_queueLock.unlock(); currentQueue.clear(); } + ASSignpostEndCustom(ASSignpostDeallocQueueDrain, self, count, ASSignpostColorDefault); }); CFRunLoopRef runloop = CFRunLoopGetCurrent(); @@ -196,8 +200,69 @@ @interface ASRunLoopQueue () { @end +#if AS_KDEBUG_ENABLE +/** + * This is real, private CA API. Valid as of iOS 10. + */ +typedef enum { + kCATransactionPhasePreLayout, + kCATransactionPhasePreCommit, + kCATransactionPhasePostCommit, +} CATransactionPhase; + +@interface CATransaction (Private) ++ (void)addCommitHandler:(void(^)(void))block forPhase:(CATransactionPhase)phase; ++ (int)currentState; +@end +#endif + @implementation ASRunLoopQueue +#if AS_KDEBUG_ENABLE ++ (void)load +{ + [self registerCATransactionObservers]; +} + ++ (void)registerCATransactionObservers +{ + static BOOL privateCAMethodsExist; + static dispatch_block_t preLayoutHandler; + static dispatch_block_t preCommitHandler; + static dispatch_block_t postCommitHandler; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + privateCAMethodsExist = [CATransaction respondsToSelector:@selector(addCommitHandler:forPhase:)]; + privateCAMethodsExist &= [CATransaction respondsToSelector:@selector(currentState)]; + if (!privateCAMethodsExist) { + NSLog(@"Private CA methods are gone."); + } + preLayoutHandler = ^{ + ASSignpostStartCustom(ASSignpostCATransactionLayout, 0, [CATransaction currentState]); + }; + preCommitHandler = ^{ + int state = [CATransaction currentState]; + ASSignpostEndCustom(ASSignpostCATransactionLayout, 0, state, ASSignpostColorDefault); + ASSignpostStartCustom(ASSignpostCATransactionCommit, 0, state); + }; + postCommitHandler = ^{ + ASSignpostEndCustom(ASSignpostCATransactionCommit, 0, [CATransaction currentState], ASSignpostColorDefault); + // Can't add new observers inside an observer. rdar://problem/31253952 + dispatch_async(dispatch_get_main_queue(), ^{ + [self registerCATransactionObservers]; + }); + }; + }); + + if (privateCAMethodsExist) { + [CATransaction addCommitHandler:preLayoutHandler forPhase:kCATransactionPhasePreLayout]; + [CATransaction addCommitHandler:preCommitHandler forPhase:kCATransactionPhasePreCommit]; + [CATransaction addCommitHandler:postCommitHandler forPhase:kCATransactionPhasePostCommit]; + } +} + +#endif // AS_KDEBUG_ENABLE + - (instancetype)initWithRunLoop:(CFRunLoopRef)runloop retainObjects:(BOOL)retainsObjects handler:(void (^)(id _Nullable, BOOL))handlerBlock { if (self = [super init]) { @@ -275,7 +340,7 @@ - (void)processQueue return; } - ASProfilingSignpostStart(0, self); + ASSignpostStart(ASSignpostRunLoopQueueBatch); // Snatch the next batch of items. NSInteger maxCountToProcess = MIN(internalQueueCount, self.batchSize); @@ -329,7 +394,7 @@ - (void)processQueue CFRunLoopWakeUp(_runLoop); } - ASProfilingSignpostEnd(0, self); + ASSignpostEnd(ASSignpostRunLoopQueueBatch); } - (void)enqueue:(id)object diff --git a/Source/Base/ASAssert.m b/Source/Base/ASAssert.m index b52f2f4b3..7759ff53f 100644 --- a/Source/Base/ASAssert.m +++ b/Source/Base/ASAssert.m @@ -13,15 +13,9 @@ #import #import -// pthread_key_create must be called before the key can be used. This function does that. static pthread_key_t ASMainThreadAssertionsDisabledKey() { - static pthread_key_t ASMainThreadAssertionsDisabledKey; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - pthread_key_create(&ASMainThreadAssertionsDisabledKey, NULL); - }); - return ASMainThreadAssertionsDisabledKey; + return ASPthreadStaticKey(NULL); } BOOL ASMainThreadAssertionsAreDisabled() { diff --git a/Source/Base/ASBaseDefines.h b/Source/Base/ASBaseDefines.h index 2fedafdfa..b269096f4 100755 --- a/Source/Base/ASBaseDefines.h +++ b/Source/Base/ASBaseDefines.h @@ -215,6 +215,24 @@ #define AS_SUBCLASSING_RESTRICTED #endif +#define ASPthreadStaticKey(dtor) ({ \ + static dispatch_once_t onceToken; \ + static pthread_key_t key; \ + dispatch_once(&onceToken, ^{ \ + pthread_key_create(&key, dtor); \ + }); \ + key; \ +}) + +#define ASCreateOnce(expr) ({ \ + static dispatch_once_t onceToken; \ + static __typeof__(expr) staticVar; \ + dispatch_once(&onceToken, ^{ \ + staticVar = expr; \ + }); \ + staticVar; \ +}) + /// Ensure that class is of certain kind #define ASDynamicCast(x, c) ({ \ id __val = x;\ diff --git a/Source/Base/ASLog.h b/Source/Base/ASLog.h index 873702402..ae734e0ba 100644 --- a/Source/Base/ASLog.h +++ b/Source/Base/ASLog.h @@ -16,9 +16,45 @@ // #import +#import -#pragma once +/// The signposts we use. Signposts are grouped by color. The SystemTrace.tracetemplate file +/// should be kept up-to-date with these values. +typedef NS_ENUM(uint32_t, ASSignpostName) { + // Collection/Table (Blue) + ASSignpostDataControllerBatch = 300, // Alloc/layout nodes before collection update. + ASSignpostRangeControllerUpdate, // Ranges update pass. + ASSignpostCollectionUpdate, // Entire update process, from -endUpdates to [super perform…] + // Rendering (Green) + ASSignpostLayerDisplay = 325, // Client display callout. + ASSignpostRunLoopQueueBatch, // One batch of ASRunLoopQueue. + + // Layout (Purple) + ASSignpostCalculateLayout = 350, // Start of calculateLayoutThatFits to end. Max 1 per thread. + + // Misc (Orange) + ASSignpostDeallocQueueDrain = 375, // One chunk of dealloc queue work. arg0 is count. + ASSignpostCATransactionLayout, // The CA transaction commit layout phase. + ASSignpostCATransactionCommit // The CA transaction commit post-layout phase. +}; + +typedef NS_ENUM(uintptr_t, ASSignpostColor) { + ASSignpostColorBlue, + ASSignpostColorGreen, + ASSignpostColorPurple, + ASSignpostColorOrange, + ASSignpostColorRed, + ASSignpostColorDefault +}; + +static inline ASSignpostColor ASSignpostGetColor(ASSignpostName name, ASSignpostColor colorPref) { + if (colorPref == ASSignpostColorDefault) { + return (ASSignpostColor)((name / 25) % 4); + } else { + return colorPref; + } +} #define ASMultiplexImageNodeLogDebug(...) #define ASMultiplexImageNodeCLogDebug(...) @@ -26,8 +62,9 @@ #define ASMultiplexImageNodeLogError(...) #define ASMultiplexImageNodeCLogError(...) -// Note: `` only exists in Xcode 8 and later. -#if defined(PROFILE) && __has_include() +#define AS_KDEBUG_ENABLE defined(PROFILE) && __has_include() + +#if AS_KDEBUG_ENABLE #import @@ -45,21 +82,27 @@ #define APPSDBG_CODE(SubClass,code) KDBG_CODE(DBG_APPS, SubClass, code) #endif -#define ASProfilingSignpost(x) \ - AS_AT_LEAST_IOS10 ? kdebug_signpost(x, 0, 0, 0, (uint32_t)(x % 4)) \ - : syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, x) | DBG_FUNC_NONE, 0, 0, 0, (uint32_t)(x % 4)); +// Currently we'll reserve arg3. +#define ASSignpost(name, identifier, arg2, color) \ + AS_AT_LEAST_IOS10 ? kdebug_signpost(name, (uintptr_t)identifier, (uintptr_t)arg2, 0, ASSignpostGetColor(name, color)) \ + : syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, name) | DBG_FUNC_NONE, (uintptr_t)identifier, (uintptr_t)arg2, 0, ASSignpostGetColor(name, color)); + +#define ASSignpostStartCustom(name, identifier, arg2) \ + AS_AT_LEAST_IOS10 ? kdebug_signpost_start(name, (uintptr_t)identifier, (uintptr_t)arg2, 0, 0) \ + : syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, name) | DBG_FUNC_START, (uintptr_t)identifier, (uintptr_t)arg2, 0, 0); +#define ASSignpostStart(name) ASSignpostStartCustom(name, self, 0) -#define ASProfilingSignpostStart(x, y) \ - AS_AT_LEAST_IOS10 ? kdebug_signpost_start((uint32_t)x, (uintptr_t)y, 0, 0, (uint32_t)(x % 4)) \ - : syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, x) | DBG_FUNC_START, (uintptr_t)y, 0, 0, (uint32_t)(x % 4)); +#define ASSignpostEndCustom(name, identifier, arg2, color) \ + AS_AT_LEAST_IOS10 ? kdebug_signpost_end(name, (uintptr_t)identifier, (uintptr_t)arg2, 0, ASSignpostGetColor(name, color)) \ + : syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, name) | DBG_FUNC_END, (uintptr_t)identifier, (uintptr_t)arg2, 0, ASSignpostGetColor(name, color)); +#define ASSignpostEnd(name) ASSignpostEndCustom(name, self, 0, ASSignpostColorDefault) -#define ASProfilingSignpostEnd(x, y) \ - AS_AT_LEAST_IOS10 ? kdebug_signpost_end((uint32_t)x, (uintptr_t)y, 0, 0, (uint32_t)(x % 4)) \ - : syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, x) | DBG_FUNC_END, (uintptr_t)y, 0, 0, (uint32_t)(x % 4)); #else -#define ASProfilingSignpost(x) -#define ASProfilingSignpostStart(x, y) -#define ASProfilingSignpostEnd(x, y) +#define ASSignpost(name, identifier, arg2, color) +#define ASSignpostStartCustom(name, identifier, arg2) +#define ASSignpostStart(name) +#define ASSignpostEndCustom(name, identifier, arg2, color) +#define ASSignpostEnd(name) #endif diff --git a/Source/Details/ASDataController.mm b/Source/Details/ASDataController.mm index d2d5974ea..a8cccd45a 100644 --- a/Source/Details/ASDataController.mm +++ b/Source/Details/ASDataController.mm @@ -40,8 +40,6 @@ //#define LOG(...) NSLog(__VA_ARGS__) #define LOG(...) -#define AS_MEASURE_AVOIDED_DATACONTROLLER_WORK 0 - #define RETURN_IF_NO_DATASOURCE(val) if (_dataSource == nil) { return val; } #define ASSERT_ON_EDITING_QUEUE ASDisplayNodeAssertNotNil(dispatch_get_specific(&kASDataControllerEditingQueueKey), @"%@ must be called on the editing transaction queue.", NSStringFromSelector(_cmd)) @@ -54,13 +52,6 @@ typedef void (^ASDataControllerCompletionBlock)(NSArray *elements, NSArray *nodes); -#if AS_MEASURE_AVOIDED_DATACONTROLLER_WORK -@interface ASDataController (AvoidedWorkMeasuring) -+ (void)_didLayoutNode; -+ (void)_expectToInsertNodes:(NSUInteger)count; -@end -#endif - @interface ASDataController () { id _layoutDelegate; @@ -159,17 +150,14 @@ - (void)setLayoutDelegate:(id)layoutDelegate - (void)batchAllocateNodesFromElements:(NSArray *)elements andLayout:(BOOL)shouldLayout batchSize:(NSInteger)batchSize batchCompletion:(ASDataControllerCompletionBlock)batchCompletionHandler { ASSERT_ON_EDITING_QUEUE; -#if AS_MEASURE_AVOIDED_DATACONTROLLER_WORK - [ASDataController _expectToInsertNodes:elements.count]; -#endif - + if (elements.count == 0 || _dataSource == nil) { batchCompletionHandler(@[], @[]); return; } - ASProfilingSignpostStart(2, _dataSource); - + ASSignpostStart(ASSignpostDataControllerBatch); + if (batchSize == 0) { batchSize = [[ASDataController class] parallelProcessorCount] * kASDataControllerSizingCountPerProcessor; } @@ -182,8 +170,8 @@ - (void)batchAllocateNodesFromElements:(NSArray *)element NSArray *nodes = [self _allocateNodesFromElements:batchedElements andLayout:shouldLayout]; batchCompletionHandler(batchedElements, nodes); } - - ASProfilingSignpostEnd(2, _dataSource); + + ASSignpostEndCustom(ASSignpostDataControllerBatch, self, 0, (_dataSource != nil ? ASSignpostColorDefault : ASSignpostColorRed)); } /** @@ -228,10 +216,6 @@ - (void)_layoutNode:(ASCellNode *)node withConstrainedSize:(ASSizeRange)constrai if (ASSizeRangeHasSignificantArea(sizeRange)) { [self _layoutNode:node withConstrainedSize:sizeRange]; } - -#if AS_MEASURE_AVOIDED_DATACONTROLLER_WORK - [ASDataController _didLayoutNode]; -#endif } allocatedNodeBuffer[i] = node; @@ -836,27 +820,3 @@ - (void)_scheduleBlockOnMainSerialQueue:(dispatch_block_t)block } @end - -#if AS_MEASURE_AVOIDED_DATACONTROLLER_WORK - -static volatile int64_t _totalExpectedItems = 0; -static volatile int64_t _totalMeasuredNodes = 0; - -@implementation ASDataController (WorkMeasuring) - -+ (void)_didLayoutNode -{ - int64_t measured = OSAtomicIncrement64(&_totalMeasuredNodes); - int64_t expected = _totalExpectedItems; - if (measured % 20 == 0 || measured == expected) { - NSLog(@"Data controller avoided work (underestimated): %lld / %lld", measured, expected); - } -} - -+ (void)_expectToInsertNodes:(NSUInteger)count -{ - OSAtomicAdd64((int64_t)count, &_totalExpectedItems); -} - -@end -#endif diff --git a/Source/Details/ASRangeController.mm b/Source/Details/ASRangeController.mm index 700b38fdb..cf0acaab6 100644 --- a/Source/Details/ASRangeController.mm +++ b/Source/Details/ASRangeController.mm @@ -223,7 +223,7 @@ - (void)_updateVisibleNodeIndexPaths [self _setVisibleNodes:newVisibleNodes]; return; // don't do anything for this update, but leave _rangeIsValid == NO to make sure we update it later } - ASProfilingSignpostStart(1, self); + ASSignpostStart(ASSignpostRangeControllerUpdate); // Get the scroll direction. Default to using the previous one, if they're not scrolling. ASScrollDirection scrollDirection = [_dataSource scrollDirectionForRangeController:self]; @@ -412,7 +412,7 @@ - (void)_updateVisibleNodeIndexPaths NSLog(@"Range update complete; modifiedIndexPaths: %@", [self descriptionWithIndexPaths:modifiedIndexPaths]); #endif - ASProfilingSignpostEnd(1, self); + ASSignpostEnd(ASSignpostRangeControllerUpdate); } #pragma mark - Notification observers diff --git a/Source/Details/ASThread.h b/Source/Details/ASThread.h index 2c30cf501..ca049d72a 100644 --- a/Source/Details/ASThread.h +++ b/Source/Details/ASThread.h @@ -22,8 +22,6 @@ #import #import -#import - #import #import diff --git a/Source/Details/Transactions/_ASAsyncTransaction.mm b/Source/Details/Transactions/_ASAsyncTransaction.mm index 0294a1013..a7c25b948 100644 --- a/Source/Details/Transactions/_ASAsyncTransaction.mm +++ b/Source/Details/Transactions/_ASAsyncTransaction.mm @@ -21,12 +21,10 @@ #import #import #import -#import #import #import #import #import -#import #define ASAsyncTransactionAssertMainThread() NSAssert(0 != pthread_main_np(), @"This method must be called on the main thread"); @@ -254,9 +252,7 @@ - (NSString *)description Operation operation = entry.popNextOperation(respectPriority); lock.unlock(); if (operation._block) { - ASProfilingSignpostStart(3, operation._block); operation._block(); - ASProfilingSignpostEnd(3, operation._block); } operation._group->leave(); operation._block = nil; // the block must be freed while mutex is unlocked diff --git a/Source/Layout/ASLayoutElement.mm b/Source/Layout/ASLayoutElement.mm index c8ad2d379..8d647c09a 100644 --- a/Source/Layout/ASLayoutElement.mm +++ b/Source/Layout/ASLayoutElement.mm @@ -50,8 +50,6 @@ - (instancetype)init int32_t const ASLayoutElementContextInvalidTransitionID = 0; int32_t const ASLayoutElementContextDefaultTransitionID = ASLayoutElementContextInvalidTransitionID + 1; -pthread_key_t ASLayoutElementContextKey; - static void ASLayoutElementDestructor(void *p) { if (p != NULL) { ASDisplayNodeCFailAssert(@"Thread exited without clearing layout element context!"); @@ -59,36 +57,31 @@ static void ASLayoutElementDestructor(void *p) { } }; -// pthread_key_create must be called before the key can be used. This function does that. -void ASLayoutElementContextEnsureKey() +pthread_key_t ASLayoutElementContextKey() { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - pthread_key_create(&ASLayoutElementContextKey, ASLayoutElementDestructor); - }); + return ASPthreadStaticKey(ASLayoutElementDestructor); } void ASLayoutElementPushContext(ASLayoutElementContext *context) { - ASLayoutElementContextEnsureKey(); // NOTE: It would be easy to support nested contexts – just use an NSMutableArray here. ASDisplayNodeCAssertNil(ASLayoutElementGetCurrentContext(), @"Nested ASLayoutElementContexts aren't supported."); - pthread_setspecific(ASLayoutElementContextKey, CFBridgingRetain(context)); + pthread_setspecific(ASLayoutElementContextKey(), CFBridgingRetain(context)); } ASLayoutElementContext *ASLayoutElementGetCurrentContext() { - ASLayoutElementContextEnsureKey(); // Don't retain here. Caller will retain if it wants to! - return (__bridge __unsafe_unretained ASLayoutElementContext *)pthread_getspecific(ASLayoutElementContextKey); + return (__bridge __unsafe_unretained ASLayoutElementContext *)pthread_getspecific(ASLayoutElementContextKey()); } void ASLayoutElementPopContext() { - ASLayoutElementContextEnsureKey(); + ASLayoutElementContextKey(); ASDisplayNodeCAssertNotNil(ASLayoutElementGetCurrentContext(), @"Attempt to pop context when there wasn't a context!"); - CFBridgingRelease(pthread_getspecific(ASLayoutElementContextKey)); - pthread_setspecific(ASLayoutElementContextKey, NULL); + auto key = ASLayoutElementContextKey(); + CFBridgingRelease(pthread_getspecific(key)); + pthread_setspecific(key, NULL); } #pragma mark - ASLayoutElementStyle diff --git a/Source/Private/ASDisplayNode+AsyncDisplay.mm b/Source/Private/ASDisplayNode+AsyncDisplay.mm index 39d8f59b6..7c9c39ef0 100644 --- a/Source/Private/ASDisplayNode+AsyncDisplay.mm +++ b/Source/Private/ASDisplayNode+AsyncDisplay.mm @@ -272,6 +272,20 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro }; } + /** + If we're profiling, wrap the display block with signpost start and end. + Color the interval red if cancelled, green otherwise. + */ +#if AS_KDEBUG_ENABLE + __unsafe_unretained id ptrSelf = self; + displayBlock = ^{ + ASSignpostStartCustom(ASSignpostLayerDisplay, ptrSelf, 0); + id result = displayBlock(); + ASSignpostEndCustom(ASSignpostLayerDisplay, ptrSelf, 0, isCancelledBlock() ? ASSignpostColorRed : ASSignpostColorGreen); + return result; + }; +#endif + return displayBlock; } diff --git a/Source/Private/TextExperiment/Component/ASTextDebugOption.m b/Source/Private/TextExperiment/Component/ASTextDebugOption.m index fe36f250e..e823d328b 100755 --- a/Source/Private/TextExperiment/Component/ASTextDebugOption.m +++ b/Source/Private/TextExperiment/Component/ASTextDebugOption.m @@ -10,7 +10,6 @@ // #import "ASTextDebugOption.h" -#import #import static pthread_mutex_t _sharedDebugLock; diff --git a/Tests/ASTableViewThrashTests.m b/Tests/ASTableViewThrashTests.m index 34326629e..e547fe39c 100644 --- a/Tests/ASTableViewThrashTests.m +++ b/Tests/ASTableViewThrashTests.m @@ -2,14 +2,24 @@ // ASTableViewThrashTests.m // Texture // -// Created by Adlai Holler on 6/21/16. -// Copyright © 2016 Facebook. All rights reserved. +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// This source code is licensed under the BSD-style license found in the +// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional +// grant of patent rights can be found in the PATENTS file in the same directory. +// +// Modifications to this file made after 4/13/2017 are: Copyright (c) 2017-present, +// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 // #import #import #import #import +#import // Set to 1 to use UITableView and see if the issue still exists. @@ -40,7 +50,7 @@ return str; } -static volatile int32_t ASThrashTestItemNextID = 1; +static atomic_uint ASThrashTestItemNextID; @interface ASThrashTestItem: NSObject @property (nonatomic, readonly) NSInteger itemID; @@ -56,7 +66,7 @@ + (BOOL)supportsSecureCoding { - (instancetype)init { self = [super init]; if (self != nil) { - _itemID = OSAtomicIncrement32(&ASThrashTestItemNextID); + _itemID = atomic_fetch_add(&ASThrashTestItemNextID, 1); } return self; } @@ -99,7 +109,7 @@ @interface ASThrashTestSection: NSObject - (CGFloat)headerHeight; @end -static volatile int32_t ASThrashTestSectionNextID = 1; +static atomic_uint ASThrashTestSectionNextID = 1; @implementation ASThrashTestSection /// Create an array of sections with the given count @@ -114,7 +124,7 @@ @implementation ASThrashTestSection - (instancetype)initWithCount:(NSInteger)count { self = [super init]; if (self != nil) { - _sectionID = OSAtomicIncrement32(&ASThrashTestSectionNextID); + _sectionID = atomic_fetch_add(&ASThrashTestSectionNextID, 1); _items = [ASThrashTestItem itemsWithCount:count]; } return self;