Skip to content

Commit 38ea2b5

Browse files
committed
Add JSVirtualMachine SPI to shrink the memory footprint of the VM
https://bugs.webkit.org/show_bug.cgi?id=185441 <rdar://problem/39999414> Reviewed by Keith Miller. This patch adds JSVirtualMachine SPI to release as much memory as possible. The SPI does: - Deletes all code caches. - Synchronous GC. - Run the scavenger. * API/JSVirtualMachine.mm: (-[JSVirtualMachine shrinkFootprint]): * API/JSVirtualMachinePrivate.h: Added. * API/tests/testapi.mm: (testObjectiveCAPIMain): * JavaScriptCore.xcodeproj/project.pbxproj: * runtime/VM.cpp: (JSC::VM::shrinkFootprint): * runtime/VM.h: Canonical link: https://commits.webkit.org/200963@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@231589 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent d6f17f5 commit 38ea2b5

7 files changed

Lines changed: 122 additions & 0 deletions

File tree

Source/JavaScriptCore/API/JSVirtualMachine.mm

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,13 @@ - (NSMapTable *)externalRememberedSet
268268
return m_externalRememberedSet;
269269
}
270270

271+
- (void)shrinkFootprint
272+
{
273+
JSC::VM* vm = toJS(m_group);
274+
JSC::JSLockHolder locker(vm);
275+
vm->shrinkFootprint();
276+
}
277+
271278
@end
272279

273280
static void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root, bool lockAcquired)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (C) 2018 Apple Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21+
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
#include <JavaScriptCore/JavaScript.h>
27+
28+
#if JSC_OBJC_API_ENABLED
29+
30+
#import <JavaScriptCore/JSVirtualMachine.h>
31+
32+
@interface JSVirtualMachine(JSPrivate)
33+
34+
/*!
35+
@method
36+
@discussion Shrinks the memory footprint of the VM by deleting various internal caches,
37+
running synchronous garbage collection, and releasing memory back to the OS. For this
38+
to free as much memory as possible, do not call this when JavaScript is running on the stack.
39+
*/
40+
41+
- (void)shrinkFootprint; // FIXME: Annotate this with NS_AVAILABLE: <rdar://problem/40071332>.
42+
43+
@end
44+
45+
#endif // JSC_OBJC_API_ENABLED

Source/JavaScriptCore/API/tests/testapi.mm

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@
2828
#import "CurrentThisInsideBlockGetterTest.h"
2929
#import "DateTests.h"
3030
#import "JSExportTests.h"
31+
#import "JSVirtualMachinePrivate.h"
3132
#import "Regress141275.h"
3233
#import "Regress141809.h"
3334

3435
#import <pthread.h>
3536
#import <vector>
37+
#import <wtf/MemoryFootprint.h>
38+
#import <wtf/Optional.h>
3639

3740
extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef);
3841
extern "C" void JSSynchronousEdenCollectForDebugging(JSContextRef);
@@ -1469,6 +1472,33 @@ static void testObjectiveCAPIMain()
14691472
checkResult(@"Ran code in five concurrent VMs that GC'd", ok);
14701473
}
14711474

