Home | History | Annotate | Download | only in src
      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:
     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 Symbol.
     69   static TypeInfo Symbol() { return TypeInfo(kSymbol); }
     70   // We know it's a heap number.
     71   static TypeInfo Double() { return TypeInfo(kDouble); }
     72   // We know it's a string.
     73   static TypeInfo String() { return TypeInfo(kString); }
     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 TypeFromValue(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 IsSymbol() {
    144     ASSERT(type_ != kUninitialized);
    145     return ((type_ & kSymbol) == kSymbol);
    146   }
    147 
    148   inline bool IsNonSymbol() {
    149     ASSERT(type_ != kUninitialized);
    150     return ((type_ & kSymbol) == 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 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   };
    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