1// Copyright 2011 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 "globals.h"
32#include "zone.h"
33#include "zone-inl.h"
34
35namespace v8 {
36namespace internal {
37
38//         Unknown
39//           |   |
40//           |   \--------------|
41//      Primitive             Non-primitive
42//           |   \--------|     |
43//         Number      String   |
44//         /    |         |     |
45//    Double  Integer32   |    /
46//        |      |       /    /
47//        |     Smi     /    /
48//        |      |     /    /
49//        |      |    /    /
50//        Uninitialized.--/
51
52class TypeInfo {
53 public:
54  TypeInfo() : type_(kUninitialized) { }
55
56  static TypeInfo Unknown() { return TypeInfo(kUnknown); }
57  // We know it's a primitive type.
58  static TypeInfo Primitive() { return TypeInfo(kPrimitive); }
59  // We know it's a number of some sort.
60  static TypeInfo Number() { return TypeInfo(kNumber); }
61  // We know it's a signed 32 bit integer.
62  static TypeInfo Integer32() { return TypeInfo(kInteger32); }
63  // We know it's a Smi.
64  static TypeInfo Smi() { return TypeInfo(kSmi); }
65  // We know it's a heap number.
66  static TypeInfo Double() { return TypeInfo(kDouble); }
67  // We know it's a string.
68  static TypeInfo String() { return TypeInfo(kString); }
69  // We know it's a non-primitive (object) type.
70  static TypeInfo NonPrimitive() { return TypeInfo(kNonPrimitive); }
71  // We haven't started collecting info yet.
72  static TypeInfo Uninitialized() { return TypeInfo(kUninitialized); }
73
74  // Return compact representation.  Very sensitive to enum values below!
75  // Compacting drops information about primitive types and strings types.
76  // We use the compact representation when we only care about number types.
77  int ThreeBitRepresentation() {
78    ASSERT(type_ != kUninitialized);
79    int answer = type_ & 0xf;
80    answer = answer > 6 ? answer - 2 : answer;
81    ASSERT(answer >= 0);
82    ASSERT(answer <= 7);
83    return answer;
84  }
85
86  // Decode compact representation.  Very sensitive to enum values below!
87  static TypeInfo ExpandedRepresentation(int three_bit_representation) {
88    Type t = static_cast<Type>(three_bit_representation > 4 ?
89                               three_bit_representation + 2 :
90                               three_bit_representation);
91    t = (t == kUnknown) ? t : static_cast<Type>(t | kPrimitive);
92    ASSERT(t == kUnknown ||
93           t == kNumber ||
94           t == kInteger32 ||
95           t == kSmi ||
96           t == kDouble);
97    return TypeInfo(t);
98  }
99
100  int ToInt() {
101    return type_;
102  }
103
104  static TypeInfo FromInt(int bit_representation) {
105    Type t = static_cast<Type>(bit_representation);
106    ASSERT(t == kUnknown ||
107           t == kPrimitive ||
108           t == kNumber ||
109           t == kInteger32 ||
110           t == kSmi ||
111           t == kDouble ||
112           t == kString ||
113           t == kNonPrimitive);
114    return TypeInfo(t);
115  }
116
117  // Return the weakest (least precise) common type.
118  static TypeInfo Combine(TypeInfo a, TypeInfo b) {
119    return TypeInfo(static_cast<Type>(a.type_ & b.type_));
120  }
121
122
123  // Integer32 is an integer that can be represented as a signed
124  // 32-bit integer. It has to be
125  // in the range [-2^31, 2^31 - 1]. We also have to check for negative 0
126  // as it is not an Integer32.
127  static inline bool IsInt32Double(double value) {
128    const DoubleRepresentation minus_zero(-0.0);
129    DoubleRepresentation rep(value);
130    if (rep.bits == minus_zero.bits) return false;
131    if (value >= kMinInt && value <= kMaxInt &&
132        value == static_cast<int32_t>(value)) {
133      return true;
134    }
135    return false;
136  }
137
138  static TypeInfo TypeFromValue(Handle<Object> value);
139
140  bool Equals(const TypeInfo& other) {
141    return type_ == other.type_;
142  }
143
144  inline bool IsUnknown() {
145    ASSERT(type_ != kUninitialized);
146    return type_ == kUnknown;
147  }
148
149  inline bool IsPrimitive() {
150    ASSERT(type_ != kUninitialized);
151    return ((type_ & kPrimitive) == kPrimitive);
152  }
153
154  inline bool IsNumber() {
155    ASSERT(type_ != kUninitialized);
156    return ((type_ & kNumber) == kNumber);
157  }
158
159  inline bool IsSmi() {
160    ASSERT(type_ != kUninitialized);
161    return ((type_ & kSmi) == kSmi);
162  }
163
164  inline bool IsInteger32() {
165    ASSERT(type_ != kUninitialized);
166    return ((type_ & kInteger32) == kInteger32);
167  }
168
169  inline bool IsDouble() {
170    ASSERT(type_ != kUninitialized);
171    return ((type_ & kDouble) == kDouble);
172  }
173
174  inline bool IsString() {
175    ASSERT(type_ != kUninitialized);
176    return ((type_ & kString) == kString);
177  }
178
179  inline bool IsNonPrimitive() {
180    ASSERT(type_ != kUninitialized);
181    return ((type_ & kNonPrimitive) == kNonPrimitive);
182  }
183
184  inline bool IsUninitialized() {
185    return type_ == kUninitialized;
186  }
187
188  const char* ToString() {
189    switch (type_) {
190      case kUnknown: return "Unknown";
191      case kPrimitive: return "Primitive";
192      case kNumber: return "Number";
193      case kInteger32: return "Integer32";
194      case kSmi: return "Smi";
195      case kDouble: return "Double";
196      case kString: return "String";
197      case kNonPrimitive: return "Object";
198      case kUninitialized: return "Uninitialized";
199    }
200    UNREACHABLE();
201    return "Unreachable code";
202  }
203
204 private:
205  enum Type {
206    kUnknown = 0,          // 0000000
207    kPrimitive = 0x10,     // 0010000
208    kNumber = 0x11,        // 0010001
209    kInteger32 = 0x13,     // 0010011
210    kSmi = 0x17,           // 0010111
211    kDouble = 0x19,        // 0011001
212    kString = 0x30,        // 0110000
213    kNonPrimitive = 0x40,  // 1000000
214    kUninitialized = 0x7f  // 1111111
215  };
216  explicit inline TypeInfo(Type t) : type_(t) { }
217
218  Type type_;
219};
220
221
222enum StringStubFeedback {
223  DEFAULT_STRING_STUB = 0,
224  STRING_INDEX_OUT_OF_BOUNDS = 1
225};
226
227
228// Forward declarations.
229class Assignment;
230class BinaryOperation;
231class Call;
232class CompareOperation;
233class CompilationInfo;
234class Property;
235class CaseClause;
236
237class TypeFeedbackOracle BASE_EMBEDDED {
238 public:
239  TypeFeedbackOracle(Handle<Code> code, Handle<Context> global_context);
240
241  bool LoadIsMonomorphic(Property* expr);
242  bool StoreIsMonomorphic(Expression* expr);
243  bool CallIsMonomorphic(Call* expr);
244
245  Handle<Map> LoadMonomorphicReceiverType(Property* expr);
246  Handle<Map> StoreMonomorphicReceiverType(Expression* expr);
247
248  ZoneMapList* LoadReceiverTypes(Property* expr, Handle<String> name);
249  ZoneMapList* StoreReceiverTypes(Assignment* expr, Handle<String> name);
250  ZoneMapList* CallReceiverTypes(Call* expr, Handle<String> name);
251
252  ExternalArrayType GetKeyedLoadExternalArrayType(Property* expr);
253  ExternalArrayType GetKeyedStoreExternalArrayType(Expression* expr);
254
255  CheckType GetCallCheckType(Call* expr);
256  Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
257
258  bool LoadIsBuiltin(Property* expr, Builtins::Name id);
259
260  // Get type information for arithmetic operations and compares.
261  TypeInfo BinaryType(BinaryOperation* expr);
262  TypeInfo CompareType(CompareOperation* expr);
263  TypeInfo SwitchType(CaseClause* clause);
264
265 private:
266  ZoneMapList* CollectReceiverTypes(int position,
267                                    Handle<String> name,
268                                    Code::Flags flags);
269
270  void SetInfo(int position, Object* target);
271
272  void PopulateMap(Handle<Code> code);
273
274  void CollectPositions(Code* code,
275                        List<int>* code_positions,
276                        List<int>* source_positions);
277
278  // Returns an element from the backing store. Returns undefined if
279  // there is no information.
280  Handle<Object> GetInfo(int pos);
281
282  Handle<Context> global_context_;
283  Handle<NumberDictionary> dictionary_;
284
285  DISALLOW_COPY_AND_ASSIGN(TypeFeedbackOracle);
286};
287
288} }  // namespace v8::internal
289
290#endif  // V8_TYPE_INFO_H_
291