]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/Options.cpp
JavaScriptCore-7600.1.4.15.12.tar.gz
[apple/javascriptcore.git] / runtime / Options.cpp
index 8f5a050674ed1ef42968dd0fc10b370e4f49387b..f0ddf98e745e606b15db48f47f03678c96534522 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "config.h"
 #include "Options.h"
 
+#include "HeapStatistics.h"
+#include <algorithm>
 #include <limits>
+#include <stdlib.h>
+#include <string.h>
+#include <wtf/DataLog.h>
 #include <wtf/NumberOfCores.h>
 #include <wtf/PageBlock.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/StringExtras.h>
 
 #if OS(DARWIN) && ENABLE(PARALLEL_GC)
 #include <sys/sysctl.h>
 #endif
 
-// Set to 1 to control the heuristics using environment variables.
-#define ENABLE_RUN_TIME_HEURISTICS 0
-
-#if ENABLE(RUN_TIME_HEURISTICS)
-#include <stdio.h>
-#include <stdlib.h>
-#include <wtf/StdLibExtras.h>
-#endif
-
-namespace JSC { namespace Options {
-
-bool useJIT;
-
-unsigned maximumOptimizationCandidateInstructionCount;
-
-unsigned maximumFunctionForCallInlineCandidateInstructionCount;
-unsigned maximumFunctionForConstructInlineCandidateInstructionCount;
-
-unsigned maximumInliningDepth;
-
-int32_t thresholdForJITAfterWarmUp;
-int32_t thresholdForJITSoon;
-
-int32_t thresholdForOptimizeAfterWarmUp;
-int32_t thresholdForOptimizeAfterLongWarmUp;
-int32_t thresholdForOptimizeSoon;
-
-int32_t executionCounterIncrementForLoop;
-int32_t executionCounterIncrementForReturn;
+namespace JSC {
 
-unsigned desiredSpeculativeSuccessFailRatio;
-
-double likelyToTakeSlowCaseThreshold;
-double couldTakeSlowCaseThreshold;
-unsigned likelyToTakeSlowCaseMinimumCount;
-unsigned couldTakeSlowCaseMinimumCount;
-
-double osrExitProminenceForFrequentExitSite;
-
-unsigned largeFailCountThresholdBase;
-unsigned largeFailCountThresholdBaseForLoop;
-unsigned forcedOSRExitCountForReoptimization;
-
-unsigned reoptimizationRetryCounterMax;
-unsigned reoptimizationRetryCounterStep;
-
-unsigned minimumOptimizationDelay;
-unsigned maximumOptimizationDelay;
-double desiredProfileLivenessRate;
-double desiredProfileFullnessRate;
-
-double doubleVoteRatioForDoubleFormat;
-
-unsigned minimumNumberOfScansBetweenRebalance;
-unsigned gcMarkStackSegmentSize;
-unsigned minimumNumberOfCellsToKeep;
-unsigned maximumNumberOfSharedSegments;
-unsigned sharedStackWakeupThreshold;
-unsigned numberOfGCMarkers;
-unsigned opaqueRootMergeThreshold;
-
-#if ENABLE(RUN_TIME_HEURISTICS)
 static bool parse(const char* string, bool& value)
 {
     if (!strcasecmp(string, "true") || !strcasecmp(string, "yes") || !strcmp(string, "1")) {
@@ -124,107 +71,302 @@ static bool parse(const char* string, double& value)
     return sscanf(string, "%lf", &value) == 1;
 }
 
-template<typename T, typename U>
-void setHeuristic(T& variable, const char* name, U value)
+static bool parse(const char* string, OptionRange& value)
 {
-    const char* stringValue = getenv(name);
-    if (!stringValue) {
-        variable = safeCast<T>(value);
-        return;
+    return value.init(string);
+}
+
+static bool parse(const char* string, const char*& value)
+{
+    value = string;
+    return true;
+}
+
+static bool parse(const char* string, GCLogging::Level& value)
+{
+    if (!strcasecmp(string, "none") || !strcasecmp(string, "no") || !strcasecmp(string, "false") || !strcmp(string, "0")) {
+        value = GCLogging::None;
+        return true;
+    }
+
+    if (!strcasecmp(string, "basic") || !strcasecmp(string, "yes") || !strcasecmp(string, "true") || !strcmp(string, "1")) {
+        value = GCLogging::Basic;
+        return true;
+    }
+
+    if (!strcasecmp(string, "verbose") || !strcmp(string, "2")) {
+        value = GCLogging::Verbose;
+        return true;
     }
+
+    return false;
+}
+
+template<typename T>
+bool overrideOptionWithHeuristic(T& variable, const char* name)
+{
+#if !OS(WINCE)
+    const char* stringValue = getenv(name);
+    if (!stringValue)
+        return false;
     
     if (parse(stringValue, variable))
-        return;
+        return true;
     
     fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
-    variable = safeCast<T>(value);
+#endif
+    return false;
+}
+
+static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads, int minimum = 1)
+{
+    int cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfWorkerThreads);
+
+    // Be paranoid, it is the OS we're dealing with, after all.
+    ASSERT(cpusToUse >= 1);
+    return std::max(cpusToUse, minimum);
 }
 
-#define SET(variable, value) setHeuristic(variable, "JSC_" #variable, value)
+static int32_t computePriorityDeltaOfWorkerThreads(int32_t twoCorePriorityDelta, int32_t multiCorePriorityDelta)
+{
+    if (WTF::numberOfProcessorCores() <= 2)
+        return twoCorePriorityDelta;
+
+    return multiCorePriorityDelta;
+}
+
+static unsigned computeNumberOfGCMarkers(unsigned maxNumberOfGCMarkers)
+{
+#if ENABLE(PARALLEL_GC)
+    return computeNumberOfWorkerThreads(maxNumberOfGCMarkers);
 #else
-#define SET(variable, value) variable = value
+    UNUSED_PARAM(maxNumberOfGCMarkers);
+    return 1;
 #endif
+}
 
-void initializeOptions()
+bool OptionRange::init(const char* rangeString)
 {
-    SET(useJIT, true);
-    
-    SET(maximumOptimizationCandidateInstructionCount, 10000);
-    
-    SET(maximumFunctionForCallInlineCandidateInstructionCount, 180);
-    SET(maximumFunctionForConstructInlineCandidateInstructionCount, 100);
-    
-    SET(maximumInliningDepth, 5);
+    // rangeString should be in the form of [!]<low>[:<high>]
+    // where low and high are unsigned
 
-    SET(thresholdForJITAfterWarmUp,     100);
-    SET(thresholdForJITSoon,            100);
+    bool invert = false;
 
-    SET(thresholdForOptimizeAfterWarmUp,     1000);
-    SET(thresholdForOptimizeAfterLongWarmUp, 5000);
-    SET(thresholdForOptimizeSoon,            1000);
+    if (m_state > Uninitialized)
+        return true;
 
-    SET(executionCounterIncrementForLoop,   1);
-    SET(executionCounterIncrementForReturn, 15);
+    if (!rangeString) {
+        m_state = InitError;
+        return false;
+    }
 
-    SET(desiredSpeculativeSuccessFailRatio, 6);
-    
-    SET(likelyToTakeSlowCaseThreshold,    0.15);
-    SET(couldTakeSlowCaseThreshold,       0.05); // Shouldn't be zero because some ops will spuriously take slow case, for example for linking or caching.
-    SET(likelyToTakeSlowCaseMinimumCount, 100);
-    SET(couldTakeSlowCaseMinimumCount,    10);
-    
-    SET(osrExitProminenceForFrequentExitSite, 0.3);
+    m_rangeString = rangeString;
 
-    SET(largeFailCountThresholdBase,         20);
-    SET(largeFailCountThresholdBaseForLoop,  1);
-    SET(forcedOSRExitCountForReoptimization, 250);
+    if (*rangeString == '!') {
+        invert = true;
+        rangeString++;
+    }
 
-    SET(reoptimizationRetryCounterStep, 1);
+    int scanResult = sscanf(rangeString, " %u:%u", &m_lowLimit, &m_highLimit);
 
-    SET(minimumOptimizationDelay,   1);
-    SET(maximumOptimizationDelay,   5);
-    SET(desiredProfileLivenessRate, 0.75);
-    SET(desiredProfileFullnessRate, 0.35);
-    
-    SET(doubleVoteRatioForDoubleFormat, 2);
-    
-    SET(minimumNumberOfScansBetweenRebalance, 10000);
-    SET(gcMarkStackSegmentSize,               pageSize());
-    SET(minimumNumberOfCellsToKeep,           10);
-    SET(maximumNumberOfSharedSegments,        3);
-    SET(sharedStackWakeupThreshold,           1);
-    SET(opaqueRootMergeThreshold,             1000);
-
-    int cpusToUse = 1;
-#if ENABLE(PARALLEL_GC)
-    cpusToUse = WTF::numberOfProcessorCores();
+    if (!scanResult || scanResult == EOF) {
+        m_state = InitError;
+        return false;
+    }
+
+    if (scanResult == 1)
+        m_highLimit = m_lowLimit;
+
+    if (m_lowLimit > m_highLimit) {
+        m_state = InitError;
+        return false;
+    }
+
+    m_state = invert ? Inverted : Normal;
+
+    return true;
+}
+
+bool OptionRange::isInRange(unsigned count)
+{
+    if (m_state < Normal)
+        return true;
+
+    if ((m_lowLimit <= count) && (count <= m_highLimit))
+        return m_state == Normal ? true : false;
+
+    return m_state == Normal ? false : true;
+}
+
+Options::Entry Options::s_options[Options::numberOfOptions];
+
+// Realize the names for each of the options:
+const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = {
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+    { #name_, Options::type_##Type },
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+};
+
+static void recomputeDependentOptions()
+{
+#if !ENABLE(JIT)
+    Options::useLLInt() = true;
+    Options::useJIT() = false;
+    Options::useDFGJIT() = false;
+    Options::useFTLJIT() = false;
+#endif
+#if !ENABLE(YARR_JIT)
+    Options::useRegExpJIT() = false;
+#endif
+#if !ENABLE(CONCURRENT_JIT)
+    Options::enableConcurrentJIT() = false;
+#endif
+#if !ENABLE(DFG_JIT)
+    Options::useDFGJIT() = false;
+    Options::useFTLJIT() = false;
+#endif
+#if !ENABLE(FTL_JIT)
+    Options::useFTLJIT() = false;
 #endif
-    // We don't scale so well beyond 4.
-    if (cpusToUse > 4)
-        cpusToUse = 4;
-    // Be paranoid, it is the OS we're dealing with, after all.
-    if (cpusToUse < 1)
-        cpusToUse = 1;
-    
-    SET(numberOfGCMarkers, cpusToUse);
 
-    ASSERT(thresholdForOptimizeAfterLongWarmUp >= thresholdForOptimizeAfterWarmUp);
-    ASSERT(thresholdForOptimizeAfterWarmUp >= thresholdForOptimizeSoon);
-    ASSERT(thresholdForOptimizeAfterWarmUp >= 0);
+    if (Options::showDisassembly()
+        || Options::showDFGDisassembly()
+        || Options::showFTLDisassembly()
+        || Options::dumpBytecodeAtDFGTime()
+        || Options::dumpGraphAtEachPhase()
+        || Options::verboseCompilation()
+        || Options::verboseFTLCompilation()
+        || Options::logCompilationChanges()
+        || Options::validateGraph()
+        || Options::validateGraphAtEachPhase()
+        || Options::verboseOSR()
+        || Options::verboseCompilationQueue()
+        || Options::reportCompileTimes()
+        || Options::reportFTLCompileTimes()
+        || Options::verboseCFA()
+        || Options::verboseFTLFailure())
+        Options::alwaysComputeHash() = true;
     
     // Compute the maximum value of the reoptimization retry counter. This is simply
     // the largest value at which we don't overflow the execute counter, when using it
     // to left-shift the execution counter by this amount. Currently the value ends
     // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles
     // total on a 32-bit processor.
-    reoptimizationRetryCounterMax = 0;
-    while ((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << (reoptimizationRetryCounterMax + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
-        reoptimizationRetryCounterMax++;
+    Options::reoptimizationRetryCounterMax() = 0;
+    while ((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << (Options::reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
+        Options::reoptimizationRetryCounterMax()++;
+
+    ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) > 0);
+    ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
+}
+
+void Options::initialize()
+{
+    // Initialize each of the options with their default values:
+#define FOR_EACH_OPTION(type_, name_, defaultValue_) \
+    name_() = defaultValue_;
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef 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_) \
+    if (overrideOptionWithHeuristic(name_(), "JSC_" #name_)) \
+        s_options[OPT_##name_].didOverride = true;
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+#if 0
+    ; // Deconfuse editors that do auto indentation
+#endif
     
-    ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) > 0);
-    ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
+    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);
 }
 
-} } // namespace JSC::Options
+// Parses a single command line option in the format "<optionName>=<value>"
+// (no spaces allowed) and set the specified option if appropriate.
+bool Options::setOption(const char* arg)
+{
+    // arg should look like this:
+    //   <jscOptionName>=<appropriate value>
+    const char* equalStr = strchr(arg, '=');
+    if (!equalStr)
+        return false;
+
+    const char* valueStr = equalStr + 1;
+
+    // For each option, check if the specify arg is a match. If so, set the arg
+    // if the value makes sense. Otherwise, move on to checking the next option.
+#define FOR_EACH_OPTION(type_, name_, defaultValue_)    \
+    if (!strncmp(arg, #name_, equalStr - arg)) {        \
+        type_ value;                                    \
+        value = (defaultValue_);                        \
+        bool success = parse(valueStr, value);          \
+        if (success) {                                  \
+            name_() = value;                            \
+            s_options[OPT_##name_].didOverride = true;  \
+            recomputeDependentOptions();                \
+            return true;                                \
+        }                                               \
+        return false;                                   \
+    }
+
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+    return false; // No option matched.
+}
+
+void Options::dumpAllOptions(FILE* stream)
+{
+    fprintf(stream, "JSC runtime options:\n");
+    for (int id = 0; id < numberOfOptions; id++)
+        dumpOption(static_cast<OptionID>(id), stream, "   ", "\n");
+}
+
+void Options::dumpOption(OptionID id, FILE* stream, const char* header, const char* footer)
+{
+    if (id >= numberOfOptions)
+        return; // Illegal option.
+
+    fprintf(stream, "%s%s: ", header, s_optionsInfo[id].name);
+    switch (s_optionsInfo[id].type) {
+    case boolType:
+        fprintf(stream, "%s", s_options[id].u.boolVal?"true":"false");
+        break;
+    case unsignedType:
+        fprintf(stream, "%u", s_options[id].u.unsignedVal);
+        break;
+    case doubleType:
+        fprintf(stream, "%lf", s_options[id].u.doubleVal);
+        break;
+    case int32Type:
+        fprintf(stream, "%d", s_options[id].u.int32Val);
+        break;
+    case optionRangeType:
+        fprintf(stream, "%s", s_options[id].u.optionRangeVal.rangeString());
+        break;
+    case optionStringType: {
+        const char* option = s_options[id].u.optionStringVal;
+        if (!option)
+            option = "";
+        fprintf(stream, "%s", option);
+        break;
+    }
+    case gcLogLevelType: {
+        fprintf(stream, "%s", GCLogging::levelAsString(s_options[id].u.gcLogLevelVal));
+        break;
+    }
+    }
+    fprintf(stream, "%s", footer);
+}
 
+} // namespace JSC