Bug 1890750 - Part 1: Include NATIVE_JIT_ENTRY in FunctionFlags::HasJitEntryFlags...
[gecko.git] / js / src / jit / JitOptions.cpp
blob053cf868a7d793ecc958eb45cb6fa6d39751dd72
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/JitOptions.h"
9 #include <cstdlib>
10 #include <type_traits>
12 #include "vm/JSScript.h"
14 using namespace js;
15 using namespace js::jit;
17 using mozilla::Maybe;
19 namespace js {
20 namespace jit {
22 DefaultJitOptions JitOptions;
24 static void Warn(const char* env, const char* value) {
25 fprintf(stderr, "Warning: I didn't understand %s=\"%s\"\n", env, value);
28 static Maybe<int> ParseInt(const char* str) {
29 char* endp;
30 int retval = strtol(str, &endp, 0);
31 if (*endp == '\0') {
32 return mozilla::Some(retval);
34 return mozilla::Nothing();
37 template <typename T>
38 T overrideDefault(const char* param, T dflt) {
39 char* str = getenv(param);
40 if (!str) {
41 return dflt;
43 if constexpr (std::is_same_v<T, bool>) {
44 if (strcmp(str, "true") == 0 || strcmp(str, "yes") == 0) {
45 return true;
47 if (strcmp(str, "false") == 0 || strcmp(str, "no") == 0) {
48 return false;
50 Warn(param, str);
51 } else {
52 Maybe<int> value = ParseInt(str);
53 if (value.isSome()) {
54 return value.ref();
56 Warn(param, str);
58 return dflt;
61 #define SET_DEFAULT(var, dflt) var = overrideDefault("JIT_OPTION_" #var, dflt)
62 DefaultJitOptions::DefaultJitOptions() {
63 // Whether to perform expensive graph-consistency DEBUG-only assertions.
64 // It can be useful to disable this to reduce DEBUG-compile time of large
65 // wasm programs.
66 SET_DEFAULT(checkGraphConsistency, true);
68 #ifdef CHECK_OSIPOINT_REGISTERS
69 // Emit extra code to verify live regs at the start of a VM call
70 // are not modified before its OsiPoint.
71 SET_DEFAULT(checkOsiPointRegisters, false);
72 #endif
74 // Whether to enable extra code to perform dynamic validation of
75 // RangeAnalysis results.
76 SET_DEFAULT(checkRangeAnalysis, false);
78 // Toggles whether Alignment Mask Analysis is globally disabled.
79 SET_DEFAULT(disableAma, false);
81 // Toggles whether Effective Address Analysis is globally disabled.
82 SET_DEFAULT(disableEaa, false);
84 // Toggles whether Edge Case Analysis is gobally disabled.
85 SET_DEFAULT(disableEdgeCaseAnalysis, false);
87 // Toggle whether global value numbering is globally disabled.
88 SET_DEFAULT(disableGvn, false);
90 // Toggles whether inlining is globally disabled.
91 SET_DEFAULT(disableInlining, false);
93 // Toggles whether loop invariant code motion is globally disabled.
94 SET_DEFAULT(disableLicm, false);
96 // Toggle whether branch pruning is globally disabled.
97 SET_DEFAULT(disablePruning, false);
99 // Toggles whether the iterator indices optimization is globally disabled.
100 SET_DEFAULT(disableIteratorIndices, false);
102 // Toggles whether instruction reordering is globally disabled.
103 SET_DEFAULT(disableInstructionReordering, false);
105 // Toggles whether atomizing loads used as property keys is globally disabled.
106 SET_DEFAULT(disableMarkLoadsUsedAsPropertyKeys, false);
108 // Toggles whether Range Analysis is globally disabled.
109 SET_DEFAULT(disableRangeAnalysis, false);
111 // Toggles wheter Recover instructions is globally disabled.
112 SET_DEFAULT(disableRecoverIns, false);
114 // Toggle whether eager scalar replacement is globally disabled.
115 SET_DEFAULT(disableScalarReplacement, false);
117 // Toggles whether CacheIR stubs are used.
118 SET_DEFAULT(disableCacheIR, false);
120 // Toggles whether sink code motion is globally disabled.
121 SET_DEFAULT(disableSink, true);
123 // Toggles whether redundant shape guard elimination is globally disabled.
124 SET_DEFAULT(disableRedundantShapeGuards, false);
126 // Toggles whether redundant GC barrier elimination is globally disabled.
127 SET_DEFAULT(disableRedundantGCBarriers, false);
129 // Toggles whether we verify that we don't recompile with the same CacheIR.
130 SET_DEFAULT(disableBailoutLoopCheck, false);
132 // Whether the Baseline Interpreter is enabled.
133 SET_DEFAULT(baselineInterpreter, true);
135 #ifdef ENABLE_PORTABLE_BASELINE_INTERP
136 // Whether the Portable Baseline Interpreter is enabled.
137 SET_DEFAULT(portableBaselineInterpreter, false);
138 #endif
140 #ifdef ENABLE_PORTABLE_BASELINE_INTERP_FORCE
141 SET_DEFAULT(portableBaselineInterpreter, true);
142 SET_DEFAULT(portableBaselineInterpreterWarmUpThreshold, 0);
143 #endif
145 // emitInterpreterEntryTrampoline and enableICFramePointers are used in
146 // combination with perf jitdump profiling. The first will enable
147 // trampolines for interpreter and baseline interpreter frames to
148 // identify which function is being executed, and the latter enables
149 // frame pointers for IC stubs. They are both enabled by default
150 // when the |IONPERF| environment variable is set.
151 bool perfEnabled = !!getenv("IONPERF");
152 SET_DEFAULT(emitInterpreterEntryTrampoline, perfEnabled);
153 SET_DEFAULT(enableICFramePointers, perfEnabled);
155 // Whether the Baseline JIT is enabled.
156 SET_DEFAULT(baselineJit, true);
158 // Whether the IonMonkey JIT is enabled.
159 SET_DEFAULT(ion, true);
161 // Whether the IonMonkey and Baseline JITs are enabled for Trusted Principals.
162 // (Ignored if ion or baselineJit is set to true.)
163 SET_DEFAULT(jitForTrustedPrincipals, false);
165 // Whether the RegExp JIT is enabled.
166 SET_DEFAULT(nativeRegExp, true);
168 // Whether Warp should use ICs instead of transpiling Baseline CacheIR.
169 SET_DEFAULT(forceInlineCaches, false);
171 // Whether all ICs should be initialized as megamorphic ICs.
172 SET_DEFAULT(forceMegamorphicICs, false);
174 // Toggles whether large scripts are rejected.
175 SET_DEFAULT(limitScriptSize, true);
177 // Toggles whether functions may be entered at loop headers.
178 SET_DEFAULT(osr, true);
180 // Whether the JIT backend (used by JITs, Wasm, Baseline Interpreter) has been
181 // disabled for this process. See JS::DisableJitBackend.
182 SET_DEFAULT(disableJitBackend, false);
184 // Whether to enable extra code to perform dynamic validations.
185 SET_DEFAULT(runExtraChecks, false);
187 // How many invocations or loop iterations are needed before functions
188 // enter the Baseline Interpreter.
189 SET_DEFAULT(baselineInterpreterWarmUpThreshold, 10);
191 #ifdef ENABLE_PORTABLE_BASELINE_INTERP
192 // How many invocations are needed before functions enter the
193 // Portable Baseline Interpreter.
194 SET_DEFAULT(portableBaselineInterpreterWarmUpThreshold, 10);
195 #endif
197 // How many invocations or loop iterations are needed before functions
198 // are compiled with the baseline compiler.
199 // Duplicated in all.js - ensure both match.
200 SET_DEFAULT(baselineJitWarmUpThreshold, 100);
202 // Disable eager baseline jit hints
203 SET_DEFAULT(disableJitHints, false);
205 // How many invocations or loop iterations are needed before functions
206 // are considered for trial inlining.
207 SET_DEFAULT(trialInliningWarmUpThreshold, 500);
209 // The initial warm-up count for ICScripts created by trial inlining.
211 // Note: the difference between trialInliningInitialWarmUpCount and
212 // trialInliningWarmUpThreshold must be:
214 // * Small enough to allow inlining multiple levels deep before the outer
215 // script reaches its normalIonWarmUpThreshold.
217 // * Greater than inliningEntryThreshold or no scripts can be inlined.
218 SET_DEFAULT(trialInliningInitialWarmUpCount, 250);
220 // How many invocations or loop iterations are needed before functions
221 // are compiled with the Ion compiler at OptimizationLevel::Normal.
222 // Duplicated in all.js - ensure both match.
223 SET_DEFAULT(normalIonWarmUpThreshold, 1500);
225 // How many invocations are needed before regexps are compiled to
226 // native code.
227 SET_DEFAULT(regexpWarmUpThreshold, 10);
229 // Number of exception bailouts (resuming into catch/finally block) before
230 // we invalidate and forbid Ion compilation.
231 SET_DEFAULT(exceptionBailoutThreshold, 10);
233 // Number of bailouts without invalidation before we set
234 // JSScript::hadFrequentBailouts and invalidate.
235 // Duplicated in all.js - ensure both match.
236 SET_DEFAULT(frequentBailoutThreshold, 10);
238 // Whether to run all debug checks in debug builds.
239 // Disabling might make it more enjoyable to run JS in debug builds.
240 SET_DEFAULT(fullDebugChecks, true);
242 // How many actual arguments are accepted on the C stack.
243 SET_DEFAULT(maxStackArgs, 20'000);
245 // How many times we will try to enter a script via OSR before
246 // invalidating the script.
247 SET_DEFAULT(osrPcMismatchesBeforeRecompile, 6000);
249 // The bytecode length limit for small function.
250 SET_DEFAULT(smallFunctionMaxBytecodeLength, 130);
252 // The minimum entry count for an IC stub before it can be trial-inlined.
253 SET_DEFAULT(inliningEntryThreshold, 100);
255 // An artificial testing limit for the maximum supported offset of
256 // pc-relative jump and call instructions.
257 SET_DEFAULT(jumpThreshold, UINT32_MAX);
259 // Branch pruning heuristic is based on a scoring system, which is look at
260 // different metrics and provide a score. The score is computed as a
261 // projection where each factor defines the weight of each metric. Then this
262 // score is compared against a threshold to prevent a branch from being
263 // removed.
264 SET_DEFAULT(branchPruningHitCountFactor, 1);
265 SET_DEFAULT(branchPruningInstFactor, 10);
266 SET_DEFAULT(branchPruningBlockSpanFactor, 100);
267 SET_DEFAULT(branchPruningEffectfulInstFactor, 3500);
268 SET_DEFAULT(branchPruningThreshold, 4000);
270 // Limits on bytecode length and number of locals/arguments for Ion
271 // compilation. There are different (lower) limits for when off-thread Ion
272 // compilation isn't available.
273 SET_DEFAULT(ionMaxScriptSize, 100 * 1000);
274 SET_DEFAULT(ionMaxScriptSizeMainThread, 2 * 1000);
275 SET_DEFAULT(ionMaxLocalsAndArgs, 10 * 1000);
276 SET_DEFAULT(ionMaxLocalsAndArgsMainThread, 256);
278 // Force the used register allocator instead of letting the optimization
279 // pass decide.
280 const char* forcedRegisterAllocatorEnv = "JIT_OPTION_forcedRegisterAllocator";
281 if (const char* env = getenv(forcedRegisterAllocatorEnv)) {
282 forcedRegisterAllocator = LookupRegisterAllocator(env);
283 if (!forcedRegisterAllocator.isSome()) {
284 Warn(forcedRegisterAllocatorEnv, env);
288 #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
289 defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_RISCV64)
290 SET_DEFAULT(spectreIndexMasking, false);
291 SET_DEFAULT(spectreObjectMitigations, false);
292 SET_DEFAULT(spectreStringMitigations, false);
293 SET_DEFAULT(spectreValueMasking, false);
294 SET_DEFAULT(spectreJitToCxxCalls, false);
295 #else
296 SET_DEFAULT(spectreIndexMasking, true);
297 SET_DEFAULT(spectreObjectMitigations, true);
298 SET_DEFAULT(spectreStringMitigations, true);
299 SET_DEFAULT(spectreValueMasking, true);
300 SET_DEFAULT(spectreJitToCxxCalls, false);
301 #endif
303 // Whether the W^X policy is enforced to mark JIT code pages as either
304 // writable or executable but never both at the same time. On Apple Silicon
305 // this must always be false because we use pthread_jit_write_protect_np.
306 #ifdef JS_USE_APPLE_FAST_WX
307 SET_DEFAULT(writeProtectCode, false);
308 #else
309 SET_DEFAULT(writeProtectCode, true);
310 #endif
312 // This is set to its actual value in InitializeJit.
313 SET_DEFAULT(supportsUnalignedAccesses, false);
315 // To access local (non-argument) slots, it's more efficient to use the frame
316 // pointer (FP) instead of the stack pointer (SP) as base register on x86 and
317 // x64 (because instructions are one byte shorter, for example).
319 // However, because this requires a negative offset from FP, on ARM64 it can
320 // be more efficient to use SP-relative addresses for larger stack frames
321 // because the range for load/store immediate offsets is [-256, 4095] and
322 // offsets outside this range will require an extra instruction.
324 // We default to FP-relative addresses on x86/x64 and SP-relative on other
325 // platforms, but to improve fuzzing we allow changing this in the shell:
327 // setJitCompilerOption("base-reg-for-locals", N); // 0 for SP, 1 for FP
328 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
329 baseRegForLocals = BaseRegForAddress::FP;
330 #else
331 baseRegForLocals = BaseRegForAddress::SP;
332 #endif
334 // Toggles the optimization whereby offsets are folded into loads and not
335 // included in the bounds check.
336 SET_DEFAULT(wasmFoldOffsets, true);
338 // Controls whether two-tiered compilation should be requested when
339 // compiling a new wasm module, independently of other heuristics, and
340 // should be delayed to test both baseline and ion paths in compiled code,
341 // as well as the transition from one tier to the other.
342 SET_DEFAULT(wasmDelayTier2, false);
344 // Until which wasm bytecode size should we accumulate functions, in order
345 // to compile efficiently on helper threads. Baseline code compiles much
346 // faster than Ion code so use scaled thresholds (see also bug 1320374).
347 SET_DEFAULT(wasmBatchBaselineThreshold, 10000);
348 SET_DEFAULT(wasmBatchIonThreshold, 1100);
350 // Controls how much assertion checking code is emitted
351 SET_DEFAULT(lessDebugCode, false);
353 SET_DEFAULT(onlyInlineSelfHosted, false);
355 SET_DEFAULT(enableWasmJitExit, true);
356 SET_DEFAULT(enableWasmJitEntry, true);
357 SET_DEFAULT(enableWasmIonFastCalls, true);
358 #ifdef WASM_CODEGEN_DEBUG
359 SET_DEFAULT(enableWasmImportCallSpew, false);
360 SET_DEFAULT(enableWasmFuncCallSpew, false);
361 #endif
363 // This is used to control whether regexps tier up from interpreted to
364 // compiled. We control this with --no-native-regexp and
365 // --regexp-warmup-threshold.
366 SET_DEFAULT(regexp_tier_up, true);
368 // Dumps a representation of parsed regexps to stderr
369 SET_DEFAULT(trace_regexp_parser, false);
370 // Dumps the calls made to the regexp assembler to stderr
371 SET_DEFAULT(trace_regexp_assembler, false);
372 // Dumps the bytecodes interpreted by the regexp engine to stderr
373 SET_DEFAULT(trace_regexp_bytecodes, false);
374 // Dumps the changes made by the regexp peephole optimizer to stderr
375 SET_DEFAULT(trace_regexp_peephole_optimization, false);
377 // ***** Irregexp shim flags *****
379 // Whether the stage 3 regexp modifiers proposal is enabled.
380 SET_DEFAULT(js_regexp_modifiers, false);
381 // Whether the stage 3 duplicate named capture groups proposal is enabled.
382 SET_DEFAULT(js_regexp_duplicate_named_groups, false);
383 // V8 uses this for differential fuzzing to handle stack overflows.
384 // We address the same problem in StackLimitCheck::HasOverflowed.
385 SET_DEFAULT(correctness_fuzzer_suppressions, false);
386 // Instead of using a flag for this, we provide an implementation of
387 // CanReadUnaligned in SMRegExpMacroAssembler.
388 SET_DEFAULT(enable_regexp_unaligned_accesses, false);
389 // This is used to guard an old prototype implementation of possessive
390 // quantifiers, which never got past the point of adding parser support.
391 SET_DEFAULT(regexp_possessive_quantifier, false);
392 // These affect the default level of optimization. We can still turn
393 // optimization off on a case-by-case basis in CompilePattern - for
394 // example, if a regexp is too long - so we might as well turn these
395 // flags on unconditionally.
396 SET_DEFAULT(regexp_optimization, true);
397 #if MOZ_BIG_ENDIAN()
398 // peephole optimization not supported on big endian
399 SET_DEFAULT(regexp_peephole_optimization, false);
400 #else
401 SET_DEFAULT(regexp_peephole_optimization, true);
402 #endif
405 bool DefaultJitOptions::isSmallFunction(JSScript* script) const {
406 return script->length() <= smallFunctionMaxBytecodeLength;
409 void DefaultJitOptions::enableGvn(bool enable) { disableGvn = !enable; }
411 #ifdef ENABLE_PORTABLE_BASELINE_INTERP
412 void DefaultJitOptions::setEagerPortableBaselineInterpreter() {
413 portableBaselineInterpreterWarmUpThreshold = 0;
415 #endif
417 void DefaultJitOptions::setEagerBaselineCompilation() {
418 baselineInterpreterWarmUpThreshold = 0;
419 baselineJitWarmUpThreshold = 0;
420 regexpWarmUpThreshold = 0;
423 void DefaultJitOptions::setEagerIonCompilation() {
424 setEagerBaselineCompilation();
425 normalIonWarmUpThreshold = 0;
428 void DefaultJitOptions::setFastWarmUp() {
429 baselineInterpreterWarmUpThreshold = 4;
430 baselineJitWarmUpThreshold = 10;
431 trialInliningWarmUpThreshold = 14;
432 trialInliningInitialWarmUpCount = 12;
433 normalIonWarmUpThreshold = 30;
435 inliningEntryThreshold = 2;
436 smallFunctionMaxBytecodeLength = 2000;
439 void DefaultJitOptions::setNormalIonWarmUpThreshold(uint32_t warmUpThreshold) {
440 normalIonWarmUpThreshold = warmUpThreshold;
443 void DefaultJitOptions::resetNormalIonWarmUpThreshold() {
444 jit::DefaultJitOptions defaultValues;
445 setNormalIonWarmUpThreshold(defaultValues.normalIonWarmUpThreshold);
448 void DefaultJitOptions::maybeSetWriteProtectCode(bool val) {
449 #ifdef JS_USE_APPLE_FAST_WX
450 // On Apple Silicon we always use pthread_jit_write_protect_np, or
451 // be_memory_inline_jit_restrict_*.
452 MOZ_ASSERT(!writeProtectCode);
453 #else
454 writeProtectCode = val;
455 #endif
458 } // namespace jit
459 } // namespace js