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 #ifndef jit_ICState_h 8 #define jit_ICState_h 9 10 #include "jit/JitOptions.h" 11 12 namespace js { 13 namespace jit { 14 15 // ICState stores information about a Baseline or Ion IC. 16 class ICState { 17 public: 18 // When we attach the maximum number of stubs, we discard all stubs and 19 // transition the IC to Megamorphic to attach stubs that are more generic 20 // (handle more cases). If we again attach the maximum number of stubs, we 21 // transition to Generic and (depending on the IC) will either attach a 22 // single stub that handles everything or stop attaching new stubs. 23 // 24 // We also transition to Generic when we repeatedly fail to attach a stub, 25 // to avoid wasting time trying. 26 enum class Mode : uint8_t { Specialized = 0, Megamorphic, Generic }; 27 28 private: 29 Mode mode_; 30 31 // Number of optimized stubs currently attached to this IC. 32 uint8_t numOptimizedStubs_; 33 34 // Number of times we failed to attach a stub. 35 uint8_t numFailures_; 36 37 static const size_t MaxOptimizedStubs = 6; 38 transition(Mode mode)39 void transition(Mode mode) { 40 MOZ_ASSERT(mode > mode_); 41 mode_ = mode; 42 numFailures_ = 0; 43 } 44 maxFailures()45 MOZ_ALWAYS_INLINE size_t maxFailures() const { 46 // Allow more failures if we attached stubs. 47 static_assert(MaxOptimizedStubs == 6, 48 "numFailures_/maxFailures should fit in uint8_t"); 49 size_t res = 5 + size_t(40) * numOptimizedStubs_; 50 MOZ_ASSERT(res <= UINT8_MAX, "numFailures_ should not overflow"); 51 return res; 52 } 53 54 public: ICState()55 ICState() { reset(); } 56 mode()57 Mode mode() const { return mode_; } numOptimizedStubs()58 size_t numOptimizedStubs() const { return numOptimizedStubs_; } hasFailures()59 bool hasFailures() const { return (numFailures_ != 0); } 60 canAttachStub()61 MOZ_ALWAYS_INLINE bool canAttachStub() const { 62 // Note: we cannot assert that numOptimizedStubs_ <= MaxOptimizedStubs 63 // because old-style baseline ICs may attach more stubs than 64 // MaxOptimizedStubs allows. 65 if (mode_ == Mode::Generic || JitOptions.disableCacheIR) { 66 return false; 67 } 68 return true; 69 } 70 71 // If this returns true, we transitioned to a new mode and the caller 72 // should discard all stubs. maybeTransition()73 MOZ_MUST_USE MOZ_ALWAYS_INLINE bool maybeTransition() { 74 // Note: we cannot assert that numOptimizedStubs_ <= MaxOptimizedStubs 75 // because old-style baseline ICs may attach more stubs than 76 // MaxOptimizedStubs allows. 77 if (mode_ == Mode::Generic) { 78 return false; 79 } 80 if (numOptimizedStubs_ < MaxOptimizedStubs && 81 numFailures_ < maxFailures()) { 82 return false; 83 } 84 if (numFailures_ == maxFailures() || mode_ == Mode::Megamorphic) { 85 transition(Mode::Generic); 86 return true; 87 } 88 MOZ_ASSERT(mode_ == Mode::Specialized); 89 transition(Mode::Megamorphic); 90 return true; 91 } reset()92 void reset() { 93 mode_ = Mode::Specialized; 94 numOptimizedStubs_ = 0; 95 numFailures_ = 0; 96 } trackAttached()97 void trackAttached() { 98 // We'd like to assert numOptimizedStubs_ < MaxOptimizedStubs, but 99 // since this code is also used for non-CacheIR Baseline stubs, assert 100 // < 16 for now. Note that we do have the stronger assert in other 101 // methods, because they are only used by CacheIR ICs. 102 MOZ_ASSERT(numOptimizedStubs_ < 16); 103 numOptimizedStubs_++; 104 // As a heuristic, reduce the failure count after each successful attach 105 // to delay hitting Generic mode. Reset to 1 instead of 0 so that 106 // BaselineInspector can distinguish no-failures from rare-failures. 107 numFailures_ = std::min(numFailures_, static_cast<uint8_t>(1)); 108 } trackNotAttached()109 void trackNotAttached() { 110 // Note: we can't assert numFailures_ < maxFailures() because 111 // maxFailures() depends on numOptimizedStubs_ and it's possible a 112 // GC discarded stubs before we got here. 113 numFailures_++; 114 MOZ_ASSERT(numFailures_ > 0, "numFailures_ should not overflow"); 115 } trackUnlinkedStub()116 void trackUnlinkedStub() { 117 MOZ_ASSERT(numOptimizedStubs_ > 0); 118 numOptimizedStubs_--; 119 } trackUnlinkedAllStubs()120 void trackUnlinkedAllStubs() { numOptimizedStubs_ = 0; } 121 }; 122 123 } // namespace jit 124 } // namespace js 125 126 #endif /* jit_ICState_h */ 127