Flutter Engine
The Flutter Engine
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()).
294 CompileType result = type->CopyNonNullable();
295 if (!result.IsNone()) {
296 SetTypeOf(check, new (zone()) CompileType(result));
297 }
298 }
299}
300
301void FlowGraphTypePropagator::CheckNonNullSelector(
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,
315 function_name, /*allow_add=*/true);
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();
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())
431 EnsureMoreAccurateRedefinition(
432 true_successor, left,
435 }
436 } else if (comparison->InputAt(0)->BindsToConstant() &&
437 comparison->InputAt(0)->BoundConstant().IsNull()) {
438 // Handle for expr != null.
439 BlockEntryInstr* true_successor =
440 negated ? instr->true_successor() : instr->false_successor();
441 EnsureMoreAccurateRedefinition(
442 true_successor, comparison->InputAt(1)->definition(),
443 comparison->InputAt(1)->Type()->CopyNonNullable());
444
445 } else if (comparison->InputAt(1)->BindsToConstant() &&
446 comparison->InputAt(1)->BoundConstant().IsNull()) {
447 // Handle for null != expr.
448 BlockEntryInstr* true_successor =
449 negated ? instr->true_successor() : instr->false_successor();
450 EnsureMoreAccurateRedefinition(
451 true_successor, comparison->InputAt(0)->definition(),
452 comparison->InputAt(0)->Type()->CopyNonNullable());
453 } else if (comparison->InputAt(0)->BindsToConstant() &&
454 comparison->InputAt(0)->BoundConstant().ptr() ==
455 Object::sentinel().ptr()) {
456 // Handle for expr != sentinel.
457 BlockEntryInstr* true_successor =
458 negated ? instr->true_successor() : instr->false_successor();
459 EnsureMoreAccurateRedefinition(
460 true_successor, comparison->InputAt(1)->definition(),
461 comparison->InputAt(1)->Type()->CopyNonSentinel());
462
463 } else if (comparison->InputAt(1)->BindsToConstant() &&
464 comparison->InputAt(1)->BoundConstant().ptr() ==
465 Object::sentinel().ptr()) {
466 // Handle for sentinel != expr.
467 BlockEntryInstr* true_successor =
468 negated ? instr->true_successor() : instr->false_successor();
469 EnsureMoreAccurateRedefinition(
470 true_successor, comparison->InputAt(0)->definition(),
471 comparison->InputAt(0)->Type()->CopyNonSentinel());
472 }
473 // TODO(fschneider): Add propagation for generic is-tests.
474}
475
476void FlowGraphTypePropagator::AddToWorklist(Definition* defn) {
477 if (defn->ssa_temp_index() == -1) {
478 return;
479 }
480
481 const intptr_t index = defn->ssa_temp_index();
482 if (!in_worklist_->Contains(index)) {
483 worklist_.Add(defn);
484 in_worklist_->Add(index);
485 }
486}
487
488Definition* FlowGraphTypePropagator::RemoveLastFromWorklist() {
489 Definition* defn = worklist_.RemoveLast();
490 ASSERT(defn->ssa_temp_index() != -1);
491 in_worklist_->Remove(defn->ssa_temp_index());
492 return defn;
493}
494
495// In the given block strengthen type assertions by hoisting first class or smi
496// check over the same value up to the point before the assertion. This allows
497// to eliminate type assertions that are postdominated by class or smi checks as
498// these checks are strongly stricter than type assertions.
499void FlowGraphTypePropagator::StrengthenAsserts(BlockEntryInstr* block) {
500 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
501 Instruction* instr = it.Current();
502
503 if (instr->IsCheckSmi() || instr->IsCheckClass()) {
504 StrengthenAssertWith(instr);
505 }
506
507 // If this is the first type assertion checking given value record it.
508 AssertAssignableInstr* assert = instr->AsAssertAssignable();
509 if (assert != nullptr) {
510 Definition* defn = assert->value()->definition()->OriginalDefinition();
511 if ((*asserts_)[defn->ssa_temp_index()] == nullptr) {
512 (*asserts_)[defn->ssa_temp_index()] = assert;
513 collected_asserts_->Add(defn->ssa_temp_index());
514 }
515 }
516 }
517
518 for (intptr_t i = 0; i < collected_asserts_->length(); i++) {
519 (*asserts_)[(*collected_asserts_)[i]] = nullptr;
520 }
521
522 collected_asserts_->TruncateTo(0);
523}
524
525void FlowGraphTypePropagator::StrengthenAssertWith(Instruction* check) {
526 // Marker that is used to mark values that already had type assertion
527 // strengthened.
528 AssertAssignableInstr* kStrengthenedAssertMarker =
529 reinterpret_cast<AssertAssignableInstr*>(-1);
530
531 Definition* defn = check->InputAt(0)->definition()->OriginalDefinition();
532
533 AssertAssignableInstr* assert = (*asserts_)[defn->ssa_temp_index()];
534 if ((assert == nullptr) || (assert == kStrengthenedAssertMarker)) {
535 return;
536 }
537 ASSERT(assert->env() != nullptr);
538
539 Instruction* check_clone = nullptr;
540 if (check->IsCheckSmi()) {
541 check_clone = new CheckSmiInstr(assert->value()->Copy(zone()),
542 assert->deopt_id(), check->source());
543 } else {
544 ASSERT(check->IsCheckClass());
545 check_clone =
546 new CheckClassInstr(assert->value()->Copy(zone()), assert->deopt_id(),
547 check->AsCheckClass()->cids(), check->source());
548 }
549 ASSERT(check_clone != nullptr);
550 check_clone->InsertBefore(assert);
551 assert->env()->DeepCopyTo(zone(), check_clone);
552
553 (*asserts_)[defn->ssa_temp_index()] = kStrengthenedAssertMarker;
554}
555
557 if (other->IsNone()) {
558 return;
559 }
560
561 if (IsNone()) {
562 *this = *other;
563 return;
564 }
565
566 can_be_null_ = can_be_null_ || other->can_be_null_;
567 can_be_sentinel_ = can_be_sentinel_ || other->can_be_sentinel_;
568
569 ToNullableCid(); // Ensure cid_ is set.
570 if ((cid_ == kNullCid) || (cid_ == kSentinelCid)) {
571 cid_ = other->cid_;
572 type_ = other->type_;
573 return;
574 }
575
576 other->ToNullableCid(); // Ensure other->cid_ is set.
577 if ((other->cid_ == kNullCid) || (other->cid_ == kSentinelCid)) {
578 return;
579 }
580
581 const AbstractType* abstract_type = ToAbstractType();
582 if (cid_ != other->cid_) {
583 cid_ = kDynamicCid;
584 }
585
586 const AbstractType* other_abstract_type = other->ToAbstractType();
587 if (abstract_type->IsSubtypeOf(*other_abstract_type, Heap::kOld)) {
588 type_ = other_abstract_type;
589 return;
590 } else if (other_abstract_type->IsSubtypeOf(*abstract_type, Heap::kOld)) {
591 return; // Nothing to do.
592 }
593
594 // Climb up the hierarchy to find a suitable supertype. Note that interface
595 // types are not considered, making the union potentially non-commutative
596 if (abstract_type->IsInstantiated() && !abstract_type->IsDynamicType() &&
597 !abstract_type->IsFunctionType() && !abstract_type->IsRecordType()) {
598 Class& cls = Class::Handle(abstract_type->type_class());
599 for (; !cls.IsNull() && !cls.IsGeneric(); cls = cls.SuperClass()) {
600 type_ = &AbstractType::ZoneHandle(cls.RareType());
601 if (other_abstract_type->IsSubtypeOf(*type_, Heap::kOld)) {
602 // Found suitable supertype: keep type_ only.
603 cid_ = kDynamicCid;
604 return;
605 }
606 }
607 }
608
609 // Can't unify.
610 type_ = &Object::dynamic_type();
611}
612
614 CompileType* new_type) {
615 ASSERT(new_type != nullptr);
616
617 // In general, prefer the newly inferred type over old type.
618 // It is possible that new and old types are unrelated or do not intersect
619 // at all (for example, in case of unreachable code).
620
621 // Discard None type as it is used to denote an unknown type.
622 if (old_type == nullptr || old_type->IsNone()) {
623 return new_type;
624 }
625 if (new_type->IsNone()) {
626 return old_type;
627 }
628
629 CompileType* preferred_type = nullptr;
630
631 // Prefer exact Cid if known.
632 const intptr_t new_type_cid = new_type->ToCid();
633 const intptr_t old_type_cid = old_type->ToCid();
634 if (new_type_cid != old_type_cid) {
635 if (new_type_cid != kDynamicCid) {
636 preferred_type = new_type;
637 } else if (old_type_cid != kDynamicCid) {
638 preferred_type = old_type;
639 }
640 }
641
642 if (preferred_type == nullptr) {
643 const AbstractType* old_abstract_type = old_type->ToAbstractType();
644 const AbstractType* new_abstract_type = new_type->ToAbstractType();
645
646 // Prefer 'int' if known.
647 if (old_type->IsNullableInt()) {
648 preferred_type = old_type;
649 } else if (new_type->IsNullableInt()) {
650 preferred_type = new_type;
651 } else if (old_abstract_type->IsSubtypeOf(*new_abstract_type, Heap::kOld)) {
652 // Prefer old type, as it is clearly more specific.
653 preferred_type = old_type;
654 } else {
655 // Prefer new type as it is more recent, even though it might be
656 // no better than the old type.
657 preferred_type = new_type;
658 }
659 }
660
661 // Refine non-nullability and whether it can be sentinel.
662 const bool can_be_null = old_type->is_nullable() && new_type->is_nullable();
663 const bool can_be_sentinel =
664 old_type->can_be_sentinel() && new_type->can_be_sentinel();
665
666 if ((preferred_type->is_nullable() && !can_be_null) ||
667 (preferred_type->can_be_sentinel() && !can_be_sentinel)) {
668 return new CompileType(can_be_null, can_be_sentinel, preferred_type->cid_,
669 preferred_type->type_);
670 } else {
671 ASSERT(preferred_type->is_nullable() == can_be_null);
672 ASSERT(preferred_type->can_be_sentinel() == can_be_sentinel);
673 return preferred_type;
674 }
675}
676
678 bool can_be_null,
679 bool can_be_sentinel) {
680 return CompileType(can_be_null && !type.IsStrictlyNonNullable(),
682}
683
686 if (cid == kDynamicCid) {
687 return CompileType::Dynamic();
688 }
689 return CompileType(cid == kNullCid, cid == kSentinelCid, cid, nullptr);
690}
691
693 ASSERT(rep != kTagged);
694 ASSERT(rep != kUntagged);
696 if (!Boxing::RequiresAllocation(rep)) {
697 return CompileType::Smi();
698 }
699 return CompileType::Int();
700 }
702}
703
705 if (rep == kUntagged) return CompileType::Object();
707 return FromUnboxedRepresentation(rep);
708 }
709 ASSERT(rep != kNoRepresentation);
710 return CompileType::Dynamic();
711}
712
715 &Object::dynamic_type());
716}
717
720 &Object::dynamic_type());
721}
722
726}
727
731}
732
736}
737
739#if defined(HAS_SMI_63_BITS)
740 return FromCid(kSmiCid);
741#else
742 return Int();
743#endif
744}
745
749}
750
754}
755
757 return CompileType(kCannotBeNull, kCannotBeSentinel, kDoubleCid,
759}
760
764}
765
769}
770
774}
775
777 if (is_nullable()) return false;
778 if (cid_ != kIllegalCid && cid_ != kDynamicCid) return false;
779 return type_ != nullptr && type_->IsObjectType();
780}
781
783 if (cid_ == kIllegalCid) {
784 // Make sure to initialize cid_ for Null type to consistently return
785 // kNullCid.
786 if ((type_ != nullptr) && type_->IsNullType()) {
787 cid_ = kNullCid;
788 }
789 // Same for sentinel.
790 if ((type_ != nullptr) && type_->IsSentinelType()) {
791 cid_ = kSentinelCid;
792 }
793 }
794
795 if ((cid_ == kDynamicCid) || (can_be_null_ && (cid_ != kNullCid)) ||
796 (can_be_sentinel_ && (cid_ != kSentinelCid))) {
797 return kDynamicCid;
798 }
799
800 return ToNullableCid();
801}
802
804 if (cid_ == kIllegalCid) {
805 if (type_ == nullptr) {
806 // Type propagation is turned off or has not yet run.
807 return kDynamicCid;
808 } else if (type_->IsVoidType()) {
809 cid_ = kDynamicCid;
810 } else if (type_->IsNullType()) {
811 cid_ = kNullCid;
812 } else if (type_->IsSentinelType()) {
813 cid_ = kSentinelCid;
814 } else if (type_->IsFunctionType() || type_->IsDartFunctionType()) {
815 cid_ = kClosureCid;
816 } else if (type_->IsRecordType() || type_->IsDartRecordType()) {
817 cid_ = kRecordCid;
818 } else if (type_->type_class_id() != kIllegalCid) {
819 const Class& type_class = Class::Handle(type_->type_class());
820 intptr_t implementation_cid = kIllegalCid;
822 &implementation_cid)) {
823 cid_ = implementation_cid;
824 } else {
825 cid_ = kDynamicCid;
826 }
827 } else {
828 cid_ = kDynamicCid;
829 }
830 }
831
832 if (can_be_sentinel_ && (cid_ != kSentinelCid)) {
833 return kDynamicCid;
834 }
835
836 return cid_;
837}
838
840 return !can_be_null_ || IsNull();
841}
842
844 return (ToCid() == kNullCid);
845}
846
848 if (type_ == nullptr) {
849 // Type propagation has not run. Return dynamic-type.
850 if (cid_ == kIllegalCid) {
851 return &Object::dynamic_type();
852 }
853
854 // VM-internal objects don't have a compile-type. Return dynamic-type
855 // in this case.
856 if (IsInternalOnlyClassId(cid_) || cid_ == kTypeArgumentsCid) {
857 type_ = &Object::dynamic_type();
858 return type_;
859 }
860
861 auto IG = IsolateGroup::Current();
862 const Class& type_class = Class::Handle(IG->class_table()->At(cid_));
863 type_ = &AbstractType::ZoneHandle(type_class.RareType());
864 }
865
866 return type_;
867}
868
870 if (other.IsTopTypeForSubtyping()) {
871 return true;
872 }
873
874 if (IsNone()) {
875 return false;
876 }
877
878 return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
879}
880
882 if (other.IsTopTypeForSubtyping()) {
883 return true;
884 }
885 // If we allow comparisons against an uninstantiated type, then we can
886 // end up incorrectly optimizing away AssertAssignables where the incoming
887 // value and outgoing value have CompileTypes that would return true to the
888 // subtype check below, but at runtime are instantiated with different type
889 // argument vectors such that the relation does not hold for the runtime
890 // instantiated values.
891 //
892 // We might consider using an approximation of the uninstantiated type,
893 // like the instantiation to bounds, and compare to that. However, in
894 // vm/dart/regress_b_230945329_test.dart we have a case where the compared
895 // uninstantiated type is the same as the one in the CompileType. Thus, no
896 // approach will be able to distinguish the two types, and so we fail the
897 // comparison in all cases.
898 if (IsNone() || !other.IsInstantiated()) {
899 return false;
900 }
901 if (is_nullable() && !Instance::NullIsAssignableTo(other)) {
902 return false;
903 }
904 return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
905}
906
908 if (other.IsTopTypeForInstanceOf()) {
909 return true;
910 }
911 if (IsNone() || !other.IsInstantiated()) {
912 return false;
913 }
914 if (is_nullable() && !other.IsNullable()) {
915 return false;
916 }
917 return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
918}
919
922 if (cid_ != kDynamicCid) {
923 class_ids->Add(cid_);
924 return true;
925 }
926 if (type_ != nullptr && type_->type_class_id() != kIllegalCid) {
927 const Class& type_class = Class::Handle(type_->type_class());
928 if (!CHA::ConcreteSubclasses(type_class, class_ids)) return false;
929 if (can_be_null_) {
930 class_ids->Add(kNullCid);
931 }
932 if (can_be_sentinel_) {
933 class_ids->Add(kSentinelCid);
934 }
935 }
936 return false;
937}
938
939// For the given type conservatively computes whether Smi can potentially
940// appear in a location of this type.
941//
942// If recurse is false this function will not call itself recursively
943// to prevent infinite recursion when traversing a cycle in type parameter
944// bounds.
945static bool CanPotentiallyBeSmi(const AbstractType& type, bool recurse) {
946 if (type.IsInstantiated()) {
948 } else if (type.IsTypeParameter()) {
949 // For type parameters look at their bounds (if recurse allows us).
950 const auto& param = TypeParameter::Cast(type);
951 return !recurse || CanPotentiallyBeSmi(AbstractType::Handle(param.bound()),
952 /*recurse=*/false);
953 } else if (type.HasTypeClass()) {
954 // If this is an uninstantiated type then it can only potentially be a super
955 // type of a Smi if it is either FutureOr<...> or Comparable<...>.
956 // In which case we need to look at the type argument to determine whether
957 // this location can contain a smi.
958 //
959 // Note: we are making a simplification here. This approach will yield
960 // true for Comparable<T> where T extends int - while in reality Smi is
961 // *not* assignable to it (because int implements Comparable<num> and not
962 // Comparable<int>).
963 if (type.IsFutureOrType() ||
964 type.type_class() == CompilerState::Current().ComparableClass().ptr()) {
965 const auto& args = TypeArguments::Handle(type.arguments());
966 const auto& arg0 = AbstractType::Handle(args.TypeAt(0));
967 return !recurse || CanPotentiallyBeSmi(arg0, /*recurse=*/true);
968 }
969 return false;
970 }
971 return false;
972}
973
975 // Fast path for known cid.
976 if (cid_ != kIllegalCid && cid_ != kDynamicCid) {
977 return cid_ == kSmiCid;
978 }
979 return CanPotentiallyBeSmi(*ToAbstractType(), /*recurse=*/true);
980}
981
983 Thread* thread = Thread::Current();
984 Zone* zone = thread->zone();
985 if (cid_ != kIllegalCid && cid_ != kDynamicCid) {
986 if ((cid_ == kNullCid) || (cid_ == kNeverCid) ||
987 IsInternalOnlyClassId(cid_) || cid_ == kTypeArgumentsCid) {
988 return false;
989 }
990 const Class& cls =
991 Class::Handle(zone, thread->isolate_group()->class_table()->At(cid_));
992 return cls.is_future_subtype();
993 }
994
996 if (type.IsTypeParameter()) {
997 type = TypeParameter::Cast(type).bound();
998 }
999 if (type.IsTypeParameter()) {
1000 // Type parameter bounds can be cyclic, do not bother handling them here.
1001 return true;
1002 }
1003 const intptr_t type_class_id = type.type_class_id();
1004 if (type_class_id == kDynamicCid || type_class_id == kVoidCid ||
1005 type_class_id == kInstanceCid || type_class_id == kFutureOrCid) {
1006 return true;
1007 }
1008 if ((type_class_id == kIllegalCid) || (type_class_id == kNullCid) ||
1009 (type_class_id == kNeverCid)) {
1010 return false;
1011 }
1012 const auto& cls = Class::Handle(zone, type.type_class());
1013 return CHA::ClassCanBeFuture(cls);
1014}
1015
1016// Keep this format in sync with pkg/vm/lib/testing/il_matchers.dart.
1018 if (IsNone()) {
1019 return;
1020 }
1021
1022 if (cid_ != kIllegalCid && cid_ != kDynamicCid) {
1023 const Class& cls =
1024 Class::Handle(IsolateGroup::Current()->class_table()->At(cid_));
1025 writer->PrintPropertyStr("c", String::Handle(cls.ScrubbedName()));
1026 }
1027
1028 if (type_ != nullptr && !type_->IsDynamicType()) {
1029 writer->PrintPropertyStr("t", String::Handle(type_->ScrubbedName()));
1030 }
1031
1032 if (can_be_null_) {
1033 writer->PrintPropertyBool("n", true);
1034 }
1035
1036 if (can_be_sentinel_) {
1037 writer->PrintPropertyBool("s", true);
1038 }
1039}
1040
1042 const char* type_name = "?";
1043 if (IsNone()) {
1044 f->AddString("T{}");
1045 return;
1046 } else if ((cid_ != kIllegalCid) && (cid_ != kDynamicCid)) {
1047 const Class& cls =
1048 Class::Handle(IsolateGroup::Current()->class_table()->At(cid_));
1049 type_name = cls.ScrubbedNameCString();
1050 } else if (type_ != nullptr) {
1051 type_name = type_->IsDynamicType() ? "*" : type_->ScrubbedNameCString();
1052 } else if (!is_nullable()) {
1053 type_name = "!null";
1054 }
1055
1056 f->Printf("T{%s%s%s}", type_name, can_be_null_ ? "?" : "",
1057 can_be_sentinel_ ? "~" : "");
1058}
1059
1060const char* CompileType::ToCString() const {
1061 char buffer[1024];
1062 BufferFormatter f(buffer, sizeof(buffer));
1063 PrintTo(&f);
1065}
1066
1068 if (reaching_type_ == nullptr) {
1069 reaching_type_ = definition()->Type();
1070 }
1071 return reaching_type_;
1072}
1073
1075 // If [type] is owned but not by the definition which flows into this use
1076 // then we need to disconnect the type from original owner by cloning it.
1077 // This is done to prevent situations when [type] is updated by its owner
1078 // but [owner] is no longer connected to this use through def-use chain
1079 // and as a result type propagator does not recompute type of the current
1080 // instruction.
1081 if (type != nullptr && type->owner() != nullptr &&
1082 type->owner() != definition()) {
1083 type = new CompileType(*type);
1084 }
1085 reaching_type_ = type;
1086}
1087
1090}
1091
1093 // Initially type of phis is unknown until type propagation is run
1094 // for the first time.
1095 return CompileType::None();
1096}
1097
1100 for (intptr_t i = 0; i < InputCount(); i++) {
1101 if (FLAG_support_il_printer && FLAG_trace_type_propagation) {
1102 THR_Print(" phi %" Pd " input %" Pd ": v%" Pd " has reaching type %s\n",
1103 ssa_temp_index(), i, InputAt(i)->definition()->ssa_temp_index(),
1104 InputAt(i)->Type()->ToCString());
1105 }
1106 result.Union(InputAt(i)->Type());
1107 }
1108
1109 if (result.IsNone()) {
1110 ASSERT(Type()->IsNone());
1111 return false;
1112 }
1113
1114 return UpdateType(result);
1115}
1116
1118 if (constrained_type_ != nullptr) {
1119 // Check if the type associated with this redefinition is more specific
1120 // than the type of its input. If yes, return it. Otherwise, fall back
1121 // to the input's type.
1122
1123 // If either type is non-nullable, the resulting type is non-nullable.
1124 const bool is_nullable =
1125 value()->Type()->is_nullable() && constrained_type_->is_nullable();
1126 // The resulting type can be the sentinel value only if both types can be.
1127 const bool can_be_sentinel = value()->Type()->can_be_sentinel() &&
1128 constrained_type_->can_be_sentinel();
1129
1130 // If either type has a concrete cid, stick with it.
1131 if (value()->Type()->ToNullableCid() != kDynamicCid) {
1132 return CompileType(is_nullable, can_be_sentinel,
1133 value()->Type()->ToNullableCid(), nullptr);
1134 }
1135 if (constrained_type_->ToNullableCid() != kDynamicCid) {
1136 return CompileType(is_nullable, can_be_sentinel,
1137 constrained_type_->ToNullableCid(), nullptr);
1138 }
1139
1141 value()->Type()->IsSubtypeOf(*constrained_type_->ToAbstractType())
1142 ? *value()->Type()
1143 : *constrained_type_);
1144 if (!is_nullable) {
1145 result = result.CopyNonNullable();
1146 }
1147 if (!can_be_sentinel) {
1148 result = result.CopyNonSentinel();
1149 }
1150 return result;
1151 }
1152 return *value()->Type();
1153}
1154
1156 return UpdateType(ComputeType());
1157}
1158
1160 CompileType* type = value()->Type();
1161 if (type->is_nullable()) {
1162 CompileType result = type->CopyNonNullable();
1163 if (!result.IsNone()) {
1164 return result;
1165 }
1166 }
1167 return *type;
1168}
1169
1171 return UpdateType(ComputeType());
1172}
1173
1175 return *index()->Type();
1176}
1177
1179 return UpdateType(ComputeType());
1180}
1181
1183 return *index()->Type();
1184}
1185
1187 return UpdateType(ComputeType());
1188}
1189
1191 return CompileType::FromCid(kSmiCid);
1192}
1193
1195 // Note that returning the declared type of the formal parameter would be
1196 // incorrect, because ParameterInstr is used as input to the type check
1197 // verifying the run time type of the passed-in parameter and this check would
1198 // always be wrongly eliminated.
1199 // However there are parameters that are known to match their declared type:
1200 // for example receiver.
1201 GraphEntryInstr* graph_entry = block_->AsGraphEntry();
1202 if (graph_entry == nullptr) {
1203 if (auto function_entry = block_->AsFunctionEntry()) {
1204 graph_entry = function_entry->graph_entry();
1205 } else if (auto osr_entry = block_->AsOsrEntry()) {
1206 graph_entry = osr_entry->graph_entry();
1207 } else if (auto catch_entry = block_->AsCatchBlockEntry()) {
1208 graph_entry = catch_entry->graph_entry();
1209 } else {
1210 UNREACHABLE();
1211 }
1212 }
1213 // Parameters at OSR entries have type dynamic.
1214 //
1215 // TODO(kmillikin): Use the actual type of the parameter at OSR entry.
1216 // The code below is not safe for OSR because it doesn't necessarily use
1217 // the correct scope.
1218 if (graph_entry->IsCompiledForOsr()) {
1219 // Parameter at OSR entry may correspond to a late local variable.
1221 }
1222
1223 const ParsedFunction& pf = graph_entry->parsed_function();
1224 const Function& function = pf.function();
1225 if (function.IsIrregexpFunction()) {
1226 // In irregexp functions, types of input parameters are known and immutable.
1227 // Set parameter types here in order to prevent unnecessary CheckClassInstr
1228 // from being generated.
1229 switch (env_index()) {
1231 return CompileType::FromCid(kRegExpCid);
1233 return CompileType::FromCid(function.string_specialization_cid());
1235 return CompileType::FromCid(kSmiCid);
1236 default:
1237 UNREACHABLE();
1238 }
1239 UNREACHABLE();
1240 return CompileType::Dynamic();
1241 }
1242
1243 const intptr_t param_index = this->param_index();
1244 if (param_index >= 0) {
1245 // Parameter is the receiver.
1246 if ((param_index == 0) &&
1247 (function.IsDynamicFunction() || function.IsGenerativeConstructor())) {
1249 if (type.IsObjectType() || type.IsNullType()) {
1250 // Receiver can be null.
1253 }
1254
1255 // Receiver can't be null but can be an instance of a subclass.
1256 intptr_t cid = kDynamicCid;
1257
1258 if (type.type_class_id() != kIllegalCid) {
1259 Thread* thread = Thread::Current();
1260 const Class& type_class = Class::Handle(type.type_class());
1261 if (!CHA::HasSubclasses(type_class)) {
1262 if (type_class.IsPrivate()) {
1263 // Private classes can never be subclassed by later loaded libs.
1264 cid = type_class.id();
1265 } else {
1266 if (FLAG_use_cha_deopt ||
1267 thread->isolate_group()->all_classes_finalized()) {
1268 if (FLAG_trace_cha) {
1269 THR_Print(
1270 " **(CHA) Computing exact type of receiver, "
1271 "no subclasses: %s\n",
1272 type_class.ToCString());
1273 }
1274 if (FLAG_use_cha_deopt) {
1275 thread->compiler_state()
1276 .cha()
1278 /*subclass_count=*/0);
1279 }
1280 cid = type_class.id();
1281 }
1282 }
1283 }
1284 }
1285
1288 }
1289
1290 const bool is_unchecked_entry_param =
1291 graph_entry->unchecked_entry() == block_;
1292
1293 const LocalVariable* param = (pf.scope() != nullptr)
1296 ASSERT(param != nullptr);
1297
1298 CompileType* inferred_type = nullptr;
1299 intptr_t inferred_cid = kDynamicCid;
1300 bool inferred_nullable = true;
1301 if (!block_->IsCatchBlockEntry()) {
1302 inferred_type = param->inferred_arg_type();
1303
1304 if (inferred_type != nullptr) {
1305 // Use inferred type if it is an int.
1306 if (inferred_type->IsNullableInt()) {
1307 TraceStrongModeType(this, inferred_type);
1308 return *inferred_type;
1309 }
1310 // Otherwise use inferred cid and nullability.
1311 inferred_cid = inferred_type->ToNullableCid();
1312 inferred_nullable = inferred_type->is_nullable();
1313 }
1314 }
1315 // If parameter type was checked by caller, then use Dart type annotation,
1316 // plus non-nullability from inferred type if known.
1317 // Do not trust static parameter type of 'operator ==' as it is a
1318 // non-nullable Object but VM handles comparison with null in
1319 // the callee, so 'operator ==' can take null as an argument.
1320 if ((function.name() != Symbols::EqualOperator().ptr()) &&
1321 (param->was_type_checked_by_caller() ||
1322 (is_unchecked_entry_param &&
1323 !param->is_explicit_covariant_parameter()))) {
1324 const AbstractType& static_type = param->static_type();
1326 inferred_nullable && !static_type.IsStrictlyNonNullable(),
1327 block_->IsCatchBlockEntry() && param->is_late(),
1328 inferred_cid == kDynamicCid ? kIllegalCid : inferred_cid,
1329 &static_type);
1331 return result;
1332 }
1333 // Last resort: use inferred type as is.
1334 if (inferred_type != nullptr) {
1335 TraceStrongModeType(this, inferred_type);
1336 return *inferred_type;
1337 }
1338 }
1339
1340 if (block_->IsCatchBlockEntry()) {
1341 // Parameter of a catch block may correspond to a late local variable.
1343 }
1344
1345 return CompileType::Dynamic();
1346}
1347
1349 if (value().IsNull()) {
1350 return CompileType::Null();
1351 }
1352
1353 intptr_t cid = value().GetClassId();
1354
1355 if (cid == kSmiCid && !compiler::target::IsSmi(Smi::Cast(value()).Value())) {
1359 }
1360
1361 if ((cid != kTypeArgumentsCid) && value().IsInstance()) {
1362 // Allocate in old-space since this may be invoked from the
1363 // background compiler.
1364 return CompileType(
1365 cid == kNullCid, cid == kSentinelCid, cid,
1366 &AbstractType::ZoneHandle(Instance::Cast(value()).GetType(Heap::kOld)));
1367 } else {
1368 // Type info for non-instance objects.
1369 return CompileType::FromCid(cid);
1370 }
1371}
1372
1374 CompileType* value_type = value()->Type();
1375
1376 const AbstractType* abs_type = &AbstractType::dynamic_type();
1377 if (dst_type()->BindsToConstant() &&
1378 dst_type()->BoundConstant().IsAbstractType()) {
1379 abs_type = &AbstractType::Cast(dst_type()->BoundConstant());
1380 if (value_type->IsSubtypeOf(*abs_type)) {
1381 return *value_type;
1382 }
1383 }
1384 return CompileType::FromAbstractType(*abs_type, value_type->is_nullable(),
1386}
1387
1389 return UpdateType(ComputeType());
1390}
1391
1393 return CompileType::Bool();
1394}
1395
1397 return CompileType::Bool();
1398}
1399
1401 return CompileType::Bool();
1402}
1403
1405 return CompileType::Bool();
1406}
1407
1409 return CompileType::Bool();
1410}
1411
1413 return CompileType::Bool();
1414}
1415
1417 return CompileType::Bool();
1418}
1419
1421 return CompileType::Bool();
1422}
1423
1425 // Used for numeric comparisons only.
1426 return CompileType::Bool();
1427}
1428
1430 // Used for numeric comparisons only.
1431 return CompileType::Bool();
1432}
1433
1436 kContextCid, &Object::dynamic_type());
1437}
1438
1441 kContextCid, &Object::dynamic_type());
1442}
1443
1446 kContextCid, &Object::dynamic_type());
1447}
1448
1450 // TODO(alexmarkov): calculate type of InstanceCallInstr eagerly
1451 // (in optimized mode) and avoid keeping separate result_type.
1452 CompileType* inferred_type = result_type();
1453 intptr_t inferred_cid = kDynamicCid;
1454 bool is_nullable = CompileType::kCanBeNull;
1455 if (inferred_type != nullptr) {
1456 if (inferred_type->IsNullableInt()) {
1457 TraceStrongModeType(this, inferred_type);
1458 return *inferred_type;
1459 }
1460 inferred_cid = inferred_type->ToNullableCid();
1461 is_nullable = inferred_type->is_nullable();
1462 }
1463
1464 // Include special cases of type inference for int operations.
1465 // This helps if both type feedback and results of TFA
1466 // are not available (e.g. in AOT unit tests).
1467 switch (token_kind()) {
1468 case Token::kADD:
1469 case Token::kSUB:
1470 case Token::kMUL:
1471 case Token::kMOD:
1472 if ((ArgumentCount() == 2) &&
1473 ArgumentValueAt(0)->Type()->IsNullableInt() &&
1474 ArgumentValueAt(1)->Type()->IsNullableInt()) {
1475 return CompileType::Int();
1476 }
1477 break;
1478 case Token::kNEGATE:
1479 if ((ArgumentCount() == 1) &&
1480 ArgumentValueAt(0)->Type()->IsNullableInt()) {
1481 return CompileType::Int();
1482 }
1483 break;
1484 default:
1485 break;
1486 }
1487
1488 const Function& target = interface_target();
1489 if (!target.IsNull()) {
1490 const AbstractType& result_type =
1491 AbstractType::ZoneHandle(target.result_type());
1492 // Currently VM doesn't have enough information to instantiate generic
1493 // result types of interface targets:
1494 // 1. receiver type inferred by the front-end is not passed to VM.
1495 // 2. VM collects type arguments through the chain of superclasses but
1496 // not through implemented interfaces.
1497 // TODO(dartbug.com/30480): instantiate generic result_type
1498 CompileType result(is_nullable && !result_type.IsStrictlyNonNullable(),
1500 inferred_cid == kDynamicCid ? kIllegalCid : inferred_cid,
1501 &result_type);
1503 return result;
1504 }
1505
1506 if (inferred_type != nullptr) {
1507 TraceStrongModeType(this, inferred_type);
1508 return *inferred_type;
1509 }
1510
1511 return CompileType::Dynamic();
1512}
1513
1515 // TODO(dartbug.com/40188): Share implementation with InstanceCallBaseInstr.
1516 const Function& target = interface_target();
1517 ASSERT(!target.IsNull());
1518 const auto& result_type = AbstractType::ZoneHandle(target.result_type());
1519 if (result_type.IsInstantiated()) {
1520 TraceStrongModeType(this, result_type);
1523 }
1524
1525 return CompileType::Dynamic();
1526}
1527
1530 const Function& target = *targets_.TargetAt(0)->target;
1531 if (target.has_pragma()) {
1533 if (cid != kDynamicCid) {
1534 return CompileType::FromCid(cid);
1535 }
1536 }
1537 }
1538
1540}
1541
1543 Value* type_args_value) {
1544 ASSERT(inferred_type != nullptr);
1545 const intptr_t cid = inferred_type->ToNullableCid();
1547 if ((cid == kGrowableObjectArrayCid || cid == kArrayCid ||
1548 cid == kImmutableArrayCid) &&
1549 type_args_value->BindsToConstant()) {
1550 Thread* thread = Thread::Current();
1551 Zone* zone = thread->zone();
1552 const Class& cls =
1553 Class::Handle(zone, thread->isolate_group()->class_table()->At(cid));
1554 auto& type_args = TypeArguments::Handle(zone);
1555 if (!type_args_value->BoundConstant().IsNull()) {
1556 type_args ^= type_args_value->BoundConstant().ptr();
1557 ASSERT(type_args.Length() >= cls.NumTypeArguments());
1558 type_args = type_args.FromInstanceTypeArguments(thread, cls);
1559 }
1561 zone, Type::New(cls, type_args, Nullability::kNonNullable));
1562 ASSERT(type.IsInstantiated());
1563 type.SetIsFinalized();
1566 }
1567 return *inferred_type;
1568}
1569
1571 // TODO(alexmarkov): calculate type of StaticCallInstr eagerly
1572 // (in optimized mode) and avoid keeping separate result_type.
1573 CompileType* const inferred_type = result_type();
1575 return ComputeListFactoryType(inferred_type, ArgumentValueAt(0));
1576 }
1577
1578 intptr_t inferred_cid = kDynamicCid;
1579 bool is_nullable = CompileType::kCanBeNull;
1580 if (inferred_type != nullptr) {
1581 if (inferred_type->IsNullableInt()) {
1582 TraceStrongModeType(this, inferred_type);
1583 return *inferred_type;
1584 }
1585 inferred_cid = inferred_type->ToNullableCid();
1586 is_nullable = inferred_type->is_nullable();
1587 }
1588
1589 if (function_.has_pragma()) {
1590 const intptr_t cid = MethodRecognizer::ResultCidFromPragma(function_);
1591 if (cid != kDynamicCid) {
1592 return CompileType::FromCid(cid);
1593 }
1594 }
1595
1596 const AbstractType& result_type =
1598 CompileType result(is_nullable && !result_type.IsStrictlyNonNullable(),
1600 inferred_cid == kDynamicCid ? kIllegalCid : inferred_cid,
1601 &result_type);
1603 return result;
1604}
1605
1607 if (local().needs_covariant_check_in_method()) {
1608 // We may not yet have checked the actual type of the parameter value.
1609 // Assuming that the value has the required type can lead to unsound
1610 // optimizations. See dartbug.com/43464.
1611 return CompileType::Dynamic();
1612 }
1613 return *local().inferred_type();
1614}
1615
1617 return *value()->Type();
1618}
1619
1621 // Returns stored value.
1622 return *value()->Type();
1623}
1624
1626 return CompileType::FromCid(kOneByteStringCid);
1627}
1628
1630 return CompileType::FromCid(kSmiCid);
1631}
1632
1634 const Field& field = this->field();
1635 ASSERT(field.is_static());
1636 bool is_nullable = true;
1637 intptr_t cid = kIllegalCid; // Abstract type is known, calculate cid lazily.
1638
1639 AbstractType* abstract_type = &AbstractType::ZoneHandle(field.type());
1640 TraceStrongModeType(this, *abstract_type);
1641 if (abstract_type->IsStrictlyNonNullable()) {
1642 is_nullable = false;
1643 }
1644
1645 if ((field.guarded_cid() != kIllegalCid) &&
1646 (field.guarded_cid() != kDynamicCid)) {
1647 cid = field.guarded_cid();
1648 if (!field.is_nullable()) {
1649 is_nullable = false;
1650 }
1651 abstract_type = nullptr; // Cid is known, calculate abstract type lazily.
1652 }
1653
1654 if (field.needs_load_guard()) {
1655 // Should be kept in sync with Slot::Get.
1656 DEBUG_ASSERT(IsolateGroup::Current()->HasAttemptedReload());
1657 return CompileType::Dynamic();
1658 }
1659
1660 const bool can_be_sentinel = !calls_initializer() && field.is_late() &&
1662 return CompileType(is_nullable, can_be_sentinel, cid, abstract_type);
1663}
1664
1666 auto type = CompileType::FromCid(kArrayCid);
1668}
1669
1672}
1673
1675 // TODO(vegorov): Incorporate type arguments into the returned type.
1676 return CompileType::FromCid(cls().id());
1677}
1678
1680 const auto& func = known_function();
1681 if (!func.IsNull()) {
1682 const auto& sig = FunctionType::ZoneHandle(func.signature());
1684 CompileType::kCannotBeSentinel, kClosureCid, &sig);
1685 }
1686 return CompileType::FromCid(kClosureCid);
1687}
1688
1690 return CompileType::FromCid(kRecordCid);
1691}
1692
1694 return CompileType::FromCid(kRecordCid);
1695}
1696
1698 return CompileType::FromCid(kSmiCid);
1699}
1700
1702 if (slot().IsRecordField()) {
1704 slot().offset_in_bytes());
1705 if (auto* alloc = instance()->definition()->AsAllocateSmallRecord()) {
1706 if (index < alloc->num_fields()) {
1707 return *(alloc->InputAt(index)->Type());
1708 }
1709 }
1710 const AbstractType* instance_type = instance()->Type()->ToAbstractType();
1711 if (instance_type->IsRecordType()) {
1712 const auto& record_type = RecordType::Cast(*instance_type);
1713 if (index < record_type.NumFields()) {
1714 const auto& field_type =
1715 AbstractType::ZoneHandle(record_type.FieldTypeAt(index));
1716 return CompileType::FromAbstractType(field_type,
1719 }
1720 }
1721 }
1722 CompileType type = slot().type();
1723 if (calls_initializer()) {
1724 type = type.CopyNonSentinel();
1725 }
1726 TraceStrongModeType(this, &type);
1727 return type;
1728}
1729
1731 switch (class_id()) {
1732 case kOneByteStringCid:
1733 case kTwoByteStringCid:
1734 return can_pack_into_smi() ? CompileType::FromCid(kSmiCid)
1735 : CompileType::Int();
1736 default:
1737 UNIMPLEMENTED();
1738 return CompileType::Dynamic();
1739 }
1740}
1741
1743 return CompileType::FromCid(kSmiCid);
1744}
1745
1747 return CompileType::FromCid(kSmiCid);
1748}
1749
1751 return CompileType::FromCid(kSmiCid);
1752}
1753
1755 return CompileType::FromCid(kSmiCid);
1756}
1757
1759 return ValueFitsSmi() ? CompileType::FromCid(kSmiCid)
1761}
1762
1764 return UpdateType(ComputeType());
1765}
1766
1768 return CompileType::Int();
1769}
1770
1772 return CompileType::FromCid(kBoolCid);
1773}
1774
1775static const intptr_t simd_op_result_cids[] = {
1776#define kInt8Cid kSmiCid
1777#define CASE(Arity, Mask, Name, Args, Result) k##Result##Cid,
1779#undef CASE
1780#undef kWordCid
1781};
1782
1785}
1786
1788 return CompileType::FromCid(result_cid_);
1789}
1790
1792 return CompileType::FromCid(kBoolCid);
1793}
1794
1797}
1798
1800 switch (from_representation()) {
1801 case kUnboxedFloat:
1802 return CompileType::FromCid(kFloat32x4Cid);
1803 case kUnboxedDouble:
1804 return CompileType::FromCid(kFloat64x2Cid);
1805 case kUnboxedInt32:
1806 return CompileType::FromCid(kInt32x4Cid);
1807 default:
1808 UNREACHABLE();
1809 return CompileType::Dynamic();
1810 }
1811}
1812
1814 return CompileType::FromCid(definition_cid_);
1815}
1816
1818 return CompileType::FromCid(definition_cid_);
1819}
1820
1821static AbstractTypePtr ExtractElementTypeFromArrayType(
1822 const AbstractType& array_type) {
1823 if (array_type.IsTypeParameter()) {
1825 AbstractType::Handle(TypeParameter::Cast(array_type).bound()));
1826 }
1827 if (!array_type.IsType()) {
1828 return Object::dynamic_type().ptr();
1829 }
1830 const intptr_t cid = array_type.type_class_id();
1831 if (cid == kGrowableObjectArrayCid || cid == kArrayCid ||
1832 cid == kImmutableArrayCid ||
1833 array_type.type_class() ==
1834 IsolateGroup::Current()->object_store()->list_class()) {
1835 const auto& type_args =
1836 TypeArguments::Handle(Type::Cast(array_type).arguments());
1837 return type_args.TypeAtNullSafe(Array::kElementTypeTypeArgPos);
1838 }
1839 return Object::dynamic_type().ptr();
1840}
1841
1842static AbstractTypePtr GetElementTypeFromArray(Value* array) {
1843 // Sometimes type of definition may contain a static type
1844 // which is useful to extract element type, but reaching type
1845 // only has a cid. So try out type of definition, if any.
1846 if (array->definition()->HasType()) {
1848 *(array->definition()->Type()->ToAbstractType())));
1849 if (!elem_type.IsDynamicType()) {
1850 return elem_type.ptr();
1851 }
1852 }
1854}
1855
1857 // 1. Try to extract element type from array value.
1858 auto& elem_type = AbstractType::Handle(GetElementTypeFromArray(array));
1859 if (!elem_type.IsDynamicType()) {
1862 }
1863
1864 // 2. Array value may be loaded from GrowableObjectArray.data.
1865 // Unwrap and try again.
1866 if (auto* load_field = array->definition()->AsLoadField()) {
1867 if (load_field->slot().IsIdentical(Slot::GrowableObjectArray_data())) {
1868 array = load_field->instance();
1869 elem_type = GetElementTypeFromArray(array);
1870 if (!elem_type.IsDynamicType()) {
1873 }
1874 }
1875 }
1876
1877 // 3. If array was loaded from a Dart field, use field's static type.
1878 // Unlike propagated type (which could be cid), static type may contain
1879 // type arguments which can be used to figure out element type.
1880 if (auto* load_field = array->definition()->AsLoadField()) {
1881 if (load_field->slot().IsDartField()) {
1882 elem_type = load_field->slot().field().type();
1883 elem_type = ExtractElementTypeFromArrayType(elem_type);
1884 }
1885 }
1886
1889}
1890
1892 // Use the precise array element representation instead of the returned
1893 // representation, since for small elements, that results in a Smi type
1894 // instead of a Int type on 32-bit architectures.
1895 auto const rep =
1899 }
1900 switch (class_id()) {
1901 case kArrayCid:
1902 case kImmutableArrayCid: {
1904 if (result_type_ != nullptr &&
1905 !CompileType::Dynamic().IsEqualTo(result_type_)) {
1906 // The original call knew something.
1907 return *CompileType::ComputeRefinedType(&elem_type, result_type_);
1908 }
1909 return elem_type;
1910 }
1911
1912 case kTypeArgumentsCid:
1913 return CompileType::FromAbstractType(Object::dynamic_type(),
1916
1917 case kRecordCid:
1918 return CompileType::Dynamic();
1919
1920 default:
1921 UNIMPLEMENTED();
1922 return CompileType::Dynamic();
1923 }
1924}
1925
1927 if ((class_id_ == kArrayCid) || (class_id_ == kImmutableArrayCid)) {
1928 // Array element type computation depends on computed
1929 // types of other instructions and may change over time.
1930 return UpdateType(ComputeType());
1931 }
1932 return false;
1933}
1934
1935} // namespace dart
static float prev(float f)
#define check(reporter, ref, unref, make, kill)
Definition: RefCntTest.cpp:85
Type
Definition: SortBench.cpp:56
#define IG
#define UNREACHABLE()
Definition: assert.h:248
#define DEBUG_ASSERT(cond)
Definition: assert.h:321
GLenum type
bool IsSubtypeOf(const AbstractType &other, Heap::Space space, FunctionTypeMapping *function_type_equivalence=nullptr) const
Definition: object.cc:21550
virtual classid_t type_class_id() const
Definition: object.cc:21033
bool IsDartFunctionType() const
Definition: object.cc:21451
bool IsTopTypeForSubtyping() const
Definition: object.cc:21396
bool IsDartRecordType() const
Definition: object.cc:21460
bool IsVoidType() const
Definition: object.h:9189
const char * ScrubbedNameCString() const
Definition: object.cc:21346
bool IsObjectType() const
Definition: object.h:9201
bool IsTopTypeForInstanceOf() const
Definition: object.cc:21379
virtual bool IsInstantiated(Genericity genericity=kAny, intptr_t num_free_fun_type_params=kAllFree) const
Definition: object.cc:21151
StringPtr ScrubbedName() const
Definition: object.cc:21342
virtual ClassPtr type_class() const
Definition: object.cc:21042
bool IsNullable() const
Definition: object.h:9066
bool IsNullType() const
Definition: object.cc:21367
bool IsDynamicType() const
Definition: object.h:9186
bool IsSentinelType() const
Definition: object.cc:21375
bool IsStrictlyNonNullable() const
Definition: object.cc:21060
virtual CompileType ComputeType() const
const Function & known_function() const
Definition: il.h:7529
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
const Class & cls() const
Definition: il.h:7435
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
classid_t class_id() const
Definition: il.h:7889
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
static constexpr intptr_t kElementTypeTypeArgPos
Definition: object.h:10903
Value * dst_type() const
Definition: il.h:4423
Value * value() const
Definition: il.h:4422
virtual CompileType ComputeType() const
Value * value() const
Definition: il.h:4491
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:10799
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Representation from_representation() const
Definition: il.h:8529
virtual CompileType ComputeType() const
virtual bool RecomputeType()
virtual bool ValueFitsSmi() const
Definition: il.cc:3253
virtual CompileType ComputeType() const
Representation from_representation() const
Definition: il.h:10502
TargetEntryInstr * false_successor() const
Definition: il.h:4048
TargetEntryInstr * true_successor() const
Definition: il.h:4047
ComparisonInstr * comparison() const
Definition: il.h:4021
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:93
static bool ClassCanBeFuture(const Class &cls)
Definition: cha.cc:160
static bool HasSingleConcreteImplementation(const Class &interface, intptr_t *implementation_cid)
Definition: cha.cc:132
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Value * index() const
Definition: il.h:10797
virtual bool RecomputeType()
Value * value() const
Definition: il.h:10701
virtual CompileType ComputeType() const
Definition: il.h:736
intptr_t MonomorphicReceiverCid() const
Definition: il.cc:806
CidRange * At(int index) const
Definition: il.h:756
intptr_t length() const
Definition: il.h:758
bool IsMonomorphic() const
Definition: il.cc:801
ClassPtr At(intptr_t cid) const
Definition: class_table.h:362
const char * ScrubbedNameCString() const
Definition: object.cc:2985
StringPtr ScrubbedName() const
Definition: object.cc:2981
intptr_t id() const
Definition: object.h:1233
intptr_t NumTypeArguments() const
Definition: object.cc:3640
bool IsPrivate() const
Definition: object.cc:6125
TypePtr RareType() const
Definition: object.cc:3036
bool IsGeneric() const
Definition: object.h:1358
bool is_future_subtype() const
Definition: object.h:2182
ClassPtr SuperClass(ClassTable *class_table=nullptr) const
Definition: object.cc:3665
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
Definition: compile_type.h:48
CompileType CopyNonNullable()
Definition: compile_type.h:113
static CompileType FromCid(intptr_t cid)
static constexpr bool kCannotBeSentinel
Definition: compile_type.h:49
bool can_be_sentinel() const
Definition: compile_type.h:80
bool IsInstanceOf(const AbstractType &other)
bool IsObject() const
CompileType(bool can_be_null, bool can_be_sentinel, intptr_t cid, const AbstractType *type)
Definition: compile_type.h:51
static CompileType DynamicOrSentinel()
static constexpr bool kCannotBeNull
Definition: compile_type.h:46
static CompileType Int()
static constexpr bool kCanBeNull
Definition: compile_type.h:45
bool IsSubtypeOf(const AbstractType &other)
static CompileType Dynamic()
bool Specialize(GrowableArray< intptr_t > *class_ids)
static CompileType String()
bool IsNone() const
Definition: compile_type.h:221
static CompileType Null()
intptr_t ToNullableCid()
static CompileType NullableDouble()
bool is_nullable() const
Definition: compile_type.h:76
static CompileType Object()
static CompileType FromRepresentation(Representation rep)
static CompileType Smi()
static CompileType Int32()
CompileType CopyNonSentinel()
Definition: compile_type.h:124
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()
Definition: compile_type.h:155
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:4230
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Value * type_arguments() const
Definition: il.h:7845
PRINT_OPERANDS_TO_SUPPORT PRINT_TO_SUPPORT bool UpdateType(CompileType new_type)
Definition: il.h:2553
CompileType * Type()
Definition: il.h:2521
intptr_t ssa_temp_index() const
Definition: il.h:2503
friend class Value
Definition: il.h:2690
bool HasType() const
Definition: il.h:2530
virtual CompileType ComputeType() const
const Function & interface_target() const
Definition: il.h:5056
virtual PRINT_OPERANDS_TO_SUPPORT CompileType ComputeType() const
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Value * value() const
Definition: il.h:5861
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
bool is_final() const
Definition: object.h:4442
bool has_initializer() const
Definition: object.h:4613
bool is_nullable() const
Definition: object.cc:11770
bool is_late() const
Definition: object.h:4444
bool is_static() const
Definition: object.h:4440
bool needs_load_guard() const
Definition: object.h:4451
intptr_t guarded_cid() const
Definition: object.cc:11749
AbstractTypePtr type() const
Definition: object.h:4550
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:503
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)
Definition: flow_graph.cc:1777
void AllocateSSAIndex(Definition *def)
Definition: flow_graph.h:274
static void RenameDominatedUses(Definition *def, Instruction *dom, Definition *other)
Definition: flow_graph.cc:2642
virtual CompileType ComputeType() const
bool IsCompiledForOsr() const
Definition: il.cc:1257
FunctionEntryInstr * unchecked_entry() const
Definition: il.h:2002
const ParsedFunction & parsed_function() const
Definition: il.h:2010
const Field & field() const
Definition: il.h:6520
Value * value() const
Definition: il.h:6518
@ kOld
Definition: heap.h:39
intptr_t GetReceiverClassIdAt(intptr_t index) const
Definition: object.cc:17020
virtual CompileType ComputeType() const
CompileType * result_type() const
Definition: il.h:4748
const ICData * ic_data() const
Definition: il.h:4716
const Function & interface_target() const
Definition: il.h:4726
Token::Kind token_kind() const
Definition: il.h:4725
virtual CompileType ComputeType() const
const String & function_name() const
Definition: il.h:4724
bool has_unique_selector() const
Definition: il.h:4731
const AbstractType & type() const
Definition: il.h:7284
virtual CompileType ComputeType() const
Value * value() const
Definition: il.h:7280
static bool NullIsAssignableTo(const AbstractType &other)
Definition: object.cc:20674
const char * ToCString() const
Definition: il_printer.cc:1683
Value * ArgumentValueAt(intptr_t index) const
Definition: il.h:3435
virtual CompileType ComputeType() const
bool all_classes_finalized() const
Definition: isolate.h:713
ObjectStore * object_store() const
Definition: isolate.h:510
static IsolateGroup * Current()
Definition: isolate.h:539
ClassTable * class_table() const
Definition: isolate.h:496
bool PrintPropertyStr(const char *name, const String &s, intptr_t offset=0, intptr_t count=-1)
Definition: json_writer.cc:256
void PrintPropertyBool(const char *name, bool b)
Definition: json_writer.cc:224
Value * object() const
Definition: il.h:8066
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
bool can_pack_into_smi() const
Definition: il.h:6902
intptr_t class_id() const
Definition: il.h:6899
const Slot & slot() const
Definition: il.h:8144
virtual CompileType ComputeType() const
Value * instance() const
Definition: il.h:8143
intptr_t class_id() const
Definition: il.h:6803
virtual bool RecomputeType()
virtual CompileType ComputeType() const
Value * array() const
Definition: il.h:6800
const LocalVariable & local() const
Definition: il.h:5814
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
const Field & field() const
Definition: il.h:6683
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)
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:2944
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:2121
virtual CompileType ComputeType() const
bool IsSureToCallSingleRecognizedTarget() const
Definition: il.cc:5669
const CallTargets & targets() const
Definition: il.h:4953
virtual CompileType ComputeType() const
Value * value() const
Definition: il.h:4109
virtual CompileType ComputeType() const
static FunctionPtr ResolveDynamicAnyArgs(Zone *zone, const Class &receiver_class, const String &function_name, bool allow_add)
Definition: resolver.cc:185
virtual CompileType ComputeType() const
Kind kind() const
Definition: il.h:11358
CompileType type() const
Definition: slot.h:538
CompileType * result_type() const
Definition: il.h:5652
const Function & function() const
Definition: il.h:5623
bool is_known_list_constructor() const
Definition: il.h:5661
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Value * value() const
Definition: il.h:5963
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
virtual Value * InputAt(intptr_t i) const
Definition: il.h:3959
intptr_t ArgumentCount() const
Definition: il.h:4586
Value * Receiver() const
Definition: il.h:4577
bool calls_initializer() const
Definition: il.h:6623
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
CompilerState & compiler_state()
Definition: thread.h:588
IsolateGroup * isolate_group() const
Definition: thread.h:541
static TypePtr IntType()
static TypePtr NullableIntType()
static TypePtr Double()
static TypePtr NullableDouble()
static TypePtr MintType()
static TypePtr NullType()
static TypePtr StringType()
static TypePtr BoolType()
static TypePtr ObjectType()
static TypePtr SmiType()
static TypePtr New(const Class &clazz, const TypeArguments &arguments, Nullability nullability=Nullability::kNonNullable, Heap::Space space=Heap::kOld)
virtual CompileType ComputeType() const
virtual CompileType ComputeType() const
Definition: il.h:75
bool BindsToConstant() const
Definition: il.cc:1183
void SetReachingType(CompileType *type)
const Object & BoundConstant() const
Definition: il.cc:1201
Definition * definition() const
Definition: il.h:103
CompileType * Type()
void RefineReachingType(CompileType *type)
intptr_t InputCount() const
Definition: il.h:2794
Value * InputAt(intptr_t i) const
Definition: il.h:2795
char * MakeCopyOfString(const char *str)
Definition: zone.cc:270
static intptr_t field_index_at_offset(intptr_t offset_in_bytes)
#define THR_Print(format,...)
Definition: log.h:20
#define UNIMPLEMENTED
#define ASSERT(E)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
GAsyncResult * result
uint32_t * target
constexpr bool FLAG_support_il_printer
Definition: flag_list.h:48
Dart_NativeFunction function
Definition: fuchsia.cc:51
#define SIMD_OP_LIST(M, BINARY_OP)
Definition: il.h:11249
size_t length
bool IsSmi(int64_t v)
Definition: runtime_api.cc:31
Definition: dart_vm.cc:33
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)
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
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)
def call(args)
Definition: dom.py:159
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
def array_type(data_type)
Definition: systemnative.py:28
#define Pd
Definition: globals.h:408
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741
static bool RequiresAllocation(Representation rep)
Definition: il.cc:470
static intptr_t BoxCid(Representation rep)
Definition: il.cc:493
intptr_t cid_start
Definition: il.h:220
bool IsIllegalRange() const
Definition: il.h:216
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
#define CASE(Arity, Mask, Name, Args, Result)