• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "src/types.h"
6 
7 #include "src/string-stream.h"
8 #include "src/types-inl.h"
9 
10 namespace v8 {
11 namespace internal {
12 
13 // -----------------------------------------------------------------------------
14 // Glb and lub computation.
15 
16 // The largest bitset subsumed by this type.
17 template<class Config>
Glb(TypeImpl * type)18 int TypeImpl<Config>::BitsetType::Glb(TypeImpl* type) {
19   DisallowHeapAllocation no_allocation;
20   if (type->IsBitset()) {
21     return type->AsBitset();
22   } else if (type->IsUnion()) {
23     UnionHandle unioned = handle(type->AsUnion());
24     int bitset = kNone;
25     for (int i = 0; i < unioned->Length(); ++i) {
26       bitset |= unioned->Get(i)->BitsetGlb();
27     }
28     return bitset;
29   } else if (type->IsClass()) {
30     // Little hack to avoid the need for a region for handlification here...
31     return REPRESENTATION(Config::is_class(type)
32         ? Lub(*Config::as_class(type))
33         : type->AsClass()->Bound(NULL)->AsBitset());
34   } else if (type->IsConstant()) {
35     return REPRESENTATION(type->AsConstant()->Bound()->AsBitset());
36   } else if (type->IsContext()) {
37     return REPRESENTATION(type->AsContext()->Bound()->AsBitset());
38   } else if (type->IsArray()) {
39     return REPRESENTATION(type->AsArray()->Bound()->AsBitset());
40   } else if (type->IsFunction()) {
41     return REPRESENTATION(type->AsFunction()->Bound()->AsBitset());
42   } else {
43     UNREACHABLE();
44     return kNone;
45   }
46 }
47 
48 
49 // The smallest bitset subsuming this type.
50 template<class Config>
Lub(TypeImpl * type)51 int TypeImpl<Config>::BitsetType::Lub(TypeImpl* type) {
52   DisallowHeapAllocation no_allocation;
53   if (type->IsBitset()) {
54     return type->AsBitset();
55   } else if (type->IsUnion()) {
56     UnionHandle unioned = handle(type->AsUnion());
57     int bitset = kNone;
58     for (int i = 0; i < unioned->Length(); ++i) {
59       bitset |= unioned->Get(i)->BitsetLub();
60     }
61     return bitset;
62   } else if (type->IsClass()) {
63     // Little hack to avoid the need for a region for handlification here...
64     return Config::is_class(type) ? Lub(*Config::as_class(type)) :
65         type->AsClass()->Bound(NULL)->AsBitset();
66   } else if (type->IsConstant()) {
67     return type->AsConstant()->Bound()->AsBitset();
68   } else if (type->IsContext()) {
69     return type->AsContext()->Bound()->AsBitset();
70   } else if (type->IsArray()) {
71     return type->AsArray()->Bound()->AsBitset();
72   } else if (type->IsFunction()) {
73     return type->AsFunction()->Bound()->AsBitset();
74   } else {
75     UNREACHABLE();
76     return kNone;
77   }
78 }
79 
80 
81 // The smallest bitset subsuming this type, ignoring explicit bounds.
82 template<class Config>
InherentLub(TypeImpl * type)83 int TypeImpl<Config>::BitsetType::InherentLub(TypeImpl* type) {
84   DisallowHeapAllocation no_allocation;
85   if (type->IsBitset()) {
86     return type->AsBitset();
87   } else if (type->IsUnion()) {
88     UnionHandle unioned = handle(type->AsUnion());
89     int bitset = kNone;
90     for (int i = 0; i < unioned->Length(); ++i) {
91       bitset |= unioned->Get(i)->InherentBitsetLub();
92     }
93     return bitset;
94   } else if (type->IsClass()) {
95     return Lub(*type->AsClass()->Map());
96   } else if (type->IsConstant()) {
97     return Lub(*type->AsConstant()->Value());
98   } else if (type->IsContext()) {
99     return kInternal & kTaggedPtr;
100   } else if (type->IsArray()) {
101     return kArray;
102   } else if (type->IsFunction()) {
103     return kFunction;
104   } else {
105     UNREACHABLE();
106     return kNone;
107   }
108 }
109 
110 
111 template<class Config>
Lub(i::Object * value)112 int TypeImpl<Config>::BitsetType::Lub(i::Object* value) {
113   DisallowHeapAllocation no_allocation;
114   if (value->IsNumber()) {
115     return Lub(value->Number()) & (value->IsSmi() ? kTaggedInt : kTaggedPtr);
116   }
117   return Lub(i::HeapObject::cast(value)->map());
118 }
119 
120 
121 template<class Config>
Lub(double value)122 int TypeImpl<Config>::BitsetType::Lub(double value) {
123   DisallowHeapAllocation no_allocation;
124   if (i::IsMinusZero(value)) return kMinusZero;
125   if (std::isnan(value)) return kNaN;
126   if (IsUint32Double(value)) return Lub(FastD2UI(value));
127   if (IsInt32Double(value)) return Lub(FastD2I(value));
128   return kOtherNumber;
129 }
130 
131 
132 template<class Config>
Lub(int32_t value)133 int TypeImpl<Config>::BitsetType::Lub(int32_t value) {
134   if (value >= 0x40000000) {
135     return i::SmiValuesAre31Bits() ? kOtherUnsigned31 : kUnsignedSmall;
136   }
137   if (value >= 0) return kUnsignedSmall;
138   if (value >= -0x40000000) return kOtherSignedSmall;
139   return i::SmiValuesAre31Bits() ? kOtherSigned32 : kOtherSignedSmall;
140 }
141 
142 
143 template<class Config>
Lub(uint32_t value)144 int TypeImpl<Config>::BitsetType::Lub(uint32_t value) {
145   DisallowHeapAllocation no_allocation;
146   if (value >= 0x80000000u) return kOtherUnsigned32;
147   if (value >= 0x40000000u) {
148     return i::SmiValuesAre31Bits() ? kOtherUnsigned31 : kUnsignedSmall;
149   }
150   return kUnsignedSmall;
151 }
152 
153 
154 template<class Config>
Lub(i::Map * map)155 int TypeImpl<Config>::BitsetType::Lub(i::Map* map) {
156   DisallowHeapAllocation no_allocation;
157   switch (map->instance_type()) {
158     case STRING_TYPE:
159     case ASCII_STRING_TYPE:
160     case CONS_STRING_TYPE:
161     case CONS_ASCII_STRING_TYPE:
162     case SLICED_STRING_TYPE:
163     case SLICED_ASCII_STRING_TYPE:
164     case EXTERNAL_STRING_TYPE:
165     case EXTERNAL_ASCII_STRING_TYPE:
166     case EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
167     case SHORT_EXTERNAL_STRING_TYPE:
168     case SHORT_EXTERNAL_ASCII_STRING_TYPE:
169     case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
170     case INTERNALIZED_STRING_TYPE:
171     case ASCII_INTERNALIZED_STRING_TYPE:
172     case EXTERNAL_INTERNALIZED_STRING_TYPE:
173     case EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
174     case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
175     case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
176     case SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE:
177     case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
178       return kString;
179     case SYMBOL_TYPE:
180       return kSymbol;
181     case ODDBALL_TYPE: {
182       Heap* heap = map->GetHeap();
183       if (map == heap->undefined_map()) return kUndefined;
184       if (map == heap->the_hole_map()) return kAny;  // TODO(rossberg): kNone?
185       if (map == heap->null_map()) return kNull;
186       if (map == heap->boolean_map()) return kBoolean;
187       ASSERT(map == heap->uninitialized_map() ||
188              map == heap->no_interceptor_result_sentinel_map() ||
189              map == heap->termination_exception_map() ||
190              map == heap->arguments_marker_map());
191       return kInternal & kTaggedPtr;
192     }
193     case HEAP_NUMBER_TYPE:
194       return kNumber & kTaggedPtr;
195     case JS_VALUE_TYPE:
196     case JS_DATE_TYPE:
197     case JS_OBJECT_TYPE:
198     case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
199     case JS_GENERATOR_OBJECT_TYPE:
200     case JS_MODULE_TYPE:
201     case JS_GLOBAL_OBJECT_TYPE:
202     case JS_BUILTINS_OBJECT_TYPE:
203     case JS_GLOBAL_PROXY_TYPE:
204     case JS_ARRAY_BUFFER_TYPE:
205     case JS_TYPED_ARRAY_TYPE:
206     case JS_DATA_VIEW_TYPE:
207     case JS_SET_TYPE:
208     case JS_MAP_TYPE:
209     case JS_SET_ITERATOR_TYPE:
210     case JS_MAP_ITERATOR_TYPE:
211     case JS_WEAK_MAP_TYPE:
212     case JS_WEAK_SET_TYPE:
213       if (map->is_undetectable()) return kUndetectable;
214       return kOtherObject;
215     case JS_ARRAY_TYPE:
216       return kArray;
217     case JS_FUNCTION_TYPE:
218       return kFunction;
219     case JS_REGEXP_TYPE:
220       return kRegExp;
221     case JS_PROXY_TYPE:
222     case JS_FUNCTION_PROXY_TYPE:
223       return kProxy;
224     case MAP_TYPE:
225       // When compiling stub templates, the meta map is used as a place holder
226       // for the actual map with which the template is later instantiated.
227       // We treat it as a kind of type variable whose upper bound is Any.
228       // TODO(rossberg): for caching of CompareNilIC stubs to work correctly,
229       // we must exclude Undetectable here. This makes no sense, really,
230       // because it means that the template isn't actually parametric.
231       // Also, it doesn't apply elsewhere. 8-(
232       // We ought to find a cleaner solution for compiling stubs parameterised
233       // over type or class variables, esp ones with bounds...
234       return kDetectable;
235     case DECLARED_ACCESSOR_INFO_TYPE:
236     case EXECUTABLE_ACCESSOR_INFO_TYPE:
237     case SHARED_FUNCTION_INFO_TYPE:
238     case ACCESSOR_PAIR_TYPE:
239     case FIXED_ARRAY_TYPE:
240     case FOREIGN_TYPE:
241       return kInternal & kTaggedPtr;
242     default:
243       UNREACHABLE();
244       return kNone;
245   }
246 }
247 
248 
249 // -----------------------------------------------------------------------------
250 // Predicates.
251 
252 // Check this <= that.
253 template<class Config>
SlowIs(TypeImpl * that)254 bool TypeImpl<Config>::SlowIs(TypeImpl* that) {
255   DisallowHeapAllocation no_allocation;
256 
257   // Fast path for bitsets.
258   if (this->IsNone()) return true;
259   if (that->IsBitset()) {
260     return (BitsetType::Lub(this) | that->AsBitset()) == that->AsBitset();
261   }
262   if (this->IsBitset() && SEMANTIC(this->AsBitset()) == BitsetType::kNone) {
263     // Bitsets only have non-bitset supertypes along the representation axis.
264     int that_bitset = that->BitsetGlb();
265     return (this->AsBitset() | that_bitset) == that_bitset;
266   }
267 
268   if (that->IsClass()) {
269     return this->IsClass()
270         && *this->AsClass()->Map() == *that->AsClass()->Map()
271         && ((Config::is_class(that) && Config::is_class(this)) ||
272             BitsetType::New(this->BitsetLub())->Is(
273                 BitsetType::New(that->BitsetLub())));
274   }
275   if (that->IsConstant()) {
276     return this->IsConstant()
277         && *this->AsConstant()->Value() == *that->AsConstant()->Value()
278         && this->AsConstant()->Bound()->Is(that->AsConstant()->Bound());
279   }
280   if (that->IsContext()) {
281     return this->IsContext()
282         && this->AsContext()->Outer()->Equals(that->AsContext()->Outer());
283   }
284   if (that->IsArray()) {
285     return this->IsArray()
286         && this->AsArray()->Element()->Equals(that->AsArray()->Element());
287   }
288   if (that->IsFunction()) {
289     // We currently do not allow for any variance here, in order to keep
290     // Union and Intersect operations simple.
291     if (!this->IsFunction()) return false;
292     FunctionType* this_fun = this->AsFunction();
293     FunctionType* that_fun = that->AsFunction();
294     if (this_fun->Arity() != that_fun->Arity() ||
295         !this_fun->Result()->Equals(that_fun->Result()) ||
296         !that_fun->Receiver()->Equals(this_fun->Receiver())) {
297       return false;
298     }
299     for (int i = 0; i < this_fun->Arity(); ++i) {
300       if (!that_fun->Parameter(i)->Equals(this_fun->Parameter(i))) return false;
301     }
302     return true;
303   }
304 
305   // (T1 \/ ... \/ Tn) <= T  <=>  (T1 <= T) /\ ... /\ (Tn <= T)
306   if (this->IsUnion()) {
307     UnionHandle unioned = handle(this->AsUnion());
308     for (int i = 0; i < unioned->Length(); ++i) {
309       if (!unioned->Get(i)->Is(that)) return false;
310     }
311     return true;
312   }
313 
314   // T <= (T1 \/ ... \/ Tn)  <=>  (T <= T1) \/ ... \/ (T <= Tn)
315   // (iff T is not a union)
316   ASSERT(!this->IsUnion());
317   if (that->IsUnion()) {
318     UnionHandle unioned = handle(that->AsUnion());
319     for (int i = 0; i < unioned->Length(); ++i) {
320       if (this->Is(unioned->Get(i))) return true;
321       if (this->IsBitset()) break;  // Fast fail, only first field is a bitset.
322     }
323     return false;
324   }
325 
326   return false;
327 }
328 
329 
330 template<class Config>
NowIs(TypeImpl * that)331 bool TypeImpl<Config>::NowIs(TypeImpl* that) {
332   DisallowHeapAllocation no_allocation;
333 
334   // TODO(rossberg): this is incorrect for
335   //   Union(Constant(V), T)->NowIs(Class(M))
336   // but fuzzing does not cover that!
337   if (this->IsConstant()) {
338     i::Object* object = *this->AsConstant()->Value();
339     if (object->IsHeapObject()) {
340       i::Map* map = i::HeapObject::cast(object)->map();
341       for (Iterator<i::Map> it = that->Classes(); !it.Done(); it.Advance()) {
342         if (*it.Current() == map) return true;
343       }
344     }
345   }
346   return this->Is(that);
347 }
348 
349 
350 // Check if this contains only (currently) stable classes.
351 template<class Config>
NowStable()352 bool TypeImpl<Config>::NowStable() {
353   DisallowHeapAllocation no_allocation;
354   for (Iterator<i::Map> it = this->Classes(); !it.Done(); it.Advance()) {
355     if (!it.Current()->is_stable()) return false;
356   }
357   return true;
358 }
359 
360 
361 // Check this overlaps that.
362 template<class Config>
Maybe(TypeImpl * that)363 bool TypeImpl<Config>::Maybe(TypeImpl* that) {
364   DisallowHeapAllocation no_allocation;
365 
366   // (T1 \/ ... \/ Tn) overlaps T <=> (T1 overlaps T) \/ ... \/ (Tn overlaps T)
367   if (this->IsUnion()) {
368     UnionHandle unioned = handle(this->AsUnion());
369     for (int i = 0; i < unioned->Length(); ++i) {
370       if (unioned->Get(i)->Maybe(that)) return true;
371     }
372     return false;
373   }
374 
375   // T overlaps (T1 \/ ... \/ Tn) <=> (T overlaps T1) \/ ... \/ (T overlaps Tn)
376   if (that->IsUnion()) {
377     UnionHandle unioned = handle(that->AsUnion());
378     for (int i = 0; i < unioned->Length(); ++i) {
379       if (this->Maybe(unioned->Get(i))) return true;
380     }
381     return false;
382   }
383 
384   ASSERT(!this->IsUnion() && !that->IsUnion());
385   if (this->IsBitset()) {
386     return BitsetType::IsInhabited(this->AsBitset() & that->BitsetLub());
387   }
388   if (that->IsBitset()) {
389     return BitsetType::IsInhabited(this->BitsetLub() & that->AsBitset());
390   }
391   if (this->IsClass()) {
392     return that->IsClass()
393         && *this->AsClass()->Map() == *that->AsClass()->Map();
394   }
395   if (this->IsConstant()) {
396     return that->IsConstant()
397         && *this->AsConstant()->Value() == *that->AsConstant()->Value();
398   }
399   if (this->IsContext()) {
400     return this->Equals(that);
401   }
402   if (this->IsArray()) {
403     // There is no variance!
404     return this->Equals(that);
405   }
406   if (this->IsFunction()) {
407     // There is no variance!
408     return this->Equals(that);
409   }
410 
411   return false;
412 }
413 
414 
415 // Check if value is contained in (inhabits) type.
416 template<class Config>
Contains(i::Object * value)417 bool TypeImpl<Config>::Contains(i::Object* value) {
418   DisallowHeapAllocation no_allocation;
419   for (Iterator<i::Object> it = this->Constants(); !it.Done(); it.Advance()) {
420     if (*it.Current() == value) return true;
421   }
422   return BitsetType::New(BitsetType::Lub(value))->Is(this);
423 }
424 
425 
426 template<class Config>
Wellformed()427 bool TypeImpl<Config>::UnionType::Wellformed() {
428   ASSERT(this->Length() >= 2);
429   for (int i = 0; i < this->Length(); ++i) {
430     ASSERT(!this->Get(i)->IsUnion());
431     if (i > 0) ASSERT(!this->Get(i)->IsBitset());
432     for (int j = 0; j < this->Length(); ++j) {
433       if (i != j) ASSERT(!this->Get(i)->Is(this->Get(j)));
434     }
435   }
436   return true;
437 }
438 
439 
440 // -----------------------------------------------------------------------------
441 // Union and intersection
442 
443 template<class Config>
Narrow(int bitset,Region * region)444 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Narrow(
445     int bitset, Region* region) {
446   TypeHandle bound = BitsetType::New(bitset, region);
447   if (this->IsClass()) {
448     return ClassType::New(this->AsClass()->Map(), bound, region);
449   } else if (this->IsConstant()) {
450     return ConstantType::New(this->AsConstant()->Value(), bound, region);
451   } else if (this->IsContext()) {
452     return ContextType::New(this->AsContext()->Outer(), bound, region);
453   } else if (this->IsArray()) {
454     return ArrayType::New(this->AsArray()->Element(), bound, region);
455   } else if (this->IsFunction()) {
456     FunctionType* function = this->AsFunction();
457     int arity = function->Arity();
458     FunctionHandle type = FunctionType::New(
459         function->Result(), function->Receiver(), bound, arity, region);
460     for (int i = 0; i < arity; ++i) {
461       type->InitParameter(i, function->Parameter(i));
462     }
463     return type;
464   }
465   UNREACHABLE();
466   return TypeHandle();
467 }
468 
469 
470 template<class Config>
BoundBy(TypeImpl * that)471 int TypeImpl<Config>::BoundBy(TypeImpl* that) {
472   ASSERT(!this->IsUnion());
473   if (that->IsUnion()) {
474     UnionType* unioned = that->AsUnion();
475     int length = unioned->Length();
476     int bitset = BitsetType::kNone;
477     for (int i = 0; i < length; ++i) {
478       bitset |= BoundBy(unioned->Get(i)->unhandle());
479     }
480     return bitset;
481   } else if (that->IsClass() && this->IsClass() &&
482       *this->AsClass()->Map() == *that->AsClass()->Map()) {
483     return that->BitsetLub();
484   } else if (that->IsConstant() && this->IsConstant() &&
485       *this->AsConstant()->Value() == *that->AsConstant()->Value()) {
486     return that->AsConstant()->Bound()->AsBitset();
487   } else if (that->IsContext() && this->IsContext() && this->Is(that)) {
488     return that->AsContext()->Bound()->AsBitset();
489   } else if (that->IsArray() && this->IsArray() && this->Is(that)) {
490     return that->AsArray()->Bound()->AsBitset();
491   } else if (that->IsFunction() && this->IsFunction() && this->Is(that)) {
492     return that->AsFunction()->Bound()->AsBitset();
493   }
494   return that->BitsetGlb();
495 }
496 
497 
498 template<class Config>
IndexInUnion(int bound,UnionHandle unioned,int current_size)499 int TypeImpl<Config>::IndexInUnion(
500     int bound, UnionHandle unioned, int current_size) {
501   ASSERT(!this->IsUnion());
502   for (int i = 0; i < current_size; ++i) {
503     TypeHandle that = unioned->Get(i);
504     if (that->IsBitset()) {
505       if ((bound | that->AsBitset()) == that->AsBitset()) return i;
506     } else if (that->IsClass() && this->IsClass()) {
507       if (*this->AsClass()->Map() == *that->AsClass()->Map()) return i;
508     } else if (that->IsConstant() && this->IsConstant()) {
509       if (*this->AsConstant()->Value() == *that->AsConstant()->Value())
510         return i;
511     } else if (that->IsContext() && this->IsContext()) {
512       if (this->Is(that)) return i;
513     } else if (that->IsArray() && this->IsArray()) {
514       if (this->Is(that)) return i;
515     } else if (that->IsFunction() && this->IsFunction()) {
516       if (this->Is(that)) return i;
517     }
518   }
519   return -1;
520 }
521 
522 
523 // Get non-bitsets from type, bounded by upper.
524 // Store at result starting at index. Returns updated index.
525 template<class Config>
ExtendUnion(UnionHandle result,int size,TypeHandle type,TypeHandle other,bool is_intersect,Region * region)526 int TypeImpl<Config>::ExtendUnion(
527     UnionHandle result, int size, TypeHandle type,
528     TypeHandle other, bool is_intersect, Region* region) {
529   int old_size = size;
530   if (type->IsUnion()) {
531     UnionHandle unioned = handle(type->AsUnion());
532     for (int i = 0; i < unioned->Length(); ++i) {
533       TypeHandle type_i = unioned->Get(i);
534       ASSERT(i == 0 || !(type_i->IsBitset() || type_i->Is(unioned->Get(0))));
535       if (!type_i->IsBitset()) {
536         size = ExtendUnion(result, size, type_i, other, is_intersect, region);
537       }
538     }
539   } else if (!type->IsBitset()) {
540     ASSERT(type->IsClass() || type->IsConstant() ||
541            type->IsArray() || type->IsFunction() || type->IsContext());
542     int inherent_bound = type->InherentBitsetLub();
543     int old_bound = type->BitsetLub();
544     int other_bound = type->BoundBy(other->unhandle()) & inherent_bound;
545     int new_bound =
546         is_intersect ? (old_bound & other_bound) : (old_bound | other_bound);
547     if (new_bound != BitsetType::kNone) {
548       int i = type->IndexInUnion(new_bound, result, old_size);
549       if (i == -1) {
550         i = size++;
551       } else if (result->Get(i)->IsBitset()) {
552         return size;  // Already fully subsumed.
553       } else {
554         int type_i_bound = result->Get(i)->BitsetLub();
555         new_bound |= type_i_bound;
556         if (new_bound == type_i_bound) return size;
557       }
558       if (new_bound != old_bound) type = type->Narrow(new_bound, region);
559       result->Set(i, type);
560     }
561   }
562   return size;
563 }
564 
565 
566 // If bitset is subsumed by another entry in the result, remove it.
567 // (Only bitsets with empty semantic axis can be subtypes of non-bitsets.)
568 template<class Config>
NormalizeUnion(UnionHandle result,int size,int bitset)569 int TypeImpl<Config>::NormalizeUnion(UnionHandle result, int size, int bitset) {
570   if (bitset != BitsetType::kNone && SEMANTIC(bitset) == BitsetType::kNone) {
571     for (int i = 1; i < size; ++i) {
572       int glb = result->Get(i)->BitsetGlb();
573       if ((bitset | glb) == glb) {
574         for (int j = 1; j < size; ++j) {
575           result->Set(j - 1, result->Get(j));
576         }
577         --size;
578         break;
579       }
580     }
581   }
582   return size;
583 }
584 
585 
586 // Union is O(1) on simple bitsets, but O(n*m) on structured unions.
587 template<class Config>
Union(TypeHandle type1,TypeHandle type2,Region * region)588 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Union(
589     TypeHandle type1, TypeHandle type2, Region* region) {
590   // Fast case: bit sets.
591   if (type1->IsBitset() && type2->IsBitset()) {
592     return BitsetType::New(type1->AsBitset() | type2->AsBitset(), region);
593   }
594 
595   // Fast case: top or bottom types.
596   if (type1->IsAny() || type2->IsNone()) return type1;
597   if (type2->IsAny() || type1->IsNone()) return type2;
598 
599   // Semi-fast case: Unioned objects are neither involved nor produced.
600   if (!(type1->IsUnion() || type2->IsUnion())) {
601     if (type1->Is(type2)) return type2;
602     if (type2->Is(type1)) return type1;
603   }
604 
605   // Slow case: may need to produce a Unioned object.
606   int size = 0;
607   if (!type1->IsBitset()) {
608     size += (type1->IsUnion() ? type1->AsUnion()->Length() : 1);
609   }
610   if (!type2->IsBitset()) {
611     size += (type2->IsUnion() ? type2->AsUnion()->Length() : 1);
612   }
613   int bitset = type1->BitsetGlb() | type2->BitsetGlb();
614   if (bitset != BitsetType::kNone) ++size;
615   ASSERT(size >= 1);
616 
617   UnionHandle unioned = UnionType::New(size, region);
618   size = 0;
619   if (bitset != BitsetType::kNone) {
620     unioned->Set(size++, BitsetType::New(bitset, region));
621   }
622   size = ExtendUnion(unioned, size, type1, type2, false, region);
623   size = ExtendUnion(unioned, size, type2, type1, false, region);
624   size = NormalizeUnion(unioned, size, bitset);
625 
626   if (size == 1) {
627     return unioned->Get(0);
628   } else {
629     unioned->Shrink(size);
630     ASSERT(unioned->Wellformed());
631     return unioned;
632   }
633 }
634 
635 
636 // Intersection is O(1) on simple bitsets, but O(n*m) on structured unions.
637 template<class Config>
Intersect(TypeHandle type1,TypeHandle type2,Region * region)638 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Intersect(
639     TypeHandle type1, TypeHandle type2, Region* region) {
640   // Fast case: bit sets.
641   if (type1->IsBitset() && type2->IsBitset()) {
642     return BitsetType::New(type1->AsBitset() & type2->AsBitset(), region);
643   }
644 
645   // Fast case: top or bottom types.
646   if (type1->IsNone() || type2->IsAny()) return type1;
647   if (type2->IsNone() || type1->IsAny()) return type2;
648 
649   // Semi-fast case: Unioned objects are neither involved nor produced.
650   if (!(type1->IsUnion() || type2->IsUnion())) {
651     if (type1->Is(type2)) return type1;
652     if (type2->Is(type1)) return type2;
653   }
654 
655   // Slow case: may need to produce a Unioned object.
656   int size = 0;
657   if (!type1->IsBitset()) {
658     size += (type1->IsUnion() ? type1->AsUnion()->Length() : 1);
659   }
660   if (!type2->IsBitset()) {
661     size += (type2->IsUnion() ? type2->AsUnion()->Length() : 1);
662   }
663   int bitset = type1->BitsetGlb() & type2->BitsetGlb();
664   if (bitset != BitsetType::kNone) ++size;
665   ASSERT(size >= 1);
666 
667   UnionHandle unioned = UnionType::New(size, region);
668   size = 0;
669   if (bitset != BitsetType::kNone) {
670     unioned->Set(size++, BitsetType::New(bitset, region));
671   }
672   size = ExtendUnion(unioned, size, type1, type2, true, region);
673   size = ExtendUnion(unioned, size, type2, type1, true, region);
674   size = NormalizeUnion(unioned, size, bitset);
675 
676   if (size == 0) {
677     return None(region);
678   } else if (size == 1) {
679     return unioned->Get(0);
680   } else {
681     unioned->Shrink(size);
682     ASSERT(unioned->Wellformed());
683     return unioned;
684   }
685 }
686 
687 
688 // -----------------------------------------------------------------------------
689 // Iteration.
690 
691 template<class Config>
NumClasses()692 int TypeImpl<Config>::NumClasses() {
693   DisallowHeapAllocation no_allocation;
694   if (this->IsClass()) {
695     return 1;
696   } else if (this->IsUnion()) {
697     UnionHandle unioned = handle(this->AsUnion());
698     int result = 0;
699     for (int i = 0; i < unioned->Length(); ++i) {
700       if (unioned->Get(i)->IsClass()) ++result;
701     }
702     return result;
703   } else {
704     return 0;
705   }
706 }
707 
708 
709 template<class Config>
NumConstants()710 int TypeImpl<Config>::NumConstants() {
711   DisallowHeapAllocation no_allocation;
712   if (this->IsConstant()) {
713     return 1;
714   } else if (this->IsUnion()) {
715     UnionHandle unioned = handle(this->AsUnion());
716     int result = 0;
717     for (int i = 0; i < unioned->Length(); ++i) {
718       if (unioned->Get(i)->IsConstant()) ++result;
719     }
720     return result;
721   } else {
722     return 0;
723   }
724 }
725 
726 
727 template<class Config> template<class T>
728 typename TypeImpl<Config>::TypeHandle
get_type()729 TypeImpl<Config>::Iterator<T>::get_type() {
730   ASSERT(!Done());
731   return type_->IsUnion() ? type_->AsUnion()->Get(index_) : type_;
732 }
733 
734 
735 // C++ cannot specialise nested templates, so we have to go through this
736 // contortion with an auxiliary template to simulate it.
737 template<class Config, class T>
738 struct TypeImplIteratorAux {
739   static bool matches(typename TypeImpl<Config>::TypeHandle type);
740   static i::Handle<T> current(typename TypeImpl<Config>::TypeHandle type);
741 };
742 
743 template<class Config>
744 struct TypeImplIteratorAux<Config, i::Map> {
matchesv8::internal::TypeImplIteratorAux745   static bool matches(typename TypeImpl<Config>::TypeHandle type) {
746     return type->IsClass();
747   }
currentv8::internal::TypeImplIteratorAux748   static i::Handle<i::Map> current(typename TypeImpl<Config>::TypeHandle type) {
749     return type->AsClass()->Map();
750   }
751 };
752 
753 template<class Config>
754 struct TypeImplIteratorAux<Config, i::Object> {
matchesv8::internal::TypeImplIteratorAux755   static bool matches(typename TypeImpl<Config>::TypeHandle type) {
756     return type->IsConstant();
757   }
currentv8::internal::TypeImplIteratorAux758   static i::Handle<i::Object> current(
759       typename TypeImpl<Config>::TypeHandle type) {
760     return type->AsConstant()->Value();
761   }
762 };
763 
764 template<class Config> template<class T>
matches(TypeHandle type)765 bool TypeImpl<Config>::Iterator<T>::matches(TypeHandle type) {
766   return TypeImplIteratorAux<Config, T>::matches(type);
767 }
768 
769 template<class Config> template<class T>
Current()770 i::Handle<T> TypeImpl<Config>::Iterator<T>::Current() {
771   return TypeImplIteratorAux<Config, T>::current(get_type());
772 }
773 
774 
775 template<class Config> template<class T>
Advance()776 void TypeImpl<Config>::Iterator<T>::Advance() {
777   DisallowHeapAllocation no_allocation;
778   ++index_;
779   if (type_->IsUnion()) {
780     UnionHandle unioned = handle(type_->AsUnion());
781     for (; index_ < unioned->Length(); ++index_) {
782       if (matches(unioned->Get(index_))) return;
783     }
784   } else if (index_ == 0 && matches(type_)) {
785     return;
786   }
787   index_ = -1;
788 }
789 
790 
791 // -----------------------------------------------------------------------------
792 // Conversion between low-level representations.
793 
794 template<class Config>
795 template<class OtherType>
Convert(typename OtherType::TypeHandle type,Region * region)796 typename TypeImpl<Config>::TypeHandle TypeImpl<Config>::Convert(
797     typename OtherType::TypeHandle type, Region* region) {
798   if (type->IsBitset()) {
799     return BitsetType::New(type->AsBitset(), region);
800   } else if (type->IsClass()) {
801     return ClassType::New(
802         type->AsClass()->Map(),
803         BitsetType::New(type->BitsetLub(), region), region);
804   } else if (type->IsConstant()) {
805     return ConstantType::New(
806         type->AsConstant()->Value(),
807         Convert<OtherType>(type->AsConstant()->Bound(), region), region);
808   } else if (type->IsContext()) {
809     TypeHandle outer = Convert<OtherType>(type->AsContext()->Outer(), region);
810     return ContextType::New(outer, region);
811   } else if (type->IsUnion()) {
812     int length = type->AsUnion()->Length();
813     UnionHandle unioned = UnionType::New(length, region);
814     for (int i = 0; i < length; ++i) {
815       unioned->Set(i, Convert<OtherType>(type->AsUnion()->Get(i), region));
816     }
817     return unioned;
818   } else if (type->IsArray()) {
819     return ArrayType::New(
820         Convert<OtherType>(type->AsArray()->Element(), region),
821         Convert<OtherType>(type->AsArray()->Bound(), region), region);
822   } else if (type->IsFunction()) {
823     FunctionHandle function = FunctionType::New(
824         Convert<OtherType>(type->AsFunction()->Result(), region),
825         Convert<OtherType>(type->AsFunction()->Receiver(), region),
826         Convert<OtherType>(type->AsFunction()->Bound(), region),
827         type->AsFunction()->Arity(), region);
828     for (int i = 0; i < function->Arity(); ++i) {
829       function->InitParameter(i,
830           Convert<OtherType>(type->AsFunction()->Parameter(i), region));
831     }
832     return function;
833   } else {
834     UNREACHABLE();
835     return None(region);
836   }
837 }
838 
839 
840 // -----------------------------------------------------------------------------
841 // Printing.
842 
843 template<class Config>
Name(int bitset)844 const char* TypeImpl<Config>::BitsetType::Name(int bitset) {
845   switch (bitset) {
846     case REPRESENTATION(kAny): return "Any";
847     #define RETURN_NAMED_REPRESENTATION_TYPE(type, value) \
848     case REPRESENTATION(k##type): return #type;
849     REPRESENTATION_BITSET_TYPE_LIST(RETURN_NAMED_REPRESENTATION_TYPE)
850     #undef RETURN_NAMED_REPRESENTATION_TYPE
851 
852     #define RETURN_NAMED_SEMANTIC_TYPE(type, value) \
853     case SEMANTIC(k##type): return #type;
854     SEMANTIC_BITSET_TYPE_LIST(RETURN_NAMED_SEMANTIC_TYPE)
855     #undef RETURN_NAMED_SEMANTIC_TYPE
856 
857     default:
858       return NULL;
859   }
860 }
861 
862 
863 template<class Config>
PrintTo(StringStream * stream,int bitset)864 void TypeImpl<Config>::BitsetType::PrintTo(StringStream* stream, int bitset) {
865   DisallowHeapAllocation no_allocation;
866   const char* name = Name(bitset);
867   if (name != NULL) {
868     stream->Add("%s", name);
869   } else {
870     static const int named_bitsets[] = {
871       #define BITSET_CONSTANT(type, value) REPRESENTATION(k##type),
872       REPRESENTATION_BITSET_TYPE_LIST(BITSET_CONSTANT)
873       #undef BITSET_CONSTANT
874 
875       #define BITSET_CONSTANT(type, value) SEMANTIC(k##type),
876       SEMANTIC_BITSET_TYPE_LIST(BITSET_CONSTANT)
877       #undef BITSET_CONSTANT
878     };
879 
880     bool is_first = true;
881     stream->Add("(");
882     for (int i(ARRAY_SIZE(named_bitsets) - 1); bitset != 0 && i >= 0; --i) {
883       int subset = named_bitsets[i];
884       if ((bitset & subset) == subset) {
885         if (!is_first) stream->Add(" | ");
886         is_first = false;
887         stream->Add("%s", Name(subset));
888         bitset -= subset;
889       }
890     }
891     ASSERT(bitset == 0);
892     stream->Add(")");
893   }
894 }
895 
896 
897 template<class Config>
PrintTo(StringStream * stream,PrintDimension dim)898 void TypeImpl<Config>::PrintTo(StringStream* stream, PrintDimension dim) {
899   DisallowHeapAllocation no_allocation;
900   if (dim != REPRESENTATION_DIM) {
901     if (this->IsBitset()) {
902       BitsetType::PrintTo(stream, SEMANTIC(this->AsBitset()));
903     } else if (this->IsClass()) {
904       stream->Add("Class(%p < ", static_cast<void*>(*this->AsClass()->Map()));
905       BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
906       stream->Add(")");
907       return;
908     } else if (this->IsConstant()) {
909       stream->Add("Constant(%p : ",
910              static_cast<void*>(*this->AsConstant()->Value()));
911       BitsetType::New(BitsetType::Lub(this))->PrintTo(stream, dim);
912       stream->Add(")");
913       return;
914     } else if (this->IsContext()) {
915       stream->Add("Context(");
916       this->AsContext()->Outer()->PrintTo(stream, dim);
917       stream->Add(")");
918     } else if (this->IsUnion()) {
919       stream->Add("(");
920       UnionHandle unioned = handle(this->AsUnion());
921       for (int i = 0; i < unioned->Length(); ++i) {
922         TypeHandle type_i = unioned->Get(i);
923         if (i > 0) stream->Add(" | ");
924         type_i->PrintTo(stream, dim);
925       }
926       stream->Add(")");
927       return;
928     } else if (this->IsArray()) {
929       stream->Add("Array(");
930       AsArray()->Element()->PrintTo(stream, dim);
931       stream->Add(")");
932     } else if (this->IsFunction()) {
933       if (!this->AsFunction()->Receiver()->IsAny()) {
934         this->AsFunction()->Receiver()->PrintTo(stream, dim);
935         stream->Add(".");
936       }
937       stream->Add("(");
938       for (int i = 0; i < this->AsFunction()->Arity(); ++i) {
939         if (i > 0) stream->Add(", ");
940         this->AsFunction()->Parameter(i)->PrintTo(stream, dim);
941       }
942       stream->Add(")->");
943       this->AsFunction()->Result()->PrintTo(stream, dim);
944     } else {
945       UNREACHABLE();
946     }
947   }
948   if (dim == BOTH_DIMS) {
949     stream->Add("/");
950   }
951   if (dim != SEMANTIC_DIM) {
952     BitsetType::PrintTo(stream, REPRESENTATION(this->BitsetLub()));
953   }
954 }
955 
956 
957 template<class Config>
TypePrint(FILE * out,PrintDimension dim)958 void TypeImpl<Config>::TypePrint(FILE* out, PrintDimension dim) {
959   HeapStringAllocator allocator;
960   StringStream stream(&allocator);
961   PrintTo(&stream, dim);
962   stream.OutputToFile(out);
963 }
964 
965 
966 template<class Config>
TypePrint(PrintDimension dim)967 void TypeImpl<Config>::TypePrint(PrintDimension dim) {
968   TypePrint(stdout, dim);
969   PrintF(stdout, "\n");
970   Flush(stdout);
971 }
972 
973 
974 // -----------------------------------------------------------------------------
975 // Instantiations.
976 
977 template class TypeImpl<ZoneTypeConfig>;
978 template class TypeImpl<ZoneTypeConfig>::Iterator<i::Map>;
979 template class TypeImpl<ZoneTypeConfig>::Iterator<i::Object>;
980 
981 template class TypeImpl<HeapTypeConfig>;
982 template class TypeImpl<HeapTypeConfig>::Iterator<i::Map>;
983 template class TypeImpl<HeapTypeConfig>::Iterator<i::Object>;
984 
985 template TypeImpl<ZoneTypeConfig>::TypeHandle
986   TypeImpl<ZoneTypeConfig>::Convert<HeapType>(
987     TypeImpl<HeapTypeConfig>::TypeHandle, TypeImpl<ZoneTypeConfig>::Region*);
988 template TypeImpl<HeapTypeConfig>::TypeHandle
989   TypeImpl<HeapTypeConfig>::Convert<Type>(
990     TypeImpl<ZoneTypeConfig>::TypeHandle, TypeImpl<HeapTypeConfig>::Region*);
991 
992 } }  // namespace v8::internal
993