Reland r216808, underlying lldb bug has been fixed.
[WebKit-https.git] / Source / JavaScriptCore / runtime / Options.cpp
1 /*
2  * Copyright (C) 2011-2017 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 "config.h"
27 #include "Options.h"
28
29 #include "AssemblerCommon.h"
30 #include "LLIntCommon.h"
31 #include "LLIntData.h"
32 #include "SigillCrashAnalyzer.h"
33 #include <algorithm>
34 #include <limits>
35 #include <math.h>
36 #include <mutex>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <wtf/ASCIICType.h>
40 #include <wtf/Compiler.h>
41 #include <wtf/DataLog.h>
42 #include <wtf/NumberOfCores.h>
43 #include <wtf/StdLibExtras.h>
44 #include <wtf/StringExtras.h>
45 #include <wtf/text/StringBuilder.h>
46 #include <wtf/threads/Signals.h>
47
48 #if PLATFORM(COCOA)
49 #include <crt_externs.h>
50 #endif
51
52 #if OS(WINDOWS)
53 #include "MacroAssemblerX86.h"
54 #endif
55
56 namespace JSC {
57
58 namespace {
59 #ifdef NDEBUG
60 bool restrictedOptionsEnabled = false;
61 #else
62 bool restrictedOptionsEnabled = true;
63 #endif
64 }
65
66 void Options::enableRestrictedOptions(bool enableOrNot)
67 {
68     restrictedOptionsEnabled = enableOrNot;
69 }
70     
71 static bool parse(const char* string, bool& value)
72 {
73     if (!strcasecmp(string, "true") || !strcasecmp(string, "yes") || !strcmp(string, "1")) {
74         value = true;
75         return true;
76     }
77     if (!strcasecmp(string, "false") || !strcasecmp(string, "no") || !strcmp(string, "0")) {
78         value = false;
79         return true;
80     }
81     return false;
82 }
83
84 static bool parse(const char* string, int32_t& value)
85 {
86     return sscanf(string, "%d", &value) == 1;
87 }
88
89 static bool parse(const char* string, unsigned& value)
90 {
91     return sscanf(string, "%u", &value) == 1;
92 }
93
94 static bool parse(const char* string, unsigned long& value)
95 {
96     return sscanf(string, "%lu", &value);
97 }
98
99 static bool UNUSED_FUNCTION parse(const char* string, unsigned long long& value)
100 {
101     return sscanf(string, "%llu", &value);
102 }
103
104 static bool parse(const char* string, double& value)
105 {
106     return sscanf(string, "%lf", &value) == 1;
107 }
108
109 static bool parse(const char* string, OptionRange& value)
110 {
111     return value.init(string);
112 }
113
114 static bool parse(const char* string, const char*& value)
115 {
116     if (!strlen(string)) {
117         value = nullptr;
118         return true;
119     }
120
121     // FIXME <https://webkit.org/b/169057>: This could leak if this option is set more than once.
122     // Given that Options are typically used for testing, this isn't considered to be a problem.
123     value = WTF::fastStrDup(string);
124     return true;
125 }
126
127 static bool parse(const char* string, GCLogging::Level& value)
128 {
129     if (!strcasecmp(string, "none") || !strcasecmp(string, "no") || !strcasecmp(string, "false") || !strcmp(string, "0")) {
130         value = GCLogging::None;
131         return true;
132     }
133
134     if (!strcasecmp(string, "basic") || !strcasecmp(string, "yes") || !strcasecmp(string, "true") || !strcmp(string, "1")) {
135         value = GCLogging::Basic;
136         return true;
137     }
138
139     if (!strcasecmp(string, "verbose") || !strcmp(string, "2")) {
140         value = GCLogging::Verbose;
141         return true;
142     }
143
144     return false;
145 }
146
147 bool Options::isAvailable(Options::ID id, Options::Availability availability)
148 {
149     if (availability == Availability::Restricted)
150         return restrictedOptionsEnabled;
151     ASSERT(availability == Availability::Configurable);
152     
153     UNUSED_PARAM(id);
154 #if ENABLE(LLINT_STATS)
155     if (id == reportLLIntStatsID || id == llintStatsFileID)
156         return true;
157 #endif
158 #if !defined(NDEBUG)
159     if (id == maxSingleAllocationSizeID)
160         return true;
161 #endif
162 #if OS(DARWIN)
163     if (id == useSigillCrashAnalyzerID)
164         return true;
165 #endif
166     return false;
167 }
168
169 template<typename T>
170 bool overrideOptionWithHeuristic(T& variable, Options::ID id, const char* name, Options::Availability availability)
171 {
172     bool available = (availability == Options::Availability::Normal)
173         || Options::isAvailable(id, availability);
174
175     const char* stringValue = getenv(name);
176     if (!stringValue)
177         return false;
178     
179     if (available && parse(stringValue, variable))
180         return true;
181     
182     fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
183     return false;
184 }
185
186 bool Options::overrideAliasedOptionWithHeuristic(const char* name)
187 {
188     const char* stringValue = getenv(name);
189     if (!stringValue)
190         return false;
191
192     String aliasedOption;
193     aliasedOption = String(&name[4]) + "=" + stringValue;
194     if (Options::setOption(aliasedOption.utf8().data()))
195         return true;
196
197     fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
198     return false;
199 }
200
201 static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads, int minimum = 1)
202 {
203     int cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfWorkerThreads);
204
205     // Be paranoid, it is the OS we're dealing with, after all.
206     ASSERT(cpusToUse >= 1);
207     return std::max(cpusToUse, minimum);
208 }
209
210 static int32_t computePriorityDeltaOfWorkerThreads(int32_t twoCorePriorityDelta, int32_t multiCorePriorityDelta)
211 {
212     if (WTF::numberOfProcessorCores() <= 2)
213         return twoCorePriorityDelta;
214
215     return multiCorePriorityDelta;
216 }
217
218 static unsigned computeNumberOfGCMarkers(unsigned maxNumberOfGCMarkers)
219 {
220     return computeNumberOfWorkerThreads(maxNumberOfGCMarkers);
221 }
222
223 const char* const OptionRange::s_nullRangeStr = "<null>";
224
225 bool OptionRange::init(const char* rangeString)
226 {
227     // rangeString should be in the form of [!]<low>[:<high>]
228     // where low and high are unsigned
229
230     bool invert = false;
231
232     if (!rangeString) {
233         m_state = InitError;
234         return false;
235     }
236
237     if (!strcmp(rangeString, s_nullRangeStr)) {
238         m_state = Uninitialized;
239         return true;
240     }
241     
242     const char* p = rangeString;
243
244     if (*p == '!') {
245         invert = true;
246         p++;
247     }
248
249     int scanResult = sscanf(p, " %u:%u", &m_lowLimit, &m_highLimit);
250
251     if (!scanResult || scanResult == EOF) {
252         m_state = InitError;
253         return false;
254     }
255
256     if (scanResult == 1)
257         m_highLimit = m_lowLimit;
258
259     if (m_lowLimit > m_highLimit) {
260         m_state = InitError;
261         return false;
262     }
263
264     // FIXME <https://webkit.org/b/169057>: This could leak if this particular option is set more than once.
265     // Given that these options are used for testing, this isn't considered to be problem.
266     m_rangeString = WTF::fastStrDup(rangeString);
267     m_state = invert ? Inverted : Normal;
268
269     return true;
270 }
271
272 bool OptionRange::isInRange(unsigned count)
273 {
274     if (m_state < Normal)
275         return true;
276
277     if ((m_lowLimit <= count) && (count <= m_highLimit))
278         return m_state == Normal ? true : false;
279
280     return m_state == Normal ? false : true;
281 }
282
283 void OptionRange::dump(PrintStream& out) const
284 {
285     out.print(m_rangeString);
286 }
287
288 Options::Entry Options::s_options[Options::numberOfOptions];
289 Options::Entry Options::s_defaultOptions[Options::numberOfOptions];
290
291 // Realize the names for each of the options:
292 const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = {
293 #define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
294     { #name_, description_, Options::Type::type_##Type, Availability::availability_ },
295     JSC_OPTIONS(FOR_EACH_OPTION)
296 #undef FOR_EACH_OPTION
297 };
298
299 static void scaleJITPolicy()
300 {
301     auto& scaleFactor = Options::jitPolicyScale();
302     if (scaleFactor > 1.0)
303         scaleFactor = 1.0;
304     else if (scaleFactor < 0.0)
305         scaleFactor = 0.0;
306
307     struct OptionToScale {
308         Options::ID id;
309         int32_t minVal;
310     };
311
312     static const OptionToScale optionsToScale[] = {
313         { Options::thresholdForJITAfterWarmUpID, 0 },
314         { Options::thresholdForJITSoonID, 0 },
315         { Options::thresholdForOptimizeAfterWarmUpID, 1 },
316         { Options::thresholdForOptimizeAfterLongWarmUpID, 1 },
317         { Options::thresholdForOptimizeSoonID, 1 },
318         { Options::thresholdForFTLOptimizeSoonID, 2 },
319         { Options::thresholdForFTLOptimizeAfterWarmUpID, 2 }
320     };
321
322     const int numberOfOptionsToScale = sizeof(optionsToScale) / sizeof(OptionToScale);
323     for (int i = 0; i < numberOfOptionsToScale; i++) {
324         Option option(optionsToScale[i].id);
325         ASSERT(option.type() == Options::Type::int32Type);
326         option.int32Val() *= scaleFactor;
327         option.int32Val() = std::max(option.int32Val(), optionsToScale[i].minVal);
328     }
329 }
330
331 static void overrideDefaults()
332 {
333 #if !PLATFORM(IOS)
334     if (WTF::numberOfProcessorCores() < 4)
335 #endif
336     {
337         Options::maximumMutatorUtilization() = 0.6;
338         Options::concurrentGCMaxHeadroom() = 1.4;
339         Options::minimumGCPauseMS() = 1;
340         Options::useStochasticMutatorScheduler() = false;
341         if (WTF::numberOfProcessorCores() <= 1)
342             Options::gcIncrementScale() = 1;
343         else
344             Options::gcIncrementScale() = 0;
345     }
346
347 #if PLATFORM(IOS)
348     // On iOS, we control heap growth using process memory footprint. Therefore these values can be agressive.
349     Options::smallHeapRAMFraction() = 0.8;
350     Options::mediumHeapRAMFraction() = 0.9;
351
352     Options::useSigillCrashAnalyzer() = true;
353 #endif
354
355 #if !ENABLE(SIGNAL_BASED_VM_TRAPS)
356     Options::usePollingTraps() = true;
357 #endif
358
359 #if !ENABLE(WEBASSEMBLY_FAST_MEMORY)
360     Options::useWebAssemblyFastMemory() = false;
361 #endif
362
363 #if !HAVE(MACH_EXCEPTIONS)
364     Options::useMachForExceptions() = false;
365 #endif
366 }
367
368 static void recomputeDependentOptions()
369 {
370 #if !defined(NDEBUG)
371     Options::validateDFGExceptionHandling() = true;
372 #endif
373 #if !ENABLE(JIT)
374     Options::useLLInt() = true;
375     Options::useJIT() = false;
376     Options::useDFGJIT() = false;
377     Options::useFTLJIT() = false;
378     Options::useDOMJIT() = false;
379 #endif
380 #if !ENABLE(YARR_JIT)
381     Options::useRegExpJIT() = false;
382 #endif
383 #if !ENABLE(CONCURRENT_JS)
384     Options::useConcurrentJIT() = false;
385 #endif
386 #if !ENABLE(DFG_JIT)
387     Options::useDFGJIT() = false;
388     Options::useFTLJIT() = false;
389 #endif
390 #if !ENABLE(FTL_JIT)
391     Options::useFTLJIT() = false;
392 #endif
393     
394 #if !CPU(X86_64) && !CPU(ARM64)
395     Options::useConcurrentGC() = false;
396 #endif
397     
398 #if OS(WINDOWS) && CPU(X86) 
399     // Disable JIT on Windows if SSE2 is not present 
400     if (!MacroAssemblerX86::supportsFloatingPoint())
401         Options::useJIT() = false;
402 #endif
403
404     if (!Options::useJIT())
405         Options::useWebAssembly() = false;
406
407     if (!Options::useWebAssembly()) {
408         Options::webAssemblyFastMemoryPreallocateCount() = 0;
409         Options::useWebAssemblyFastTLS() = false;
410     }
411     
412     if (Options::dumpDisassembly()
413         || Options::dumpDFGDisassembly()
414         || Options::dumpFTLDisassembly()
415         || Options::dumpBytecodeAtDFGTime()
416         || Options::dumpGraphAtEachPhase()
417         || Options::dumpDFGGraphAtEachPhase()
418         || Options::dumpDFGFTLGraphAtEachPhase()
419         || Options::dumpB3GraphAtEachPhase()
420         || Options::dumpAirGraphAtEachPhase()
421         || Options::verboseCompilation()
422         || Options::verboseFTLCompilation()
423         || Options::logCompilationChanges()
424         || Options::validateGraph()
425         || Options::validateGraphAtEachPhase()
426         || Options::verboseOSR()
427         || Options::verboseCompilationQueue()
428         || Options::reportCompileTimes()
429         || Options::reportBaselineCompileTimes()
430         || Options::reportDFGCompileTimes()
431         || Options::reportFTLCompileTimes()
432         || Options::reportDFGPhaseTimes()
433         || Options::verboseCFA()
434         || Options::verboseFTLFailure())
435         Options::alwaysComputeHash() = true;
436     
437     if (!Options::useConcurrentGC())
438         Options::collectContinuously() = false;
439
440     if (Option(Options::jitPolicyScaleID).isOverridden())
441         scaleJITPolicy();
442     
443     if (Options::forceEagerCompilation()) {
444         Options::thresholdForJITAfterWarmUp() = 10;
445         Options::thresholdForJITSoon() = 10;
446         Options::thresholdForOptimizeAfterWarmUp() = 20;
447         Options::thresholdForOptimizeAfterLongWarmUp() = 20;
448         Options::thresholdForOptimizeSoon() = 20;
449         Options::thresholdForFTLOptimizeAfterWarmUp() = 20;
450         Options::thresholdForFTLOptimizeSoon() = 20;
451         Options::maximumEvalCacheableSourceLength() = 150000;
452         Options::useConcurrentJIT() = false;
453     }
454     if (Options::useMaximalFlushInsertionPhase()) {
455         Options::useOSREntryToDFG() = false;
456         Options::useOSREntryToFTL() = false;
457     }
458     
459 #if PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000
460     // Override globally for now. Longer term we'll just make the default
461     // be to have this option enabled, and have platforms that don't support
462     // it just silently use a single mapping.
463     Options::useSeparatedWXHeap() = true;
464 #endif
465
466     if (Options::alwaysUseShadowChicken())
467         Options::maximumInliningDepth() = 1;
468
469     // Compute the maximum value of the reoptimization retry counter. This is simply
470     // the largest value at which we don't overflow the execute counter, when using it
471     // to left-shift the execution counter by this amount. Currently the value ends
472     // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles
473     // total on a 32-bit processor.
474     Options::reoptimizationRetryCounterMax() = 0;
475     while ((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << (Options::reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()))
476         Options::reoptimizationRetryCounterMax()++;
477
478     ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) > 0);
479     ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
480
481 #if ENABLE(LLINT_STATS)
482     LLInt::Data::loadStats();
483 #endif
484 #if !defined(NDEBUG)
485     if (Options::maxSingleAllocationSize())
486         fastSetMaxSingleAllocationSize(Options::maxSingleAllocationSize());
487     else
488         fastSetMaxSingleAllocationSize(std::numeric_limits<size_t>::max());
489 #endif
490
491     if (Options::useZombieMode()) {
492         Options::sweepSynchronously() = true;
493         Options::scribbleFreeCells() = true;
494     }
495
496     if (Options::useSigillCrashAnalyzer())
497         enableSigillCrashAnalyzer();
498 }
499
500 void Options::initialize()
501 {
502     static std::once_flag initializeOptionsOnceFlag;
503     
504     std::call_once(
505         initializeOptionsOnceFlag,
506         [] {
507             // Initialize each of the options with their default values:
508 #define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
509             name_() = defaultValue_;                                    \
510             name_##Default() = defaultValue_;
511             JSC_OPTIONS(FOR_EACH_OPTION)
512 #undef FOR_EACH_OPTION
513
514             overrideDefaults();
515                 
516             // Allow environment vars to override options if applicable.
517             // The evn var should be the name of the option prefixed with
518             // "JSC_".
519 #if PLATFORM(COCOA)
520             bool hasBadOptions = false;
521             for (char** envp = *_NSGetEnviron(); *envp; envp++) {
522                 const char* env = *envp;
523                 if (!strncmp("JSC_", env, 4)) {
524                     if (!Options::setOption(&env[4])) {
525                         dataLog("ERROR: invalid option: ", *envp, "\n");
526                         hasBadOptions = true;
527                     }
528                 }
529             }
530             if (hasBadOptions && Options::validateOptions())
531                 CRASH();
532 #else // PLATFORM(COCOA)
533 #define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
534             overrideOptionWithHeuristic(name_(), name_##ID, "JSC_" #name_, Availability::availability_);
535             JSC_OPTIONS(FOR_EACH_OPTION)
536 #undef FOR_EACH_OPTION
537 #endif // PLATFORM(COCOA)
538
539 #define FOR_EACH_OPTION(aliasedName_, unaliasedName_, equivalence_) \
540             overrideAliasedOptionWithHeuristic("JSC_" #aliasedName_);
541             JSC_ALIASED_OPTIONS(FOR_EACH_OPTION)
542 #undef FOR_EACH_OPTION
543
544 #if 0
545                 ; // Deconfuse editors that do auto indentation
546 #endif
547     
548             recomputeDependentOptions();
549
550             // Do range checks where needed and make corrections to the options:
551             ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp());
552             ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon());
553             ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
554             ASSERT(Options::criticalGCMemoryThreshold() > 0.0 && Options::criticalGCMemoryThreshold() < 1.0);
555
556             dumpOptionsIfNeeded();
557             ensureOptionsAreCoherent();
558
559 #if HAVE(MACH_EXCEPTIONS)
560             if (Options::useMachForExceptions())
561                 handleSignalsWithMach();
562 #endif
563         });
564 }
565
566 void Options::dumpOptionsIfNeeded()
567 {
568     if (Options::dumpOptions()) {
569         DumpLevel level = static_cast<DumpLevel>(Options::dumpOptions());
570         if (level > DumpLevel::Verbose)
571             level = DumpLevel::Verbose;
572             
573         const char* title = nullptr;
574         switch (level) {
575         case DumpLevel::None:
576             break;
577         case DumpLevel::Overridden:
578             title = "Overridden JSC options:";
579             break;
580         case DumpLevel::All:
581             title = "All JSC options:";
582             break;
583         case DumpLevel::Verbose:
584             title = "All JSC options with descriptions:";
585             break;
586         }
587
588         StringBuilder builder;
589         dumpAllOptions(builder, level, title, nullptr, "   ", "\n", DumpDefaults);
590         dataLog(builder.toString());
591     }
592 }
593
594 bool Options::setOptions(const char* optionsStr)
595 {
596     Vector<char*> options;
597
598     size_t length = strlen(optionsStr);
599     char* optionsStrCopy = WTF::fastStrDup(optionsStr);
600     char* end = optionsStrCopy + length;
601     char* p = optionsStrCopy;
602
603     while (p < end) {
604         // Skip white space.
605         while (p < end && isASCIISpace(*p))
606             p++;
607         if (p == end)
608             break;
609
610         char* optionStart = p;
611         p = strstr(p, "=");
612         if (!p) {
613             dataLogF("'=' not found in option string: %p\n", optionStart);
614             WTF::fastFree(optionsStrCopy);
615             return false;
616         }
617         p++;
618
619         char* valueBegin = p;
620         bool hasStringValue = false;
621         const int minStringLength = 2; // The min is an empty string i.e. 2 double quotes.
622         if ((p + minStringLength < end) && (*p == '"')) {
623             p = strstr(p + 1, "\"");
624             if (!p) {
625                 dataLogF("Missing trailing '\"' in option string: %p\n", optionStart);
626                 WTF::fastFree(optionsStrCopy);
627                 return false; // End of string not found.
628             }
629             hasStringValue = true;
630         }
631
632         // Find next white space.
633         while (p < end && !isASCIISpace(*p))
634             p++;
635         if (!p)
636             p = end; // No more " " separator. Hence, this is the last arg.
637
638         // If we have a well-formed string value, strip the quotes.
639         if (hasStringValue) {
640             char* valueEnd = p;
641             ASSERT((*valueBegin == '"') && ((valueEnd - valueBegin) >= minStringLength) && (valueEnd[-1] == '"'));
642             memmove(valueBegin, valueBegin + 1, valueEnd - valueBegin - minStringLength);
643             valueEnd[-minStringLength] = '\0';
644         }
645
646         // Strip leading -- if present.
647         if ((p -  optionStart > 2) && optionStart[0] == '-' && optionStart[1] == '-')
648             optionStart += 2;
649
650         *p++ = '\0';
651         options.append(optionStart);
652     }
653
654     bool success = true;
655     for (auto& option : options) {
656         bool optionSuccess = setOption(option);
657         if (!optionSuccess) {
658             dataLogF("Failed to set option : %s\n", option);
659             success = false;
660         }
661     }
662
663     recomputeDependentOptions();
664
665     dumpOptionsIfNeeded();
666
667     ensureOptionsAreCoherent();
668
669     WTF::fastFree(optionsStrCopy);
670
671     return success;
672 }
673
674 // Parses a single command line option in the format "<optionName>=<value>"
675 // (no spaces allowed) and set the specified option if appropriate.
676 bool Options::setOptionWithoutAlias(const char* arg)
677 {
678     // arg should look like this:
679     //   <jscOptionName>=<appropriate value>
680     const char* equalStr = strchr(arg, '=');
681     if (!equalStr)
682         return false;
683
684     const char* valueStr = equalStr + 1;
685
686     // For each option, check if the specify arg is a match. If so, set the arg
687     // if the value makes sense. Otherwise, move on to checking the next option.
688 #define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
689     if (strlen(#name_) == static_cast<size_t>(equalStr - arg)      \
690         && !strncmp(arg, #name_, equalStr - arg)) {                \
691         if (Availability::availability_ != Availability::Normal     \
692             && !isAvailable(name_##ID, Availability::availability_)) \
693             return false;                                          \
694         type_ value;                                               \
695         value = (defaultValue_);                                   \
696         bool success = parse(valueStr, value);                     \
697         if (success) {                                             \
698             name_() = value;                                       \
699             recomputeDependentOptions();                           \
700             return true;                                           \
701         }                                                          \
702         return false;                                              \
703     }
704
705     JSC_OPTIONS(FOR_EACH_OPTION)
706 #undef FOR_EACH_OPTION
707
708     return false; // No option matched.
709 }
710
711 static bool invertBoolOptionValue(const char* valueStr, const char*& invertedValueStr)
712 {
713     bool boolValue;
714     if (!parse(valueStr, boolValue))
715         return false;
716     invertedValueStr = boolValue ? "false" : "true";
717     return true;
718 }
719
720
721 bool Options::setAliasedOption(const char* arg)
722 {
723     // arg should look like this:
724     //   <jscOptionName>=<appropriate value>
725     const char* equalStr = strchr(arg, '=');
726     if (!equalStr)
727         return false;
728
729 #if COMPILER(CLANG)
730 #if __has_warning("-Wtautological-compare")
731 #pragma clang diagnostic push
732 #pragma clang diagnostic ignored "-Wtautological-compare"
733 #endif
734 #endif
735
736     // For each option, check if the specify arg is a match. If so, set the arg
737     // if the value makes sense. Otherwise, move on to checking the next option.
738 #define FOR_EACH_OPTION(aliasedName_, unaliasedName_, equivalence) \
739     if (strlen(#aliasedName_) == static_cast<size_t>(equalStr - arg)    \
740         && !strncmp(arg, #aliasedName_, equalStr - arg)) {              \
741         String unaliasedOption(#unaliasedName_);                        \
742         if (equivalence == SameOption)                                  \
743             unaliasedOption = unaliasedOption + equalStr;               \
744         else {                                                          \
745             ASSERT(equivalence == InvertedOption);                      \
746             const char* invertedValueStr = nullptr;                     \
747             if (!invertBoolOptionValue(equalStr + 1, invertedValueStr)) \
748                 return false;                                           \
749             unaliasedOption = unaliasedOption + "=" + invertedValueStr; \
750         }                                                               \
751         return setOptionWithoutAlias(unaliasedOption.utf8().data());   \
752     }
753
754     JSC_ALIASED_OPTIONS(FOR_EACH_OPTION)
755 #undef FOR_EACH_OPTION
756
757 #if COMPILER(CLANG)
758 #if __has_warning("-Wtautological-compare")
759 #pragma clang diagnostic pop
760 #endif
761 #endif
762
763     return false; // No option matched.
764 }
765
766 bool Options::setOption(const char* arg)
767 {
768     bool success = setOptionWithoutAlias(arg);
769     if (success)
770         return true;
771     return setAliasedOption(arg);
772 }
773
774
775 void Options::dumpAllOptions(StringBuilder& builder, DumpLevel level, const char* title,
776     const char* separator, const char* optionHeader, const char* optionFooter, DumpDefaultsOption dumpDefaultsOption)
777 {
778     if (title) {
779         builder.append(title);
780         builder.append('\n');
781     }
782
783     for (int id = 0; id < numberOfOptions; id++) {
784         if (separator && id)
785             builder.append(separator);
786         dumpOption(builder, level, static_cast<ID>(id), optionHeader, optionFooter, dumpDefaultsOption);
787     }
788 }
789
790 void Options::dumpAllOptionsInALine(StringBuilder& builder)
791 {
792     dumpAllOptions(builder, DumpLevel::All, nullptr, " ", nullptr, nullptr, DontDumpDefaults);
793 }
794
795 void Options::dumpAllOptions(FILE* stream, DumpLevel level, const char* title)
796 {
797     StringBuilder builder;
798     dumpAllOptions(builder, level, title, nullptr, "   ", "\n", DumpDefaults);
799     fprintf(stream, "%s", builder.toString().utf8().data());
800 }
801
802 void Options::dumpOption(StringBuilder& builder, DumpLevel level, Options::ID id,
803     const char* header, const char* footer, DumpDefaultsOption dumpDefaultsOption)
804 {
805     if (id >= numberOfOptions)
806         return; // Illegal option.
807
808     Option option(id);
809     Availability availability = option.availability();
810     if (availability != Availability::Normal && !isAvailable(id, availability))
811         return;
812
813     bool wasOverridden = option.isOverridden();
814     bool needsDescription = (level == DumpLevel::Verbose && option.description());
815
816     if (level == DumpLevel::Overridden && !wasOverridden)
817         return;
818
819     if (header)
820         builder.append(header);
821     builder.append(option.name());
822     builder.append('=');
823     option.dump(builder);
824
825     if (wasOverridden && (dumpDefaultsOption == DumpDefaults)) {
826         builder.appendLiteral(" (default: ");
827         option.defaultOption().dump(builder);
828         builder.appendLiteral(")");
829     }
830
831     if (needsDescription) {
832         builder.appendLiteral("   ... ");
833         builder.append(option.description());
834     }
835
836     builder.append(footer);
837 }
838
839 void Options::ensureOptionsAreCoherent()
840 {
841     bool coherent = true;
842     if (!(useLLInt() || useJIT())) {
843         coherent = false;
844         dataLog("INCOHERENT OPTIONS: at least one of useLLInt or useJIT must be true\n");
845     }
846     if (!coherent)
847         CRASH();
848 }
849
850 void Option::dump(StringBuilder& builder) const
851 {
852     switch (type()) {
853     case Options::Type::boolType:
854         builder.append(m_entry.boolVal ? "true" : "false");
855         break;
856     case Options::Type::unsignedType:
857         builder.appendNumber(m_entry.unsignedVal);
858         break;
859     case Options::Type::sizeType:
860         builder.appendNumber(m_entry.sizeVal);
861         break;
862     case Options::Type::doubleType:
863         builder.appendNumber(m_entry.doubleVal);
864         break;
865     case Options::Type::int32Type:
866         builder.appendNumber(m_entry.int32Val);
867         break;
868     case Options::Type::optionRangeType:
869         builder.append(m_entry.optionRangeVal.rangeString());
870         break;
871     case Options::Type::optionStringType: {
872         const char* option = m_entry.optionStringVal;
873         if (!option)
874             option = "";
875         builder.append('"');
876         builder.append(option);
877         builder.append('"');
878         break;
879     }
880     case Options::Type::gcLogLevelType: {
881         builder.append(GCLogging::levelAsString(m_entry.gcLogLevelVal));
882         break;
883     }
884     }
885 }
886
887 bool Option::operator==(const Option& other) const
888 {
889     switch (type()) {
890     case Options::Type::boolType:
891         return m_entry.boolVal == other.m_entry.boolVal;
892     case Options::Type::unsignedType:
893         return m_entry.unsignedVal == other.m_entry.unsignedVal;
894     case Options::Type::sizeType:
895         return m_entry.sizeVal == other.m_entry.sizeVal;
896     case Options::Type::doubleType:
897         return (m_entry.doubleVal == other.m_entry.doubleVal) || (std::isnan(m_entry.doubleVal) && std::isnan(other.m_entry.doubleVal));
898     case Options::Type::int32Type:
899         return m_entry.int32Val == other.m_entry.int32Val;
900     case Options::Type::optionRangeType:
901         return m_entry.optionRangeVal.rangeString() == other.m_entry.optionRangeVal.rangeString();
902     case Options::Type::optionStringType:
903         return (m_entry.optionStringVal == other.m_entry.optionStringVal)
904             || (m_entry.optionStringVal && other.m_entry.optionStringVal && !strcmp(m_entry.optionStringVal, other.m_entry.optionStringVal));
905     case Options::Type::gcLogLevelType:
906         return m_entry.gcLogLevelVal == other.m_entry.gcLogLevelVal;
907     }
908     return false;
909 }
910
911 } // namespace JSC
912