1475+
@autoreleasepool {
1476+
JSContext *context = [[JSContext alloc] init];
1477+
JSVirtualMachine *vm = [context virtualMachine];
1478+
[vm shrinkFootprint]; // Make sure that when we allocate a ton of memory below we reuse at little as possible.
1479+
1480+
std::optional<size_t> footprintBefore = WTF::memoryFootprint();
1481+
RELEASE_ASSERT(footprintBefore);
1482+
1483+
[context evaluateScript:@"for (let i = 0; i < 10000; ++i) { eval(`myVariable_${i} = [i]`); }"];
1484+
1485+
static constexpr size_t approximateBytes = 10000 * sizeof(int);
1486+
std::optional<size_t> footprintMiddle = WTF::memoryFootprint();
1487+
RELEASE_ASSERT(footprintMiddle);
1488+
checkResult(@"Footprint is larger than what we allocated", *footprintMiddle > approximateBytes);
1489+
checkResult(@"Footprint got larger as we allocated a ton of stuff", *footprintMiddle > *footprintBefore);
1490+
size_t allocationDelta = *footprintMiddle - *footprintBefore;
1491+
checkResult(@"We allocated as much or more memory than what we expected to", allocationDelta >= approximateBytes);
1492+
1493+
[context evaluateScript:@"for (let i = 0; i < 10000; ++i) { eval(`myVariable_${i} = null`); }"];
1494+
[vm shrinkFootprint];
1495+
std::optional<size_t> footprintAfter = WTF::memoryFootprint();
1496+
RELEASE_ASSERT(footprintAfter);
1497+
checkResult(@"Footprint got smaller after we shrank the VM", *footprintAfter < *footprintMiddle);
1498+
size_t freeDelta = *footprintMiddle - *footprintAfter;
1499+
checkResult(@"Shrinking the footprint of the VM actually freed memory", freeDelta > (approximateBytes / 2));
1500+
}
1501+
14721502
currentThisInsideBlockGetterTest();
14731503
runDateTests();
14741504
runJSExportTests();

Source/JavaScriptCore/ChangeLog

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
2018-05-09 Saam Barati <sbarati@apple.com>
2+
3+
Add JSVirtualMachine SPI to shrink the memory footprint of the VM
4+
https://bugs.webkit.org/show_bug.cgi?id=185441
5+
<rdar://problem/39999414>
6+
7+
Reviewed by Keith Miller.
8+
9+
This patch adds JSVirtualMachine SPI to release as much memory as possible.
10+
The SPI does:
11+
- Deletes all code caches.
12+
- Synchronous GC.
13+
- Run the scavenger.
14+
15+
* API/JSVirtualMachine.mm:
16+
(-[JSVirtualMachine shrinkFootprint]):
17+
* API/JSVirtualMachinePrivate.h: Added.
18+
* API/tests/testapi.mm:
19+
(testObjectiveCAPIMain):
20+
* JavaScriptCore.xcodeproj/project.pbxproj:
21+
* runtime/VM.cpp:
22+
(JSC::VM::shrinkFootprint):
23+
* runtime/VM.h:
24+
125
2018-05-09 Leo Balter <leonardo.balter@gmail.com>
226

