Home | History | Annotate | Download | only in src
      1 // Copyright 2013 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 #include "types.h"
     29 #include "string-stream.h"
     30 
     31 namespace v8 {
     32 namespace internal {
     33 
     34 int Type::NumClasses() {
     35   if (is_class()) {
     36     return 1;
     37   } else if (is_union()) {
     38     Handle<Unioned> unioned = as_union();
     39     int result = 0;
     40     for (int i = 0; i < unioned->length(); ++i) {
     41       if (union_get(unioned, i)->is_class()) ++result;
     42     }
     43     return result;
     44   } else {
     45     return 0;
     46   }
     47 }
     48 
     49 
     50 int Type::NumConstants() {
     51   if (is_constant()) {
     52     return 1;
     53   } else if (is_union()) {
     54     Handle<Unioned> unioned = as_union();
     55     int result = 0;
     56     for (int i = 0; i < unioned->length(); ++i) {
     57       if (union_get(unioned, i)->is_constant()) ++result;
     58     }
     59     return result;
     60   } else {
     61     return 0;
     62   }
     63 }
     64 
     65 
     66 template<class T>
     67 Handle<Type> Type::Iterator<T>::get_type() {
     68   ASSERT(!Done());
     69   return type_->is_union() ? union_get(type_->as_union(), index_) : type_;
     70 }
     71 
     72 template<>
     73 Handle<i::Map> Type::Iterator<i::Map>::Current() {
     74   return get_type()->as_class();
     75 }
     76 
     77 template<>
     78 Handle<i::Object> Type::Iterator<i::Object>::Current() {
     79   return get_type()->as_constant();
     80 }
     81 
     82 
     83 template<>
     84 bool Type::Iterator<i::Map>::matches(Handle<Type> type) {
     85   return type->is_class();
     86 }
     87 
     88 template<>
     89 bool Type::Iterator<i::Object>::matches(Handle<Type> type) {
     90   return type->is_constant();
     91 }
     92 
     93 
     94 template<class T>
     95 void Type::Iterator<T>::Advance() {
     96   ++index_;
     97   if (type_->is_union()) {
     98     Handle<Unioned> unioned = type_->as_union();
     99     for (; index_ < unioned->length(); ++index_) {
    100       if (matches(union_get(unioned, index_))) return;
    101     }
    102   } else if (index_ == 0 && matches(type_)) {
    103     return;
    104   }
    105   index_ = -1;
    106 }
    107 
    108 template class Type::Iterator<i::Map>;
    109 template class Type::Iterator<i::Object>;
    110 
    111 
    112 // Get the smallest bitset subsuming this type.
    113 int Type::LubBitset() {
    114   if (this->is_bitset()) {
    115     return this->as_bitset();
    116   } else if (this->is_union()) {
    117     Handle<Unioned> unioned = this->as_union();
    118     int bitset = kNone;
    119     for (int i = 0; i < unioned->length(); ++i) {
    120       bitset |= union_get(unioned, i)->LubBitset();
    121     }
    122     return bitset;
    123   } else if (this->is_class()) {
    124     return LubBitset(*this->as_class());
    125   } else {
    126     return LubBitset(*this->as_constant());
    127   }
    128 }
    129 
    130 
    131 int Type::LubBitset(i::Object* value) {
    132   if (value->IsSmi()) return kSmi;
    133   i::Map* map = i::HeapObject::cast(value)->map();
    134   if (map->instance_type() == HEAP_NUMBER_TYPE) {
    135     int32_t i;
    136     uint32_t u;
    137     if (value->ToInt32(&i)) return Smi::IsValid(i) ? kSmi : kOtherSigned32;
    138     if (value->ToUint32(&u)) return kUnsigned32;
    139     return kDouble;
    140   }
    141   if (map->instance_type() == ODDBALL_TYPE) {
    142     if (value->IsUndefined()) return kUndefined;
    143     if (value->IsNull()) return kNull;
    144     if (value->IsBoolean()) return kBoolean;
    145     if (value->IsTheHole()) return kAny;  // TODO(rossberg): kNone?
    146     UNREACHABLE();
    147   }
    148   return Type::LubBitset(map);
    149 }
    150 
    151 
    152 int Type::LubBitset(i::Map* map) {
    153   switch (map->instance_type()) {
    154     case STRING_TYPE:
    155     case ASCII_STRING_TYPE:
    156     case CONS_STRING_TYPE:
    157     case CONS_ASCII_STRING_TYPE:
    158     case SLICED_STRING_TYPE:
    159     case SLICED_ASCII_STRING_TYPE:
    160     case EXTERNAL_STRING_TYPE:
    161     case EXTERNAL_ASCII_STRING_TYPE:
    162     case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
    163     case SHORT_EXTERNAL_STRING_TYPE:
    164     case SHORT_EXTERNAL_ASCII_STRING_TYPE:
    165     case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
    166     case INTERNALIZED_STRING_TYPE:
    167     case ASCII_INTERNALIZED_STRING_TYPE:
    168     case CONS_INTERNALIZED_STRING_TYPE:
    169     case CONS_ASCII_INTERNALIZED_STRING_TYPE:
    170     case EXTERNAL_INTERNALIZED_STRING_TYPE:
    171     case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
    172     case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
    173     case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
    174     case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
    175     case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
    176       return kString;
    177     case SYMBOL_TYPE:
    178       return kSymbol;
    179     case ODDBALL_TYPE:
    180       return kOddball;
    181     case HEAP_NUMBER_TYPE:
    182       return kDouble;
    183     case JS_VALUE_TYPE:
    184     case JS_DATE_TYPE:
    185     case JS_OBJECT_TYPE:
    186     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
    187     case JS_GENERATOR_OBJECT_TYPE:
    188     case JS_MODULE_TYPE:
    189     case JS_GLOBAL_OBJECT_TYPE:
    190     case JS_BUILTINS_OBJECT_TYPE:
    191     case JS_GLOBAL_PROXY_TYPE:
    192     case JS_ARRAY_BUFFER_TYPE:
    193     case JS_TYPED_ARRAY_TYPE:
    194     case JS_DATA_VIEW_TYPE:
    195     case JS_SET_TYPE:
    196     case JS_MAP_TYPE:
    197     case JS_WEAK_MAP_TYPE:
    198     case JS_WEAK_SET_TYPE:
    199       if (map->is_undetectable()) return kUndetectable;
    200       return kOtherObject;
    201     case JS_ARRAY_TYPE:
    202       return kArray;
    203     case JS_FUNCTION_TYPE:
    204       return kFunction;
    205     case JS_REGEXP_TYPE:
    206       return kRegExp;
    207     case JS_PROXY_TYPE:
    208     case JS_FUNCTION_PROXY_TYPE:
    209       return kProxy;
    210     case MAP_TYPE:
    211       // When compiling stub templates, the meta map is used as a place holder
    212       // for the actual map with which the template is later instantiated.
    213       // We treat it as a kind of type variable whose upper bound is Any.
    214       // TODO(rossberg): for caching of CompareNilIC stubs to work correctly,
    215       // we must exclude Undetectable here. This makes no sense, really,
    216       // because it means that the template isn't actually parametric.
    217       // Also, it doesn't apply elsewhere. 8-(
    218       // We ought to find a cleaner solution for compiling stubs parameterised
    219       // over type or class variables, esp ones with bounds...
    220       return kDetectable;
    221     case DECLARED_ACCESSOR_INFO_TYPE:
    222     case EXECUTABLE_ACCESSOR_INFO_TYPE:
    223     case ACCESSOR_PAIR_TYPE:
    224     case FIXED_ARRAY_TYPE:
    225       return kInternal;
    226     default:
    227       UNREACHABLE();
    228       return kNone;
    229   }
    230 }
    231 
    232 
    233 // Get the largest bitset subsumed by this type.
    234 int Type::GlbBitset() {
    235   if (this->is_bitset()) {
    236     return this->as_bitset();
    237   } else if (this->is_union()) {
    238     // All but the first are non-bitsets and thus would yield kNone anyway.
    239     return union_get(this->as_union(), 0)->GlbBitset();
    240   } else {
    241     return kNone;
    242   }
    243 }
    244 
    245 
    246 // Most precise _current_ type of a value (usually its class).
    247 Type* Type::OfCurrently(Handle<i::Object> value) {
    248   if (value->IsSmi()) return Smi();
    249   i::Map* map = i::HeapObject::cast(*value)->map();
    250   if (map->instance_type() == HEAP_NUMBER_TYPE ||
    251       map->instance_type() == ODDBALL_TYPE) {
    252     return Type::Of(value);
    253   }
    254   return Class(i::handle(map));
    255 }
    256 
    257 
    258 // Check this <= that.
    259 bool Type::SlowIs(Type* that) {
    260   // Fast path for bitsets.
    261   if (this->is_none()) return true;
    262   if (that->is_bitset()) {
    263     return (this->LubBitset() | that->as_bitset()) == that->as_bitset();
    264   }
    265 
    266   if (that->is_class()) {
    267     return this->is_class() && *this->as_class() == *that->as_class();
    268   }
    269   if (that->is_constant()) {
    270     return this->is_constant() && *this->as_constant() == *that->as_constant();
    271   }
    272 
    273   // (T1 \/ ... \/ Tn) <= T  <=>  (T1 <= T) /\ ... /\ (Tn <= T)
    274   if (this->is_union()) {
    275     Handle<Unioned> unioned = this->as_union();
    276     for (int i = 0; i < unioned->length(); ++i) {
    277       Handle<Type> this_i = union_get(unioned, i);
    278       if (!this_i->Is(that)) return false;
    279     }
    280     return true;
    281   }
    282 
    283   // T <= (T1 \/ ... \/ Tn)  <=>  (T <= T1) \/ ... \/ (T <= Tn)
    284   // (iff T is not a union)
    285   ASSERT(!this->is_union());
    286   if (that->is_union()) {
    287     Handle<Unioned> unioned = that->as_union();
    288     for (int i = 0; i < unioned->length(); ++i) {
    289       Handle<Type> that_i = union_get(unioned, i);
    290       if (this->Is(that_i)) return true;
    291       if (this->is_bitset()) break;  // Fast fail, no other field is a bitset.
    292     }
    293     return false;
    294   }
    295 
    296   return false;
    297 }
    298 
    299 
    300 bool Type::IsCurrently(Type* that) {
    301   return this->Is(that) ||
    302       (this->is_constant() && that->is_class() &&
    303        this->as_constant()->IsHeapObject() &&
    304        i::HeapObject::cast(*this->as_constant())->map() == *that->as_class());
    305 }
    306 
    307 
    308 // Check this overlaps that.
    309 bool Type::Maybe(Type* that) {
    310   // Fast path for bitsets.
    311   if (this->is_bitset()) {
    312     return (this->as_bitset() & that->LubBitset()) != 0;
    313   }
    314   if (that->is_bitset()) {
    315     return (this->LubBitset() & that->as_bitset()) != 0;
    316   }
    317 
    318   // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T)
    319   if (this->is_union()) {
    320     Handle<Unioned> unioned = this->as_union();
    321     for (int i = 0; i < unioned->length(); ++i) {
    322       Handle<Type> this_i = union_get(unioned, i);
    323       if (this_i->Maybe(that)) return true;
    324     }
    325     return false;
    326   }
    327 
    328   // T overlaps (T1 \/ ... \/ Tn) <=> (T overlaps T1) \/ ... \/ (T overlaps Tn)
    329   if (that->is_union()) {
    330     Handle<Unioned> unioned = that->as_union();
    331     for (int i = 0; i < unioned->length(); ++i) {
    332       Handle<Type> that_i = union_get(unioned, i);
    333       if (this->Maybe(that_i)) return true;
    334     }
    335     return false;
    336   }
    337 
    338   ASSERT(!that->is_union());
    339   if (this->is_class()) {
    340     return that->is_class() && *this->as_class() == *that->as_class();
    341   }
    342   if (this->is_constant()) {
    343     return that->is_constant() && *this->as_constant() == *that->as_constant();
    344   }
    345 
    346   return false;
    347 }
    348 
    349 
    350 bool Type::InUnion(Handle<Unioned> unioned, int current_size) {
    351   ASSERT(!this->is_union());
    352   for (int i = 0; i < current_size; ++i) {
    353     Handle<Type> type = union_get(unioned, i);
    354     if (this->Is(type)) return true;
    355   }
    356   return false;
    357 }
    358 
    359 
    360 // Get non-bitsets from this which are not subsumed by union, store at unioned,
    361 // starting at index. Returns updated index.
    362 int Type::ExtendUnion(Handle<Unioned> result, int current_size) {
    363   int old_size = current_size;
    364   if (this->is_class() || this->is_constant()) {
    365     if (!this->InUnion(result, old_size)) result->set(current_size++, this);
    366   } else if (this->is_union()) {
    367     Handle<Unioned> unioned = this->as_union();
    368     for (int i = 0; i < unioned->length(); ++i) {
    369       Handle<Type> type = union_get(unioned, i);
    370       ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0))));
    371       if (type->is_bitset()) continue;
    372       if (!type->InUnion(result, old_size)) result->set(current_size++, *type);
    373     }
    374   }
    375   return current_size;
    376 }
    377 
    378 
    379 // Union is O(1) on simple bit unions, but O(n*m) on structured unions.
    380 // TODO(rossberg): Should we use object sets somehow? Is it worth it?
    381 Type* Type::Union(Handle<Type> type1, Handle<Type> type2) {
    382   // Fast case: bit sets.
    383   if (type1->is_bitset() && type2->is_bitset()) {
    384     return from_bitset(type1->as_bitset() | type2->as_bitset());
    385   }
    386 
    387   // Fast case: top or bottom types.
    388   if (type1->SameValue(Type::Any())) return *type1;
    389   if (type2->SameValue(Type::Any())) return *type2;
    390   if (type1->SameValue(Type::None())) return *type2;
    391   if (type2->SameValue(Type::None())) return *type1;
    392 
    393   // Semi-fast case: Unioned objects are neither involved nor produced.
    394   if (!(type1->is_union() || type2->is_union())) {
    395     if (type1->Is(type2)) return *type2;
    396     if (type2->Is(type1)) return *type1;
    397   }
    398 
    399   // Slow case: may need to produce a Unioned object.
    400   Isolate* isolate = NULL;
    401   int size = type1->is_bitset() || type2->is_bitset() ? 1 : 0;
    402   if (!type1->is_bitset()) {
    403     isolate = i::HeapObject::cast(*type1)->GetIsolate();
    404     size += (type1->is_union() ? type1->as_union()->length() : 1);
    405   }
    406   if (!type2->is_bitset()) {
    407     isolate = i::HeapObject::cast(*type2)->GetIsolate();
    408     size += (type2->is_union() ? type2->as_union()->length() : 1);
    409   }
    410   ASSERT(isolate != NULL);
    411   ASSERT(size >= 2);
    412   Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size);
    413   size = 0;
    414 
    415   int bitset = type1->GlbBitset() | type2->GlbBitset();
    416   if (bitset != kNone) unioned->set(size++, from_bitset(bitset));
    417   size = type1->ExtendUnion(unioned, size);
    418   size = type2->ExtendUnion(unioned, size);
    419 
    420   if (size == 1) {
    421     return *union_get(unioned, 0);
    422   } else if (size == unioned->length()) {
    423     return from_handle(unioned);
    424   }
    425 
    426   // There was an overlap. Copy to smaller union.
    427   Handle<Unioned> result = isolate->factory()->NewFixedArray(size);
    428   for (int i = 0; i < size; ++i) result->set(i, unioned->get(i));
    429   return from_handle(result);
    430 }
    431 
    432 
    433 // Get non-bitsets from this which are also in that, store at unioned,
    434 // starting at index. Returns updated index.
    435 int Type::ExtendIntersection(
    436     Handle<Unioned> result, Handle<Type> that, int current_size) {
    437   int old_size = current_size;
    438   if (this->is_class() || this->is_constant()) {
    439     if (this->Is(that) && !this->InUnion(result, old_size))
    440       result->set(current_size++, this);
    441   } else if (this->is_union()) {
    442     Handle<Unioned> unioned = this->as_union();
    443     for (int i = 0; i < unioned->length(); ++i) {
    444       Handle<Type> type = union_get(unioned, i);
    445       ASSERT(i == 0 || !(type->is_bitset() || type->Is(union_get(unioned, 0))));
    446       if (type->is_bitset()) continue;
    447       if (type->Is(that) && !type->InUnion(result, old_size))
    448         result->set(current_size++, *type);
    449     }
    450   }
    451   return current_size;
    452 }
    453 
    454 
    455 // Intersection is O(1) on simple bit unions, but O(n*m) on structured unions.
    456 // TODO(rossberg): Should we use object sets somehow? Is it worth it?
    457 Type* Type::Intersect(Handle<Type> type1, Handle<Type> type2) {
    458   // Fast case: bit sets.
    459   if (type1->is_bitset() && type2->is_bitset()) {
    460     return from_bitset(type1->as_bitset() & type2->as_bitset());
    461   }
    462 
    463   // Fast case: top or bottom types.
    464   if (type1->SameValue(Type::None())) return *type1;
    465   if (type2->SameValue(Type::None())) return *type2;
    466   if (type1->SameValue(Type::Any())) return *type2;
    467   if (type2->SameValue(Type::Any())) return *type1;
    468 
    469   // Semi-fast case: Unioned objects are neither involved nor produced.
    470   if (!(type1->is_union() || type2->is_union())) {
    471     if (type1->Is(type2)) return *type1;
    472     if (type2->Is(type1)) return *type2;
    473   }
    474 
    475   // Slow case: may need to produce a Unioned object.
    476   Isolate* isolate = NULL;
    477   int size = 0;
    478   if (!type1->is_bitset()) {
    479     isolate = i::HeapObject::cast(*type1)->GetIsolate();
    480     size = (type1->is_union() ? type1->as_union()->length() : 2);
    481   }
    482   if (!type2->is_bitset()) {
    483     isolate = i::HeapObject::cast(*type2)->GetIsolate();
    484     int size2 = (type2->is_union() ? type2->as_union()->length() : 2);
    485     size = (size == 0 ? size2 : Min(size, size2));
    486   }
    487   ASSERT(isolate != NULL);
    488   ASSERT(size >= 2);
    489   Handle<Unioned> unioned = isolate->factory()->NewFixedArray(size);
    490   size = 0;
    491 
    492   int bitset = type1->GlbBitset() & type2->GlbBitset();
    493   if (bitset != kNone) unioned->set(size++, from_bitset(bitset));
    494   size = type1->ExtendIntersection(unioned, type2, size);
    495   size = type2->ExtendIntersection(unioned, type1, size);
    496 
    497   if (size == 0) {
    498     return None();
    499   } else if (size == 1) {
    500     return *union_get(unioned, 0);
    501   } else if (size == unioned->length()) {
    502     return from_handle(unioned);
    503   }
    504 
    505   // There were dropped cases. Copy to smaller union.
    506   Handle<Unioned> result = isolate->factory()->NewFixedArray(size);
    507   for (int i = 0; i < size; ++i) result->set(i, unioned->get(i));
    508   return from_handle(result);
    509 }
    510 
    511 
    512 Type* Type::Optional(Handle<Type> type) {
    513   return type->is_bitset()
    514       ? from_bitset(type->as_bitset() | kUndefined)
    515       : Union(type, Undefined()->handle_via_isolate_of(*type));
    516 }
    517 
    518 
    519 Representation Representation::FromType(Handle<Type> type) {
    520   if (type->Is(Type::None())) return Representation::None();
    521   if (type->Is(Type::Smi())) return Representation::Smi();
    522   if (type->Is(Type::Signed32())) return Representation::Integer32();
    523   if (type->Is(Type::Number())) return Representation::Double();
    524   return Representation::Tagged();
    525 }
    526 
    527 
    528 #ifdef OBJECT_PRINT
    529 void Type::TypePrint() {
    530   TypePrint(stdout);
    531   PrintF(stdout, "\n");
    532   Flush(stdout);
    533 }
    534 
    535 
    536 const char* Type::bitset_name(int bitset) {
    537   switch (bitset) {
    538     #define PRINT_COMPOSED_TYPE(type, value) case k##type: return #type;
    539     BITSET_TYPE_LIST(PRINT_COMPOSED_TYPE)
    540     #undef PRINT_COMPOSED_TYPE
    541     default:
    542       return NULL;
    543   }
    544 }
    545 
    546 
    547 void Type::TypePrint(FILE* out) {
    548   if (is_bitset()) {
    549     int bitset = as_bitset();
    550     const char* name = bitset_name(bitset);
    551     if (name != NULL) {
    552       PrintF(out, "%s", name);
    553     } else {
    554       bool is_first = true;
    555       PrintF(out, "(");
    556       for (int mask = 1; mask != 0; mask = mask << 1) {
    557         if ((bitset & mask) != 0) {
    558           if (!is_first) PrintF(out, " | ");
    559           is_first = false;
    560           PrintF(out, "%s", bitset_name(mask));
    561         }
    562       }
    563       PrintF(out, ")");
    564     }
    565   } else if (is_constant()) {
    566     PrintF(out, "Constant(%p : ", static_cast<void*>(*as_constant()));
    567     from_bitset(LubBitset())->TypePrint(out);
    568     PrintF(")");
    569   } else if (is_class()) {
    570     PrintF(out, "Class(%p < ", static_cast<void*>(*as_class()));
    571     from_bitset(LubBitset())->TypePrint(out);
    572     PrintF(")");
    573   } else if (is_union()) {
    574     PrintF(out, "(");
    575     Handle<Unioned> unioned = as_union();
    576     for (int i = 0; i < unioned->length(); ++i) {
    577       Handle<Type> type_i = union_get(unioned, i);
    578       if (i > 0) PrintF(out, " | ");
    579       type_i->TypePrint(out);
    580     }
    581     PrintF(out, ")");
    582   }
    583 }
    584 #endif
    585 
    586 
    587 } }  // namespace v8::internal
    588