// Copyright 2013 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_TYPES_H_ #define V8_TYPES_H_ #include "v8.h" #include "objects.h" namespace v8 { namespace internal { // A simple type system for compiler-internal use. It is based entirely on // union types, and all subtyping hence amounts to set inclusion. Besides the // obvious primitive types and some predefined unions, the type language also // can express class types (a.k.a. specific maps) and singleton types (i.e., // concrete constants). // // The following equations and inequations hold: // // None <= T // T <= Any // // Oddball = Boolean \/ Null \/ Undefined // Number = Integer32 \/ Double // Integer31 < Integer32 // Name = String \/ Symbol // UniqueName = InternalizedString \/ Symbol // InternalizedString < String // // Allocated = Receiver \/ Number \/ Name // Detectable = Allocated - Undetectable // Undetectable < Object // Receiver = Object \/ Proxy // Array < Object // Function < Object // // Class(map) < T iff instance_type(map) < T // Constant(x) < T iff instance_type(map(x)) < T // // Note that Constant(x) < Class(map(x)) does _not_ hold, since x's map can // change! (Its instance type cannot, however.) // TODO(rossberg): the latter is not currently true for proxies, because of fix, // but will hold once we implement direct proxies. // // There are two main functions for testing types: // // T1->Is(T2) -- tests whether T1 is included in T2 (i.e., T1 <= T2) // T1->Maybe(T2) -- tests whether T1 and T2 overlap (i.e., T1 /\ T2 =/= 0) // // Typically, the former is to be used to select representations (e.g., via // T->Is(Integer31())), and the to check whether a specific case needs handling // (e.g., via T->Maybe(Number())). // // There is no functionality to discover whether a type is a leaf in the // lattice. That is intentional. It should always be possible to refine the // lattice (e.g., splitting up number types further) without invalidating any // existing assumptions or tests. // // Internally, all 'primitive' types, and their unions, are represented as // bitsets via smis. Class is a heap pointer to the respective map. Only // Constant's, or unions containing Class'es or Constant's, require allocation. // Note that the bitset representation is closed under both Union and Intersect. // // The type representation is heap-allocated, so cannot (currently) be used in // a parallel compilation context. class Type : public Object { public: static Type* None() { return from_bitset(kNone); } static Type* Any() { return from_bitset(kAny); } static Type* Allocated() { return from_bitset(kAllocated); } static Type* Detectable() { return from_bitset(kDetectable); } static Type* Oddball() { return from_bitset(kOddball); } static Type* Boolean() { return from_bitset(kBoolean); } static Type* Null() { return from_bitset(kNull); } static Type* Undefined() { return from_bitset(kUndefined); } static Type* Number() { return from_bitset(kNumber); } static Type* Integer31() { return from_bitset(kInteger31); } static Type* Integer32() { return from_bitset(kInteger32); } static Type* Double() { return from_bitset(kDouble); } static Type* Name() { return from_bitset(kName); } static Type* UniqueName() { return from_bitset(kUniqueName); } static Type* String() { return from_bitset(kString); } static Type* InternalizedString() { return from_bitset(kInternalizedString); } static Type* Symbol() { return from_bitset(kSymbol); } static Type* Receiver() { return from_bitset(kReceiver); } static Type* Object() { return from_bitset(kObject); } static Type* Undetectable() { return from_bitset(kUndetectable); } static Type* Array() { return from_bitset(kArray); } static Type* Function() { return from_bitset(kFunction); } static Type* Proxy() { return from_bitset(kProxy); } static Type* Class(Handle map) { return from_handle(map); } static Type* Constant(Handle value) { return Constant(value, value->GetIsolate()); } static Type* Constant(Handle value, Isolate* isolate) { return from_handle(isolate->factory()->NewBox(value)); } static Type* Union(Handle type1, Handle type2); static Type* Intersect(Handle type1, Handle type2); static Type* Optional(Handle type); // type \/ Undefined bool Is(Type* that); bool Is(Handle that) { return this->Is(*that); } bool Maybe(Type* that); bool Maybe(Handle that) { return this->Maybe(*that); } bool IsClass() { return is_class(); } bool IsConstant() { return is_constant(); } Handle AsClass() { return as_class(); } Handle AsConstant() { return as_constant(); } int NumClasses(); int NumConstants(); template class Iterator { public: bool Done() const { return index_ < 0; } Handle Current(); void Advance(); private: friend class Type; Iterator() : index_(-1) {} explicit Iterator(Handle type) : type_(type), index_(-1) { Advance(); } inline bool matches(Handle type); inline Handle get_type(); Handle type_; int index_; }; Iterator Classes() { if (this->is_bitset()) return Iterator(); return Iterator(this->handle()); } Iterator Constants() { if (this->is_bitset()) return Iterator(); return Iterator(this->handle()); } private: // A union is a fixed array containing types. Invariants: // - its length is at least 2 // - at most one field is a bitset, and it must go into index 0 // - no field is a union typedef FixedArray Unioned; enum { kNull = 1 << 0, kUndefined = 1 << 1, kBoolean = 1 << 2, kInteger31 = 1 << 3, kOtherInteger = 1 << 4, kDouble = 1 << 5, kSymbol = 1 << 6, kInternalizedString = 1 << 7, kOtherString = 1 << 8, kUndetectable = 1 << 9, kArray = 1 << 10, kFunction = 1 << 11, kOtherObject = 1 << 12, kProxy = 1 << 13, kOddball = kBoolean | kNull | kUndefined, kInteger32 = kInteger31 | kOtherInteger, kNumber = kInteger32 | kDouble, kString = kInternalizedString | kOtherString, kUniqueName = kSymbol | kInternalizedString, kName = kSymbol | kString, kObject = kUndetectable | kArray | kFunction | kOtherObject, kReceiver = kObject | kProxy, kAllocated = kDouble | kName | kReceiver, kAny = kOddball | kNumber | kAllocated, kDetectable = kAllocated - kUndetectable, kNone = 0 }; bool is_bitset() { return this->IsSmi(); } bool is_class() { return this->IsMap(); } bool is_constant() { return this->IsBox(); } bool is_union() { return this->IsFixedArray(); } int as_bitset() { return Smi::cast(this)->value(); } Handle as_class() { return Handle::cast(handle()); } Handle as_constant() { Handle box = Handle::cast(handle()); return v8::internal::handle(box->value(), box->GetIsolate()); } Handle as_union() { return Handle::cast(handle()); } Handle handle() { return handle_via_isolate_of(this); } Handle handle_via_isolate_of(Type* type) { ASSERT(type->IsHeapObject()); return v8::internal::handle(this, HeapObject::cast(type)->GetIsolate()); } static Type* from_bitset(int bitset) { return static_cast(Object::cast(Smi::FromInt(bitset))); } static Type* from_handle(Handle handle) { return static_cast(Object::cast(*handle)); } static Handle union_get(Handle unioned, int i) { Type* type = static_cast(unioned->get(i)); ASSERT(!type->is_union()); return type->handle_via_isolate_of(from_handle(unioned)); } int LubBitset(); // least upper bound that's a bitset int GlbBitset(); // greatest lower bound that's a bitset bool InUnion(Handle unioned, int current_size); int ExtendUnion(Handle unioned, int current_size); int ExtendIntersection( Handle unioned, Handle type, int current_size); }; } } // namespace v8::internal #endif // V8_TYPES_H_