327
[JSC] Fix ArraySpeciesCreate to return a new Array when the given object is not an array

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,7 @@
10991099
7919B7801E03559C005BEED8 /* B3Compile.h in Headers */ = {isa = PBXBuildFile; fileRef = 7919B77F1E03559C005BEED8 /* B3Compile.h */; settings = {ATTRIBUTES = (Private, ); }; };
11001100
79233C2B1D34715700C5A834 /* JITMathIC.h in Headers */ = {isa = PBXBuildFile; fileRef = 79233C291D34715700C5A834 /* JITMathIC.h */; settings = {ATTRIBUTES = (Private, ); }; };
11011101
792CB34A1C4EED5C00D13AF3 /* PCToCodeOriginMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 792CB3481C4EED5C00D13AF3 /* PCToCodeOriginMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
1102+
795AC61820A2355E0052C76C /* JSVirtualMachinePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 795AC61720A2354B0052C76C /* JSVirtualMachinePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
11021103
7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 796465681B952FF0003059EE /* GetPutInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
11031104
7965C2171E5D799600B7591D /* AirAllocateRegistersByGraphColoring.h in Headers */ = {isa = PBXBuildFile; fileRef = 7965C2151E5D799600B7591D /* AirAllocateRegistersByGraphColoring.h */; settings = {ATTRIBUTES = (Private, ); }; };
11041105
796DAA2B1E89CCD6005DF24A /* CalleeBits.h in Headers */ = {isa = PBXBuildFile; fileRef = 796DAA2A1E89CCD6005DF24A /* CalleeBits.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -3611,6 +3612,7 @@
36113612
79233C291D34715700C5A834 /* JITMathIC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITMathIC.h; sourceTree = "<group>"; };
36123613
792CB3471C4EED5C00D13AF3 /* PCToCodeOriginMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCToCodeOriginMap.cpp; sourceTree = "<group>"; };
36133614
792CB3481C4EED5C00D13AF3 /* PCToCodeOriginMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCToCodeOriginMap.h; sourceTree = "<group>"; };
3615+
795AC61720A2354B0052C76C /* JSVirtualMachinePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSVirtualMachinePrivate.h; sourceTree = "<group>"; };
36143616
795F099C1E03600500BBE37F /* B3Compile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3Compile.cpp; path = b3/B3Compile.cpp; sourceTree = "<group>"; };
36153617
796465681B952FF0003059EE /* GetPutInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPutInfo.h; sourceTree = "<group>"; };
36163618
7965C2141E5D799600B7591D /* AirAllocateRegistersByGraphColoring.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirAllocateRegistersByGraphColoring.cpp; path = b3/air/AirAllocateRegistersByGraphColoring.cpp; sourceTree = "<group>"; };
@@ -5848,6 +5850,7 @@
58485850
14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */,
58495851
1482B6EA0A4300B300517CFC /* JSValueRef.h */,
58505852
86E3C60F167BAB87006D760A /* JSVirtualMachine.h */,
5853+
795AC61720A2354B0052C76C /* JSVirtualMachinePrivate.h */,
58515854
86E3C610167BAB87006D760A /* JSVirtualMachine.mm */,
58525855
86E3C611167BAB87006D760A /* JSVirtualMachineInternal.h */,
58535856
A7482E37116A697B003B0712 /* JSWeakObjectMapRefInternal.h */,
@@ -8594,6 +8597,7 @@
85948597
0FFB921C16D02F110055A5DB /* DFGOSRExitCompilationInfo.h in Headers */,
85958598
0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */,
85968599
0F392C8A1B46188400844728 /* DFGOSRExitFuzz.h in Headers */,
8600+
795AC61820A2355E0052C76C /* JSVirtualMachinePrivate.h in Headers */,
85978601
0FEFC9AB1681A3B600567F53 /* DFGOSRExitJumpPlaceholder.h in Headers */,
85988602
0F235BEE17178E7300690C7F /* DFGOSRExitPreparation.h in Headers */,
85998603
0F6237981AE45CA700D402EA /* DFGPhantomInsertionPhase.h in Headers */,

Source/JavaScriptCore/runtime/VM.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,16 @@ void VM::deleteAllCode(DeleteAllCodeEffort effort)
771771
});
772772
}
773773

774+
void VM::shrinkFootprint()
775+
{
776+
sanitizeStackForVM(this);
777+
deleteAllCode(DeleteAllCodeIfNotCollecting);
778+
heap.collectSync();
779+
WTF::releaseFastMallocFreeMemory();
780+
// FIXME: Consider stopping various automatic threads here.
781+
// https://bugs.webkit.org/show_bug.cgi?id=185447
782+
}
783+
774784
SourceProviderCache* VM::addSourceProviderCache(SourceProvider* sourceProvider)
775785
{
776786
auto addResult = sourceProviderCacheMap.add(sourceProvider, nullptr);

Source/JavaScriptCore/runtime/VM.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,8 @@ class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {
746746
JS_EXPORT_PRIVATE void deleteAllCode(DeleteAllCodeEffort);
747747
JS_EXPORT_PRIVATE void deleteAllLinkedCode(DeleteAllCodeEffort);
748748

749+
void shrinkFootprint();
750+
749751
WatchpointSet* ensureWatchpointSetForImpureProperty(const Identifier&);
750752
void registerWatchpointForImpureProperty(const Identifier&, Watchpoint*);
751753

0 commit comments

Comments
 (0)