1 | /* |
2 | * Copyright (C) 2011-2019 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 "CPU.h" |
31 | #include "LLIntCommon.h" |
32 | #include "MinimumReservedZoneSize.h" |
33 | #include "SigillCrashAnalyzer.h" |
34 | #include <algorithm> |
35 | #include <limits> |
36 | #include <math.h> |
37 | #include <mutex> |
38 | #include <stdlib.h> |
39 | #include <string.h> |
40 | #include <wtf/ASCIICType.h> |
41 | #include <wtf/Compiler.h> |
42 | #include <wtf/DataLog.h> |
43 | #include <wtf/NumberOfCores.h> |
44 | #include <wtf/Optional.h> |
45 | #include <wtf/PointerPreparations.h> |
46 | #include <wtf/StdLibExtras.h> |
47 | #include <wtf/text/StringBuilder.h> |
48 | #include <wtf/threads/Signals.h> |
49 | |
50 | #if PLATFORM(COCOA) |
51 | #include <crt_externs.h> |
52 | #endif |
53 | |
54 | #if ENABLE(JIT) |
55 | #include "MacroAssembler.h" |
56 | #endif |
57 | |
58 | namespace JSC { |
59 | |
60 | template<typename T> |
61 | Optional<T> parse(const char* string); |
62 | |
63 | template<> |
64 | Optional<OptionsStorage::Bool> parse(const char* string) |
65 | { |
66 | if (equalLettersIgnoringASCIICase(string, "true" ) || equalLettersIgnoringASCIICase(string, "yes" ) || !strcmp(string, "1" )) |
67 | return true; |
68 | if (equalLettersIgnoringASCIICase(string, "false" ) || equalLettersIgnoringASCIICase(string, "no" ) || !strcmp(string, "0" )) |
69 | return false; |
70 | return WTF::nullopt; |
71 | } |
72 | |
73 | template<> |
74 | Optional<OptionsStorage::Int32> parse(const char* string) |
75 | { |
76 | int32_t value; |
77 | if (sscanf(string, "%d" , &value) == 1) |
78 | return value; |
79 | return WTF::nullopt; |
80 | } |
81 | |
82 | template<> |
83 | Optional<OptionsStorage::Unsigned> parse(const char* string) |
84 | { |
85 | unsigned value; |
86 | if (sscanf(string, "%u" , &value) == 1) |
87 | return value; |
88 | return WTF::nullopt; |
89 | } |
90 | |
91 | #if CPU(ADDRESS64) || OS(DARWIN) |
92 | template<> |
93 | Optional<OptionsStorage::Size> parse(const char* string) |
94 | { |
95 | size_t value; |
96 | if (sscanf(string, "%zu" , &value) == 1) |
97 | return value; |
98 | return WTF::nullopt; |
99 | } |
100 | #endif // CPU(ADDRESS64) || OS(DARWIN) |
101 | |
102 | template<> |
103 | Optional<OptionsStorage::Double> parse(const char* string) |
104 | { |
105 | double value; |
106 | if (sscanf(string, "%lf" , &value) == 1) |
107 | return value; |
108 | return WTF::nullopt; |
109 | } |
110 | |
111 | template<> |
112 | Optional<OptionsStorage::OptionRange> parse(const char* string) |
113 | { |
114 | OptionRange range; |
115 | if (range.init(string)) |
116 | return range; |
117 | return WTF::nullopt; |
118 | } |
119 | |
120 | template<> |
121 | Optional<OptionsStorage::OptionString> parse(const char* string) |
122 | { |
123 | const char* value = nullptr; |
124 | if (!strlen(string)) |
125 | return value; |
126 | |
127 | // FIXME <https://webkit.org/b/169057>: This could leak if this option is set more than once. |
128 | // Given that Options are typically used for testing, this isn't considered to be a problem. |
129 | value = WTF::fastStrDup(string); |
130 | return value; |
131 | } |
132 | |
133 | template<> |
134 | Optional<OptionsStorage::GCLogLevel> parse(const char* string) |
135 | { |
136 | if (equalLettersIgnoringASCIICase(string, "none" ) || equalLettersIgnoringASCIICase(string, "no" ) || equalLettersIgnoringASCIICase(string, "false" ) || !strcmp(string, "0" )) |
137 | return GCLogging::None; |
138 | |
139 | if (equalLettersIgnoringASCIICase(string, "basic" ) || equalLettersIgnoringASCIICase(string, "yes" ) || equalLettersIgnoringASCIICase(string, "true" ) || !strcmp(string, "1" )) |
140 | return GCLogging::Basic; |
141 | |
142 | if (equalLettersIgnoringASCIICase(string, "verbose" ) || !strcmp(string, "2" )) |
143 | return GCLogging::Verbose; |
144 | |
145 | return WTF::nullopt; |
146 | } |
147 | |
148 | bool Options::isAvailable(Options::ID id, Options::Availability availability) |
149 | { |
150 | if (availability == Availability::Restricted) |
151 | return g_jscConfig.restrictedOptionsEnabled; |
152 | ASSERT(availability == Availability::Configurable); |
153 | |
154 | UNUSED_PARAM(id); |
155 | #if !defined(NDEBUG) |
156 | if (id == maxSingleAllocationSizeID) |
157 | return true; |
158 | #endif |
159 | #if OS(DARWIN) |
160 | if (id == useSigillCrashAnalyzerID) |
161 | return true; |
162 | #endif |
163 | #if ENABLE(ASSEMBLER) && OS(LINUX) |
164 | if (id == logJITCodeForPerfID) |
165 | return true; |
166 | #endif |
167 | if (id == traceLLIntExecutionID) |
168 | return !!LLINT_TRACING; |
169 | if (id == traceLLIntSlowPathID) |
170 | return !!LLINT_TRACING; |
171 | return false; |
172 | } |
173 | |
174 | template<typename T> |
175 | bool overrideOptionWithHeuristic(T& variable, Options::ID id, const char* name, Options::Availability availability) |
176 | { |
177 | bool available = (availability == Options::Availability::Normal) |
178 | || Options::isAvailable(id, availability); |
179 | |
180 | const char* stringValue = getenv(name); |
181 | if (!stringValue) |
182 | return false; |
183 | |
184 | if (available) { |
185 | Optional<T> value = parse<T>(stringValue); |
186 | if (value) { |
187 | variable = value.value(); |
188 | return true; |
189 | } |
190 | } |
191 | |
192 | fprintf(stderr, "WARNING: failed to parse %s=%s\n" , name, stringValue); |
193 | return false; |
194 | } |
195 | |
196 | bool Options::overrideAliasedOptionWithHeuristic(const char* name) |
197 | { |
198 | const char* stringValue = getenv(name); |
199 | if (!stringValue) |
200 | return false; |
201 | |
202 | String aliasedOption; |
203 | aliasedOption = String(&name[4]) + "=" + stringValue; |
204 | if (Options::setOption(aliasedOption.utf8().data())) |
205 | return true; |
206 | |
207 | fprintf(stderr, "WARNING: failed to parse %s=%s\n" , name, stringValue); |
208 | return false; |
209 | } |
210 | |
211 | static unsigned computeNumberOfWorkerThreads(int maxNumberOfWorkerThreads, int minimum = 1) |
212 | { |
213 | int cpusToUse = std::min(kernTCSMAwareNumberOfProcessorCores(), maxNumberOfWorkerThreads); |
214 | |
215 | // Be paranoid, it is the OS we're dealing with, after all. |
216 | ASSERT(cpusToUse >= 1); |
217 | return std::max(cpusToUse, minimum); |
218 | } |
219 | |
220 | static int32_t computePriorityDeltaOfWorkerThreads(int32_t twoCorePriorityDelta, int32_t multiCorePriorityDelta) |
221 | { |
222 | if (kernTCSMAwareNumberOfProcessorCores() <= 2) |
223 | return twoCorePriorityDelta; |
224 | |
225 | return multiCorePriorityDelta; |
226 | } |
227 | |
228 | static bool jitEnabledByDefault() |
229 | { |
230 | return is32Bit() || isAddress64Bit(); |
231 | } |
232 | |
233 | static unsigned computeNumberOfGCMarkers(unsigned maxNumberOfGCMarkers) |
234 | { |
235 | return computeNumberOfWorkerThreads(maxNumberOfGCMarkers); |
236 | } |
237 | |
238 | const char* const OptionRange::s_nullRangeStr = "<null>" ; |
239 | |
240 | bool OptionRange::init(const char* rangeString) |
241 | { |
242 | // rangeString should be in the form of [!]<low>[:<high>] |
243 | // where low and high are unsigned |
244 | |
245 | bool invert = false; |
246 | |
247 | if (!rangeString) { |
248 | m_state = InitError; |
249 | return false; |
250 | } |
251 | |
252 | if (!strcmp(rangeString, s_nullRangeStr)) { |
253 | m_state = Uninitialized; |
254 | return true; |
255 | } |
256 | |
257 | const char* p = rangeString; |
258 | |
259 | if (*p == '!') { |
260 | invert = true; |
261 | p++; |
262 | } |
263 | |
264 | int scanResult = sscanf(p, " %u:%u" , &m_lowLimit, &m_highLimit); |
265 | |
266 | if (!scanResult || scanResult == EOF) { |
267 | m_state = InitError; |
268 | return false; |
269 | } |
270 | |
271 | if (scanResult == 1) |
272 | m_highLimit = m_lowLimit; |
273 | |
274 | if (m_lowLimit > m_highLimit) { |
275 | m_state = InitError; |
276 | return false; |
277 | } |
278 | |
279 | // FIXME <https://webkit.org/b/169057>: This could leak if this particular option is set more than once. |
280 | // Given that these options are used for testing, this isn't considered to be problem. |
281 | m_rangeString = WTF::fastStrDup(rangeString); |
282 | m_state = invert ? Inverted : Normal; |
283 | |
284 | return true; |
285 | } |
286 | |
287 | bool OptionRange::isInRange(unsigned count) |
288 | { |
289 | if (m_state < Normal) |
290 | return true; |
291 | |
292 | if ((m_lowLimit <= count) && (count <= m_highLimit)) |
293 | return m_state == Normal ? true : false; |
294 | |
295 | return m_state == Normal ? false : true; |
296 | } |
297 | |
298 | void OptionRange::dump(PrintStream& out) const |
299 | { |
300 | out.print(m_rangeString); |
301 | } |
302 | |
303 | // Realize the names for each of the options: |
304 | const Options::ConstMetaData Options::s_constMetaData[NumberOfOptions] = { |
305 | #define FILL_OPTION_INFO(type_, name_, defaultValue_, availability_, description_) \ |
306 | { #name_, description_, Options::Type::type_, Availability::availability_, offsetof(OptionsStorage, name_), offsetof(OptionsStorage, name_##Default) }, |
307 | FOR_EACH_JSC_OPTION(FILL_OPTION_INFO) |
308 | #undef FILL_OPTION_INFO |
309 | }; |
310 | |
311 | static void scaleJITPolicy() |
312 | { |
313 | auto& scaleFactor = Options::jitPolicyScale(); |
314 | if (scaleFactor > 1.0) |
315 | scaleFactor = 1.0; |
316 | else if (scaleFactor < 0.0) |
317 | scaleFactor = 0.0; |
318 | |
319 | auto scaleOption = [&] (int32_t& optionValue, int32_t minValue) { |
320 | optionValue *= scaleFactor; |
321 | optionValue = std::max(optionValue, minValue); |
322 | }; |
323 | |
324 | scaleOption(Options::thresholdForJITAfterWarmUp(), 0); |
325 | scaleOption(Options::thresholdForJITSoon(), 0); |
326 | scaleOption(Options::thresholdForOptimizeAfterWarmUp(), 1); |
327 | scaleOption(Options::thresholdForOptimizeAfterLongWarmUp(), 1); |
328 | scaleOption(Options::thresholdForOptimizeSoon(), 1); |
329 | scaleOption(Options::thresholdForFTLOptimizeSoon(), 2); |
330 | scaleOption(Options::thresholdForFTLOptimizeAfterWarmUp(), 2); |
331 | } |
332 | |
333 | static void overrideDefaults() |
334 | { |
335 | #if !PLATFORM(IOS_FAMILY) |
336 | if (WTF::numberOfProcessorCores() < 4) |
337 | #endif |
338 | { |
339 | Options::maximumMutatorUtilization() = 0.6; |
340 | Options::concurrentGCMaxHeadroom() = 1.4; |
341 | Options::minimumGCPauseMS() = 1; |
342 | Options::useStochasticMutatorScheduler() = false; |
343 | if (WTF::numberOfProcessorCores() <= 1) |
344 | Options::gcIncrementScale() = 1; |
345 | else |
346 | Options::gcIncrementScale() = 0; |
347 | } |
348 | |
349 | #if PLATFORM(IOS_FAMILY) |
350 | // On iOS, we control heap growth using process memory footprint. Therefore these values can be agressive. |
351 | Options::smallHeapRAMFraction() = 0.8; |
352 | Options::mediumHeapRAMFraction() = 0.9; |
353 | |
354 | #if !PLATFORM(WATCHOS) && defined(__LP64__) |
355 | Options::useSigillCrashAnalyzer() = true; |
356 | #endif |
357 | #endif |
358 | |
359 | #if !ENABLE(SIGNAL_BASED_VM_TRAPS) |
360 | Options::usePollingTraps() = true; |
361 | #endif |
362 | |
363 | #if !ENABLE(WEBASSEMBLY_FAST_MEMORY) |
364 | Options::useWebAssemblyFastMemory() = false; |
365 | #endif |
366 | |
367 | #if !HAVE(MACH_EXCEPTIONS) |
368 | Options::useMachForExceptions() = false; |
369 | #endif |
370 | |
371 | if (Options::useWasmLLInt() && !Options::wasmLLIntTiersUpToBBQ()) { |
372 | Options::thresholdForOMGOptimizeAfterWarmUp() = 1500; |
373 | Options::thresholdForOMGOptimizeSoon() = 100; |
374 | } |
375 | } |
376 | |
377 | static void correctOptions() |
378 | { |
379 | unsigned thresholdForGlobalLexicalBindingEpoch = Options::thresholdForGlobalLexicalBindingEpoch(); |
380 | if (thresholdForGlobalLexicalBindingEpoch == 0 || thresholdForGlobalLexicalBindingEpoch == 1) |
381 | Options::thresholdForGlobalLexicalBindingEpoch() = UINT_MAX; |
382 | } |
383 | |
384 | static void recomputeDependentOptions() |
385 | { |
386 | #if !defined(NDEBUG) |
387 | Options::validateDFGExceptionHandling() = true; |
388 | #endif |
389 | #if !ENABLE(JIT) |
390 | Options::useLLInt() = true; |
391 | Options::useJIT() = false; |
392 | Options::useBaselineJIT() = false; |
393 | Options::useDFGJIT() = false; |
394 | Options::useFTLJIT() = false; |
395 | Options::useDOMJIT() = false; |
396 | Options::useRegExpJIT() = false; |
397 | #endif |
398 | #if !ENABLE(CONCURRENT_JS) |
399 | Options::useConcurrentJIT() = false; |
400 | #endif |
401 | #if !ENABLE(YARR_JIT) |
402 | Options::useRegExpJIT() = false; |
403 | #endif |
404 | #if !ENABLE(DFG_JIT) |
405 | Options::useDFGJIT() = false; |
406 | Options::useFTLJIT() = false; |
407 | #endif |
408 | #if !ENABLE(FTL_JIT) |
409 | Options::useFTLJIT() = false; |
410 | #endif |
411 | |
412 | #if !CPU(X86_64) && !CPU(ARM64) |
413 | Options::useConcurrentGC() = false; |
414 | #endif |
415 | |
416 | if (!Options::useJIT()) { |
417 | Options::useSigillCrashAnalyzer() = false; |
418 | Options::useWebAssembly() = false; |
419 | } |
420 | |
421 | if (!jitEnabledByDefault() && !Options::useJIT()) |
422 | Options::useLLInt() = true; |
423 | |
424 | if (!Options::useWebAssembly()) |
425 | Options::useFastTLSForWasmContext() = false; |
426 | |
427 | if (Options::dumpDisassembly() |
428 | || Options::dumpDFGDisassembly() |
429 | || Options::dumpFTLDisassembly() |
430 | || Options::dumpBytecodeAtDFGTime() |
431 | || Options::dumpGraphAtEachPhase() |
432 | || Options::dumpDFGGraphAtEachPhase() |
433 | || Options::dumpDFGFTLGraphAtEachPhase() |
434 | || Options::dumpB3GraphAtEachPhase() |
435 | || Options::dumpAirGraphAtEachPhase() |
436 | || Options::verboseCompilation() |
437 | || Options::verboseFTLCompilation() |
438 | || Options::logCompilationChanges() |
439 | || Options::validateGraph() |
440 | || Options::validateGraphAtEachPhase() |
441 | || Options::verboseOSR() |
442 | || Options::verboseCompilationQueue() |
443 | || Options::reportCompileTimes() |
444 | || Options::reportBaselineCompileTimes() |
445 | || Options::reportDFGCompileTimes() |
446 | || Options::reportFTLCompileTimes() |
447 | || Options::logPhaseTimes() |
448 | || Options::verboseCFA() |
449 | || Options::verboseDFGFailure() |
450 | || Options::verboseFTLFailure() |
451 | || Options::dumpRandomizingFuzzerAgentPredictions()) |
452 | Options::alwaysComputeHash() = true; |
453 | |
454 | if (!Options::useConcurrentGC()) |
455 | Options::collectContinuously() = false; |
456 | |
457 | if (Options::jitPolicyScale() != Options::jitPolicyScaleDefault()) |
458 | scaleJITPolicy(); |
459 | |
460 | if (Options::forceEagerCompilation()) { |
461 | Options::thresholdForJITAfterWarmUp() = 10; |
462 | Options::thresholdForJITSoon() = 10; |
463 | Options::thresholdForOptimizeAfterWarmUp() = 20; |
464 | Options::thresholdForOptimizeAfterLongWarmUp() = 20; |
465 | Options::thresholdForOptimizeSoon() = 20; |
466 | Options::thresholdForFTLOptimizeAfterWarmUp() = 20; |
467 | Options::thresholdForFTLOptimizeSoon() = 20; |
468 | Options::maximumEvalCacheableSourceLength() = 150000; |
469 | Options::useConcurrentJIT() = false; |
470 | } |
471 | #if ENABLE(SEPARATED_WX_HEAP) |
472 | // Override globally for now. Longer term we'll just make the default |
473 | // be to have this option enabled, and have platforms that don't support |
474 | // it just silently use a single mapping. |
475 | Options::useSeparatedWXHeap() = true; |
476 | #else |
477 | Options::useSeparatedWXHeap() = false; |
478 | #endif |
479 | |
480 | if (Options::alwaysUseShadowChicken()) |
481 | Options::maximumInliningDepth() = 1; |
482 | |
483 | // Compute the maximum value of the reoptimization retry counter. This is simply |
484 | // the largest value at which we don't overflow the execute counter, when using it |
485 | // to left-shift the execution counter by this amount. Currently the value ends |
486 | // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles |
487 | // total on a 32-bit processor. |
488 | Options::reoptimizationRetryCounterMax() = 0; |
489 | while ((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << (Options::reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max())) |
490 | Options::reoptimizationRetryCounterMax()++; |
491 | |
492 | ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) > 0); |
493 | ASSERT((static_cast<int64_t>(Options::thresholdForOptimizeAfterLongWarmUp()) << Options::reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max())); |
494 | |
495 | #if !defined(NDEBUG) |
496 | if (Options::maxSingleAllocationSize()) |
497 | fastSetMaxSingleAllocationSize(Options::maxSingleAllocationSize()); |
498 | else |
499 | fastSetMaxSingleAllocationSize(std::numeric_limits<size_t>::max()); |
500 | #endif |
501 | |
502 | if (Options::useZombieMode()) { |
503 | Options::sweepSynchronously() = true; |
504 | Options::scribbleFreeCells() = true; |
505 | } |
506 | |
507 | if (Options::reservedZoneSize() < minimumReservedZoneSize) |
508 | Options::reservedZoneSize() = minimumReservedZoneSize; |
509 | if (Options::softReservedZoneSize() < Options::reservedZoneSize() + minimumReservedZoneSize) |
510 | Options::softReservedZoneSize() = Options::reservedZoneSize() + minimumReservedZoneSize; |
511 | |
512 | #if USE(JSVALUE32_64) |
513 | // FIXME: Make probe OSR exit work on 32-bit: |
514 | // https://bugs.webkit.org/show_bug.cgi?id=177956 |
515 | Options::useProbeOSRExit() = false; |
516 | #endif |
517 | |
518 | if (!Options::useCodeCache()) |
519 | Options::diskCachePath() = nullptr; |
520 | |
521 | if (Options::randomIntegrityAuditRate() < 0) |
522 | Options::randomIntegrityAuditRate() = 0; |
523 | else if (Options::randomIntegrityAuditRate() > 1.0) |
524 | Options::randomIntegrityAuditRate() = 1.0; |
525 | } |
526 | |
527 | inline void* Options::addressOfOption(Options::ID id) |
528 | { |
529 | auto offset = Options::s_constMetaData[id].offsetOfOption; |
530 | return reinterpret_cast<uint8_t*>(&g_jscConfig.options) + offset; |
531 | } |
532 | |
533 | inline void* Options::addressOfOptionDefault(Options::ID id) |
534 | { |
535 | auto offset = Options::s_constMetaData[id].offsetOfOptionDefault; |
536 | return reinterpret_cast<uint8_t*>(&g_jscConfig.options) + offset; |
537 | } |
538 | |
539 | void Options::initialize() |
540 | { |
541 | static std::once_flag initializeOptionsOnceFlag; |
542 | |
543 | std::call_once( |
544 | initializeOptionsOnceFlag, |
545 | [] { |
546 | // Sanity check that options address computation is working. |
547 | RELEASE_ASSERT(Options::addressOfOption(useKernTCSMID) == &Options::useKernTCSM()); |
548 | RELEASE_ASSERT(Options::addressOfOptionDefault(useKernTCSMID) == &Options::useKernTCSMDefault()); |
549 | RELEASE_ASSERT(Options::addressOfOption(gcMaxHeapSizeID) == &Options::gcMaxHeapSize()); |
550 | RELEASE_ASSERT(Options::addressOfOptionDefault(gcMaxHeapSizeID) == &Options::gcMaxHeapSizeDefault()); |
551 | RELEASE_ASSERT(Options::addressOfOption(forceOSRExitToLLIntID) == &Options::forceOSRExitToLLInt()); |
552 | RELEASE_ASSERT(Options::addressOfOptionDefault(forceOSRExitToLLIntID) == &Options::forceOSRExitToLLIntDefault()); |
553 | |
554 | #ifndef NDEBUG |
555 | Config::enableRestrictedOptions(); |
556 | #endif |
557 | // Initialize each of the options with their default values: |
558 | #define INIT_OPTION(type_, name_, defaultValue_, availability_, description_) { \ |
559 | auto |
---|