]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/Options.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / Options.cpp
CommitLineData
6fe7ccc8 1/*
ed1e77d3 2 * Copyright (C) 2011-2012, 2014-2015 Apple Inc. All rights reserved.
6fe7ccc8
A
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 "config.h"
27#include "Options.h"
28
93a37866
A
29#include "HeapStatistics.h"
30#include <algorithm>
6fe7ccc8 31#include <limits>
ed1e77d3
A
32#include <math.h>
33#include <mutex>
93a37866
A
34#include <stdlib.h>
35#include <string.h>
81345200 36#include <wtf/DataLog.h>
6fe7ccc8
A
37#include <wtf/NumberOfCores.h>
38#include <wtf/PageBlock.h>
93a37866
A
39#include <wtf/StdLibExtras.h>
40#include <wtf/StringExtras.h>
6fe7ccc8
A
41
42#if OS(DARWIN) && ENABLE(PARALLEL_GC)
43#include <sys/sysctl.h>
44#endif
45
ed1e77d3
A
46#if OS(WINDOWS)
47#include "MacroAssemblerX86.h"
48#endif
49
93a37866 50namespace JSC {
6fe7ccc8 51
6fe7ccc8
A
52static bool parse(const char* string, bool& value)
53{
54 if (!strcasecmp(string, "true") || !strcasecmp(string, "yes") || !strcmp(string, "1")) {
55 value = true;
56 return true;
57 }
58 if (!strcasecmp(string, "false") || !strcasecmp(string, "no") || !strcmp(string, "0")) {
59 value = false;
60 return true;
61 }
62 return false;
63}
64
65static bool parse(const char* string, int32_t& value)
66{
67 return sscanf(string, "%d", &value) == 1;
68}
69
70static bool parse(const char* string, unsigned& value)
71{
72 return sscanf(string, "%u", &value) == 1;
73}
74
75static bool parse(const char* string, double& value)
76{
77 return sscanf(string, "%lf", &value) == 1;
78}
79
93a37866
A
80static bool parse(const char* string, OptionRange& value)
81{
82 return value.init(string);
83}
84
81345200
A
85static bool parse(const char* string, const char*& value)
86{
87 value = string;
88 return true;
89}
90
91static bool parse(const char* string, GCLogging::Level& value)
92{
93 if (!strcasecmp(string, "none") || !strcasecmp(string, "no") || !strcasecmp(string, "false") || !strcmp(string, "0")) {
94 value = GCLogging::None;
95 return true;
96 }
97
98 if (!strcasecmp(string, "basic") || !strcasecmp(string, "yes") || !strcasecmp(string, "true") || !strcmp(string, "1")) {
99 value = GCLogging::Basic;
100 return true;
101 }
102
103 if (!strcasecmp(string, "verbose") || !strcmp(string, "2")) {
104 value = GCLogging::Verbose;
105 return true;
106 }
107
108 return false;
109}
110
93a37866 111template<typename T>
81345200 112bool overrideOptionWithHeuristic(T& variable, const char* name)
6fe7ccc8
A
113{
114 const char* stringValue = getenv(name);
93a37866 115 if (!stringValue)
81345200 116 return false;
6fe7ccc8
A
117
118 if (parse(stringValue, variable))
81345200 119 return true;
6fe7ccc8
A
120
121 fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
81345200 122 return false;
6fe7ccc8
A
123}
124
81345200 125static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads, int minimum = 1)
93a37866 126{
81345200 127 int cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfWorkerThreads);
93a37866
A
128
129 // Be paranoid, it is the OS we're dealing with, after all.
130 ASSERT(cpusToUse >= 1);
81345200
A
131 return std::max(cpusToUse, minimum);
132}
133
134static int32_t computePriorityDeltaOfWorkerThreads(int32_t twoCorePriorityDelta, int32_t multiCorePriorityDelta)
135{
136 if (WTF::numberOfProcessorCores() <= 2)
137 return twoCorePriorityDelta;
138
139 return multiCorePriorityDelta;
140}
141
142static unsigned computeNumberOfGCMarkers(unsigned maxNumberOfGCMarkers)
143{
144#if ENABLE(PARALLEL_GC)
145 return computeNumberOfWorkerThreads(maxNumberOfGCMarkers);
6fe7ccc8 146#else
93a37866 147 UNUSED_PARAM(maxNumberOfGCMarkers);
81345200 148 return 1;
6fe7ccc8 149#endif
93a37866
A
150}
151
152bool OptionRange::init(const char* rangeString)
6fe7ccc8 153{
93a37866
A
154 // rangeString should be in the form of [!]<low>[:<high>]
155 // where low and high are unsigned
6fe7ccc8 156
93a37866 157 bool invert = false;
6fe7ccc8 158
93a37866
A
159 if (m_state > Uninitialized)
160 return true;
6fe7ccc8 161
93a37866
A
162 if (!rangeString) {
163 m_state = InitError;
164 return false;
165 }
6fe7ccc8 166
93a37866 167 m_rangeString = rangeString;
6fe7ccc8 168
93a37866
A
169 if (*rangeString == '!') {
170 invert = true;
171 rangeString++;
172 }
6fe7ccc8 173
93a37866 174 int scanResult = sscanf(rangeString, " %u:%u", &m_lowLimit, &m_highLimit);
6fe7ccc8 175
93a37866
A
176 if (!scanResult || scanResult == EOF) {
177 m_state = InitError;
178 return false;
179 }
6fe7ccc8 180
93a37866
A
181 if (scanResult == 1)
182 m_highLimit = m_lowLimit;
183
184 if (m_lowLimit > m_highLimit) {
185 m_state = InitError;
186 return false;
187 }
188
189 m_state = invert ? Inverted : Normal;
190
191 return true;
192}
193
194bool OptionRange::isInRange(unsigned count)
195{
196 if (m_state < Normal)
197 return true;
198
199 if ((m_lowLimit <= count) && (count <= m_highLimit))
200 return m_state == Normal ? true : false;
201
202 return m_state == Normal ? false : true;
203}
204
ed1e77d3
A
205void OptionRange::dump(PrintStream& out) const
206{
207 out.print(m_rangeString);
208}
209
93a37866 210Options::Entry Options::s_options[Options::numberOfOptions];
ed1e77d3 211Options::Entry Options::s_defaultOptions[Options::numberOfOptions];
93a37866
A
212
213// Realize the names for each of the options:
214const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = {
ed1e77d3
A
215#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
216 { #name_, description_, Options::Type::type_##Type },
93a37866
A
217 JSC_OPTIONS(FOR_EACH_OPTION)
218#undef FOR_EACH_OPTION
219};
220
ed1e77d3
A
221static void scaleJITPolicy()
222{
223 auto& scaleFactor = Options::jitPolicyScale();
224 if (scaleFactor > 1.0)
225 scaleFactor = 1.0;
226 else if (scaleFactor < 0.0)
227 scaleFactor = 0.0;
228
229 struct OptionToScale {
230 Options::OptionID id;
231 int32_t minVal;
232 };
233
234 static const OptionToScale optionsToScale[] = {
235 { Options::thresholdForJITAfterWarmUpID, 0 },
236 { Options::thresholdForJITSoonID, 0 },
237 { Options::thresholdForOptimizeAfterWarmUpID, 1 },
238 { Options::thresholdForOptimizeAfterLongWarmUpID, 1 },
239 { Options::thresholdForOptimizeSoonID, 1 },
240 { Options::thresholdForFTLOptimizeSoonID, 2 },
241 { Options::thresholdForFTLOptimizeAfterWarmUpID, 2 }
242 };
243
244 const int numberOfOptionsToScale = sizeof(optionsToScale) / sizeof(OptionToScale);
245 for (int i = 0; i < numberOfOptionsToScale; i++) {
246 Option option(optionsToScale[i].id);
247 ASSERT(option.type() == Options::Type::int32Type);
248 option.int32Val() *= scaleFactor;
249 option.int32Val() = std::max(option.int32Val(), optionsToScale[i].minVal);
250 }
251}
252
81345200
A
253static void recomputeDependentOptions()
254{
255#if !ENABLE(JIT)
256 Options::useLLInt() = true;
257 Options::useJIT() = false;
258 Options::useDFGJIT() = false;
259 Options::useFTLJIT() = false;
260#endif
261#if !ENABLE(YARR_JIT)
262 Options::useRegExpJIT() = false;
263#endif
264#if !ENABLE(CONCURRENT_JIT)
265 Options::enableConcurrentJIT() = false;
266#endif
267#if !ENABLE(DFG_JIT)
268 Options::useDFGJIT() = false;
269 Options::useFTLJIT() = false;
270#endif
271#if !ENABLE(FTL_JIT)
272 Options::useFTLJIT() = false;
273#endif
ed1e77d3
A
274#if OS(WINDOWS) && CPU(X86)
275 // Disable JIT on Windows if SSE2 is not present
276 if (!MacroAssemblerX86::supportsFloatingPoint())
277 Options::useJIT() = false;
278#endif
81345200
A
279 if (Options::showDisassembly()
280 || Options::showDFGDisassembly()
281 || Options::showFTLDisassembly()
282 || Options::dumpBytecodeAtDFGTime()
283 || Options::dumpGraphAtEachPhase()
284 || Options::verboseCompilation()
285 || Options::verboseFTLCompilation()
286 || Options::logCompilationChanges()
287 || Options::validateGraph()
288 || Options::validateGraphAtEachPhase()
289 || Options::verboseOSR()
290 || Options::verboseCompilationQueue()
291 || Options::reportCompileTimes()
292 || Options::reportFTLCompileTimes()
293 || Options::verboseCFA()
294 || Options::verboseFTLFailure())
295 Options::alwaysComputeHash() = true;
ed1e77d3
A
296
297 if (Option(Options::jitPolicyScaleID).isOverridden())
298 scaleJITPolicy();
81345200 299
ed1e77d3
A
300 if (Options::forceEagerCompilation()) {
301 Options::thresholdForJITAfterWarmUp() = 10;
302 Options::thresholdForJITSoon() = 10;
303 Options::thresholdForOptimizeAfterWarmUp() = 20;
304 Options::thresholdForOptimizeAfterLongWarmUp() = 20;
305 Options::thresholdForOptimizeSoon() = 20;
306 Options::thresholdForFTLOptimizeAfterWarmUp() = 20;
307 Options::thresholdForFTLOptimizeSoon() = 20;
308 Options::maximumEvalCacheableSourceLength() = 150000;
309 Options::enableConcurrentJIT() = false;
310 }
311
81345200
A
312 // Compute the maximum value of the reoptimization retry counter. This is simply
313 // the largest value at which we don't overflow the execute counter, when using it
314 // to left-shift the execution counter by this amount. Currently the value ends
315 // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles
316 // total on a 32-bit processor.
317 Options::reoptimizationRetryCounterMax() = 0;
318 while ((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << (Options::reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
319 Options::reoptimizationRetryCounterMax()++;
320
321 ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) > 0);
322 ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
323}
324
93a37866
A
325void Options::initialize()
326{
ed1e77d3
A
327 static std::once_flag initializeOptionsOnceFlag;
328
329 std::call_once(
330 initializeOptionsOnceFlag,
331 [] {
332 // Initialize each of the options with their default values:
333#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
334 name_() = defaultValue_; \
335 name_##Default() = defaultValue_;
336 JSC_OPTIONS(FOR_EACH_OPTION)
93a37866 337#undef FOR_EACH_OPTION
ed1e77d3
A
338
339 // It *probably* makes sense for other platforms to enable this.
340#if PLATFORM(IOS) && CPU(ARM64)
341 enableLLVMFastISel() = true;
342#endif
93a37866 343
ed1e77d3
A
344 // Allow environment vars to override options if applicable.
345 // The evn var should be the name of the option prefixed with
346 // "JSC_".
347#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
348 overrideOptionWithHeuristic(name_(), "JSC_" #name_);
349 JSC_OPTIONS(FOR_EACH_OPTION)
93a37866
A
350#undef FOR_EACH_OPTION
351
352#if 0
ed1e77d3 353 ; // Deconfuse editors that do auto indentation
93a37866 354#endif
6fe7ccc8 355
ed1e77d3
A
356 recomputeDependentOptions();
357
358 // Do range checks where needed and make corrections to the options:
359 ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp());
360 ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon());
361 ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
362
363 if (Options::showOptions()) {
364 DumpLevel level = static_cast<DumpLevel>(Options::showOptions());
365 if (level > DumpLevel::Verbose)
366 level = DumpLevel::Verbose;
367
368 const char* title = nullptr;
369 switch (level) {
370 case DumpLevel::None:
371 break;
372 case DumpLevel::Overridden:
373 title = "Overridden JSC options:";
374 break;
375 case DumpLevel::All:
376 title = "All JSC options:";
377 break;
378 case DumpLevel::Verbose:
379 title = "All JSC options with descriptions:";
380 break;
381 }
382 dumpAllOptions(level, title);
383 }
384
385 ensureOptionsAreCoherent();
386 });
93a37866
A
387}
388
389// Parses a single command line option in the format "<optionName>=<value>"
390// (no spaces allowed) and set the specified option if appropriate.
391bool Options::setOption(const char* arg)
392{
393 // arg should look like this:
394 // <jscOptionName>=<appropriate value>
395 const char* equalStr = strchr(arg, '=');
396 if (!equalStr)
397 return false;
398
399 const char* valueStr = equalStr + 1;
400
401 // For each option, check if the specify arg is a match. If so, set the arg
402 // if the value makes sense. Otherwise, move on to checking the next option.
ed1e77d3 403#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
93a37866
A
404 if (!strncmp(arg, #name_, equalStr - arg)) { \
405 type_ value; \
81345200 406 value = (defaultValue_); \
93a37866
A
407 bool success = parse(valueStr, value); \
408 if (success) { \
409 name_() = value; \
81345200 410 recomputeDependentOptions(); \
93a37866
A
411 return true; \
412 } \
413 return false; \
414 }
415
416 JSC_OPTIONS(FOR_EACH_OPTION)
417#undef FOR_EACH_OPTION
418
81345200 419 return false; // No option matched.
6fe7ccc8
A
420}
421
ed1e77d3 422void Options::dumpAllOptions(DumpLevel level, const char* title, FILE* stream)
93a37866 423{
ed1e77d3
A
424 if (title)
425 fprintf(stream, "%s\n", title);
93a37866 426 for (int id = 0; id < numberOfOptions; id++)
ed1e77d3 427 dumpOption(level, static_cast<OptionID>(id), stream, " ", "\n");
93a37866
A
428}
429
ed1e77d3 430void Options::dumpOption(DumpLevel level, OptionID id, FILE* stream, const char* header, const char* footer)
93a37866
A
431{
432 if (id >= numberOfOptions)
433 return; // Illegal option.
434
ed1e77d3
A
435 Option option(id);
436 bool wasOverridden = option.isOverridden();
437 bool needsDescription = (level == DumpLevel::Verbose && option.description());
438
439 if (level == DumpLevel::Overridden && !wasOverridden)
440 return;
441
442 fprintf(stream, "%s%s: ", header, option.name());
443 option.dump(stream);
444
445 if (wasOverridden) {
446 fprintf(stream, " (default: ");
447 option.defaultOption().dump(stream);
448 fprintf(stream, ")");
449 }
450
451 if (needsDescription)
452 fprintf(stream, " ... %s", option.description());
453
454 fprintf(stream, "%s", footer);
455}
456
457void Options::ensureOptionsAreCoherent()
458{
459 bool coherent = true;
460 if (!(useLLInt() || useJIT())) {
461 coherent = false;
462 dataLog("INCOHERENT OPTIONS: at least one of useLLInt or useJIT must be true\n");
463 }
464 if (!coherent)
465 CRASH();
466}
467
468void Option::dump(FILE* stream) const
469{
470 switch (type()) {
471 case Options::Type::boolType:
472 fprintf(stream, "%s", m_entry.boolVal ? "true" : "false");
93a37866 473 break;
ed1e77d3
A
474 case Options::Type::unsignedType:
475 fprintf(stream, "%u", m_entry.unsignedVal);
93a37866 476 break;
ed1e77d3
A
477 case Options::Type::doubleType:
478 fprintf(stream, "%lf", m_entry.doubleVal);
93a37866 479 break;
ed1e77d3
A
480 case Options::Type::int32Type:
481 fprintf(stream, "%d", m_entry.int32Val);
93a37866 482 break;
ed1e77d3
A
483 case Options::Type::optionRangeType:
484 fprintf(stream, "%s", m_entry.optionRangeVal.rangeString());
93a37866 485 break;
ed1e77d3
A
486 case Options::Type::optionStringType: {
487 const char* option = m_entry.optionStringVal;
81345200
A
488 if (!option)
489 option = "";
490 fprintf(stream, "%s", option);
491 break;
492 }
ed1e77d3
A
493 case Options::Type::gcLogLevelType: {
494 fprintf(stream, "%s", GCLogging::levelAsString(m_entry.gcLogLevelVal));
81345200
A
495 break;
496 }
93a37866 497 }
ed1e77d3
A
498}
499
500bool Option::operator==(const Option& other) const
501{
502 switch (type()) {
503 case Options::Type::boolType:
504 return m_entry.boolVal == other.m_entry.boolVal;
505 case Options::Type::unsignedType:
506 return m_entry.unsignedVal == other.m_entry.unsignedVal;
507 case Options::Type::doubleType:
508 return (m_entry.doubleVal == other.m_entry.doubleVal) || (isnan(m_entry.doubleVal) && isnan(other.m_entry.doubleVal));
509 case Options::Type::int32Type:
510 return m_entry.int32Val == other.m_entry.int32Val;
511 case Options::Type::optionRangeType:
512 return m_entry.optionRangeVal.rangeString() == other.m_entry.optionRangeVal.rangeString();
513 case Options::Type::optionStringType:
514 return (m_entry.optionStringVal == other.m_entry.optionStringVal)
515 || (m_entry.optionStringVal && other.m_entry.optionStringVal && !strcmp(m_entry.optionStringVal, other.m_entry.optionStringVal));
516 case Options::Type::gcLogLevelType:
517 return m_entry.gcLogLevelVal == other.m_entry.gcLogLevelVal;
518 }
519 return false;
93a37866 520}
6fe7ccc8 521
93a37866 522} // namespace JSC
6fe7ccc8 523