[bmalloc] Add IsoHeap test to ensure that IsoHeap pages are not allocating too large VA
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2019 03:42:09 +0000 (03:42 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 25 Jul 2019 03:42:09 +0000 (03:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=200103

Reviewed by Mark Lam.

Source/bmalloc:

* bmalloc/IsoPage.cpp:

Source/WebCore:

No behavior change in WebCore.

* page/MemoryRelease.cpp:
* page/ResourceUsageThread.h:
(WebCore::TagInfo::TagInfo): Deleted.
* page/cocoa/ResourceUsageThreadCocoa.mm:
(WebCore::vmPageSize): Deleted.
(WebCore::logFootprintComparison): Deleted.
(WebCore::displayNameForVMTag): Deleted.
(WebCore::pagesPerVMTag): Deleted.

Source/WebCore/PAL:

Move VMTag page memory investigation code from PAL to WTF to reuse it in TestWTF.

* PAL.xcodeproj/project.pbxproj:
* pal/PlatformMac.cmake:

Source/WebKit:

Move MachVMSPI.h from PAL to WTF.

* Platform/cocoa/SharedMemoryCocoa.cpp:

Source/WTF:

We move VMTag page investigation code from PAL to WTF to use it in TestWTF.
And we also accumulate allocated VA size in `reserved` field of `TagInfo`.

* WTF.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/PlatformMac.cmake:
* wtf/ResourceUsage.h: Added.
* wtf/cocoa/MemoryPressureHandlerCocoa.mm:
* wtf/cocoa/ResourceUsageCocoa.cpp: Added.
(WTF::vmPageSize):
(WTF::logFootprintComparison):
(WTF::displayNameForVMTag):
(WTF::pagesPerVMTag):
* wtf/spi/cocoa/MachVMSPI.h: Added.

Tools:

This patch adds tests to TestWTF IsoHeap tests to ensure that IsoHeap's component is not leaking pages or not allocating too large VAs for memory allocation.
We use VMTag to get the system view of the allocated VAs and check whether it is not incredibly large.

While the tests are white-box tests (it means that this is a bit flaky to the implementation changes of IsoHeap), I adjusted some threshold to make this less-flaky
to the future implementation changes while it catches the severe issues we had.

* TestWebKitAPI/Tests/WTF/bmalloc/IsoHeap.cpp:
(assertEmptyPointerSet):
(assertHasOnlyObjects):
(assertClean):
(TEST):
(allocateAndDeallocate):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247815 268f45cc-cd09-0410-ab3c-d52691b4dbfc

21 files changed:
Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/CMakeLists.txt
Source/WTF/wtf/PlatformMac.cmake
Source/WTF/wtf/ResourceUsage.h [new file with mode: 0644]
Source/WTF/wtf/cocoa/MemoryPressureHandlerCocoa.mm
Source/WTF/wtf/cocoa/ResourceUsageCocoa.cpp [new file with mode: 0644]
Source/WTF/wtf/spi/cocoa/MachVMSPI.h [moved from Source/WebCore/PAL/pal/spi/cocoa/MachVMSPI.h with 100% similarity]
Source/WebCore/ChangeLog
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj
Source/WebCore/PAL/pal/PlatformMac.cmake
Source/WebCore/page/MemoryRelease.cpp
Source/WebCore/page/ResourceUsageThread.h
Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm
Source/WebKit/ChangeLog
Source/WebKit/Platform/cocoa/SharedMemoryCocoa.cpp
Source/bmalloc/ChangeLog
Source/bmalloc/bmalloc/IsoPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WTF/bmalloc/IsoHeap.cpp

index 900b13d..001a6e7 100644 (file)
@@ -1,3 +1,25 @@
+2019-07-24  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [bmalloc] Add IsoHeap test to ensure that IsoHeap pages are not allocating too large VA
+        https://bugs.webkit.org/show_bug.cgi?id=200103
+
+        Reviewed by Mark Lam.
+
+        We move VMTag page investigation code from PAL to WTF to use it in TestWTF.
+        And we also accumulate allocated VA size in `reserved` field of `TagInfo`.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/PlatformMac.cmake:
+        * wtf/ResourceUsage.h: Added.
+        * wtf/cocoa/MemoryPressureHandlerCocoa.mm:
+        * wtf/cocoa/ResourceUsageCocoa.cpp: Added.
+        (WTF::vmPageSize):
+        (WTF::logFootprintComparison):
+        (WTF::displayNameForVMTag):
+        (WTF::pagesPerVMTag):
+        * wtf/spi/cocoa/MachVMSPI.h: Added.
+
 2019-07-23  Keith Miller  <keith_miller@apple.com>
 
         Add cheat sheet comment for HashMap/Set iterator/AddResult
index 077afbf..d1d5f9b 100644 (file)
                E38C41251EB4E04C0042957D /* CPUTimeCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38C41241EB4E04C0042957D /* CPUTimeCocoa.cpp */; };
                E38C41281EB4E0680042957D /* CPUTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38C41261EB4E0680042957D /* CPUTime.cpp */; };
                E38D6E271F5522E300A75CC4 /* StringBuilderJSON.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38D6E261F5522E300A75CC4 /* StringBuilderJSON.cpp */; };
