Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
type_propagator.cc
Go to the documentation of this file.
1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6
8
9#include "vm/bit_vector.h"
11#include "vm/object_store.h"
12#include "vm/regexp_assembler.h"
13#include "vm/resolver.h"
14#include "vm/timeline.h"
15
16namespace dart {
17
19 trace_type_propagation,
20 false,
21 "Trace flow graph type propagation");
22
23static void TraceStrongModeType(const Instruction* instr,
24 const AbstractType& type) {
25 if (FLAG_trace_strong_mode_types) {
26 THR_Print("[Strong mode] Type of %s - %s\n", instr->ToCString(),
27 type.ToCString());
28 }
29}
30
31static void TraceStrongModeType(const Instruction* instr,
32 CompileType* compileType) {
33 if (FLAG_trace_strong_mode_types) {
34 const AbstractType* type = compileType->ToAbstractType();
35 if ((type != nullptr) && !type->IsDynamicType()) {
37 }
38 }
39}
40
41void FlowGraphTypePropagator::Propagate(FlowGraph* flow_graph) {
42 TIMELINE_DURATION(flow_graph->thread(), CompilerVerbose,
43 "FlowGraphTypePropagator");
44 FlowGraphTypePropagator propagator(flow_graph);
45 propagator.Propagate();
46}
47
48FlowGraphTypePropagator::FlowGraphTypePropagator(FlowGraph* flow_graph)
49 : FlowGraphVisitor(flow_graph->reverse_postorder()),
50 flow_graph_(flow_graph),
51 is_aot_(CompilerState::Current().is_aot()),
52 visited_blocks_(new(flow_graph->zone())
53 BitVector(flow_graph->zone(),
54 flow_graph->reverse_postorder().length())),
55 types_(flow_graph->current_ssa_temp_index()),
56 in_worklist_(nullptr),
57 asserts_(nullptr),
58 collected_asserts_(nullptr) {
59 for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
60 types_.Add(nullptr);
61 }
62
63 asserts_ = new ZoneGrowableArray<AssertAssignableInstr*>(
64 flow_graph->current_ssa_temp_index());
65 for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
66 asserts_->Add(nullptr);
67 }
68
69 collected_asserts_ = new ZoneGrowableArray<intptr_t>(10);
70}
71
72void FlowGraphTypePropagator::Propagate() {
73 // Walk the dominator tree and propagate reaching types to all Values.
74 // Collect all phis for a fixed point iteration.
75 PropagateRecursive(flow_graph_->graph_entry());
76
77 // Initially the worklist contains only phis.
78 // Reset compile type of all phis to None to ensure that
79 // types are correctly propagated through the cycles of
80 // phis.
81 in_worklist_ = new (flow_graph_->zone())
82 BitVector(flow_graph_->zone(), flow_graph_->current_ssa_temp_index());
83 for (intptr_t i = 0; i < worklist_.length(); i++) {
84 ASSERT(worklist_[i]->IsPhi());
85 *worklist_[i]->Type() = CompileType::None();
86 }
87
88 // Iterate until a fixed point is reached, updating the types of
89 // definitions.
90 while (!worklist_.is_empty()) {
91 Definition* def = RemoveLastFromWorklist();
92 if (FLAG_support_il_printer && FLAG_trace_type_propagation &&
93 flow_graph_->should_print()) {
94 THR_Print("recomputing type of v%" Pd ": %s\n", def->ssa_temp_index(),
95 def->Type()->ToCString());
96 }
97 if (def->RecomputeType()) {
98 if (FLAG_support_il_printer && FLAG_trace_type_propagation &&
99 flow_graph_->should_print()) {
100 THR_Print(" ... new type %s\n", def->Type()->ToCString());
101 }
102 for (Value::Iterator it(def->input_use_list()); !it.Done();
103 it.Advance()) {
104 Instruction* instr = it.Current()->instruction();
105
106 Definition* use_defn = instr->AsDefinition();
107 if (use_defn != nullptr) {
108 AddToWorklist(use_defn);
109 }
110 }
111 }
112 }
113}
114
115void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
116 if (visited_blocks_->Contains(block->postorder_number())) {
117 return;
118 }
119 visited_blocks_->Add(block->postorder_number());
120
121 const intptr_t rollback_point = rollback_.length();
122
123 if (!is_aot_) {
124 // Don't try to strengthen asserts with class checks in AOT mode, this is a
125 // speculative optimization which only really makes sense in JIT mode.
126 // It is also written to expect environments to be attached to
127 // AssertAssignable instructions, which is not always a case in AOT mode.
128 StrengthenAsserts(block);
129 }
130
131 block->Accept(this);
132
133 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
134 Instruction* instr = it.Current();
135
136 for (intptr_t i = 0; i < instr->InputCount(); i++) {
137 VisitValue(instr->InputAt(i));
138 }
139 if (instr->IsDefinition()) {
140 instr->AsDefinition()->RecomputeType();
141 }
142 instr->Accept(this);
143 }
144
145 GotoInstr* goto_instr = block->last_instruction()->AsGoto();
146 if (goto_instr != nullptr) {
147 JoinEntryInstr* join = goto_instr->successor();
148 intptr_t pred_index = join->IndexOfPredecessor(block);
149 ASSERT(pred_index >= 0);
150 for (PhiIterator it(join); !it.Done(); it.Advance()) {
151 VisitValue(it.Current()->InputAt(pred_index));
152 }
153 }
154
155 for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
156 PropagateRecursive(block->dominated_blocks()[i]);
157 }
158
159 RollbackTo(rollback_point);
160}
161
162void FlowGraphTypePropagator::RollbackTo(intptr_t rollback_point) {
163 for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
164 types_[rollback_[i].index()] = rollback_[i].type();
165 }
166 rollback_.TruncateTo(rollback_point);
167}
168
169CompileType* FlowGraphTypePropagator::TypeOf(Definition* def) {
170 const intptr_t index = def->ssa_temp_index();
171
172 CompileType* type = types_[index];
173 if (type == nullptr) {
174 type = types_[index] = def->Type();
175 ASSERT(type != nullptr);
176 }
177 return type;
178}
179
180void FlowGraphTypePropagator::SetTypeOf(Definition* def, CompileType* type) {
181 const intptr_t index = def->ssa_temp_index();
182 rollback_.Add(RollbackEntry(index, types_[index]));
183 types_[index] = type;
184}
185
186void FlowGraphTypePropagator::SetCid(Definition* def, intptr_t cid) {
187 CompileType* current = TypeOf(def);
188 if (current->IsNone() || (current->ToCid() != cid)) {
189 SetTypeOf(def, new (zone()) CompileType(CompileType::FromCid(cid)));
190 }
191}
192
193void FlowGraphTypePropagator::GrowTypes(intptr_t up_to) {
194 // Grow types array if a new redefinition was inserted.
195 for (intptr_t i = types_.length(); i <= up_to; ++i) {
196 types_.Add(nullptr);
197 }
198}
199
200void FlowGraphTypePropagator::EnsureMoreAccurateRedefinition(
201 Instruction* prev,
202 Definition* original,
203 CompileType new_type) {
204 RedefinitionInstr* redef =
205 flow_graph_->EnsureRedefinition(prev, original, new_type);
206 if (redef != nullptr) {
207 GrowTypes(redef->ssa_temp_index() + 1);
208 }
209}
210
211void FlowGraphTypePropagator::VisitValue(Value* value) {
212 CompileType* type = TypeOf(value->definition());
213
214 // Force propagation of None type (which means unknown) to inputs of phis
215 // in order to avoid contamination of cycles of phis with previously inferred
216 // types.
217 if (type->IsNone() && value->instruction()->IsPhi()) {
218 value->SetReachingType(type);
219 } else {
220 value->RefineReachingType(type);
221 }
222
223 if (FLAG_support_il_printer && FLAG_trace_type_propagation &&
224 flow_graph_->should_print()) {
225 THR_Print("reaching type to %s for v%" Pd " is %s\n",
226 value->instruction()->ToCString(),
227 value->definition()->ssa_temp_index(),
228 value->Type()->ToCString());
229 }
230}
231
233 for (PhiIterator it(join); !it.Done(); it.Advance()) {
234 worklist_.Add(it.Current());
235 }
236}
237
239 SetCid(check->value()->definition(), kSmiCid);
240}
241
244 // Array bounds checks also test index for smi.
245 SetCid(check->index()->definition(), kSmiCid);
246}
247
249 // Use a monomorphic cid directly.
250 const Cids& cids = check->cids();
251 if (cids.IsMonomorphic()) {
252 SetCid(check->value()->definition(), cids.MonomorphicReceiverCid());
253 return;
254 }
255 // Take the union of polymorphic cids.
257 for (intptr_t i = 0, n = cids.length(); i < n; i++) {
258 CidRange* cid_range = cids.At(i);
259 ASSERT(!cid_range->IsIllegalRange());
260 for (intptr_t cid = cid_range->cid_start; cid <= cid_range->cid_end;
261 cid++) {
263 result.Union(&tp);
264 }
265 }
266 if (!result.IsNone()) {
267 SetTypeOf(check->value()->definition(), new (zone()) CompileType(result));
268 }
269}
270
272 LoadClassIdInstr* load_cid =
273 check->value()->definition()->OriginalDefinition()->AsLoadClassId();
274 if (load_cid != nullptr && check->cids().IsSingleCid()) {
275 SetCid(load_cid->object()->definition(), check->cids().cid_start);
276 }
277}
278
280 Definition* receiver = check->value()->definition();
281 CompileType* type = TypeOf(receiver);
282 if (type->is_nullable()) {
283 // If the type is nullable, translate an implicit control
284 // dependence to an explicit data dependence at this point
285 // to guard against invalid code motion later. Valid code
286 // motion of the check may still enable valid code motion
287 // of the checked code.
288 if (check->ssa_temp_index() == -1) {
289 flow_graph_->AllocateSSAIndex(check);
290 GrowTypes(check->ssa_temp_index() + 1);
291 }
293 // Set non-nullable type on check itself (but avoid None()).
295 if (!result.IsNone()) {
296 SetTypeOf(check, new (zone()) CompileType(result));
297 }
298 }
299}
300
301void FlowGraphTypePropagator::CheckNonNullSelector(
302 Instruction* call,
303 Definition* receiver,
304 const String& function_name) {
305 if (!receiver->Type()->is_nullable()) {
306 // Nothing to do if type is already non-nullable.
307 return;
308 }
309 Thread* thread = Thread::Current();
310 const Class& null_class =
311 Class::Handle(thread->isolate_group()->object_store()->null_class());
312 Function& target = Function::Handle();
313 if (Error::Handle(null_class.EnsureIsFinalized(thread)).IsNull()) {
314 target = Resolver::ResolveDynamicAnyArgs(thread->zone(), null_class,
316 }
317 if (target.IsNull()) {
318 // If the selector is not defined on Null, we can propagate non-nullness.
319 CompileType* type = TypeOf(receiver);
320 if (type->is_nullable()) {
321 // Insert redefinition for the receiver to guard against invalid
322 // code motion.
323 EnsureMoreAccurateRedefinition(call, receiver, type->CopyNonNullable());
324 }
325 }
326}
327
329 if (instr->has_unique_selector()) {
330 SetCid(instr->Receiver()->definition(),
331 instr->ic_data()->GetReceiverClassIdAt(0));
332 return;
333 }
334 CheckNonNullSelector(instr, instr->Receiver()->definition(),
335 instr->function_name());
336}
337
340 if (instr->has_unique_selector()) {
341 SetCid(instr->Receiver()->definition(),
343 return;
344 }
345 CheckNonNullSelector(instr, instr->Receiver()->definition(),
346 instr->function_name());
347}
348
350 GuardFieldClassInstr* guard) {
351 const intptr_t cid = guard->field().guarded_cid();
352 if ((cid == kIllegalCid) || (cid == kDynamicCid)) {
353 return;
354 }
355
356 Definition* def = guard->value()->definition();
357 CompileType* current = TypeOf(def);
358 if (current->IsNone() || (current->ToCid() != cid) ||
359 (current->is_nullable() && !guard->field().is_nullable())) {
360 const bool is_nullable =
361 guard->field().is_nullable() && current->is_nullable();
362 SetTypeOf(def,
363 new (zone()) CompileType(
364 is_nullable, CompileType::kCannotBeSentinel, cid, nullptr));
365 }
366}
367
370 auto defn = check->value()->definition();
371 SetTypeOf(defn, new (zone()) CompileType(check->ComputeType()));
372 if (check->ssa_temp_index() == -1) {
373 flow_graph_->AllocateSSAIndex(check);
374 GrowTypes(check->ssa_temp_index() + 1);
375 }
377}
378
380 SetTypeOf(instr->value()->definition(),
381 new (zone()) CompileType(CompileType::Bool()));
382}
383
385
387 StrictCompareInstr* comparison = instr->comparison()->AsStrictCompare();
388 if (comparison == nullptr) return;
389 bool negated = comparison->kind() == Token::kNE_STRICT;
390 LoadClassIdInstr* load_cid =
391 comparison->InputAt(0)->definition()->AsLoadClassId();
392 InstanceCallInstr* call =
393 comparison->InputAt(0)->definition()->AsInstanceCall();
394 InstanceOfInstr* instance_of =
395 comparison->InputAt(0)->definition()->AsInstanceOf();
396 bool is_simple_instance_of =
397 (call != nullptr) && call->MatchesCoreName(Symbols::_simpleInstanceOf());
398 if (load_cid != nullptr && comparison->InputAt(1)->BindsToConstant()) {
399 intptr_t cid = Smi::Cast(comparison->InputAt(1)->BoundConstant()).Value();
400 BlockEntryInstr* true_successor =
401 negated ? instr->false_successor() : instr->true_successor();
402 EnsureMoreAccurateRedefinition(true_successor,
403 load_cid->object()->definition(),
405 } else if ((is_simple_instance_of || (instance_of != nullptr)) &&
406 comparison->InputAt(1)->BindsToConstant() &&
407 comparison->InputAt(1)->BoundConstant().IsBool()) {
408 if (comparison->InputAt(1)->BoundConstant().ptr() == Bool::False().ptr()) {
409 negated = !negated;
410 }
411 BlockEntryInstr* true_successor =
412 negated ? instr->false_successor() : instr->true_successor();
413 const AbstractType* type = nullptr;
414 Definition* left = nullptr;
415 if (is_simple_instance_of) {
416 ASSERT(call->ArgumentAt(1)->IsConstant());
417 const Object& type_obj = call->ArgumentAt(1)->AsConstant()->value();
418 if (!type_obj.IsType()) {
419 return;
420 }
421 type = &Type::Cast(type_obj);
422 left = call->ArgumentAt(0);
423 } else {
424 type = &(instance_of->type());
425 left = instance_of->value()->definition();
426 }
427 if (!type->IsTopTypeForInstanceOf()) {
428 const bool is_nullable = (type->IsNullable() || type->IsTypeParameter() ||
429 (type->IsNeverType() && type->IsLegacy()))
432 EnsureMoreAccurateRedefinition(
433 true_successor, left,
436 }
437 } else if (comparison->InputAt(0)->BindsToConstant() &&
438 comparison->InputAt(0)->BoundConstant().IsNull()) {
439 // Handle for expr != null.
440 BlockEntryInstr* true_successor =
441 negated ? instr->true_successor() : instr->false_successor();
442 EnsureMoreAccurateRedefinition(
443 true_successor, comparison->InputAt(1)->definition(),
444 comparison->InputAt(1)->Type()->CopyNonNullable());
445
446 } else if (comparison->InputAt(1)->BindsToConstant() &&
447 comparison->InputAt(1)->BoundConstant().IsNull()) {
448 // Handle for null != expr.
449 BlockEntryInstr* true_successor =
450 negated ? instr->true_successor() : instr->false_successor();
451 EnsureMoreAccurateRedefinition(
452 true_successor, comparison->InputAt(0)->definition(),
453 comparison->InputAt(0)->Type()->CopyNonNullable());
454 } else if (comparison->InputAt(0)->BindsToConstant() &&
455 comparison->InputAt(0)->BoundConstant().ptr() ==
456 Object::sentinel().ptr()) {
457 // Handle for expr != sentinel.
458 BlockEntryInstr* true_successor =
459 negated ? instr->true_successor() : instr->false_successor();
460 EnsureMoreAccurateRedefinition(
461 true_successor, comparison->InputAt(1)->definition(),
462 comparison->InputAt(1)->Type()->CopyNonSentinel());
463
464 } else if (comparison->InputAt(1)->BindsToConstant() &&
465 comparison->InputAt(1)->BoundConstant().ptr() ==
466 Object::sentinel().ptr()) {
467 // Handle for sentinel != expr.
468 BlockEntryInstr* true_successor =
469 negated ? instr->true_successor() : instr->false_successor();
470 EnsureMoreAccurateRedefinition(
471 true_successor, comparison->InputAt(0)->definition(),
472 comparison->InputAt(0)->Type()->CopyNonSentinel());
473 }
474 // TODO(fschneider): Add propagation for generic is-tests.
475}
476
477void FlowGraphTypePropagator::AddToWorklist(Definition* defn) {
478 if (defn->ssa_temp_index() == -1) {
479 return;
480 }
481
482 const intptr_t index = defn->ssa_temp_index();
483 if (!in_worklist_->Contains(index)) {
484 worklist_.Add(defn);
485 in_worklist_->Add(index);
486 }
487}
488
489Definition* FlowGraphTypePropagator::RemoveLastFromWorklist() {
490 Definition* defn = worklist_.RemoveLast();
491 ASSERT(defn->ssa_temp_index() != -1);
492 in_worklist_->Remove(defn->ssa_temp_index());
493 return defn;
494}
495
496// In the given block strengthen type assertions by hoisting first class or smi
497// check over the same value up to the point before the assertion. This allows
498// to eliminate type assertions that are postdominated by class or smi checks as
499// these checks are strongly stricter than type assertions.
500void FlowGraphTypePropagator::StrengthenAsserts(BlockEntryInstr* block) {
501 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
502 Instruction* instr = it.Current();
503
504 if (instr->IsCheckSmi() || instr->IsCheckClass()) {
505 StrengthenAssertWith(instr);
506 }
507
508 // If this is the first type assertion checking given value record it.
509 AssertAssignableInstr* assert = instr->AsAssertAssignable();
510 if (assert != nullptr) {
511 Definition* defn = assert->value()->definition()->OriginalDefinition();
512 if ((*asserts_)[defn->ssa_temp_index()] == nullptr) {
513 (*asserts_)[defn->ssa_temp_index()] = assert;
514 collected_asserts_->Add(defn->ssa_temp_index());
515 }
516 }
517 }
518
519 for (intptr_t i = 0; i < collected_asserts_->length(); i++) {
520 (*asserts_)[(*collected_asserts_)[i]] = nullptr;
521 }
522
523 collected_asserts_->TruncateTo(0);
524}
525
526void FlowGraphTypePropagator::StrengthenAssertWith(Instruction* check) {
527 // Marker that is used to mark values that already had type assertion
528 // strengthened.
529 AssertAssignableInstr* kStrengthenedAssertMarker =
530 reinterpret_cast<AssertAssignableInstr*>(-1);
531
532 Definition* defn = check->InputAt(0)->definition()->OriginalDefinition();
533
534 AssertAssignableInstr* assert = (*asserts_)[defn->ssa_temp_index()];
535 if ((assert == nullptr) || (assert == kStrengthenedAssertMarker)) {
536 return;
537 }
538 ASSERT(assert->env() != nullptr);
539
540 Instruction* check_clone = nullptr;
541 if (check->IsCheckSmi()) {
542 check_clone = new CheckSmiInstr(assert->value()->Copy(zone()),
543 assert->deopt_id(), check->source());
544 } else {
545 ASSERT(check->IsCheckClass());
546 check_clone =
547 new CheckClassInstr(assert->value()->Copy(zone()), assert->deopt_id(),
548 check->AsCheckClass()->cids(), check->source());
549 }
550 ASSERT(check_clone != nullptr);
551 check_clone->InsertBefore(assert);
552 assert->env()->DeepCopyTo(zone(), check_clone);
553
554 (*asserts_)[defn->ssa_temp_index()] = kStrengthenedAssertMarker;
555}
556
558 if (other->IsNone()) {
559 return;
560 }
561
562 if (IsNone()) {
563 *this = *other;
564 return;
565 }
566
567 can_be_null_ = can_be_null_ || other->can_be_null_;
568 can_be_sentinel_ = can_be_sentinel_ || other->can_be_sentinel_;
569
570 ToNullableCid(); // Ensure cid_ is set.
571 if ((cid_ == kNullCid) || (cid_ == kSentinelCid)) {
572 cid_ = other->cid_;
573 type_ = other->type_;
574 return;
575 }
576
577 other->ToNullableCid(); // Ensure other->cid_ is set.
578 if ((other->cid_ == kNullCid) || (other->cid_ == kSentinelCid)) {
579 return;
580 }
581
582 const AbstractType* abstract_type = ToAbstractType();
583 if (cid_ != other->cid_) {
584 cid_ = kDynamicCid;
585 }
586
587 const AbstractType* other_abstract_type = other->ToAbstractType();
588 if (abstract_type->IsSubtypeOf(*other_abstract_type, Heap::kOld)) {
589 type_ = other_abstract_type;
590 return;
591 } else if (other_abstract_type->IsSubtypeOf(*abstract_type, Heap::kOld)) {
592 return; // Nothing to do.
593 }
594
595 // Climb up the hierarchy to find a suitable supertype. Note that interface
596 // types are not considered, making the union potentially non-commutative
597 if (abstract_type->IsInstantiated() && !abstract_type->IsDynamicType() &&
598 !abstract_type->IsFunctionType() && !abstract_type->IsRecordType()) {
599 Class& cls = Class::Handle(abstract_type->type_class());
600 for (; !cls.IsNull() && !cls.IsGeneric(); cls = cls.SuperClass()) {
601 type_ = &AbstractType::ZoneHandle(cls.RareType());
602 if (other_abstract_type->IsSubtypeOf(*type_, Heap::kOld)) {
603 // Found suitable supertype: keep type_ only.
604 cid_ = kDynamicCid;
605 return;
606 }
607 }
608 }
609
610 // Can't unify.
611 type_ = &Object::dynamic_type();
612}
613
615 CompileType* new_type) {
616 ASSERT(new_type != nullptr);
617
618 // In general, prefer the newly inferred type over old type.
619 // It is possible that new and old types are unrelated or do not intersect
620 // at all (for example, in case of unreachable code).
621
622 // Discard None type as it is used to denote an unknown type.
623 if (old_type == nullptr || old_type->IsNone()) {
624 return new_type;
625 }
626 if (new_type->IsNone()) {
627 return old_type;
628 }
629
630 CompileType* preferred_type = nullptr;
631
632 // Prefer exact Cid if known.
633 const intptr_t new_type_cid = new_type->ToCid();
634 const intptr_t old_type_cid = old_type->ToCid();
635 if (new_type_cid != old_type_cid) {
636 if (new_type_cid != kDynamicCid) {
637 preferred_type = new_type;
638 } else if (old_type_cid != kDynamicCid) {
639 preferred_type = old_type;
640 }
641 }
642
643 if (preferred_type == nullptr) {
644 const AbstractType* old_abstract_type = old_type->ToAbstractType();
645 const AbstractType* new_abstract_type = new_type->ToAbstractType();
646
647 // Prefer 'int' if known.
648 if (old_type->IsNullableInt()) {
649 preferred_type = old_type;
650 } else if (new_type->IsNullableInt()) {
651 preferred_type = new_type;
652 } else if (old_abstract_type->IsSubtypeOf(*new_abstract_type, Heap::kOld)) {
653 // Prefer old type, as it is clearly more specific.
654 preferred_type = old_type;
655 } else {
656 // Prefer new type as it is more recent, even though it might be
657 // no better than the old type.
658 preferred_type = new_type;
659 }
660 }
661
662 // Refine non-nullability and whether it can be sentinel.
663 const bool can_be_null = old_type->is_nullable() && new_type->is_nullable();
664 const bool can_be_sentinel =
665 old_type->can_be_sentinel() && new_type->can_be_sentinel();
666
667 if ((preferred_type->is_nullable() && !can_be_null) ||
668 (preferred_type->can_be_sentinel() && !can_be_sentinel)) {
669 return new CompileType(can_be_null, can_be_sentinel, preferred_type->cid_,
670 preferred_type->type_);
671 } else {
672 ASSERT(preferred_type->is_nullable() == can_be_null);
673 ASSERT(preferred_type->can_be_sentinel() == can_be_sentinel);
674 return preferred_type;
675 }
676}
677
679 bool can_be_null,
680 bool can_be_sentinel) {
681 return CompileType(can_be_null && !type.IsStrictlyNonNullable(),
683}
684
687 if (cid == kDynamicCid) {
688 return CompileType::Dynamic();
689 }
690 return CompileType(cid == kNullCid, cid == kSentinelCid, cid, nullptr);
691}
692
694 ASSERT(rep != kTagged);
695 ASSERT(rep != kUntagged);
697 if (!Boxing::RequiresAllocation(rep)) {
698 return CompileType::Smi();
699 }
700 return CompileType::Int();
701 }
703}
704
706 if (rep == kUntagged) return CompileType::Object();
708 return FromUnboxedRepresentation(rep);
709 }
710 ASSERT(rep != kNoRepresentation);
711 return CompileType::Dynamic();
712}
713
716 &Object::dynamic_type());
717}
718
723
728
733
738
740#if defined(HAS_SMI_63_BITS)
741 return FromCid(kSmiCid);
742#else
743 return Int();
744#endif
745}
746
751
756
761
766
771
776
778 if (is_nullable()) return false;
779 if (cid_ != kIllegalCid && cid_ != kDynamicCid) return false;
780 return type_ != nullptr && type_->IsObjectType();
781}
782
784 if (cid_ == kIllegalCid) {
785 // Make sure to initialize cid_ for Null type to consistently return
786 // kNullCid.
787 if ((type_ != nullptr) && type_->IsNullType()) {
788 cid_ = kNullCid;
789 }
790 // Same for sentinel.
791 if ((type_ != nullptr) && type_->IsSentinelType()) {
792 cid_ = kSentinelCid;
793 }
794 }
795
796 if ((cid_ == kDynamicCid) || (can_be_null_ && (cid_ != kNullCid)) ||
797 (can_be_sentinel_ && (cid_ != kSentinelCid))) {
798 return kDynamicCid;
799 }
800
801 return ToNullableCid();
802}
803
805 if (cid_ == kIllegalCid) {
806 if (type_ == nullptr) {
807 // Type propagation is turned off or has not yet run.
808 return kDynamicCid;
809 } else if (type_->IsVoidType()) {
810 cid_ = kDynamicCid;
811 } else if (type_->IsNullType()) {
812 cid_ = kNullCid;
813 } else if (type_->IsSentinelType()) {
814 cid_ = kSentinelCid;
815 } else if (type_->IsFunctionType() || type_->IsDartFunctionType()) {
816 cid_ = kClosureCid;
817 } else if (type_->IsRecordType() || type_->IsDartRecordType()) {
818 cid_ = kRecordCid;
819 } else if (type_->type_class_id() != kIllegalCid) {
820 const Class& type_class = Class::Handle(type_->type_class());
821 intptr_t implementation_cid = kIllegalCid;
823 &implementation_cid)) {
824 cid_ = implementation_cid;
825 } else {
826 cid_ = kDynamicCid;
827 }
828 } else {
829 cid_ = kDynamicCid;
830 }
831 }
832
833 if (can_be_sentinel_ && (cid_ != kSentinelCid)) {
834 return kDynamicCid;
835 }
836
837 return cid_;
838}
839
841 return !can_be_null_ || IsNull();
842}
843
845 return (ToCid() == kNullCid);
846}
847
849 if (type_ == nullptr) {
850 // Type propagation has not run. Return dynamic-type.
851 if (cid_ == kIllegalCid) {
852 return &Object::dynamic_type();
853 }
854
855 // VM-internal objects don't have a compile-type. Return dynamic-type
856 // in this case.
857 if (IsInternalOnlyClassId(cid_) || cid_ == kTypeArgumentsCid) {
858 type_ = &Object::dynamic_type();
859 return type_;
860 }
861
862 auto IG = IsolateGroup::Current();
863 const Class& type_class = Class::Handle(IG->class_table()->At(cid_));
864 type_ = &AbstractType::ZoneHandle(type_class.RareType());
865 }
866
867 return type_;
868}
869
871 if (other.IsTopTypeForSubtyping()) {
872 return true;
873 }
874
875 if (IsNone()) {
876 return false;
877 }
878
879 return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
880}
881
883 if (other.IsTopTypeForSubtyping()) {
884 return true;
885 }
886 // If we allow comparisons against an uninstantiated type, then we can
887 // end up incorrectly optimizing away AssertAssignables where the incoming
888 // value and outgoing value have CompileTypes that would return true to the
889 // subtype check below, but at runtime are instantiated with different type
890 // argument vectors such that the relation does not hold for the runtime
891 // instantiated values.
892 //
893 // We might consider using an approximation of the uninstantiated type,
894 // like the instantiation to bounds, and compare to that. However, in
895 // vm/dart/regress_b_230945329_test.dart we have a case where the compared
896 // uninstantiated type is the same as the one in the CompileType. Thus, no
897 // approach will be able to distinguish the two types, and so we fail the
898 // comparison in all cases.
899 if (IsNone() || !other.IsInstantiated()) {
900 return false;
901 }
902 if (is_nullable() && !Instance::NullIsAssignableTo(other)) {
903 return false;
904 }
905 return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
906}
907
909 if (other.IsTopTypeForInstanceOf()) {
910 return true;
911 }
912 if (IsNone() || !other.IsInstantiated()) {
913 return false;
914 }
915 if (is_nullable() && !other.IsNullable()) {
916 return false;
917 }
918 return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
919}
920
923 if (cid_ != kDynamicCid) {
924 class_ids->Add(cid_);
925 return true;
926 }
927 if (type_ != nullptr && type_->type_class_id() != kIllegalCid) {
928 const Class& type_class = Class::Handle(type_->type_class());
929 if (!CHA::ConcreteSubclasses(type_class, class_ids)) return false;
930 if (can_be_null_) {
931 class_ids->Add(kNullCid);
932 }
933 if (can_be_sentinel_) {
934 class_ids->Add(kSentinelCid);
935 }
936 }
937 return false;
938}
939
940// For the given type conservatively computes whether Smi can potentially
941// appear in a location of this type.
942//
943// If recurse is false this function will not call itself recursively
944// to prevent infinite recursion when traversing a cycle in type parameter
945// bounds.
946static bool CanPotentiallyBeSmi(const AbstractType& type, bool recurse) {
947 if (type.IsInstantiated()) {
949 } else if (type.IsTypeParameter()) {
950 // For type parameters look at their bounds (if recurse allows us).
951 const auto& param = TypeParameter::Cast(type);
952 return !recurse || CanPotentiallyBeSmi(AbstractType::Handle(param.bound()),
953 /*recurse=*/false);
954 } else if (type.HasTypeClass()) {
955 // If this is an uninstantiated type then it can only potentially be a super
956 // type of a Smi if it is either FutureOr<...> or Comparable<...>.
957 // In which case we need to look at the type argument to determine whether
958 // this location can contain a smi.
959 //
960 // Note: we are making a simplification here. This approach will yield
961 // true for Comparable<T> where T extends int - while in reality Smi is
962 // *not* assignable to it (because int implements Comparable<num> and not
963 // Comparable<int>).
964 if (type.IsFutureOrType() ||
965 type.type_class() == CompilerState::Current().ComparableClass().ptr()) {
966 const auto& args = TypeArguments::Handle(type.arguments());
967 const auto& arg0 = AbstractType::Handle(args.TypeAt(0));
968 return !recurse || CanPotentiallyBeSmi(arg0, /*recurse=*/true);
969 }
970 return false;
971 }
972 return false;
973}
974
976 // Fast path for known cid.
977 if (cid_ != kIllegalCid && cid_ != kDynamicCid) {
978 return cid_ == kSmiCid;
979 }
980 return CanPotentiallyBeSmi(*ToAbstractType(), /*recurse=*/true);
981}
982
984 Thread* thread = Thread::Current();
985 Zone* zone = thread->zone();
986 if (cid_ != kIllegalCid && cid_ != kDynamicCid) {
987 if ((cid_ == kNullCid) || (cid_ == kNeverCid) ||
988 IsInternalOnlyClassId(cid_) || cid_ == kTypeArgumentsCid) {
989 return false;
990 }
991 const Class& cls =
992 Class::Handle(zone, thread->isolate_group()->class_table()->At(cid_));
993 return cls.is_future_subtype();
994 }
995
997 if (type.IsTypeParameter()) {
998 type = TypeParameter::Cast(type).bound();
999 }
1000 if (type.IsTypeParameter()) {
1001 // Type parameter bounds can be cyclic, do not bother handling them here.
1002 return true;
1003 }
1004 const intptr_t type_class_id = type.type_class_id();
1005 if (type_class_id == kDynamicCid || type_class_id == kVoidCid ||
1006 type_class_id == kInstanceCid || type_class_id == kFutureOrCid) {
1007 return true;
1008 }
1009 if ((type_class_id == kIllegalCid) || (type_class_id == kNullCid) ||
1010 (type_class_id == kNeverCid)) {
1011 return false;
1012 }
1013 const auto& cls = Class::Handle(zone, type.type_class());
1014 return CHA::ClassCanBeFuture(cls);
1015}
1016
1017// Keep this format in sync with pkg/vm/lib/testing/il_matchers.dart.
1019 if (IsNone()) {
1020 return;
1021 }
1022
1023 if (cid_ != kIllegalCid && cid_ != kDynamicCid) {
1024 const Class& cls =
1025 Class::Handle(IsolateGroup::Current()->class_table()->At(cid_));
1026 writer->PrintPropertyStr("c", String::Handle(cls.ScrubbedName()));
1027 }
1028
1029 if (type_ != nullptr && !type_->IsDynamicType()) {
1030 writer->PrintPropertyStr("t", String::Handle(type_->ScrubbedName()));
1031 }
1032
1033 if (can_be_null_) {
1034 writer->PrintPropertyBool("n", true);
1035 }
1036
1037 if (can_be_sentinel_) {
1038 writer->PrintPropertyBool("s", true);
1039 }
1040}
1041
1043 const char* type_name = "?";
1044 if (IsNone()) {
1045 f->AddString("T{}");
1046 return;
1047 } else if ((cid_ != kIllegalCid) && (cid_ != kDynamicCid)) {
1048 const Class& cls =
1049 Class::Handle(IsolateGroup::Current()->class_table()->At(cid_));
1050 type_name = cls.ScrubbedNameCString();
1051 } else if (type_ != nullptr) {
1052 type_name = type_->IsDynamicType() ? "*" : type_->ScrubbedNameCString();
1053 } else if (!is_nullable()) {
1054 type_name = "!null";
1055 }
1056
1057 f->Printf("T{%s%s%s}", type_name, can_be_null_ ? "?" : "",
1058 can_be_sentinel_ ? "~" : "");
1059}
1060
1061const char* CompileType::ToCString() const {
1062 char buffer[1024];
1063 BufferFormatter f(buffer, sizeof(buffer));
1064 PrintTo(&f);
1066}
1067
1069 if (reaching_type_ == nullptr) {
1070 reaching_type_ = definition()->Type();
1071 }
1072 return reaching_type_;
1073}
1074
1076 // If [type] is owned but not by the definition which flows into this use
1077 // then we need to disconnect the type from original owner by cloning it.
1078 // This is done to prevent situations when [type] is updated by its owner
1079 // but [owner] is no longer connected to this use through def-use chain
1080 // and as a result type propagator does not recompute type of the current
1081 // instruction.
1082 if (type != nullptr && type->owner() != nullptr &&
1083 type->owner() != definition()) {
1084 type = new CompileType(*type);
1085 }
1086 reaching_type_ = type;
1087}
1088
1092
1094 // Initially type of phis is unknown until type propagation is run
1095 // for the first time.
1096 return CompileType::None();
1097}
1098
1101 for (intptr_t i = 0; i < InputCount(); i++) {
1102 if (FLAG_support_il_printer && FLAG_trace_type_propagation) {
1103 THR_Print(" phi %" Pd " input %" Pd ": v%" Pd " has reaching type %s\n",
1104 ssa_temp_index(), i, InputAt(i)->definition()->ssa_temp_index(),
1105 InputAt(i)->Type()->ToCString());
1106 }
1107 result.Union(InputAt(i)->Type());
1108 }
1109
1110 if (result.IsNone()) {
1111 ASSERT(Type()->IsNone());
1112 return false;
1113 }
1114
1115 return UpdateType(result);
1116}
1117
1119 if (constrained_type_ != nullptr) {
1120 // Check if the type associated with this redefinition is more specific
1121 // than the type of its input. If yes, return it. Otherwise, fall back
1122 // to the input's type.
1123
1124 // If either type is non-nullable, the resulting type is non-nullable.
1125 const bool is_nullable =
1126 value()->Type()->is_nullable() && constrained_type_->is_nullable();
1127 // The resulting type can be the sentinel value only if both types can be.
1128 const bool can_be_sentinel = value()->Type()->can_be_sentinel() &&
1129 constrained_type_->can_be_sentinel();
1130
1131 // If either type has a concrete cid, stick with it.
1132 if (value()->Type()->ToNullableCid() != kDynamicCid) {
1133 return CompileType(is_nullable, can_be_sentinel,
1134 value()->Type()->ToNullableCid(), nullptr);
1135 }
1136 if (constrained_type_->ToNullableCid() != kDynamicCid) {
1137 return CompileType(is_nullable, can_be_sentinel,
1138 constrained_type_->ToNullableCid(), nullptr);
1139 }
1140
1142 value()->Type()->IsSubtypeOf(*constrained_type_->ToAbstractType())
1143 ? *value()->Type()
1144 : *constrained_type_);
1145 if (!is_nullable) {
1147 }
1148 if (!can_be_sentinel) {
1150 }
1151 return result;
1152 }
1153 return *value()->Type();
1154}
1155
1157 return UpdateType(ComputeType());
1158}
1159
1161 CompileType* type = value()->Type();
1162 if (type->is_nullable()) {
1164 if (!result.IsNone()) {
1165 return result;
1166 }
1167 }
1168 return *type;
1169}
1170
1172 return UpdateType(ComputeType());
1173}
1174
1176 return *index()->Type();
1177}
1178
1180 return UpdateType(ComputeType());
1181}
1182
1186
1188 return UpdateType(ComputeType());
1189}
1190
1194
1196 // Note that returning the declared type of the formal parameter would be
1197 // incorrect, because ParameterInstr is used as input to the type check
1198 // verifying the run time type of the passed-in parameter and this check would
1199 // always be wrongly eliminated.
1200 // However there are parameters that are known to match their declared type:
1201 // for example receiver.
1202 GraphEntryInstr* graph_entry = block_->AsGraphEntry();
1203 if (graph_entry == nullptr) {
1204 if (auto function_entry = block_->AsFunctionEntry()) {
1205 graph_entry = function_entry->graph_entry();
1206 } else if (auto osr_entry = block_->AsOsrEntry()) {
1207 graph_entry = osr_entry->graph_entry();
1208 } else if (auto catch_entry = block_->AsCatchBlockEntry()) {
1209 graph_entry = catch_entry->graph_entry();
1210 } else {
1211 UNREACHABLE();
1212 }
1213 }
1214 // Parameters at OSR entries have type dynamic.
1215 //
1216 // TODO(kmillikin): Use the actual type of the parameter at OSR entry.
1217 // The code below is not safe for OSR because it doesn't necessarily use
1218 // the correct scope.
1219 if (graph_entry->IsCompiledForOsr()) {
1220 // Parameter at OSR entry may correspond to a late local variable.
1222 }
1223
1224 const ParsedFunction& pf = graph_entry->parsed_function();
1225 const Function& function = pf.function();
1226 if (function.IsIrregexpFunction()) {
1227 // In irregexp functions, types of input parameters are known and immutable.
1228 // Set parameter types here in order to prevent unnecessary CheckClassInstr
1229 // from being generated.
1230 switch (env_index()) {
1232 return CompileType::FromCid(kRegExpCid);
1234 return CompileType::FromCid(function.string_specialization_cid());
1236 return CompileType::FromCid(kSmiCid);
1237 default:
1238 UNREACHABLE();
1239 }
1240 UNREACHABLE();
1241 return CompileType::Dynamic();
1242 }
1243
1244 const intptr_t param_index = this->param_index();
1245 if (param_index >= 0) {
1246 // Parameter is the receiver.
1247 if ((param_index == 0) &&
1248 (function.IsDynamicFunction() || function.IsGenerativeConstructor())) {
1250 if (type.IsObjectType() || type.IsNullType()) {
1251 // Receiver can be null.
1254 }
1255
1256 // Receiver can't be null but can be an instance of a subclass.
1257 intptr_t cid = kDynamicCid;
1258
1259 if (type.type_class_id() != kIllegalCid) {
1260 Thread* thread = Thread::Current();
1261 const Class& type_class = Class::Handle(type.type_class());
1262 if (!CHA::HasSubclasses(type_class)) {
1263 if (type_class.IsPrivate()) {
1264 // Private classes can never be subclassed by later loaded libs.
1265 cid = type_class.id();
1266 } else {
1267 if (FLAG_use_cha_deopt ||
1268 thread->isolate_group()->all_classes_finalized()) {
1269 if (FLAG_trace_cha) {
1270 THR_Print(
1271 " **(CHA) Computing exact type of receiver, "
1272 "no subclasses: %s\n",
1273 type_class.ToCString());
1274 }
1275 if (FLAG_use_cha_deopt) {
1276 thread->compiler_state()
1277 .cha()
1279 /*subclass_count=*/0);
1280 }
1281 cid = type_class.id();
1282 }
1283 }
1284 }
1285 }
1286
1289 }
1290
1291 const bool is_unchecked_entry_param =
1292 graph_entry->unchecked_entry() == block_;
1293
1294 const LocalVariable* param = (pf.scope() != nullptr)
1297 ASSERT(param != nullptr);
1298
1299 CompileType* inferred_type = nullptr;
1300 intptr_t inferred_cid = kDynamicCid;
1301 bool inferred_nullable = true;
1302 if (!block_->IsCatchBlockEntry()) {
1303 inferred_type = param->inferred_arg_type();
1304
1305 if (inferred_type != nullptr) {
1306 // Use inferred type if it is an int.
1307 if (inferred_type->IsNullableInt()) {
1308 TraceStrongModeType(this, inferred_type);
1309 return *inferred_type;
1310 }
1311 // Otherwise use inferred cid and nullability.
1312 inferred_cid = inferred_type->ToNullableCid();
1313 inferred_nullable = inferred_type->is_nullable();
1314 }
1315 }
1316 // If parameter type was checked by caller, then use Dart type annotation,
1317 // plus non-nullability from inferred type if known.
1318 // Do not trust static parameter type of 'operator ==' as it is a
1319 // non-nullable Object but VM handles comparison with null in
1320 // the callee, so 'operator ==' can take null as an argument.
1321 if ((function.name() != Symbols::EqualOperator().ptr()) &&
1322 (param->was_type_checked_by_caller() ||
1323 (is_unchecked_entry_param &&
1324 !param->is_explicit_covariant_parameter()))) {
1325 const AbstractType& static_type = param->static_type();
1327 inferred_nullable && !static_type.IsStrictlyNonNullable(),
1328 block_->IsCatchBlockEntry() && param->is_late(),
1329 inferred_cid == kDynamicCid ? kIllegalCid : inferred_cid,
1330 &static_type);
1332 return result;
1333 }
1334 // Last resort: use inferred type as is.
1335 if (inferred_type != nullptr) {
1336 TraceStrongModeType(this, inferred_type);
1337 return *inferred_type;
1338 }
1339 }
1340
1341 if (block_->IsCatchBlockEntry()) {
1342 // Parameter of a catch block may correspond to a late local variable.
1344 }
1345
1346 return CompileType::Dynamic();
1347}
1348
1350 if (value().IsNull()) {
1351 return CompileType::Null();
1352 }
1353
1354 intptr_t cid = value().GetClassId();
1355
1356 if (cid == kSmiCid && !compiler::target::IsSmi(Smi::Cast(value()).Value())) {
1360 }
1361
1362 if ((cid != kTypeArgumentsCid) && value().IsInstance()) {
1363 // Allocate in old-space since this may be invoked from the
1364 // background compiler.
1365 return CompileType(
1366 cid == kNullCid, cid == kSentinelCid, cid,
1367 &AbstractType::ZoneHandle(Instance::Cast(value()).GetType(Heap::kOld)));
1368 } else {
1369 // Type info for non-instance objects.
1370 return CompileType::FromCid(cid);
1371 }
1372}
1373
1375 CompileType* value_type = value()->Type();
1376
1377 const AbstractType* abs_type = &AbstractType::dynamic_type();
1378 if (dst_type()->BindsToConstant() &&
1379 dst_type()->BoundConstant().IsAbstractType()) {
1380 abs_type = &AbstractType::Cast(dst_type()->BoundConstant());
1381 if (value_type->IsSubtypeOf(*abs_type)) {
1382 return *value_type;
1383 }
1384 }
1385 return CompileType::FromAbstractType(*abs_type, value_type->is_nullable(),
1387}
1388
1390 return UpdateType(ComputeType());
1391}
1392
1396
1400
1404
1408
1412
1416
1420
1424
1426 // Used for numeric comparisons only.
1427 return CompileType::Bool();
1428}
1429
1431 // Used for numeric comparisons only.
1432 return CompileType::Bool();
1433}
1434
1437 kContextCid, &Object::dynamic_type());
1438}
1439
1442 kContextCid, &Object::dynamic_type());
1443}
1444
1449
1451 // TODO(alexmarkov): calculate type of InstanceCallInstr eagerly
1452 // (in optimized mode) and avoid keeping separate result_type.
1453 CompileType* inferred_type = result_type();
1454 intptr_t inferred_cid = kDynamicCid;
1455 bool is_nullable = CompileType::kCanBeNull;
1456 if (inferred_type != nullptr) {
1457 if (inferred_type->IsNullableInt()) {
1458 TraceStrongModeType(this, inferred_type);
1459 return *inferred_type;
1460 }
1461 inferred_cid = inferred_type->ToNullableCid();
1462 is_nullable = inferred_type->is_nullable();
1463 }
1464
1465 // Include special cases of type inference for int operations.
1466 // This helps if both type feedback and results of TFA
1467 // are not available (e.g. in AOT unit tests).
1468 switch (token_kind()) {
1469 case Token::kADD:
1470 case Token::kSUB:
1471 case Token::kMUL:
1472 case Token::kMOD:
1473 if ((ArgumentCount() == 2) &&
1474 ArgumentValueAt(0)->Type()->IsNullableInt() &&
1475 ArgumentValueAt(1)->Type()->IsNullableInt()) {
1476 return CompileType::Int();
1477 }
1478 break;
1479 case Token::kNEGATE:
1480 if ((ArgumentCount() == 1) &&
1481 ArgumentValueAt(0)->Type()->IsNullableInt()) {
1482 return CompileType::Int();
1483 }
1484 break;
1485 default:
1486 break;
1487 }
1488
1489 const Function& target = interface_target();
1490 if (!target.IsNull()) {
1491 const AbstractType& result_type =
1492 AbstractType::ZoneHandle(target.result_type());
1493 // Currently VM doesn't have enough information to instantiate generic
1494 // result types of interface targets:
1495 // 1. receiver type inferred by the front-end is not passed to VM.
1496 // 2. VM collects type arguments through the chain of superclasses but
1497 // not through implemented interfaces.
1498 // TODO(dartbug.com/30480): instantiate generic result_type
1499 CompileType result(is_nullable && !result_type.IsStrictlyNonNullable(),
1501 inferred_cid == kDynamicCid ? kIllegalCid : inferred_cid,
1502 &result_type);
1504 return result;
1505 }
1506
1507 if (inferred_type != nullptr) {
1508 TraceStrongModeType(this, inferred_type);
1509 return *inferred_type;
1510 }
1511
1512 return CompileType::Dynamic();
1513}
1514
1516 // TODO(dartbug.com/40188): Share implementation with InstanceCallBaseInstr.
1517 const Function& target = interface_target();
1518 ASSERT(!target.IsNull());
1519 const auto& result_type = AbstractType::ZoneHandle(target.result_type());
1520 if (result_type.IsInstantiated()) {
1521 TraceStrongModeType(this, result_type);
1524 }
1525
1526 return CompileType::Dynamic();
1527}
1528
1530 bool is_nullable = CompileType::kCanBeNull;
1532 const Function& target = *targets_.TargetAt(0)->target;
1533 if (target.has_pragma()) {
1535 if (cid != kDynamicCid) {
1536 return CompileType::FromCid(cid);
1538 is_nullable = CompileType::kCannotBeNull;
1539 }
1540 }
1541 }
1542
1544 return is_nullable ? type : type.CopyNonNullable();
1545}
1546
1548 Value* type_args_value) {
1549 ASSERT(inferred_type != nullptr);
1550 const intptr_t cid = inferred_type->ToNullableCid();
1552 if ((cid == kGrowableObjectArrayCid || cid == kArrayCid ||
1553 cid == kImmutableArrayCid) &&
1554 type_args_value->BindsToConstant()) {
1555 Thread* thread = Thread::Current();
1556 Zone* zone = thread->zone();
1557 const Class& cls =
1558 Class::Handle(zone, thread->isolate_group()->class_table()->At(cid));
1559 auto& type_args = TypeArguments::Handle(zone);
1560 if (!type_args_value->BoundConstant().IsNull()) {
1561 type_args ^= type_args_value->BoundConstant().ptr();
1562 ASSERT(type_args.Length() >= cls.NumTypeArguments());
1563 type_args = type_args.FromInstanceTypeArguments(thread, cls);
1564 }
1566 zone, Type::New(cls, type_args, Nullability::kNonNullable));
1567 ASSERT(type.IsInstantiated());
1568 type.SetIsFinalized();
1571 }
1572 return *inferred_type;
1573}
1574
1576 // TODO(alexmarkov): calculate type of StaticCallInstr eagerly
1577 // (in optimized mode) and avoid keeping separate result_type.
1578 CompileType* const inferred_type = result_type();
1580 return ComputeListFactoryType(inferred_type, ArgumentValueAt(0));
1581 }
1582
1583 intptr_t inferred_cid = kDynamicCid;
1584 bool is_nullable = CompileType::kCanBeNull;
1585 if (inferred_type != nullptr) {
1586 if (inferred_type->IsNullableInt()) {
1587 TraceStrongModeType(this, inferred_type);
1588 return *inferred_type;
1589 }
1590 inferred_cid = inferred_type->ToNullableCid();
1591 is_nullable = inferred_type->is_nullable();
1592 }
1593
1594 if (function_.has_pragma()) {
1595 const intptr_t cid = MethodRecognizer::ResultCidFromPragma(function_);
1596 if (cid != kDynamicCid) {
1597 return CompileType::FromCid(cid);
1598 }
1600 is_nullable = CompileType::kCannotBeNull;
1601 }
1602 }
1603
1604 const AbstractType& result_type =
1606 CompileType result(is_nullable && !result_type.IsStrictlyNonNullable(),
1608 inferred_cid == kDynamicCid ? kIllegalCid : inferred_cid,
1609 &result_type);
1611 return result;
1612}
1613
1615 if (local().needs_covariant_check_in_method()) {
1616 // We may not yet have checked the actual type of the parameter value.
1617 // Assuming that the value has the required type can lead to unsound
1618 // optimizations. See dartbug.com/43464.
1619 return CompileType::Dynamic();
1620 }
1621 return *local().inferred_type();
1622}
1623
1625 return *value()->Type();
1626}
1627
1629 // Returns stored value.
1630 return *value()->Type();
1631}
1632
1636
1640
1642 const Field& field = this->field();
1643 ASSERT(field.is_static());
1644 bool is_nullable = true;
1645 intptr_t cid = kIllegalCid; // Abstract type is known, calculate cid lazily.
1646
1647 AbstractType* abstract_type = &AbstractType::ZoneHandle(field.type());
1648 TraceStrongModeType(this, *abstract_type);
1649 if (abstract_type->IsStrictlyNonNullable()) {
1650 is_nullable = false;
1651 }
1652
1653 if ((field.guarded_cid() != kIllegalCid) &&
1654 (field.guarded_cid() != kDynamicCid)) {
1655 cid = field.guarded_cid();
1656 if (!field.is_nullable()) {
1657 is_nullable = false;
1658 }
1659 abstract_type = nullptr; // Cid is known, calculate abstract type lazily.
1660 }
1661
1662 if (field.needs_load_guard()) {
1663 // Should be kept in sync with Slot::Get.
1664 DEBUG_ASSERT(IsolateGroup::Current()->HasAttemptedReload());
1665 return CompileType::Dynamic();
1666 }
1667
1668 const bool can_be_sentinel = !calls_initializer() && field.is_late() &&
1670 return CompileType(is_nullable, can_be_sentinel, cid, abstract_type);
1671}
1672
1677
1681
1683 // TODO(vegorov): Incorporate type arguments into the returned type.
1684 return CompileType::FromCid(cls().id());
1685}
1686
1688 const auto& func = known_function();
1689 if (!func.IsNull()) {
1690 const auto& sig = FunctionType::ZoneHandle(func.signature());
1692 CompileType::kCannotBeSentinel, kClosureCid, &sig);
1693 }
1694 return CompileType::FromCid(kClosureCid);
1695}
1696
1700
1704
1708
1710 if (slot().IsRecordField()) {
1711 const intptr_t index = compiler::target::Record::field_index_at_offset(
1712 slot().offset_in_bytes());
1713 if (auto* alloc = instance()->definition()->AsAllocateSmallRecord()) {
1714 if (index < alloc->num_fields()) {
1715 return *(alloc->InputAt(index)->Type());
1716 }
1717 }
1718 const AbstractType* instance_type = instance()->Type()->ToAbstractType();
1719 if (instance_type->IsRecordType()) {
1720 const auto& record_type = RecordType::Cast(*instance_type);
1721 if (index < record_type.NumFields()) {
1722 const auto& field_type =
1723 AbstractType::ZoneHandle(record_type.FieldTypeAt(index));
1724 return CompileType::FromAbstractType(field_type,
1727 }
1728 }
1729 }
1730 CompileType type = slot().type();
1731 if (calls_initializer()) {
1733 }
1734 TraceStrongModeType(this, &type);
1735 return type;
1736}
1737
1739 switch (class_id()) {
1740 case kOneByteStringCid:
1741 case kTwoByteStringCid:
1742 return can_pack_into_smi() ? CompileType::FromCid(kSmiCid)
1743 : CompileType::Int();
1744 default:
1745 UNIMPLEMENTED();
1746 return CompileType::Dynamic();
1747 }
1748}
1749
1753
1757
1761
1765
1770
1772 return UpdateType(ComputeType());
1773}
1774
1778
1782
1783static const intptr_t simd_op_result_cids[] = {
1784#define kInt8Cid kSmiCid
1785#define CASE(Arity, Mask, Name, Args, Result) k##Result##Cid,
1787#undef CASE
1788#undef kWordCid
1789};
1790
1794
1796 return CompileType::FromCid(result_cid_);
1797}
1798
1802
1806
1808 switch (from_representation()) {
1809 case kUnboxedFloat:
1810 return CompileType::FromCid(kFloat32x4Cid);
1811 case kUnboxedDouble:
1812 return CompileType::FromCid(kFloat64x2Cid);
1813 case kUnboxedInt32:
1814 return CompileType::FromCid(kInt32x4Cid);
1815 default:
1816 UNREACHABLE();
1817 return CompileType::Dynamic();
1818 }
1819}
1820
1822 return CompileType::FromCid(definition_cid_);
1823}
1824
1826 return CompileType::FromCid(definition_cid_);
1827}
1828
1829static AbstractTypePtr ExtractElementTypeFromArrayType(
1830 const AbstractType& array_type) {
1831 if (array_type.IsTypeParameter()) {
1833 AbstractType::Handle(TypeParameter::Cast(array_type).bound()));
1834 }
1835 if (!array_type.IsType()) {
1836 return Object::dynamic_type().ptr();
1837 }
1838 const intptr_t cid = array_type.type_class_id();
1839 if (cid == kGrowableObjectArrayCid || cid == kArrayCid ||
1840 cid == kImmutableArrayCid ||
1841 array_type.type_class() ==
1842 IsolateGroup::Current()->object_store()->list_class()) {
1843 const auto& type_args =
1844 TypeArguments::Handle(Type::Cast(array_type).arguments());
1845 return type_args.TypeAtNullSafe(Array::kElementTypeTypeArgPos);
1846 }
1847 return Object::dynamic_type().ptr();
1848}
1849
1850static AbstractTypePtr GetElementTypeFromArray(Value* array) {
1851 // Sometimes type of definition may contain a static type
1852 // which is useful to extract element type, but reaching type
1853 // only has a cid. So try out type of definition, if any.
1854 if (array->definition()->HasType()) {
1856 *(array->definition()->Type()->ToAbstractType())));
1857 if (!elem_type.IsDynamicType()) {
1858 return elem_type.ptr();
1859 }
1860 }
1862}
1863
1865 // 1. Try to extract element type from array value.
1866 auto& elem_type = AbstractType::Handle(GetElementTypeFromArray(array));
1867 if (!elem_type.IsDynamicType()) {
1870 }
1871
1872 // 2. Array value may be loaded from GrowableObjectArray.data.
1873 // Unwrap and try again.
1874 if (auto* load_field = array->definition()->AsLoadField()) {
1875 if (load_field->slot().IsIdentical(Slot::GrowableObjectArray_data())) {
1876 array = load_field->instance();
1877 elem_type = GetElementTypeFromArray(array);
1878 if (!elem_type.IsDynamicType()) {
1881 }
1882 }
1883 }
1884
1885 // 3. If array was loaded from a Dart field, use field's static type.
1886 // Unlike propagated type (which could be cid), static type may contain
1887 // type arguments which can be used to figure out element type.
1888 if (auto* load_field = array->definition()->AsLoadField()) {
1889 if (load_field->slot().IsDartField()) {
1890 elem_type = load_field->slot().field().type();
1891 elem_type = ExtractElementTypeFromArrayType(elem_type);
1892 }
1893 }
1894
1897}
1898
1900 // Use the precise array element representation instead of the returned
1901 // representation, since for small elements, that results in a Smi type
1902 // instead of a Int type on 32-bit architectures.
1903 auto const rep =
1907 }
1908 switch (class_id()) {
1909 case kArrayCid:
1910 case kImmutableArrayCid: {
1912 if (result_type_ != nullptr &&
1913 !CompileType::Dynamic().IsEqualTo(result_type_)) {
1914 // The original call knew something.
1915 return *CompileType::ComputeRefinedType(&elem_type, result_type_);
1916 }
1917 return elem_type;
1918 }
1919
1920 case kTypeArgumentsCid:
1921 return CompileType::FromAbstractType(Object::dynamic_type(),
1924
1925 case kRecordCid:
1926 return CompileType::Dynamic();
1927
1928 default:
1929 UNIMPLEMENTED();
1930 return CompileType::Dynamic();
1931 }
1932}
1933
1935 if ((class_id_ == kArrayCid) || (class_id_ == kImmutableArrayCid)) {
1936 // Array element type computation depends on computed
1937 // types of other instructions and may change over time.
1938 return UpdateType(ComputeType());
1939 }
1940 return false;
1941}
1942
1943} // namespace dart
static float prev(float f)
#define check(reporter, ref, unref, make, kill)
static bool left(const SkPoint &p0, const SkPoint &p1)
#define IG
#define UNREACHABLE()
Definition assert.h:248
#define DEBUG_ASSERT(cond)
Definition assert.h:321
bool IsSubtypeOf(const AbstractType &other, Heap::Space space, FunctionTypeMapping *function_type_equivalence=nullptr) const
Definition object.cc:21611
virtual classid_t type_class_id() const
Definition object.cc:21074
bool IsDartFunctionType() const
Definition object.cc:21512
bool IsTopTypeForSubtyping() const
Definition object.cc:21457
bool IsDartRecordType() const
Definition object.cc:21521
bool IsVoidType() const
Definition object.h:9169
const char * ScrubbedNameCString() const
Definition object.cc:21407
bool IsObjectType() const
Definition object.h:9181
bool IsTopTypeForInstanceOf() const
Definition object.cc:21440
virtual bool IsInstantiated(Genericity genericity=kAny, intptr_t num_free_fun_type_params=kAllFree) const
Definition object.cc:21200
StringPtr ScrubbedName() const
Definition object.cc:21403
virtual ClassPtr type_class() const
Definition object.cc:21083
bool IsNullable() const
Definition object.h:9043
bool IsNullType() const
Definition object.cc:21428
bool IsDynamicType() const
Definition object.h:9166
bool IsSentinelType() const
Definition object.cc:21436
bool IsStrictlyNonNullable() const
Definition object.cc:21101
virtual CompileType ComputeType() const
const Function & known_function() const
Definition il.h:7490
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
const Class & cls() const
Definition il.h:7396
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
classid_t class_id() const
Definition il.h:7850
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
static constexpr intptr_t kElementTypeTypeArgPos
Definition object.h:10877
Value * dst_type() const
Definition il.h:4405
Value * value() const
Definition il.h:4404
virtual CompileType ComputeType() const
Value * value() const
Definition il.h:4473
virtual CompileType ComputeType() const
void TruncateTo(intptr_t length)
void Add(const T &value)
intptr_t length() const
virtual CompileType ComputeType() const
void Add(intptr_t i)
Definition bit_vector.h:63
bool Contains(intptr_t i) const
Definition bit_vector.h:91
void Remove(intptr_t i)
Definition bit_vector.h:68
static const Bool & False()
Definition object.h:10778
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Representation from_representation() const
Definition il.h:8481
virtual CompileType ComputeType() const
virtual bool ValueFitsSmi() const
Definition il.cc:3244
virtual CompileType ComputeType() const
Representation from_representation() const
Definition il.h:10448
TargetEntryInstr * false_successor() const
Definition il.h:4030
TargetEntryInstr * true_successor() const
Definition il.h:4029
ComparisonInstr * comparison() const
Definition il.h:4003
static bool HasSubclasses(const Class &cls)
Definition cha.cc:64
void AddToGuardedClassesForSubclassCount(const Class &cls, intptr_t subclass_count)
Definition cha.cc:40
static bool ConcreteSubclasses(const Class &cls, GrowableArray< intptr_t > *class_ids)
Definition cha.cc:90
static bool ClassCanBeFuture(const Class &cls)
Definition cha.cc:154
static bool HasSingleConcreteImplementation(const Class &interface, intptr_t *implementation_cid)
Definition cha.cc:127
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Value * index() const
Definition il.h:10743
virtual bool RecomputeType()
Value * value() const
Definition il.h:10647
virtual CompileType ComputeType() const
intptr_t MonomorphicReceiverCid() const
Definition il.cc:804
CidRange * At(int index) const
Definition il.h:750
intptr_t length() const
Definition il.h:752
bool IsMonomorphic() const
Definition il.cc:799
ClassPtr At(intptr_t cid) const
const char * ScrubbedNameCString() const
Definition object.cc:3046
StringPtr ScrubbedName() const
Definition object.cc:3042
intptr_t id() const
Definition object.h:1235
intptr_t NumTypeArguments() const
Definition object.cc:3690
bool IsPrivate() const
Definition object.cc:6180
TypePtr RareType() const
Definition object.cc:3097
bool IsGeneric() const
Definition object.h:1360
bool is_future_subtype() const
Definition object.h:2172
ClassPtr SuperClass(ClassTable *class_table=nullptr) const
Definition object.cc:3715
virtual CompileType ComputeType() const
static CompileType * ComputeRefinedType(CompileType *old_type, CompileType *new_type)
void Union(CompileType *other)
bool IsAssignableTo(const AbstractType &other)
static constexpr bool kCanBeSentinel
CompileType CopyNonNullable()
static CompileType FromCid(intptr_t cid)
static constexpr bool kCannotBeSentinel
bool can_be_sentinel() const
bool IsInstanceOf(const AbstractType &other)
static CompileType DynamicOrSentinel()
static constexpr bool kCannotBeNull
static CompileType Int()
static constexpr bool kCanBeNull
bool IsSubtypeOf(const AbstractType &other)
static CompileType Dynamic()
bool Specialize(GrowableArray< intptr_t > *class_ids)
static CompileType String()
bool IsNone() const
static CompileType Null()
static CompileType NullableDouble()
bool is_nullable() const
static CompileType Object()
static CompileType FromRepresentation(Representation rep)
static CompileType Smi()
static CompileType Int32()
CompileType CopyNonSentinel()
static CompileType FromAbstractType(const AbstractType &type, bool can_be_null, bool can_be_sentinel)
static CompileType NullableInt()
const char * ToCString() const
void PrintTo(BaseTextBuffer *f) const
static CompileType Bool()
static CompileType None()
const AbstractType * ToAbstractType()
static CompileType FromUnboxedRepresentation(Representation rep)
static CompileType Double()
const Class & ComparableClass()
static CompilerState & Current()
virtual CompileType ComputeType() const
const Object & value() const
Definition il.h:4212
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Value * type_arguments() const
Definition il.h:7806
PRINT_OPERANDS_TO_SUPPORT PRINT_TO_SUPPORT bool UpdateType(CompileType new_type)
Definition il.h:2535
CompileType * Type()
Definition il.h:2503
intptr_t ssa_temp_index() const
Definition il.h:2485
bool HasType() const
Definition il.h:2512
virtual CompileType ComputeType() const
const Function & interface_target() const
Definition il.h:5038
virtual PRINT_OPERANDS_TO_SUPPORT CompileType ComputeType() const
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Value * value() const
Definition il.h:5812
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
bool is_final() const
Definition object.h:4420
bool has_initializer() const
Definition object.h:4586
bool is_nullable() const
Definition object.cc:11821
bool is_late() const
Definition object.h:4422
bool is_static() const
Definition object.h:4418
bool needs_load_guard() const
Definition object.h:4429
intptr_t guarded_cid() const
Definition object.cc:11800
AbstractTypePtr type() const
Definition object.h:4523
virtual void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr *instr)
virtual void VisitAssertBoolean(AssertBooleanInstr *instr)
virtual void VisitCheckClassId(CheckClassIdInstr *instr)
virtual void VisitCheckNull(CheckNullInstr *instr)
virtual void VisitCheckSmi(CheckSmiInstr *instr)
static void Propagate(FlowGraph *flow_graph)
virtual void VisitAssertSubtype(AssertSubtypeInstr *instr)
virtual void VisitAssertAssignable(AssertAssignableInstr *instr)
virtual void VisitJoinEntry(JoinEntryInstr *instr)
virtual void VisitGuardFieldClass(GuardFieldClassInstr *instr)
virtual void VisitInstanceCall(InstanceCallInstr *instr)
virtual void VisitCheckArrayBound(CheckArrayBoundInstr *instr)
virtual void VisitBranch(BranchInstr *instr)
virtual void VisitCheckClass(CheckClassInstr *instr)
GraphEntryInstr * graph_entry() const
Definition flow_graph.h:268
bool should_print() const
Definition flow_graph.h:505
Zone * zone() const
Definition flow_graph.h:261
intptr_t current_ssa_temp_index() const
Definition flow_graph.h:243
Thread * thread() const
Definition flow_graph.h:260
RedefinitionInstr * EnsureRedefinition(Instruction *prev, Definition *original, CompileType compile_type)
void AllocateSSAIndex(Definition *def)
Definition flow_graph.h:274
static void RenameDominatedUses(Definition *def, Instruction *dom, Definition *other)
virtual CompileType ComputeType() const
bool IsCompiledForOsr() const
Definition il.cc:1255
FunctionEntryInstr * unchecked_entry() const
Definition il.h:1987
const ParsedFunction & parsed_function() const
Definition il.h:1995
const Field & field() const
Definition il.h:6476
Value * value() const
Definition il.h:6474
@ kOld
Definition heap.h:39
intptr_t GetReceiverClassIdAt(intptr_t index) const
Definition object.cc:17067
virtual CompileType ComputeType() const
CompileType * result_type() const
Definition il.h:4730
const ICData * ic_data() const
Definition il.h:4698
const Function & interface_target() const
Definition il.h:4708
Token::Kind token_kind() const
Definition il.h:4707
virtual CompileType ComputeType() const
const String & function_name() const
Definition il.h:4706
bool has_unique_selector() const
Definition il.h:4713
const AbstractType & type() const
Definition il.h:7245
virtual CompileType ComputeType() const
Value * value() const
Definition il.h:7241
static bool NullIsAssignableTo(const AbstractType &other)
Definition object.cc:20715
const char * ToCString() const
Value * ArgumentValueAt(intptr_t index) const
Definition il.h:3417
virtual CompileType ComputeType() const
bool all_classes_finalized() const
Definition isolate.h:706
ObjectStore * object_store() const
Definition isolate.h:505
static IsolateGroup * Current()
Definition isolate.h:534
ClassTable * class_table() const
Definition isolate.h:491
bool PrintPropertyStr(const char *name, const String &s, intptr_t offset=0, intptr_t count=-1)
void PrintPropertyBool(const char *name, bool b)
Value * object() const
Definition il.h:8018
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
bool can_pack_into_smi() const
Definition il.h:6858
intptr_t class_id() const
Definition il.h:6855
const Slot & slot() const
Definition il.h:8096
virtual CompileType ComputeType() const
Value * instance() const
Definition il.h:8095
intptr_t class_id() const
Definition il.h:6759
virtual CompileType ComputeType() const
Value * array() const
Definition il.h:6756
const LocalVariable & local() const
Definition il.h:5765
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
const Field & field() const
Definition il.h:6639
bool is_late() const
Definition scopes.h:160
CompileType * inferred_type() const
Definition scopes.h:136
const AbstractType & static_type() const
Definition scopes.h:134
bool was_type_checked_by_caller() const
Definition scopes.h:194
CompileType * inferred_arg_type() const
Definition scopes.h:137
bool is_explicit_covariant_parameter() const
Definition scopes.h:168
virtual CompileType ComputeType() const
static intptr_t ResultCidFromPragma(const Object &function_or_field)
static bool HasNonNullableResultTypeFromPragma(const Object &function_or_field)
intptr_t GetClassId() const
Definition object.h:341
ObjectPtr ptr() const
Definition object.h:332
virtual const char * ToCString() const
Definition object.h:366
bool IsNull() const
Definition object.h:363
static Object & Handle()
Definition object.h:407
static Object & ZoneHandle()
Definition object.h:419
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
intptr_t param_index() const
Definition il.h:2926
const Function & function() const
Definition parser.h:73
LocalScope * scope() const
Definition parser.h:76
LocalVariable * ParameterVariable(intptr_t i) const
Definition parser.h:239
LocalVariable * RawParameterVariable(intptr_t i) const
Definition parser.h:235
virtual bool RecomputeType()
virtual CompileType ComputeType() const
bool Done() const
Definition il.h:2106
virtual CompileType ComputeType() const
bool IsSureToCallSingleRecognizedTarget() const
Definition il.cc:5671
const CallTargets & targets() const
Definition il.h:4935
virtual CompileType ComputeType() const
Value * value() const
Definition il.h:4091
virtual CompileType ComputeType() const
static FunctionPtr ResolveDynamicAnyArgs(Zone *zone, const Class &receiver_class, const String &function_name, bool allow_add=true)
Definition resolver.cc:198
virtual CompileType ComputeType() const
Kind kind() const
Definition il.h:11304
CompileType type() const
Definition slot.h:538
CompileType * result_type() const
Definition il.h:5603
const Function & function() const
Definition il.h:5574
bool is_known_list_constructor() const
Definition il.h:5612
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Value * value() const
Definition il.h:5914
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
virtual Value * InputAt(intptr_t i) const
Definition il.h:3941
intptr_t ArgumentCount() const
Definition il.h:4568
Value * Receiver() const
Definition il.h:4559
bool calls_initializer() const
Definition il.h:6579
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Zone * zone() const
static Thread * Current()
Definition thread.h:361
CompilerState & compiler_state()
Definition thread.h:583
IsolateGroup * isolate_group() const
Definition thread.h:540
static TypePtr SmiType()
Definition object.cc:21894
static TypePtr BoolType()
Definition object.cc:21882
static TypePtr New(const Class &clazz, const TypeArguments &arguments, Nullability nullability=Nullability::kLegacy, Heap::Space space=Heap::kOld)
Definition object.cc:22492
static TypePtr NullableDouble()
Definition object.cc:21906
static TypePtr ObjectType()
Definition object.cc:21878
static TypePtr NullableIntType()
Definition object.cc:21890
static TypePtr Double()
Definition object.cc:21902
static TypePtr StringType()
Definition object.cc:21930
static TypePtr MintType()
Definition object.cc:21898
static TypePtr IntType()
Definition object.cc:21886
static TypePtr NullType()
Definition object.cc:21862
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
bool BindsToConstant() const
Definition il.cc:1181
void SetReachingType(CompileType *type)
const Object & BoundConstant() const
Definition il.cc:1199
Definition * definition() const
Definition il.h:103
CompileType * Type()
void RefineReachingType(CompileType *type)
intptr_t InputCount() const
Definition il.h:2776
Value * InputAt(intptr_t i) const
Definition il.h:2777
char * MakeCopyOfString(const char *str)
Definition zone.cc:270
#define THR_Print(format,...)
Definition log.h:20
#define UNIMPLEMENTED
#define ASSERT(E)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
uint8_t value
GAsyncResult * result
uint32_t * target
constexpr bool FLAG_support_il_printer
Definition flag_list.h:48
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
Dart_NativeFunction function
Definition fuchsia.cc:51
#define CASE(Arity, Mask, Name, Args, Result)
#define SIMD_OP_LIST(M, BINARY_OP)
Definition il.h:11195
size_t length
bool IsSmi(int64_t v)
static CompileType ComputeListFactoryType(CompileType *inferred_type, Value *type_args_value)
DART_EXPORT bool IsNull(Dart_Handle object)
static const intptr_t simd_op_result_cids[]
@ kIllegalCid
Definition class_id.h:214
@ kNullCid
Definition class_id.h:252
@ kVoidCid
Definition class_id.h:254
@ kDynamicCid
Definition class_id.h:253
@ kNeverCid
Definition class_id.h:255
Representation
Definition locations.h:66
static AbstractTypePtr GetElementTypeFromArray(Value *array)
static AbstractTypePtr ExtractElementTypeFromArrayType(const AbstractType &array_type)
static CompileType ComputeArrayElementType(Value *array)
static bool CanPotentiallyBeSmi(const AbstractType &type, bool recurse)
const intptr_t cid
static Dart_TypedData_Type GetType(intptr_t class_id)
bool IsInternalOnlyClassId(intptr_t index)
Definition class_id.h:299
const char *const function_name
static void TraceStrongModeType(const Instruction *instr, const AbstractType &type)
SINT Vec< 2 *N, T > join(const Vec< N, T > &lo, const Vec< N, T > &hi)
Definition SkVx.h:242
#define Pd
Definition globals.h:408
static bool RequiresAllocation(Representation rep)
Definition il.cc:468
static intptr_t BoxCid(Representation rep)
Definition il.cc:491
intptr_t cid_start
Definition il.h:220
bool IsIllegalRange() const
Definition il.h:216
intptr_t cid_end
Definition il.h:221
static constexpr bool IsUnboxedInteger(Representation rep)
Definition locations.h:92
static constexpr bool IsUnboxed(Representation rep)
Definition locations.h:101
static Representation RepresentationOfArrayElement(classid_t cid)
Definition locations.cc:79
#define TIMELINE_DURATION(thread, stream, name)
Definition timeline.h:39