1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_IC_STATE_H_ 6 #define V8_IC_STATE_H_ 7 8 #include "src/macro-assembler.h" 9 #include "src/parsing/token.h" 10 11 namespace v8 { 12 namespace internal { 13 14 class AstType; 15 16 const int kMaxKeyedPolymorphism = 4; 17 18 19 class ICUtility : public AllStatic { 20 public: 21 // Clear the inline cache to initial state. 22 static void Clear(Isolate* isolate, Address address, Address constant_pool); 23 }; 24 25 26 class BinaryOpICState final BASE_EMBEDDED { 27 public: 28 BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state); 29 BinaryOpICState(Isolate* isolate, Token::Value op) 30 : op_(op), 31 left_kind_(NONE), 32 right_kind_(NONE), 33 result_kind_(NONE), 34 fixed_right_arg_(Nothing<int>()), 35 isolate_(isolate) { 36 DCHECK_LE(FIRST_TOKEN, op); 37 DCHECK_LE(op, LAST_TOKEN); 38 } 39 40 InlineCacheState GetICState() const { 41 if (Max(left_kind_, right_kind_) == NONE) { 42 return ::v8::internal::UNINITIALIZED; 43 } 44 if (Max(left_kind_, right_kind_) == GENERIC) { 45 return ::v8::internal::MEGAMORPHIC; 46 } 47 if (Min(left_kind_, right_kind_) == GENERIC) { 48 return ::v8::internal::GENERIC; 49 } 50 return ::v8::internal::MONOMORPHIC; 51 } 52 53 ExtraICState GetExtraICState() const; 54 std::string ToString() const; 55 56 static void GenerateAheadOfTime(Isolate*, 57 void (*Generate)(Isolate*, 58 const BinaryOpICState&)); 59 60 // Returns true if the IC _could_ create allocation mementos. 61 bool CouldCreateAllocationMementos() const { 62 if (left_kind_ == STRING || right_kind_ == STRING) { 63 DCHECK_EQ(Token::ADD, op_); 64 return true; 65 } 66 return false; 67 } 68 69 // Returns true if the IC _should_ create allocation mementos. 70 bool ShouldCreateAllocationMementos() const { 71 return FLAG_allocation_site_pretenuring && CouldCreateAllocationMementos(); 72 } 73 74 bool HasSideEffects() const { 75 return Max(left_kind_, right_kind_) == GENERIC; 76 } 77 78 // Returns true if the IC should enable the inline smi code (i.e. if either 79 // parameter may be a smi). 80 bool UseInlinedSmiCode() const { 81 return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_); 82 } 83 84 static const int FIRST_TOKEN = Token::BIT_OR; 85 static const int LAST_TOKEN = Token::MOD; 86 87 Token::Value op() const { return op_; } 88 Maybe<int> fixed_right_arg() const { return fixed_right_arg_; } 89 90 AstType* GetLeftType() const { return KindToType(left_kind_); } 91 AstType* GetRightType() const { return KindToType(right_kind_); } 92 AstType* GetResultType() const; 93 94 void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result); 95 96 Isolate* isolate() const { return isolate_; } 97 98 enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC }; 99 Kind kind() const { 100 return KindGeneralize(KindGeneralize(left_kind_, right_kind_), 101 result_kind_); 102 } 103 104 private: 105 friend std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s); 106 107 Kind UpdateKind(Handle<Object> object, Kind kind) const; 108 109 static const char* KindToString(Kind kind); 110 static AstType* KindToType(Kind kind); 111 static bool KindMaybeSmi(Kind kind) { 112 return (kind >= SMI && kind <= NUMBER) || kind == GENERIC; 113 } 114 static bool KindLessGeneralThan(Kind kind1, Kind kind2) { 115 if (kind1 == NONE) return true; 116 if (kind1 == kind2) return true; 117 if (kind2 == GENERIC) return true; 118 if (kind2 == STRING) return false; 119 return kind1 <= kind2; 120 } 121 static Kind KindGeneralize(Kind kind1, Kind kind2) { 122 if (KindLessGeneralThan(kind1, kind2)) return kind2; 123 if (KindLessGeneralThan(kind2, kind1)) return kind1; 124 return GENERIC; 125 } 126 127 // We truncate the last bit of the token. 128 STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4)); 129 class OpField : public BitField<int, 0, 4> {}; 130 class ResultKindField : public BitField<Kind, 4, 3> {}; 131 class LeftKindField : public BitField<Kind, 7, 3> {}; 132 // When fixed right arg is set, we don't need to store the right kind. 133 // Thus the two fields can overlap. 134 class HasFixedRightArgField : public BitField<bool, 10, 1> {}; 135 class FixedRightArgValueField : public BitField<int, 11, 4> {}; 136 class RightKindField : public BitField<Kind, 11, 3> {}; 137 138 Token::Value op_; 139 Kind left_kind_; 140 Kind right_kind_; 141 Kind result_kind_; 142 Maybe<int> fixed_right_arg_; 143 Isolate* isolate_; 144 }; 145 146 147 std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s); 148 149 150 class CompareICState { 151 public: 152 // The type/state lattice is defined by the following inequations: 153 // UNINITIALIZED < ... 154 // ... < GENERIC 155 // SMI < NUMBER 156 // INTERNALIZED_STRING < STRING 157 // INTERNALIZED_STRING < UNIQUE_NAME 158 // KNOWN_RECEIVER < RECEIVER 159 enum State { 160 UNINITIALIZED, 161 BOOLEAN, 162 SMI, 163 NUMBER, 164 STRING, 165 INTERNALIZED_STRING, 166 UNIQUE_NAME, // Symbol or InternalizedString 167 RECEIVER, // JSReceiver 168 KNOWN_RECEIVER, // JSReceiver with specific map (faster check) 169 GENERIC 170 }; 171 172 static AstType* StateToType(Zone* zone, State state, 173 Handle<Map> map = Handle<Map>()); 174 175 static State NewInputState(State old_state, Handle<Object> value); 176 177 static const char* GetStateName(CompareICState::State state); 178 179 static State TargetState(Isolate* isolate, State old_state, State old_left, 180 State old_right, Token::Value op, 181 bool has_inlined_smi_code, Handle<Object> x, 182 Handle<Object> y); 183 }; 184 185 } // namespace internal 186 } // namespace v8 187 188 #endif // V8_IC_STATE_H_ 189