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