+               E392FA2722E92BFF00ECDC73 /* ResourceUsageCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E392FA2622E92BFF00ECDC73 /* ResourceUsageCocoa.cpp */; };
                E3A32BC41FC830E2007D7E76 /* JSValueMalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3A32BC21FC830E2007D7E76 /* JSValueMalloc.cpp */; };
                E4A0AD391A96245500536DF6 /* WorkQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD371A96245500536DF6 /* WorkQueue.cpp */; };
                E4A0AD3D1A96253C00536DF6 /* WorkQueueCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4A0AD3C1A96253C00536DF6 /* WorkQueueCocoa.cpp */; };
                E300E521203D645F00DA79BE /* UniqueArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UniqueArray.h; sourceTree = "<group>"; };
                E311FB151F0A568B003C08DE /* ThreadGroup.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadGroup.cpp; sourceTree = "<group>"; };
                E311FB161F0A568B003C08DE /* ThreadGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadGroup.h; sourceTree = "<group>"; };
+               E31BDE2822E913CC0029B105 /* MachVMSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachVMSPI.h; sourceTree = "<group>"; };
                E3200AB41E9A536D003B59D2 /* PlatformRegisters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformRegisters.h; sourceTree = "<group>"; };
                E33D5F871FBED66700BF625E /* RecursableLambda.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecursableLambda.h; sourceTree = "<group>"; };
                E34CD0D022810A020020D299 /* Packed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Packed.h; sourceTree = "<group>"; };
                E38C41261EB4E0680042957D /* CPUTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPUTime.cpp; sourceTree = "<group>"; };
                E38C41271EB4E0680042957D /* CPUTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CPUTime.h; sourceTree = "<group>"; };
                E38D6E261F5522E300A75CC4 /* StringBuilderJSON.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringBuilderJSON.cpp; sourceTree = "<group>"; };
+               E392FA2622E92BFF00ECDC73 /* ResourceUsageCocoa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResourceUsageCocoa.cpp; sourceTree = "<group>"; };
                E3A32BC21FC830E2007D7E76 /* JSValueMalloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSValueMalloc.cpp; sourceTree = "<group>"; };
                E3A32BC31FC830E2007D7E76 /* JSValueMalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueMalloc.h; sourceTree = "<group>"; };
                E3CF76902115D6BA0091DE48 /* CompactPointerTuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompactPointerTuple.h; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                9384B73E20DEA284005B73B2 /* CFXPCBridgeSPI.h */,
+                               E31BDE2822E913CC0029B105 /* MachVMSPI.h */,
                                93D191CF20CAECE800C51B8E /* objcSPI.h */,
                                A5098B011C16A4F900087797 /* SecuritySPI.h */,
                        );
                                AD89B6B91E64150F0090707F /* MemoryPressureHandlerCocoa.mm */,
                                5CC0EE872162BC2200A1A842 /* NSURLExtras.h */,
                                5CC0EE882162BC2200A1A842 /* NSURLExtras.mm */,
+                               E392FA2622E92BFF00ECDC73 /* ResourceUsageCocoa.cpp */,
                                A30D412C1F0DE0BA00B71954 /* SoftLinking.h */,
                                5CC0EE862162BC2200A1A842 /* URLCocoa.mm */,
                                E4A0AD3C1A96253C00536DF6 /* WorkQueueCocoa.cpp */,
                                A8A47414151A825B004123FF /* RandomNumber.cpp in Sources */,
                                0FEC3C5E1F368A9700F59B6C /* ReadWriteLock.cpp in Sources */,
                                A8A4741A151A825B004123FF /* RefCountedLeakCounter.cpp in Sources */,
+                               E392FA2722E92BFF00ECDC73 /* ResourceUsageCocoa.cpp in Sources */,
                                2CDED0F318115C85004DBA70 /* RunLoop.cpp in Sources */,
                                2CDED0EF18115C38004DBA70 /* RunLoopCF.cpp in Sources */,
                                A3EE5C3E21FFAC7D00FABD61 /* RunLoopTimerCF.cpp in Sources */,
