Chromium Code Reviews| 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_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 3655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3666 intptr_t view_cid) { | 3666 intptr_t view_cid) { |
| 3667 bool simd_view = (view_cid == kTypedDataFloat32x4ArrayCid) || | 3667 bool simd_view = (view_cid == kTypedDataFloat32x4ArrayCid) || |
| 3668 (view_cid == kTypedDataInt32x4ArrayCid); | 3668 (view_cid == kTypedDataInt32x4ArrayCid); |
| 3669 if (simd_view && !ShouldInlineSimd()) { | 3669 if (simd_view && !ShouldInlineSimd()) { |
| 3670 return false; | 3670 return false; |
| 3671 } | 3671 } |
| 3672 return TryReplaceInstanceCallWithInline(call); | 3672 return TryReplaceInstanceCallWithInline(call); |
| 3673 } | 3673 } |
| 3674 | 3674 |
| 3675 | 3675 |
| 3676 // Returns a Boolean constant if all classes in ic_data yield the same type-test | 3676 // If type tests specified by 'ic_data' do not depend on type arguments, |
| 3677 // result and the type tests do not depend on type arguments. Otherwise return | 3677 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
| 3678 // Bool::null(). | 3678 // If all tests yield the same result, return it otherwise return Bool::null. |
| 3679 RawBool* FlowGraphOptimizer::InstanceOfAsBool(const ICData& ic_data, | 3679 // If no mapping is possible, 'results' is empty. |
| 3680 const AbstractType& type) const { | 3680 // An instance-of test returning all same results can be converted to a class |
| 3681 // check. | |
| 3682 RawBool* FlowGraphOptimizer::InstanceOfAsBool( | |
| 3683 const ICData& ic_data, | |
| 3684 const AbstractType& type, | |
| 3685 ZoneGrowableArray<intptr_t>* results) const { | |
| 3686 results->Clear(); | |
|
Florian Schneider
2014/04/28 15:41:01
Is results reused somewhere?
Maybe just ASSERT(re
srdjan
2014/04/28 15:44:58
Done.
| |
| 3681 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. | 3687 ASSERT(ic_data.num_args_tested() == 1); // Unary checks only. |
| 3682 if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) { | 3688 if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) { |
| 3683 return Bool::null(); | 3689 return Bool::null(); |
| 3684 } | 3690 } |
| 3685 const Class& type_class = Class::Handle(type.type_class()); | 3691 const Class& type_class = Class::Handle(type.type_class()); |
| 3686 const intptr_t num_type_args = type_class.NumTypeArguments(); | 3692 const intptr_t num_type_args = type_class.NumTypeArguments(); |
| 3687 if (num_type_args > 0) { | 3693 if (num_type_args > 0) { |
| 3688 // Only raw types can be directly compared, thus disregarding type | 3694 // Only raw types can be directly compared, thus disregarding type |
| 3689 // arguments. | 3695 // arguments. |
| 3690 const intptr_t num_type_params = type_class.NumTypeParameters(); | 3696 const intptr_t num_type_params = type_class.NumTypeParameters(); |
| 3691 const intptr_t from_index = num_type_args - num_type_params; | 3697 const intptr_t from_index = num_type_args - num_type_params; |
| 3692 const TypeArguments& type_arguments = | 3698 const TypeArguments& type_arguments = |
| 3693 TypeArguments::Handle(type.arguments()); | 3699 TypeArguments::Handle(type.arguments()); |
| 3694 const bool is_raw_type = type_arguments.IsNull() || | 3700 const bool is_raw_type = type_arguments.IsNull() || |
| 3695 type_arguments.IsRaw(from_index, num_type_params); | 3701 type_arguments.IsRaw(from_index, num_type_params); |
| 3696 if (!is_raw_type) { | 3702 if (!is_raw_type) { |
| 3697 // Unknown result. | 3703 // Unknown result. |
| 3698 return Bool::null(); | 3704 return Bool::null(); |
| 3699 } | 3705 } |
| 3700 } | 3706 } |
| 3707 | |
| 3701 const ClassTable& class_table = *Isolate::Current()->class_table(); | 3708 const ClassTable& class_table = *Isolate::Current()->class_table(); |
| 3702 Bool& prev = Bool::Handle(); | 3709 Bool& prev = Bool::Handle(); |
| 3703 Class& cls = Class::Handle(); | 3710 Class& cls = Class::Handle(); |
| 3711 | |
| 3712 bool results_differ = false; | |
| 3704 for (int i = 0; i < ic_data.NumberOfChecks(); i++) { | 3713 for (int i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 3705 cls = class_table.At(ic_data.GetReceiverClassIdAt(i)); | 3714 cls = class_table.At(ic_data.GetReceiverClassIdAt(i)); |
| 3706 if (cls.NumTypeArguments() > 0) return Bool::null(); | 3715 if (cls.NumTypeArguments() > 0) { |
| 3716 return Bool::null(); | |
| 3717 } | |
| 3707 const bool is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(), | 3718 const bool is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(), |
| 3708 type_class, | 3719 type_class, |
| 3709 TypeArguments::Handle(), | 3720 TypeArguments::Handle(), |
| 3710 NULL); | 3721 NULL); |
| 3722 results->Add(cls.id()); | |
| 3723 results->Add(is_subtype); | |
| 3711 if (prev.IsNull()) { | 3724 if (prev.IsNull()) { |
| 3712 prev = Bool::Get(is_subtype).raw(); | 3725 prev = Bool::Get(is_subtype).raw(); |
| 3713 } else { | 3726 } else { |
| 3714 if (is_subtype != prev.value()) return Bool::null(); | 3727 if (is_subtype != prev.value()) { |
| 3728 results_differ = true; | |
| 3729 } | |
| 3715 } | 3730 } |
| 3716 } | 3731 } |
| 3717 return prev.raw(); | 3732 return results_differ ? Bool::null() : prev.raw(); |
| 3718 } | 3733 } |
| 3719 | 3734 |
| 3720 | 3735 |
| 3721 static Definition* OriginalDefinition(Definition* defn) { | 3736 static Definition* OriginalDefinition(Definition* defn) { |
| 3722 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { | 3737 while (defn->IsRedefinition() || defn->IsAssertAssignable()) { |
| 3723 if (defn->IsRedefinition()) { | 3738 if (defn->IsRedefinition()) { |
| 3724 defn = defn->AsRedefinition()->value()->definition(); | 3739 defn = defn->AsRedefinition()->value()->definition(); |
| 3725 } else { | 3740 } else { |
| 3726 defn = defn->AsAssertAssignable()->value()->definition(); | 3741 defn = defn->AsAssertAssignable()->value()->definition(); |
| 3727 } | 3742 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 3752 const TypeArguments& type_arguments = | 3767 const TypeArguments& type_arguments = |
| 3753 TypeArguments::Handle(type.arguments()); | 3768 TypeArguments::Handle(type.arguments()); |
| 3754 const bool is_raw_type = type_arguments.IsNull() || | 3769 const bool is_raw_type = type_arguments.IsNull() || |
| 3755 type_arguments.IsRaw(from_index, num_type_params); | 3770 type_arguments.IsRaw(from_index, num_type_params); |
| 3756 return is_raw_type; | 3771 return is_raw_type; |
| 3757 } | 3772 } |
| 3758 return true; | 3773 return true; |
| 3759 } | 3774 } |
| 3760 | 3775 |
| 3761 | 3776 |
| 3777 static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results, | |
| 3778 intptr_t test_cid) { | |
| 3779 for (intptr_t i = 0; i < results.length(); i += 2) { | |
| 3780 if (results[i] == test_cid) return true; | |
| 3781 } | |
| 3782 return false; | |
| 3783 } | |
| 3784 | |
| 3785 | |
| 3786 static void TryAddTest(ZoneGrowableArray<intptr_t>* results, | |
| 3787 intptr_t test_cid, | |
| 3788 bool result) { | |
| 3789 if (!CidTestResultsContains(*results, test_cid)) { | |
| 3790 results->Add(test_cid); | |
| 3791 results->Add(result); | |
| 3792 } | |
| 3793 } | |
| 3794 | |
| 3795 | |
| 3796 // Tries to add cid tests to 'results' so that no deoptimization is | |
| 3797 // necessary. | |
| 3798 // TODO(srdjan): Do also for other than 'int' type. | |
| 3799 static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results, | |
| 3800 const AbstractType& type) { | |
| 3801 ASSERT(results->length() >= 2); // At least on eentry. | |
| 3802 const ClassTable& class_table = *Isolate::Current()->class_table(); | |
| 3803 if ((*results)[0] != kSmiCid) { | |
| 3804 const Class& cls = Class::Handle(class_table.At(kSmiCid)); | |
| 3805 const Class& type_class = Class::Handle(type.type_class()); | |
| 3806 const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(), | |
| 3807 type_class, | |
| 3808 TypeArguments::Handle(), | |
| 3809 NULL); | |
| 3810 results->Add((*results)[results->length() - 2]); | |
| 3811 results->Add((*results)[results->length() - 2]); | |
| 3812 for (intptr_t i = results->length() - 3; i > 1; --i) { | |
| 3813 (*results)[i] = (*results)[i - 2]; | |
| 3814 } | |
| 3815 (*results)[0] = kSmiCid; | |
| 3816 (*results)[1] = smi_is_subtype; | |
| 3817 } | |
| 3818 | |
| 3819 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded()); | |
| 3820 ASSERT(results->length() >= 2); | |
| 3821 // const Class& type_class = Class::Handle(type.type_class()) | |
|
Florian Schneider
2014/04/28 15:41:01
Remove commented-out code.
srdjan
2014/04/28 15:44:58
Done.
| |
| 3822 if (type.IsIntType()) { | |
| 3823 ASSERT((*results)[0] == kSmiCid); | |
| 3824 TryAddTest(results, kMintCid, true); | |
| 3825 TryAddTest(results, kBigintCid, true); | |
| 3826 // Cannot deoptimize since all tests returning true have been added. | |
| 3827 return false; | |
| 3828 } | |
| 3829 | |
| 3830 return true; // May deoptimize since we have not identified all 'true' tests. | |
| 3831 } | |
| 3832 | |
| 3833 | |
| 3762 // TODO(srdjan): Use ICData to check if always true or false. | 3834 // TODO(srdjan): Use ICData to check if always true or false. |
| 3763 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 3835 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 3764 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 3836 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 3765 Definition* left = call->ArgumentAt(0); | 3837 Definition* left = call->ArgumentAt(0); |
| 3766 Definition* instantiator = call->ArgumentAt(1); | 3838 Definition* instantiator = call->ArgumentAt(1); |
| 3767 Definition* type_args = call->ArgumentAt(2); | 3839 Definition* type_args = call->ArgumentAt(2); |
| 3768 const AbstractType& type = | 3840 const AbstractType& type = |
| 3769 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 3841 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 3770 const bool negate = Bool::Cast( | 3842 const bool negate = Bool::Cast( |
| 3771 OriginalDefinition(call->ArgumentAt(4))->AsConstant()->value()).value(); | 3843 OriginalDefinition(call->ArgumentAt(4))->AsConstant()->value()).value(); |
| 3772 const ICData& unary_checks = | 3844 const ICData& unary_checks = |
| 3773 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 3845 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 3774 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 3846 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 3775 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); | 3847 ZoneGrowableArray<intptr_t>* results = |
| 3776 if (!as_bool.IsNull()) { | 3848 new ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); |
| 3849 Bool& as_bool = | |
| 3850 Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type, results)); | |
| 3851 if (as_bool.IsNull()) { | |
| 3852 if (results->length() == unary_checks.NumberOfChecks() * 2) { | |
| 3853 const bool can_deopt = TryExpandTestCidsResult(results, type); | |
| 3854 TestCidsInstr* test_cids = new TestCidsInstr( | |
| 3855 call->token_pos(), | |
| 3856 negate ? Token::kISNOT : Token::kIS, | |
| 3857 new Value(left), | |
| 3858 *results, | |
| 3859 can_deopt ? call->deopt_id() : Isolate::kNoDeoptId); | |
| 3860 // Remove type. | |
| 3861 ReplaceCall(call, test_cids); | |
| 3862 return; | |
| 3863 } | |
| 3864 } else { | |
| 3865 // TODO(srdjan): Use TestCidsInstr also for this case. | |
| 3866 // One result only. | |
| 3777 AddReceiverCheck(call); | 3867 AddReceiverCheck(call); |
| 3778 if (negate) { | 3868 if (negate) { |
| 3779 as_bool = Bool::Get(!as_bool.value()).raw(); | 3869 as_bool = Bool::Get(!as_bool.value()).raw(); |
| 3780 } | 3870 } |
| 3781 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); | 3871 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); |
| 3782 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 3872 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 3783 PushArgumentInstr* push = call->PushArgumentAt(i); | 3873 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 3784 push->ReplaceUsesWith(push->value()->definition()); | 3874 push->ReplaceUsesWith(push->value()->definition()); |
| 3785 push->RemoveFromGraph(); | 3875 push->RemoveFromGraph(); |
| 3786 } | 3876 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 3816 new Value(left), | 3906 new Value(left), |
| 3817 new Value(instantiator), | 3907 new Value(instantiator), |
| 3818 new Value(type_args), | 3908 new Value(type_args), |
| 3819 type, | 3909 type, |
| 3820 negate, | 3910 negate, |
| 3821 call->deopt_id()); | 3911 call->deopt_id()); |
| 3822 ReplaceCall(call, instance_of); | 3912 ReplaceCall(call, instance_of); |
| 3823 } | 3913 } |
| 3824 | 3914 |
| 3825 | 3915 |
| 3916 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | |
| 3826 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 3917 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
| 3827 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 3918 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
| 3828 Definition* left = call->ArgumentAt(0); | 3919 Definition* left = call->ArgumentAt(0); |
| 3829 Definition* instantiator = call->ArgumentAt(1); | 3920 Definition* instantiator = call->ArgumentAt(1); |
| 3830 Definition* type_args = call->ArgumentAt(2); | 3921 Definition* type_args = call->ArgumentAt(2); |
| 3831 const AbstractType& type = | 3922 const AbstractType& type = |
| 3832 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 3923 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
| 3833 ASSERT(!type.IsMalformedOrMalbounded()); | 3924 ASSERT(!type.IsMalformedOrMalbounded()); |
| 3834 const ICData& unary_checks = | 3925 const ICData& unary_checks = |
| 3835 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); | 3926 ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecks()); |
| 3836 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 3927 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
| 3837 Bool& as_bool = Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type)); | 3928 ZoneGrowableArray<intptr_t>* results = |
| 3929 new ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); | |
| 3930 const Bool& as_bool = | |
| 3931 Bool::ZoneHandle(InstanceOfAsBool(unary_checks, type, results)); | |
| 3838 if (as_bool.raw() == Bool::True().raw()) { | 3932 if (as_bool.raw() == Bool::True().raw()) { |
| 3839 AddReceiverCheck(call); | 3933 AddReceiverCheck(call); |
| 3840 // Remove the original push arguments. | 3934 // Remove the original push arguments. |
| 3841 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 3935 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 3842 PushArgumentInstr* push = call->PushArgumentAt(i); | 3936 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 3843 push->ReplaceUsesWith(push->value()->definition()); | 3937 push->ReplaceUsesWith(push->value()->definition()); |
| 3844 push->RemoveFromGraph(); | 3938 push->RemoveFromGraph(); |
| 3845 } | 3939 } |
| 3846 // Remove call, replace it with 'left'. | 3940 // Remove call, replace it with 'left'. |
| 3847 call->ReplaceUsesWith(left); | 3941 call->ReplaceUsesWith(left); |
| (...skipping 3568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7416 Integer::Cast(right))), | 7510 Integer::Cast(right))), |
| 7417 Smi::Handle(Smi::New(0))); | 7511 Smi::Handle(Smi::New(0))); |
| 7418 SetValue(instr, result ? Bool::True() : Bool::False()); | 7512 SetValue(instr, result ? Bool::True() : Bool::False()); |
| 7419 } else { | 7513 } else { |
| 7420 SetValue(instr, non_constant_); | 7514 SetValue(instr, non_constant_); |
| 7421 } | 7515 } |
| 7422 } | 7516 } |
| 7423 } | 7517 } |
| 7424 | 7518 |
| 7425 | 7519 |
| 7520 void ConstantPropagator::VisitTestCids(TestCidsInstr* instr) { | |
| 7521 SetValue(instr, non_constant_); | |
| 7522 } | |
| 7523 | |
| 7524 | |
| 7426 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { | 7525 void ConstantPropagator::VisitEqualityCompare(EqualityCompareInstr* instr) { |
| 7427 const Object& left = instr->left()->definition()->constant_value(); | 7526 const Object& left = instr->left()->definition()->constant_value(); |
| 7428 const Object& right = instr->right()->definition()->constant_value(); | 7527 const Object& right = instr->right()->definition()->constant_value(); |
| 7429 | 7528 |
| 7430 if (instr->left()->definition() == instr->right()->definition()) { | 7529 if (instr->left()->definition() == instr->right()->definition()) { |
| 7431 // Fold x == x, and x != x to true/false for numbers comparisons. | 7530 // Fold x == x, and x != x to true/false for numbers comparisons. |
| 7432 if (RawObject::IsIntegerClassId(instr->operation_cid())) { | 7531 if (RawObject::IsIntegerClassId(instr->operation_cid())) { |
| 7433 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); | 7532 return SetValue(instr, Bool::Get(instr->kind() == Token::kEQ)); |
| 7434 } | 7533 } |
| 7435 } | 7534 } |
| (...skipping 1063 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8499 // These are the branches produced by inlining in a test context. Also, | 8598 // These are the branches produced by inlining in a test context. Also, |
| 8500 // the phi has no other uses so they can simply be eliminated. The block | 8599 // the phi has no other uses so they can simply be eliminated. The block |
| 8501 // has no other phis and no instructions intervening between the phi and | 8600 // has no other phis and no instructions intervening between the phi and |
| 8502 // branch so the block can simply be eliminated. | 8601 // branch so the block can simply be eliminated. |
| 8503 BranchInstr* branch = block->last_instruction()->AsBranch(); | 8602 BranchInstr* branch = block->last_instruction()->AsBranch(); |
| 8504 ASSERT(branch != NULL); | 8603 ASSERT(branch != NULL); |
| 8505 ComparisonInstr* comparison = branch->comparison(); | 8604 ComparisonInstr* comparison = branch->comparison(); |
| 8506 Value* left = comparison->left(); | 8605 Value* left = comparison->left(); |
| 8507 PhiInstr* phi = left->definition()->AsPhi(); | 8606 PhiInstr* phi = left->definition()->AsPhi(); |
| 8508 Value* right = comparison->right(); | 8607 Value* right = comparison->right(); |
| 8509 ConstantInstr* constant = right->definition()->AsConstant(); | 8608 ConstantInstr* constant = |
| 8609 (right == NULL) ? NULL : right->definition()->AsConstant(); | |
| 8510 return (phi != NULL) && | 8610 return (phi != NULL) && |
| 8511 (constant != NULL) && | 8611 (constant != NULL) && |
| 8512 (phi->GetBlock() == block) && | 8612 (phi->GetBlock() == block) && |
| 8513 PhiHasSingleUse(phi, left) && | 8613 PhiHasSingleUse(phi, left) && |
| 8514 (block->next() == branch) && | 8614 (block->next() == branch) && |
| 8515 (block->phis()->length() == 1); | 8615 (block->phis()->length() == 1); |
| 8516 } | 8616 } |
| 8517 | 8617 |
| 8518 | 8618 |
| 8519 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) { | 8619 JoinEntryInstr* BranchSimplifier::ToJoinEntry(TargetEntryInstr* target) { |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9053 } | 9153 } |
| 9054 | 9154 |
| 9055 // Insert materializations at environment uses. | 9155 // Insert materializations at environment uses. |
| 9056 for (intptr_t i = 0; i < exits.length(); i++) { | 9156 for (intptr_t i = 0; i < exits.length(); i++) { |
| 9057 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); | 9157 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots); |
| 9058 } | 9158 } |
| 9059 } | 9159 } |
| 9060 | 9160 |
| 9061 | 9161 |
| 9062 } // namespace dart | 9162 } // namespace dart |
| OLD | NEW |