Title: [187125] trunk
Revision
187125
Author
fpi...@apple.com
Date
2015-07-21 14:41:30 -0700 (Tue, 21 Jul 2015)

Log Message

Fixed VM pool allocation should have a reserve for allocations that cannot fail
https://bugs.webkit.org/show_bug.cgi?id=147154
rdar://problem/21847618

Reviewed by Geoffrey Garen.
        
Source/_javascript_Core:

This adds the notion of a JIT pool reserve fraction. Some fraction, currently 1/4, of
the JIT pool is reserved for allocations that cannot fail. It makes sense to make this
a fraction rather than a constant because each allocation that can fail may cause some
number of allocations that cannot fail (for example, the OSR exit thunks that we
compile when we exit from some CodeBlock cannot fail).
        
I've tested this by adding a test mode where we artificially limit the JIT pool size.
Prior to the fix, we had >20 failures. Now we have none.

* heap/GCLogging.cpp:
(WTF::printInternal): I needed a dump method on Options members when debugging this.
* heap/GCLogging.h:
* jit/ExecutableAllocator.h: Raise the ARM64 limit to 32MB because 16MB is cutting it too close.
* jit/ExecutableAllocatorFixedVMPool.cpp:
(JSC::FixedVMPoolExecutableAllocator::FixedVMPoolExecutableAllocator): Add the ability to artificially limit JIT pool size for testing.
(JSC::ExecutableAllocator::memoryPressureMultiplier): Implement the reserve when computing memory pressure for JIT tier-up heuristics.
(JSC::ExecutableAllocator::allocate): Implement the reserve when allocating can-fail things.
* jsc.cpp: Rewire some options parsing so that CommandLine happens before we create the JIT pool.
(main):
(CommandLine::parseArguments):
(jscmain):
* runtime/Options.cpp: 
(JSC::OptionRange::dump): I needed a dump method on Options members when debugging this.
(JSC::Options::initialize): This can now be called more than once.
* runtime/Options.h:

Tools:

Add a new test mode where we artificially limit JIT memory to 50KB. If our JIT OOM
mitigations work, these should all pass. Prior to this patch there were >20 failures.

* Scripts/run-jsc-stress-tests:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (187124 => 187125)


--- trunk/Source/_javascript_Core/ChangeLog	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-07-21 21:41:30 UTC (rev 187125)
@@ -1,3 +1,37 @@
+2015-07-21  Filip Pizlo  <fpi...@apple.com>
+
+        Fixed VM pool allocation should have a reserve for allocations that cannot fail
+        https://bugs.webkit.org/show_bug.cgi?id=147154
+        rdar://problem/21847618
+
+        Reviewed by Geoffrey Garen.
+        
+        This adds the notion of a JIT pool reserve fraction. Some fraction, currently 1/4, of
+        the JIT pool is reserved for allocations that cannot fail. It makes sense to make this
+        a fraction rather than a constant because each allocation that can fail may cause some
+        number of allocations that cannot fail (for example, the OSR exit thunks that we
+        compile when we exit from some CodeBlock cannot fail).
+        
+        I've tested this by adding a test mode where we artificially limit the JIT pool size.
+        Prior to the fix, we had >20 failures. Now we have none.
+
+        * heap/GCLogging.cpp:
+        (WTF::printInternal): I needed a dump method on Options members when debugging this.
+        * heap/GCLogging.h:
+        * jit/ExecutableAllocator.h: Raise the ARM64 limit to 32MB because 16MB is cutting it too close.
+        * jit/ExecutableAllocatorFixedVMPool.cpp:
+        (JSC::FixedVMPoolExecutableAllocator::FixedVMPoolExecutableAllocator): Add the ability to artificially limit JIT pool size for testing.
+        (JSC::ExecutableAllocator::memoryPressureMultiplier): Implement the reserve when computing memory pressure for JIT tier-up heuristics.
+        (JSC::ExecutableAllocator::allocate): Implement the reserve when allocating can-fail things.
+        * jsc.cpp: Rewire some options parsing so that CommandLine happens before we create the JIT pool.
+        (main):
+        (CommandLine::parseArguments):
+        (jscmain):
+        * runtime/Options.cpp: 
+        (JSC::OptionRange::dump): I needed a dump method on Options members when debugging this.
+        (JSC::Options::initialize): This can now be called more than once.
+        * runtime/Options.h:
+
 2015-07-21  Saam barati  <saambara...@gmail.com>
 
         ObjectPatternNode's entry should use "const Identifier&" instead of "Identifier"