index b7fe714..a32e7e2 100644 (file)
@@ -190,6 +190,7 @@ set(WTF_PUBLIC_HEADERS
     RefCountedLeakCounter.h
     RefCounter.h
     RefPtr.h
+    ResourceUsage.h
     RetainPtr.h
     RunLoop.h
     RunLoopTimer.h
index 797c5cf..ae8abb2 100644 (file)
@@ -25,6 +25,7 @@ list(APPEND WTF_PUBLIC_HEADERS
     spi/cf/CFStringSPI.h
 
     spi/cocoa/CFXPCBridgeSPI.h
+    spi/cocoa/MachVMSPI.h
     spi/cocoa/SecuritySPI.h
     spi/cocoa/objcSPI.h
 
@@ -58,6 +59,7 @@ list(APPEND WTF_SOURCES
     cocoa/MemoryFootprintCocoa.cpp
     cocoa/MemoryPressureHandlerCocoa.mm
     cocoa/NSURLExtras.mm
+    cocoa/ResourceUsageCocoa.cpp
     cocoa/URLCocoa.mm
     cocoa/WorkQueueCocoa.cpp
 
diff --git a/Source/WTF/wtf/ResourceUsage.h b/Source/WTF/wtf/ResourceUsage.h
new file mode 100644 (file)
index 0000000..5422e56
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
+ */
+
+#pragma once
+
+#include <array>
+
+namespace WTF {
+
+#if PLATFORM(COCOA)
+
+struct TagInfo {
+    size_t dirty { 0 };
+    size_t reclaimable { 0 };
+    size_t reserved { 0 };
+};
+
+WTF_EXPORT_PRIVATE const char* displayNameForVMTag(unsigned);
+WTF_EXPORT_PRIVATE size_t vmPageSize();
+WTF_EXPORT_PRIVATE std::array<TagInfo, 256> pagesPerVMTag();
+WTF_EXPORT_PRIVATE void logFootprintComparison(const std::array<TagInfo, 256>&, const std::array<TagInfo, 256>&);
+
+#endif
+
+}
+
+#if PLATFORM(COCOA)
+using WTF::TagInfo;
+using WTF::displayNameForVMTag;
+using WTF::vmPageSize;
+using WTF::pagesPerVMTag;
+#endif
index 75ea83f..21d05ec 100644 (file)
@@ -30,6 +30,7 @@
 #import <mach/task_info.h>
 #import <malloc/malloc.h>
 #import <notify.h>
+#import <wtf/ResourceUsage.h>
 #import <wtf/spi/darwin/DispatchSPI.h>
 
 #define ENABLE_FMW_FOOTPRINT_COMPARISON 0
diff --git a/Source/WTF/wtf/cocoa/ResourceUsageCocoa.cpp b/Source/WTF/wtf/cocoa/ResourceUsageCocoa.cpp
new file mode 100644 (file)
index 0000000..dfca072
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2014-2018 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
+ */
+
+#include "config.h"
+#include <wtf/ResourceUsage.h>
+
+#include <mach/mach_error.h>
+#include <mach/mach_init.h>
+#include <utility>
+#include <wtf/spi/cocoa/MachVMSPI.h>
+#include <wtf/text/StringConcatenateNumbers.h>
+
+namespace WTF {
+
+size_t vmPageSize()
+{
+#if PLATFORM(IOS_FAMILY)
+    return vm_kernel_page_size;
+#else
+    static size_t cached = sysconf(_SC_PAGESIZE);
+    return cached;
+#endif
+}
+
+void logFootprintComparison(const std::array<TagInfo, 256>& before, const std::array<TagInfo, 256>& after)
+{
+    const size_t pageSize = vmPageSize();
+
+    WTFLogAlways("Per-tag breakdown of memory reclaimed by pressure handler:");
+    WTFLogAlways("  ## %16s %10s %10s %10s", "VM Tag", "Before", "After", "Diff");
+    for (unsigned i = 0; i < 256; ++i) {
+        ssize_t dirtyBefore = before[i].dirty * pageSize;
+        ssize_t dirtyAfter = after[i].dirty * pageSize;
+        ssize_t dirtyDiff = dirtyAfter - dirtyBefore;
+        if (!dirtyBefore && !dirtyAfter)
+            continue;
+        String tagName = displayNameForVMTag(i);
+        if (!tagName)
+            tagName = makeString("Tag ", i);
+        WTFLogAlways("  %02X %16s %10ld %10ld %10ld",
+            i,
+            tagName.ascii().data(),
+            dirtyBefore,
+            dirtyAfter,
+            dirtyDiff
+        );
+    }
+}
+
+const char* displayNameForVMTag(unsigned tag)
+{
+    switch (tag) {
+    case VM_MEMORY_IOKIT: return "IOKit";
+    case VM_MEMORY_LAYERKIT: return "CoreAnimation";
+    case VM_MEMORY_IMAGEIO: return "ImageIO";
+    case VM_MEMORY_CGIMAGE: return "CG image";
+    case VM_MEMORY_JAVASCRIPT_CORE: return "Gigacage";
+    case VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR: return "JSC JIT";
+    case VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE: return "IsoHeap";
+    case VM_MEMORY_MALLOC: return "malloc";
+    case VM_MEMORY_MALLOC_HUGE: return "malloc (huge)";
+    case VM_MEMORY_MALLOC_LARGE: return "malloc (large)";
+    case VM_MEMORY_MALLOC_SMALL: return "malloc (small)";
+    case VM_MEMORY_MALLOC_TINY: return "malloc (tiny)";
+    case VM_MEMORY_MALLOC_NANO: return "malloc (nano)";
+    case VM_MEMORY_TCMALLOC: return "bmalloc";
+    case VM_MEMORY_FOUNDATION: return "Foundation";
+    case VM_MEMORY_STACK: return "Stack";
+    case VM_MEMORY_SQLITE: return "SQLite";
+    case VM_MEMORY_UNSHARED_PMAP: return "pmap (unshared)";
+    case VM_MEMORY_DYLIB: return "dylib";
+    case VM_MEMORY_CORESERVICES: return "CoreServices";
+    case VM_MEMORY_OS_ALLOC_ONCE: return "os_alloc_once";
+    case VM_MEMORY_LIBDISPATCH: return "libdispatch";
+    default: return nullptr;
+    }
+}
+
+std::array<TagInfo, 256> pagesPerVMTag()
+{
+    std::array<TagInfo, 256> tags;
+    task_t task = mach_task_self();
+    mach_vm_size_t size;
+    uint32_t depth = 0;
+    struct vm_region_submap_info_64 info = { };
+    mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
+    for (mach_vm_address_t addr = 0; ; addr += size) {
+        int purgeableState;
+        if (mach_vm_purgable_control(task, addr, VM_PURGABLE_GET_STATE, &purgeableState) != KERN_SUCCESS)
+            purgeableState = VM_PURGABLE_DENY;
+
+        kern_return_t kr = mach_vm_region_recurse(task, &addr, &size, &depth, (vm_region_info_t)&info, &count);
+        if (kr != KERN_SUCCESS)
+            break;
+
+        tags[info.user_tag].reserved += size / vmPageSize();
+
+        if (purgeableState == VM_PURGABLE_VOLATILE) {
+            tags[info.user_tag].reclaimable += info.pages_resident;
+            continue;
+        }
+
+        if (purgeableState == VM_PURGABLE_EMPTY) {
+            tags[info.user_tag].reclaimable += size / vmPageSize();
+            continue;
+        }
+
+        bool anonymous = !info.external_pager;
+        if (anonymous) {
+            tags[info.user_tag].dirty += info.pages_resident - info.pages_reusable;
+            tags[info.user_tag].reclaimable += info.pages_reusable;
+        } else
+            tags[info.user_tag].dirty += info.pages_dirtied;
+    }
+
+    return tags;
+}
+
+}
index 10185ff..b137fa0 100644 (file)
@@ -1,3 +1,21 @@
+2019-07-24  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [bmalloc] Add IsoHeap test to ensure that IsoHeap pages are not allocating too large VA
+        https://bugs.webkit.org/show_bug.cgi?id=200103
+
+        Reviewed by Mark Lam.
+
+        No behavior change in WebCore.
+
+        * page/MemoryRelease.cpp:
+        * page/ResourceUsageThread.h:
+        (WebCore::TagInfo::TagInfo): Deleted.
+        * page/cocoa/ResourceUsageThreadCocoa.mm:
+        (WebCore::vmPageSize): Deleted.
+        (WebCore::logFootprintComparison): Deleted.
+        (WebCore::displayNameForVMTag): Deleted.
+        (WebCore::pagesPerVMTag): Deleted.
+
 2019-07-24  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: support `console.screenshot` with detached Nodes that are graphical
index 0ce96d8..4e76c49 100644 (file)
@@ -1,3 +1,15 @@
+2019-07-24  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [bmalloc] Add IsoHeap test to ensure that IsoHeap pages are not allocating too large VA
+        https://bugs.webkit.org/show_bug.cgi?id=200103
+
+        Reviewed by Mark Lam.
+
+        Move VMTag page memory investigation code from PAL to WTF to reuse it in TestWTF.
+
+        * PAL.xcodeproj/project.pbxproj:
+        * pal/PlatformMac.cmake:
+
 2019-07-22  Simon Fraser  <simon.fraser@apple.com>
 
         Make some constructors explicit
index c438c3b..deab01d 100644 (file)
@@ -43,7 +43,6 @@
                0C2DA1451F3BEB4900DBC317 /* IOSurfaceSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2DA1291F3BEB4900DBC317 /* IOSurfaceSPI.h */; };
                0C2DA1461F3BEB4900DBC317 /* IOTypesSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2DA12A1F3BEB4900DBC317 /* IOTypesSPI.h */; };
                0C2DA1471F3BEB4900DBC317 /* URLFormattingSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2DA12B1F3BEB4900DBC317 /* URLFormattingSPI.h */; };
