• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 namespace v8 {
37 namespace internal {
38 
39 const 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 
55 class TypeInfo {
56  public:
TypeInfo()57   TypeInfo() : type_(kUninitialized) { }
58 
Unknown()59   static TypeInfo Unknown() { return TypeInfo(kUnknown); }
60   // We know it's a primitive type.
Primitive()61   static TypeInfo Primitive() { return TypeInfo(kPrimitive); }
62   // We know it's a number of some sort.
Number()63   static TypeInfo Number() { return TypeInfo(kNumber); }
64   // We know it's a signed 32 bit integer.
Integer32()65   static TypeInfo Integer32() { return TypeInfo(kInteger32); }
66   // We know it's a Smi.
Smi()67   static TypeInfo Smi() { return TypeInfo(kSmi); }
68   // We know it's a Symbol.
Symbol()69   static TypeInfo Symbol() { return TypeInfo(kSymbol); }
70   // We know it's a heap number.
Double()71   static TypeInfo Double() { return TypeInfo(kDouble); }
72   // We know it's a string.
String()73   static TypeInfo String() { return TypeInfo(kString); }
74   // We know it's a non-primitive (object) type.
NonPrimitive()75   static TypeInfo NonPrimitive() { return TypeInfo(kNonPrimitive); }
76   // We haven't started collecting info yet.
Uninitialized()77   static TypeInfo Uninitialized() { return TypeInfo(kUninitialized); }
78 
ToInt()79   int ToInt() {
80     return type_;
81   }
82 
FromInt(int bit_representation)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.
Combine(TypeInfo a,TypeInfo b)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.
IsInt32Double(double value)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 
Equals(const TypeInfo & other)119   bool Equals(const TypeInfo& other) {
120     return type_ == other.type_;
121   }
122 
IsUnknown()123   inline bool IsUnknown() {
124     ASSERT(type_ != kUninitialized);
125     return type_ == kUnknown;
126   }
127 
IsPrimitive()128   inline bool IsPrimitive() {
129     ASSERT(type_ != kUninitialized);
130     return ((type_ & kPrimitive) == kPrimitive);
131   }
132 
IsNumber()133   inline bool IsNumber() {
134     ASSERT(type_ != kUninitialized);
135     return ((type_ & kNumber) == kNumber);
136   }
137 
IsSmi()138   inline bool IsSmi() {
139     ASSERT(type_ != kUninitialized);
140     return ((type_ & kSmi) == kSmi);
141   }
142 
IsSymbol()143   inline bool IsSymbol() {
144     ASSERT(type_ != kUninitialized);
145     return ((type_ & kSymbol) == kSymbol);
146   }
147 
IsNonSymbol()148   inline bool IsNonSymbol() {
149     ASSERT(type_ != kUninitialized);
150     return ((type_ & kSymbol) == kString);
151   }
152 
IsInteger32()153   inline bool IsInteger32() {
154     ASSERT(type_ != kUninitialized);
155     return ((type_ & kInteger32) == kInteger32);
156   }
157 
IsDouble()158   inline bool IsDouble() {
159     ASSERT(type_ != kUninitialized);
160     return ((type_ & kDouble) == kDouble);
161   }
162 
IsString()163   inline bool IsString() {
164     ASSERT(type_ != kUninitialized);
165     return ((type_ & kString) == kString);
166   }
167 
IsNonPrimitive()168   inline bool IsNonPrimitive() {
169     ASSERT(type_ != kUninitialized);
170     return ((type_ & kNonPrimitive) == kNonPrimitive);
171   }
172 
IsUninitialized()173   inline bool IsUninitialized() {
174     return type_ == kUninitialized;
175   }
176 
ToString()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   };
TypeInfo(Type t)207   explicit inline TypeInfo(Type t) : type_(t) { }
208 
209   Type type_;
210 };
211 
212 
213 enum StringStubFeedback {
214   DEFAULT_STRING_STUB = 0,
215   STRING_INDEX_OUT_OF_BOUNDS = 1
216 };
217 
218 
219 // Forward declarations.
220 class Assignment;
221 class BinaryOperation;
222 class Call;
223 class CallNew;
224 class CaseClause;
225 class CompareOperation;
226 class CompilationInfo;
227 class CountOperation;
228 class Expression;
229 class Property;
230 class SmallMapList;
231 class UnaryOperation;
232 class ForInStatement;
233 
234 
235 class 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