Modified: trunk/Source/_javascript_Core/heap/GCLogging.cpp (187124 => 187125)


--- trunk/Source/_javascript_Core/heap/GCLogging.cpp	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Source/_javascript_Core/heap/GCLogging.cpp	2015-07-21 21:41:30 UTC (rev 187125)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
 #include "HeapIterationScope.h"
 #include "JSCell.h"
 #include "JSCellInlines.h"
+#include <wtf/PrintStream.h>
 
 namespace JSC {
 
@@ -113,3 +114,26 @@
 }
 
 } // namespace JSC
+
+namespace WTF {
+
+void printInternal(PrintStream& out, JSC::GCLogging::Level level)
+{
+    switch (level) {
+    case JSC::GCLogging::Level::None:
+        out.print("None");
+        return;
+    case JSC::GCLogging::Level::Basic:
+        out.print("Basic");
+        return;
+    case JSC::GCLogging::Level::Verbose:
+        out.print("Verbose");
+        return;
+    default:
+        out.print("Level=", level - JSC::GCLogging::Level::None);
+        return;
+    }
+}
+
+} // namespace WTF
+

Modified: trunk/Source/_javascript_Core/heap/GCLogging.h (187124 => 187125)


--- trunk/Source/_javascript_Core/heap/GCLogging.h	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Source/_javascript_Core/heap/GCLogging.h	2015-07-21 21:41:30 UTC (rev 187125)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -48,4 +48,12 @@
 
 } // namespace JSC
 
+namespace WTF {
+
+class PrintStream;
+
+void printInternal(PrintStream&, JSC::GCLogging::Level);
+
+} // namespace WTF
+
 #endif // GCLogging_h

Modified: trunk/Source/_javascript_Core/jit/ExecutableAllocator.h (187124 => 187125)


--- trunk/Source/_javascript_Core/jit/ExecutableAllocator.h	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Source/_javascript_Core/jit/ExecutableAllocator.h	2015-07-21 21:41:30 UTC (rev 187125)
@@ -80,13 +80,16 @@
 #endif
 
 #if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
-#if CPU(ARM) || CPU(ARM64)
+#if CPU(ARM)
 static const size_t fixedExecutableMemoryPoolSize = 16 * 1024 * 1024;
+#elif CPU(ARM64)
+static const size_t fixedExecutableMemoryPoolSize = 32 * 1024 * 1024;
 #elif CPU(X86_64)
 static const size_t fixedExecutableMemoryPoolSize = 1024 * 1024 * 1024;
 #else
 static const size_t fixedExecutableMemoryPoolSize = 32 * 1024 * 1024;
 #endif
+static const double executablePoolReservationFraction = 0.25;
 
 extern uintptr_t startOfFixedExecutableMemoryPool;
 #endif

Modified: trunk/Source/_javascript_Core/jit/ExecutableAllocatorFixedVMPool.cpp (187124 => 187125)


