v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
turbofan-types.cc
Go to the documentation of this file.
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
6
7#include <iomanip>
8
14#include "src/utils/ostreams.h"
15
16#ifdef V8_ENABLE_WEBASSEMBLY
18#endif
19
20namespace v8 {
21namespace internal {
22namespace compiler {
23
24// -----------------------------------------------------------------------------
25// Range-related helper functions.
26
27bool RangeType::Limits::IsEmpty() { return this->min > this->max; }
28
31 Limits result(lhs);
32 if (lhs.min < rhs.min) result.min = rhs.min;
33 if (lhs.max > rhs.max) result.max = rhs.max;
34 return result;
35}
36
39 if (lhs.IsEmpty()) return rhs;
40 if (rhs.IsEmpty()) return lhs;
41 Limits result(lhs);
42 if (lhs.min > rhs.min) result.min = rhs.min;
43 if (lhs.max < rhs.max) result.max = rhs.max;
44 return result;
45}
46
47bool Type::Overlap(const RangeType* lhs, const RangeType* rhs) {
51 .IsEmpty();
52}
53
54bool Type::Contains(const RangeType* lhs, const RangeType* rhs) {
56 return lhs->Min() <= rhs->Min() && rhs->Max() <= lhs->Max();
57}
58
59// -----------------------------------------------------------------------------
60// Min and Max computation.
61
62double Type::Min() const {
63 DCHECK(this->Is(Number()));
64 DCHECK(!this->Is(NaN()));
65 if (this->IsBitset()) return BitsetType::Min(this->AsBitset());
66 if (this->IsUnion()) {
67 double min = +V8_INFINITY;
68 for (int i = 1, n = AsUnion()->Length(); i < n; ++i) {
69 min = std::min(min, AsUnion()->Get(i).Min());
70 }
71 Type bitset = AsUnion()->Get(0);
72 if (!bitset.Is(NaN())) min = std::min(min, bitset.Min());
73 return min;
74 }
75 if (this->IsRange()) return this->AsRange()->Min();
76 DCHECK(this->IsOtherNumberConstant());
77 return this->AsOtherNumberConstant()->Value();
78}
79
80double Type::Max() const {
81 DCHECK(this->Is(Number()));
82 DCHECK(!this->Is(NaN()));
83 if (this->IsBitset()) return BitsetType::Max(this->AsBitset());
84 if (this->IsUnion()) {
85 double max = -V8_INFINITY;
86 for (int i = 1, n = this->AsUnion()->Length(); i < n; ++i) {
87 max = std::max(max, this->AsUnion()->Get(i).Max());
88 }
89 Type bitset = this->AsUnion()->Get(0);
90 if (!bitset.Is(NaN())) max = std::max(max, bitset.Max());
91 return max;
92 }
93 if (this->IsRange()) return this->AsRange()->Max();
94 DCHECK(this->IsOtherNumberConstant());
95 return this->AsOtherNumberConstant()->Value();
96}
97
98// -----------------------------------------------------------------------------
99// Glb and lub computation.
100
101// The largest bitset subsumed by this type.
104 // Fast case.
105 if (IsBitset()) {
106 return AsBitset();
107 } else if (IsUnion()) {
108 SLOW_DCHECK(AsUnion()->Wellformed());
109 return AsUnion()->Get(0).BitsetGlb() |
110 AsUnion()->Get(1).BitsetGlb(); // Shortcut.
111 } else if (IsRange()) {
112 bitset glb = BitsetType::Glb(AsRange()->Min(), AsRange()->Max());
113 return glb;
114 } else {
115 return BitsetType::kNone;
116 }
117}
118
119// The smallest bitset subsuming this type, possibly not a proper one.
122 if (IsBitset()) return AsBitset();
123 if (IsUnion()) {
124 // Take the representation from the first element, which is always
125 // a bitset.
126 bitset lub = AsUnion()->Get(0).BitsetLub();
127 for (int i = 0, n = AsUnion()->Length(); i < n; ++i) {
128 // Other elements only contribute their semantic part.
129 lub |= AsUnion()->Get(i).BitsetLub();
130 }
131 return lub;
132 }
133 if (IsHeapConstant()) return AsHeapConstant()->Lub();
134 if (IsOtherNumberConstant()) {
135 return AsOtherNumberConstant()->Lub();
136 }
137 if (IsRange()) return AsRange()->Lub();
138 if (IsTuple()) return BitsetType::kOtherInternal;
139#if V8_ENABLE_WEBASSEMBLY
140 if (IsWasm()) return static_cast<const WasmType*>(ToTypeBase())->Lub();
141#endif
142 UNREACHABLE();
143}
144
145// TODO(neis): Once the broker mode kDisabled is gone, change the input type to
146// MapRef and get rid of the HeapObjectType class.
147template <typename MapRefLike>
149 switch (map.instance_type()) {
168 return kString;
175 return kInternalizedString;
176 case SYMBOL_TYPE:
177 return kSymbol;
178 case BIGINT_TYPE:
179 return kBigInt;
180 case ODDBALL_TYPE:
181 switch (map.oddball_type(broker)) {
183 break;
185 return kBoolean;
187 return kNull;
189 return kUndefined;
190 }
191 UNREACHABLE();
192 case HOLE_TYPE:
193 // Holes have a single map and we should have distinguished them earlier
194 // by pointer comparison on the value.
195 UNREACHABLE();
196 case HEAP_NUMBER_TYPE:
197 return kNumber;
198 case JS_ARRAY_ITERATOR_PROTOTYPE_TYPE:
199 case JS_ITERATOR_PROTOTYPE_TYPE:
200 case JS_MAP_ITERATOR_PROTOTYPE_TYPE:
201 case JS_OBJECT_PROTOTYPE_TYPE:
202 case JS_OBJECT_TYPE:
203 case JS_PROMISE_PROTOTYPE_TYPE:
204 case JS_REG_EXP_PROTOTYPE_TYPE:
205 case JS_SET_ITERATOR_PROTOTYPE_TYPE:
206 case JS_SET_PROTOTYPE_TYPE:
207 case JS_STRING_ITERATOR_PROTOTYPE_TYPE:
208 case JS_ARGUMENTS_OBJECT_TYPE:
209 case JS_ERROR_TYPE:
210 case JS_EXTERNAL_OBJECT_TYPE:
211 case JS_GLOBAL_OBJECT_TYPE:
212 case JS_GLOBAL_PROXY_TYPE:
213 case JS_API_OBJECT_TYPE:
214 case JS_SPECIAL_API_OBJECT_TYPE:
215 case JS_TYPED_ARRAY_PROTOTYPE_TYPE:
216 if (map.is_undetectable()) {
217 // Currently we assume that every undetectable receiver is also
218 // callable, which is what we need to support document.all. We
219 // could add another Type bit to support other use cases in the
220 // future if necessary.
221 DCHECK(map.is_callable());
222 return kOtherUndetectable;
223 }
224 if (map.is_callable()) {
225 return kOtherCallable;
226 }
227 return kOtherObject;
228 case JS_ARRAY_TYPE:
229 return kArray;
230 case JS_PRIMITIVE_WRAPPER_TYPE: {
231 DCHECK(!map.is_callable());
232 DCHECK(!map.is_undetectable());
233 auto elements_kind = map.elements_kind();
234 if (elements_kind == ElementsKind::FAST_STRING_WRAPPER_ELEMENTS ||
236 return kStringWrapper;
237 }
238 return kOtherObject;
239 }
240 case JS_MESSAGE_OBJECT_TYPE:
241 case JS_DATE_TYPE:
242#ifdef V8_INTL_SUPPORT
243 case JS_V8_BREAK_ITERATOR_TYPE:
244 case JS_COLLATOR_TYPE:
245 case JS_DATE_TIME_FORMAT_TYPE:
246 case JS_DISPLAY_NAMES_TYPE:
247 case JS_DURATION_FORMAT_TYPE:
248 case JS_LIST_FORMAT_TYPE:
249 case JS_LOCALE_TYPE:
250 case JS_NUMBER_FORMAT_TYPE:
251 case JS_PLURAL_RULES_TYPE:
252 case JS_RELATIVE_TIME_FORMAT_TYPE:
253 case JS_SEGMENT_ITERATOR_TYPE:
254 case JS_SEGMENTER_TYPE:
255 case JS_SEGMENTS_TYPE:
256#endif // V8_INTL_SUPPORT
257 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
258 case JS_DISPOSABLE_STACK_BASE_TYPE:
259 case JS_ASYNC_DISPOSABLE_STACK_TYPE:
260 case JS_SYNC_DISPOSABLE_STACK_TYPE:
261 case JS_GENERATOR_OBJECT_TYPE:
262 case JS_ASYNC_FUNCTION_OBJECT_TYPE:
263 case JS_ASYNC_GENERATOR_OBJECT_TYPE:
264 case JS_MODULE_NAMESPACE_TYPE:
265 case JS_ARRAY_BUFFER_TYPE:
266 case JS_ARRAY_ITERATOR_TYPE:
267 case JS_REG_EXP_TYPE:
268 case JS_REG_EXP_STRING_ITERATOR_TYPE:
269 case JS_DATA_VIEW_TYPE:
270 case JS_RAB_GSAB_DATA_VIEW_TYPE:
271 case JS_SET_TYPE:
272 case JS_MAP_TYPE:
273 case JS_SET_KEY_VALUE_ITERATOR_TYPE:
274 case JS_SET_VALUE_ITERATOR_TYPE:
275 case JS_MAP_KEY_ITERATOR_TYPE:
276 case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
277 case JS_MAP_VALUE_ITERATOR_TYPE:
278 case JS_STRING_ITERATOR_TYPE:
279 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
280 case JS_ITERATOR_MAP_HELPER_TYPE:
281 case JS_ITERATOR_FILTER_HELPER_TYPE:
282 case JS_ITERATOR_TAKE_HELPER_TYPE:
283 case JS_ITERATOR_DROP_HELPER_TYPE:
284 case JS_ITERATOR_FLAT_MAP_HELPER_TYPE:
285 case JS_VALID_ITERATOR_WRAPPER_TYPE:
286 case JS_FINALIZATION_REGISTRY_TYPE:
287 case JS_WEAK_MAP_TYPE:
288 case JS_WEAK_REF_TYPE:
289 case JS_WEAK_SET_TYPE:
290 case JS_PROMISE_TYPE:
291 case JS_SHADOW_REALM_TYPE:
292 case JS_SHARED_ARRAY_TYPE:
293 case JS_SHARED_STRUCT_TYPE:
294 case JS_ATOMICS_CONDITION_TYPE:
295 case JS_ATOMICS_MUTEX_TYPE:
296 case JS_TEMPORAL_CALENDAR_TYPE:
297 case JS_TEMPORAL_DURATION_TYPE:
298 case JS_TEMPORAL_INSTANT_TYPE:
299 case JS_TEMPORAL_PLAIN_DATE_TYPE:
300 case JS_TEMPORAL_PLAIN_DATE_TIME_TYPE:
301 case JS_TEMPORAL_PLAIN_MONTH_DAY_TYPE:
302 case JS_TEMPORAL_PLAIN_TIME_TYPE:
303 case JS_TEMPORAL_PLAIN_YEAR_MONTH_TYPE:
304 case JS_TEMPORAL_TIME_ZONE_TYPE:
305 case JS_TEMPORAL_ZONED_DATE_TIME_TYPE:
306 case JS_RAW_JSON_TYPE:
307#if V8_ENABLE_WEBASSEMBLY
308 case WASM_GLOBAL_OBJECT_TYPE:
309 case WASM_INSTANCE_OBJECT_TYPE:
310 case WASM_MEMORY_OBJECT_TYPE:
311 case WASM_MODULE_OBJECT_TYPE:
312 case WASM_SUSPENDER_OBJECT_TYPE:
313 case WASM_SUSPENDING_OBJECT_TYPE:
314 case WASM_TABLE_OBJECT_TYPE:
315 case WASM_TAG_OBJECT_TYPE:
316 case WASM_EXCEPTION_PACKAGE_TYPE:
317 case WASM_VALUE_OBJECT_TYPE:
318#endif // V8_ENABLE_WEBASSEMBLY
319 case WEAK_CELL_TYPE:
320 DCHECK(!map.is_callable());
321 DCHECK(!map.is_undetectable());
322 return kOtherObject;
323#if V8_ENABLE_WEBASSEMBLY
324 case WASM_STRUCT_TYPE:
325 case WASM_ARRAY_TYPE:
326 return kWasmObject;
327#endif // V8_ENABLE_WEBASSEMBLY
328 case JS_BOUND_FUNCTION_TYPE:
329 DCHECK(!map.is_undetectable());
330 return kBoundFunction;
331 case JS_WRAPPED_FUNCTION_TYPE:
332 DCHECK(!map.is_undetectable());
333 return kOtherCallable;
334 case JS_FUNCTION_TYPE:
335 case JS_PROMISE_CONSTRUCTOR_TYPE:
336 case JS_REG_EXP_CONSTRUCTOR_TYPE:
337 case JS_ARRAY_CONSTRUCTOR_TYPE:
338#define TYPED_ARRAY_CONSTRUCTORS_SWITCH(Type, type, TYPE, Ctype) \
339 case TYPE##_TYPED_ARRAY_CONSTRUCTOR_TYPE:
341#undef TYPED_ARRAY_CONSTRUCTORS_SWITCH
342 DCHECK(!map.is_undetectable());
343 return kCallableFunction;
344 case JS_TYPED_ARRAY_TYPE:
345 DCHECK(!map.is_callable());
346 DCHECK(!map.is_undetectable());
347 return kTypedArray;
348 case JS_CLASS_CONSTRUCTOR_TYPE:
349 return kClassConstructor;
350 case JS_PROXY_TYPE:
351 DCHECK(!map.is_undetectable());
352 if (map.is_callable()) return kCallableProxy;
353 return kOtherProxy;
354 case MAP_TYPE:
355 case ALLOCATION_SITE_TYPE:
356 case ACCESSOR_INFO_TYPE:
357 case SHARED_FUNCTION_INFO_TYPE:
358 case FUNCTION_TEMPLATE_INFO_TYPE:
359 case FUNCTION_TEMPLATE_RARE_DATA_TYPE:
360 case ACCESSOR_PAIR_TYPE:
361 case EMBEDDER_DATA_ARRAY_TYPE:
362 case FIXED_ARRAY_TYPE:
363 case CLASS_BOILERPLATE_TYPE:
364 case PROPERTY_DESCRIPTOR_OBJECT_TYPE:
365 case HASH_TABLE_TYPE:
366 case ORDERED_HASH_MAP_TYPE:
367 case ORDERED_HASH_SET_TYPE:
368 case ORDERED_NAME_DICTIONARY_TYPE:
369 case NAME_DICTIONARY_TYPE:
370 case GLOBAL_DICTIONARY_TYPE:
371 case NUMBER_DICTIONARY_TYPE:
372 case SIMPLE_NUMBER_DICTIONARY_TYPE:
373 case EPHEMERON_HASH_TABLE_TYPE:
374 case WEAK_FIXED_ARRAY_TYPE:
375 case WEAK_ARRAY_LIST_TYPE:
376 case FIXED_DOUBLE_ARRAY_TYPE:
377 case FEEDBACK_METADATA_TYPE:
378 case BYTE_ARRAY_TYPE:
379 case BYTECODE_ARRAY_TYPE:
380 case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
381 case ARRAY_BOILERPLATE_DESCRIPTION_TYPE:
382 case REG_EXP_BOILERPLATE_DESCRIPTION_TYPE:
383 case TRANSITION_ARRAY_TYPE:
384 case FEEDBACK_CELL_TYPE:
385 case CLOSURE_FEEDBACK_CELL_ARRAY_TYPE:
386 case FEEDBACK_VECTOR_TYPE:
387 case PROPERTY_ARRAY_TYPE:
388 case FOREIGN_TYPE:
389 case SCOPE_INFO_TYPE:
390 case SCRIPT_CONTEXT_TABLE_TYPE:
391 case AWAIT_CONTEXT_TYPE:
392 case BLOCK_CONTEXT_TYPE:
393 case CATCH_CONTEXT_TYPE:
394 case DEBUG_EVALUATE_CONTEXT_TYPE:
395 case EVAL_CONTEXT_TYPE:
396 case FUNCTION_CONTEXT_TYPE:
397 case MODULE_CONTEXT_TYPE:
398 case MODULE_REQUEST_TYPE:
399 case NATIVE_CONTEXT_TYPE:
400 case SCRIPT_CONTEXT_TYPE:
401 case WITH_CONTEXT_TYPE:
402 case SCRIPT_TYPE:
403 case INSTRUCTION_STREAM_TYPE:
404 case CODE_TYPE:
405 case PROPERTY_CELL_TYPE:
406 case CONTEXT_SIDE_PROPERTY_CELL_TYPE:
407 case SOURCE_TEXT_MODULE_TYPE:
408 case SOURCE_TEXT_MODULE_INFO_ENTRY_TYPE:
409 case SYNTHETIC_MODULE_TYPE:
410 case CELL_TYPE:
411 case PREPARSE_DATA_TYPE:
412 case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE:
413 case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE:
414 case COVERAGE_INFO_TYPE:
415 case REG_EXP_DATA_TYPE:
416 case ATOM_REG_EXP_DATA_TYPE:
417 case IR_REG_EXP_DATA_TYPE:
418#if V8_ENABLE_WEBASSEMBLY
419 case WASM_TYPE_INFO_TYPE:
420#endif // V8_ENABLE_WEBASSEMBLY
421 return kOtherInternal;
422
423 // Remaining instance types are unsupported for now. If any of them do
424 // require bit set types, they should get kOtherInternal.
425 default:
426 UNREACHABLE();
427 }
428 UNREACHABLE();
429}
430
431// Explicit instantiation.
433
436 if (IsMinusZero(value)) return kMinusZero;
437 if (std::isnan(value)) return kNaN;
438 if (IsUint32Double(value) || IsInt32Double(value)) return Lub(value, value);
439 return kOtherNumber;
440}
441
442// Minimum values of plain numeric bitsets.
444 {kOtherNumber, kPlainNumber, -V8_INFINITY},
445 {kOtherSigned32, kNegative32, kMinInt},
446 {kNegative31, kNegative31, -0x40000000},
447 {kUnsigned30, kUnsigned30, 0},
448 {kOtherUnsigned31, kUnsigned31, 0x40000000},
449 {kOtherUnsigned32, kUnsigned32, 0x80000000},
450 {kOtherNumber, kPlainNumber, static_cast<double>(kMaxUInt32) + 1}};
451
452const BitsetType::Boundary* BitsetType::Boundaries() { return BoundariesArray; }
453
455 // Windows doesn't like arraysize here.
456 // return arraysize(BoundariesArray);
457 return 7;
458}
459
461 DCHECK_IMPLIES(bits & kOtherString, (bits & kString) == kString);
463 if (!(bits & kPlainNumber)) return bits; // Shortcut.
464 const Boundary* boundaries = Boundaries();
465 for (size_t i = 0; i < BoundariesSize(); ++i) {
466 DCHECK(BitsetType::Is(boundaries[i].internal, boundaries[i].external));
467 if (bits & boundaries[i].internal) bits |= boundaries[i].external;
468 }
469 return bits;
470}
471
472Type::bitset BitsetType::Lub(double min, double max) {
474 bitset lub = kNone;
475 const Boundary* mins = Boundaries();
476
477 for (size_t i = 1; i < BoundariesSize(); ++i) {
478 if (min < mins[i].min) {
479 lub |= mins[i - 1].internal;
480 if (max < mins[i].min) return lub;
481 }
482 }
483 return lub | mins[BoundariesSize() - 1].internal;
484}
485
486Type::bitset BitsetType::NumberBits(bitset bits) { return bits & kPlainNumber; }
487
488Type::bitset BitsetType::Glb(double min, double max) {
490 bitset glb = kNone;
491 const Boundary* mins = Boundaries();
492
493 // If the range does not touch 0, the bound is empty.
494 if (max < -1 || min > 0) return glb;
495
496 for (size_t i = 1; i + 1 < BoundariesSize(); ++i) {
497 if (min <= mins[i].min) {
498 if (max + 1 < mins[i + 1].min) break;
499 glb |= mins[i].external;
500 }
501 }
502 // OtherNumber also contains float numbers, so it can never be
503 // in the greatest lower bound.
504 return glb & ~(kOtherNumber);
505}
506
509 DCHECK(Is(bits, kNumber));
510 DCHECK(!Is(bits, kNaN));
511 const Boundary* mins = Boundaries();
512 bool mz = bits & kMinusZero;
513 for (size_t i = 0; i < BoundariesSize(); ++i) {
514 if (Is(mins[i].internal, bits)) {
515 return mz ? std::min(0.0, mins[i].min) : mins[i].min;
516 }
517 }
518 DCHECK(mz);
519 return 0;
520}
521
524 DCHECK(Is(bits, kNumber));
525 DCHECK(!Is(bits, kNaN));
526 const Boundary* mins = Boundaries();
527 bool mz = bits & kMinusZero;
528 if (BitsetType::Is(mins[BoundariesSize() - 1].internal, bits)) {
529 return +V8_INFINITY;
530 }
531 for (size_t i = BoundariesSize() - 1; i-- > 0;) {
532 if (Is(mins[i].internal, bits)) {
533 return mz ? std::max(0.0, mins[i + 1].min - 1) : mins[i + 1].min - 1;
534 }
535 }
536 DCHECK(mz);
537 return 0;
538}
539
540// static
542 // Not an integer, not NaN, and not -0.
543 return !std::isnan(value) && !RangeType::IsInteger(value) &&
544 !IsMinusZero(value);
545}
546
548 HeapObjectRef heap_ref)
549 : TypeBase(kHeapConstant), bitset_(bitset), heap_ref_(heap_ref) {}
550
554
555// -----------------------------------------------------------------------------
556// Predicates.
557
558bool Type::SimplyEquals(Type that) const {
560 if (this->IsHeapConstant()) {
561 return that.IsHeapConstant() &&
562 this->AsHeapConstant()->Value().address() ==
563 that.AsHeapConstant()->Value().address();
564 }
565 if (this->IsOtherNumberConstant()) {
566 return that.IsOtherNumberConstant() &&
567 this->AsOtherNumberConstant()->Value() ==
568 that.AsOtherNumberConstant()->Value();
569 }
570 if (this->IsRange()) {
571 if (that.IsHeapConstant() || that.IsOtherNumberConstant()) return false;
572 }
573 if (this->IsTuple()) {
574 if (!that.IsTuple()) return false;
575 const TupleType* this_tuple = this->AsTuple();
576 const TupleType* that_tuple = that.AsTuple();
577 if (this_tuple->Arity() != that_tuple->Arity()) {
578 return false;
579 }
580 for (int i = 0, n = this_tuple->Arity(); i < n; ++i) {
581 if (!this_tuple->Element(i).Equals(that_tuple->Element(i))) return false;
582 }
583 return true;
584 }
585 UNREACHABLE();
586}
587
588// Check if [this] <= [that].
589bool Type::SlowIs(Type that) const {
591
592 // Fast bitset cases
593 if (that.IsBitset()) {
594 return BitsetType::Is(this->BitsetLub(), that.AsBitset());
595 }
596
597 if (this->IsBitset()) {
598 return BitsetType::Is(this->AsBitset(), that.BitsetGlb());
599 }
600
601 // (T1 \/ ... \/ Tn) <= T if (T1 <= T) /\ ... /\ (Tn <= T)
602 if (this->IsUnion()) {
603 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
604 if (!this->AsUnion()->Get(i).Is(that)) return false;
605 }
606 return true;
607 }
608
609 // T <= (T1 \/ ... \/ Tn) if (T <= T1) \/ ... \/ (T <= Tn)
610 if (that.IsUnion()) {
611 for (int i = 0, n = that.AsUnion()->Length(); i < n; ++i) {
612 if (this->Is(that.AsUnion()->Get(i))) return true;
613 if (i > 1 && this->IsRange()) return false; // Shortcut.
614 }
615 return false;
616 }
617
618 if (that.IsRange()) {
619 return this->IsRange() && Contains(that.AsRange(), this->AsRange());
620 }
621 if (this->IsRange()) return false;
622
623#ifdef V8_ENABLE_WEBASSEMBLY
624 if (this->IsWasm()) {
625 if (!that.IsWasm()) return false;
626 wasm::TypeInModule this_type = this->AsWasm();
627 wasm::TypeInModule that_type = that.AsWasm();
628 return wasm::IsSubtypeOf(this_type.type, that_type.type, this_type.module,
629 that_type.module);
630 }
631#endif
632
633 return this->SimplyEquals(that);
634}
635
636// Check if [this] and [that] overlap.
637bool Type::Maybe(Type that) const {
639
640 if (BitsetType::IsNone(this->BitsetLub() & that.BitsetLub())) return false;
641
642 // (T1 \/ ... \/ Tn) overlaps T if (T1 overlaps T) \/ ... \/ (Tn overlaps T)
643 if (this->IsUnion()) {
644 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
645 if (this->AsUnion()->Get(i).Maybe(that)) return true;
646 }
647 return false;
648 }
649
650 // T overlaps (T1 \/ ... \/ Tn) if (T overlaps T1) \/ ... \/ (T overlaps Tn)
651 if (that.IsUnion()) {
652 for (int i = 0, n = that.AsUnion()->Length(); i < n; ++i) {
653 if (this->Maybe(that.AsUnion()->Get(i))) return true;
654 }
655 return false;
656 }
657
658 if (this->IsBitset() && that.IsBitset()) return true;
659
660 if (this->IsRange()) {
661 if (that.IsRange()) {
662 return Overlap(this->AsRange(), that.AsRange());
663 }
664 if (that.IsBitset()) {
665 bitset number_bits = BitsetType::NumberBits(that.AsBitset());
666 if (number_bits == BitsetType::kNone) {
667 return false;
668 }
669 double min = std::max(BitsetType::Min(number_bits), this->Min());
670 double max = std::min(BitsetType::Max(number_bits), this->Max());
671 return min <= max;
672 }
673 }
674 if (that.IsRange()) {
675 return that.Maybe(*this); // This case is handled above.
676 }
677
678 if (this->IsBitset() || that.IsBitset()) return true;
679
680 return this->SimplyEquals(that);
681}
682
683// Return the range in [this], or [nullptr].
686 if (this->IsRange()) return *this;
687 if (this->IsUnion() && this->AsUnion()->Get(1).IsRange()) {
688 return this->AsUnion()->Get(1);
689 }
690 return nullptr;
691}
692
695 // This checks the invariants of the union representation:
696 // 1. There are at least two elements.
697 // 2. The first element is a bitset, no other element is a bitset.
698 // 3. At most one element is a range, and it must be the second one.
699 // 4. No element is itself a union.
700 // 5. No element (except the bitset) is a subtype of any other.
701 // 6. If there is a range, then the bitset type does not contain
702 // plain number bits.
703 DCHECK_LE(2, this->Length()); // (1)
704 DCHECK(this->Get(0).IsBitset()); // (2a)
705
706 for (int i = 0; i < this->Length(); ++i) {
707 if (i != 0) DCHECK(!this->Get(i).IsBitset()); // (2b)
708 if (i != 1) DCHECK(!this->Get(i).IsRange()); // (3)
709 DCHECK(!this->Get(i).IsUnion()); // (4)
710 for (int j = 0; j < this->Length(); ++j) {
711 if (i != j && i != 0) DCHECK(!this->Get(i).Is(this->Get(j))); // (5)
712 }
713 }
714 DCHECK(!this->Get(1).IsRange() ||
715 (BitsetType::NumberBits(this->Get(0).AsBitset()) ==
716 BitsetType::kNone)); // (6)
717 return true;
718}
719
720// -----------------------------------------------------------------------------
721// Union and intersection
722
723Type Type::Intersect(Type type1, Type type2, Zone* zone) {
724 // Fast case: bit sets.
725 if (type1.IsBitset() && type2.IsBitset()) {
726 return NewBitset(type1.AsBitset() & type2.AsBitset());
727 }
728
729 // Fast case: top or bottom types.
730 if (type1.IsNone() || type2.IsAny()) return type1; // Shortcut.
731 if (type2.IsNone() || type1.IsAny()) return type2; // Shortcut.
732
733 // Semi-fast case.
734 if (type1.Is(type2)) return type1;
735 if (type2.Is(type1)) return type2;
736
737 // Slow case: create union.
738
739 // Semantic subtyping check - this is needed for consistency with the
740 // semi-fast case above.
741 if (type1.Is(type2)) {
742 type2 = Any();
743 } else if (type2.Is(type1)) {
744 type1 = Any();
745 }
746
747 bitset bits = type1.BitsetGlb() & type2.BitsetGlb();
748 int size1 = type1.IsUnion() ? type1.AsUnion()->Length() : 1;
749 int size2 = type2.IsUnion() ? type2.AsUnion()->Length() : 1;
750 int size;
751 if (base::bits::SignedAddOverflow32(size1, size2, &size)) return Any();
752 if (base::bits::SignedAddOverflow32(size, 2, &size)) return Any();
753 UnionType* result = UnionType::New(size, zone);
754 size = 0;
755
756 // Deal with bitsets.
757 result->Set(size++, NewBitset(bits));
758
760 size = IntersectAux(type1, type2, result, size, &lims, zone);
761
762 // If the range is not empty, then insert it into the union and
763 // remove the number bits from the bitset.
764 if (!lims.IsEmpty()) {
765 size = UpdateRange(Type::Range(lims, zone), result, size, zone);
766
767 // Remove the number bits.
768 bitset number_bits = BitsetType::NumberBits(bits);
769 bits &= ~number_bits;
770 result->Set(0, NewBitset(bits));
771 }
772 return NormalizeUnion(result, size, zone);
773}
774
775int Type::UpdateRange(Type range, UnionType* result, int size, Zone* zone) {
776 if (size == 1) {
777 result->Set(size++, range);
778 } else {
779 // Make space for the range.
780 result->Set(size++, result->Get(1));
781 result->Set(1, range);
782 }
783
784 // Remove any components that just got subsumed.
785 for (int i = 2; i < size;) {
786 if (result->Get(i).Is(range)) {
787 result->Set(i, result->Get(--size));
788 } else {
789 ++i;
790 }
791 }
792 return size;
793}
794
796 bitset number_bits = BitsetType::NumberBits(bits);
797
798 if (number_bits == BitsetType::kNone) {
800 }
801
802 return RangeType::Limits(BitsetType::Min(number_bits),
803 BitsetType::Max(number_bits));
804}
805
807 Zone* zone) {
808 RangeType::Limits range_lims(range.AsRange());
809 RangeType::Limits bitset_lims = ToLimits(bitset.AsBitset(), zone);
810 return RangeType::Limits::Intersect(range_lims, bitset_lims);
811}
812
813int Type::IntersectAux(Type lhs, Type rhs, UnionType* result, int size,
814 RangeType::Limits* lims, Zone* zone) {
815 if (lhs.IsUnion()) {
816 for (int i = 0, n = lhs.AsUnion()->Length(); i < n; ++i) {
817 size = IntersectAux(lhs.AsUnion()->Get(i), rhs, result, size, lims, zone);
818 }
819 return size;
820 }
821 if (rhs.IsUnion()) {
822 for (int i = 0, n = rhs.AsUnion()->Length(); i < n; ++i) {
823 size = IntersectAux(lhs, rhs.AsUnion()->Get(i), result, size, lims, zone);
824 }
825 return size;
826 }
827
828 if (BitsetType::IsNone(lhs.BitsetLub() & rhs.BitsetLub())) return size;
829
830 if (lhs.IsRange()) {
831 if (rhs.IsBitset()) {
832 RangeType::Limits lim = IntersectRangeAndBitset(lhs, rhs, zone);
833
834 if (!lim.IsEmpty()) {
835 *lims = RangeType::Limits::Union(lim, *lims);
836 }
837 return size;
838 }
839 if (rhs.IsRange()) {
842 if (!lim.IsEmpty()) {
843 *lims = RangeType::Limits::Union(lim, *lims);
844 }
845 }
846 return size;
847 }
848 if (rhs.IsRange()) {
849 // This case is handled symmetrically above.
850 return IntersectAux(rhs, lhs, result, size, lims, zone);
851 }
852 if (lhs.IsBitset() || rhs.IsBitset()) {
853 return AddToUnion(lhs.IsBitset() ? rhs : lhs, result, size, zone);
854 }
855 if (lhs.SimplyEquals(rhs)) {
856 return AddToUnion(lhs, result, size, zone);
857 }
858 return size;
859}
860
861// Make sure that we produce a well-formed range and bitset:
862// If the range is non-empty, the number bits in the bitset should be
863// clear. Moreover, if we have a canonical range (such as Signed32),
864// we want to produce a bitset rather than a range.
866 // Fast path: If the bitset does not mention numbers, we can just keep the
867 // range.
868 bitset number_bits = BitsetType::NumberBits(*bits);
869 if (number_bits == 0) {
870 return range;
871 }
872
873 // If the range is semantically contained within the bitset, return None and
874 // leave the bitset untouched.
875 bitset range_lub = range.BitsetLub();
876 if (BitsetType::Is(range_lub, *bits)) {
877 return None();
878 }
879
880 // Slow path: reconcile the bitset range and the range.
881 double bitset_min = BitsetType::Min(number_bits);
882 double bitset_max = BitsetType::Max(number_bits);
883
884 double range_min = range.Min();
885 double range_max = range.Max();
886
887 // Remove the number bits from the bitset, they would just confuse us now.
888 // NOTE: bits contains OtherNumber iff bits contains PlainNumber, in which
889 // case we already returned after the subtype check above.
890 *bits &= ~number_bits;
891
892 if (range_min <= bitset_min && range_max >= bitset_max) {
893 // Bitset is contained within the range, just return the range.
894 return range;
895 }
896
897 if (bitset_min < range_min) {
898 range_min = bitset_min;
899 }
900 if (bitset_max > range_max) {
901 range_max = bitset_max;
902 }
903 return Type::Range(range_min, range_max, zone);
904}
905
906Type Type::Constant(double value, Zone* zone) {
907 if (RangeType::IsInteger(value)) {
908 return Range(value, value, zone);
909 } else if (IsMinusZero(value)) {
910 return Type::MinusZero();
911 } else if (std::isnan(value)) {
912 return Type::NaN();
913 }
914
916 return OtherNumberConstant(value, zone);
917}
918
920 // TODO(jgruber,chromium:1209798): Using kAssumeMemoryFence works around
921 // the fact that the graph stores handles (and not refs). The assumption is
922 // that any handle inserted into the graph is safe to read; but we don't
923 // preserve the reason why it is safe to read. Thus we must over-approximate
924 // here and assume the existence of a memory fence. In the future, we should
925 // consider having the graph store ObjectRefs or ObjectData pointer instead,
926 // which would make new ref construction here unnecessary.
927 ObjectRef ref = MakeRefAssumeMemoryFence(broker, value);
928 return Constant(broker, ref, zone);
929}
930
931Type Type::Constant(JSHeapBroker* broker, ObjectRef ref, Zone* zone) {
932 if (ref.IsSmi()) {
933 return Constant(static_cast<double>(ref.AsSmi()), zone);
934 }
935 if (ref.IsString() && !ref.IsInternalizedString()) {
936 return Type::String();
937 }
938 if (ref.IsJSPrimitiveWrapper() &&
939 ref.AsJSPrimitiveWrapper().IsStringWrapper(broker)) {
940 return Type::StringWrapper();
941 }
942 if (ref.HoleType() != HoleType::kNone) {
943 return Type::Hole();
944 }
945 if (ref.IsJSTypedArray()) {
946 return Type::TypedArray();
947 }
948 // If we see a HeapNumber wrapped in a Constant node,
949 // then it should be a mutable HeapNumber, and it should be
950 // treated as HeapConstants. Any other number, should
951 // use Type::Constant(double, Zone*).
952 return HeapConstant(ref.AsHeapObject(), broker, zone);
953}
954
955Type Type::Union(Type type1, Type type2, Zone* zone) {
956 // Fast case: bit sets.
957 if (type1.IsBitset() && type2.IsBitset()) {
958 return NewBitset(type1.AsBitset() | type2.AsBitset());
959 }
960
961 // Fast case: top or bottom types.
962 if (type1.IsAny() || type2.IsNone()) return type1;
963 if (type2.IsAny() || type1.IsNone()) return type2;
964
965 // Semi-fast case.
966 if (type1.Is(type2)) return type2;
967 if (type2.Is(type1)) return type1;
968
969 // Slow case: create union.
970 int size1 = type1.IsUnion() ? type1.AsUnion()->Length() : 1;
971 int size2 = type2.IsUnion() ? type2.AsUnion()->Length() : 1;
972 int size;
973 if (base::bits::SignedAddOverflow32(size1, size2, &size)) return Any();
974 if (base::bits::SignedAddOverflow32(size, 2, &size)) return Any();
975 UnionType* result = UnionType::New(size, zone);
976 size = 0;
977
978 // Compute the new bitset.
979 bitset new_bitset = type1.BitsetGlb() | type2.BitsetGlb();
980
981 // Deal with ranges.
982 Type range = None();
983 Type range1 = type1.GetRange();
984 Type range2 = type2.GetRange();
985 if (range1 != nullptr && range2 != nullptr) {
986 RangeType::Limits lims =
988 RangeType::Limits(range2.AsRange()));
989 Type union_range = Type::Range(lims, zone);
990 range = NormalizeRangeAndBitset(union_range, &new_bitset, zone);
991 } else if (range1 != nullptr) {
992 range = NormalizeRangeAndBitset(range1, &new_bitset, zone);
993 } else if (range2 != nullptr) {
994 range = NormalizeRangeAndBitset(range2, &new_bitset, zone);
995 }
996 Type bits = NewBitset(new_bitset);
997 result->Set(size++, bits);
998 if (!range.IsNone()) result->Set(size++, range);
999
1000 size = AddToUnion(type1, result, size, zone);
1001 size = AddToUnion(type2, result, size, zone);
1002 return NormalizeUnion(result, size, zone);
1003}
1004
1005// Add [type] to [result] unless [type] is bitset, range, or already subsumed.
1006// Return new size of [result].
1007int Type::AddToUnion(Type type, UnionType* result, int size, Zone* zone) {
1008 if (type.IsBitset() || type.IsRange()) return size;
1009 if (type.IsUnion()) {
1010 for (int i = 0, n = type.AsUnion()->Length(); i < n; ++i) {
1011 size = AddToUnion(type.AsUnion()->Get(i), result, size, zone);
1012 }
1013 return size;
1014 }
1015 for (int i = 0; i < size; ++i) {
1016 if (type.Is(result->Get(i))) return size;
1017 }
1018 result->Set(size++, type);
1019 return size;
1020}
1021
1022Type Type::NormalizeUnion(UnionType* unioned, int size, Zone* zone) {
1023 DCHECK_LE(1, size);
1024 DCHECK(unioned->Get(0).IsBitset());
1025 // If the union has just one element, return it.
1026 if (size == 1) {
1027 return unioned->Get(0);
1028 }
1029 bitset bits = unioned->Get(0).AsBitset();
1030 // If the union only consists of a range, we can get rid of the union.
1031 if (size == 2 && bits == BitsetType::kNone) {
1032 if (unioned->Get(1).IsRange()) {
1033 return Type::Range(unioned->Get(1).AsRange()->Min(),
1034 unioned->Get(1).AsRange()->Max(), zone);
1035 }
1036 }
1037 unioned->Shrink(size);
1038 SLOW_DCHECK(unioned->Wellformed());
1039 return Type(unioned);
1040}
1041
1044 if (this->IsHeapConstant() || this->IsOtherNumberConstant()) {
1045 return 1;
1046 } else if (this->IsUnion()) {
1047 int result = 0;
1048 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
1049 if (this->AsUnion()->Get(i).IsHeapConstant()) ++result;
1050 }
1051 return result;
1052 } else {
1053 return 0;
1054 }
1055}
1056
1057// -----------------------------------------------------------------------------
1058// Printing.
1059
1060const char* BitsetType::Name(bitset bits) {
1061 switch (bits) {
1062#define RETURN_NAMED_TYPE(type, value) \
1063 case k##type: \
1064 return #type;
1067#undef RETURN_NAMED_TYPE
1068
1069 default:
1070 return nullptr;
1071 }
1072}
1073
1074void BitsetType::Print(std::ostream& os, bitset bits) {
1076 const char* name = Name(bits);
1077 if (name != nullptr) {
1078 os << name;
1079 return;
1080 }
1081
1082 // clang-format off
1083 static const bitset named_bitsets[] = {
1084#define BITSET_CONSTANT(type, value) k##type,
1087#undef BITSET_CONSTANT
1088 };
1089 // clang-format on
1090
1091 bool is_first = true;
1092 os << "(";
1093 for (int i(arraysize(named_bitsets) - 1); bits != 0 && i >= 0; --i) {
1094 bitset subset = named_bitsets[i];
1095 if ((bits & subset) == subset) {
1096 if (!is_first) os << " | ";
1097 is_first = false;
1098 os << Name(subset);
1099 bits -= subset;
1100 }
1101 }
1102 DCHECK_EQ(0, bits);
1103 os << ")";
1104}
1105
1106void Type::PrintTo(std::ostream& os) const {
1108 if (this->IsBitset()) {
1109 BitsetType::Print(os, this->AsBitset());
1110 } else if (this->IsHeapConstant()) {
1111 os << "HeapConstant(" << this->AsHeapConstant()->Ref() << ")";
1112 } else if (this->IsOtherNumberConstant()) {
1113 os << "OtherNumberConstant(" << this->AsOtherNumberConstant()->Value()
1114 << ")";
1115 } else if (this->IsRange()) {
1116 std::ostream::fmtflags saved_flags = os.setf(std::ios::fixed);
1117 std::streamsize saved_precision = os.precision(0);
1118 os << "Range(" << this->AsRange()->Min() << ", " << this->AsRange()->Max()
1119 << ")";
1120 os.flags(saved_flags);
1121 os.precision(saved_precision);
1122 } else if (this->IsUnion()) {
1123 os << "(";
1124 for (int i = 0, n = this->AsUnion()->Length(); i < n; ++i) {
1125 Type type_i = this->AsUnion()->Get(i);
1126 if (i > 0) os << " | ";
1127 os << type_i;
1128 }
1129 os << ")";
1130 } else if (this->IsTuple()) {
1131 os << "<";
1132 for (int i = 0, n = this->AsTuple()->Arity(); i < n; ++i) {
1133 Type type_i = this->AsTuple()->Element(i);
1134 if (i > 0) os << ", ";
1135 os << type_i;
1136 }
1137 os << ">";
1138#ifdef V8_ENABLE_WEBASSEMBLY
1139 } else if (this->IsWasm()) {
1140 os << "Wasm:" << this->AsWasm().type.name();
1141#endif
1142 } else {
1143 UNREACHABLE();
1144 }
1145}
1146
1147#ifdef DEBUG
1148void Type::Print() const {
1149 StdoutStream os;
1150 PrintTo(os);
1151 os << std::endl;
1152}
1153void BitsetType::Print(bitset bits) {
1154 StdoutStream os;
1155 Print(os, bits);
1156 os << std::endl;
1157}
1158#endif
1159
1163
1165 return SmiValuesAre31Bits() ? kUnsigned30 : kUnsigned31;
1166}
1167
1168// static
1169Type Type::Tuple(Type first, Type second, Type third, Zone* zone) {
1170 TupleType* tuple = TupleType::New(3, zone);
1171 tuple->InitElement(0, first);
1172 tuple->InitElement(1, second);
1173 tuple->InitElement(2, third);
1174 return FromTypeBase(tuple);
1175}
1176
1178 TupleType* tuple = TupleType::New(2, zone);
1179 tuple->InitElement(0, first);
1180 tuple->InitElement(1, second);
1181 return FromTypeBase(tuple);
1182}
1183
1184// static
1186 return FromTypeBase(OtherNumberConstantType::New(value, zone));
1187}
1188
1189// static
1191 DCHECK_EQ(value.HoleType(), HoleType::kNone);
1192 DCHECK_IMPLIES(value.IsString(), value.IsInternalizedString());
1194 BitsetType::Lub(value.GetHeapObjectType(broker), broker);
1195 if (Type(bitset).IsSingleton()) return Type(bitset);
1196 return HeapConstantType::New(value, bitset, zone);
1197}
1198
1199// static
1200Type Type::Range(double min, double max, Zone* zone) {
1201 return FromTypeBase(RangeType::New(min, max, zone));
1202}
1203
1204// static
1206 return FromTypeBase(RangeType::New(lims, zone));
1207}
1208
1211 return static_cast<const HeapConstantType*>(ToTypeBase());
1212}
1213
1218
1219const RangeType* Type::AsRange() const {
1221 return static_cast<const RangeType*>(ToTypeBase());
1222}
1223
1224const TupleType* Type::AsTuple() const {
1226 return static_cast<const TupleType*>(ToTypeBase());
1227}
1228
1229const UnionType* Type::AsUnion() const {
1231 return static_cast<const UnionType*>(ToTypeBase());
1232}
1233
1234#ifdef V8_ENABLE_WEBASSEMBLY
1235// static
1236Type Type::Wasm(wasm::ValueType value_type, const wasm::WasmModule* module,
1237 Zone* zone) {
1238 return FromTypeBase(WasmType::New(value_type, module, zone));
1239}
1240
1241// static
1242Type Type::Wasm(wasm::TypeInModule type_in_module, Zone* zone) {
1243 return Wasm(type_in_module.type, type_in_module.module, zone);
1244}
1245
1246wasm::TypeInModule Type::AsWasm() const {
1248 auto wasm_type = static_cast<const WasmType*>(ToTypeBase());
1249 return {wasm_type->value_type(), wasm_type->module()};
1250}
1251#endif
1252
1253std::ostream& operator<<(std::ostream& os, Type type) {
1254 type.PrintTo(os);
1255 return os;
1256}
1257
1260 if (IsBitset()) {
1261 const bitset bits = AsBitset();
1262 uint32_t low = bits & 0xffffffff;
1263 uint32_t high = (bits >> 32) & 0xffffffff;
1264 return factory->NewTurbofanBitsetType(low, high, AllocationType::kYoung);
1265 } else if (IsUnion()) {
1266 const UnionType* union_type = AsUnion();
1267 Handle<TurbofanType> result = union_type->Get(0).AllocateOnHeap(factory);
1268 for (int i = 1; i < union_type->Length(); ++i) {
1269 result = factory->NewTurbofanUnionType(
1270 result, union_type->Get(i).AllocateOnHeap(factory),
1272 }
1273 return result;
1274 } else if (IsHeapConstant()) {
1275 return factory->NewTurbofanHeapConstantType(AsHeapConstant()->Value(),
1277 } else if (IsOtherNumberConstant()) {
1278 return factory->NewTurbofanOtherNumberConstantType(
1280 } else if (IsRange()) {
1281 return factory->NewTurbofanRangeType(AsRange()->Min(), AsRange()->Max(),
1283 } else {
1284 // Other types are not supported for type assertions.
1285 UNREACHABLE();
1286 }
1287}
1288
1289#define VERIFY_TORQUE_LOW_BITSET_AGREEMENT(Name, _) \
1290 static_assert(static_cast<uint32_t>(BitsetType::k##Name) == \
1291 static_cast<uint32_t>(TurbofanTypeLowBits::k##Name));
1292#define VERIFY_TORQUE_HIGH_BITSET_AGREEMENT(Name, _) \
1293 static_assert(static_cast<uint32_t>( \
1294 static_cast<uint64_t>(BitsetType::k##Name) >> 32) == \
1295 static_cast<uint32_t>(TurbofanTypeHighBits::k##Name));
1299#undef VERIFY_TORQUE_HIGH_BITSET_AGREEMENT
1300#undef VERIFY_TORQUE_LOW_BITSET_AGREEMENT
1301
1302} // namespace compiler
1303} // namespace internal
1304} // namespace v8
#define SLOW_DCHECK(condition)
Definition checks.h:21
static bitset Glb(double min, double max)
static bool Is(bitset bits1, bitset bits2)
static void Print(std::ostream &os, bitset)
static const char * Name(bitset)
static const Boundary BoundariesArray[]
static const Boundary * Boundaries()
static bool IsNone(bitset bits)
static bitset Lub(HeapObjectType const &type, JSHeapBroker *broker)
static bitset NumberBits(bitset bits)
static bitset ExpandInternals(bitset bits)
HeapConstantType(BitsetType::bitset bitset, HeapObjectRef heap_ref)
static HeapConstantType * New(HeapObjectRef heap_ref, BitsetType::bitset bitset, Zone *zone)
IndirectHandle< HeapObject > object() const
static OtherNumberConstantType * New(double value, Zone *zone)
BitsetType::bitset Lub() const
static RangeType * New(double min, double max, Zone *zone)
void InitElement(int i, Type type)
static TupleType * New(int length, Zone *zone)
static bool Contains(const RangeType *lhs, const RangeType *rhs)
static int IntersectAux(Type type, Type other, UnionType *result, int size, RangeType::Limits *limits, Zone *zone)
static Type Union(Type type1, Type type2, Zone *zone)
static RangeType::Limits ToLimits(bitset bits, Zone *zone)
static Type HeapConstant(HeapObjectRef value, JSHeapBroker *broker, Zone *zone)
const UnionType * AsUnion() const
bool Maybe(Type that) const
const OtherNumberConstantType * AsOtherNumberConstant() const
void PrintTo(std::ostream &os) const
const HeapConstantType * AsHeapConstant() const
bool SlowIs(Type that) const
static Type Constant(JSHeapBroker *broker, Handle< i::Object > value, Zone *zone)
const TupleType * AsTuple() const
const TypeBase * ToTypeBase() const
bool Equals(Type that) const
static Type OtherNumberConstant(double value, Zone *zone)
static int UpdateRange(Type type, UnionType *result, int size, Zone *zone)
static Type Tuple(Type first, Type second, Type third, Zone *zone)
bool SimplyEquals(Type that) const
static Type Intersect(Type type1, Type type2, Zone *zone)
bool Is(Type that) const
static Type NormalizeRangeAndBitset(Type range, bitset *bits, Zone *zone)
static bool Overlap(const RangeType *lhs, const RangeType *rhs)
const RangeType * AsRange() const
static Type FromTypeBase(TypeBase *type)
Handle< TurbofanType > AllocateOnHeap(Factory *factory)
static Type Range(double min, double max, Zone *zone)
static Type NewBitset(bitset bits)
static int AddToUnion(Type type, UnionType *result, int size, Zone *zone)
static RangeType::Limits IntersectRangeAndBitset(Type range, Type bits, Zone *zone)
bool IsKind(TypeBase::Kind kind) const
static Type NormalizeUnion(UnionType *unioned, int size, Zone *zone)
static UnionType * New(int length, Zone *zone)
#define V8_INFINITY
Definition globals.h:23
#define PROPER_BITSET_TYPE_LIST(V)
#define PROPER_ATOMIC_BITSET_TYPE_HIGH_LIST(V)
#define INTERNAL_BITSET_TYPE_LIST(V)
#define PROPER_ATOMIC_BITSET_TYPE_LOW_LIST(V)
#define TYPED_ARRAYS(V)
JSHeapBroker * broker
double second
ZoneVector< RpoNumber > & result
int n
Definition mul-fft.cc:296
bool SignedAddOverflow32(int32_t lhs, int32_t rhs, int32_t *val)
Definition bits.h:296
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
ref_traits< T >::ref_type MakeRefAssumeMemoryFence(JSHeapBroker *broker, Tagged< T > object)
std::ostream & operator<<(std::ostream &os, AccessMode access_mode)
V8_INLINE bool IsSubtypeOf(ValueType subtype, ValueType supertype, const WasmModule *sub_module, const WasmModule *super_module)
bool IsUint32Double(double value)
constexpr int kMinInt
Definition globals.h:375
bool Is(IndirectHandle< U > value)
Definition handles-inl.h:51
bool IsInt32Double(double value)
@ SLOW_STRING_WRAPPER_ELEMENTS
@ FAST_STRING_WRAPPER_ELEMENTS
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
constexpr bool SmiValuesAre31Bits()
@ UNCACHED_EXTERNAL_INTERNALIZED_ONE_BYTE_STRING_TYPE
@ SHARED_SEQ_ONE_BYTE_STRING_TYPE
@ SHARED_SEQ_TWO_BYTE_STRING_TYPE
@ UNCACHED_EXTERNAL_TWO_BYTE_STRING_TYPE
@ SHARED_EXTERNAL_TWO_BYTE_STRING_TYPE
@ UNCACHED_EXTERNAL_INTERNALIZED_TWO_BYTE_STRING_TYPE
@ SLICED_TWO_BYTE_STRING_TYPE
@ UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE
@ SHARED_UNCACHED_EXTERNAL_TWO_BYTE_STRING_TYPE
@ SLICED_ONE_BYTE_STRING_TYPE
@ EXTERNAL_TWO_BYTE_STRING_TYPE
@ SHARED_UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE
@ EXTERNAL_INTERNALIZED_TWO_BYTE_STRING_TYPE
@ SHARED_EXTERNAL_ONE_BYTE_STRING_TYPE
@ EXTERNAL_INTERNALIZED_ONE_BYTE_STRING_TYPE
@ EXTERNAL_ONE_BYTE_STRING_TYPE
@ INTERNALIZED_ONE_BYTE_STRING_TYPE
@ INTERNALIZED_TWO_BYTE_STRING_TYPE
static bool IsMinusZero(double value)
constexpr uint32_t kMaxUInt32
Definition globals.h:387
@ None
Definition v8-object.h:141
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define arraysize(array)
Definition macros.h:67
static Limits Union(Limits lhs, Limits rhs)
static Limits Intersect(Limits lhs, Limits rhs)
#define TYPED_ARRAY_CONSTRUCTORS_SWITCH(Type, type, TYPE, Ctype)
#define BITSET_CONSTANT(type, value)
#define VERIFY_TORQUE_LOW_BITSET_AGREEMENT(Name, _)
#define VERIFY_TORQUE_HIGH_BITSET_AGREEMENT(Name, _)
#define RETURN_NAMED_TYPE(type, value)