Add a version of JSVirtualMachine shrinkFootprint that runs when the VM goes idle
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 May 2018 04:36:07 +0000 (04:36 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 May 2018 04:36:07 +0000 (04:36 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186064

Reviewed by Mark Lam.

shrinkFootprint was implemented as:
```
sanitizeStackForVM(this);
deleteAllCode(DeleteAllCodeIfNotCollecting);
heap.collectNow(Synchronousness::Sync);
WTF::releaseFastMallocFreeMemory();
```

However, for correctness reasons, deleteAllCode is implemented to do
work when the VM is idle: no JS is running on the stack. This means
that if shrinkFootprint is called when JS is running on the stack, it
ends up freeing less memory than it could have if it waited to run until
the VM goes idle.

This patch makes it so we wait until idle before doing work. I'm seeing a
10% footprint progression when testing this against a client of the JSC SPI.

Because this is a semantic change in how the SPI works, this patch
adds new SPI named shrinkFootprintWhenIdle. The plan is to move
all clients of the shrinkFootprint SPI to shrinkFootprintWhenIdle.
Once that happens, we will delete shrinkFootprint. Until then,
we make shrinkFootprint do exactly what shrinkFootprintWhenIdle does.

* API/JSVirtualMachine.mm:
(-[JSVirtualMachine shrinkFootprint]):
(-[JSVirtualMachine shrinkFootprintWhenIdle]):
* API/JSVirtualMachinePrivate.h:
* runtime/VM.cpp:
(JSC::VM::shrinkFootprintWhenIdle):
(JSC::VM::shrinkFootprint): Deleted.
* runtime/VM.h:

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

Source/JavaScriptCore/API/JSVirtualMachine.mm
Source/JavaScriptCore/API/JSVirtualMachinePrivate.h
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h

index a091cfd..424a457 100644 (file)
@@ -272,7 +272,14 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
 {
     JSC::VM* vm = toJS(m_group);
     JSC::JSLockHolder locker(vm);
-    vm->shrinkFootprint();
+    vm->shrinkFootprintWhenIdle();
+}
+
+- (void)shrinkFootprintWhenIdle
+{
+    JSC::VM* vm = toJS(m_group);
+    JSC::JSLockHolder locker(vm);
+    vm->shrinkFootprintWhenIdle();
 }
 
 @end
index 0c20b23..e2a2233 100644 (file)
 
 @interface JSVirtualMachine(JSPrivate)
 
+- (void)shrinkFootprint; // FIXME: Remove this SPI when clients move to shrinkFootprintWhenIdle: https://bugs.webkit.org/show_bug.cgi?id=186071
+
 /*!
 @method
 @discussion Shrinks the memory footprint of the VM by deleting various internal caches,
- running synchronous garbage collection, and releasing memory back to the OS. For this
- to free as much memory as possible, do not call this when JavaScript is running on the stack.
+ running synchronous garbage collection, and releasing memory back to the OS. Note: this
+ API waits until no JavaScript is running on the stack before it frees any memory. It's
+ best to call this API when no JavaScript is running on the stack for this reason. However, if
+ you do call this API when JavaScript is running on the stack, the API will wait until all JavaScript
+ on the stack finishes running to free memory back to the OS. Therefore, calling this
+ API may not synchronously free memory.
 */
 
-- (void)shrinkFootprint; // FIXME: Annotate this with NS_AVAILABLE: <rdar://problem/40071332>.
+- (void)shrinkFootprintWhenIdle; // FIXME: Annotate this with NS_AVAILABLE: <rdar://problem/40071332>.
 
 @end
 
index b2ac55d..8a3c236 100644 (file)
@@ -1,5 +1,44 @@
 2018-05-29  Saam Barati  <sbarati@apple.com>
 
+        Add a version of JSVirtualMachine shrinkFootprint that runs when the VM goes idle
+        https://bugs.webkit.org/show_bug.cgi?id=186064
+
+        Reviewed by Mark Lam.
+
+        shrinkFootprint was implemented as:
+        ```
+        sanitizeStackForVM(this);
+        deleteAllCode(DeleteAllCodeIfNotCollecting);
+        heap.collectNow(Synchronousness::Sync);
+        WTF::releaseFastMallocFreeMemory();
+        ```
+        
+        However, for correctness reasons, deleteAllCode is implemented to do
+        work when the VM is idle: no JS is running on the stack. This means
+        that if shrinkFootprint is called when JS is running on the stack, it
+        ends up freeing less memory than it could have if it waited to run until
+        the VM goes idle.
+        
+        This patch makes it so we wait until idle before doing work. I'm seeing a
+        10% footprint progression when testing this against a client of the JSC SPI.
+        
+        Because this is a semantic change in how the SPI works, this patch
+        adds new SPI named shrinkFootprintWhenIdle. The plan is to move
+        all clients of the shrinkFootprint SPI to shrinkFootprintWhenIdle.
+        Once that happens, we will delete shrinkFootprint. Until then,
+        we make shrinkFootprint do exactly what shrinkFootprintWhenIdle does.
+
+        * API/JSVirtualMachine.mm:
+        (-[JSVirtualMachine shrinkFootprint]):
+        (-[JSVirtualMachine shrinkFootprintWhenIdle]):
+        * API/JSVirtualMachinePrivate.h:
+        * runtime/VM.cpp:
+        (JSC::VM::shrinkFootprintWhenIdle):
+        (JSC::VM::shrinkFootprint): Deleted.
+        * runtime/VM.h:
+
+2018-05-29  Saam Barati  <sbarati@apple.com>
+
         shrinkFootprint needs to request a full collection
         https://bugs.webkit.org/show_bug.cgi?id=186069
 
index d20b7f5..83b1b30 100644 (file)
@@ -777,14 +777,16 @@ void VM::deleteAllCode(DeleteAllCodeEffort effort)
     });
 }
 
-void VM::shrinkFootprint()
-{
-    sanitizeStackForVM(this);
-    deleteAllCode(DeleteAllCodeIfNotCollecting);
-    heap.collectNow(Synchronousness::Sync, CollectionScope::Full);
-    WTF::releaseFastMallocFreeMemory();
-    // FIXME: Consider stopping various automatic threads here.
-    // https://bugs.webkit.org/show_bug.cgi?id=185447
+void VM::shrinkFootprintWhenIdle()
+{
+    whenIdle([=] () {
+        sanitizeStackForVM(this);
+        deleteAllCode(DeleteAllCodeIfNotCollecting);
+        heap.collectNow(Synchronousness::Sync, CollectionScope::Full);
+        // FIXME: Consider stopping various automatic threads here.
+        // https://bugs.webkit.org/show_bug.cgi?id=185447
+        WTF::releaseFastMallocFreeMemory();
+    });
 }
 
 SourceProviderCache* VM::addSourceProviderCache(SourceProvider* sourceProvider)
index f3afd22..90e364e 100644 (file)
@@ -745,7 +745,7 @@ public:
     JS_EXPORT_PRIVATE void deleteAllCode(DeleteAllCodeEffort);
     JS_EXPORT_PRIVATE void deleteAllLinkedCode(DeleteAllCodeEffort);
 
-    void shrinkFootprint();
+    void shrinkFootprintWhenIdle();
 
     WatchpointSet* ensureWatchpointSetForImpureProperty(const Identifier&);
     void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*);