// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef V8_TYPE_INFO_H_ #define V8_TYPE_INFO_H_ #include "allocation.h" #include "globals.h" #include "types.h" #include "zone-inl.h" namespace v8 { namespace internal { const int kMaxKeyedPolymorphism = 4; // Unknown // | \____________ // | | // Primitive Non-primitive // | \_______ | // | | | // Number String | // / \ | | // Double Integer32 | / // | | / / // | Smi / / // | | / __/ // Uninitialized. class TypeInfo { public: TypeInfo() : type_(kUninitialized) { } static TypeInfo Unknown() { return TypeInfo(kUnknown); } // We know it's a primitive type. static TypeInfo Primitive() { return TypeInfo(kPrimitive); } // We know it's a number of some sort. static TypeInfo Number() { return TypeInfo(kNumber); } // We know it's a signed 32 bit integer. static TypeInfo Integer32() { return TypeInfo(kInteger32); } // We know it's a Smi. static TypeInfo Smi() { return TypeInfo(kSmi); } // We know it's a heap number. static TypeInfo Double() { return TypeInfo(kDouble); } // We know it's a string. static TypeInfo String() { return TypeInfo(kString); } // We know it's an internalized string. static TypeInfo InternalizedString() { return TypeInfo(kInternalizedString); } // We know it's a non-primitive (object) type. static TypeInfo NonPrimitive() { return TypeInfo(kNonPrimitive); } // We haven't started collecting info yet. static TypeInfo Uninitialized() { return TypeInfo(kUninitialized); } int ToInt() { return type_; } static TypeInfo FromInt(int bit_representation) { Type t = static_cast(bit_representation); ASSERT(t == kUnknown || t == kPrimitive || t == kNumber || t == kInteger32 || t == kSmi || t == kDouble || t == kString || t == kNonPrimitive); return TypeInfo(t); } // Return the weakest (least precise) common type. static TypeInfo Combine(TypeInfo a, TypeInfo b) { return TypeInfo(static_cast(a.type_ & b.type_)); } // Integer32 is an integer that can be represented as a signed // 32-bit integer. It has to be // in the range [-2^31, 2^31 - 1]. We also have to check for negative 0 // as it is not an Integer32. static inline bool IsInt32Double(double value) { const DoubleRepresentation minus_zero(-0.0); DoubleRepresentation rep(value); if (rep.bits == minus_zero.bits) return false; if (value >= kMinInt && value <= kMaxInt && value == static_cast(value)) { return true; } return false; } static TypeInfo FromValue(Handle value); bool Equals(const TypeInfo& other) { return type_ == other.type_; } inline bool IsUnknown() { ASSERT(type_ != kUninitialized); return type_ == kUnknown; } inline bool IsPrimitive() { ASSERT(type_ != kUninitialized); return ((type_ & kPrimitive) == kPrimitive); } inline bool IsNumber() { ASSERT(type_ != kUninitialized); return ((type_ & kNumber) == kNumber); } inline bool IsSmi() { ASSERT(type_ != kUninitialized); return ((type_ & kSmi) == kSmi); } inline bool IsInternalizedString() { ASSERT(type_ != kUninitialized); return ((type_ & kInternalizedString) == kInternalizedString); } inline bool IsNonInternalizedString() { ASSERT(type_ != kUninitialized); return ((type_ & kInternalizedString) == kString); } inline bool IsInteger32() { ASSERT(type_ != kUninitialized); return ((type_ & kInteger32) == kInteger32); } inline bool IsDouble() { ASSERT(type_ != kUninitialized); return ((type_ & kDouble) == kDouble); } inline bool IsString() { ASSERT(type_ != kUninitialized); return ((type_ & kString) == kString); } inline bool IsNonPrimitive() { ASSERT(type_ != kUninitialized); return ((type_ & kNonPrimitive) == kNonPrimitive); } inline bool IsUninitialized() { return type_ == kUninitialized; } const char* ToString() { switch (type_) { case kUnknown: return "Unknown"; case kPrimitive: return "Primitive"; case kNumber: return "Number"; case kInteger32: return "Integer32"; case kSmi: return "Smi"; case kInternalizedString: return "InternalizedString"; case kDouble: return "Double"; case kString: return "String"; case kNonPrimitive: return "Object"; case kUninitialized: return "Uninitialized"; } UNREACHABLE(); return "Unreachable code"; } private: enum Type { kUnknown = 0, // 0000000 kPrimitive = 0x10, // 0010000 kNumber = 0x11, // 0010001 kInteger32 = 0x13, // 0010011 kSmi = 0x17, // 0010111 kDouble = 0x19, // 0011001 kString = 0x30, // 0110000 kInternalizedString = 0x32, // 0110010 kNonPrimitive = 0x40, // 1000000 kUninitialized = 0x7f // 1111111 }; explicit inline TypeInfo(Type t) : type_(t) { } Type type_; }; enum StringStubFeedback { DEFAULT_STRING_STUB = 0, STRING_INDEX_OUT_OF_BOUNDS = 1 }; // Forward declarations. class CompilationInfo; class ICStub; class SmallMapList; class TypeFeedbackOracle: public ZoneObject { public: TypeFeedbackOracle(Handle code, Handle native_context, Isolate* isolate, Zone* zone); bool LoadIsMonomorphicNormal(TypeFeedbackId id); bool LoadIsUninitialized(TypeFeedbackId id); bool LoadIsPreMonomorphic(TypeFeedbackId id); bool LoadIsPolymorphic(TypeFeedbackId id); bool StoreIsUninitialized(TypeFeedbackId id); bool StoreIsMonomorphicNormal(TypeFeedbackId id); bool StoreIsPreMonomorphic(TypeFeedbackId id); bool StoreIsKeyedPolymorphic(TypeFeedbackId id); bool CallIsMonomorphic(TypeFeedbackId aid); bool KeyedArrayCallIsHoley(TypeFeedbackId id); bool CallNewIsMonomorphic(TypeFeedbackId id); bool ObjectLiteralStoreIsMonomorphic(TypeFeedbackId id); // TODO(1571) We can't use ForInStatement::ForInType as the return value due // to various cycles in our headers. // TODO(rossberg): once all oracle access is removed from ast.cc, it should // be possible. byte ForInType(TypeFeedbackId id); Handle LoadMonomorphicReceiverType(TypeFeedbackId id); Handle StoreMonomorphicReceiverType(TypeFeedbackId id); KeyedAccessStoreMode GetStoreMode(TypeFeedbackId id); void LoadReceiverTypes(TypeFeedbackId id, Handle name, SmallMapList* types); void StoreReceiverTypes(TypeFeedbackId id, Handle name, SmallMapList* types); void CallReceiverTypes(TypeFeedbackId id, Handle name, int arity, CallKind call_kind, SmallMapList* types); void CollectKeyedReceiverTypes(TypeFeedbackId id, SmallMapList* types); void CollectPolymorphicStoreReceiverTypes(TypeFeedbackId id, SmallMapList* types); void PropertyReceiverTypes(TypeFeedbackId id, Handle name, SmallMapList* receiver_types, bool* is_prototype); void KeyedPropertyReceiverTypes(TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string); void AssignmentReceiverTypes(TypeFeedbackId id, Handle name, SmallMapList* receiver_types); void KeyedAssignmentReceiverTypes(TypeFeedbackId id, SmallMapList* receiver_types, KeyedAccessStoreMode* store_mode); void CountReceiverTypes(TypeFeedbackId id, SmallMapList* receiver_types); static bool CanRetainOtherContext(Map* map, Context* native_context); static bool CanRetainOtherContext(JSFunction* function, Context* native_context); void CollectPolymorphicMaps(Handle code, SmallMapList* types); CheckType GetCallCheckType(TypeFeedbackId id); Handle GetCallTarget(TypeFeedbackId id); Handle GetCallNewTarget(TypeFeedbackId id); Handle GetCallNewAllocationInfoCell(TypeFeedbackId id); Handle GetObjectLiteralStoreMap(TypeFeedbackId id); bool LoadIsBuiltin(TypeFeedbackId id, Builtins::Name builtin_id); bool LoadIsStub(TypeFeedbackId id, ICStub* stub); // TODO(1571) We can't use ToBooleanStub::Types as the return value because // of various cycles in our headers. Death to tons of implementations in // headers!! :-P byte ToBooleanTypes(TypeFeedbackId id); // Get type information for arithmetic operations and compares. void BinaryType(TypeFeedbackId id, Handle* left, Handle* right, Handle* result, Token::Value operation); void CompareType(TypeFeedbackId id, Handle* left, Handle* right, Handle* combined); Handle CountType(TypeFeedbackId id); Handle ClauseType(TypeFeedbackId id); Zone* zone() const { return zone_; } Isolate* isolate() const { return isolate_; } private: void CollectReceiverTypes(TypeFeedbackId id, Handle name, Code::Flags flags, SmallMapList* types); void SetInfo(TypeFeedbackId id, Object* target); void BuildDictionary(Handle code); void GetRelocInfos(Handle code, ZoneList* infos); void CreateDictionary(Handle code, ZoneList* infos); void RelocateRelocInfos(ZoneList* infos, byte* old_start, byte* new_start); void ProcessRelocInfos(ZoneList* infos); void ProcessTypeFeedbackCells(Handle code); // Returns an element from the backing store. Returns undefined if // there is no information. Handle GetInfo(TypeFeedbackId id); // Return the cell that contains type feedback. Handle GetInfoCell(TypeFeedbackId id); private: Handle native_context_; Isolate* isolate_; Zone* zone_; Handle dictionary_; DISALLOW_COPY_AND_ASSIGN(TypeFeedbackOracle); }; } } // namespace v8::internal #endif // V8_TYPE_INFO_H_