WebCoreStatistics.mm   [plain text]


/*
 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer. 
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution. 
 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#import "WebCoreStatistics.h"

#import "DOMElementInternal.h"
#import "WebCache.h"
#import "WebFrameInternal.h"
#import <JavaScriptCore/JSLock.h>
#import <JavaScriptCore/MemoryStatistics.h>
#import <WebCore/BackForwardCache.h>
#import <WebCore/CommonVM.h>
#import <WebCore/FontCache.h>
#import <WebCore/Frame.h>
#import <WebCore/GCController.h>
#import <WebCore/GlyphPage.h>
#import <WebCore/GraphicsContext.h>
#import <WebCore/JSDOMWindow.h>
#import <WebCore/PageConsoleClient.h>
#import <WebCore/PrintContext.h>
#import <WebCore/RenderTreeAsText.h>
#import <WebCore/RenderView.h>

using namespace JSC;
using namespace WebCore;

@implementation WebCoreStatistics

+ (NSArray *)statistics
{
    return [WebCache statistics];
}

+ (size_t)javaScriptObjectsCount
{
    JSLockHolder lock(commonVM());
    return commonVM().heap.objectCount();
}

+ (size_t)javaScriptGlobalObjectsCount
{
    JSLockHolder lock(commonVM());
    return commonVM().heap.globalObjectCount();
}

+ (size_t)javaScriptProtectedObjectsCount
{
    JSLockHolder lock(commonVM());
    return commonVM().heap.protectedObjectCount();
}

+ (size_t)javaScriptProtectedGlobalObjectsCount
{
    JSLockHolder lock(commonVM());
    return commonVM().heap.protectedGlobalObjectCount();
}

static RetainPtr<NSCountedSet> createNSCountedSet(const HashCountedSet<const char*>& set)
{
    auto result = adoptNS([[NSCountedSet alloc] initWithCapacity:set.size()]);
    for (auto& entry : set) {
        auto key = [NSString stringWithUTF8String:entry.key];
        for (unsigned i = 0; i < entry.value; ++i)
            [result addObject:key];
    }
    return result;
}

+ (NSCountedSet *)javaScriptProtectedObjectTypeCounts
{
    JSLockHolder lock(commonVM());
    return createNSCountedSet(*commonVM().heap.protectedObjectTypeCounts()).autorelease();
}

+ (NSCountedSet *)javaScriptObjectTypeCounts
{
    JSLockHolder lock(commonVM());
    return createNSCountedSet(*commonVM().heap.objectTypeCounts()).autorelease();
}

+ (void)garbageCollectJavaScriptObjects
{
    GCController::singleton().garbageCollectNow();
}

+ (void)garbageCollectJavaScriptObjectsOnAlternateThreadForDebugging:(BOOL)waitUntilDone
{
    GCController::singleton().garbageCollectOnAlternateThreadForDebugging(waitUntilDone);
}

+ (void)setJavaScriptGarbageCollectorTimerEnabled:(BOOL)enable
{
    GCController::singleton().setJavaScriptGarbageCollectorTimerEnabled(enable);
}

+ (size_t)iconPageURLMappingCount
{
    return 0;
}

+ (size_t)iconRetainedPageURLCount
{
    return 0;
}

+ (size_t)iconRecordCount
{
    return 0;
}

+ (size_t)iconsWithDataCount
{
    return 0;
}

+ (size_t)cachedFontDataCount
{
    return FontCache::singleton().fontCount();
}

+ (size_t)cachedFontDataInactiveCount
{
    return FontCache::singleton().inactiveFontCount();
}

+ (void)purgeInactiveFontData
{
    FontCache::singleton().purgeInactiveFontData();
}

+ (size_t)glyphPageCount
{
    return GlyphPage::count();
}

+ (BOOL)shouldPrintExceptions
{
    JSLockHolder lock(commonVM());
    return PageConsoleClient::shouldPrintExceptions();
}

+ (void)setShouldPrintExceptions:(BOOL)print
{
    JSLockHolder lock(commonVM());
    PageConsoleClient::setShouldPrintExceptions(print);
}

+ (void)emptyCache
{
    [WebCache empty];
}

+ (void)setCacheDisabled:(BOOL)disabled
{
    [WebCache setDisabled:disabled];
}

+ (void)startIgnoringWebCoreNodeLeaks
{
    WebCore::Node::startIgnoringLeaks();
}

+ (void)stopIgnoringWebCoreNodeLeaks
{
    WebCore::Node::stopIgnoringLeaks();
}

+ (NSDictionary *)memoryStatistics
{
    auto fastMallocStatistics = WTF::fastMallocStatistics();
    JSLockHolder lock(commonVM());
    size_t heapSize = commonVM().heap.size();
    size_t heapFree = commonVM().heap.capacity() - heapSize;
    auto globalMemoryStats = globalMemoryStatistics();
    return @{
        @"FastMallocReservedVMBytes": @(fastMallocStatistics.reservedVMBytes),
        @"FastMallocCommittedVMBytes": @(fastMallocStatistics.committedVMBytes),
        @"FastMallocFreeListBytes": @(fastMallocStatistics.freeListBytes),
        @"JavaScriptHeapSize": @(heapSize),
        @"JavaScriptFreeSize": @(heapFree),
        @"JavaScriptStackSize": @(globalMemoryStats.stackBytes),
        @"JavaScriptJITSize": @(globalMemoryStats.JITBytes),
    };
}

+ (void)returnFreeMemoryToSystem
{
    WTF::releaseFastMallocFreeMemory();
}

+ (int)cachedPageCount
{
    return BackForwardCache::singleton().pageCount();
}

+ (int)cachedFrameCount
{
    return BackForwardCache::singleton().frameCount();
}

// Deprecated
+ (int)autoreleasedPageCount
{
    return 0;
}

// Deprecated
+ (size_t)javaScriptNoGCAllowedObjectsCount
{
    return 0;
}

+ (size_t)javaScriptReferencedObjectsCount
{
    JSLockHolder lock(commonVM());
    return commonVM().heap.protectedObjectCount();
}

+ (NSSet *)javaScriptRootObjectClasses
{
    return [self javaScriptRootObjectTypeCounts];
}

+ (size_t)javaScriptInterpretersCount
{
    return [self javaScriptProtectedGlobalObjectsCount];
}

+ (NSCountedSet *)javaScriptRootObjectTypeCounts
{
    return [self javaScriptProtectedObjectTypeCounts];
}

@end

@implementation WebFrame (WebKitDebug)

- (NSString *)renderTreeAsExternalRepresentationForPrinting
{
    return externalRepresentation(_private->coreFrame, { RenderAsTextFlag::PrintingMode });
}

static OptionSet<RenderAsTextFlag> toRenderAsTextFlags(WebRenderTreeAsTextOptions options)
{
    OptionSet<RenderAsTextFlag> flags;

    if (options & WebRenderTreeAsTextShowAllLayers)
        flags.add(RenderAsTextFlag::ShowAllLayers);
    if (options & WebRenderTreeAsTextShowLayerNesting)
        flags.add(RenderAsTextFlag::ShowLayerNesting);
    if (options & WebRenderTreeAsTextShowCompositedLayers)
        flags.add(RenderAsTextFlag::ShowCompositedLayers);
    if (options & WebRenderTreeAsTextShowOverflow)
        flags.add(RenderAsTextFlag::ShowOverflow);
    if (options & WebRenderTreeAsTextShowSVGGeometry)
        flags.add(RenderAsTextFlag::ShowSVGGeometry);
    if (options & WebRenderTreeAsTextShowLayerFragments)
        flags.add(RenderAsTextFlag::ShowLayerFragments);

    return flags;
}

- (NSString *)renderTreeAsExternalRepresentationWithOptions:(WebRenderTreeAsTextOptions)options
{
    return externalRepresentation(_private->coreFrame, toRenderAsTextFlags(options));
}

- (int)numberOfPagesWithPageWidth:(float)pageWidthInPixels pageHeight:(float)pageHeightInPixels
{
    Frame* coreFrame = _private->coreFrame;
    if (!coreFrame)
        return -1;

    return PrintContext::numberOfPages(*coreFrame, FloatSize(pageWidthInPixels, pageHeightInPixels));
}

- (void)printToCGContext:(CGContextRef)cgContext pageWidth:(float)pageWidthInPixels pageHeight:(float)pageHeightInPixels
{
    Frame* coreFrame = _private->coreFrame;
    if (!coreFrame)
        return;

    GraphicsContext graphicsContext(cgContext);
    PrintContext::spoolAllPagesWithBoundaries(*coreFrame, graphicsContext, FloatSize(pageWidthInPixels, pageHeightInPixels));
}

@end