Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1820)

Side by Side Diff: src/hydrogen.cc

Issue 11415173: Array bounds check elimination. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Refactoring (and fixing refactoring issues). Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/hydrogen.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 dominator_(NULL), 64 dominator_(NULL),
65 dominated_blocks_(4, graph->zone()), 65 dominated_blocks_(4, graph->zone()),
66 last_environment_(NULL), 66 last_environment_(NULL),
67 argument_count_(-1), 67 argument_count_(-1),
68 first_instruction_index_(-1), 68 first_instruction_index_(-1),
69 last_instruction_index_(-1), 69 last_instruction_index_(-1),
70 deleted_phis_(4, graph->zone()), 70 deleted_phis_(4, graph->zone()),
71 parent_loop_header_(NULL), 71 parent_loop_header_(NULL),
72 is_inline_return_target_(false), 72 is_inline_return_target_(false),
73 is_deoptimizing_(false), 73 is_deoptimizing_(false),
74 dominates_loop_successors_(false) { } 74 dominates_loop_successors_(false),
75 is_osr_entry_(false) { }
75 76
76 77
77 void HBasicBlock::AttachLoopInformation() { 78 void HBasicBlock::AttachLoopInformation() {
78 ASSERT(!IsLoopHeader()); 79 ASSERT(!IsLoopHeader());
79 loop_information_ = new(zone()) HLoopInformation(this, zone()); 80 loop_information_ = new(zone()) HLoopInformation(this, zone());
80 } 81 }
81 82
82 83
83 void HBasicBlock::DetachLoopInformation() { 84 void HBasicBlock::DetachLoopInformation() {
84 ASSERT(IsLoopHeader()); 85 ASSERT(IsLoopHeader());
(...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 if (!pointer->is_set()) { 590 if (!pointer->is_set()) {
590 HConstant* constant = 591 HConstant* constant =
591 new(zone()) HConstant(value, Representation::Integer32()); 592 new(zone()) HConstant(value, Representation::Integer32());
592 constant->InsertAfter(GetConstantUndefined()); 593 constant->InsertAfter(GetConstantUndefined());
593 pointer->set(constant); 594 pointer->set(constant);
594 } 595 }
595 return pointer->get(); 596 return pointer->get();
596 } 597 }
597 598
598 599
600 HConstant* HGraph::GetConstant0() {
601 return GetConstantInt32(&constant_0_, 0);
602 }
603
604
599 HConstant* HGraph::GetConstant1() { 605 HConstant* HGraph::GetConstant1() {
600 return GetConstantInt32(&constant_1_, 1); 606 return GetConstantInt32(&constant_1_, 1);
601 } 607 }
602 608
603 609
604 HConstant* HGraph::GetConstantMinus1() { 610 HConstant* HGraph::GetConstantMinus1() {
605 return GetConstantInt32(&constant_minus1_, -1); 611 return GetConstantInt32(&constant_minus1_, -1);
606 } 612 }
607 613
608 614
(...skipping 2710 matching lines...) Expand 10 before | Expand all | Expand 10 after
3319 if (FLAG_use_range) { 3325 if (FLAG_use_range) {
3320 HRangeAnalysis rangeAnalysis(this); 3326 HRangeAnalysis rangeAnalysis(this);
3321 rangeAnalysis.Analyze(); 3327 rangeAnalysis.Analyze();
3322 } 3328 }
3323 ComputeMinusZeroChecks(); 3329 ComputeMinusZeroChecks();
3324 3330
3325 // Eliminate redundant stack checks on backwards branches. 3331 // Eliminate redundant stack checks on backwards branches.
3326 HStackCheckEliminator sce(this); 3332 HStackCheckEliminator sce(this);
3327 sce.Process(); 3333 sce.Process();
3328 3334
3329 EliminateRedundantBoundsChecks(); 3335 if (FLAG_array_bounds_checks_dehoisting) {
3336 EliminateOrDehoistBoundsChecks();
3337 } else {
3338 EliminateRedundantBoundsChecks();
3339 }
3330 DehoistSimpleArrayIndexComputations(); 3340 DehoistSimpleArrayIndexComputations();
3331 if (FLAG_dead_code_elimination) DeadCodeElimination(); 3341 if (FLAG_dead_code_elimination) DeadCodeElimination();
3332 3342
3333 return true; 3343 return true;
3334 } 3344 }
3335 3345
3336 3346
3337 // We try to "factor up" HBoundsCheck instructions towards the root of the 3347 // We try to "factor up" HBoundsCheck instructions towards the root of the
3338 // dominator tree. 3348 // dominator tree.
3339 // For now we handle checks where the index is like "exp + int32value". 3349 // For now we handle checks where the index is like "exp + int32value".
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
3663 } 3673 }
3664 3674
3665 3675
3666 void HGraph::EliminateRedundantBoundsChecks() { 3676 void HGraph::EliminateRedundantBoundsChecks() {
3667 HPhase phase("H_Eliminate bounds checks", this); 3677 HPhase phase("H_Eliminate bounds checks", this);
3668 BoundsCheckTable checks_table(zone()); 3678 BoundsCheckTable checks_table(zone());
3669 EliminateRedundantBoundsChecks(entry_block(), &checks_table); 3679 EliminateRedundantBoundsChecks(entry_block(), &checks_table);
3670 } 3680 }
3671 3681
3672 3682
3683 // Helper class for array access index manipulation in
3684 // BoundsCheckValueInfo::CoverCheckWithBase.
3685 // The indexes have the form "base + constant" and the manipulations involve
3686 // changing the constant. Since the original constant HValue could be used
3687 // elsewhere we cannot change it and must create a new one.
3688 // However we need to create the HAdd only the first time we manipulate an
3689 // index, and later on we just reuse the instruction.
3690 class BoundsCheckManipulationData: public ZoneObject {
3691 public:
3692 HValue* Base() { return base_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3693 HBoundsCheck* Check() { return check_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3694 int Offset() { return offset_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3695
3696 // Change the index to use a new offset.
3697 void ChangeOffset(int new_offset) {
3698 HConstant* new_constant = new(zone())
Jakob Kummerow 2012/12/05 15:20:02 nit: please break the line after '=', and indent t
3699 HConstant(new_offset, Representation::Integer32());
3700 if (added_add_ == NULL) {
3701 new_constant->InsertBefore(Check());
3702 added_add_ = new(zone()) HAdd(NULL, Base(), new_constant);
3703 added_add_->AssumeRepresentation(Check()->index()->representation());
3704 added_add_->InsertBefore(Check());
3705 } else {
3706 new_constant->InsertBefore(added_add_);
3707 added_offset_->DeleteAndReplaceWith(new_constant);
3708 }
3709 added_offset_ = new_constant;
3710 Check()->SetOperandAt(0, added_add_);
Jakob Kummerow 2012/12/05 15:20:02 I'd prefer introducing a method HBoundsCheck::SetI
3711 offset_ = new_offset;
3712 }
3713
3714 // If we ended up creating an "add zero" instruction we can remove it.
3715 void RemoveNullAdd() {
Jakob Kummerow 2012/12/05 15:20:02 Why do we have to do this as an additional step? C
3716 if (added_add_ != NULL && added_offset_->Integer32Value() == 0) {
3717 added_add_->DeleteAndReplaceWith(added_add_->left());
3718 added_offset_->DeleteAndReplaceWith(NULL);
3719 added_add_ = NULL;
3720 added_offset_ = NULL;
3721 }
3722 }
3723
3724 BoundsCheckManipulationData(HValue* base, HBoundsCheck* check, int offset) :
Jakob Kummerow 2012/12/05 15:20:02 nit: ':' goes on the next line, with 4-space inden
3725 base_(base), check_(check), offset_(offset),
3726 added_add_(NULL), added_offset_(NULL) {}
3727
3728 private:
3729 HValue* base_;
3730 HBoundsCheck* check_;
3731 int offset_;
3732 HAdd* added_add_;
3733 HConstant* added_offset_;
3734
3735 Zone* zone() { return Check()->block()->zone(); }
Jakob Kummerow 2012/12/05 15:20:02 nit: methods before data members
3736 };
3737
3738
3739 class BoundsCheckValueInfo;
3740
3741
3742 static bool BoundsCheckValueInfoMatch(void* v1, void* v2);
3743
3744
3745 // The "knowledge base" used for array bounds check elimination.
3746 // A hash table indexed by HValue ID and containing a list of known facts for
3747 // the given value.
3748 class BoundsCheckValueInfoTable : public ZoneObject {
3749 public:
3750 Zone* zone() { return zone_; }
3751
3752 // If the entry is in the table but the list is empty, remove it.
3753 void CleanupKey(HValue* key);
3754
3755 BoundsCheckValueInfo** LookupKey(HValue* key);
3756 BoundsCheckValueInfo** LookupOrInsert(HValue* key);
3757 BoundsCheckValueInfo** Insert(BoundsCheckValueInfo* data);
3758 void Delete(HValue* key);
3759
3760 explicit BoundsCheckValueInfoTable(Zone* zone)
Jakob Kummerow 2012/12/05 15:20:02 nit: the constructor should be the first thing in
3761 : zone_(zone),
3762 map_(BoundsCheckValueInfoMatch,
3763 ZoneHashMap::kDefaultHashMapCapacity,
3764 ZoneAllocationPolicy(zone)){ }
Jakob Kummerow 2012/12/05 15:20:02 nit: space before '{'
3765 private:
Jakob Kummerow 2012/12/05 15:20:02 nit: empty line before "private:" (doesn't presubm
3766 Zone* zone_;
3767 ZoneHashMap map_;
3768 };
3769
3770
3771 enum ValueInfoRelation {
3772 NONE,
3773 NE,
Jakob Kummerow 2012/12/05 15:20:02 Feel free to put all values onto the same line (I
3774 GT,
3775 GE,
3776 EQ,
3777 LE,
3778 LT
3779 };
3780
3781
3782 class BoundsCheckRemovalBlockContext BASE_EMBEDDED {
3783 public:
3784 HBasicBlock* block() { return block_; }
3785 BoundsCheckValueInfoTable* table() { return table_; }
3786 BoundsCheckValueInfo* data_list_head() { return bb_data_list_; }
3787 BoundsCheckValueInfo** data_insertion_point() { return &bb_data_list_; }
3788 BoundsCheckRemovalBlockContext* previous() { return previous_; }
3789
3790 BoundsCheckValueInfo* NewValueInfo(HValue* v,
3791 HValue* c,
3792 ValueInfoRelation r,
3793 bool is_incremental,
3794 HBoundsCheck* bounds_check = NULL,
3795 int check_offset = 0);
3796
3797 BoundsCheckRemovalBlockContext(
Jakob Kummerow 2012/12/05 15:20:02 again, constructor comes first
3798 HBasicBlock* block,
3799 BoundsCheckRemovalBlockContext* previous)
3800 : table_(previous != NULL ? previous->table() :
Jakob Kummerow 2012/12/05 15:20:02 proper indentation please: : table_(previous
3801 new(block->graph()->zone())
3802 BoundsCheckValueInfoTable(block->graph()->zone())),
3803 block_(block), bb_data_list_(NULL), previous_(previous) {}
3804
3805 private:
3806 BoundsCheckValueInfoTable* table_;
3807 HBasicBlock* block_;
3808 BoundsCheckValueInfo* bb_data_list_;
3809 BoundsCheckRemovalBlockContext* previous_;
3810 };
3811
3812
3813 // The individual "fact" in the knowledge base.
3814 // Each fact has the form "value relation constraint", where value and
Jakob Kummerow 2012/12/05 15:20:02 suggestion: // Each fact has the form (value, rela
3815 // constraint are both HValue instances and "relation" can be one of the
3816 // usual relational operators (less than, greater than, ecc).
3817 class BoundsCheckValueInfo: public ZoneObject {
3818 public:
3819 HValue* Value() { return value_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3820 ValueInfoRelation Relation() { return relation_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3821 HValue* Constraint() { return constraint_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3822 // True if Value() will "cover" every single integer value in the range
Jakob Kummerow 2012/12/05 15:20:02 s/"cover"/take/
3823 // defined by the relation.
3824 // This could be used to detect in advance that an array is not holey
3825 // because a loop will write every single array element.
3826 bool IsIncremental() { return is_incremental_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3827
3828 bool ConstraintIsZero() {
3829 if (!constraint_->IsConstant()) { return false; }
3830 HConstant* c = HConstant::cast(constraint_);
3831 return c->DoubleValue() == 0.0;
Jakob Kummerow 2012/12/05 15:20:02 This won't work for non-number constants. Use "ret
3832 }
3833 Zone* zone() { return Value()->block()->zone(); }
3834
3835 // A HBoundsCheck on the same index; it is equivalent to having...
Jakob Kummerow 2012/12/05 15:20:02 ...?
3836 HBoundsCheck* BoundsCheck() { return bounds_check_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3837
3838 // The following properties are all helpers for CoverCheckWithBase.
Jakob Kummerow 2012/12/05 15:20:02 If they're helpers for another member, why are the
3839 // To make things easier at construction time every list head will just copy
3840 // the values from the next element (which is the previous one in the
3841 // dominator tree traversal).
3842 // This simplifies both searching (the list head always holds current values)
3843 // and backtracking (the remaining list head has naturally the right values).
3844
3845 // Offset used by CoverCheckWithBase.
3846 int CheckOffset() { return check_offset_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3847 // Lower check used by CoverCheckWithBase.
3848 BoundsCheckManipulationData* LowerCheck() { return lower_check_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3849 // Upper check used by CoverCheckWithBase.
3850 BoundsCheckManipulationData* UpperCheck() { return upper_check_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3851 // Initial state for CoverCheckWithBase (both checks should be NULL).
3852 bool HasNoBaseHandledCheck() { return lower_check_ == NULL; }
Jakob Kummerow 2012/12/05 15:20:02 What's a BaseHandledCheck? Why not just "HasNoChec
3853 // "single check" state for CoverCheckWithBase.
3854 bool HasSingleBaseHandledCheck() {
3855 return lower_check_ != NULL && lower_check_ == upper_check_;
3856 }
3857 // End of CoverCheckWithBase helpers.
3858
3859 // Basic block in which this fact was created.
3860 HBasicBlock* BasicBlock() const { return basic_block_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3861 // Next known fact for this value.
3862 BoundsCheckValueInfo* NextForValue() { return next_for_value_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3863 // Next fact created in this basic block.
3864 BoundsCheckValueInfo* NextInBasicBlock() { return next_in_basic_block_; }
Jakob Kummerow 2012/12/05 15:20:02 nit: lower-case names for simple accessors.
3865
3866
3867 // This method handles the special case of indexes like "base + constant".
3868 // For any given HValue "exp", two bounds checks "exp + c1" and exp + c2"
3869 // will obviously "cover" every other array access where the index value is
3870 // between "exp + c1" and exp + c2".
3871 // Now, suppose that we meet an index "exp + c3" which is out of this range.
3872 // If we are in the same basic block we can easily change either c1 or c2
3873 // in one of the two previous checks so that the 3rd check is redundant.
3874 // (if we are not in the same BB the change would be optimistic and could
3875 // lead to "unneeded" deoptimizations so we don't do it).
3876 // This method does exactly that, handling changes between these states:
3877 // - No previous check was met (HasNoBaseHandledCheck() == true)
3878 // - We have one previous check (HasSingleBaseHandledCheck() == true)
3879 // - We have two previous checks.
3880 // The class BoundsCheckManipulationData helps keeping track of the changed
3881 // instructions so that it is easy to change than again if needed.
Jakob Kummerow 2012/12/05 15:20:02 s/than/them/
3882 bool CoverCheckWithBase(
Jakob Kummerow 2012/12/05 15:20:02 nit: for method declarations (as opposed to calls)
3883 HValue* base, HBoundsCheck* new_check, int32_t new_offset) {
3884 ASSERT(new_check->index()->representation().IsInteger32());
3885 bool remove_new_check = false;
Jakob Kummerow 2012/12/05 15:20:02 Why do we need a variable for this? Looks like ass
3886
3887 if (HasNoBaseHandledCheck()) {
3888 lower_check_ = new(zone())
3889 BoundsCheckManipulationData(base, new_check, new_offset);
3890 upper_check_ = lower_check_;
3891 } else {
3892 if (new_offset > UpperCheck()->Offset()) {
3893 if (HasSingleBaseHandledCheck() ||
3894 upper_check_->Check()->block() != BasicBlock()) {
Jakob Kummerow 2012/12/05 15:20:02 Why is this check necessary? BoundsCheckValueInfo
3895 upper_check_ = new(zone())
3896 BoundsCheckManipulationData(base, new_check, new_offset);
3897 } else {
3898 upper_check_->ChangeOffset(new_offset);
3899 remove_new_check = true;
3900 }
3901 } else if (new_offset < LowerCheck()->Offset()) {
3902 if (HasSingleBaseHandledCheck() ||
3903 lower_check_->Check()->block() != BasicBlock()) {
3904 lower_check_ = new(zone())
3905 BoundsCheckManipulationData(base, new_check, new_offset);
3906 } else {
3907 lower_check_->ChangeOffset(new_offset);
3908 remove_new_check = true;
3909 }
3910 } else {
3911 remove_new_check = true;
3912 }
3913 }
3914
3915 return remove_new_check;
3916 }
3917
3918 void RemoveNullAdds() {
3919 if (lower_check_ == NULL) return;
3920 lower_check_->RemoveNullAdd();
3921 if (upper_check_ == lower_check_) return;
3922 upper_check_->RemoveNullAdd();
3923 }
3924
3925 uint32_t Hash() {
3926 return static_cast<uint32_t>(value_->Hashcode());
3927 }
3928
3929 // Instead of doing a graph walk we attempt to simplify the index.
3930 // Since simplifications can be recursive we put a limit on the number
3931 // of steps we take.
3932 // This is roughly equivalent to limiting the graph walks to only a
3933 // given number of steps (but is way easier to implement...).
3934 static const int kDepthLimit = 3;
3935
3936 // The main method that queries the knowledge base to see if a given value
3937 // has a relation with a given limit ("value" is the array index and
3938 // "limit" is the array length).
3939 // If, as a result, both *lower_covered and *upper_covered are true then the
3940 // bounds check can be eliminated: the lower part stands for "value >= 0"
3941 // and the upper part for "value < limit".
3942 // Either of them is NULL it means that the caller is not interested in that
3943 // part of the relation.
3944 // Depth limits the complexity of the attempted value decompositions.
3945 static void ComputeIndexRelation(HValue* value,
3946 HValue* limit,
3947 HBasicBlock* block,
3948 HValue** hoisted_limit,
3949 bool* lower_covered,
3950 bool* upper_covered,
3951 BoundsCheckValueInfoTable* table,
3952 int depth) {
3953 BoundsCheckValueInfo** value_head;
3954 if (lower_covered == NULL && upper_covered == NULL) return;
3955 if (depth == 0) {
3956 value_head = table->LookupOrInsert(value);
3957 } else if (depth > kDepthLimit) {
3958 return;
3959 } else {
3960 value_head = table->LookupKey(value);
3961 if (value_head == NULL) {
3962 return;
3963 }
3964 }
3965
3966 for (BoundsCheckValueInfo* value_info = *value_head;
3967 value_info != NULL;
Jakob Kummerow 2012/12/05 15:20:02 nit: aligning "value_info" with "BoundsCheckValueI
3968 value_info = value_info->NextForValue()) {
3969 if (lower_covered != NULL) {
3970 if (value_info->ConstraintIsZero() && value_info->Relation() == GE) {
3971 *lower_covered = true;
3972 }
3973 }
3974 if (upper_covered != NULL) {
Jakob Kummerow 2012/12/05 15:20:02 Ugh. 5 levels of nested "if"s? I'd prefer the foll
3975 if (value_info->Relation() == LT) {
3976 if (value_info->Constraint() == limit) {
3977 *upper_covered = true;
3978 } else if (hoisted_limit != NULL) {
3979 HValue* constraint = value_info->Constraint();
3980 if (constraint->block()->Dominates(
3981 block->loop_information()->loop_header())) {
3982 if (*hoisted_limit == NULL ||
3983 constraint->block()->Dominates((*hoisted_limit)->block())) {
3984 *hoisted_limit = constraint;
3985 }
3986 }
3987 }
3988 }
3989 }
3990 }
3991
3992 if (!((lower_covered == NULL || *lower_covered) &&
3993 (upper_covered == NULL || *upper_covered))) {
Jakob Kummerow 2012/12/05 15:20:02 Please indent this so that the indentation reflect
3994 bool skip_lower = false;
3995 bool skip_upper = false;
3996 int32_t constant;
3997 HValue* simplified_value = SimplifyValue(
3998 value, &skip_lower, &skip_upper, &constant);
3999 if (simplified_value != NULL) {
4000 ComputeIndexRelation(simplified_value, limit, block, hoisted_limit,
4001 skip_lower ? NULL : lower_covered,
4002 skip_upper ? NULL : upper_covered,
4003 table, depth + 1);
4004 }
4005 }
4006
4007 if (!((lower_covered == NULL || *lower_covered) &&
Jakob Kummerow 2012/12/05 15:20:02 same here
4008 (upper_covered == NULL || *upper_covered))) {
4009 if (value->IsPhi()) {
4010 HPhi* phi = HPhi::cast(value);
4011 bool lower_skip_state = false;
4012 bool upper_skip_state = false;
4013 for (int i = 0;
4014 i < phi->OperandCount() && !(lower_skip_state && upper_skip_state);
4015 i++) {
4016 bool lower_skip_argument = false;
4017 bool upper_skip_argument = false;
4018 ComputeIndexRelation(phi->OperandAt(i), limit, block, hoisted_limit,
4019 &lower_skip_argument,
4020 &upper_skip_argument,
4021 table, depth + 1);
4022 if (lower_skip_argument) {
4023 lower_skip_state = true;
4024 }
4025 if (upper_skip_argument) {
4026 upper_skip_state = true;
4027 }
4028 }
4029
4030 if (lower_covered != NULL && !lower_skip_state) *lower_covered = true;
4031 if (upper_covered != NULL && !upper_skip_state) *upper_covered = true;
4032 }
4033 }
4034 }
4035
4036 static bool CoverBasePlusConstant(HBoundsCheck* check,
Jakob Kummerow 2012/12/05 15:20:02 Another method that doesn't tell me what the metho
4037 BoundsCheckRemovalBlockContext* context) {
4038 HValue* index_base;
4039 int32_t offset;
4040 if (GetCheckIndexBase(check->index(), &index_base, &offset)) {
4041 BoundsCheckValueInfo** base_head =
4042 context->table()->LookupOrInsert(index_base);
4043 BoundsCheckValueInfo* base_info = *base_head;
4044 if (base_info == NULL) {
4045 base_info = context->NewValueInfo(
4046 index_base, check->length(), NONE, false, check, offset);
4047 }
4048 return base_info->CoverCheckWithBase(index_base, check, offset);
4049 } else {
Jakob Kummerow 2012/12/05 15:20:02 nit: no need for "else", just "return false".
4050 return false;
4051 }
4052 }
4053
4054 static void HandleCheck(HBoundsCheck* check,
4055 BoundsCheckRemovalBlockContext* context) {
4056 HValue* index = check->index();
4057 HValue* length = check->length();
4058 bool lower_covered = false;
4059 bool upper_covered = false;
4060 HBasicBlock* block = context->block();
4061 HValue* hoisted_limit = NULL;
4062 HValue** hoisted_limit_pointer;
Jakob Kummerow 2012/12/05 15:20:02 initialize this to NULL here...
4063
4064 if (block->graph()->use_optimistic_licm() &&
4065 block->loop_information() != NULL &&
4066 length->block()->Dominates(block->loop_information()->loop_header())) {
4067 hoisted_limit_pointer = &hoisted_limit;
4068 } else {
4069 hoisted_limit_pointer = NULL;
Jakob Kummerow 2012/12/05 15:20:02 ...and drop this.
4070 }
4071
4072 ComputeIndexRelation(
4073 index, length, block, hoisted_limit_pointer,
Jakob Kummerow 2012/12/05 15:20:02 nit: no need to break the first line of arguments
4074 &lower_covered, &upper_covered, context->table(), 0);
4075
4076 if (!(lower_covered && upper_covered)) {
4077 if (CoverBasePlusConstant(check, context)) {
4078 lower_covered = true;
4079 upper_covered = true;
4080 }
4081 }
4082
4083 if ((!(lower_covered && upper_covered)) && hoisted_limit != NULL) {
Jakob Kummerow 2012/12/05 15:20:02 simplification: you can remove one set of parenthe
4084 HBasicBlock* hoisting_block =
4085 block->loop_information()->loop_pre_header();
4086 BoundsCheckRemovalBlockContext* hoisting_context = context;
4087 while (hoisting_context != NULL &&
4088 hoisting_context->block() != hoisting_block) {
Jakob Kummerow 2012/12/05 15:20:02 nit: prefer alignment at '(' (i.e. in this case th
4089 hoisting_context = hoisting_context->previous();
4090 }
4091
4092 if (hoisting_context != NULL) {
4093 HBoundsCheck* new_check =
4094 new(context->table()->zone()) HBoundsCheck(hoisted_limit, length);
4095 new_check->InsertBefore(hoisting_block->last());
4096 context->NewValueInfo(
4097 index, block->graph()->GetConstant0(), GE, false);
4098 context->NewValueInfo(index, length, LT, false);
4099 lower_covered = true;
4100 upper_covered = true;
4101 }
4102 }
4103
4104 bool remove_check = true;
4105 if (!lower_covered) {
4106 remove_check = false;
4107 context->NewValueInfo(index, block->graph()->GetConstant0(), GE, false);
4108 }
4109 if (!upper_covered) {
4110 remove_check = false;
4111 context->NewValueInfo(index, length, LT, false);
4112 }
4113 if (remove_check) {
4114 check->DeleteAndReplaceWith(NULL);
4115 }
4116 }
4117
4118 // Handles a HPhi definition, eventually creating a new fact.
4119 static void FromPhi(HPhi* phi,
Jakob Kummerow 2012/12/05 15:20:02 nit: some other name please. We commonly use "stat
4120 BoundsCheckRemovalBlockContext* context) {
4121 if (phi->OperandCount() != 2) return;
4122
4123 ValueInfoRelation relation;
4124 bool is_incremental;
4125
4126 relation = RelationFromMonotonicOperation(
4127 phi, phi->OperandAt(0), &is_incremental);
4128 if (relation != NONE) {
4129 context->NewValueInfo(phi, phi->OperandAt(1), relation, is_incremental);
4130 return;
4131 }
4132
4133 relation = RelationFromMonotonicOperation(
4134 phi, phi->OperandAt(1), &is_incremental);
4135 if (relation != NONE) {
4136 context->NewValueInfo(phi, phi->OperandAt(0), relation, is_incremental);
4137 return;
4138 }
4139 }
4140
4141 // Handles a conditional branch, eventually creating new facts.
4142 static void FromConditionalBranch(
Jakob Kummerow 2012/12/05 15:20:02 Again, please choose some name that doesn't sound
4143 HCompareIDAndBranch* condition,
4144 BoundsCheckRemovalBlockContext* context) {
4145 HValue* value;
4146 HValue* constraint;
4147 ValueInfoRelation relation;
4148 bool isElseBranch;
Jakob Kummerow 2012/12/05 15:20:02 nit: unix_hacker_style names for variables
4149 if (context->block() == condition->SuccessorAt(0)) {
4150 isElseBranch = false;
4151 } else if (context->block() == condition->SuccessorAt(1)) {
4152 isElseBranch = true;
4153 } else {
4154 return;
4155 }
4156
4157 relation = FromToken(condition->token());
4158 if (relation == NONE) return;
4159
4160 if (isElseBranch) {
4161 value = condition->right();
4162 constraint = condition->left();
4163 } else {
4164 value = condition->left();
4165 constraint = condition->right();
4166 }
4167
4168 context->NewValueInfo(value, constraint, relation, false);
4169 context->NewValueInfo(constraint, value, Switched(relation), false);
Jakob Kummerow 2012/12/05 15:20:02 Whoa. Do we really need to store every fact twice?
4170 }
4171
4172 static const char* RelationName(ValueInfoRelation r) {
4173 switch (r) {
4174 case NE:
4175 return "NE";
4176 case GT:
4177 return "GT";
4178 case GE:
4179 return "GE";
4180 case EQ:
4181 return "EQ";
4182 case LE:
4183 return "LE";
4184 case LT:
4185 return "LT";
4186 case NONE:
4187 return "NONE";
4188 default:
Jakob Kummerow 2012/12/05 15:20:02 since you're handling all cases explicitly, you do
4189 UNREACHABLE();
4190 return "UNREACHABLE";
4191 }
4192 }
4193
4194 bool UnlinkFromValue() {
4195 *previous_for_value_ = next_for_value_;
Jakob Kummerow 2012/12/05 15:20:02 Having different levels of pointer indirection for
4196 if (next_for_value_ != NULL) {
4197 next_for_value_->previous_for_value_ = previous_for_value_;
4198 }
4199 bool result = (next_for_value_ == NULL);
4200 previous_for_value_ = NULL;
4201 next_for_value_ = NULL;
4202 RemoveNullAdds();
4203 return result;
4204 }
4205
4206 BoundsCheckValueInfo(HValue* v,
Jakob Kummerow 2012/12/05 15:20:02 nit: constructor should be the first thing in the
4207 HValue* c,
Jakob Kummerow 2012/12/05 15:20:02 what do "v" and "c" mean?
4208 ValueInfoRelation r,
4209 bool is_incremental,
4210 BoundsCheckRemovalBlockContext* context,
4211 HBoundsCheck* bounds_check = NULL,
4212 int check_offset = 0) :
Jakob Kummerow 2012/12/05 15:20:02 nit: ':' goes on the next line
4213 value_(DiscardOsrValue(v)), constraint_(DiscardOsrValue(c)),
4214 relation_(r), is_incremental_(is_incremental),
4215 bounds_check_(bounds_check),
4216 check_offset_(check_offset),
4217 basic_block_(context->block()),
4218 previous_for_value_(context->table()->LookupOrInsert(value_)),
4219 next_for_value_(*previous_for_value_),
4220 next_in_basic_block_(*context->data_insertion_point()),
4221 lower_check_(next_for_value_ != NULL ?
Jakob Kummerow 2012/12/05 15:20:02 nit: if a ternary operator doesn't fit on one line
4222 next_for_value_->LowerCheck() : NULL),
4223 upper_check_(next_for_value_ != NULL ?
4224 next_for_value_->UpperCheck() : NULL) {
4225 if (next_for_value_ != NULL) {
4226 next_for_value_->previous_for_value_ = &(next_for_value_);
4227 }
4228 *previous_for_value_ = this;
4229 *context->data_insertion_point() = this;
4230 }
4231
4232 private:
4233 HValue* value_;
Jakob Kummerow 2012/12/05 15:20:02 nit: member variables come last in the "private:"
4234 HValue* constraint_;
4235 ValueInfoRelation relation_;
4236 bool is_incremental_;
4237 HBoundsCheck* bounds_check_;
4238 int check_offset_;
4239
4240 HBasicBlock* basic_block_;
4241 BoundsCheckValueInfo** previous_for_value_;
4242 BoundsCheckValueInfo* next_for_value_;
4243 BoundsCheckValueInfo* next_in_basic_block_;
4244 BoundsCheckManipulationData* lower_check_;
4245 BoundsCheckManipulationData* upper_check_;
4246
4247 // Detect if a value has the form "base plus constant".
4248 static bool GetCheckIndexBase(HValue* index,
Jakob Kummerow 2012/12/05 15:20:02 Another method name that puzzles me, especially in
4249 HValue** index_base,
4250 int32_t* offset) {
4251 *index_base = NULL;
4252 *offset = 0;
4253 if (!index->representation().IsInteger32()) return NULL;
4254
4255 HConstant* constant = NULL;
4256 bool is_sub = false;
4257
4258 if (index->IsAdd()) {
4259 HAdd* add = HAdd::cast(index);
4260 if (add->left()->IsConstant()) {
4261 constant = HConstant::cast(add->left());
4262 *index_base = add->right();
4263 } else if (add->right()->IsConstant()) {
4264 constant = HConstant::cast(add->right());
4265 *index_base = add->left();
4266 }
4267 } else if (index->IsSub()) {
4268 HSub* sub = HSub::cast(index);
4269 is_sub = true;
4270 if (sub->left()->IsConstant()) {
Jakob Kummerow 2012/12/05 15:20:02 This was probably supposed to be sub->right()->IsC
4271 constant = HConstant::cast(sub->left());
4272 *index_base = sub->right();
4273 }
4274 }
4275
4276 if (constant != NULL && constant->HasInteger32Value()) {
4277 *offset = is_sub ? - constant->Integer32Value()
4278 : constant->Integer32Value();
4279 return true;
4280 }
4281 return false;
4282 }
4283
4284 // Attempts value simplification or decomposition.
4285 static HValue* SimplifyValue(HValue* value,
4286 bool* skip_lower,
Jakob Kummerow 2012/12/05 15:20:02 nit: indentation
4287 bool* skip_upper,
4288 int32_t* constant) {
4289 HValue* result = NULL;
4290 *constant = 0;
4291
4292 if (value->IsAdd()) {
4293 HAdd* add = HAdd::cast(value);
4294 HConstant* constant_operand = NULL;
4295 if (add->left()->IsConstant()) {
Jakob Kummerow 2012/12/05 15:20:02 This code here is an almost exact duplicate of the
4296 result = add->right();
4297 constant_operand = HConstant::cast(add->left());
4298 } else if (add->right()->IsConstant()) {
4299 result = add->left();
4300 constant_operand = HConstant::cast(add->right());
4301 }
4302 if (constant_operand != NULL && constant_operand->HasInteger32Value()) {
4303 *constant = constant_operand->Integer32Value();
4304 if (*constant > 0) {
4305 *skip_upper = true;
4306 } else if (*constant < 0) {
4307 *skip_lower = true;
4308 } else {
4309 result = value;
4310 }
4311 } else {
4312 result = NULL;
4313 }
4314 } else if (value->IsSub()) {
4315 HSub* sub = HSub::cast(value);
4316 HConstant* constant_operand = NULL;
4317 if (sub->left()->IsConstant()) {
4318 result = sub->right();
4319 constant_operand = HConstant::cast(sub->left());
4320 } else if (sub->right()->IsConstant()) {
4321 result = sub->left();
4322 constant_operand = HConstant::cast(sub->right());
4323 }
4324 if (constant_operand != NULL && constant_operand->HasInteger32Value()) {
4325 *constant = constant_operand->Integer32Value();
4326 if (*constant > 0) {
4327 *skip_lower = true;
4328 } else if (*constant > 0) {
Jakob Kummerow 2012/12/05 15:20:02 This is the same condition as before. You probably
4329 *skip_upper = true;
4330 } else {
4331 result = value;
4332 }
4333 } else {
4334 result = NULL;
4335 }
4336 }
4337
4338 return result;
4339 }
4340
4341
4342 static ValueInfoRelation FromToken(Token::Value token) {
Jakob Kummerow 2012/12/05 15:20:02 Having such a simple mapping from Token::Value to
4343 switch (token) {
4344 case Token::EQ:
4345 case Token::EQ_STRICT:
4346 return EQ;
4347 case Token::LT:
4348 return LT;
4349 case Token::GT:
4350 return GT;
4351 case Token::LTE:
4352 return LE;
4353 case Token::GTE:
4354 return GE;
4355 default:
4356 return NONE;
4357 }
4358 }
4359
4360 // Detects if a HPhi defines a monotonic operation, and if it does
4361 // returns the appropriate relation.
4362 // *value_increment is true if the value will assume every integer value
4363 // in the range.
4364 static ValueInfoRelation RelationFromMonotonicOperation(
4365 HPhi* base, HValue* operation, bool* value_increment) {
Jakob Kummerow 2012/12/05 15:20:02 nit: for method/function declarations, either ever
4366 *value_increment = false;
4367
4368 if (operation->opcode() == HValue::kAdd) {
4369 HAdd* add = HAdd::cast(operation);
Jakob Kummerow 2012/12/05 15:20:02 nit: indentation
4370 HValue* maybe_constant;
4371 if (add->right() == base) {
4372 maybe_constant = add->left();
4373 } else if (add->left() == base) {
4374 maybe_constant = add->right();
4375 } else {
4376 return NONE;
4377 }
4378
4379 if (maybe_constant->IsConstant()) {
4380 HConstant* c = HConstant::cast(maybe_constant);
4381 if ((c->DoubleValue() == 1) || (c->DoubleValue() == -1))
Jakob Kummerow 2012/12/05 15:20:02 Again: 1) why DoubleValue() and not Integer32Value
4382 *value_increment = true;
4383 if (c->DoubleValue() > 0) {
4384 return GE;
4385 } else if (c->DoubleValue() < 0) {
4386 return LE;
4387 } else if (c->DoubleValue() == 0) {
4388 return EQ;
4389 } else {
4390 return NONE;
4391 }
4392 }
4393 return NONE;
4394 } else if (operation->opcode() == HValue::kSub) {
4395 HSub* sub = HSub::cast(operation);
4396 if (sub->right() == base && sub->left()->IsConstant()) {
Jakob Kummerow 2012/12/05 15:20:02 this looks like another left/right mixup.
4397 HConstant* c = HConstant::cast(sub->left());
4398 if ((c->DoubleValue() == 1) || (c->DoubleValue() == -1))
4399 *value_increment = true;
4400 if (c->DoubleValue() > 0) {
4401 return LE;
4402 } else if (c->DoubleValue() < 0) {
4403 return GE;
4404 } else if (c->DoubleValue() == 0) {
4405 return EQ;
4406 } else {
4407 return NONE;
4408 }
4409 } else {
4410 return NONE;
4411 }
4412 }
4413 return NONE;
4414 }
4415
4416 static ValueInfoRelation Switched(ValueInfoRelation other) {
Jakob Kummerow 2012/12/05 15:20:02 "Switched"? Into shuffle mode? Also, we already h
4417 switch (other) {
4418 case NE:
4419 return EQ;
4420 case GT:
4421 return LE;
4422 case GE:
4423 return LT;
4424 case EQ:
4425 return NE;
4426 case LE:
4427 return GT;
4428 case LT:
4429 return GE;
4430 default:
4431 UNREACHABLE();
4432 return NONE;
4433 }
4434 }
4435
4436 // Helper method to discard a HPhi induced by OSR.
4437 static HValue* DiscardOsrValue(HValue* v) {
4438 if (!v->IsPhi()) return v;
4439 HPhi* phi = HPhi::cast(v);
4440 if (phi->OperandCount() != 2) return v;
4441 if (phi->OperandAt(0)->block()->is_osr_entry()) {
4442 return phi->OperandAt(1);
4443 } else if (phi->OperandAt(1)->block()->is_osr_entry()) {
4444 return phi->OperandAt(0);
4445 } else {
4446 return v;
4447 }
4448 }
4449 };
4450
4451
4452 BoundsCheckValueInfo* BoundsCheckRemovalBlockContext::NewValueInfo(
4453 HValue* v,
4454 HValue* c,
Jakob Kummerow 2012/12/05 15:20:02 what do "v" and "c" stand for?
4455 ValueInfoRelation r,
4456 bool is_incremental,
4457 HBoundsCheck* bounds_check,
4458 int check_offset) {
4459 return new (table()->zone()) BoundsCheckValueInfo(
4460 v, c, r, is_incremental, this, bounds_check, check_offset);
4461 }
4462
4463
4464 static bool BoundsCheckValueInfoMatch(void* v1, void* v2) {
4465 BoundsCheckValueInfo* k1 = static_cast<BoundsCheckValueInfo*>(v1);
4466 BoundsCheckValueInfo* k2 = static_cast<BoundsCheckValueInfo*>(v2);
4467 return k1->Value() == k2->Value();
4468 }
4469
4470
4471 void BoundsCheckValueInfoTable::CleanupKey(HValue* key) {
4472 ZoneHashMap::Entry* e = map_.Lookup(
4473 key, static_cast<uint32_t>(key->Hashcode()), false,
4474 ZoneAllocationPolicy(zone()));
4475 if (e != NULL && e->value == NULL) {
4476 map_.Remove(key, key->Hashcode());
4477 }
4478 }
4479
4480
4481 BoundsCheckValueInfo** BoundsCheckValueInfoTable::LookupKey(HValue* key) {
4482 ZoneHashMap::Entry* entry = map_.Lookup(
4483 key, static_cast<uint32_t>(key->Hashcode()), false,
4484 ZoneAllocationPolicy(zone()));
4485 if (entry != NULL) {
4486 return reinterpret_cast<BoundsCheckValueInfo**>(&(entry->value));
4487 } else {
4488 return NULL;
4489 }
4490 }
4491
4492
4493 BoundsCheckValueInfo** BoundsCheckValueInfoTable::LookupOrInsert(HValue* key) {
4494 return reinterpret_cast<BoundsCheckValueInfo**>(
4495 &(map_.Lookup(key, static_cast<uint32_t>(key->Hashcode()), true,
4496 ZoneAllocationPolicy(zone()))->value));
Jakob Kummerow 2012/12/05 15:20:02 nit: please align with "key"
4497 }
4498
4499
4500 BoundsCheckValueInfo** BoundsCheckValueInfoTable::Insert(
4501 BoundsCheckValueInfo* data) {
4502 BoundsCheckValueInfo** result = LookupOrInsert(data->Value());
4503 *result = data;
4504 return result;
4505 }
4506
4507
4508 void BoundsCheckValueInfoTable::Delete(HValue* key) {
4509 map_.Remove(key, key->Hashcode());
4510 }
4511
4512
4513 // Recursive traversal of the dominator tree to remove array bounds checks.
4514 void HGraph::EliminateOrDehoistBoundsChecks(
4515 HBasicBlock* bb,
4516 BoundsCheckRemovalBlockContext* previous_context) {
4517 BoundsCheckRemovalBlockContext context(bb, previous_context);
4518
4519 // Add facts deduced from conditional branches.
4520 if (bb->predecessors()->length() == 1) {
4521 HBasicBlock* predecessor = bb->predecessors()->at(0);
4522 HInstruction* end = predecessor->last();
4523 if (end->IsCompareIDAndBranch()) {
4524 BoundsCheckValueInfo::FromConditionalBranch(
Jakob Kummerow 2012/12/05 15:20:02 Looks like "static void Foo::Bar(..., Baz*)" could
4525 HCompareIDAndBranch::cast(end), &context);
4526 }
4527 }
4528
4529 // Add facts deduced from phi definitions.
4530 for (int i = 0; i < bb->phis()->length(); i++) {
4531 BoundsCheckValueInfo::FromPhi(bb->phis()->at(i), &context);
Jakob Kummerow 2012/12/05 15:20:02 again, why "void A::B(C, &context)" instead of "co
4532 }
4533
4534 for (HInstruction* i = bb->first(); i != NULL; i = i->next()) {
4535 if (!i->IsBoundsCheck()) continue;
4536
4537 HBoundsCheck* check = HBoundsCheck::cast(i);
4538 check->ReplaceAllUsesWith(check->index());
Jakob Kummerow 2012/12/05 15:20:02 Why this line?
4539 BoundsCheckValueInfo::HandleCheck(check, &context);
Jakob Kummerow 2012/12/05 15:20:02 again, why "void A::B(C, &context)" instead of "co
4540 }
4541
4542 for (int i = 0; i < bb->dominated_blocks()->length(); ++i) {
4543 EliminateOrDehoistBoundsChecks(
4544 bb->dominated_blocks()->at(i), &context);
4545 }
4546
4547 for (BoundsCheckValueInfo* value_info = context.data_list_head();
4548 value_info != NULL;
Jakob Kummerow 2012/12/05 15:20:02 nit: aligning 'v' with 'B' looks better
4549 value_info = value_info->NextInBasicBlock()) {
4550 if (value_info->UnlinkFromValue()) {
4551 context.table()->CleanupKey(value_info->Value());
4552 }
4553 }
4554 }
4555
4556
4557 void HGraph::EliminateOrDehoistBoundsChecks() {
4558 HPhase phase("H_Eliminate or dehoist bounds checks", this);
4559 EliminateOrDehoistBoundsChecks(entry_block(), NULL);
4560 }
4561
4562
3673 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) { 4563 static void DehoistArrayIndex(ArrayInstructionInterface* array_operation) {
3674 HValue* index = array_operation->GetKey(); 4564 HValue* index = array_operation->GetKey();
3675 if (!index->representation().IsInteger32()) return; 4565 if (!index->representation().IsInteger32()) return;
3676 4566
3677 HConstant* constant; 4567 HConstant* constant;
3678 HValue* subexpression; 4568 HValue* subexpression;
3679 int32_t sign; 4569 int32_t sign;
3680 if (index->IsAdd()) { 4570 if (index->IsAdd()) {
3681 sign = 1; 4571 sign = 1;
3682 HAdd* add = HAdd::cast(index); 4572 HAdd* add = HAdd::cast(index);
(...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after
4296 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); 5186 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
4297 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); 5187 HBasicBlock* osr_entry = graph()->CreateBasicBlock();
4298 HValue* true_value = graph()->GetConstantTrue(); 5188 HValue* true_value = graph()->GetConstantTrue();
4299 HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry); 5189 HBranch* test = new(zone()) HBranch(true_value, non_osr_entry, osr_entry);
4300 current_block()->Finish(test); 5190 current_block()->Finish(test);
4301 5191
4302 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); 5192 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
4303 non_osr_entry->Goto(loop_predecessor); 5193 non_osr_entry->Goto(loop_predecessor);
4304 5194
4305 set_current_block(osr_entry); 5195 set_current_block(osr_entry);
5196 osr_entry->set_osr_entry();
4306 BailoutId osr_entry_id = statement->OsrEntryId(); 5197 BailoutId osr_entry_id = statement->OsrEntryId();
4307 int first_expression_index = environment()->first_expression_index(); 5198 int first_expression_index = environment()->first_expression_index();
4308 int length = environment()->length(); 5199 int length = environment()->length();
4309 ZoneList<HUnknownOSRValue*>* osr_values = 5200 ZoneList<HUnknownOSRValue*>* osr_values =
4310 new(zone()) ZoneList<HUnknownOSRValue*>(length, zone()); 5201 new(zone()) ZoneList<HUnknownOSRValue*>(length, zone());
4311 5202
4312 for (int i = 0; i < first_expression_index; ++i) { 5203 for (int i = 0; i < first_expression_index; ++i) {
4313 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue; 5204 HUnknownOSRValue* osr_value = new(zone()) HUnknownOSRValue;
4314 AddInstruction(osr_value); 5205 AddInstruction(osr_value);
4315 environment()->Bind(i, osr_value); 5206 environment()->Bind(i, osr_value);
(...skipping 5743 matching lines...) Expand 10 before | Expand all | Expand 10 after
10059 } 10950 }
10060 } 10951 }
10061 10952
10062 #ifdef DEBUG 10953 #ifdef DEBUG
10063 if (graph_ != NULL) graph_->Verify(false); // No full verify. 10954 if (graph_ != NULL) graph_->Verify(false); // No full verify.
10064 if (allocator_ != NULL) allocator_->Verify(); 10955 if (allocator_ != NULL) allocator_->Verify();
10065 #endif 10956 #endif
10066 } 10957 }
10067 10958
10068 } } // namespace v8::internal 10959 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698