1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_TYPE_INFO_H_
29#define V8_TYPE_INFO_H_
30
31#include "allocation.h"
32#include "ast.h"
33#include "globals.h"
34#include "zone-inl.h"
35
36namespace v8 {
37namespace internal {
38
39const int kMaxKeyedPolymorphism = 4;
40
41//         Unknown
42//           |   \____________
43//           |                |
44//      Primitive       Non-primitive
45//           |   \_______     |
46//           |           |    |
47//        Number       String |
48//         /   \         |    |
49//    Double  Integer32  |   /
50//        |      |      /   /
51//        |     Smi    /   /
52//        |      |    / __/
53//        Uninitialized.
54
55class TypeInfo {
56 public:
57  TypeInfo() : type_(kUninitialized) { }
58
59  static TypeInfo Unknown() { return TypeInfo(kUnknown); }
60  // We know it's a primitive type.
61  static TypeInfo Primitive() { return TypeInfo(kPrimitive); }
62  // We know it's a number of some sort.
63  static TypeInfo Number() { return TypeInfo(kNumber); }
64  // We know it's a signed 32 bit integer.
65  static TypeInfo Integer32() { return TypeInfo(kInteger32); }
66  // We know it's a Smi.
67  static TypeInfo Smi() { return TypeInfo(kSmi); }
68  // We know it's a Symbol.
69  static TypeInfo Symbol() { return TypeInfo(kSymbol); }
70  // We know it's a heap number.
71  static TypeInfo Double() { return TypeInfo(kDouble); }
72  // We know it's a string.
73  static TypeInfo String() { return TypeInfo(kString); }
74  // We know it's a non-primitive (object) type.
75  static TypeInfo NonPrimitive() { return TypeInfo(kNonPrimitive); }
76  // We haven't started collecting info yet.
77  static TypeInfo Uninitialized() { return TypeInfo(kUninitialized); }
78
79  int ToInt() {
80    return type_;
81  }
82
83  static TypeInfo FromInt(int bit_representation) {
84    Type t = static_cast<Type>(bit_representation);
85    ASSERT(t == kUnknown ||
86           t == kPrimitive ||
87           t == kNumber ||
88           t == kInteger32 ||
89           t == kSmi ||
90           t == kDouble ||
91           t == kString ||
92           t == kNonPrimitive);
93    return TypeInfo(t);
94  }
95
96  // Return the weakest (least precise) common type.
97  static TypeInfo Combine(TypeInfo a, TypeInfo b) {
98    return TypeInfo(static_cast<Type>(a.type_ & b.type_));
99  }
100
101
102  // Integer32 is an integer that can be represented as a signed
103  // 32-bit integer. It has to be
104  // in the range [-2^31, 2^31 - 1]. We also have to check for negative 0
105  // as it is not an Integer32.
106  static inline bool IsInt32Double(double value) {
107    const DoubleRepresentation minus_zero(-0.0);
108    DoubleRepresentation rep(value);
109    if (rep.bits == minus_zero.bits) return false;
110    if (value >= kMinInt && value <= kMaxInt &&
111        value == static_cast<int32_t>(value)) {
112      return true;
113    }
114    return false;
115  }
116
117  static TypeInfo TypeFromValue(Handle<Object> value);
118
119  bool Equals(const TypeInfo& other) {
120    return type_ == other.type_;
121  }
122
123  inline bool IsUnknown() {
124    ASSERT(type_ != kUninitialized);
125    return type_ == kUnknown;
126  }
127
128  inline bool IsPrimitive() {
129    ASSERT(type_ != kUninitialized);
130    return ((type_ & kPrimitive) == kPrimitive);
131  }
132
133  inline bool IsNumber() {
134    ASSERT(type_ != kUninitialized);
135    return ((type_ & kNumber) == kNumber);
136  }
137
138  inline bool IsSmi() {
139    ASSERT(type_ != kUninitialized);
140    return ((type_ & kSmi) == kSmi);
141  }
142
143  inline bool IsSymbol() {
144    ASSERT(type_ != kUninitialized);
145    return ((type_ & kSymbol) == kSymbol);
146  }
147
148  inline bool IsNonSymbol() {
149    ASSERT(type_ != kUninitialized);
150    return ((type_ & kSymbol) == kString);
151  }
152
153  inline bool IsInteger32() {
154    ASSERT(type_ != kUninitialized);
155    return ((type_ & kInteger32) == kInteger32);
156  }
157
158  inline bool IsDouble() {
159    ASSERT(type_ != kUninitialized);
160    return ((type_ & kDouble) == kDouble);
161  }
162
163  inline bool IsString() {
164    ASSERT(type_ != kUninitialized);
165    return ((type_ & kString) == kString);
166  }
167
168  inline bool IsNonPrimitive() {
169    ASSERT(type_ != kUninitialized);
170    return ((type_ & kNonPrimitive) == kNonPrimitive);
171  }
172
173  inline bool IsUninitialized() {
174    return type_ == kUninitialized;
175  }
176
177  const char* ToString() {
178    switch (type_) {
179      case kUnknown: return "Unknown";
180      case kPrimitive: return "Primitive";
181      case kNumber: return "Number";
182      case kInteger32: return "Integer32";
183      case kSmi: return "Smi";
184      case kSymbol: return "Symbol";
185      case kDouble: return "Double";
186      case kString: return "String";
187      case kNonPrimitive: return "Object";
188      case kUninitialized: return "Uninitialized";
189    }
190    UNREACHABLE();
191    return "Unreachable code";
192  }
193
194 private:
195  enum Type {
196    kUnknown = 0,          // 0000000
197    kPrimitive = 0x10,     // 0010000
198    kNumber = 0x11,        // 0010001
199    kInteger32 = 0x13,     // 0010011
200    kSmi = 0x17,           // 0010111
201    kDouble = 0x19,        // 0011001
202    kString = 0x30,        // 0110000
203    kSymbol = 0x32,        // 0110010
204    kNonPrimitive = 0x40,  // 1000000
205    kUninitialized = 0x7f  // 1111111
206  };
207  explicit inline TypeInfo(Type t) : type_(t) { }
208
209  Type type_;
210};
211
212
213enum StringStubFeedback {
214  DEFAULT_STRING_STUB = 0,
215  STRING_INDEX_OUT_OF_BOUNDS = 1
216};
217
218
219// Forward declarations.
220class Assignment;
221class BinaryOperation;
222class Call;
223class CallNew;
224class CaseClause;
225class CompareOperation;
226class CompilationInfo;
227class CountOperation;
228class Expression;
229class Property;
230class SmallMapList;
231class UnaryOperation;
232class ForInStatement;
233
234
235class TypeFeedbackOracle BASE_EMBEDDED {
236 public:
237  TypeFeedbackOracle(Handle<Code> code,
238                     Handle<Context> global_context,
239                     Isolate* isolate);
240
241  bool LoadIsMonomorphicNormal(Property* expr);
242  bool LoadIsUninitialized(Property* expr);
243  bool LoadIsMegamorphicWithTypeInfo(Property* expr);
244  bool StoreIsMonomorphicNormal(Expression* expr);
245  bool StoreIsMegamorphicWithTypeInfo(Expression* expr);
246  bool CallIsMonomorphic(Call* expr);
247  bool CallNewIsMonomorphic(CallNew* expr);
248  bool ObjectLiteralStoreIsMonomorphic(ObjectLiteral::Property* prop);
249
250  bool IsForInFastCase(ForInStatement* expr);
251
252  Handle<Map> LoadMonomorphicReceiverType(Property* expr);
253  Handle<Map> StoreMonomorphicReceiverType(Expression* expr);
254
255  void LoadReceiverTypes(Property* expr,
256                         Handle<String> name,
257                         SmallMapList* types);
258  void StoreReceiverTypes(Assignment* expr,
259                          Handle<String> name,
260                          SmallMapList* types);
261  void CallReceiverTypes(Call* expr,
262                         Handle<String> name,
263                         CallKind call_kind,
264                         SmallMapList* types);
265  void CollectKeyedReceiverTypes(unsigned ast_id,
266                                 SmallMapList* types);
267
268  static bool CanRetainOtherContext(Map* map, Context* global_context);
269  static bool CanRetainOtherContext(JSFunction* function,
270                                    Context* global_context);
271
272  CheckType GetCallCheckType(Call* expr);
273  Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
274
275  Handle<JSFunction> GetCallTarget(Call* expr);
276  Handle<JSFunction> GetCallNewTarget(CallNew* expr);
277
278  Handle<Map> GetObjectLiteralStoreMap(ObjectLiteral::Property* prop);
279
280  bool LoadIsBuiltin(Property* expr, Builtins::Name id);
281
282  // TODO(1571) We can't use ToBooleanStub::Types as the return value because
283  // of various cylces in our headers. Death to tons of implementations in
284  // headers!! :-P
285  byte ToBooleanTypes(unsigned ast_id);
286
287  // Get type information for arithmetic operations and compares.
288  TypeInfo UnaryType(UnaryOperation* expr);
289  TypeInfo BinaryType(BinaryOperation* expr);
290  TypeInfo CompareType(CompareOperation* expr);
291  bool IsSymbolCompare(CompareOperation* expr);
292  Handle<Map> GetCompareMap(CompareOperation* expr);
293  TypeInfo SwitchType(CaseClause* clause);
294  TypeInfo IncrementType(CountOperation* expr);
295
296 private:
297  void CollectReceiverTypes(unsigned ast_id,
298                            Handle<String> name,
299                            Code::Flags flags,
300                            SmallMapList* types);
301
302  void SetInfo(unsigned ast_id, Object* target);
303
304  void BuildDictionary(Handle<Code> code);
305  void GetRelocInfos(Handle<Code> code, ZoneList<RelocInfo>* infos);
306  void CreateDictionary(Handle<Code> code, ZoneList<RelocInfo>* infos);
307  void RelocateRelocInfos(ZoneList<RelocInfo>* infos,
308                          byte* old_start,
309                          byte* new_start);
310  void ProcessRelocInfos(ZoneList<RelocInfo>* infos);
311  void ProcessTypeFeedbackCells(Handle<Code> code);
312
313  // Returns an element from the backing store. Returns undefined if
314  // there is no information.
315  Handle<Object> GetInfo(unsigned ast_id);
316
317  Handle<Context> global_context_;
318  Isolate* isolate_;
319  Handle<UnseededNumberDictionary> dictionary_;
320
321  DISALLOW_COPY_AND_ASSIGN(TypeFeedbackOracle);
322};
323
324} }  // namespace v8::internal
325
326#endif  // V8_TYPE_INFO_H_
327