/* * Copyright (C) 2011, 2012 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. ``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 * 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 "Options.h" #include "HeapStatistics.h" #include #include #include #include #include #include #include #include #include #include #if OS(DARWIN) && ENABLE(PARALLEL_GC) #include #endif namespace JSC { static bool parse(const char* string, bool& value) { if (!strcasecmp(string, "true") || !strcasecmp(string, "yes") || !strcmp(string, "1")) { value = true; return true; } if (!strcasecmp(string, "false") || !strcasecmp(string, "no") || !strcmp(string, "0")) { value = false; return true; } return false; } static bool parse(const char* string, int32_t& value) { return sscanf(string, "%d", &value) == 1; } static bool parse(const char* string, unsigned& value) { return sscanf(string, "%u", &value) == 1; } static bool parse(const char* string, double& value) { return sscanf(string, "%lf", &value) == 1; } template void overrideOptionWithHeuristic(T& variable, const char* name) { #if !OS(WINCE) const char* stringValue = getenv(name); if (!stringValue) return; if (parse(stringValue, variable)) return; fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue); #endif } static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers) { int cpusToUse = 1; #if ENABLE(PARALLEL_GC) cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfGCMarkers); // Be paranoid, it is the OS we're dealing with, after all. ASSERT(cpusToUse >= 1); if (cpusToUse < 1) cpusToUse = 1; #else UNUSED_PARAM(maxNumberOfGCMarkers); #endif return cpusToUse; } 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 }; 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 #if USE(CF) || OS(UNIX) objectsAreImmortal() = !!getenv("JSImmortalZombieEnabled"); useZombieMode() = !!getenv("JSImmortalZombieEnabled") || !!getenv("JSZombieEnabled"); gcMaxHeapSize() = getenv("GCMaxHeapSize") ? HeapStatistics::parseMemoryAmount(getenv("GCMaxHeapSize")) : 0; recordGCPauseTimes() = !!getenv("JSRecordGCPauseTimes"); logHeapStatisticsAtExit() = gcMaxHeapSize() || recordGCPauseTimes(); #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_) \ overrideOptionWithHeuristic(name_(), "JSC_" #name_); JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION #if 0 ; // Deconfuse editors that do auto indentation #endif #if !ENABLE(JIT) useJIT() = false; useDFGJIT() = false; #endif #if !ENABLE(YARR_JIT) useRegExpJIT() = false; #endif // Do range checks where needed and make corrections to the options: ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp()); ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon()); ASSERT(thresholdForOptimizeAfterWarmUp() >= 0); // 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(thresholdForOptimizeAfterLongWarmUp()) << (reoptimizationRetryCounterMax() + 1)) <= static_cast(std::numeric_limits::max())) reoptimizationRetryCounterMax()++; ASSERT((static_cast(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) > 0); ASSERT((static_cast(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) <= static_cast(std::numeric_limits::max())); } // Parses a single command line option in the format "=" // (no spaces allowed) and set the specified option if appropriate. bool Options::setOption(const char* arg) { // arg should look like this: // = 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; \ bool success = parse(valueStr, value); \ if (success) { \ name_() = value; \ 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(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; } fprintf(stream, "%s", footer); } } // namespace JSC