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