Chromium Code Reviews| 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->transition().is_null()) { | |
| 180 // TODO(mstarzinger): Handle dereference is actually not allowed | |
| 181 // here. Fix this by allocating the HConstant at graph building. | |
| 182 AllowHandleDereference allow_deref; | |
| 183 Zone* graph_zone = graph()->zone(); | |
| 184 HConstant* map = new(graph_zone) HConstant(store->transition()); | |
| 185 map->FinalizeUniqueValueId(); | |
| 186 map->InsertBefore(store); | |
| 187 state->SetOperandAt(0, map); | |
| 188 } | |
| 189 store->DeleteAndReplaceWith(NULL); | |
| 190 if (FLAG_trace_escape_analysis) { | |
| 191 PrintF("Replacing store #%d%s\n", instr->id(), | |
| 192 store->transition().is_null() ? "" : " (with transition)"); | |
| 193 } | |
| 194 break; | |
| 195 } | |
| 196 case HValue::kSimulate: { | |
| 197 HSimulate* simulate = HSimulate::cast(instr); | |
| 198 // TODO(mstarzinger): This doesn't track deltas for values on the | |
| 199 // operand stack yet. Find a repro test case and fix this. | |
| 200 for (int i = 0; i < simulate->OperandCount(); i++) { | |
| 201 if (simulate->OperandAt(i) != allocate) continue; | |
| 202 simulate->SetOperandAt(i, state); | |
| 203 } | |
| 204 break; | |
| 205 } | |
| 206 case HValue::kArgumentsObject: | |
| 207 case HValue::kCapturedObject: { | |
| 208 for (int i = 0; i < instr->OperandCount(); i++) { | |
| 209 if (instr->OperandAt(i) != allocate) continue; | |
| 210 instr->SetOperandAt(i, state); | |
| 211 } | |
| 212 break; | |
| 213 } | |
| 214 case HValue::kCheckHeapObject: { | |
| 215 HCheckHeapObject* check = HCheckHeapObject::cast(instr); | |
| 216 if (check->value() != allocate) continue; | |
| 217 check->DeleteAndReplaceWith(NULL); | |
| 218 break; | |
| 219 } | |
| 220 case HValue::kCheckMaps: { | |
| 221 HCheckMaps* mapcheck = HCheckMaps::cast(instr); | |
| 222 if (mapcheck->value() != allocate) continue; | |
| 223 // TODO(mstarzinger): This approach breaks if the tracked map value | |
| 224 // is not a HConstant. Find a repro test case and fix this. | |
|
titzer
2013/08/06 12:15:47
Could it be the case that a later load or store st
Michael Starzinger
2013/08/07 10:51:16
Yes, this could unfortunately happen. We cannot en
| |
| 225 ASSERT(mapcheck->HasNoUses()); | |
| 226 mapcheck->DeleteAndReplaceWith(NULL); | |
| 227 break; | |
| 228 } | |
| 229 default: | |
| 230 // Nothing to see here, move along ... | |
| 231 break; | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 // Propagate the block state forward to all successor blocks. | |
| 236 for (int i = 0; i < block->end()->SuccessorCount(); i++) { | |
| 237 HBasicBlock* succ = block->end()->SuccessorAt(i); | |
| 238 if (!allocate_block->Dominates(succ)) continue; | |
| 239 if (succ->predecessors()->length() == 1) { | |
| 240 // Case 1: This is the only predecessor, just reuse state. | |
| 241 SetStateAt(succ, state); | |
| 242 } else if (StateAt(succ) == NULL && succ->IsLoopHeader()) { | |
| 243 // Case 2: This is a state that enters a loop header, be | |
| 244 // pessimistic about loop headers, add phis for all values. | |
| 245 SetStateAt(succ, NewStateForLoopHeader(succ->first(), state)); | |
| 246 } else if (StateAt(succ) == NULL) { | |
| 247 // Case 3: This is the first state propagated forward to the | |
| 248 // successor, leave a copy of the current state. | |
| 249 SetStateAt(succ, NewStateCopy(succ->first(), state)); | |
| 250 } else { | |
| 251 // Case 4: This is a state that needs merging with previously | |
| 252 // propagated states, potentially introducing new phis lazily or | |
| 253 // adding values to existing phis. | |
| 254 HCapturedObject* succ_state = StateAt(succ); | |
| 255 for (int index = 0; index < number_of_values_; index++) { | |
| 256 HValue* operand = state->OperandAt(index); | |
| 257 HValue* succ_operand = succ_state->OperandAt(index); | |
| 258 if (succ_operand->IsPhi() && succ_operand->block() == succ) { | |
| 259 // Phi already exists, add operand. | |
| 260 HPhi* phi = HPhi::cast(succ_operand); | |
| 261 phi->SetOperandAt(succ->PredecessorIndexOf(block), operand); | |
| 262 } else if (succ_operand != operand) { | |
| 263 // Phi does not exist, introduce one. | |
| 264 HPhi* phi = NewPhiAndInsert(succ, succ_operand, index); | |
| 265 phi->SetOperandAt(succ->PredecessorIndexOf(block), operand); | |
| 266 succ_state->SetOperandAt(index, phi); | |
| 267 } | |
| 268 } | |
| 269 } | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 // All uses have been handled. | |
| 274 ASSERT(allocate->HasNoUses()); | |
| 275 allocate->DeleteAndReplaceWith(NULL); | |
| 276 } | |
| 277 | |
| 278 | |
| 279 void HEscapeAnalysisPhase::PerformScalarReplacement() { | |
| 280 for (int i = 0; i < captured_.length(); i++) { | |
| 281 HAllocate* allocate = HAllocate::cast(captured_.at(i)); | |
| 282 | |
| 283 // Compute number of scalar values and start with clean slate. | |
| 284 if (!allocate->size()->IsInteger32Constant()) continue; | |
| 285 int size_in_bytes = allocate->size()->GetInteger32Constant(); | |
| 286 number_of_values_ = size_in_bytes / kPointerSize; | |
| 287 block_states_.Clear(); | |
| 288 | |
| 289 // Perform actual analysis steps. | |
| 290 AnalyzeDataFlow(allocate); | |
| 291 | |
| 292 cumulative_values_ += number_of_values_; | |
| 293 ASSERT(allocate->HasNoUses()); | |
| 294 ASSERT(!allocate->IsLinked()); | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 | |
| 66 } } // namespace v8::internal | 299 } } // namespace v8::internal |
| OLD | NEW |