michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "jit/IonOptimizationLevels.h" michael@0: michael@0: #include "jsanalyze.h" michael@0: #include "jsscript.h" michael@0: michael@0: using namespace js; michael@0: using namespace js::jit; michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: OptimizationInfos js_IonOptimizations; michael@0: michael@0: void michael@0: OptimizationInfo::initNormalOptimizationInfo() michael@0: { michael@0: level_ = Optimization_Normal; michael@0: michael@0: eaa_ = true; michael@0: edgeCaseAnalysis_ = true; michael@0: eliminateRedundantChecks_ = true; michael@0: inlineInterpreted_ = true; michael@0: inlineNative_ = true; michael@0: gvn_ = true; michael@0: gvnKind_ = GVN_Optimistic; michael@0: licm_ = true; michael@0: uce_ = true; michael@0: rangeAnalysis_ = true; michael@0: registerAllocator_ = RegisterAllocator_LSRA; michael@0: michael@0: inlineMaxTotalBytecodeLength_ = 1000; michael@0: inliningMaxCallerBytecodeLength_ = 10000; michael@0: maxInlineDepth_ = 3; michael@0: smallFunctionMaxInlineDepth_ = 10; michael@0: usesBeforeCompile_ = 1000; michael@0: usesBeforeInliningFactor_ = 0.125; michael@0: } michael@0: michael@0: void michael@0: OptimizationInfo::initAsmjsOptimizationInfo() michael@0: { michael@0: // The AsmJS optimization level michael@0: // Disables some passes that don't work well with asmjs. michael@0: michael@0: // Take normal option values for not specified values. michael@0: initNormalOptimizationInfo(); michael@0: michael@0: level_ = Optimization_AsmJS; michael@0: edgeCaseAnalysis_ = false; michael@0: eliminateRedundantChecks_ = false; michael@0: registerAllocator_ = RegisterAllocator_Backtracking; michael@0: } michael@0: michael@0: uint32_t michael@0: OptimizationInfo::usesBeforeCompile(JSScript *script, jsbytecode *pc) const michael@0: { michael@0: JS_ASSERT(pc == nullptr || pc == script->code() || JSOp(*pc) == JSOP_LOOPENTRY); michael@0: michael@0: if (pc == script->code()) michael@0: pc = nullptr; michael@0: michael@0: uint32_t minUses = usesBeforeCompile_; michael@0: if (js_JitOptions.forceDefaultIonUsesBeforeCompile) michael@0: minUses = js_JitOptions.forcedDefaultIonUsesBeforeCompile; michael@0: michael@0: // If the script is too large to compile on the main thread, we can still michael@0: // compile it off thread. In these cases, increase the use count threshold michael@0: // to improve the compilation's type information and hopefully avoid later michael@0: // recompilation. michael@0: michael@0: if (script->length() > MAX_MAIN_THREAD_SCRIPT_SIZE) michael@0: minUses = minUses * (script->length() / (double) MAX_MAIN_THREAD_SCRIPT_SIZE); michael@0: michael@0: uint32_t numLocalsAndArgs = analyze::TotalSlots(script); michael@0: if (numLocalsAndArgs > MAX_MAIN_THREAD_LOCALS_AND_ARGS) michael@0: minUses = minUses * (numLocalsAndArgs / (double) MAX_MAIN_THREAD_LOCALS_AND_ARGS); michael@0: michael@0: if (!pc || js_JitOptions.eagerCompilation) michael@0: return minUses; michael@0: michael@0: // It's more efficient to enter outer loops, rather than inner loops, via OSR. michael@0: // To accomplish this, we use a slightly higher threshold for inner loops. michael@0: // Note that the loop depth is always > 0 so we will prefer non-OSR over OSR. michael@0: uint32_t loopDepth = LoopEntryDepthHint(pc); michael@0: JS_ASSERT(loopDepth > 0); michael@0: return minUses + loopDepth * 100; michael@0: } michael@0: michael@0: OptimizationInfos::OptimizationInfos() michael@0: { michael@0: infos_[Optimization_Normal - 1].initNormalOptimizationInfo(); michael@0: infos_[Optimization_AsmJS - 1].initAsmjsOptimizationInfo(); michael@0: michael@0: #ifdef DEBUG michael@0: OptimizationLevel level = firstLevel(); michael@0: while (!isLastLevel(level)) { michael@0: OptimizationLevel next = nextLevel(level); michael@0: JS_ASSERT(level < next); michael@0: level = next; michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: OptimizationLevel michael@0: OptimizationInfos::nextLevel(OptimizationLevel level) const michael@0: { michael@0: JS_ASSERT(!isLastLevel(level)); michael@0: switch (level) { michael@0: case Optimization_DontCompile: michael@0: return Optimization_Normal; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Unknown optimization level."); michael@0: } michael@0: } michael@0: michael@0: OptimizationLevel michael@0: OptimizationInfos::firstLevel() const michael@0: { michael@0: return nextLevel(Optimization_DontCompile); michael@0: } michael@0: michael@0: bool michael@0: OptimizationInfos::isLastLevel(OptimizationLevel level) const michael@0: { michael@0: return level == Optimization_Normal; michael@0: } michael@0: michael@0: OptimizationLevel michael@0: OptimizationInfos::levelForScript(JSScript *script, jsbytecode *pc) const michael@0: { michael@0: OptimizationLevel prev = Optimization_DontCompile; michael@0: michael@0: while (!isLastLevel(prev)) { michael@0: OptimizationLevel level = nextLevel(prev); michael@0: const OptimizationInfo *info = get(level); michael@0: if (script->getUseCount() < info->usesBeforeCompile(script, pc)) michael@0: return prev; michael@0: michael@0: prev = level; michael@0: } michael@0: michael@0: return prev; michael@0: } michael@0: michael@0: } // namespace jit michael@0: } // namespace js