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 35 namespace v8 { 36 namespace 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 52 class TypeInfo { 53 public: TypeInfo()54 TypeInfo() : type_(kUninitialized) { } 55 Unknown()56 static TypeInfo Unknown() { return TypeInfo(kUnknown); } 57 // We know it's a primitive type. Primitive()58 static TypeInfo Primitive() { return TypeInfo(kPrimitive); } 59 // We know it's a number of some sort. Number()60 static TypeInfo Number() { return TypeInfo(kNumber); } 61 // We know it's a signed 32 bit integer. Integer32()62 static TypeInfo Integer32() { return TypeInfo(kInteger32); } 63 // We know it's a Smi. Smi()64 static TypeInfo Smi() { return TypeInfo(kSmi); } 65 // We know it's a heap number. Double()66 static TypeInfo Double() { return TypeInfo(kDouble); } 67 // We know it's a string. String()68 static TypeInfo String() { return TypeInfo(kString); } 69 // We know it's a non-primitive (object) type. NonPrimitive()70 static TypeInfo NonPrimitive() { return TypeInfo(kNonPrimitive); } 71 // We haven't started collecting info yet. Uninitialized()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. ThreeBitRepresentation()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! ExpandedRepresentation(int three_bit_representation)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 ToInt()100 int ToInt() { 101 return type_; 102 } 103 FromInt(int bit_representation)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. Combine(TypeInfo a,TypeInfo b)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. IsInt32Double(double value)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 Equals(const TypeInfo & other)140 bool Equals(const TypeInfo& other) { 141 return type_ == other.type_; 142 } 143 IsUnknown()144 inline bool IsUnknown() { 145 ASSERT(type_ != kUninitialized); 146 return type_ == kUnknown; 147 } 148 IsPrimitive()149 inline bool IsPrimitive() { 150 ASSERT(type_ != kUninitialized); 151 return ((type_ & kPrimitive) == kPrimitive); 152 } 153 IsNumber()154 inline bool IsNumber() { 155 ASSERT(type_ != kUninitialized); 156 return ((type_ & kNumber) == kNumber); 157 } 158 IsSmi()159 inline bool IsSmi() { 160 ASSERT(type_ != kUninitialized); 161 return ((type_ & kSmi) == kSmi); 162 } 163 IsInteger32()164 inline bool IsInteger32() { 165 ASSERT(type_ != kUninitialized); 166 return ((type_ & kInteger32) == kInteger32); 167 } 168 IsDouble()169 inline bool IsDouble() { 170 ASSERT(type_ != kUninitialized); 171 return ((type_ & kDouble) == kDouble); 172 } 173 IsString()174 inline bool IsString() { 175 ASSERT(type_ != kUninitialized); 176 return ((type_ & kString) == kString); 177 } 178 IsNonPrimitive()179 inline bool IsNonPrimitive() { 180 ASSERT(type_ != kUninitialized); 181 return ((type_ & kNonPrimitive) == kNonPrimitive); 182 } 183 IsUninitialized()184 inline bool IsUninitialized() { 185 return type_ == kUninitialized; 186 } 187 ToString()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 }; TypeInfo(Type t)216 explicit inline TypeInfo(Type t) : type_(t) { } 217 218 Type type_; 219 }; 220 221 222 enum StringStubFeedback { 223 DEFAULT_STRING_STUB = 0, 224 STRING_INDEX_OUT_OF_BOUNDS = 1 225 }; 226 227 228 // Forward declarations. 229 class Assignment; 230 class BinaryOperation; 231 class Call; 232 class CompareOperation; 233 class CompilationInfo; 234 class Property; 235 class CaseClause; 236 237 class 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