]>
Commit | Line | Data |
---|---|---|
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 | 50 | namespace JSC { |
6fe7ccc8 | 51 | |
6fe7ccc8 A |
52 | static 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 | ||
65 | static bool parse(const char* string, int32_t& value) | |
66 | { | |
67 | return sscanf(string, "%d", &value) == 1; | |
68 | } | |
69 | ||
70 | static bool parse(const char* string, unsigned& value) | |
71 | { | |
72 | return sscanf(string, "%u", &value) == 1; | |
73 | } | |
74 | ||
75 | static bool parse(const char* string, double& value) | |
76 | { | |
77 | return sscanf(string, "%lf", &value) == 1; | |
78 | } | |
79 | ||
93a37866 A |
80 | static bool parse(const char* string, OptionRange& value) |
81 | { | |
82 | return value.init(string); | |
83 | } | |
84 | ||
81345200 A |
85 | static bool parse(const char* string, const char*& value) |
86 | { | |
87 | value = string; | |
88 | return true; | |
89 | } | |
90 | ||
91 | static 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 | 111 | template<typename T> |
81345200 | 112 | bool 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 | 125 | static 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 | ||
134 | static int32_t computePriorityDeltaOfWorkerThreads(int32_t twoCorePriorityDelta, int32_t multiCorePriorityDelta) | |
135 | { | |
136 | if (WTF::numberOfProcessorCores() <= 2) | |
137 | return twoCorePriorityDelta; | |
138 | ||
139 | return multiCorePriorityDelta; | |
140 | } | |
141 | ||
142 | static 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 | ||
152 | bool 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 | ||
194 | bool 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 |
205 | void OptionRange::dump(PrintStream& out) const |
206 | { | |
207 | out.print(m_rangeString); | |
208 | } | |
209 | ||
93a37866 | 210 | Options::Entry Options::s_options[Options::numberOfOptions]; |
ed1e77d3 | 211 | Options::Entry Options::s_defaultOptions[Options::numberOfOptions]; |
93a37866 A |
212 | |
213 | // Realize the names for each of the options: | |
214 | const 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 |
221 | static 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 |
253 | static 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 |
325 | void 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. | |
391 | bool 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 | 422 | void 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 | 430 | void 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 | ||
457 | void 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 | ||
468 | void 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 | ||
500 | bool 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 |