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 "globals.h"
33#include "types.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 heap number.
69  static TypeInfo Double() { return TypeInfo(kDouble); }
70  // We know it's a string.
71  static TypeInfo String() { return TypeInfo(kString); }
72  // We know it's an internalized string.
73  static TypeInfo InternalizedString() { return TypeInfo(kInternalizedString); }
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 FromValue(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 IsInternalizedString() {
144    ASSERT(type_ != kUninitialized);
145    return ((type_ & kInternalizedString) == kInternalizedString);
146  }
147
148  inline bool IsNonInternalizedString() {
149    ASSERT(type_ != kUninitialized);
150    return ((type_ & kInternalizedString) == 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 kInternalizedString: return "InternalizedString";
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    kInternalizedString = 0x32,  // 0110010
204    kNonPrimitive = 0x40,        // 1000000
205    kUninitialized = 0x7f        // 1111111
206  };
207
208  explicit inline TypeInfo(Type t) : type_(t) { }
209
210  Type type_;
211};
212
213
214enum StringStubFeedback {
215  DEFAULT_STRING_STUB = 0,
216  STRING_INDEX_OUT_OF_BOUNDS = 1
217};
218
219
220// Forward declarations.
221class CompilationInfo;
222class ICStub;
223class SmallMapList;
224
225
226class TypeFeedbackOracle: public ZoneObject {
227 public:
228  TypeFeedbackOracle(Handle<Code> code,
229                     Handle<Context> native_context,
230                     Isolate* isolate,
231                     Zone* zone);
232
233  bool LoadIsUninitialized(TypeFeedbackId id);
234  bool LoadIsPreMonomorphic(TypeFeedbackId id);
235  bool StoreIsUninitialized(TypeFeedbackId id);
236  bool StoreIsPreMonomorphic(TypeFeedbackId id);
237  bool StoreIsKeyedPolymorphic(TypeFeedbackId id);
238  bool CallIsMonomorphic(TypeFeedbackId aid);
239  bool KeyedArrayCallIsHoley(TypeFeedbackId id);
240  bool CallNewIsMonomorphic(TypeFeedbackId id);
241
242  // TODO(1571) We can't use ForInStatement::ForInType as the return value due
243  // to various cycles in our headers.
244  // TODO(rossberg): once all oracle access is removed from ast.cc, it should
245  // be possible.
246  byte ForInType(TypeFeedbackId id);
247
248  KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id);
249
250  void CallReceiverTypes(TypeFeedbackId id,
251                         Handle<String> name,
252                         int arity,
253                         CallKind call_kind,
254                         SmallMapList* types);
255  void PropertyReceiverTypes(TypeFeedbackId id,
256                             Handle<String> name,
257                             SmallMapList* receiver_types,
258                             bool* is_prototype);
259  void KeyedPropertyReceiverTypes(TypeFeedbackId id,
260                                  SmallMapList* receiver_types,
261                                  bool* is_string);
262  void AssignmentReceiverTypes(TypeFeedbackId id,
263                               Handle<String> name,
264                               SmallMapList* receiver_types);
265  void KeyedAssignmentReceiverTypes(TypeFeedbackId id,
266                                    SmallMapList* receiver_types,
267                                    KeyedAccessStoreMode* store_mode);
268  void CountReceiverTypes(TypeFeedbackId id,
269                          SmallMapList* receiver_types);
270
271  void CollectReceiverTypes(TypeFeedbackId id,
272                            SmallMapList* types);
273
274  static bool CanRetainOtherContext(Map* map, Context* native_context);
275  static bool CanRetainOtherContext(JSFunction* function,
276                                    Context* native_context);
277
278  CheckType GetCallCheckType(TypeFeedbackId id);
279  Handle<JSFunction> GetCallTarget(TypeFeedbackId id);
280  Handle<JSFunction> GetCallNewTarget(TypeFeedbackId id);
281  Handle<Cell> GetCallNewAllocationInfoCell(TypeFeedbackId id);
282
283  bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id);
284  bool LoadIsStub(TypeFeedbackId id, ICStub* stub);
285
286  // TODO(1571) We can't use ToBooleanStub::Types as the return value because
287  // of various cycles in our headers. Death to tons of implementations in
288  // headers!! :-P
289  byte ToBooleanTypes(TypeFeedbackId id);
290
291  // Get type information for arithmetic operations and compares.
292  void BinaryType(TypeFeedbackId id,
293                  Handle<Type>* left,
294                  Handle<Type>* right,
295                  Handle<Type>* result,
296                  Maybe<int>* fixed_right_arg,
297                  Token::Value operation);
298
299  void CompareType(TypeFeedbackId id,
300                   Handle<Type>* left,
301                   Handle<Type>* right,
302                   Handle<Type>* combined);
303
304  Handle<Type> CountType(TypeFeedbackId id);
305
306  Handle<Type> ClauseType(TypeFeedbackId id);
307
308  Zone* zone() const { return zone_; }
309  Isolate* isolate() const { return isolate_; }
310
311 private:
312  void CollectReceiverTypes(TypeFeedbackId id,
313                            Handle<String> name,
314                            Code::Flags flags,
315                            SmallMapList* types);
316
317  void SetInfo(TypeFeedbackId id, Object* target);
318
319  void BuildDictionary(Handle<Code> code);
320  void GetRelocInfos(Handle<Code> code, ZoneList<RelocInfo>* infos);
321  void CreateDictionary(Handle<Code> code, ZoneList<RelocInfo>* infos);
322  void RelocateRelocInfos(ZoneList<RelocInfo>* infos,
323                          byte* old_start,
324                          byte* new_start);
325  void ProcessRelocInfos(ZoneList<RelocInfo>* infos);
326  void ProcessTypeFeedbackCells(Handle<Code> code);
327
328  // Returns an element from the backing store. Returns undefined if
329  // there is no information.
330  Handle<Object> GetInfo(TypeFeedbackId id);
331
332  // Return the cell that contains type feedback.
333  Handle<Cell> GetInfoCell(TypeFeedbackId id);
334
335 private:
336  Handle<Context> native_context_;
337  Isolate* isolate_;
338  Zone* zone_;
339  Handle<UnseededNumberDictionary> dictionary_;
340
341  DISALLOW_COPY_AND_ASSIGN(TypeFeedbackOracle);
342};
343
344} }  // namespace v8::internal
345
346#endif  // V8_TYPE_INFO_H_
347