-               0C2DA1481F3BEB4900DBC317 /* MachVMSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2DA12C1F3BEB4900DBC317 /* MachVMSPI.h */; };
                0C2DA1491F3BEB4900DBC317 /* NEFilterSourceSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2DA12D1F3BEB4900DBC317 /* NEFilterSourceSPI.h */; };
                0C2DA14A1F3BEB4900DBC317 /* NSAttributedStringSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2DA12E1F3BEB4900DBC317 /* NSAttributedStringSPI.h */; };
                0C2DA14B1F3BEB4900DBC317 /* NSButtonCellSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2DA12F1F3BEB4900DBC317 /* NSButtonCellSPI.h */; };
                0C2DA1291F3BEB4900DBC317 /* IOSurfaceSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOSurfaceSPI.h; sourceTree = "<group>"; };
                0C2DA12A1F3BEB4900DBC317 /* IOTypesSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IOTypesSPI.h; sourceTree = "<group>"; };
                0C2DA12B1F3BEB4900DBC317 /* URLFormattingSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = URLFormattingSPI.h; sourceTree = "<group>"; };
-               0C2DA12C1F3BEB4900DBC317 /* MachVMSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachVMSPI.h; sourceTree = "<group>"; };
                0C2DA12D1F3BEB4900DBC317 /* NEFilterSourceSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NEFilterSourceSPI.h; sourceTree = "<group>"; };
                0C2DA12E1F3BEB4900DBC317 /* NSAttributedStringSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSAttributedStringSPI.h; sourceTree = "<group>"; };
                0C2DA12F1F3BEB4900DBC317 /* NSButtonCellSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSButtonCellSPI.h; sourceTree = "<group>"; };
                                0C2DA1291F3BEB4900DBC317 /* IOSurfaceSPI.h */,
                                0C2DA12A1F3BEB4900DBC317 /* IOTypesSPI.h */,
                                0C5AF9121F43A4C7002EAC02 /* LaunchServicesSPI.h */,
-                               0C2DA12C1F3BEB4900DBC317 /* MachVMSPI.h */,
                                1CC3ACE722BD7EB800F360F0 /* MetalSPI.h */,
                                0C2DA12D1F3BEB4900DBC317 /* NEFilterSourceSPI.h */,
                                0C2DA12E1F3BEB4900DBC317 /* NSAttributedStringSPI.h */,
                                0C2DA0651F33CA3300DBC317 /* spi */,
                                A3788E9F1F05B7CE00679425 /* system */,
                                A30D411D1F0DD0AC00B71954 /* text */,
-                               1C022EFD22CFE8E1006DF01B /* Gunzip.h */,
                                0C2D9E721EEF5AF600DBC317 /* ExportMacros.h */,
                                F44291621FA52670002CC93E /* FileSizeFormatter.cpp */,
                                F442915F1FA5261E002CC93E /* FileSizeFormatter.h */,
