JitOptions.cpp (17617B)
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/. */ 6 7 #include "jit/JitOptions.h" 8 9 #include <cstdlib> 10 #include <type_traits> 11 12 #include "vm/JSScript.h" 13 14 using namespace js; 15 using namespace js::jit; 16 17 using mozilla::Maybe; 18 19 namespace js { 20 namespace jit { 21 22 MOZ_RUNINIT DefaultJitOptions JitOptions; 23 24 static void Warn(const char* env, const char* value) { 25 fprintf(stderr, "Warning: I didn't understand %s=\"%s\"\n", env, value); 26 } 27 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); 33 } 34 return mozilla::Nothing(); 35 } 36 37 template <typename T> 38 T overrideDefault(const char* param, T dflt) { 39 char* str = getenv(param); 40 if (!str) { 41 return dflt; 42 } 43 if constexpr (std::is_same_v<T, bool>) { 44 if (strcmp(str, "true") == 0 || strcmp(str, "yes") == 0) { 45 return true; 46 } 47 if (strcmp(str, "false") == 0 || strcmp(str, "no") == 0) { 48 return false; 49 } 50 Warn(param, str); 51 } else { 52 Maybe<int> value = ParseInt(str); 53 if (value.isSome()) { 54 return value.ref(); 55 } 56 Warn(param, str); 57 } 58 return dflt; 59 } 60 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); 67 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 73 74 // Whether to enable extra code to perform dynamic validation of 75 // RangeAnalysis results. 76 SET_DEFAULT(checkRangeAnalysis, false); 77 78 // Toggles whether Alignment Mask Analysis is globally disabled. 79 SET_DEFAULT(disableAma, false); 80 81 // Toggles whether Effective Address Analysis is globally disabled. 82 SET_DEFAULT(disableEaa, false); 83 84 // Toggles whether Edge Case Analysis is gobally disabled. 85 SET_DEFAULT(disableEdgeCaseAnalysis, false); 86 87 // Toggle whether global value numbering is globally disabled. 88 SET_DEFAULT(disableGvn, false); 89 90 // Toggles whether inlining is globally disabled. 91 SET_DEFAULT(disableInlining, false); 92 93 // Toggles whether loop invariant code motion is globally disabled. 94 SET_DEFAULT(disableLicm, false); 95 96 // Toggle whether branch pruning is globally disabled. 97 SET_DEFAULT(disablePruning, false); 98 99 // Toggles whether the iterator indices optimization is globally disabled. 100 SET_DEFAULT(disableIteratorIndices, false); 101 102 // Toggles whether instruction reordering is globally disabled. 103 SET_DEFAULT(disableInstructionReordering, false); 104 105 // Toggles whether atomizing loads used as property keys is globally disabled. 106 SET_DEFAULT(disableMarkLoadsUsedAsPropertyKeys, false); 107 108 // Toggles whether Range Analysis is globally disabled. 109 SET_DEFAULT(disableRangeAnalysis, false); 110 111 // Toggles wheter Recover instructions is globally disabled. 112 SET_DEFAULT(disableRecoverIns, false); 113 114 // Toggle whether eager scalar replacement is globally disabled. 115 SET_DEFAULT(disableScalarReplacement, false); 116 117 // Toggles whether CacheIR stubs are used. 118 SET_DEFAULT(disableCacheIR, false); 119 120 // Toggles whether stubs are folded. 121 SET_DEFAULT(disableStubFolding, false); 122 123 // Toggles whether stubs with different offsets in Loads or Stores are folded. 124 SET_DEFAULT(disableStubFoldingLoadsAndStores, false); 125 126 // Toggles whether sink code motion is globally disabled. 127 SET_DEFAULT(disableSink, true); 128 129 // Toggles whether redundant shape guard elimination is globally disabled. 130 SET_DEFAULT(disableRedundantShapeGuards, false); 131 132 // Toggles whether redundant GC barrier elimination is globally disabled. 133 SET_DEFAULT(disableRedundantGCBarriers, false); 134 135 // Toggles whether we verify that we don't recompile with the same CacheIR. 136 SET_DEFAULT(disableBailoutLoopCheck, false); 137 138 // Whether the Baseline Interpreter is enabled. 139 SET_DEFAULT(baselineInterpreter, true); 140 141 // Whether replacing Object.keys with NativeIterators is globally disabled. 142 SET_DEFAULT(disableObjectKeysScalarReplacement, false); 143 144 #ifdef ENABLE_PORTABLE_BASELINE_INTERP 145 // Whether the Portable Baseline Interpreter is enabled. 146 SET_DEFAULT(portableBaselineInterpreter, false); 147 #endif 148 149 #ifdef ENABLE_PORTABLE_BASELINE_INTERP_FORCE 150 SET_DEFAULT(portableBaselineInterpreter, true); 151 SET_DEFAULT(portableBaselineInterpreterWarmUpThreshold, 0); 152 #endif 153 154 // emitInterpreterEntryTrampoline and enableICFramePointers are used in 155 // combination with perf jitdump profiling. The first will enable 156 // trampolines for interpreter and baseline interpreter frames to 157 // identify which function is being executed, and the latter enables 158 // frame pointers for IC stubs. They are both enabled by default 159 // when the |IONPERF| environment variable is set. 160 bool perfEnabled = !!getenv("IONPERF"); 161 SET_DEFAULT(emitInterpreterEntryTrampoline, perfEnabled); 162 SET_DEFAULT(enableICFramePointers, perfEnabled); 163 164 // Whether the Baseline JIT is enabled. 165 SET_DEFAULT(baselineJit, true); 166 167 // Whether the IonMonkey JIT is enabled. 168 SET_DEFAULT(ion, true); 169 170 // Whether the IonMonkey and Baseline JITs are enabled for Trusted Principals. 171 // (Ignored if ion or baselineJit is set to true.) 172 SET_DEFAULT(jitForTrustedPrincipals, false); 173 174 // Whether the RegExp JIT is enabled. 175 SET_DEFAULT(nativeRegExp, true); 176 177 // Whether offthread baseline compilation should be batched. 178 SET_DEFAULT(baselineBatching, false); 179 180 // Whether Warp should use ICs instead of transpiling Baseline CacheIR. 181 SET_DEFAULT(forceInlineCaches, false); 182 183 // Whether all ICs should be initialized as megamorphic ICs. 184 SET_DEFAULT(forceMegamorphicICs, false); 185 186 // Toggles whether large scripts are rejected. 187 SET_DEFAULT(limitScriptSize, true); 188 189 // Toggles whether functions may be entered at loop headers. 190 SET_DEFAULT(osr, true); 191 192 // Whether the JIT backend (used by JITs, Wasm, Baseline Interpreter) has been 193 // disabled for this process. See JS::DisableJitBackend. 194 SET_DEFAULT(disableJitBackend, false); 195 196 // Whether to enable extra code to perform dynamic validations. 197 SET_DEFAULT(runExtraChecks, false); 198 199 #ifdef ENABLE_JS_AOT_ICS 200 SET_DEFAULT(enableAOTICs, false); 201 SET_DEFAULT(enableAOTICEnforce, false); 202 #endif 203 204 #ifdef ENABLE_JS_AOT_ICS_FORCE 205 SET_DEFAULT(enableAOTICs, true); 206 #endif 207 208 #ifdef ENABLE_JS_AOT_ICS_ENFORCE 209 SET_DEFAULT(enableAOTICs, true); 210 SET_DEFAULT(enableAOTICEnforce, true); 211 #endif 212 213 // How many invocations or loop iterations are needed before functions 214 // enter the Baseline Interpreter. 215 SET_DEFAULT(baselineInterpreterWarmUpThreshold, 10); 216 217 #ifdef ENABLE_PORTABLE_BASELINE_INTERP 218 // How many invocations are needed before functions enter the 219 // Portable Baseline Interpreter. 220 SET_DEFAULT(portableBaselineInterpreterWarmUpThreshold, 10); 221 #endif 222 223 // How many invocations or loop iterations are needed before functions 224 // are compiled with the baseline compiler. 225 // Duplicated in all.js - ensure both match. 226 SET_DEFAULT(baselineJitWarmUpThreshold, 100); 227 228 // How many scripts can be queued up for offthread baseline compilation 229 // before they are dispatched. 230 SET_DEFAULT(baselineQueueCapacity, 8); 231 232 // Disable eager baseline jit hints 233 SET_DEFAULT(disableJitHints, false); 234 235 // How many invocations or loop iterations are needed before functions 236 // are considered for trial inlining. 237 SET_DEFAULT(trialInliningWarmUpThreshold, 500); 238 239 // The initial warm-up count for ICScripts created by trial inlining. 240 // 241 // Note: the difference between trialInliningInitialWarmUpCount and 242 // trialInliningWarmUpThreshold must be: 243 // 244 // * Small enough to allow inlining multiple levels deep before the outer 245 // script reaches its normalIonWarmUpThreshold. 246 // 247 // * Greater than inliningEntryThreshold or no scripts can be inlined. 248 SET_DEFAULT(trialInliningInitialWarmUpCount, 250); 249 250 // How many invocations or loop iterations are needed before functions 251 // are compiled with the Ion compiler at OptimizationLevel::Normal. 252 // Duplicated in all.js - ensure both match. 253 SET_DEFAULT(normalIonWarmUpThreshold, 1500); 254 255 // How many invocations are needed before regexps are compiled to 256 // native code. 257 SET_DEFAULT(regexpWarmUpThreshold, 10); 258 259 // Number of exception bailouts (resuming into catch/finally block) before 260 // we invalidate and forbid Ion compilation. 261 SET_DEFAULT(exceptionBailoutThreshold, 10); 262 263 // Number of bailouts without invalidation before we set 264 // JSScript::hadFrequentBailouts and invalidate. 265 // Duplicated in all.js - ensure both match. 266 SET_DEFAULT(frequentBailoutThreshold, 10); 267 268 // Whether to run all debug checks in debug builds. 269 // Disabling might make it more enjoyable to run JS in debug builds. 270 SET_DEFAULT(fullDebugChecks, true); 271 272 // How many actual arguments are accepted on the C stack. 273 SET_DEFAULT(maxStackArgs, 20'000); 274 275 // How many times we will try to enter a script via OSR before 276 // invalidating the script. 277 SET_DEFAULT(osrPcMismatchesBeforeRecompile, 6000); 278 279 // The bytecode length limit for small function. 280 SET_DEFAULT(smallFunctionMaxBytecodeLength, 140); 281 282 // The minimum entry count for an IC stub before it can be trial-inlined. 283 SET_DEFAULT(inliningEntryThreshold, 100); 284 285 // An artificial testing limit for the maximum supported offset of 286 // pc-relative jump and call instructions. 287 SET_DEFAULT(jumpThreshold, UINT32_MAX); 288 289 // Branch pruning heuristic is based on a scoring system, which is look at 290 // different metrics and provide a score. The score is computed as a 291 // projection where each factor defines the weight of each metric. Then this 292 // score is compared against a threshold to prevent a branch from being 293 // removed. 294 SET_DEFAULT(branchPruningHitCountFactor, 1); 295 SET_DEFAULT(branchPruningInstFactor, 10); 296 SET_DEFAULT(branchPruningBlockSpanFactor, 100); 297 SET_DEFAULT(branchPruningEffectfulInstFactor, 3500); 298 SET_DEFAULT(branchPruningThreshold, 4000); 299 300 // Limits on bytecode length and number of locals/arguments for Ion 301 // compilation. There are different (lower) limits for when off-thread Ion 302 // compilation isn't available. 303 SET_DEFAULT(ionMaxScriptSize, 100 * 1000); 304 SET_DEFAULT(ionMaxScriptSizeMainThread, 2 * 1000); 305 SET_DEFAULT(ionMaxLocalsAndArgs, 10 * 1000); 306 SET_DEFAULT(ionMaxLocalsAndArgsMainThread, 256); 307 308 #if defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONG64) || \ 309 defined(JS_CODEGEN_RISCV64) 310 SET_DEFAULT(spectreIndexMasking, false); 311 SET_DEFAULT(spectreObjectMitigations, false); 312 SET_DEFAULT(spectreStringMitigations, false); 313 SET_DEFAULT(spectreValueMasking, false); 314 SET_DEFAULT(spectreJitToCxxCalls, false); 315 #else 316 SET_DEFAULT(spectreIndexMasking, true); 317 SET_DEFAULT(spectreObjectMitigations, true); 318 SET_DEFAULT(spectreStringMitigations, true); 319 SET_DEFAULT(spectreValueMasking, true); 320 SET_DEFAULT(spectreJitToCxxCalls, false); 321 #endif 322 323 // Whether the W^X policy is enforced to mark JIT code pages as either 324 // writable or executable but never both at the same time. On Apple Silicon 325 // this must always be false because we use pthread_jit_write_protect_np. 326 #ifdef JS_USE_APPLE_FAST_WX 327 SET_DEFAULT(writeProtectCode, false); 328 #else 329 SET_DEFAULT(writeProtectCode, true); 330 #endif 331 332 // This is set to its actual value in InitializeJit. 333 SET_DEFAULT(supportsUnalignedAccesses, false); 334 335 // To access local (non-argument) slots, it's more efficient to use the frame 336 // pointer (FP) instead of the stack pointer (SP) as base register on x86 and 337 // x64 (because instructions are one byte shorter, for example). 338 // 339 // However, because this requires a negative offset from FP, on ARM64 it can 340 // be more efficient to use SP-relative addresses for larger stack frames 341 // because the range for load/store immediate offsets is [-256, 4095] and 342 // offsets outside this range will require an extra instruction. 343 // 344 // We default to FP-relative addresses on x86/x64 and SP-relative on other 345 // platforms, but to improve fuzzing we allow changing this in the shell: 346 // 347 // setJitCompilerOption("base-reg-for-locals", N); // 0 for SP, 1 for FP 348 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) 349 baseRegForLocals = BaseRegForAddress::FP; 350 #else 351 baseRegForLocals = BaseRegForAddress::SP; 352 #endif 353 354 // Toggles the optimization whereby offsets are folded into loads and not 355 // included in the bounds check. 356 SET_DEFAULT(wasmFoldOffsets, true); 357 358 // Controls whether two-tiered compilation should be requested when 359 // compiling a new wasm module, independently of other heuristics, and 360 // should be delayed to test both baseline and ion paths in compiled code, 361 // as well as the transition from one tier to the other. 362 SET_DEFAULT(wasmDelayTier2, false); 363 364 // Until which wasm bytecode size should we accumulate functions, in order 365 // to compile efficiently on helper threads. Baseline code compiles much 366 // faster than Ion code so use scaled thresholds (see also bug 1320374 367 // and bug 1930875). Ion compilation can use a lot of memory, so having a 368 // low threshold here (1100) helps avoid OOMs in the per-task pool allocators. 369 SET_DEFAULT(wasmBatchBaselineThreshold, 25000); 370 SET_DEFAULT(wasmBatchIonThreshold, 1100); 371 372 // Controls how much assertion checking code is emitted 373 SET_DEFAULT(lessDebugCode, false); 374 375 SET_DEFAULT(onlyInlineSelfHosted, false); 376 377 SET_DEFAULT(enableWasmJitExit, true); 378 SET_DEFAULT(enableWasmJitEntry, true); 379 SET_DEFAULT(enableWasmIonFastCalls, true); 380 #ifdef WASM_CODEGEN_DEBUG 381 SET_DEFAULT(enableWasmImportCallSpew, false); 382 SET_DEFAULT(enableWasmFuncCallSpew, false); 383 #endif 384 385 // This is used to control whether regexps tier up from interpreted to 386 // compiled. We control this with --no-native-regexp and 387 // --regexp-warmup-threshold. 388 SET_DEFAULT(regexp_tier_up, true); 389 390 // Dumps a representation of parsed regexps to stderr 391 SET_DEFAULT(trace_regexp_parser, false); 392 // Dumps the calls made to the regexp assembler to stderr 393 SET_DEFAULT(trace_regexp_assembler, false); 394 // Dumps the bytecodes interpreted by the regexp engine to stderr 395 SET_DEFAULT(trace_regexp_bytecodes, false); 396 // Dumps the changes made by the regexp peephole optimizer to stderr 397 SET_DEFAULT(trace_regexp_peephole_optimization, false); 398 399 // ***** Irregexp shim flags ***** 400 401 // Whether the stage 3 regexp modifiers proposal is enabled. 402 SET_DEFAULT(js_regexp_modifiers, true); 403 // Whether the stage 3 duplicate named capture groups proposal is enabled. 404 SET_DEFAULT(js_regexp_duplicate_named_groups, true); 405 // V8 uses this for differential fuzzing to handle stack overflows. 406 // We address the same problem in StackLimitCheck::HasOverflowed. 407 SET_DEFAULT(correctness_fuzzer_suppressions, false); 408 // Instead of using a flag for this, we provide an implementation of 409 // CanReadUnaligned in SMRegExpMacroAssembler. 410 SET_DEFAULT(enable_regexp_unaligned_accesses, false); 411 // This is used to guard an old prototype implementation of possessive 412 // quantifiers, which never got past the point of adding parser support. 413 SET_DEFAULT(regexp_possessive_quantifier, false); 414 // These affect the default level of optimization. We can still turn 415 // optimization off on a case-by-case basis in CompilePattern - for 416 // example, if a regexp is too long - so we might as well turn these 417 // flags on unconditionally. 418 SET_DEFAULT(regexp_optimization, true); 419 #if MOZ_BIG_ENDIAN() 420 // peephole optimization not supported on big endian 421 SET_DEFAULT(regexp_peephole_optimization, false); 422 #else 423 SET_DEFAULT(regexp_peephole_optimization, true); 424 #endif 425 } 426 427 bool DefaultJitOptions::isSmallFunction(JSScript* script) const { 428 return script->length() <= smallFunctionMaxBytecodeLength; 429 } 430 431 void DefaultJitOptions::enableGvn(bool enable) { disableGvn = !enable; } 432 433 #ifdef ENABLE_PORTABLE_BASELINE_INTERP 434 void DefaultJitOptions::setEagerPortableBaselineInterpreter() { 435 portableBaselineInterpreterWarmUpThreshold = 0; 436 } 437 #endif 438 439 void DefaultJitOptions::setEagerBaselineCompilation() { 440 baselineInterpreterWarmUpThreshold = 0; 441 baselineJitWarmUpThreshold = 0; 442 regexpWarmUpThreshold = 0; 443 } 444 445 void DefaultJitOptions::setEagerIonCompilation() { 446 setEagerBaselineCompilation(); 447 normalIonWarmUpThreshold = 0; 448 } 449 450 void DefaultJitOptions::setFastWarmUp() { 451 baselineInterpreterWarmUpThreshold = 4; 452 baselineJitWarmUpThreshold = 10; 453 trialInliningWarmUpThreshold = 14; 454 trialInliningInitialWarmUpCount = 12; 455 normalIonWarmUpThreshold = 30; 456 457 inliningEntryThreshold = 2; 458 smallFunctionMaxBytecodeLength = 2000; 459 } 460 461 void DefaultJitOptions::setNormalIonWarmUpThreshold(uint32_t warmUpThreshold) { 462 normalIonWarmUpThreshold = warmUpThreshold; 463 } 464 465 void DefaultJitOptions::resetNormalIonWarmUpThreshold() { 466 jit::DefaultJitOptions defaultValues; 467 setNormalIonWarmUpThreshold(defaultValues.normalIonWarmUpThreshold); 468 } 469 470 void DefaultJitOptions::maybeSetWriteProtectCode(bool val) { 471 #ifdef JS_USE_APPLE_FAST_WX 472 // On Apple Silicon we always use pthread_jit_write_protect_np, or 473 // be_memory_inline_jit_restrict_*. 474 MOZ_ASSERT(!writeProtectCode); 475 #else 476 writeProtectCode = val; 477 #endif 478 } 479 480 } // namespace jit 481 } // namespace js