| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_type_propagator.h" | 5 #include "vm/flow_graph_type_propagator.h" |
| 6 | 6 |
| 7 #include "vm/cha.h" | 7 #include "vm/cha.h" |
| 8 #include "vm/bit_vector.h" | 8 #include "vm/bit_vector.h" |
| 9 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
| 10 #include "vm/regexp_assembler.h" | 10 #include "vm/regexp_assembler.h" |
| 11 #include "vm/timeline.h" | 11 #include "vm/timeline.h" |
| 12 | 12 |
| 13 namespace dart { | 13 namespace dart { |
| 14 | 14 |
| 15 DEFINE_FLAG(bool, trace_type_propagation, false, | 15 DEFINE_FLAG(bool, |
| 16 trace_type_propagation, |
| 17 false, |
| 16 "Trace flow graph type propagation"); | 18 "Trace flow graph type propagation"); |
| 17 | 19 |
| 18 DECLARE_FLAG(bool, propagate_types); | 20 DECLARE_FLAG(bool, propagate_types); |
| 19 | 21 |
| 20 | 22 |
| 21 void FlowGraphTypePropagator::Propagate(FlowGraph* flow_graph) { | 23 void FlowGraphTypePropagator::Propagate(FlowGraph* flow_graph) { |
| 22 #ifndef PRODUCT | 24 #ifndef PRODUCT |
| 23 Thread* thread = flow_graph->thread(); | 25 Thread* thread = flow_graph->thread(); |
| 24 TimelineStream* compiler_timeline = Timeline::GetCompilerStream(); | 26 TimelineStream* compiler_timeline = Timeline::GetCompilerStream(); |
| 25 TimelineDurationScope tds2(thread, | 27 TimelineDurationScope tds2(thread, compiler_timeline, |
| 26 compiler_timeline, | |
| 27 "FlowGraphTypePropagator"); | 28 "FlowGraphTypePropagator"); |
| 28 #endif // !PRODUCT | 29 #endif // !PRODUCT |
| 29 FlowGraphTypePropagator propagator(flow_graph); | 30 FlowGraphTypePropagator propagator(flow_graph); |
| 30 propagator.Propagate(); | 31 propagator.Propagate(); |
| 31 } | 32 } |
| 32 | 33 |
| 33 | 34 |
| 34 FlowGraphTypePropagator::FlowGraphTypePropagator(FlowGraph* flow_graph) | 35 FlowGraphTypePropagator::FlowGraphTypePropagator(FlowGraph* flow_graph) |
| 35 : FlowGraphVisitor(flow_graph->reverse_postorder()), | 36 : FlowGraphVisitor(flow_graph->reverse_postorder()), |
| 36 flow_graph_(flow_graph), | 37 flow_graph_(flow_graph), |
| 37 visited_blocks_(new(flow_graph->zone()) BitVector( | 38 visited_blocks_(new (flow_graph->zone()) |
| 38 flow_graph->zone(), flow_graph->reverse_postorder().length())), | 39 BitVector(flow_graph->zone(), |
| 40 flow_graph->reverse_postorder().length())), |
| 39 types_(flow_graph->current_ssa_temp_index()), | 41 types_(flow_graph->current_ssa_temp_index()), |
| 40 in_worklist_(new(flow_graph->zone()) BitVector( | 42 in_worklist_(new (flow_graph->zone()) |
| 41 flow_graph->zone(), flow_graph->current_ssa_temp_index())), | 43 BitVector(flow_graph->zone(), |
| 44 flow_graph->current_ssa_temp_index())), |
| 42 asserts_(NULL), | 45 asserts_(NULL), |
| 43 collected_asserts_(NULL) { | 46 collected_asserts_(NULL) { |
| 44 for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) { | 47 for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) { |
| 45 types_.Add(NULL); | 48 types_.Add(NULL); |
| 46 } | 49 } |
| 47 | 50 |
| 48 if (Isolate::Current()->type_checks()) { | 51 if (Isolate::Current()->type_checks()) { |
| 49 asserts_ = new ZoneGrowableArray<AssertAssignableInstr*>( | 52 asserts_ = new ZoneGrowableArray<AssertAssignableInstr*>( |
| 50 flow_graph->current_ssa_temp_index()); | 53 flow_graph->current_ssa_temp_index()); |
| 51 for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) { | 54 for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 73 for (intptr_t i = 0; i < worklist_.length(); i++) { | 76 for (intptr_t i = 0; i < worklist_.length(); i++) { |
| 74 ASSERT(worklist_[i]->IsPhi()); | 77 ASSERT(worklist_[i]->IsPhi()); |
| 75 *worklist_[i]->Type() = CompileType::None(); | 78 *worklist_[i]->Type() = CompileType::None(); |
| 76 } | 79 } |
| 77 | 80 |
| 78 // Iterate until a fixed point is reached, updating the types of | 81 // Iterate until a fixed point is reached, updating the types of |
| 79 // definitions. | 82 // definitions. |
| 80 while (!worklist_.is_empty()) { | 83 while (!worklist_.is_empty()) { |
| 81 Definition* def = RemoveLastFromWorklist(); | 84 Definition* def = RemoveLastFromWorklist(); |
| 82 if (FLAG_support_il_printer && FLAG_trace_type_propagation) { | 85 if (FLAG_support_il_printer && FLAG_trace_type_propagation) { |
| 83 THR_Print("recomputing type of v%" Pd ": %s\n", | 86 THR_Print("recomputing type of v%" Pd ": %s\n", def->ssa_temp_index(), |
| 84 def->ssa_temp_index(), | |
| 85 def->Type()->ToCString()); | 87 def->Type()->ToCString()); |
| 86 } | 88 } |
| 87 if (def->RecomputeType()) { | 89 if (def->RecomputeType()) { |
| 88 if (FLAG_support_il_printer && FLAG_trace_type_propagation) { | 90 if (FLAG_support_il_printer && FLAG_trace_type_propagation) { |
| 89 THR_Print(" ... new type %s\n", def->Type()->ToCString()); | 91 THR_Print(" ... new type %s\n", def->Type()->ToCString()); |
| 90 } | 92 } |
| 91 for (Value::Iterator it(def->input_use_list()); | 93 for (Value::Iterator it(def->input_use_list()); !it.Done(); |
| 92 !it.Done(); | |
| 93 it.Advance()) { | 94 it.Advance()) { |
| 94 Instruction* instr = it.Current()->instruction(); | 95 Instruction* instr = it.Current()->instruction(); |
| 95 | 96 |
| 96 Definition* use_defn = instr->AsDefinition(); | 97 Definition* use_defn = instr->AsDefinition(); |
| 97 if (use_defn != NULL) { | 98 if (use_defn != NULL) { |
| 98 AddToWorklist(use_defn); | 99 AddToWorklist(use_defn); |
| 99 } | 100 } |
| 100 | 101 |
| 101 // If the value flow into a branch recompute type constrained by the | 102 // If the value flow into a branch recompute type constrained by the |
| 102 // branch (if any). This ensures that correct non-nullable type will | 103 // branch (if any). This ensures that correct non-nullable type will |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 } | 212 } |
| 212 | 213 |
| 213 | 214 |
| 214 void FlowGraphTypePropagator::VisitValue(Value* value) { | 215 void FlowGraphTypePropagator::VisitValue(Value* value) { |
| 215 CompileType* type = TypeOf(value->definition()); | 216 CompileType* type = TypeOf(value->definition()); |
| 216 value->SetReachingType(type); | 217 value->SetReachingType(type); |
| 217 | 218 |
| 218 if (FLAG_support_il_printer && FLAG_trace_type_propagation) { | 219 if (FLAG_support_il_printer && FLAG_trace_type_propagation) { |
| 219 THR_Print("reaching type to %s for v%" Pd " is %s\n", | 220 THR_Print("reaching type to %s for v%" Pd " is %s\n", |
| 220 value->instruction()->ToCString(), | 221 value->instruction()->ToCString(), |
| 221 value->definition()->ssa_temp_index(), | 222 value->definition()->ssa_temp_index(), type->ToCString()); |
| 222 type->ToCString()); | |
| 223 } | 223 } |
| 224 } | 224 } |
| 225 | 225 |
| 226 | 226 |
| 227 void FlowGraphTypePropagator::VisitJoinEntry(JoinEntryInstr* join) { | 227 void FlowGraphTypePropagator::VisitJoinEntry(JoinEntryInstr* join) { |
| 228 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 228 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
| 229 worklist_.Add(it.Current()); | 229 worklist_.Add(it.Current()); |
| 230 } | 230 } |
| 231 } | 231 } |
| 232 | 232 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 257 | 257 |
| 258 | 258 |
| 259 void FlowGraphTypePropagator::VisitCheckClassId(CheckClassIdInstr* check) { | 259 void FlowGraphTypePropagator::VisitCheckClassId(CheckClassIdInstr* check) { |
| 260 // Can't propagate the type/cid because it may cause illegal code motion and | 260 // Can't propagate the type/cid because it may cause illegal code motion and |
| 261 // we don't track dependencies in all places via redefinitions. | 261 // we don't track dependencies in all places via redefinitions. |
| 262 } | 262 } |
| 263 | 263 |
| 264 | 264 |
| 265 void FlowGraphTypePropagator::VisitInstanceCall(InstanceCallInstr* instr) { | 265 void FlowGraphTypePropagator::VisitInstanceCall(InstanceCallInstr* instr) { |
| 266 if (instr->has_unique_selector()) { | 266 if (instr->has_unique_selector()) { |
| 267 SetCid(instr->ArgumentAt(0), | 267 SetCid(instr->ArgumentAt(0), instr->ic_data()->GetReceiverClassIdAt(0)); |
| 268 instr->ic_data()->GetReceiverClassIdAt(0)); | |
| 269 } | 268 } |
| 270 } | 269 } |
| 271 | 270 |
| 272 | 271 |
| 273 void FlowGraphTypePropagator::VisitPolymorphicInstanceCall( | 272 void FlowGraphTypePropagator::VisitPolymorphicInstanceCall( |
| 274 PolymorphicInstanceCallInstr* instr) { | 273 PolymorphicInstanceCallInstr* instr) { |
| 275 if (instr->instance_call()->has_unique_selector()) { | 274 if (instr->instance_call()->has_unique_selector()) { |
| 276 SetCid(instr->ArgumentAt(0), | 275 SetCid(instr->ArgumentAt(0), instr->ic_data().GetReceiverClassIdAt(0)); |
| 277 instr->ic_data().GetReceiverClassIdAt(0)); | |
| 278 } | 276 } |
| 279 } | 277 } |
| 280 | 278 |
| 281 | 279 |
| 282 void FlowGraphTypePropagator::VisitGuardFieldClass( | 280 void FlowGraphTypePropagator::VisitGuardFieldClass( |
| 283 GuardFieldClassInstr* guard) { | 281 GuardFieldClassInstr* guard) { |
| 284 const intptr_t cid = guard->field().guarded_cid(); | 282 const intptr_t cid = guard->field().guarded_cid(); |
| 285 if ((cid == kIllegalCid) || | 283 if ((cid == kIllegalCid) || (cid == kDynamicCid) || |
| 286 (cid == kDynamicCid) || | |
| 287 Field::IsExternalizableCid(cid)) { | 284 Field::IsExternalizableCid(cid)) { |
| 288 return; | 285 return; |
| 289 } | 286 } |
| 290 | 287 |
| 291 Definition* def = guard->value()->definition(); | 288 Definition* def = guard->value()->definition(); |
| 292 CompileType* current = TypeOf(def); | 289 CompileType* current = TypeOf(def); |
| 293 if (current->IsNone() || | 290 if (current->IsNone() || (current->ToCid() != cid) || |
| 294 (current->ToCid() != cid) || | |
| 295 (current->is_nullable() && !guard->field().is_nullable())) { | 291 (current->is_nullable() && !guard->field().is_nullable())) { |
| 296 const bool is_nullable = | 292 const bool is_nullable = |
| 297 guard->field().is_nullable() && current->is_nullable(); | 293 guard->field().is_nullable() && current->is_nullable(); |
| 298 SetTypeOf(def, ZoneCompileType::Wrap(CompileType(is_nullable, cid, NULL))); | 294 SetTypeOf(def, ZoneCompileType::Wrap(CompileType(is_nullable, cid, NULL))); |
| 299 } | 295 } |
| 300 } | 296 } |
| 301 | 297 |
| 302 | 298 |
| 303 void FlowGraphTypePropagator::VisitAssertAssignable( | 299 void FlowGraphTypePropagator::VisitAssertAssignable( |
| 304 AssertAssignableInstr* instr) { | 300 AssertAssignableInstr* instr) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 AssertAssignableInstr* assert = (*asserts_)[defn->ssa_temp_index()]; | 366 AssertAssignableInstr* assert = (*asserts_)[defn->ssa_temp_index()]; |
| 371 if ((assert == NULL) || (assert == kStrengthenedAssertMarker)) { | 367 if ((assert == NULL) || (assert == kStrengthenedAssertMarker)) { |
| 372 return; | 368 return; |
| 373 } | 369 } |
| 374 ASSERT(assert->env() != NULL); | 370 ASSERT(assert->env() != NULL); |
| 375 | 371 |
| 376 Instruction* check_clone = NULL; | 372 Instruction* check_clone = NULL; |
| 377 if (check->IsCheckSmi()) { | 373 if (check->IsCheckSmi()) { |
| 378 check_clone = | 374 check_clone = |
| 379 new CheckSmiInstr(assert->value()->Copy(zone()), | 375 new CheckSmiInstr(assert->value()->Copy(zone()), |
| 380 assert->env()->deopt_id(), | 376 assert->env()->deopt_id(), check->token_pos()); |
| 381 check->token_pos()); | |
| 382 check_clone->AsCheckSmi()->set_licm_hoisted( | 377 check_clone->AsCheckSmi()->set_licm_hoisted( |
| 383 check->AsCheckSmi()->licm_hoisted()); | 378 check->AsCheckSmi()->licm_hoisted()); |
| 384 } else { | 379 } else { |
| 385 ASSERT(check->IsCheckClass()); | 380 ASSERT(check->IsCheckClass()); |
| 386 check_clone = | 381 check_clone = new CheckClassInstr( |
| 387 new CheckClassInstr(assert->value()->Copy(zone()), | 382 assert->value()->Copy(zone()), assert->env()->deopt_id(), |
| 388 assert->env()->deopt_id(), | 383 check->AsCheckClass()->unary_checks(), check->token_pos()); |
| 389 check->AsCheckClass()->unary_checks(), | |
| 390 check->token_pos()); | |
| 391 check_clone->AsCheckClass()->set_licm_hoisted( | 384 check_clone->AsCheckClass()->set_licm_hoisted( |
| 392 check->AsCheckClass()->licm_hoisted()); | 385 check->AsCheckClass()->licm_hoisted()); |
| 393 } | 386 } |
| 394 ASSERT(check_clone != NULL); | 387 ASSERT(check_clone != NULL); |
| 395 ASSERT(assert->deopt_id() == assert->env()->deopt_id()); | 388 ASSERT(assert->deopt_id() == assert->env()->deopt_id()); |
| 396 check_clone->InsertBefore(assert); | 389 check_clone->InsertBefore(assert); |
| 397 assert->env()->DeepCopyTo(zone(), check_clone); | 390 assert->env()->DeepCopyTo(zone(), check_clone); |
| 398 | 391 |
| 399 (*asserts_)[defn->ssa_temp_index()] = kStrengthenedAssertMarker; | 392 (*asserts_)[defn->ssa_temp_index()] = kStrengthenedAssertMarker; |
| 400 } | 393 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 422 return; | 415 return; |
| 423 } | 416 } |
| 424 | 417 |
| 425 if (ToNullableCid() != other->ToNullableCid()) { | 418 if (ToNullableCid() != other->ToNullableCid()) { |
| 426 ASSERT(cid_ != kNullCid); | 419 ASSERT(cid_ != kNullCid); |
| 427 cid_ = kDynamicCid; | 420 cid_ = kDynamicCid; |
| 428 } | 421 } |
| 429 | 422 |
| 430 const AbstractType* compile_type = ToAbstractType(); | 423 const AbstractType* compile_type = ToAbstractType(); |
| 431 const AbstractType* other_compile_type = other->ToAbstractType(); | 424 const AbstractType* other_compile_type = other->ToAbstractType(); |
| 432 if (compile_type->IsMoreSpecificThan( | 425 if (compile_type->IsMoreSpecificThan(*other_compile_type, NULL, NULL, |
| 433 *other_compile_type, NULL, NULL, Heap::kOld)) { | 426 Heap::kOld)) { |
| 434 type_ = other_compile_type; | 427 type_ = other_compile_type; |
| 435 } else if (other_compile_type-> | 428 } else if (other_compile_type->IsMoreSpecificThan(*compile_type, NULL, NULL, |
| 436 IsMoreSpecificThan(*compile_type, NULL, NULL, Heap::kOld)) { | 429 Heap::kOld)) { |
| 437 // Nothing to do. | 430 // Nothing to do. |
| 438 } else { | 431 } else { |
| 439 // Can't unify. | 432 // Can't unify. |
| 440 type_ = &Object::dynamic_type(); | 433 type_ = &Object::dynamic_type(); |
| 441 } | 434 } |
| 442 } | 435 } |
| 443 | 436 |
| 444 | 437 |
| 445 static bool IsNullableCid(intptr_t cid) { | 438 static bool IsNullableCid(intptr_t cid) { |
| 446 ASSERT(cid != kIllegalCid); | 439 ASSERT(cid != kIllegalCid); |
| 447 return cid == kNullCid || cid == kDynamicCid; | 440 return cid == kNullCid || cid == kDynamicCid; |
| 448 } | 441 } |
| 449 | 442 |
| 450 | 443 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 // Don't infer a cid from an abstract type since there can be multiple | 514 // Don't infer a cid from an abstract type since there can be multiple |
| 522 // compatible classes with different cids. | 515 // compatible classes with different cids. |
| 523 if (!CHA::IsImplemented(type_class) && !CHA::HasSubclasses(type_class)) { | 516 if (!CHA::IsImplemented(type_class) && !CHA::HasSubclasses(type_class)) { |
| 524 if (type_class.IsPrivate()) { | 517 if (type_class.IsPrivate()) { |
| 525 // Type of a private class cannot change through later loaded libs. | 518 // Type of a private class cannot change through later loaded libs. |
| 526 cid_ = type_class.id(); | 519 cid_ = type_class.id(); |
| 527 } else if (FLAG_use_cha_deopt || | 520 } else if (FLAG_use_cha_deopt || |
| 528 thread->isolate()->all_classes_finalized()) { | 521 thread->isolate()->all_classes_finalized()) { |
| 529 if (FLAG_trace_cha) { | 522 if (FLAG_trace_cha) { |
| 530 THR_Print(" **(CHA) Compile type not subclassed: %s\n", | 523 THR_Print(" **(CHA) Compile type not subclassed: %s\n", |
| 531 type_class.ToCString()); | 524 type_class.ToCString()); |
| 532 } | 525 } |
| 533 if (FLAG_use_cha_deopt) { | 526 if (FLAG_use_cha_deopt) { |
| 534 cha->AddToGuardedClasses(type_class, /*subclass_count=*/0); | 527 cha->AddToGuardedClasses(type_class, /*subclass_count=*/0); |
| 535 } | 528 } |
| 536 cid_ = type_class.id(); | 529 cid_ = type_class.id(); |
| 537 } else { | 530 } else { |
| 538 cid_ = kDynamicCid; | 531 cid_ = kDynamicCid; |
| 539 } | 532 } |
| 540 } else { | 533 } else { |
| 541 cid_ = kDynamicCid; | 534 cid_ = kDynamicCid; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 | 610 |
| 618 if (compile_type.IsMalformedOrMalbounded()) { | 611 if (compile_type.IsMalformedOrMalbounded()) { |
| 619 return false; | 612 return false; |
| 620 } | 613 } |
| 621 | 614 |
| 622 // The Null type is only a subtype of Object and of dynamic. | 615 // The Null type is only a subtype of Object and of dynamic. |
| 623 // Functions that do not explicitly return a value, implicitly return null, | 616 // Functions that do not explicitly return a value, implicitly return null, |
| 624 // except generative constructors, which return the object being constructed. | 617 // except generative constructors, which return the object being constructed. |
| 625 // It is therefore acceptable for void functions to return null. | 618 // It is therefore acceptable for void functions to return null. |
| 626 if (compile_type.IsNullType()) { | 619 if (compile_type.IsNullType()) { |
| 627 *is_instance = is_nullable || | 620 *is_instance = is_nullable || type.IsObjectType() || type.IsDynamicType() || |
| 628 type.IsObjectType() || type.IsDynamicType() || type.IsVoidType(); | 621 type.IsVoidType(); |
| 629 return true; | 622 return true; |
| 630 } | 623 } |
| 631 | 624 |
| 632 // A non-null value is not an instance of void. | 625 // A non-null value is not an instance of void. |
| 633 if (type.IsVoidType()) { | 626 if (type.IsVoidType()) { |
| 634 *is_instance = IsNull(); | 627 *is_instance = IsNull(); |
| 635 return HasDecidableNullability(); | 628 return HasDecidableNullability(); |
| 636 } | 629 } |
| 637 | 630 |
| 638 // If the value can be null then we can't eliminate the | 631 // If the value can be null then we can't eliminate the |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 // for the first time. | 666 // for the first time. |
| 674 return CompileType::None(); | 667 return CompileType::None(); |
| 675 } | 668 } |
| 676 | 669 |
| 677 | 670 |
| 678 bool PhiInstr::RecomputeType() { | 671 bool PhiInstr::RecomputeType() { |
| 679 CompileType result = CompileType::None(); | 672 CompileType result = CompileType::None(); |
| 680 for (intptr_t i = 0; i < InputCount(); i++) { | 673 for (intptr_t i = 0; i < InputCount(); i++) { |
| 681 if (FLAG_support_il_printer && FLAG_trace_type_propagation) { | 674 if (FLAG_support_il_printer && FLAG_trace_type_propagation) { |
| 682 THR_Print(" phi %" Pd " input %" Pd ": v%" Pd " has reaching type %s\n", | 675 THR_Print(" phi %" Pd " input %" Pd ": v%" Pd " has reaching type %s\n", |
| 683 ssa_temp_index(), | 676 ssa_temp_index(), i, InputAt(i)->definition()->ssa_temp_index(), |
| 684 i, | |
| 685 InputAt(i)->definition()->ssa_temp_index(), | |
| 686 InputAt(i)->Type()->ToCString()); | 677 InputAt(i)->Type()->ToCString()); |
| 687 } | 678 } |
| 688 result.Union(InputAt(i)->Type()); | 679 result.Union(InputAt(i)->Type()); |
| 689 } | 680 } |
| 690 | 681 |
| 691 if (result.IsNone()) { | 682 if (result.IsNone()) { |
| 692 ASSERT(Type()->IsNone()); | 683 ASSERT(Type()->IsNone()); |
| 693 return false; | 684 return false; |
| 694 } | 685 } |
| 695 | 686 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 // In irregexp functions, types of input parameters are known and immutable. | 728 // In irregexp functions, types of input parameters are known and immutable. |
| 738 // Set parameter types here in order to prevent unnecessary CheckClassInstr | 729 // Set parameter types here in order to prevent unnecessary CheckClassInstr |
| 739 // from being generated. | 730 // from being generated. |
| 740 switch (index()) { | 731 switch (index()) { |
| 741 case RegExpMacroAssembler::kParamRegExpIndex: | 732 case RegExpMacroAssembler::kParamRegExpIndex: |
| 742 return CompileType::FromCid(kRegExpCid); | 733 return CompileType::FromCid(kRegExpCid); |
| 743 case RegExpMacroAssembler::kParamStringIndex: | 734 case RegExpMacroAssembler::kParamStringIndex: |
| 744 return CompileType::FromCid(function.string_specialization_cid()); | 735 return CompileType::FromCid(function.string_specialization_cid()); |
| 745 case RegExpMacroAssembler::kParamStartOffsetIndex: | 736 case RegExpMacroAssembler::kParamStartOffsetIndex: |
| 746 return CompileType::FromCid(kSmiCid); | 737 return CompileType::FromCid(kSmiCid); |
| 747 default: UNREACHABLE(); | 738 default: |
| 739 UNREACHABLE(); |
| 748 } | 740 } |
| 749 UNREACHABLE(); | 741 UNREACHABLE(); |
| 750 return CompileType::Dynamic(); | 742 return CompileType::Dynamic(); |
| 751 } | 743 } |
| 752 | 744 |
| 753 // Parameter is the receiver. | 745 // Parameter is the receiver. |
| 754 if ((index() == 0) && | 746 if ((index() == 0) && |
| 755 (function.IsDynamicFunction() || function.IsGenerativeConstructor())) { | 747 (function.IsDynamicFunction() || function.IsGenerativeConstructor())) { |
| 756 LocalScope* scope = graph_entry->parsed_function().node_sequence()->scope(); | 748 LocalScope* scope = graph_entry->parsed_function().node_sequence()->scope(); |
| 757 const AbstractType& type = scope->VariableAt(index())->type(); | 749 const AbstractType& type = scope->VariableAt(index())->type(); |
| 758 if (type.IsObjectType() || type.IsNullType()) { | 750 if (type.IsObjectType() || type.IsNullType()) { |
| 759 // Receiver can be null. | 751 // Receiver can be null. |
| 760 return CompileType::FromAbstractType(type, CompileType::kNullable); | 752 return CompileType::FromAbstractType(type, CompileType::kNullable); |
| 761 } | 753 } |
| 762 | 754 |
| 763 // Receiver can't be null but can be an instance of a subclass. | 755 // Receiver can't be null but can be an instance of a subclass. |
| 764 intptr_t cid = kDynamicCid; | 756 intptr_t cid = kDynamicCid; |
| 765 | 757 |
| 766 if (type.HasResolvedTypeClass()) { | 758 if (type.HasResolvedTypeClass()) { |
| 767 Thread* thread = Thread::Current(); | 759 Thread* thread = Thread::Current(); |
| 768 const Class& type_class = Class::Handle(type.type_class()); | 760 const Class& type_class = Class::Handle(type.type_class()); |
| 769 if (!CHA::HasSubclasses(type_class)) { | 761 if (!CHA::HasSubclasses(type_class)) { |
| 770 if (type_class.IsPrivate()) { | 762 if (type_class.IsPrivate()) { |
| 771 // Private classes can never be subclassed by later loaded libs. | 763 // Private classes can never be subclassed by later loaded libs. |
| 772 cid = type_class.id(); | 764 cid = type_class.id(); |
| 773 } else { | 765 } else { |
| 774 if (FLAG_use_cha_deopt || | 766 if (FLAG_use_cha_deopt || |
| 775 thread->isolate()->all_classes_finalized()) { | 767 thread->isolate()->all_classes_finalized()) { |
| 776 if (FLAG_trace_cha) { | 768 if (FLAG_trace_cha) { |
| 777 THR_Print(" **(CHA) Computing exact type of receiver, " | 769 THR_Print( |
| 770 " **(CHA) Computing exact type of receiver, " |
| 778 "no subclasses: %s\n", | 771 "no subclasses: %s\n", |
| 779 type_class.ToCString()); | 772 type_class.ToCString()); |
| 780 } | 773 } |
| 781 if (FLAG_use_cha_deopt) { | 774 if (FLAG_use_cha_deopt) { |
| 782 thread->cha()->AddToGuardedClasses( | 775 thread->cha()->AddToGuardedClasses(type_class, |
| 783 type_class, /*subclass_count=*/0); | 776 /*subclass_count=*/0); |
| 784 } | 777 } |
| 785 cid = type_class.id(); | 778 cid = type_class.id(); |
| 786 } | 779 } |
| 787 } | 780 } |
| 788 } | 781 } |
| 789 } | 782 } |
| 790 | 783 |
| 791 return CompileType(CompileType::kNonNullable, cid, &type); | 784 return CompileType(CompileType::kNonNullable, cid, &type); |
| 792 } | 785 } |
| 793 | 786 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 804 if (value().IsNull()) { | 797 if (value().IsNull()) { |
| 805 return CompileType::Null(); | 798 return CompileType::Null(); |
| 806 } | 799 } |
| 807 | 800 |
| 808 intptr_t cid = value().GetClassId(); | 801 intptr_t cid = value().GetClassId(); |
| 809 if (Field::IsExternalizableCid(cid)) { | 802 if (Field::IsExternalizableCid(cid)) { |
| 810 cid = kDynamicCid; | 803 cid = kDynamicCid; |
| 811 } | 804 } |
| 812 | 805 |
| 813 if (value().IsInstance()) { | 806 if (value().IsInstance()) { |
| 814 return CompileType::Create(cid, | 807 return CompileType::Create( |
| 815 AbstractType::ZoneHandle(Instance::Cast(value()).GetType())); | 808 cid, AbstractType::ZoneHandle(Instance::Cast(value()).GetType())); |
| 816 } else { | 809 } else { |
| 817 // Type info for non-instance objects. | 810 // Type info for non-instance objects. |
| 818 return CompileType::FromCid(cid); | 811 return CompileType::FromCid(cid); |
| 819 } | 812 } |
| 820 } | 813 } |
| 821 | 814 |
| 822 | 815 |
| 823 CompileType AssertAssignableInstr::ComputeType() const { | 816 CompileType AssertAssignableInstr::ComputeType() const { |
| 824 CompileType* value_type = value()->Type(); | 817 CompileType* value_type = value()->Type(); |
| 825 | 818 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 877 } | 870 } |
| 878 | 871 |
| 879 | 872 |
| 880 CompileType RelationalOpInstr::ComputeType() const { | 873 CompileType RelationalOpInstr::ComputeType() const { |
| 881 // Used for numeric comparisons only. | 874 // Used for numeric comparisons only. |
| 882 return CompileType::Bool(); | 875 return CompileType::Bool(); |
| 883 } | 876 } |
| 884 | 877 |
| 885 | 878 |
| 886 CompileType CurrentContextInstr::ComputeType() const { | 879 CompileType CurrentContextInstr::ComputeType() const { |
| 887 return CompileType(CompileType::kNonNullable, | 880 return CompileType(CompileType::kNonNullable, kContextCid, |
| 888 kContextCid, | |
| 889 &Object::dynamic_type()); | 881 &Object::dynamic_type()); |
| 890 } | 882 } |
| 891 | 883 |
| 892 | 884 |
| 893 CompileType CloneContextInstr::ComputeType() const { | 885 CompileType CloneContextInstr::ComputeType() const { |
| 894 return CompileType(CompileType::kNonNullable, | 886 return CompileType(CompileType::kNonNullable, kContextCid, |
| 895 kContextCid, | |
| 896 &Object::dynamic_type()); | 887 &Object::dynamic_type()); |
| 897 } | 888 } |
| 898 | 889 |
| 899 | 890 |
| 900 CompileType AllocateContextInstr::ComputeType() const { | 891 CompileType AllocateContextInstr::ComputeType() const { |
| 901 return CompileType(CompileType::kNonNullable, | 892 return CompileType(CompileType::kNonNullable, kContextCid, |
| 902 kContextCid, | |
| 903 &Object::dynamic_type()); | 893 &Object::dynamic_type()); |
| 904 } | 894 } |
| 905 | 895 |
| 906 | 896 |
| 907 CompileType AllocateUninitializedContextInstr::ComputeType() const { | 897 CompileType AllocateUninitializedContextInstr::ComputeType() const { |
| 908 return CompileType(CompileType::kNonNullable, | 898 return CompileType(CompileType::kNonNullable, kContextCid, |
| 909 kContextCid, | |
| 910 &Object::dynamic_type()); | 899 &Object::dynamic_type()); |
| 911 } | 900 } |
| 912 | 901 |
| 913 | 902 |
| 914 CompileType PolymorphicInstanceCallInstr::ComputeType() const { | 903 CompileType PolymorphicInstanceCallInstr::ComputeType() const { |
| 915 if (!HasSingleRecognizedTarget()) return CompileType::Dynamic(); | 904 if (!HasSingleRecognizedTarget()) return CompileType::Dynamic(); |
| 916 const Function& target = Function::Handle(ic_data().GetTargetAt(0)); | 905 const Function& target = Function::Handle(ic_data().GetTargetAt(0)); |
| 917 return (target.recognized_kind() != MethodRecognizer::kUnknown) | 906 return (target.recognized_kind() != MethodRecognizer::kUnknown) |
| 918 ? CompileType::FromCid(MethodRecognizer::ResultCid(target)) | 907 ? CompileType::FromCid(MethodRecognizer::ResultCid(target)) |
| 919 : CompileType::Dynamic(); | 908 : CompileType::Dynamic(); |
| 920 } | 909 } |
| 921 | 910 |
| 922 | 911 |
| 923 CompileType StaticCallInstr::ComputeType() const { | 912 CompileType StaticCallInstr::ComputeType() const { |
| 924 if (result_cid_ != kDynamicCid) { | 913 if (result_cid_ != kDynamicCid) { |
| 925 return CompileType::FromCid(result_cid_); | 914 return CompileType::FromCid(result_cid_); |
| 926 } | 915 } |
| 927 | 916 |
| 928 if (Isolate::Current()->type_checks()) { | 917 if (Isolate::Current()->type_checks()) { |
| 929 // Void functions are known to return null, which is checked at the return | 918 // Void functions are known to return null, which is checked at the return |
| 930 // from the function. | 919 // from the function. |
| 931 const AbstractType& result_type = | 920 const AbstractType& result_type = |
| 932 AbstractType::ZoneHandle(function().result_type()); | 921 AbstractType::ZoneHandle(function().result_type()); |
| 933 return CompileType::FromAbstractType(result_type.IsVoidType() | 922 return CompileType::FromAbstractType( |
| 934 ? AbstractType::ZoneHandle(Type::NullType()) | 923 result_type.IsVoidType() ? AbstractType::ZoneHandle(Type::NullType()) |
| 935 : result_type); | 924 : result_type); |
| 936 } | 925 } |
| 937 | 926 |
| 938 return CompileType::Dynamic(); | 927 return CompileType::Dynamic(); |
| 939 } | 928 } |
| 940 | 929 |
| 941 | 930 |
| 942 CompileType LoadLocalInstr::ComputeType() const { | 931 CompileType LoadLocalInstr::ComputeType() const { |
| 943 if (Isolate::Current()->type_checks()) { | 932 if (Isolate::Current()->type_checks()) { |
| 944 return CompileType::FromAbstractType(local().type()); | 933 return CompileType::FromAbstractType(local().type()); |
| 945 } | 934 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 957 return *value()->Type(); | 946 return *value()->Type(); |
| 958 } | 947 } |
| 959 | 948 |
| 960 | 949 |
| 961 CompileType OneByteStringFromCharCodeInstr::ComputeType() const { | 950 CompileType OneByteStringFromCharCodeInstr::ComputeType() const { |
| 962 return CompileType::FromCid(kOneByteStringCid); | 951 return CompileType::FromCid(kOneByteStringCid); |
| 963 } | 952 } |
| 964 | 953 |
| 965 | 954 |
| 966 CompileType StringToCharCodeInstr::ComputeType() const { | 955 CompileType StringToCharCodeInstr::ComputeType() const { |
| 967 return CompileType::FromCid(kSmiCid); | 956 return CompileType::FromCid(kSmiCid); |
| 968 } | 957 } |
| 969 | 958 |
| 970 | 959 |
| 971 CompileType StringInterpolateInstr::ComputeType() const { | 960 CompileType StringInterpolateInstr::ComputeType() const { |
| 972 // TODO(srdjan): Do better and determine if it is a one or two byte string. | 961 // TODO(srdjan): Do better and determine if it is a one or two byte string. |
| 973 return CompileType::String(); | 962 return CompileType::String(); |
| 974 } | 963 } |
| 975 | 964 |
| 976 | 965 |
| 977 CompileType LoadStaticFieldInstr::ComputeType() const { | 966 CompileType LoadStaticFieldInstr::ComputeType() const { |
| 978 bool is_nullable = CompileType::kNullable; | 967 bool is_nullable = CompileType::kNullable; |
| 979 intptr_t cid = kDynamicCid; | 968 intptr_t cid = kDynamicCid; |
| 980 AbstractType* abstract_type = NULL; | 969 AbstractType* abstract_type = NULL; |
| 981 const Field& field = this->StaticField(); | 970 const Field& field = this->StaticField(); |
| 982 if (Isolate::Current()->type_checks()) { | 971 if (Isolate::Current()->type_checks()) { |
| 983 cid = kIllegalCid; | 972 cid = kIllegalCid; |
| 984 abstract_type = &AbstractType::ZoneHandle(field.type()); | 973 abstract_type = &AbstractType::ZoneHandle(field.type()); |
| 985 } | 974 } |
| 986 ASSERT(field.is_static()); | 975 ASSERT(field.is_static()); |
| 987 if (field.is_final()) { | 976 if (field.is_final()) { |
| 988 if (!FLAG_fields_may_be_reset) { | 977 if (!FLAG_fields_may_be_reset) { |
| 989 const Instance& obj = Instance::Handle(field.StaticValue()); | 978 const Instance& obj = Instance::Handle(field.StaticValue()); |
| 990 if ((obj.raw() != Object::sentinel().raw()) && | 979 if ((obj.raw() != Object::sentinel().raw()) && |
| 991 (obj.raw() != Object::transition_sentinel().raw()) && | 980 (obj.raw() != Object::transition_sentinel().raw()) && !obj.IsNull()) { |
| 992 !obj.IsNull()) { | |
| 993 is_nullable = CompileType::kNonNullable; | 981 is_nullable = CompileType::kNonNullable; |
| 994 cid = obj.GetClassId(); | 982 cid = obj.GetClassId(); |
| 995 } | 983 } |
| 996 } else if (field.guarded_cid() != kIllegalCid) { | 984 } else if (field.guarded_cid() != kIllegalCid) { |
| 997 cid = field.guarded_cid(); | 985 cid = field.guarded_cid(); |
| 998 if (!IsNullableCid(cid)) is_nullable = CompileType::kNonNullable; | 986 if (!IsNullableCid(cid)) is_nullable = CompileType::kNonNullable; |
| 999 } | 987 } |
| 1000 } | 988 } |
| 1001 if (Field::IsExternalizableCid(cid)) { | 989 if (Field::IsExternalizableCid(cid)) { |
| 1002 cid = kDynamicCid; | 990 cid = kDynamicCid; |
| 1003 } | 991 } |
| 1004 return CompileType(is_nullable, cid, abstract_type); | 992 return CompileType(is_nullable, cid, abstract_type); |
| 1005 } | 993 } |
| 1006 | 994 |
| 1007 | 995 |
| 1008 CompileType CreateArrayInstr::ComputeType() const { | 996 CompileType CreateArrayInstr::ComputeType() const { |
| 1009 // TODO(fschneider): Add abstract type and type arguments to the compile type. | 997 // TODO(fschneider): Add abstract type and type arguments to the compile type. |
| 1010 return CompileType::FromCid(kArrayCid); | 998 return CompileType::FromCid(kArrayCid); |
| 1011 } | 999 } |
| 1012 | 1000 |
| 1013 | 1001 |
| 1014 CompileType AllocateObjectInstr::ComputeType() const { | 1002 CompileType AllocateObjectInstr::ComputeType() const { |
| 1015 if (!closure_function().IsNull()) { | 1003 if (!closure_function().IsNull()) { |
| 1016 ASSERT(cls().id() == kClosureCid); | 1004 ASSERT(cls().id() == kClosureCid); |
| 1017 return CompileType(CompileType::kNonNullable, | 1005 return CompileType(CompileType::kNonNullable, kClosureCid, |
| 1018 kClosureCid, | |
| 1019 &Type::ZoneHandle(closure_function().SignatureType())); | 1006 &Type::ZoneHandle(closure_function().SignatureType())); |
| 1020 } | 1007 } |
| 1021 // TODO(vegorov): Incorporate type arguments into the returned type. | 1008 // TODO(vegorov): Incorporate type arguments into the returned type. |
| 1022 return CompileType::FromCid(cls().id()); | 1009 return CompileType::FromCid(cls().id()); |
| 1023 } | 1010 } |
| 1024 | 1011 |
| 1025 | 1012 |
| 1026 CompileType LoadUntaggedInstr::ComputeType() const { | 1013 CompileType LoadUntaggedInstr::ComputeType() const { |
| 1027 return CompileType::Dynamic(); | 1014 return CompileType::Dynamic(); |
| 1028 } | 1015 } |
| 1029 | 1016 |
| 1030 | 1017 |
| 1031 CompileType LoadClassIdInstr::ComputeType() const { | 1018 CompileType LoadClassIdInstr::ComputeType() const { |
| 1032 return CompileType::FromCid(kSmiCid); | 1019 return CompileType::FromCid(kSmiCid); |
| 1033 } | 1020 } |
| 1034 | 1021 |
| 1035 | 1022 |
| 1036 CompileType LoadFieldInstr::ComputeType() const { | 1023 CompileType LoadFieldInstr::ComputeType() const { |
| 1037 // Type may be null if the field is a VM field, e.g. context parent. | 1024 // Type may be null if the field is a VM field, e.g. context parent. |
| 1038 // Keep it as null for debug purposes and do not return dynamic in production | 1025 // Keep it as null for debug purposes and do not return dynamic in production |
| 1039 // mode, since misuse of the type would remain undetected. | 1026 // mode, since misuse of the type would remain undetected. |
| 1040 if (type().IsNull()) { | 1027 if (type().IsNull()) { |
| 1041 return CompileType::Dynamic(); | 1028 return CompileType::Dynamic(); |
| 1042 } | 1029 } |
| 1043 | 1030 |
| 1044 const AbstractType* abstract_type = NULL; | 1031 const AbstractType* abstract_type = NULL; |
| 1045 if (Isolate::Current()->type_checks() && | 1032 if (Isolate::Current()->type_checks() && |
| 1046 (type().IsFunctionType() || | 1033 (type().IsFunctionType() || |
| 1047 (type().HasResolvedTypeClass() && | 1034 (type().HasResolvedTypeClass() && |
| 1048 !Field::IsExternalizableCid(Class::Handle(type().type_class()).id())))) { | 1035 !Field::IsExternalizableCid( |
| 1036 Class::Handle(type().type_class()).id())))) { |
| 1049 abstract_type = &type(); | 1037 abstract_type = &type(); |
| 1050 } | 1038 } |
| 1051 | 1039 |
| 1052 if ((field_ != NULL) && (field_->guarded_cid() != kIllegalCid)) { | 1040 if ((field_ != NULL) && (field_->guarded_cid() != kIllegalCid)) { |
| 1053 bool is_nullable = field_->is_nullable(); | 1041 bool is_nullable = field_->is_nullable(); |
| 1054 intptr_t field_cid = field_->guarded_cid(); | 1042 intptr_t field_cid = field_->guarded_cid(); |
| 1055 if (Field::IsExternalizableCid(field_cid)) { | 1043 if (Field::IsExternalizableCid(field_cid)) { |
| 1056 // We cannot assume that the type of the value in the field has not | 1044 // We cannot assume that the type of the value in the field has not |
| 1057 // changed on the fly. | 1045 // changed on the fly. |
| 1058 field_cid = kDynamicCid; | 1046 field_cid = kDynamicCid; |
| 1059 } | 1047 } |
| 1060 return CompileType(is_nullable, field_cid, abstract_type); | 1048 return CompileType(is_nullable, field_cid, abstract_type); |
| 1061 } | 1049 } |
| 1062 | 1050 |
| 1063 ASSERT(!Field::IsExternalizableCid(result_cid_)); | 1051 ASSERT(!Field::IsExternalizableCid(result_cid_)); |
| 1064 return CompileType::Create(result_cid_, *abstract_type); | 1052 return CompileType::Create(result_cid_, *abstract_type); |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1433 CompileType MergedMathInstr::ComputeType() const { | 1421 CompileType MergedMathInstr::ComputeType() const { |
| 1434 return CompileType::Dynamic(); | 1422 return CompileType::Dynamic(); |
| 1435 } | 1423 } |
| 1436 | 1424 |
| 1437 | 1425 |
| 1438 CompileType ExtractNthOutputInstr::ComputeType() const { | 1426 CompileType ExtractNthOutputInstr::ComputeType() const { |
| 1439 return CompileType::FromCid(definition_cid_); | 1427 return CompileType::FromCid(definition_cid_); |
| 1440 } | 1428 } |
| 1441 | 1429 |
| 1442 } // namespace dart | 1430 } // namespace dart |
| OLD | NEW |