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 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: 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 214 enum StringStubFeedback { 215 DEFAULT_STRING_STUB = 0, 216 STRING_INDEX_OUT_OF_BOUNDS = 1 217 }; 218 219 220 // Forward declarations. 221 // TODO(rossberg): these should all go away eventually. 222 class Assignment; 223 class Call; 224 class CallNew; 225 class CaseClause; 226 class CompilationInfo; 227 class CountOperation; 228 class Expression; 229 class ForInStatement; 230 class ICStub; 231 class Property; 232 class SmallMapList; 233 class ObjectLiteral; 234 class ObjectLiteralProperty; 235 236 237 class TypeFeedbackOracle: public ZoneObject { 238 public: 239 TypeFeedbackOracle(Handle<Code> code, 240 Handle<Context> native_context, 241 Isolate* isolate, 242 Zone* zone); 243 244 bool LoadIsMonomorphicNormal(Property* expr); 245 bool LoadIsUninitialized(Property* expr); 246 bool LoadIsPolymorphic(Property* expr); 247 bool StoreIsUninitialized(TypeFeedbackId ast_id); 248 bool StoreIsMonomorphicNormal(TypeFeedbackId ast_id); 249 bool StoreIsKeyedPolymorphic(TypeFeedbackId ast_id); 250 bool CallIsMonomorphic(Call* expr); 251 bool CallNewIsMonomorphic(CallNew* expr); 252 bool ObjectLiteralStoreIsMonomorphic(ObjectLiteralProperty* prop); 253 254 // TODO(1571) We can't use ForInStatement::ForInType as the return value due 255 // to various cycles in our headers. 256 byte ForInType(ForInStatement* expr); 257 258 Handle<Map> LoadMonomorphicReceiverType(Property* expr); 259 Handle<Map> StoreMonomorphicReceiverType(TypeFeedbackId id); 260 261 KeyedAccessStoreMode GetStoreMode(TypeFeedbackId ast_id); 262 263 void LoadReceiverTypes(Property* expr, 264 Handle<String> name, 265 SmallMapList* types); 266 void StoreReceiverTypes(Assignment* expr, 267 Handle<String> name, 268 SmallMapList* types); 269 void CallReceiverTypes(Call* expr, 270 Handle<String> name, 271 CallKind call_kind, 272 SmallMapList* types); 273 void CollectKeyedReceiverTypes(TypeFeedbackId ast_id, 274 SmallMapList* types); 275 void CollectPolymorphicStoreReceiverTypes(TypeFeedbackId ast_id, 276 SmallMapList* types); 277 278 static bool CanRetainOtherContext(Map* map, Context* native_context); 279 static bool CanRetainOtherContext(JSFunction* function, 280 Context* native_context); 281 282 void CollectPolymorphicMaps(Handle<Code> code, SmallMapList* types); 283 284 CheckType GetCallCheckType(Call* expr); 285 Handle<JSFunction> GetCallTarget(Call* expr); 286 Handle<JSFunction> GetCallNewTarget(CallNew* expr); 287 Handle<Cell> GetCallNewAllocationInfoCell(CallNew* expr); 288 289 Handle<Map> GetObjectLiteralStoreMap(ObjectLiteralProperty* prop); 290 291 bool LoadIsBuiltin(Property* expr, Builtins::Name id); 292 bool LoadIsStub(Property* expr, ICStub* stub); 293 294 // TODO(1571) We can't use ToBooleanStub::Types as the return value because 295 // of various cycles in our headers. Death to tons of implementations in 296 // headers!! :-P 297 byte ToBooleanTypes(TypeFeedbackId id); 298 299 // Get type information for arithmetic operations and compares. 300 void BinaryType(TypeFeedbackId id, 301 Handle<Type>* left, 302 Handle<Type>* right, 303 Handle<Type>* result, 304 Maybe<int>* fixed_right_arg); 305 306 void CompareType(TypeFeedbackId id, 307 Handle<Type>* left, 308 Handle<Type>* right, 309 Handle<Type>* combined); 310 311 Handle<Type> ClauseType(TypeFeedbackId id); 312 313 TypeInfo IncrementType(CountOperation* expr); 314 315 Zone* zone() const { return zone_; } 316 Isolate* isolate() const { return isolate_; } 317 318 private: 319 void CollectReceiverTypes(TypeFeedbackId ast_id, 320 Handle<String> name, 321 Code::Flags flags, 322 SmallMapList* types); 323 324 void SetInfo(TypeFeedbackId ast_id, Object* target); 325 326 void BuildDictionary(Handle<Code> code); 327 void GetRelocInfos(Handle<Code> code, ZoneList<RelocInfo>* infos); 328 void CreateDictionary(Handle<Code> code, ZoneList<RelocInfo>* infos); 329 void RelocateRelocInfos(ZoneList<RelocInfo>* infos, 330 byte* old_start, 331 byte* new_start); 332 void ProcessRelocInfos(ZoneList<RelocInfo>* infos); 333 void ProcessTypeFeedbackCells(Handle<Code> code); 334 335 // Returns an element from the backing store. Returns undefined if 336 // there is no information. 337 Handle<Object> GetInfo(TypeFeedbackId ast_id); 338 339 // Return the cell that contains type feedback. 340 Handle<Cell> GetInfoCell(TypeFeedbackId ast_id); 341 342 private: 343 Handle<Context> native_context_; 344 Isolate* isolate_; 345 Zone* zone_; 346 Handle<UnseededNumberDictionary> dictionary_; 347 348 DISALLOW_COPY_AND_ASSIGN(TypeFeedbackOracle); 349 }; 350 351 } } // namespace v8::internal 352 353 #endif // V8_TYPE_INFO_H_ 354