+                               1C022EFD22CFE8E1006DF01B /* Gunzip.h */,
                                A39DE74D1F7C443C007BCB00 /* HysteresisActivity.h */,
                                1C4876D61F8D7F4E00CCEEBD /* Logging.cpp */,
                                1C4876D71F8D7F4E00CCEEBD /* Logging.h */,
                1C4876DE1F8D831300CCEEBD /* cocoa */ = {
                        isa = PBXGroup;
                        children = (
-                               1C022EFC22CFE8E0006DF01B /* Gunzip.cpp */,
                                57FD318822B3592F008D0E8B /* AppSSOSoftLink.h */,
                                57FD318922B3593E008D0E8B /* AppSSOSoftLink.mm */,
                                077E87B0226A460200A2AFF0 /* AVFoundationSoftLink.h */,
                                077E87AF226A460200A2AFF0 /* AVFoundationSoftLink.mm */,
                                F44291661FA52705002CC93E /* FileSizeFormatterCocoa.mm */,
+                               1C022EFC22CFE8E0006DF01B /* Gunzip.cpp */,
                                A1F63C9D21A4DBF7006FB43B /* PassKitSoftLink.h */,
                                A1F63C9E21A4DBF7006FB43B /* PassKitSoftLink.mm */,
                        );
                                0C2D9E731EEF5AF600DBC317 /* ExportMacros.h in Headers */,
                                F44291601FA5261E002CC93E /* FileSizeFormatter.h in Headers */,
                                0C5AF91B1F43A4C7002EAC02 /* GraphicsServicesSPI.h in Headers */,
+                               1C022EFF22CFEC53006DF01B /* Gunzip.h in Headers */,
                                A102658E1F567E9D00B4C844 /* HIServicesSPI.h in Headers */,
                                A10265891F56747A00B4C844 /* HIToolboxSPI.h in Headers */,
                                A39DE74E1F7C443D007BCB00 /* HysteresisActivity.h in Headers */,
                                1C4876D91F8D7F4E00CCEEBD /* Logging.h in Headers */,
                                44E1A8AF21FA54E600C3048E /* LookupSoftLink.h in Headers */,
                                0C77858B1F45130F00F4EBB6 /* LookupSPI.h in Headers */,
-                               1C022EFF22CFEC53006DF01B /* Gunzip.h in Headers */,
-                               0C2DA1481F3BEB4900DBC317 /* MachVMSPI.h in Headers */,
                                0C5AF91D1F43A4C7002EAC02 /* MediaPlayerSPI.h in Headers */,
                                0C77858C1F45130F00F4EBB6 /* MediaRemoteSPI.h in Headers */,
                                0C00CFD41F68CE4600AAC26D /* MediaTimeAVFoundation.h in Headers */,
                                A1175B581F6B470500C4B9F0 /* DefaultSearchProvider.cpp in Sources */,
                                F44291641FA52670002CC93E /* FileSizeFormatter.cpp in Sources */,
                                F44291681FA52705002CC93E /* FileSizeFormatterCocoa.mm in Sources */,
+                               1C022EFE22CFE8E1006DF01B /* Gunzip.cpp in Sources */,
                                A30D41221F0DD0EA00B71954 /* KillRing.cpp in Sources */,
                                A30D41251F0DD12D00B71954 /* KillRingMac.mm in Sources */,
-                               1C022EFE22CFE8E1006DF01B /* Gunzip.cpp in Sources */,
                                1C4876D81F8D7F4E00CCEEBD /* Logging.cpp in Sources */,
                                44E1A8B021FA54EB00C3048E /* LookupSoftLink.mm in Sources */,
                                0CF99CA41F736375007EE793 /* MediaTimeAVFoundation.cpp in Sources */,
index 71729a8..7330499 100644 (file)
@@ -30,7 +30,6 @@ list(APPEND PAL_PUBLIC_HEADERS
     spi/cocoa/IOSurfaceSPI.h
     spi/cocoa/IOTypesSPI.h
     spi/cocoa/LaunchServicesSPI.h
-    spi/cocoa/MachVMSPI.h
     spi/cocoa/NEFilterSourceSPI.h
     spi/cocoa/NSAttributedStringSPI.h
     spi/cocoa/NSButtonCellSPI.h
index 8a2135e..0d73e4b 100644 (file)
@@ -50,6 +50,7 @@
 #include "TextPainter.h"
 #include "WorkerThread.h"
 #include <wtf/FastMalloc.h>
+#include <wtf/ResourceUsage.h>
 #include <wtf/SystemTracing.h>
 
 #if PLATFORM(COCOA)
index 0e35ea2..4ac6a3f 100644 (file)
@@ -94,19 +94,6 @@ private:
 
 };
 
-#if PLATFORM(COCOA)
-struct TagInfo {
-    TagInfo() { }
-    size_t dirty { 0 };
-    size_t reclaimable { 0 };
-};
-
-const char* displayNameForVMTag(unsigned);
-size_t vmPageSize();
-std::array<TagInfo, 256> pagesPerVMTag();
-void logFootprintComparison(const std::array<TagInfo, 256>&, const std::array<TagInfo, 256>&);
-#endif
-
 } // namespace WebCore
 
 #endif // ENABLE(RESOURCE_USAGE)
index 107a9c9..869f812 100644 (file)
 #include <JavaScriptCore/VM.h>
 #include <mach/mach.h>
 #include <mach/vm_statistics.h>
-#include <pal/spi/cocoa/MachVMSPI.h>
 #include <wtf/MachSendRight.h>
