Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 : {
18 : public:
19 : // When we attach the maximum number of stubs, we discard all stubs and
20 : // transition the IC to Megamorphic to attach stubs that are more generic
21 : // (handle more cases). If we again attach the maximum number of stubs, we
22 : // transition to Generic and (depending on the IC) will either attach a
23 : // single stub that handles everything or stop attaching new stubs.
24 : //
25 : // We also transition to Generic when we repeatedly fail to attach a stub,
26 : // to avoid wasting time trying.
27 : enum class Mode : uint8_t { Specialized = 0, Megamorphic, Generic };
28 :
29 : private:
30 : Mode mode_;
31 :
32 : // Number of optimized stubs currently attached to this IC.
33 : uint8_t numOptimizedStubs_;
34 :
35 : // Number of times we failed to attach a stub.
36 : uint8_t numFailures_;
37 :
38 : // This is only used for shared Baseline ICs and stored here to save space.
39 : bool invalid_ : 1;
40 :
41 : static const size_t MaxOptimizedStubs = 6;
42 :
43 204 : void transition(Mode mode) {
44 204 : MOZ_ASSERT(mode > mode_);
45 204 : mode_ = mode;
46 204 : numFailures_ = 0;
47 204 : }
48 :
49 7263 : MOZ_ALWAYS_INLINE size_t maxFailures() const {
50 : // Allow more failures if we attached stubs.
51 : static_assert(MaxOptimizedStubs == 6,
52 : "numFailures_/maxFailures should fit in uint8_t");
53 7263 : size_t res = 5 + size_t(40) * numOptimizedStubs_;
54 7263 : MOZ_ASSERT(res <= UINT8_MAX, "numFailures_ should not overflow");
55 7263 : return res;
56 : }
57 :
58 : public:
59 17243 : ICState()
60 17243 : : invalid_(false)
61 : {
62 17243 : reset();
63 17243 : }
64 :
65 12137 : Mode mode() const { return mode_; }
66 17083 : size_t numOptimizedStubs() const { return numOptimizedStubs_; }
67 :
68 12577 : MOZ_ALWAYS_INLINE bool canAttachStub() const {
69 12577 : MOZ_ASSERT(numOptimizedStubs_ <= MaxOptimizedStubs);
70 12577 : if (mode_ == Mode::Generic || JitOptions.disableCacheIR)
71 5442 : return false;
72 7135 : return true;
73 : }
74 :
75 10091 : bool invalid() const { return invalid_; }
76 0 : void setInvalid() { invalid_ = true; }
77 :
78 : // If this returns true, we transitioned to a new mode and the caller
79 : // should discard all stubs.
80 12577 : MOZ_MUST_USE MOZ_ALWAYS_INLINE bool maybeTransition() {
81 12577 : MOZ_ASSERT(numOptimizedStubs_ <= MaxOptimizedStubs);
82 12577 : if (mode_ == Mode::Generic)
83 5366 : return false;
84 7211 : if (numOptimizedStubs_ < MaxOptimizedStubs && numFailures_ < maxFailures())
85 7007 : return false;
86 204 : if (numFailures_ == maxFailures() || mode_ == Mode::Megamorphic) {
87 76 : transition(Mode::Generic);
88 76 : return true;
89 : }
90 128 : MOZ_ASSERT(mode_ == Mode::Specialized);
91 128 : transition(Mode::Megamorphic);
92 128 : return true;
93 : }
94 17243 : void reset() {
95 17243 : mode_ = Mode::Specialized;
96 17243 : numOptimizedStubs_ = 0;
97 17243 : numFailures_ = 0;
98 17243 : }
99 10034 : void trackAttached() {
100 : // We'd like to assert numOptimizedStubs_ < MaxOptimizedStubs, but
101 : // since this code is also used for non-CacheIR Baseline stubs, assert
102 : // < 16 for now. Note that we do have the stronger assert in other
103 : // methods, because they are only used by CacheIR ICs.
104 10034 : MOZ_ASSERT(numOptimizedStubs_ < 16);
105 10034 : numOptimizedStubs_++;
106 10034 : numFailures_ = 0;
107 10034 : }
108 648 : void trackNotAttached() {
109 : // Note: we can't assert numFailures_ < maxFailures() because
110 : // maxFailures() depends on numOptimizedStubs_ and it's possible a
111 : // GC discarded stubs before we got here.
112 648 : numFailures_++;
113 648 : MOZ_ASSERT(numFailures_ > 0, "numFailures_ should not overflow");
114 648 : }
115 1056 : void trackUnlinkedStub() {
116 1056 : MOZ_ASSERT(numOptimizedStubs_ > 0);
117 1056 : numOptimizedStubs_--;
118 1056 : }
119 1 : void trackUnlinkedAllStubs() {
120 1 : numOptimizedStubs_ = 0;
121 1 : }
122 : };
123 :
124 : } // namespace jit
125 : } // namespace js
126 :
127 : #endif /* jit_ICState_h */
|