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