tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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