+#include <wtf/ResourceUsage.h>
+#include <wtf/spi/cocoa/MachVMSPI.h>
 #include <wtf/text/StringConcatenateNumbers.h>
 
 namespace WebCore {
 
-size_t vmPageSize()
-{
-#if PLATFORM(IOS_FAMILY)
-    return vm_kernel_page_size;
-#else
-    static size_t cached = sysconf(_SC_PAGESIZE);
-    return cached;
-#endif
-}
-
-void logFootprintComparison(const std::array<TagInfo, 256>& before, const std::array<TagInfo, 256>& after)
-{
-    const size_t pageSize = vmPageSize();
-
-    WTFLogAlways("Per-tag breakdown of memory reclaimed by pressure handler:");
-    WTFLogAlways("  ## %16s %10s %10s %10s", "VM Tag", "Before", "After", "Diff");
-    for (unsigned i = 0; i < 256; ++i) {
-        ssize_t dirtyBefore = before[i].dirty * pageSize;
-        ssize_t dirtyAfter = after[i].dirty * pageSize;
-        ssize_t dirtyDiff = dirtyAfter - dirtyBefore;
-        if (!dirtyBefore && !dirtyAfter)
-            continue;
-        String tagName = displayNameForVMTag(i);
-        if (!tagName)
-            tagName = makeString("Tag ", i);
-        WTFLogAlways("  %02X %16s %10ld %10ld %10ld",
-            i,
-            tagName.ascii().data(),
-            dirtyBefore,
-            dirtyAfter,
-            dirtyDiff
-        );
-    }
-}
-
-const char* displayNameForVMTag(unsigned tag)
-{
-    switch (tag) {
-    case VM_MEMORY_IOKIT: return "IOKit";
-    case VM_MEMORY_LAYERKIT: return "CoreAnimation";
-    case VM_MEMORY_IMAGEIO: return "ImageIO";
-    case VM_MEMORY_CGIMAGE: return "CG image";
-    case VM_MEMORY_JAVASCRIPT_CORE: return "Gigacage";
-    case VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR: return "JSC JIT";
-    case VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE: return "IsoHeap";
-    case VM_MEMORY_MALLOC: return "malloc";
-    case VM_MEMORY_MALLOC_HUGE: return "malloc (huge)";
-    case VM_MEMORY_MALLOC_LARGE: return "malloc (large)";
-    case VM_MEMORY_MALLOC_SMALL: return "malloc (small)";
-    case VM_MEMORY_MALLOC_TINY: return "malloc (tiny)";
-    case VM_MEMORY_MALLOC_NANO: return "malloc (nano)";
-    case VM_MEMORY_TCMALLOC: return "bmalloc";
-    case VM_MEMORY_FOUNDATION: return "Foundation";
-    case VM_MEMORY_STACK: return "Stack";
-    case VM_MEMORY_SQLITE: return "SQLite";
-    case VM_MEMORY_UNSHARED_PMAP: return "pmap (unshared)";
-    case VM_MEMORY_DYLIB: return "dylib";
-    case VM_MEMORY_CORESERVICES: return "CoreServices";
-    case VM_MEMORY_OS_ALLOC_ONCE: return "os_alloc_once";
-    case VM_MEMORY_LIBDISPATCH: return "libdispatch";
-    default: return nullptr;
-    }
-}
-
-std::array<TagInfo, 256> pagesPerVMTag()
-{
-    std::array<TagInfo, 256> tags;
-    task_t task = mach_task_self();
-    mach_vm_size_t size;
-    uint32_t depth = 0;
-    struct vm_region_submap_info_64 info = { };
-    mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
-    for (mach_vm_address_t addr = 0; ; addr += size) {
-        int purgeableState;
-        if (mach_vm_purgable_control(task, addr, VM_PURGABLE_GET_STATE, &purgeableState) != KERN_SUCCESS)
-            purgeableState = VM_PURGABLE_DENY;
-
-        kern_return_t kr = mach_vm_region_recurse(task, &addr, &size, &depth, (vm_region_info_t)&info, &count);
-        if (kr != KERN_SUCCESS)
-            break;
-
-        if (purgeableState == VM_PURGABLE_VOLATILE) {
-            tags[info.user_tag].reclaimable += info.pages_resident;
-            continue;
-        }
-
-        if (purgeableState == VM_PURGABLE_EMPTY) {
-            tags[info.user_tag].reclaimable += size / vmPageSize();
-            continue;
-        }
-
-        bool anonymous = !info.external_pager;
-        if (anonymous) {
-            tags[info.user_tag].dirty += info.pages_resident - info.pages_reusable;
-            tags[info.user_tag].reclaimable += info.pages_reusable;
-        } else
-            tags[info.user_tag].dirty += info.pages_dirtied;
-    }
-
-    return tags;
-}
-
 static unsigned categoryForVMTag(unsigned tag)
 {
     switch (tag) {
index 4c19ebc..b26bf76 100644 (file)
@@ -1,3 +1,14 @@
+2019-07-24  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [bmalloc] Add IsoHeap test to ensure that IsoHeap pages are not allocating too large VA
+        https://bugs.webkit.org/show_bug.cgi?id=200103
+
+        Reviewed by Mark Lam.
+
+        Move MachVMSPI.h from PAL to WTF.
+
+        * Platform/cocoa/SharedMemoryCocoa.cpp:
+
 2019-07-24  Youenn Fablet  <youenn@apple.com>
 
         Disable speculative loading if cache is not to be used for the load
index e8c6fc0..17e6270 100644 (file)
@@ -34,9 +34,9 @@
 #include <mach/mach_error.h>
 #include <mach/mach_port.h>
 #include <mach/vm_map.h>
-#include <pal/spi/cocoa/MachVMSPI.h>
 #include <wtf/MachSendRight.h>
 #include <wtf/RefPtr.h>
+#include <wtf/spi/cocoa/MachVMSPI.h>
 
 namespace WebKit {
 
index e8502fa..3f0fb2e 100644 (file)
@@ -1,3 +1,12 @@
+2019-07-24  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [bmalloc] Add IsoHeap test to ensure that IsoHeap pages are not allocating too large VA
+        https://bugs.webkit.org/show_bug.cgi?id=200103
+
+        Reviewed by Mark Lam.
+
+        * bmalloc/IsoPage.cpp:
+
 2019-07-22  Yusuke Suzuki  <ysuzuki@apple.com>
 
         [bmalloc] Each IsoPage gets 1MB VA because VMHeap::tryAllocateLargeChunk rounds up
index 707c360..42049d1 100644 (file)
@@ -26,7 +26,7 @@
 #include "IsoPage.h"
 
 #include "PerProcess.h"
-#include "VMHeap.h"
+#include "VMAllocate.h"
 
 namespace bmalloc {
 
index 58cb65e..46c52a1 100644 (file)
@@ -1,3 +1,23 @@
+2019-07-24  Yusuke Suzuki  <ysuzuki@apple.com>
+
+        [bmalloc] Add IsoHeap test to ensure that IsoHeap pages are not allocating too large VA
+        https://bugs.webkit.org/show_bug.cgi?id=200103
+
+        Reviewed by Mark Lam.
+
+        This patch adds tests to TestWTF IsoHeap tests to ensure that IsoHeap's component is not leaking pages or not allocating too large VAs for memory allocation.
+        We use VMTag to get the system view of the allocated VAs and check whether it is not incredibly large.
+
+        While the tests are white-box tests (it means that this is a bit flaky to the implementation changes of IsoHeap), I adjusted some threshold to make this less-flaky
+        to the future implementation changes while it catches the severe issues we had.
+
+        * TestWebKitAPI/Tests/WTF/bmalloc/IsoHeap.cpp:
+        (assertEmptyPointerSet):
+        (assertHasOnlyObjects):
+        (assertClean):
+        (TEST):
+        (allocateAndDeallocate):
+
 2019-07-24  Fujii Hironori  <fujii.hironori@gmail.com>
 
         [CMake] CMAKE_SHARED_LINKER_FLAGS drops "-Wl,--no-undefined"
index 1ae50a5..81b2ced 100644 (file)
@@ -30,7 +30,9 @@
 #include <bmalloc/bmalloc.h>
 #include <bmalloc/Environment.h>
 #include <bmalloc/IsoHeapInlines.h>
+#include <wtf/ResourceUsage.h>
 #include <wtf/Threading.h>
+#include <wtf/VMTags.h>
 #include <wtf/WeakRandom.h>
 
 #include <cmath>
 using namespace bmalloc;
 using namespace bmalloc::api;
 
-#define RUN(test) do {                          \
-if (!shouldRun(#test))                  \
-break;                              \
-puts(#test "...");                      \
-test;                                   \
-puts(#test ": OK!");                    \
-} while (false)
-
-// Nothing fancy for now; we just use the existing WTF assertion machinery.
-#define CHECK(x) do {                                                   \
-if (!!(x))                                                      \
-break;                                                      \
-fprintf(stderr, "%s:%d: in %s: assertion %s failed.\n",         \
-__FILE__, __LINE__, __PRETTY_FUNCTION__, #x);               \
-abort();                                                        \
-} while (false)
-
 static std::set<void*> toptrset(const std::vector<void*>& ptrs)
 {
     std::set<void*> result;
@@ -81,7 +66,7 @@ static void assertEmptyPointerSet(const std::set<void*>& pointers)
     for (void* ptr : pointers)
         printf(" %p", ptr);
     printf("\n");
-    CHECK(pointers.empty());
+    EXPECT_TRUE(pointers.empty());
 }
 
 template<typename heapType>
@@ -111,7 +96,7 @@ static void assertHasOnlyObjects(IsoHeap<heapType>& heap, std::set<void*> pointe
     std::lock_guard<bmalloc::Mutex> locker(impl.lock);
     impl.forEachLiveObject(
         [&] (void* object) {
-            CHECK(pointers.erase(object) == 1);
+            EXPECT_EQ(pointers.erase(object), 1U);
         });
     assertEmptyPointerSet(pointers);
 }
@@ -124,14 +109,14 @@ static void assertClean(IsoHeap<heapType>& heap)
         auto& impl = heap.impl();
         {
             std::lock_guard<bmalloc::Mutex> locker(impl.lock);
-            CHECK(!impl.numLiveObjects());
+            EXPECT_FALSE(impl.numLiveObjects());
         }
     }
     heap.scavenge();
     if (!Environment::get()->isDebugHeapEnabled()) {
         auto& impl = heap.impl();
         std::lock_guard<bmalloc::Mutex> locker(impl.lock);
-        CHECK(!impl.numCommittedPages());
+        EXPECT_FALSE(impl.numCommittedPages());
     }
 }
 
@@ -139,11 +124,11 @@ TEST(bmalloc, IsoSimple)
 {
     static IsoHeap<double> heap;
     void* ptr1 = heap.allocate();
-    CHECK(ptr1);
+    EXPECT_TRUE(ptr1);
     void* ptr2 = heap.allocate();
-    CHECK(ptr2);
-    CHECK(ptr1 != ptr2);
-    CHECK(std::abs(static_cast<char*>(ptr1) - static_cast<char*>(ptr2)) >= 8);
+    EXPECT_TRUE(ptr2);
+    EXPECT_NE(ptr1, ptr2);
+    EXPECT_GE(std::abs(static_cast<char*>(ptr1) - static_cast<char*>(ptr2)), 8);
     assertHasObjects(heap, {ptr1, ptr2});
     heap.deallocate(ptr1);
     heap.deallocate(ptr2);
@@ -154,11 +139,11 @@ TEST(bmalloc, IsoSimpleScavengeBeforeDealloc)
 {
     static IsoHeap<double> heap;
     void* ptr1 = heap.allocate();
-    CHECK(ptr1);
+    EXPECT_TRUE(ptr1);
     void* ptr2 = heap.allocate();
-    CHECK(ptr2);
-    CHECK(ptr1 != ptr2);
-    CHECK(std::abs(static_cast<char*>(ptr1) - static_cast<char*>(ptr2)) >= 8);
+    EXPECT_TRUE(ptr2);
+    EXPECT_NE(ptr1, ptr2);
+    EXPECT_GE(std::abs(static_cast<char*>(ptr1) - static_cast<char*>(ptr2)), 8);
     scavengeThisThread();
     assertHasOnlyObjects(heap, {ptr1, ptr2});
     heap.deallocate(ptr1);
@@ -172,7 +157,7 @@ TEST(bmalloc, IsoFlipFlopFragmentedPages)
     std::vector<void*> ptrs;
     for (unsigned i = 100000; i--;) {
         void* ptr = heap.allocate();
-        CHECK(ptr);
+        EXPECT_TRUE(ptr);
         ptrs.push_back(ptr);
     }
     for (unsigned i = 0; i < ptrs.size(); i += 2) {
@@ -192,10 +177,10 @@ TEST(bmalloc, IsoFlipFlopFragmentedPagesScavengeInMiddle)
     std::vector<void*> ptrs;
     for (unsigned i = 100000; i--;) {
         void* ptr = heap.allocate();
-        CHECK(ptr);
+        EXPECT_TRUE(ptr);
         ptrs.push_back(ptr);
     }
-    CHECK(toptrset(ptrs).size() == ptrs.size());
+    EXPECT_EQ(toptrset(ptrs).size(), ptrs.size());
     for (unsigned i = 0; i < ptrs.size(); i += 2) {
         heap.deallocate(ptrs[i]);
         ptrs[i] = nullptr;
@@ -212,7 +197,7 @@ TEST(bmalloc, IsoFlipFlopFragmentedPagesScavengeInMiddle)
         ptrs.push_back(heap.allocate());
     {
         std::lock_guard<bmalloc::Mutex> locker(impl.lock);
-        CHECK(numCommittedPagesBefore == impl.numCommittedPages());
+        EXPECT_EQ(numCommittedPagesBefore, impl.numCommittedPages());
     }
     for (void* ptr : ptrs)
         heap.deallocate(ptr);
@@ -225,10 +210,10 @@ TEST(bmalloc, IsoFlipFlopFragmentedPagesScavengeInMiddle288)
     std::vector<void*> ptrs;
     for (unsigned i = 100000; i--;) {
         void* ptr = heap.allocate();
-        CHECK(ptr);
+        EXPECT_TRUE(ptr);
         ptrs.push_back(ptr);
     }
-    CHECK(toptrset(ptrs).size() == ptrs.size());
+    EXPECT_EQ(toptrset(ptrs).size(), ptrs.size());
     for (unsigned i = 0; i < ptrs.size(); i += 2) {
         heap.deallocate(ptrs[i]);
         ptrs[i] = nullptr;
@@ -245,7 +230,7 @@ TEST(bmalloc, IsoFlipFlopFragmentedPagesScavengeInMiddle288)
         ptrs.push_back(heap.allocate());
     {
         std::lock_guard<bmalloc::Mutex> locker(impl.lock);
-        CHECK(numCommittedPagesBefore == impl.numCommittedPages());
+        EXPECT_EQ(numCommittedPagesBefore, impl.numCommittedPages());
     }
     for (void* ptr : ptrs)
         heap.deallocate(ptr);
@@ -260,7 +245,7 @@ TEST(bmalloc, IsoMallocAndFreeFast)
         ptr = heap.allocate();
         heap.deallocate(ptr);
     }
-    CHECK(!IsoPageBase::pageFor(ptr)->isShared());
+    EXPECT_FALSE(IsoPageBase::pageFor(ptr)->isShared());
 }
 
 class BisoMalloced {
@@ -319,21 +304,21 @@ TEST(bmalloc, ScavengedMemoryShouldBeReused)
         // Let's exhaust the capacity of the lower tier.
         for (unsigned i = 0; i < IsoPage<decltype(heap)::Config>::numObjects; ++i) {
             void* ptr = heap.allocate();
-            CHECK(ptr);
+            EXPECT_TRUE(ptr);
             lowerTierPtrs.push_back(ptr);
         }
 
         // After that, allocating pointers in the upper tier.
         for (unsigned i = 0; ;i++) {
             void* ptr = heap.allocate();
-            CHECK(ptr);
+            EXPECT_TRUE(ptr);
             ptrs.push_back(ptr);
             if (heap.impl().numCommittedPages() == numPagesToCommit)
                 break;
         }
 
         std::set<void*> uniquedPtrsOfUpperTiers = toptrset(ptrs);
-        CHECK(ptrs.size() == uniquedPtrsOfUpperTiers.size());
+        EXPECT_EQ(ptrs.size(), uniquedPtrsOfUpperTiers.size());
 
         std::set<void*> uniquedPtrs = uniquedPtrsOfUpperTiers;
         for (void* ptr : lowerTierPtrs)
@@ -351,7 +336,7 @@ TEST(bmalloc, ScavengedMemoryShouldBeReused)
         assertHasOnlyObjects(heap, uniquedPtrs);
 
         auto* ptr2 = heap.allocate();
-        CHECK(uniquedPtrsOfUpperTiers.find(ptr2) != uniquedPtrsOfUpperTiers.end());
+        EXPECT_NE(uniquedPtrsOfUpperTiers.find(ptr2), uniquedPtrsOfUpperTiers.end());
         heap.deallocate(ptr2);
 
         for (void* ptr : lowerTierPtrs)
@@ -2481,4 +2466,65 @@ TEST(bmalloc, IsoHeapMultipleThreads)
         thread->waitForCompletion();
 }
 
+#if PLATFORM(COCOA)
+static void allocateAndDeallocate()
+{
+    static IsoHeap<double> heap;
+    std::vector<void*> ptrs;
+    // This exhausts # of instances assigned to IsoHeap shared tier.
+    for (unsigned i = 0; i < 100; ++i)
+        ptrs.push_back(heap.allocate());
+    for (void* ptr : ptrs)
+        heap.deallocate(ptr);
+    heap.scavenge();
+}
+
+TEST(bmalloc, IsoHeapIsoTLSLeak)
+{
+    allocateAndDeallocate();
+    auto before = pagesPerVMTag();
+    for (unsigned i = 0; i < 1000; ++i) {
+        auto thread = Thread::create("IsoHeapStress", allocateAndDeallocate);
+        thread->waitForCompletion();
+    }
+    auto after = pagesPerVMTag();
+    // Previously, we have an issue that every thread leaks 1~ page. The underlying IsoHeap implementation can add some IsoPages during this test and it would change the value of this,
+    // but we can relatively non-flakily say that such an implementation change would not add 100 more pages, and if we have a leak in IsoTLS, it is larger than 1000 pages and this test correctly catch the issue.
+    EXPECT_LT((static_cast<int64_t>(after[VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE].reserved) - static_cast<int64_t>(before[VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE].reserved)) * static_cast<int64_t>(WTF::vmPageSize()), 100 * static_cast<int64_t>(WTF::vmPageSize()));
+}
+
+TEST(bmalloc, IsoHeapIsoPageAllocatingOnePage)
+{
+    struct LargeData {
+        std::array<double, 256> data;
+    };
+    static IsoHeap<LargeData> heap;
+
+    std::vector<void*> ptrs;
+    for (unsigned i = 0; i < 50; ++i)
+        ptrs.push_back(heap.allocate());
+    for (void* ptr : ptrs)
+        heap.deallocate(ptr);
+    heap.scavenge();
+    ptrs.clear();
+
+    auto before = pagesPerVMTag();
+
+    for (unsigned i = 0; i < 16000; ++i)
+        ptrs.push_back(heap.allocate());
+    for (auto* ptr : ptrs)
+        heap.deallocate(ptr);
+    heap.scavenge();
+    ptrs.clear();
+
+    auto after = pagesPerVMTag();
+    // This number (50MB) heavily relies on the underlying implementation of IsoHeap. To make this test less-flaky, we picked a bit large number than the current one, 50MB,
+    // to make this test work even if the underlying implementation of IsoHeap is changed, e.g. adding more # of IsoHeap shared tier instances.
+    // Currently, this number says 31MB in macOS, so 50MB threshold can catch the issue if the catastrophic thing happens. For example, if we revert https://bugs.webkit.org/show_bug.cgi?id=200024,
+    // we will see 2GB VA allocations here, which can be caught by this test. We can adjust this threshold if the underlying implementation is largely changed and this number
+    EXPECT_LT((static_cast<int64_t>(after[VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE].reserved) - static_cast<int64_t>(before[VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE].reserved)) * static_cast<int64_t>(WTF::vmPageSize()), (50 << 20));
+}
+
+#endif
+
 #endif