OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | 56 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
57 HInstruction* instr = it.Current(); | 57 HInstruction* instr = it.Current(); |
58 if (instr->IsAllocate()) { | 58 if (instr->IsAllocate()) { |
59 CollectIfNoEscapingUses(instr); | 59 CollectIfNoEscapingUses(instr); |
60 } | 60 } |
61 } | 61 } |
62 } | 62 } |
63 } | 63 } |
64 | 64 |
65 | 65 |
| 66 HCapturedObject* HEscapeAnalysisPhase::NewState(HInstruction* previous) { |
| 67 Zone* zone = graph()->zone(); |
| 68 HCapturedObject* state = new(zone) HCapturedObject(number_of_values_, zone); |
| 69 state->InsertAfter(previous); |
| 70 return state; |
| 71 } |
| 72 |
| 73 |
| 74 // Create a new state for replacing HAllocate instructions. |
| 75 HCapturedObject* HEscapeAnalysisPhase::NewStateForAllocation( |
| 76 HInstruction* previous) { |
| 77 HConstant* undefined = graph()->GetConstantUndefined(); |
| 78 HCapturedObject* state = NewState(previous); |
| 79 for (int index = 0; index < number_of_values_; index++) { |
| 80 state->SetOperandAt(index, undefined); |
| 81 } |
| 82 return state; |
| 83 } |
| 84 |
| 85 |
| 86 // Create a new state full of phis for loop header entries. |
| 87 HCapturedObject* HEscapeAnalysisPhase::NewStateForLoopHeader( |
| 88 HInstruction* previous, HCapturedObject* old_state) { |
| 89 HBasicBlock* block = previous->block(); |
| 90 HCapturedObject* state = NewState(previous); |
| 91 for (int index = 0; index < number_of_values_; index++) { |
| 92 HValue* operand = old_state->OperandAt(index); |
| 93 HPhi* phi = NewPhiAndInsert(block, operand, index); |
| 94 state->SetOperandAt(index, phi); |
| 95 } |
| 96 return state; |
| 97 } |
| 98 |
| 99 |
| 100 // Create a new state by copying an existing one. |
| 101 HCapturedObject* HEscapeAnalysisPhase::NewStateCopy( |
| 102 HInstruction* previous, HCapturedObject* old_state) { |
| 103 HCapturedObject* state = NewState(previous); |
| 104 for (int index = 0; index < number_of_values_; index++) { |
| 105 HValue* operand = old_state->OperandAt(index); |
| 106 state->SetOperandAt(index, operand); |
| 107 } |
| 108 return state; |
| 109 } |
| 110 |
| 111 |
| 112 // Insert a newly created phi into the given block and fill all incoming |
| 113 // edges with the given value. The merge index is chosen so that it is |
| 114 // unique for this particular scalar replacement index. |
| 115 HPhi* HEscapeAnalysisPhase::NewPhiAndInsert( |
| 116 HBasicBlock* block, HValue* incoming_value, int index) { |
| 117 Zone* zone = graph()->zone(); |
| 118 HBasicBlock* pred = block->predecessors()->first(); |
| 119 int phi_index = pred->last_environment()->length() + cumulative_values_; |
| 120 HPhi* phi = new(zone) HPhi(phi_index + index, zone); |
| 121 for (int i = 0; i < block->predecessors()->length(); i++) { |
| 122 phi->AddInput(incoming_value); |
| 123 } |
| 124 block->AddPhi(phi); |
| 125 return phi; |
| 126 } |
| 127 |
| 128 |
| 129 // Performs a forward data-flow analysis of all loads and stores on the |
| 130 // given captured allocation. This uses a reverse post-order iteration |
| 131 // over affected basic blocks. All non-escaping instructions are handled |
| 132 // and replaced during the analysis. |
| 133 void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) { |
| 134 HBasicBlock* allocate_block = allocate->block(); |
| 135 block_states_.AddBlock(NULL, graph()->blocks()->length(), zone()); |
| 136 |
| 137 // Iterate all blocks starting with the allocation block, since the |
| 138 // allocation cannot dominate blocks that come before. |
| 139 int start = allocate_block->block_id(); |
| 140 for (int i = start; i < graph()->blocks()->length(); i++) { |
| 141 HBasicBlock* block = graph()->blocks()->at(i); |
| 142 HCapturedObject* state = StateAt(block); |
| 143 |
| 144 // Skip blocks that are not dominated by the captured allocation. |
| 145 if (!allocate_block->Dominates(block) && allocate_block != block) continue; |
| 146 if (FLAG_trace_escape_analysis) { |
| 147 PrintF("Analyzing data-flow in B%d\n", block->block_id()); |
| 148 } |
| 149 |
| 150 // Go through all instructions of the current block. |
| 151 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 152 HInstruction* instr = it.Current(); |
| 153 switch (instr->opcode()) { |
| 154 case HValue::kAllocate: { |
| 155 if (instr != allocate) continue; |
| 156 state = NewStateForAllocation(allocate); |
| 157 break; |
| 158 } |
| 159 case HValue::kLoadNamedField: { |
| 160 HLoadNamedField* load = HLoadNamedField::cast(instr); |
| 161 int index = load->access().offset() / kPointerSize; |
| 162 if (load->object() != allocate) continue; |
| 163 ASSERT(load->access().IsInobject()); |
| 164 HValue* replacement = state->OperandAt(index); |
| 165 load->DeleteAndReplaceWith(replacement); |
| 166 if (FLAG_trace_escape_analysis) { |
| 167 PrintF("Replacing load #%d with #%d (%s)\n", instr->id(), |
| 168 replacement->id(), replacement->Mnemonic()); |
| 169 } |
| 170 break; |
| 171 } |
| 172 case HValue::kStoreNamedField: { |
| 173 HStoreNamedField* store = HStoreNamedField::cast(instr); |
| 174 int index = store->access().offset() / kPointerSize; |
| 175 if (store->object() != allocate) continue; |
| 176 ASSERT(store->access().IsInobject()); |
| 177 state = NewStateCopy(store, state); |
| 178 state->SetOperandAt(index, store->value()); |
| 179 if (store->has_transition()) { |
| 180 state->SetOperandAt(0, store->transition()); |
| 181 } |
| 182 store->DeleteAndReplaceWith(NULL); |
| 183 if (FLAG_trace_escape_analysis) { |
| 184 PrintF("Replacing store #%d%s\n", instr->id(), |
| 185 store->has_transition() ? " (with transition)" : ""); |
| 186 } |
| 187 break; |
| 188 } |
| 189 case HValue::kSimulate: { |
| 190 HSimulate* simulate = HSimulate::cast(instr); |
| 191 // TODO(mstarzinger): This doesn't track deltas for values on the |
| 192 // operand stack yet. Find a repro test case and fix this. |
| 193 for (int i = 0; i < simulate->OperandCount(); i++) { |
| 194 if (simulate->OperandAt(i) != allocate) continue; |
| 195 simulate->SetOperandAt(i, state); |
| 196 } |
| 197 break; |
| 198 } |
| 199 case HValue::kArgumentsObject: |
| 200 case HValue::kCapturedObject: { |
| 201 for (int i = 0; i < instr->OperandCount(); i++) { |
| 202 if (instr->OperandAt(i) != allocate) continue; |
| 203 instr->SetOperandAt(i, state); |
| 204 } |
| 205 break; |
| 206 } |
| 207 case HValue::kCheckHeapObject: { |
| 208 HCheckHeapObject* check = HCheckHeapObject::cast(instr); |
| 209 if (check->value() != allocate) continue; |
| 210 check->DeleteAndReplaceWith(NULL); |
| 211 break; |
| 212 } |
| 213 case HValue::kCheckMaps: { |
| 214 HCheckMaps* mapcheck = HCheckMaps::cast(instr); |
| 215 if (mapcheck->value() != allocate) continue; |
| 216 // TODO(mstarzinger): This approach breaks if the tracked map value |
| 217 // is not a HConstant. Find a repro test case and fix this. |
| 218 ASSERT(mapcheck->HasNoUses()); |
| 219 mapcheck->DeleteAndReplaceWith(NULL); |
| 220 break; |
| 221 } |
| 222 default: |
| 223 // Nothing to see here, move along ... |
| 224 break; |
| 225 } |
| 226 } |
| 227 |
| 228 // Propagate the block state forward to all successor blocks. |
| 229 for (int i = 0; i < block->end()->SuccessorCount(); i++) { |
| 230 HBasicBlock* succ = block->end()->SuccessorAt(i); |
| 231 if (!allocate_block->Dominates(succ)) continue; |
| 232 if (succ->predecessors()->length() == 1) { |
| 233 // Case 1: This is the only predecessor, just reuse state. |
| 234 SetStateAt(succ, state); |
| 235 } else if (StateAt(succ) == NULL && succ->IsLoopHeader()) { |
| 236 // Case 2: This is a state that enters a loop header, be |
| 237 // pessimistic about loop headers, add phis for all values. |
| 238 SetStateAt(succ, NewStateForLoopHeader(succ->first(), state)); |
| 239 } else if (StateAt(succ) == NULL) { |
| 240 // Case 3: This is the first state propagated forward to the |
| 241 // successor, leave a copy of the current state. |
| 242 SetStateAt(succ, NewStateCopy(succ->first(), state)); |
| 243 } else { |
| 244 // Case 4: This is a state that needs merging with previously |
| 245 // propagated states, potentially introducing new phis lazily or |
| 246 // adding values to existing phis. |
| 247 HCapturedObject* succ_state = StateAt(succ); |
| 248 for (int index = 0; index < number_of_values_; index++) { |
| 249 HValue* operand = state->OperandAt(index); |
| 250 HValue* succ_operand = succ_state->OperandAt(index); |
| 251 if (succ_operand->IsPhi() && succ_operand->block() == succ) { |
| 252 // Phi already exists, add operand. |
| 253 HPhi* phi = HPhi::cast(succ_operand); |
| 254 phi->SetOperandAt(succ->PredecessorIndexOf(block), operand); |
| 255 } else if (succ_operand != operand) { |
| 256 // Phi does not exist, introduce one. |
| 257 HPhi* phi = NewPhiAndInsert(succ, succ_operand, index); |
| 258 phi->SetOperandAt(succ->PredecessorIndexOf(block), operand); |
| 259 succ_state->SetOperandAt(index, phi); |
| 260 } |
| 261 } |
| 262 } |
| 263 } |
| 264 } |
| 265 |
| 266 // All uses have been handled. |
| 267 ASSERT(allocate->HasNoUses()); |
| 268 allocate->DeleteAndReplaceWith(NULL); |
| 269 } |
| 270 |
| 271 |
| 272 void HEscapeAnalysisPhase::PerformScalarReplacement() { |
| 273 for (int i = 0; i < captured_.length(); i++) { |
| 274 HAllocate* allocate = HAllocate::cast(captured_.at(i)); |
| 275 |
| 276 // Compute number of scalar values and start with clean slate. |
| 277 if (!allocate->size()->IsInteger32Constant()) continue; |
| 278 int size_in_bytes = allocate->size()->GetInteger32Constant(); |
| 279 number_of_values_ = size_in_bytes / kPointerSize; |
| 280 block_states_.Clear(); |
| 281 |
| 282 // Perform actual analysis steps. |
| 283 AnalyzeDataFlow(allocate); |
| 284 |
| 285 cumulative_values_ += number_of_values_; |
| 286 ASSERT(allocate->HasNoUses()); |
| 287 ASSERT(!allocate->IsLinked()); |
| 288 } |
| 289 } |
| 290 |
| 291 |
66 } } // namespace v8::internal | 292 } } // namespace v8::internal |
OLD | NEW |