/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "jit/IonOptimizationLevels.h" #include "jsscript.h" #include "jit/Ion.h" using namespace js; using namespace js::jit; namespace js { namespace jit { OptimizationLevelInfo IonOptimizations; void OptimizationInfo::initNormalOptimizationInfo() { level_ = OptimizationLevel::Normal; autoTruncate_ = true; eaa_ = true; eagerSimdUnbox_ = true; edgeCaseAnalysis_ = true; eliminateRedundantChecks_ = true; inlineInterpreted_ = true; inlineNative_ = true; licm_ = true; loopUnrolling_ = true; gvn_ = true; rangeAnalysis_ = true; reordering_ = true; sincos_ = true; sink_ = true; registerAllocator_ = RegisterAllocator_Backtracking; inlineMaxBytecodePerCallSiteMainThread_ = 550; inlineMaxBytecodePerCallSiteOffThread_ = 1100; inlineMaxCalleeInlinedBytecodeLength_ = 3550; inlineMaxTotalBytecodeLength_ = 85000; inliningMaxCallerBytecodeLength_ = 1600; maxInlineDepth_ = 3; scalarReplacement_ = true; smallFunctionMaxInlineDepth_ = 10; compilerWarmUpThreshold_ = CompilerWarmupThreshold; compilerSmallFunctionWarmUpThreshold_ = CompilerSmallFunctionWarmupThreshold; inliningWarmUpThresholdFactor_ = 0.125; inliningRecompileThresholdFactor_ = 4; } void OptimizationInfo::initWasmOptimizationInfo() { // The Wasm optimization level // Disables some passes that don't work well with wasm. // Take normal option values for not specified values. initNormalOptimizationInfo(); level_ = OptimizationLevel::Wasm; ama_ = true; autoTruncate_ = false; eagerSimdUnbox_ = false; // wasm has no boxing / unboxing. edgeCaseAnalysis_ = false; eliminateRedundantChecks_ = false; scalarReplacement_ = false; // wasm has no objects. sincos_ = false; sink_ = false; } uint32_t OptimizationInfo::compilerWarmUpThreshold(JSScript* script, jsbytecode* pc) const { MOZ_ASSERT(pc == nullptr || pc == script->code() || JSOp(*pc) == JSOP_LOOPENTRY); if (pc == script->code()) pc = nullptr; uint32_t warmUpThreshold = compilerWarmUpThreshold_; if (JitOptions.forcedDefaultIonWarmUpThreshold.isSome()) warmUpThreshold = JitOptions.forcedDefaultIonWarmUpThreshold.ref(); if (JitOptions.isSmallFunction(script)) { warmUpThreshold = compilerSmallFunctionWarmUpThreshold_; if (JitOptions.forcedDefaultIonSmallFunctionWarmUpThreshold.isSome()) warmUpThreshold = JitOptions.forcedDefaultIonSmallFunctionWarmUpThreshold.ref(); } // If the script is too large to compile on the main thread, we can still // compile it off thread. In these cases, increase the warm-up counter // threshold to improve the compilation's type information and hopefully // avoid later recompilation. if (script->length() > MAX_MAIN_THREAD_SCRIPT_SIZE) warmUpThreshold *= (script->length() / (double) MAX_MAIN_THREAD_SCRIPT_SIZE); uint32_t numLocalsAndArgs = NumLocalsAndArgs(script); if (numLocalsAndArgs > MAX_MAIN_THREAD_LOCALS_AND_ARGS) warmUpThreshold *= (numLocalsAndArgs / (double) MAX_MAIN_THREAD_LOCALS_AND_ARGS); if (!pc || JitOptions.eagerCompilation) return warmUpThreshold; // It's more efficient to enter outer loops, rather than inner loops, via OSR. // To accomplish this, we use a slightly higher threshold for inner loops. // Note that the loop depth is always > 0 so we will prefer non-OSR over OSR. uint32_t loopDepth = LoopEntryDepthHint(pc); MOZ_ASSERT(loopDepth > 0); return warmUpThreshold + loopDepth * 100; } OptimizationLevelInfo::OptimizationLevelInfo() { infos_[OptimizationLevel::Normal].initNormalOptimizationInfo(); infos_[OptimizationLevel::Wasm].initWasmOptimizationInfo(); #ifdef DEBUG OptimizationLevel level = firstLevel(); while (!isLastLevel(level)) { OptimizationLevel next = nextLevel(level); MOZ_ASSERT_IF(level != OptimizationLevel::DontCompile, level < next); level = next; } #endif } OptimizationLevel OptimizationLevelInfo::nextLevel(OptimizationLevel level) const { MOZ_ASSERT(!isLastLevel(level)); switch (level) { case OptimizationLevel::DontCompile: return OptimizationLevel::Normal; case OptimizationLevel::Normal: case OptimizationLevel::Wasm: case OptimizationLevel::Count:; } MOZ_CRASH("Unknown optimization level."); } OptimizationLevel OptimizationLevelInfo::firstLevel() const { return nextLevel(OptimizationLevel::DontCompile); } bool OptimizationLevelInfo::isLastLevel(OptimizationLevel level) const { return level == OptimizationLevel::Normal; } OptimizationLevel OptimizationLevelInfo::levelForScript(JSScript* script, jsbytecode* pc) const { OptimizationLevel prev = OptimizationLevel::DontCompile; while (!isLastLevel(prev)) { OptimizationLevel level = nextLevel(prev); const OptimizationInfo* info = get(level); if (script->getWarmUpCount() < info->compilerWarmUpThreshold(script, pc)) return prev; prev = level; } return prev; } } // namespace jit } // namespace js