+2004-05-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin.
+
+ - -[WebFrame childFrames] is so hot that a special internal
+ version which avoids the copy and autorelease results in a .75%
+ performance improvement on HTML iBench.
+
+ * WebView.subproj/WebFramePrivate.h: Prototype new method.
+ * WebView.subproj/WebFrame.m:
+ (-[WebFrame _internalChildFrames]): New method, just returns
+ internal value instead of copying.
+
+ (-[WebFrame _descendantFrameNamed:]): Use it
+ (-[WebFrame _textSizeMultiplierChanged]): likewise
+ (-[WebFrame _viewWillMoveToHostWindow:]): likewise
+ (-[WebFrame _viewDidMoveToHostWindow]): likewise
+ (-[WebFrame _saveDocumentAndScrollState]): likewise
+ (-[WebFrame _numPendingOrLoadingRequests:]): likewise
+ (-[WebFrame _checkLoadComplete]): Refactored this and it's two
+ helpers a little so we could get away with using
+ _internalChildFrames.
+ (-[WebFrame _checkLoadCompleteForThisFrame]): Renamed from
+ _isLoadComplete
+ (-[WebFrame _recursiveCheckLoadComplete]): renamed from (class
+ method) _recursiveCheckCompleteFromFrame:
+ * WebView.subproj/WebDataSource.m:
+ (-[WebDataSource _defersCallbacksChanged]): Use it
+ (-[WebDataSource isLoading]): likewise
+ * WebView.subproj/WebView.m:
+ (-[WebView _frameForDataSource:fromFrame:]): likewise
+ (-[WebView _frameForView:fromFrame:]): likewise
+
2004-05-10 Chris Blumenberg <cblu@apple.com>
Forgot to commit this copied header.
[client setDefersCallbacks:defers];
}
- [[[self webFrame] childFrames] makeObjectsPerformSelector:@selector(_defersCallbacksChanged)];
+ // It's OK to use the internal version of getting the child
+ // frames, since undeferring callbacks will not do any immediate
+ // work, and so the set of frames can't change out from under us.
+ [[[self webFrame] _internalChildFrames] makeObjectsPerformSelector:@selector(_defersCallbacksChanged)];
}
- (NSURLRequest *)_originalRequest
// Put in the auto-release pool because it's common to call this from a run loop source,
// and then the entire list of frames lasts until the next autorelease.
NSAutoreleasePool *pool = [NSAutoreleasePool new];
- NSEnumerator *e = [[[self webFrame] childFrames] objectEnumerator];
+
+ // It's OK to use the internal version of getting the child
+ // frames, since nothing we do here can possibly change the set of
+ // frames.
+ NSEnumerator *e = [[[self webFrame] _internalChildFrames] objectEnumerator];
WebFrame *childFrame;
while ((childFrame = [e nextObject])) {
if ([[childFrame dataSource] isLoading] || [[childFrame provisionalDataSource] isLoading]) {
@end
+@interface NSArray (WebSafeMakePerform)
+
+- (void)_web_safeMakeObjectsPerformSelector:(SEL)aSelector
+
+@end
+
+
+@implementation NSArray (WebSafeMakePerform)
+
+- (void)_web_safeMakeObjectsPerformSelector:(SEL)aSelector
+{
+ unsigned count = [self count];
+ if (0 == count)
+ return;
+
+ if (count > 128) {
+ [[self copy] makeObjectsPerformSelector:aSelector];
+ return;
+ }
+
+ id batch[128];
+ [self getObjects:batch range:NSMakeRange(0, count)];
+ unsigned i;
+ for (i = 0; i < count; i++) {
+ objc_msgSend(batch[i], aSelector);
+ }
+}
+
+@end
// One day we might want to expand the use of this kind of class such that we'd receive one
// over the bridge, and possibly hand it on through to the FormsDelegate.
return self;
}
- NSArray *children = [self childFrames];
+ // It's OK to use the internal version of getting the child
+ // frames, since we know this method won't change the set of
+ // frames
+ NSArray *children = [self _internalChildFrames];
WebFrame *frame;
unsigned i;
if (pageCache){
[[self dataSource] _setPrimaryLoadComplete: YES];
- [self _isLoadComplete];
+ [self _checkLoadCompleteForThisFrame];
}
}
}
}
-- (void)_isLoadComplete
+- (void)_checkLoadCompleteForThisFrame
{
ASSERT([self webView] != nil);
ASSERT_NOT_REACHED();
}
-+ (void)_recursiveCheckCompleteFromFrame: (WebFrame *)fromFrame
+- (void)_recursiveCheckLoadComplete
{
- int i, count;
- NSArray *childFrames;
-
- childFrames = [fromFrame childFrames];
- count = [childFrames count];
- for (i = 0; i < count; i++) {
- WebFrame *childFrame;
-
- childFrame = [childFrames objectAtIndex: i];
- [WebFrame _recursiveCheckCompleteFromFrame: childFrame];
- [childFrame _isLoadComplete];
- }
- [fromFrame _isLoadComplete];
+ // Checking for load complete may indeed alter the set of child
+ // frames. However, _web_safeMakeObjectsPerformSelector: makes
+ // sure to copy the array so it is safe against changes.
+ [[self _internalChildFrames] _web_safeMakeObjectsPerformSelector:@selector(_recursiveCheckLoadComplete)];
+ [self _checkLoadCompleteForThisFrame];
}
// Called every time a resource is completely loaded, or an error is received.
ASSERT([self webView] != nil);
// Now walk the frame tree to see if any frame that may have initiated a load is done.
- [WebFrame _recursiveCheckCompleteFromFrame: [[self webView] mainFrame]];
+ [[[self webView] mainFrame] _recursiveCheckLoadComplete];
}
- (WebBridge *)_bridge
[(NSView <_web_WebDocumentTextSizing> *)view _web_textSizeMultiplierChanged];
}
- [[self childFrames] makeObjectsPerformSelector:@selector(_textSizeMultiplierChanged)];
+ // It's OK to use the internal version because this method is
+ // guaranteed not to change the set of frames.
+ [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_textSizeMultiplierChanged)];
}
- (void)_defersCallbacksChanged
- (void)_viewWillMoveToHostWindow:(NSWindow *)hostWindow
{
[[[self frameView] documentView] viewWillMoveToHostWindow:hostWindow];
- [[self childFrames] makeObjectsPerformSelector:@selector(_viewWillMoveToHostWindow:) withObject:hostWindow];
+ // It's OK to use the internal version because this method is
+ // guaranteed not to change the set of frames.
+ [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_viewWillMoveToHostWindow:) withObject:hostWindow];
}
- (void)_viewDidMoveToHostWindow
{
[[[self frameView] documentView] viewDidMoveToHostWindow];
- [[self childFrames] makeObjectsPerformSelector:@selector(_viewDidMoveToHostWindow)];
+ // It's OK to use the internal version because this method is
+ // guaranteed not to change the set of frames.
+ [[self _internalChildFrames] makeObjectsPerformSelector:@selector(_viewDidMoveToHostWindow)];
}
- (void)_reloadAllowingStaleDataWithOverrideEncoding:(NSString *)encoding
[_private->bridge saveDocumentState];
[self _saveScrollPositionToItem:[_private currentItem]];
- NSArray *frames = [self childFrames];
+ // It's OK to use the internal version because this method is
+ // guaranteed not to change the set of frames.
+ NSArray *frames = [self _internalChildFrames];
int count = [frames count];
int i;
for (i = 0; i < count; i++) {
return [[self _bridge] numPendingOrLoadingRequests];
num = [[self _bridge] numPendingOrLoadingRequests];
- NSArray *children = [self childFrames];
+ // It's OK to use the internal version because this method is
+ // guaranteed not to change the set of frames.
+ NSArray *children = [self _internalChildFrames];
int i, count = [children count];
WebFrame *child;
for (i = 0; i < count; i++){
}
}
+- (NSArray *)_internalChildFrames
+{
+ return _private->children;
+}
+
@end
@implementation WebFrame (WebInternal)