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);
BinaryOpICState(Isolate * isolate,Token::Value op)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 
GetICState()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.
CouldCreateAllocationMementos()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.
ShouldCreateAllocationMementos()70   bool ShouldCreateAllocationMementos() const {
71     return FLAG_allocation_site_pretenuring && CouldCreateAllocationMementos();
72   }
73 
HasSideEffects()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).
UseInlinedSmiCode()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 
op()87   Token::Value op() const { return op_; }
fixed_right_arg()88   Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
89 
GetLeftType()90   AstType* GetLeftType() const { return KindToType(left_kind_); }
GetRightType()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 
isolate()96   Isolate* isolate() const { return isolate_; }
97 
98   enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
kind()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);
KindMaybeSmi(Kind kind)111   static bool KindMaybeSmi(Kind kind) {
112     return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
113   }
KindLessGeneralThan(Kind kind1,Kind kind2)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   }
KindGeneralize(Kind kind1,Kind kind2)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