--- trunk/Source/_javascript_Core/jit/ExecutableAllocatorFixedVMPool.cpp	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Source/_javascript_Core/jit/ExecutableAllocatorFixedVMPool.cpp	2015-07-21 21:41:30 UTC (rev 187125)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -60,9 +60,14 @@
     FixedVMPoolExecutableAllocator()
         : MetaAllocator(jitAllocationGranule) // round up all allocations to 32 bytes
     {
-        m_reservation = PageReservation::reserveWithGuardPages(fixedExecutableMemoryPoolSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
+        size_t reservationSize;
+        if (Options::jitMemoryReservationSize())
+            reservationSize = Options::jitMemoryReservationSize();
+        else
+            reservationSize = fixedExecutableMemoryPoolSize;
+        m_reservation = PageReservation::reserveWithGuardPages(reservationSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
         if (m_reservation) {
-            ASSERT(m_reservation.size() == fixedExecutableMemoryPoolSize);
+            ASSERT(m_reservation.size() == reservationSize);
             addFreshFreeSpace(m_reservation.base(), m_reservation.size());
             
             startOfFixedExecutableMemoryPool = reinterpret_cast<uintptr_t>(m_reservation.base());
@@ -148,12 +153,14 @@
     MetaAllocator::Statistics statistics = allocator->currentStatistics();
     ASSERT(statistics.bytesAllocated <= statistics.bytesReserved);
     size_t bytesAllocated = statistics.bytesAllocated + addedMemoryUsage;
-    if (bytesAllocated >= statistics.bytesReserved)
-        bytesAllocated = statistics.bytesReserved;
+    size_t bytesAvailable = static_cast<size_t>(
+        statistics.bytesReserved * (1 - executablePoolReservationFraction));
+    if (bytesAllocated >= bytesAvailable)
+        bytesAllocated = bytesAvailable;
     double result = 1.0;
-    size_t divisor = statistics.bytesReserved - bytesAllocated;
+    size_t divisor = bytesAvailable - bytesAllocated;
     if (divisor)
-        result = static_cast<double>(statistics.bytesReserved) / divisor;
+        result = static_cast<double>(bytesAvailable) / divisor;
     if (result < 1.0)
         result = 1.0;
     return result;
@@ -170,6 +177,16 @@
         && doExecutableAllocationFuzzingIfEnabled() == PretendToFailExecutableAllocation)
         return nullptr;
     
+    if (effort == JITCompilationCanFail) {
+        // Don't allow allocations if we are down to reserve.
+        MetaAllocator::Statistics statistics = allocator->currentStatistics();
+        size_t bytesAllocated = statistics.bytesAllocated + sizeInBytes;
+        size_t bytesAvailable = static_cast<size_t>(
+            statistics.bytesReserved * (1 - executablePoolReservationFraction));
+        if (bytesAllocated > bytesAvailable)
+            return nullptr;
+    }
+    
     RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID);
     if (!result) {
         if (effort != JITCompilationCanFail) {

Modified: trunk/Source/_javascript_Core/jsc.cpp (187124 => 187125)


--- trunk/Source/_javascript_Core/jsc.cpp	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Source/_javascript_Core/jsc.cpp	2015-07-21 21:41:30 UTC (rev 187125)
@@ -1248,12 +1248,6 @@
     ecore_init();
 #endif
 
-    // Initialize JSC before getting VM.
-#if ENABLE(SAMPLING_REGIONS)
-    WTF::initializeMainThread();
-#endif
-    JSC::initializeThreading();
-
     if (char* timeoutString = getenv("JSC_timeout")) {
         if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
             dataLog(
@@ -1430,6 +1424,8 @@
 
 void CommandLine::parseArguments(int argc, char** argv)
 {
+    Options::initialize();
+    
     int i = 1;
     bool needToDumpOptions = false;
     bool needToExit = false;
@@ -1494,8 +1490,7 @@
         }
 
         // See if the -- option is a JSC VM option.
-        // NOTE: At this point, we know that the arg starts with "--". Skip it.
-        if (JSC::Options::setOption(&arg[2])) {
+        if (strstr(arg, "--") == arg && JSC::Options::setOption(&arg[2])) {
             // The arg was recognized as a VM option and has been parsed.
             continue; // Just continue with the next arg. 
         }
@@ -1523,6 +1518,13 @@
     // Note that the options parsing can affect VM creation, and thus
     // comes first.
     CommandLine options(argc, argv);
+
+    // Initialize JSC before getting VM.
+#if ENABLE(SAMPLING_REGIONS)
+    WTF::initializeMainThread();
+#endif
+    JSC::initializeThreading();
+
     VM* vm = &VM::create(LargeHeap).leakRef();
     int result;
     {

Modified: trunk/Source/_javascript_Core/runtime/Options.cpp (187124 => 187125)


--- trunk/Source/_javascript_Core/runtime/Options.cpp	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Source/_javascript_Core/runtime/Options.cpp	2015-07-21 21:41:30 UTC (rev 187125)
@@ -30,6 +30,7 @@
 #include <algorithm>
 #include <limits>
 #include <math.h>
+#include <mutex>
 #include <stdlib.h>
 #include <string.h>
 #include <wtf/DataLog.h>
@@ -201,6 +202,11 @@
     return m_state == Normal ? false : true;
 }
 
+void OptionRange::dump(PrintStream& out) const
+{
+    out.print(m_rangeString);
+}
+
 Options::Entry Options::s_options[Options::numberOfOptions];
 Options::Entry Options::s_defaultOptions[Options::numberOfOptions];
 
@@ -318,60 +324,66 @@
 
 void Options::initialize()
 {
-    // Initialize each of the options with their default values:
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
-    name_() = defaultValue_; \
-    name_##Default() = defaultValue_;
-    JSC_OPTIONS(FOR_EACH_OPTION)
+    static std::once_flag initializeOptionsOnceFlag;
+    
+    std::call_once(
+        initializeOptionsOnceFlag,
+        [] {
+            // Initialize each of the options with their default values:
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_)      \
+            name_() = defaultValue_;                                    \
+            name_##Default() = defaultValue_;
+            JSC_OPTIONS(FOR_EACH_OPTION)
 #undef FOR_EACH_OPTION
     
-    // It *probably* makes sense for other platforms to enable this.
+                // It *probably* makes sense for other platforms to enable this.
 #if PLATFORM(IOS) && CPU(ARM64)
-    enableLLVMFastISel() = true;
+                enableLLVMFastISel() = true;
 #endif
         
-    // Allow environment vars to override options if applicable.
-    // The evn var should be the name of the option prefixed with
-    // "JSC_".
-#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
-    overrideOptionWithHeuristic(name_(), "JSC_" #name_);
-    JSC_OPTIONS(FOR_EACH_OPTION)
+            // Allow environment vars to override options if applicable.
+            // The evn var should be the name of the option prefixed with
+            // "JSC_".
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_)      \
+            overrideOptionWithHeuristic(name_(), "JSC_" #name_);
+            JSC_OPTIONS(FOR_EACH_OPTION)
 #undef FOR_EACH_OPTION
 
 #if 0
-    ; // Deconfuse editors that do auto indentation
+                ; // Deconfuse editors that do auto indentation
 #endif
     
-    recomputeDependentOptions();
+            recomputeDependentOptions();
 
-    // Do range checks where needed and make corrections to the options:
-    ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp());
-    ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon());
-    ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
+            // Do range checks where needed and make corrections to the options:
+            ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp());
+            ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon());
+            ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
 
-    if (Options::showOptions()) {
-        DumpLevel level = static_cast<DumpLevel>(Options::showOptions());
-        if (level > DumpLevel::Verbose)
-            level = DumpLevel::Verbose;
+            if (Options::showOptions()) {
+                DumpLevel level = static_cast<DumpLevel>(Options::showOptions());
+                if (level > DumpLevel::Verbose)
+                    level = DumpLevel::Verbose;
 
-        const char* title = nullptr;
-        switch (level) {
-        case DumpLevel::None:
-            break;
-        case DumpLevel::Overridden:
-            title = "Overridden JSC options:";
-            break;
-        case DumpLevel::All:
-            title = "All JSC options:";
-            break;
-        case DumpLevel::Verbose:
-            title = "All JSC options with descriptions:";
-            break;
-        }
-        dumpAllOptions(level, title);
-    }
+                const char* title = nullptr;
+                switch (level) {
+                case DumpLevel::None:
+                    break;
+                case DumpLevel::Overridden:
+                    title = "Overridden JSC options:";
+                    break;
+                case DumpLevel::All:
+                    title = "All JSC options:";
+                    break;
+                case DumpLevel::Verbose:
+                    title = "All JSC options with descriptions:";
+                    break;
+                }
+                dumpAllOptions(level, title);
+            }
 
-    ensureOptionsAreCoherent();
+            ensureOptionsAreCoherent();
+        });
 }
 
 // Parses a single command line option in the format "<optionName>=<value>"

Modified: trunk/Source/_javascript_Core/runtime/Options.h (187124 => 187125)


--- trunk/Source/_javascript_Core/runtime/Options.h	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Source/_javascript_Core/runtime/Options.h	2015-07-21 21:41:30 UTC (rev 187125)
@@ -30,6 +30,7 @@
 #include "JSExportMacros.h"
 #include <stdint.h>
 #include <stdio.h>
+#include <wtf/PrintStream.h>
 #include <wtf/StdLibExtras.h>
 
 namespace JSC {
@@ -80,6 +81,8 @@
     bool init(const char*);
     bool isInRange(unsigned);
     const char* rangeString() const { return (m_state > InitError) ? m_rangeString : "<null>"; }
+    
+    void dump(PrintStream& out) const;
 
 private:
     RangeState m_state;
@@ -106,6 +109,7 @@
     v(unsigned, errorModeReservedZoneSize, 64 * KB, nullptr) \
     \
     v(bool, crashIfCantAllocateJITMemory, false, nullptr) \
+    v(unsigned, jitMemoryReservationSize, 0, nullptr) \
     \
     v(bool, forceDFGCodeBlockLiveness, false, nullptr) \
     v(bool, forceICFailure, false, nullptr) \
@@ -350,7 +354,7 @@
         gcLogLevelType,
     };
 
-    static void initialize();
+    JS_EXPORT_PRIVATE static void initialize();
 
     // Parses a single command line option in the format "<optionName>=<value>"
     // (no spaces allowed) and set the specified option if appropriate.

Modified: trunk/Tools/ChangeLog (187124 => 187125)


--- trunk/Tools/ChangeLog	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Tools/ChangeLog	2015-07-21 21:41:30 UTC (rev 187125)
@@ -1,3 +1,16 @@
+2015-07-21  Filip Pizlo  <fpi...@apple.com>
+
+        Fixed VM pool allocation should have a reserve for allocations that cannot fail
+        https://bugs.webkit.org/show_bug.cgi?id=147154
+        rdar://problem/21847618
+
+        Reviewed by Geoffrey Garen.
+        
+        Add a new test mode where we artificially limit JIT memory to 50KB. If our JIT OOM
+        mitigations work, these should all pass. Prior to this patch there were >20 failures.
+
+        * Scripts/run-jsc-stress-tests:
+
 2015-07-20  Carlos Garcia Campos  <cgar...@igalia.com>
 
         [GTK] Add API to be notified about editor state changes

Modified: trunk/Tools/Scripts/run-jsc-stress-tests (187124 => 187125)


--- trunk/Tools/Scripts/run-jsc-stress-tests	2015-07-21 21:39:58 UTC (rev 187124)
+++ trunk/Tools/Scripts/run-jsc-stress-tests	2015-07-21 21:41:30 UTC (rev 187125)
@@ -758,6 +758,10 @@
     run("ftl-no-cjit-no-access-inlining", "--enableAccessInlining=false", *(FTL_OPTIONS + NO_CJIT_OPTIONS)) if $enableFTL
 end
 
+def runFTLNoCJITSmallPool
+    run("ftl-no-cjit-small-pool", "--jitMemoryReservationSize=50000", *(FTL_OPTIONS + NO_CJIT_OPTIONS)) if $enableFTL
+end
+
 def defaultRun
     runDefault
     runAlwaysTriggerCopyPhase
@@ -771,6 +775,7 @@
         runFTLNoCJITNoInlineValidate
         runFTLEager
         runFTLEagerNoCJITValidate
+        runFTLNoCJITSmallPool
     end
 end
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to