1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "src/ostreams.h"
8 #include "src/types-inl.h"
14 // NOTE: If code is marked as being a "shortcut", this means that removing
15 // the code won't affect the semantics of the surrounding function definition.
18 // -----------------------------------------------------------------------------
19 // Range-related helper functions.
21 // The result may be invalid (max < min).
22 template<class Config>
23 typename TypeImpl<Config>::Limits TypeImpl<Config>::Intersect(
24 Limits lhs, Limits rhs) {
25 DisallowHeapAllocation no_allocation;
27 if (lhs.min->Number() < rhs.min->Number()) result.min = rhs.min;
28 if (lhs.max->Number() > rhs.max->Number()) result.max = rhs.max;
33 template<class Config>
34 typename TypeImpl<Config>::Limits TypeImpl<Config>::Union(
35 Limits lhs, Limits rhs) {
36 DisallowHeapAllocation no_allocation;
38 if (lhs.min->Number() > rhs.min->Number()) result.min = rhs.min;
39 if (lhs.max->Number() < rhs.max->Number()) result.max = rhs.max;
44 template<class Config>
45 bool TypeImpl<Config>::Overlap(
46 typename TypeImpl<Config>::RangeType* lhs,
47 typename TypeImpl<Config>::RangeType* rhs) {
48 DisallowHeapAllocation no_allocation;
49 typename TypeImpl<Config>::Limits lim = Intersect(Limits(lhs), Limits(rhs));
50 return lim.min->Number() <= lim.max->Number();
54 template<class Config>
55 bool TypeImpl<Config>::Contains(
56 typename TypeImpl<Config>::RangeType* lhs,
57 typename TypeImpl<Config>::RangeType* rhs) {
58 DisallowHeapAllocation no_allocation;
59 return lhs->Min()->Number() <= rhs->Min()->Number()
60 && rhs->Max()->Number() <= lhs->Max()->Number();
64 template<class Config>
65 bool TypeImpl<Config>::Contains(
66 typename TypeImpl<Config>::RangeType* range, i::Object* val) {
67 DisallowHeapAllocation no_allocation;
69 && range->Min()->Number() <= val->Number()
70 && val->Number() <= range->Max()->Number();
74 // -----------------------------------------------------------------------------
75 // Min and Max computation.
77 template<class Config>
78 double TypeImpl<Config>::Min() {
79 DCHECK(this->Is(Number()));
80 if (this->IsBitset()) return BitsetType::Min(this->AsBitset());
81 if (this->IsUnion()) {
82 double min = +V8_INFINITY;
83 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
84 min = std::min(min, this->AsUnion()->Get(i)->Min());
88 if (this->IsRange()) return this->AsRange()->Min()->Number();
89 if (this->IsConstant()) return this->AsConstant()->Value()->Number();
95 template<class Config>
96 double TypeImpl<Config>::Max() {
97 DCHECK(this->Is(Number()));
98 if (this->IsBitset()) return BitsetType::Max(this->AsBitset());
99 if (this->IsUnion()) {
100 double max = -V8_INFINITY;
101 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
102 max = std::max(max, this->AsUnion()->Get(i)->Max());
106 if (this->IsRange()) return this->AsRange()->Max()->Number();
107 if (this->IsConstant()) return this->AsConstant()->Value()->Number();
113 // -----------------------------------------------------------------------------
114 // Glb and lub computation.
117 // The largest bitset subsumed by this type.
118 template<class Config>
119 typename TypeImpl<Config>::bitset
120 TypeImpl<Config>::BitsetType::Glb(TypeImpl* type) {
121 DisallowHeapAllocation no_allocation;
122 if (type->IsBitset()) {
123 return type->AsBitset();
124 } else if (type->IsUnion()) {
125 SLOW_DCHECK(type->AsUnion()->Wellformed());
126 return type->AsUnion()->Get(0)->BitsetGlb(); // Shortcut.
127 // (The remaining BitsetGlb's are None anyway).
134 // The smallest bitset subsuming this type.
135 template<class Config>
136 typename TypeImpl<Config>::bitset
137 TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
138 DisallowHeapAllocation no_allocation;
139 if (type->IsBitset()) return type->AsBitset();
140 if (type->IsUnion()) {
142 for (int i = 0, n = type->AsUnion()->Length(); i < n; ++i) {
143 bitset |= type->AsUnion()->Get(i)->BitsetLub();
147 if (type->IsClass()) {
148 // Little hack to avoid the need for a region for handlification here...
149 return Config::is_class(type) ? Lub(*Config::as_class(type)) :
150 type->AsClass()->Bound(NULL)->AsBitset();
152 if (type->IsConstant()) return type->AsConstant()->Bound()->AsBitset();
153 if (type->IsRange()) return type->AsRange()->BitsetLub();
154 if (type->IsContext()) return kInternal & kTaggedPtr;
155 if (type->IsArray()) return kArray;
156 if (type->IsFunction()) return kFunction;
162 template<class Config>
163 typename TypeImpl<Config>::bitset
164 TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
165 DisallowHeapAllocation no_allocation;
166 switch (map->instance_type()) {
168 case ONE_BYTE_STRING_TYPE:
169 case CONS_STRING_TYPE:
170 case CONS_ONE_BYTE_STRING_TYPE:
171 case SLICED_STRING_TYPE:
172 case SLICED_ONE_BYTE_STRING_TYPE:
173 case EXTERNAL_STRING_TYPE:
174 case EXTERNAL_ONE_BYTE_STRING_TYPE:
175 case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
176 case SHORT_EXTERNAL_STRING_TYPE:
177 case SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE:
178 case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
180 case INTERNALIZED_STRING_TYPE:
181 case ONE_BYTE_INTERNALIZED_STRING_TYPE:
182 case EXTERNAL_INTERNALIZED_STRING_TYPE:
183 case EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
184 case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
185 case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
186 case SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
187 case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
188 return kInternalizedString;
192 Heap* heap = map->GetHeap();
193 if (map == heap->undefined_map()) return kUndefined;
194 if (map == heap->null_map()) return kNull;
195 if (map == heap->boolean_map()) return kBoolean;
196 DCHECK(map == heap->the_hole_map() ||
197 map == heap->uninitialized_map() ||
198 map == heap->no_interceptor_result_sentinel_map() ||
199 map == heap->termination_exception_map() ||
200 map == heap->arguments_marker_map());
201 return kInternal & kTaggedPtr;
203 case HEAP_NUMBER_TYPE:
204 return kNumber & kTaggedPtr;
208 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
209 case JS_GENERATOR_OBJECT_TYPE:
211 case JS_GLOBAL_OBJECT_TYPE:
212 case JS_BUILTINS_OBJECT_TYPE:
213 case JS_GLOBAL_PROXY_TYPE:
214 case JS_ARRAY_BUFFER_TYPE:
215 case JS_TYPED_ARRAY_TYPE:
216 case JS_DATA_VIEW_TYPE:
219 case JS_SET_ITERATOR_TYPE:
220 case JS_MAP_ITERATOR_TYPE:
221 case JS_WEAK_MAP_TYPE:
222 case JS_WEAK_SET_TYPE:
226 if (map->is_undetectable()) return kUndetectable;
230 case JS_FUNCTION_TYPE:
235 case JS_FUNCTION_PROXY_TYPE:
238 // When compiling stub templates, the meta map is used as a place holder
239 // for the actual map with which the template is later instantiated.
240 // We treat it as a kind of type variable whose upper bound is Any.
241 // TODO(rossberg): for caching of CompareNilIC stubs to work correctly,
242 // we must exclude Undetectable here. This makes no sense, really,
243 // because it means that the template isn't actually parametric.
244 // Also, it doesn't apply elsewhere. 8-(
245 // We ought to find a cleaner solution for compiling stubs parameterised
246 // over type or class variables, esp ones with bounds...
248 case DECLARED_ACCESSOR_INFO_TYPE:
249 case EXECUTABLE_ACCESSOR_INFO_TYPE:
250 case SHARED_FUNCTION_INFO_TYPE:
251 case ACCESSOR_PAIR_TYPE:
252 case FIXED_ARRAY_TYPE:
253 case BYTE_ARRAY_TYPE:
256 return kInternal & kTaggedPtr;
264 template<class Config>
265 typename TypeImpl<Config>::bitset
266 TypeImpl<Config>::BitsetType::Lub(i::Object* value) {
267 DisallowHeapAllocation no_allocation;
268 if (value->IsNumber()) {
269 return Lub(value->Number()) & (value->IsSmi() ? kTaggedInt : kTaggedPtr);
271 return Lub(i::HeapObject::cast(value)->map());
275 template<class Config>
276 typename TypeImpl<Config>::bitset
277 TypeImpl<Config>::BitsetType::Lub(double value) {
278 DisallowHeapAllocation no_allocation;
279 if (i::IsMinusZero(value)) return kMinusZero;
280 if (std::isnan(value)) return kNaN;
281 if (IsUint32Double(value) || IsInt32Double(value)) return Lub(value, value);
286 // Minimum values of regular numeric bitsets when SmiValuesAre31Bits.
287 template<class Config>
288 const typename TypeImpl<Config>::BitsetType::BitsetMin
289 TypeImpl<Config>::BitsetType::BitsetMins31[] = {
290 {kOtherNumber, -V8_INFINITY},
291 {kOtherSigned32, kMinInt},
292 {kOtherSignedSmall, -0x40000000},
294 {kOtherUnsigned31, 0x40000000},
295 {kOtherUnsigned32, 0x80000000},
296 {kOtherNumber, static_cast<double>(kMaxUInt32) + 1}
300 // Minimum values of regular numeric bitsets when SmiValuesAre32Bits.
301 // OtherSigned32 and OtherUnsigned31 are empty (see the diagrams in types.h).
302 template<class Config>
303 const typename TypeImpl<Config>::BitsetType::BitsetMin
304 TypeImpl<Config>::BitsetType::BitsetMins32[] = {
305 {kOtherNumber, -V8_INFINITY},
306 {kOtherSignedSmall, kMinInt},
308 {kOtherUnsigned32, 0x80000000},
309 {kOtherNumber, static_cast<double>(kMaxUInt32) + 1}
313 template<class Config>
314 typename TypeImpl<Config>::bitset
315 TypeImpl<Config>::BitsetType::Lub(double min, double max) {
316 DisallowHeapAllocation no_allocation;
318 const BitsetMin* mins = BitsetMins();
320 for (size_t i = 1; i < BitsetMinsSize(); ++i) {
321 if (min < mins[i].min) {
322 lub |= mins[i-1].bits;
323 if (max < mins[i].min) return lub;
326 return lub |= mins[BitsetMinsSize()-1].bits;
330 template<class Config>
331 double TypeImpl<Config>::BitsetType::Min(bitset bits) {
332 DisallowHeapAllocation no_allocation;
333 DCHECK(Is(bits, kNumber));
334 const BitsetMin* mins = BitsetMins();
335 bool mz = SEMANTIC(bits & kMinusZero);
336 for (size_t i = 0; i < BitsetMinsSize(); ++i) {
337 if (Is(SEMANTIC(mins[i].bits), bits)) {
338 return mz ? std::min(0.0, mins[i].min) : mins[i].min;
342 return base::OS::nan_value();
346 template<class Config>
347 double TypeImpl<Config>::BitsetType::Max(bitset bits) {
348 DisallowHeapAllocation no_allocation;
349 DCHECK(Is(bits, kNumber));
350 const BitsetMin* mins = BitsetMins();
351 bool mz = SEMANTIC(bits & kMinusZero);
352 if (BitsetType::Is(mins[BitsetMinsSize()-1].bits, bits)) {
355 for (size_t i = BitsetMinsSize()-1; i-- > 0; ) {
356 if (Is(SEMANTIC(mins[i].bits), bits)) {
358 std::max(0.0, mins[i+1].min - 1) : mins[i+1].min - 1;
362 return base::OS::nan_value();
366 // -----------------------------------------------------------------------------
370 template<class Config>
371 bool TypeImpl<Config>::SimplyEquals(TypeImpl* that) {
372 DisallowHeapAllocation no_allocation;
373 if (this->IsClass()) {
374 return that->IsClass()
375 && *this->AsClass()->Map() == *that->AsClass()->Map();
377 if (this->IsConstant()) {
378 return that->IsConstant()
379 && *this->AsConstant()->Value() == *that->AsConstant()->Value();
381 if (this->IsContext()) {
382 return that->IsContext()
383 && this->AsContext()->Outer()->Equals(that->AsContext()->Outer());
385 if (this->IsArray()) {
386 return that->IsArray()
387 && this->AsArray()->Element()->Equals(that->AsArray()->Element());
389 if (this->IsFunction()) {
390 if (!that->IsFunction()) return false;
391 FunctionType* this_fun = this->AsFunction();
392 FunctionType* that_fun = that->AsFunction();
393 if (this_fun->Arity() != that_fun->Arity() ||
394 !this_fun->Result()->Equals(that_fun->Result()) ||
395 !this_fun->Receiver()->Equals(that_fun->Receiver())) {
398 for (int i = 0, n = this_fun->Arity(); i < n; ++i) {
399 if (!this_fun->Parameter(i)->Equals(that_fun->Parameter(i))) return false;
408 // Check if [this] <= [that].
409 template<class Config>
410 bool TypeImpl<Config>::SlowIs(TypeImpl* that) {
411 DisallowHeapAllocation no_allocation;
413 if (that->IsBitset()) {
414 return BitsetType::Is(this->BitsetLub(), that->AsBitset());
416 if (this->IsBitset()) {
417 return BitsetType::Is(this->AsBitset(), that->BitsetGlb());
420 // (T1 \/ ... \/ Tn) <= T if (T1 <= T) /\ ... /\ (Tn <= T)
421 if (this->IsUnion()) {
422 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
423 if (!this->AsUnion()->Get(i)->Is(that)) return false;
428 // T <= (T1 \/ ... \/ Tn) if (T <= T1) \/ ... \/ (T <= Tn)
429 if (that->IsUnion()) {
430 for (int i = 0, n = that->AsUnion()->Length(); i < n; ++i) {
431 if (this->Is(that->AsUnion()->Get(i))) return true;
432 if (i > 1 && this->IsRange()) return false; // Shortcut.
437 if (that->IsRange()) {
438 return (this->IsRange() && Contains(that->AsRange(), this->AsRange()))
439 || (this->IsConstant() &&
440 Contains(that->AsRange(), *this->AsConstant()->Value()));
442 if (this->IsRange()) return false;
444 return this->SimplyEquals(that);
448 template<class Config>
449 bool TypeImpl<Config>::NowIs(TypeImpl* that) {
450 DisallowHeapAllocation no_allocation;
452 // TODO(rossberg): this is incorrect for
453 // Union(Constant(V), T)->NowIs(Class(M))
454 // but fuzzing does not cover that!
455 if (this->IsConstant()) {
456 i::Object* object = *this->AsConstant()->Value();
457 if (object->IsHeapObject()) {
458 i::Map* map = i::HeapObject::cast(object)->map();
459 for (Iterator<i::Map> it = that->Classes(); !it.Done(); it.Advance()) {
460 if (*it.Current() == map) return true;
464 return this->Is(that);
468 // Check if [this] contains only (currently) stable classes.
469 template<class Config>
470 bool TypeImpl<Config>::NowStable() {
471 DisallowHeapAllocation no_allocation;
472 for (Iterator<i::Map> it = this->Classes(); !it.Done(); it.Advance()) {
473 if (!it.Current()->is_stable()) return false;
479 // Check if [this] and [that] overlap.
480 template<class Config>
481 bool TypeImpl<Config>::Maybe(TypeImpl* that) {
482 DisallowHeapAllocation no_allocation;
484 // (T1 \/ ... \/ Tn) overlaps T if (T1 overlaps T) \/ ... \/ (Tn overlaps T)
485 if (this->IsUnion()) {
486 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
487 if (this->AsUnion()->Get(i)->Maybe(that)) return true;
492 // T overlaps (T1 \/ ... \/ Tn) if (T overlaps T1) \/ ... \/ (T overlaps Tn)
493 if (that->IsUnion()) {
494 for (int i = 0, n = that->AsUnion()->Length(); i < n; ++i) {
495 if (this->Maybe(that->AsUnion()->Get(i))) return true;
500 if (!BitsetType::IsInhabited(this->BitsetLub() & that->BitsetLub()))
502 if (this->IsBitset() || that->IsBitset()) return true;
504 if (this->IsClass() != that->IsClass()) return true;
506 if (this->IsRange()) {
507 if (that->IsConstant()) {
508 return Contains(this->AsRange(), *that->AsConstant()->Value());
510 return that->IsRange() && Overlap(this->AsRange(), that->AsRange());
512 if (that->IsRange()) {
513 if (this->IsConstant()) {
514 return Contains(that->AsRange(), *this->AsConstant()->Value());
516 return this->IsRange() && Overlap(this->AsRange(), that->AsRange());
519 return this->SimplyEquals(that);
523 // Return the range in [this], or [NULL].
524 template<class Config>
525 typename TypeImpl<Config>::RangeType* TypeImpl<Config>::GetRange() {
526 DisallowHeapAllocation no_allocation;
527 if (this->IsRange()) return this->AsRange();
528 if (this->IsUnion() && this->AsUnion()->Get(1)->IsRange()) {
529 return this->AsUnion()->Get(1)->AsRange();
535 template<class Config>
536 bool TypeImpl<Config>::Contains(i::Object* value) {
537 DisallowHeapAllocation no_allocation;
538 for (Iterator<i::Object> it = this->Constants(); !it.Done(); it.Advance()) {
539 if (*it.Current() == value) return true;
541 if (IsInteger(value)) {
542 RangeType* range = this->GetRange();
543 if (range != NULL && Contains(range, value)) return true;
545 return BitsetType::New(BitsetType::Lub(value))->Is(this);
549 template<class Config>
550 bool TypeImpl<Config>::UnionType::Wellformed() {
551 DisallowHeapAllocation no_allocation;
552 // This checks the invariants of the union representation:
553 // 1. There are at least two elements.
554 // 2. At most one element is a bitset, and it must be the first one.
555 // 3. At most one element is a range, and it must be the second one
556 // (even when the first element is not a bitset).
557 // 4. No element is itself a union.
558 // 5. No element is a subtype of any other.
559 DCHECK(this->Length() >= 2); // (1)
560 for (int i = 0; i < this->Length(); ++i) {
561 if (i != 0) DCHECK(!this->Get(i)->IsBitset()); // (2)
562 if (i != 1) DCHECK(!this->Get(i)->IsRange()); // (3)
563 DCHECK(!this->Get(i)->IsUnion()); // (4)
564 for (int j = 0; j < this->Length(); ++j) {
565 if (i != j) DCHECK(!this->Get(i)->Is(this->Get(j))); // (5)
572 // -----------------------------------------------------------------------------
573 // Union and intersection
576 static bool AddIsSafe(int x, int y) {
578 y <= std::numeric_limits<int>::max() - x :
579 y >= std::numeric_limits<int>::min() - x;
583 template<class Config>
584 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
585 TypeHandle type1, TypeHandle type2, Region* region) {
586 bitset bits = type1->BitsetGlb() & type2->BitsetGlb();
587 if (!BitsetType::IsInhabited(bits)) bits = BitsetType::kNone;
589 // Fast case: bit sets.
590 if (type1->IsBitset() && type2->IsBitset()) {
591 return BitsetType::New(bits, region);
594 // Fast case: top or bottom types.
595 if (type1->IsNone() || type2->IsAny()) return type1; // Shortcut.
596 if (type2->IsNone() || type1->IsAny()) return type2; // Shortcut.
599 if (type1->Is(type2)) return type1;
600 if (type2->Is(type1)) return type2;
602 // Slow case: create union.
603 int size1 = type1->IsUnion() ? type1->AsUnion()->Length() : 1;
604 int size2 = type2->IsUnion() ? type2->AsUnion()->Length() : 1;
605 if (!AddIsSafe(size1, size2)) return Any(region);
606 int size = size1 + size2;
607 if (!AddIsSafe(size, 2)) return Any(region);
609 UnionHandle result = UnionType::New(size, region);
612 // Deal with bitsets.
613 result->Set(size++, BitsetType::New(bits, region));
616 TypeHandle range = None(region);
617 RangeType* range1 = type1->GetRange();
618 RangeType* range2 = type2->GetRange();
619 if (range1 != NULL && range2 != NULL) {
620 Limits lim = Intersect(Limits(range1), Limits(range2));
621 if (lim.min->Number() <= lim.max->Number()) {
622 range = RangeType::New(lim, region);
625 result->Set(size++, range);
627 size = IntersectAux(type1, type2, result, size, region);
628 return NormalizeUnion(result, size);
632 template<class Config>
633 int TypeImpl<Config>::UpdateRange(
634 RangeHandle range, UnionHandle result, int size, Region* region) {
635 TypeHandle old_range = result->Get(1);
636 DCHECK(old_range->IsRange() || old_range->IsNone());
637 if (range->Is(old_range)) return size;
638 if (!old_range->Is(range->unhandle())) {
639 range = RangeType::New(
640 Union(Limits(range->AsRange()), Limits(old_range->AsRange())), region);
642 result->Set(1, range);
644 // Remove any components that just got subsumed.
645 for (int i = 2; i < size; ) {
646 if (result->Get(i)->Is(range->unhandle())) {
647 result->Set(i, result->Get(--size));
656 template<class Config>
657 int TypeImpl<Config>::IntersectAux(
658 TypeHandle lhs, TypeHandle rhs,
659 UnionHandle result, int size, Region* region) {
660 if (lhs->IsUnion()) {
661 for (int i = 0, n = lhs->AsUnion()->Length(); i < n; ++i) {
662 size = IntersectAux(lhs->AsUnion()->Get(i), rhs, result, size, region);
666 if (rhs->IsUnion()) {
667 for (int i = 0, n = rhs->AsUnion()->Length(); i < n; ++i) {
668 size = IntersectAux(lhs, rhs->AsUnion()->Get(i), result, size, region);
673 if (!BitsetType::IsInhabited(lhs->BitsetLub() & rhs->BitsetLub())) {
677 if (lhs->IsRange()) {
678 if (rhs->IsBitset() || rhs->IsClass()) {
680 Config::template cast<RangeType>(lhs), result, size, region);
682 if (rhs->IsConstant() &&
683 Contains(lhs->AsRange(), *rhs->AsConstant()->Value())) {
684 return AddToUnion(rhs, result, size, region);
688 if (rhs->IsRange()) {
689 if (lhs->IsBitset() || lhs->IsClass()) {
691 Config::template cast<RangeType>(rhs), result, size, region);
693 if (lhs->IsConstant() &&
694 Contains(rhs->AsRange(), *lhs->AsConstant()->Value())) {
695 return AddToUnion(lhs, result, size, region);
700 if (lhs->IsBitset() || rhs->IsBitset()) {
701 return AddToUnion(lhs->IsBitset() ? rhs : lhs, result, size, region);
703 if (lhs->IsClass() != rhs->IsClass()) {
704 return AddToUnion(lhs->IsClass() ? rhs : lhs, result, size, region);
706 if (lhs->SimplyEquals(rhs->unhandle())) {
707 return AddToUnion(lhs, result, size, region);
713 template<class Config>
714 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Union(
715 TypeHandle type1, TypeHandle type2, Region* region) {
717 // Fast case: bit sets.
718 if (type1->IsBitset() && type2->IsBitset()) {
719 return BitsetType::New(type1->AsBitset() | type2->AsBitset(), region);
722 // Fast case: top or bottom types.
723 if (type1->IsAny() || type2->IsNone()) return type1;
724 if (type2->IsAny() || type1->IsNone()) return type2;
727 if (type1->Is(type2)) return type2;
728 if (type2->Is(type1)) return type1;
730 // Slow case: create union.
731 int size1 = type1->IsUnion() ? type1->AsUnion()->Length() : 1;
732 int size2 = type2->IsUnion() ? type2->AsUnion()->Length() : 1;
733 if (!AddIsSafe(size1, size2)) return Any(region);
734 int size = size1 + size2;
735 if (!AddIsSafe(size, 2)) return Any(region);
737 UnionHandle result = UnionType::New(size, region);
740 // Deal with bitsets.
741 TypeHandle bits = BitsetType::New(
742 type1->BitsetGlb() | type2->BitsetGlb(), region);
743 result->Set(size++, bits);
746 TypeHandle range = None(region);
747 RangeType* range1 = type1->GetRange();
748 RangeType* range2 = type2->GetRange();
749 if (range1 != NULL && range2 != NULL) {
750 range = RangeType::New(Union(Limits(range1), Limits(range2)), region);
751 } else if (range1 != NULL) {
752 range = handle(range1);
753 } else if (range2 != NULL) {
754 range = handle(range2);
756 result->Set(size++, range);
758 size = AddToUnion(type1, result, size, region);
759 size = AddToUnion(type2, result, size, region);
760 return NormalizeUnion(result, size);
764 // Add [type] to [result] unless [type] is bitset, range, or already subsumed.
765 // Return new size of [result].
766 template<class Config>
767 int TypeImpl<Config>::AddToUnion(
768 TypeHandle type, UnionHandle result, int size, Region* region) {
769 if (type->IsBitset() || type->IsRange()) return size;
770 if (type->IsUnion()) {
771 for (int i = 0, n = type->AsUnion()->Length(); i < n; ++i) {
772 size = AddToUnion(type->AsUnion()->Get(i), result, size, region);
776 for (int i = 0; i < size; ++i) {
777 if (type->Is(result->Get(i))) return size;
779 result->Set(size++, type);
784 template<class Config>
785 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::NormalizeUnion(
786 UnionHandle unioned, int size) {
788 // If range is subsumed by bitset, use its place for a different type.
789 if (unioned->Get(1)->Is(unioned->Get(0))) {
790 unioned->Set(1, unioned->Get(--size));
792 // If bitset is None, use its place for a different type.
793 if (size >= 2 && unioned->Get(0)->IsNone()) {
794 unioned->Set(0, unioned->Get(--size));
796 if (size == 1) return unioned->Get(0);
797 unioned->Shrink(size);
798 SLOW_DCHECK(unioned->Wellformed());
803 // -----------------------------------------------------------------------------
806 template<class Config>
807 int TypeImpl<Config>::NumClasses() {
808 DisallowHeapAllocation no_allocation;
809 if (this->IsClass()) {
811 } else if (this->IsUnion()) {
813 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
814 if (this->AsUnion()->Get(i)->IsClass()) ++result;
823 template<class Config>
824 int TypeImpl<Config>::NumConstants() {
825 DisallowHeapAllocation no_allocation;
826 if (this->IsConstant()) {
828 } else if (this->IsUnion()) {
830 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
831 if (this->AsUnion()->Get(i)->IsConstant()) ++result;
840 template<class Config> template<class T>
841 typename TypeImpl<Config>::TypeHandle
842 TypeImpl<Config>::Iterator<T>::get_type() {
844 return type_->IsUnion() ? type_->AsUnion()->Get(index_) : type_;
848 // C++ cannot specialise nested templates, so we have to go through this
849 // contortion with an auxiliary template to simulate it.
850 template<class Config, class T>
851 struct TypeImplIteratorAux {
852 static bool matches(typename TypeImpl<Config>::TypeHandle type);
853 static i::Handle<T> current(typename TypeImpl<Config>::TypeHandle type);
856 template<class Config>
857 struct TypeImplIteratorAux<Config, i::Map> {
858 static bool matches(typename TypeImpl<Config>::TypeHandle type) {
859 return type->IsClass();
861 static i::Handle<i::Map> current(typename TypeImpl<Config>::TypeHandle type) {
862 return type->AsClass()->Map();
866 template<class Config>
867 struct TypeImplIteratorAux<Config, i::Object> {
868 static bool matches(typename TypeImpl<Config>::TypeHandle type) {
869 return type->IsConstant();
871 static i::Handle<i::Object> current(
872 typename TypeImpl<Config>::TypeHandle type) {
873 return type->AsConstant()->Value();
877 template<class Config> template<class T>
878 bool TypeImpl<Config>::Iterator<T>::matches(TypeHandle type) {
879 return TypeImplIteratorAux<Config, T>::matches(type);
882 template<class Config> template<class T>
883 i::Handle<T> TypeImpl<Config>::Iterator<T>::Current() {
884 return TypeImplIteratorAux<Config, T>::current(get_type());
888 template<class Config> template<class T>
889 void TypeImpl<Config>::Iterator<T>::Advance() {
890 DisallowHeapAllocation no_allocation;
892 if (type_->IsUnion()) {
893 for (int n = type_->AsUnion()->Length(); index_ < n; ++index_) {
894 if (matches(type_->AsUnion()->Get(index_))) return;
896 } else if (index_ == 0 && matches(type_)) {
903 // -----------------------------------------------------------------------------
904 // Conversion between low-level representations.
906 template<class Config>
907 template<class OtherType>
908 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
909 typename OtherType::TypeHandle type, Region* region) {
910 if (type->IsBitset()) {
911 return BitsetType::New(type->AsBitset(), region);
912 } else if (type->IsClass()) {
913 return ClassType::New(type->AsClass()->Map(), region);
914 } else if (type->IsConstant()) {
915 return ConstantType::New(type->AsConstant()->Value(), region);
916 } else if (type->IsRange()) {
917 return RangeType::New(
918 type->AsRange()->Min(), type->AsRange()->Max(), region);
919 } else if (type->IsContext()) {
920 TypeHandle outer = Convert<OtherType>(type->AsContext()->Outer(), region);
921 return ContextType::New(outer, region);
922 } else if (type->IsUnion()) {
923 int length = type->AsUnion()->Length();
924 UnionHandle unioned = UnionType::New(length, region);
925 for (int i = 0; i < length; ++i) {
926 TypeHandle t = Convert<OtherType>(type->AsUnion()->Get(i), region);
930 } else if (type->IsArray()) {
931 TypeHandle element = Convert<OtherType>(type->AsArray()->Element(), region);
932 return ArrayType::New(element, region);
933 } else if (type->IsFunction()) {
934 TypeHandle res = Convert<OtherType>(type->AsFunction()->Result(), region);
935 TypeHandle rcv = Convert<OtherType>(type->AsFunction()->Receiver(), region);
936 FunctionHandle function = FunctionType::New(
937 res, rcv, type->AsFunction()->Arity(), region);
938 for (int i = 0; i < function->Arity(); ++i) {
939 TypeHandle param = Convert<OtherType>(
940 type->AsFunction()->Parameter(i), region);
941 function->InitParameter(i, param);
951 // -----------------------------------------------------------------------------
954 template<class Config>
955 const char* TypeImpl<Config>::BitsetType::Name(bitset bits) {
957 case REPRESENTATION(kAny): return "Any";
958 #define RETURN_NAMED_REPRESENTATION_TYPE(type, value) \
959 case REPRESENTATION(k##type): return #type;
960 REPRESENTATION_BITSET_TYPE_LIST(RETURN_NAMED_REPRESENTATION_TYPE)
961 #undef RETURN_NAMED_REPRESENTATION_TYPE
963 #define RETURN_NAMED_SEMANTIC_TYPE(type, value) \
964 case SEMANTIC(k##type): return #type;
965 SEMANTIC_BITSET_TYPE_LIST(RETURN_NAMED_SEMANTIC_TYPE)
966 #undef RETURN_NAMED_SEMANTIC_TYPE
974 template <class Config>
975 void TypeImpl<Config>::BitsetType::Print(std::ostream& os, // NOLINT
977 DisallowHeapAllocation no_allocation;
978 const char* name = Name(bits);
984 static const bitset named_bitsets[] = {
985 #define BITSET_CONSTANT(type, value) REPRESENTATION(k##type),
986 REPRESENTATION_BITSET_TYPE_LIST(BITSET_CONSTANT)
987 #undef BITSET_CONSTANT
989 #define BITSET_CONSTANT(type, value) SEMANTIC(k##type),
990 SEMANTIC_BITSET_TYPE_LIST(BITSET_CONSTANT)
991 #undef BITSET_CONSTANT
994 bool is_first = true;
996 for (int i(arraysize(named_bitsets) - 1); bits != 0 && i >= 0; --i) {
997 bitset subset = named_bitsets[i];
998 if ((bits & subset) == subset) {
999 if (!is_first) os << " | ";
1010 template <class Config>
1011 void TypeImpl<Config>::PrintTo(std::ostream& os, PrintDimension dim) {
1012 DisallowHeapAllocation no_allocation;
1013 if (dim != REPRESENTATION_DIM) {
1014 if (this->IsBitset()) {
1015 BitsetType::Print(os, SEMANTIC(this->AsBitset()));
1016 } else if (this->IsClass()) {
1017 os << "Class(" << static_cast<void*>(*this->AsClass()->Map()) << " < ";
1018 BitsetType::New(BitsetType::Lub(this))->PrintTo(os, dim);
1020 } else if (this->IsConstant()) {
1021 os << "Constant(" << Brief(*this->AsConstant()->Value()) << ")";
1022 } else if (this->IsRange()) {
1023 os << "Range(" << this->AsRange()->Min()->Number()
1024 << ", " << this->AsRange()->Max()->Number() << ")";
1025 } else if (this->IsContext()) {
1027 this->AsContext()->Outer()->PrintTo(os, dim);
1029 } else if (this->IsUnion()) {
1031 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
1032 TypeHandle type_i = this->AsUnion()->Get(i);
1033 if (i > 0) os << " | ";
1034 type_i->PrintTo(os, dim);
1037 } else if (this->IsArray()) {
1039 AsArray()->Element()->PrintTo(os, dim);
1041 } else if (this->IsFunction()) {
1042 if (!this->AsFunction()->Receiver()->IsAny()) {
1043 this->AsFunction()->Receiver()->PrintTo(os, dim);
1047 for (int i = 0; i < this->AsFunction()->Arity(); ++i) {
1048 if (i > 0) os << ", ";
1049 this->AsFunction()->Parameter(i)->PrintTo(os, dim);
1052 this->AsFunction()->Result()->PrintTo(os, dim);
1057 if (dim == BOTH_DIMS) os << "/";
1058 if (dim != SEMANTIC_DIM) {
1059 BitsetType::Print(os, REPRESENTATION(this->BitsetLub()));
1065 template <class Config>
1066 void TypeImpl<Config>::Print() {
1067 OFStream os(stdout);
1071 template <class Config>
1072 void TypeImpl<Config>::BitsetType::Print(bitset bits) {
1073 OFStream os(stdout);
1080 // -----------------------------------------------------------------------------
1083 template class TypeImpl<ZoneTypeConfig>;
1084 template class TypeImpl<ZoneTypeConfig>::Iterator<i::Map>;
1085 template class TypeImpl<ZoneTypeConfig>::Iterator<i::Object>;
1087 template class TypeImpl<HeapTypeConfig>;
1088 template class TypeImpl<HeapTypeConfig>::Iterator<i::Map>;
1089 template class TypeImpl<HeapTypeConfig>::Iterator<i::Object>;
1091 template TypeImpl<ZoneTypeConfig>::TypeHandle
1092 TypeImpl<ZoneTypeConfig>::Convert<HeapType>(
1093 TypeImpl<HeapTypeConfig>::TypeHandle, TypeImpl<ZoneTypeConfig>::Region*);
1094 template TypeImpl<HeapTypeConfig>::TypeHandle
1095 TypeImpl<HeapTypeConfig>::Convert<Type>(
1096 TypeImpl<ZoneTypeConfig>::TypeHandle, TypeImpl<HeapTypeConfig>::Region*);
1098 } } // namespace v8::internal