]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 | 1 | /* |
93a37866 | 2 | * Copyright (C) 2011, 2012 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> |
93a37866 A |
32 | #include <stdio.h> |
33 | #include <stdlib.h> | |
34 | #include <string.h> | |
6fe7ccc8 A |
35 | #include <wtf/NumberOfCores.h> |
36 | #include <wtf/PageBlock.h> | |
93a37866 A |
37 | #include <wtf/StdLibExtras.h> |
38 | #include <wtf/StringExtras.h> | |
6fe7ccc8 A |
39 | |
40 | #if OS(DARWIN) && ENABLE(PARALLEL_GC) | |
41 | #include <sys/sysctl.h> | |
42 | #endif | |
43 | ||
93a37866 | 44 | namespace JSC { |
6fe7ccc8 | 45 | |
6fe7ccc8 A |
46 | static bool parse(const char* string, bool& value) |
47 | { | |
48 | if (!strcasecmp(string, "true") || !strcasecmp(string, "yes") || !strcmp(string, "1")) { | |
49 | value = true; | |
50 | return true; | |
51 | } | |
52 | if (!strcasecmp(string, "false") || !strcasecmp(string, "no") || !strcmp(string, "0")) { | |
53 | value = false; | |
54 | return true; | |
55 | } | |
56 | return false; | |
57 | } | |
58 | ||
59 | static bool parse(const char* string, int32_t& value) | |
60 | { | |
61 | return sscanf(string, "%d", &value) == 1; | |
62 | } | |
63 | ||
64 | static bool parse(const char* string, unsigned& value) | |
65 | { | |
66 | return sscanf(string, "%u", &value) == 1; | |
67 | } | |
68 | ||
69 | static bool parse(const char* string, double& value) | |
70 | { | |
71 | return sscanf(string, "%lf", &value) == 1; | |
72 | } | |
73 | ||
93a37866 A |
74 | static bool parse(const char* string, OptionRange& value) |
75 | { | |
76 | return value.init(string); | |
77 | } | |
78 | ||
79 | template<typename T> | |
80 | void overrideOptionWithHeuristic(T& variable, const char* name) | |
6fe7ccc8 | 81 | { |
93a37866 | 82 | #if !OS(WINCE) |
6fe7ccc8 | 83 | const char* stringValue = getenv(name); |
93a37866 | 84 | if (!stringValue) |
6fe7ccc8 | 85 | return; |
6fe7ccc8 A |
86 | |
87 | if (parse(stringValue, variable)) | |
88 | return; | |
89 | ||
90 | fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue); | |
93a37866 | 91 | #endif |
6fe7ccc8 A |
92 | } |
93 | ||
93a37866 A |
94 | static unsigned computeNumberOfGCMarkers(int maxNumberOfGCMarkers) |
95 | { | |
96 | int cpusToUse = 1; | |
97 | ||
98 | #if ENABLE(PARALLEL_GC) | |
99 | cpusToUse = std::min(WTF::numberOfProcessorCores(), maxNumberOfGCMarkers); | |
100 | ||
101 | // Be paranoid, it is the OS we're dealing with, after all. | |
102 | ASSERT(cpusToUse >= 1); | |
103 | if (cpusToUse < 1) | |
104 | cpusToUse = 1; | |
6fe7ccc8 | 105 | #else |
93a37866 | 106 | UNUSED_PARAM(maxNumberOfGCMarkers); |
6fe7ccc8 A |
107 | #endif |
108 | ||
93a37866 A |
109 | return cpusToUse; |
110 | } | |
111 | ||
112 | bool OptionRange::init(const char* rangeString) | |
6fe7ccc8 | 113 | { |
93a37866 A |
114 | // rangeString should be in the form of [!]<low>[:<high>] |
115 | // where low and high are unsigned | |
6fe7ccc8 | 116 | |
93a37866 | 117 | bool invert = false; |
6fe7ccc8 | 118 | |
93a37866 A |
119 | if (m_state > Uninitialized) |
120 | return true; | |
6fe7ccc8 | 121 | |
93a37866 A |
122 | if (!rangeString) { |
123 | m_state = InitError; | |
124 | return false; | |
125 | } | |
6fe7ccc8 | 126 | |
93a37866 | 127 | m_rangeString = rangeString; |
6fe7ccc8 | 128 | |
93a37866 A |
129 | if (*rangeString == '!') { |
130 | invert = true; | |
131 | rangeString++; | |
132 | } | |
6fe7ccc8 | 133 | |
93a37866 | 134 | int scanResult = sscanf(rangeString, " %u:%u", &m_lowLimit, &m_highLimit); |
6fe7ccc8 | 135 | |
93a37866 A |
136 | if (!scanResult || scanResult == EOF) { |
137 | m_state = InitError; | |
138 | return false; | |
139 | } | |
6fe7ccc8 | 140 | |
93a37866 A |
141 | if (scanResult == 1) |
142 | m_highLimit = m_lowLimit; | |
143 | ||
144 | if (m_lowLimit > m_highLimit) { | |
145 | m_state = InitError; | |
146 | return false; | |
147 | } | |
148 | ||
149 | m_state = invert ? Inverted : Normal; | |
150 | ||
151 | return true; | |
152 | } | |
153 | ||
154 | bool OptionRange::isInRange(unsigned count) | |
155 | { | |
156 | if (m_state < Normal) | |
157 | return true; | |
158 | ||
159 | if ((m_lowLimit <= count) && (count <= m_highLimit)) | |
160 | return m_state == Normal ? true : false; | |
161 | ||
162 | return m_state == Normal ? false : true; | |
163 | } | |
164 | ||
165 | Options::Entry Options::s_options[Options::numberOfOptions]; | |
166 | ||
167 | // Realize the names for each of the options: | |
168 | const Options::EntryInfo Options::s_optionsInfo[Options::numberOfOptions] = { | |
169 | #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ | |
170 | { #name_, Options::type_##Type }, | |
171 | JSC_OPTIONS(FOR_EACH_OPTION) | |
172 | #undef FOR_EACH_OPTION | |
173 | }; | |
174 | ||
175 | void Options::initialize() | |
176 | { | |
177 | // Initialize each of the options with their default values: | |
178 | #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ | |
179 | name_() = defaultValue_; | |
180 | JSC_OPTIONS(FOR_EACH_OPTION) | |
181 | #undef FOR_EACH_OPTION | |
182 | ||
183 | #if USE(CF) || OS(UNIX) | |
184 | objectsAreImmortal() = !!getenv("JSImmortalZombieEnabled"); | |
185 | useZombieMode() = !!getenv("JSImmortalZombieEnabled") || !!getenv("JSZombieEnabled"); | |
186 | ||
187 | gcMaxHeapSize() = getenv("GCMaxHeapSize") ? HeapStatistics::parseMemoryAmount(getenv("GCMaxHeapSize")) : 0; | |
188 | recordGCPauseTimes() = !!getenv("JSRecordGCPauseTimes"); | |
189 | logHeapStatisticsAtExit() = gcMaxHeapSize() || recordGCPauseTimes(); | |
6fe7ccc8 | 190 | #endif |
6fe7ccc8 | 191 | |
93a37866 A |
192 | // Allow environment vars to override options if applicable. |
193 | // The evn var should be the name of the option prefixed with | |
194 | // "JSC_". | |
195 | #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ | |
196 | overrideOptionWithHeuristic(name_(), "JSC_" #name_); | |
197 | JSC_OPTIONS(FOR_EACH_OPTION) | |
198 | #undef FOR_EACH_OPTION | |
199 | ||
200 | #if 0 | |
201 | ; // Deconfuse editors that do auto indentation | |
202 | #endif | |
6fe7ccc8 | 203 | |
93a37866 A |
204 | #if !ENABLE(JIT) |
205 | useJIT() = false; | |
206 | useDFGJIT() = false; | |
207 | #endif | |
208 | #if !ENABLE(YARR_JIT) | |
209 | useRegExpJIT() = false; | |
210 | #endif | |
211 | ||
212 | // Do range checks where needed and make corrections to the options: | |
213 | ASSERT(thresholdForOptimizeAfterLongWarmUp() >= thresholdForOptimizeAfterWarmUp()); | |
214 | ASSERT(thresholdForOptimizeAfterWarmUp() >= thresholdForOptimizeSoon()); | |
215 | ASSERT(thresholdForOptimizeAfterWarmUp() >= 0); | |
216 | ||
6fe7ccc8 A |
217 | // Compute the maximum value of the reoptimization retry counter. This is simply |
218 | // the largest value at which we don't overflow the execute counter, when using it | |
219 | // to left-shift the execution counter by this amount. Currently the value ends | |
220 | // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles | |
221 | // total on a 32-bit processor. | |
93a37866 A |
222 | reoptimizationRetryCounterMax() = 0; |
223 | while ((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << (reoptimizationRetryCounterMax() + 1)) <= static_cast<int64_t>(std::numeric_limits<int32>::max())) | |
224 | reoptimizationRetryCounterMax()++; | |
225 | ||
226 | ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) > 0); | |
227 | ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp()) << reoptimizationRetryCounterMax()) <= static_cast<int64_t>(std::numeric_limits<int32>::max())); | |
228 | } | |
229 | ||
230 | // Parses a single command line option in the format "<optionName>=<value>" | |
231 | // (no spaces allowed) and set the specified option if appropriate. | |
232 | bool Options::setOption(const char* arg) | |
233 | { | |
234 | // arg should look like this: | |
235 | // <jscOptionName>=<appropriate value> | |
236 | const char* equalStr = strchr(arg, '='); | |
237 | if (!equalStr) | |
238 | return false; | |
239 | ||
240 | const char* valueStr = equalStr + 1; | |
241 | ||
242 | // For each option, check if the specify arg is a match. If so, set the arg | |
243 | // if the value makes sense. Otherwise, move on to checking the next option. | |
244 | #define FOR_EACH_OPTION(type_, name_, defaultValue_) \ | |
245 | if (!strncmp(arg, #name_, equalStr - arg)) { \ | |
246 | type_ value; \ | |
247 | value = 0; \ | |
248 | bool success = parse(valueStr, value); \ | |
249 | if (success) { \ | |
250 | name_() = value; \ | |
251 | return true; \ | |
252 | } \ | |
253 | return false; \ | |
254 | } | |
255 | ||
256 | JSC_OPTIONS(FOR_EACH_OPTION) | |
257 | #undef FOR_EACH_OPTION | |
258 | ||
259 | return false; // No option matched. | |
6fe7ccc8 A |
260 | } |
261 | ||
93a37866 A |
262 | void Options::dumpAllOptions(FILE* stream) |
263 | { | |
264 | fprintf(stream, "JSC runtime options:\n"); | |
265 | for (int id = 0; id < numberOfOptions; id++) | |
266 | dumpOption(static_cast<OptionID>(id), stream, " ", "\n"); | |
267 | } | |
268 | ||
269 | void Options::dumpOption(OptionID id, FILE* stream, const char* header, const char* footer) | |
270 | { | |
271 | if (id >= numberOfOptions) | |
272 | return; // Illegal option. | |
273 | ||
274 | fprintf(stream, "%s%s: ", header, s_optionsInfo[id].name); | |
275 | switch (s_optionsInfo[id].type) { | |
276 | case boolType: | |
277 | fprintf(stream, "%s", s_options[id].u.boolVal?"true":"false"); | |
278 | break; | |
279 | case unsignedType: | |
280 | fprintf(stream, "%u", s_options[id].u.unsignedVal); | |
281 | break; | |
282 | case doubleType: | |
283 | fprintf(stream, "%lf", s_options[id].u.doubleVal); | |
284 | break; | |
285 | case int32Type: | |
286 | fprintf(stream, "%d", s_options[id].u.int32Val); | |
287 | break; | |
288 | case optionRangeType: | |
289 | fprintf(stream, "%s", s_options[id].u.optionRangeVal.rangeString()); | |
290 | break; | |
291 | } | |
292 | fprintf(stream, "%s", footer); | |
293 | } | |
6fe7ccc8 | 294 | |
93a37866 | 295 | } // namespace JSC |
6fe7ccc8 | 296 |