Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/escape-analysis-reducer.h" | 5 #include "src/compiler/escape-analysis-reducer.h" |
| 6 | 6 |
| 7 #include "src/compiler/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
| 8 #include "src/counters.h" | 8 #include "src/counters.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 case IrOpcode::kStoreElement: | 29 case IrOpcode::kStoreElement: |
| 30 return ReduceStore(node); | 30 return ReduceStore(node); |
| 31 case IrOpcode::kAllocate: | 31 case IrOpcode::kAllocate: |
| 32 return ReduceAllocate(node); | 32 return ReduceAllocate(node); |
| 33 case IrOpcode::kFinishRegion: | 33 case IrOpcode::kFinishRegion: |
| 34 return ReduceFinishRegion(node); | 34 return ReduceFinishRegion(node); |
| 35 case IrOpcode::kReferenceEqual: | 35 case IrOpcode::kReferenceEqual: |
| 36 return ReduceReferenceEqual(node); | 36 return ReduceReferenceEqual(node); |
| 37 case IrOpcode::kObjectIsSmi: | 37 case IrOpcode::kObjectIsSmi: |
| 38 return ReduceObjectIsSmi(node); | 38 return ReduceObjectIsSmi(node); |
| 39 case IrOpcode::kStateValues: | |
| 40 case IrOpcode::kFrameState: | |
| 41 return ReplaceWithDeoptDummy(node); | |
| 42 default: | 39 default: |
| 40 if (node->op()->EffectInputCount() > 0) { | |
|
Jarin
2016/01/05 12:51:19
As discussed offline, this serves as an over-appro
sigurds
2016/01/05 13:08:57
Done.
| |
| 41 return ReduceFrameStateUses(node); | |
| 42 } | |
| 43 break; | 43 break; |
| 44 } | 44 } |
| 45 return NoChange(); | 45 return NoChange(); |
| 46 } | 46 } |
| 47 | 47 |
| 48 | 48 |
| 49 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) { | 49 Reduction EscapeAnalysisReducer::ReduceLoad(Node* node) { |
| 50 DCHECK(node->opcode() == IrOpcode::kLoadField || | 50 DCHECK(node->opcode() == IrOpcode::kLoadField || |
| 51 node->opcode() == IrOpcode::kLoadElement); | 51 node->opcode() == IrOpcode::kLoadElement); |
| 52 if (Node* rep = escape_analysis()->GetReplacement(node)) { | 52 if (Node* rep = escape_analysis()->GetReplacement(node)) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 118 } | 118 } |
| 119 return NoChange(); | 119 return NoChange(); |
| 120 } | 120 } |
| 121 | 121 |
| 122 | 122 |
| 123 Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) { | 123 Reduction EscapeAnalysisReducer::ReduceReferenceEqual(Node* node) { |
| 124 DCHECK_EQ(node->opcode(), IrOpcode::kReferenceEqual); | 124 DCHECK_EQ(node->opcode(), IrOpcode::kReferenceEqual); |
| 125 Node* left = NodeProperties::GetValueInput(node, 0); | 125 Node* left = NodeProperties::GetValueInput(node, 0); |
| 126 Node* right = NodeProperties::GetValueInput(node, 1); | 126 Node* right = NodeProperties::GetValueInput(node, 1); |
| 127 if (escape_analysis()->IsVirtual(left)) { | 127 if (escape_analysis()->IsVirtual(left)) { |
| 128 if (escape_analysis()->IsVirtual(right)) { | 128 if (escape_analysis()->IsVirtual(right) && |
| 129 if (Node* rep = escape_analysis()->GetReplacement(left)) { | 129 escape_analysis()->CompareVirtualObjects(left, right)) { |
| 130 left = rep; | 130 ReplaceWithValue(node, jsgraph()->TrueConstant()); |
| 131 } | 131 if (FLAG_trace_turbo_escape) { |
| 132 if (Node* rep = escape_analysis()->GetReplacement(right)) { | 132 PrintF("Replaced ref eq #%d with true\n", node->id()); |
| 133 right = rep; | |
| 134 } | |
| 135 // TODO(sigurds): What to do if either is a PHI? | |
| 136 if (left == right) { | |
| 137 ReplaceWithValue(node, jsgraph()->TrueConstant()); | |
| 138 if (FLAG_trace_turbo_escape) { | |
| 139 PrintF("Replaced ref eq #%d with true\n", node->id()); | |
| 140 } | |
| 141 return Replace(node); | |
| 142 } | 133 } |
| 143 } | 134 } |
| 144 // Right-hand side is either not virtual, or a different node. | 135 // Right-hand side is not a virtual object, or a different one. |
| 145 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 136 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
| 146 if (FLAG_trace_turbo_escape) { | 137 if (FLAG_trace_turbo_escape) { |
| 147 PrintF("Replaced ref eq #%d with false\n", node->id()); | 138 PrintF("Replaced ref eq #%d with false\n", node->id()); |
| 148 } | 139 } |
| 149 return Replace(node); | 140 return Replace(node); |
| 150 } else if (escape_analysis()->IsVirtual(right)) { | 141 } else if (escape_analysis()->IsVirtual(right)) { |
| 151 // Left-hand side is not a virtual object. | 142 // Left-hand side is not a virtual object. |
| 152 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 143 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
| 153 if (FLAG_trace_turbo_escape) { | 144 if (FLAG_trace_turbo_escape) { |
| 154 PrintF("Replaced ref eq #%d with false\n", node->id()); | 145 PrintF("Replaced ref eq #%d with false\n", node->id()); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 165 ReplaceWithValue(node, jsgraph()->FalseConstant()); | 156 ReplaceWithValue(node, jsgraph()->FalseConstant()); |
| 166 if (FLAG_trace_turbo_escape) { | 157 if (FLAG_trace_turbo_escape) { |
| 167 PrintF("Replaced ObjectIsSmi #%d with false\n", node->id()); | 158 PrintF("Replaced ObjectIsSmi #%d with false\n", node->id()); |
| 168 } | 159 } |
| 169 return Replace(node); | 160 return Replace(node); |
| 170 } | 161 } |
| 171 return NoChange(); | 162 return NoChange(); |
| 172 } | 163 } |
| 173 | 164 |
| 174 | 165 |
| 175 // TODO(sigurds): This is a temporary solution until escape analysis | 166 Reduction EscapeAnalysisReducer::ReduceFrameStateUses(Node* node) { |
| 176 // supports deoptimization. | 167 DCHECK_GE(node->op()->EffectInputCount(), 1); |
| 177 Reduction EscapeAnalysisReducer::ReplaceWithDeoptDummy(Node* node) { | 168 bool changed = false; |
| 178 DCHECK(node->opcode() == IrOpcode::kStateValues || | 169 for (int i = 0; i < node->InputCount(); ++i) { |
| 179 node->opcode() == IrOpcode::kFrameState); | 170 Node* input = node->InputAt(i); |
| 180 Reduction r = NoChange(); | 171 if (input->opcode() == IrOpcode::kFrameState) { |
| 181 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 172 if (Node* ret = ReduceFrameState(input, node, false)) { |
| 182 Node* input = NodeProperties::GetValueInput(node, i); | 173 node->ReplaceInput(i, ret); |
| 183 if (input->opcode() == IrOpcode::kFinishRegion || | 174 changed = true; |
| 184 input->opcode() == IrOpcode::kAllocate || | |
| 185 input->opcode() == IrOpcode::kPhi) { | |
| 186 if (escape_analysis()->IsVirtual(input)) { | |
| 187 NodeProperties::ReplaceValueInput(node, jsgraph()->UndefinedConstant(), | |
| 188 i); | |
| 189 if (FLAG_trace_turbo_escape) { | |
| 190 PrintF("Replaced state value (#%d) input with dummy\n", node->id()); | |
| 191 } | |
| 192 r = Changed(node); | |
| 193 } | 175 } |
| 194 } | 176 } |
| 195 } | 177 } |
| 196 return r; | 178 if (changed) { |
| 179 return Changed(node); | |
| 180 } | |
| 181 return NoChange(); | |
| 197 } | 182 } |
| 198 | 183 |
| 199 | 184 |
| 185 Node* EscapeAnalysisReducer::ReduceFrameState(Node* node, Node* effect, | |
| 186 bool multiple_users) { | |
| 187 DCHECK(node->opcode() == IrOpcode::kFrameState); | |
| 188 if (FLAG_trace_turbo_escape) { | |
| 189 PrintF("Reducing FrameState %d\n", node->id()); | |
| 190 } | |
| 191 Node* clone = nullptr; | |
| 192 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | |
| 193 Node* input = NodeProperties::GetValueInput(node, i); | |
| 194 Node* ret = | |
| 195 input->opcode() == IrOpcode::kStateValues | |
| 196 ? ReduceStateValueInputs(input, effect, node->UseCount() > 1) | |
| 197 : ReduceStateValueInput(node, i, effect, node->UseCount() > 1); | |
| 198 if (ret) { | |
| 199 if (node->UseCount() > 1 || multiple_users) { | |
| 200 if (FLAG_trace_turbo_escape) { | |
| 201 PrintF(" Cloning #%d", node->id()); | |
| 202 } | |
| 203 node = clone = jsgraph()->graph()->CloneNode(node); | |
| 204 if (FLAG_trace_turbo_escape) { | |
| 205 PrintF(" to #%d\n", node->id()); | |
| 206 } | |
| 207 multiple_users = false; // Don't clone anymore. | |
| 208 } | |
| 209 NodeProperties::ReplaceValueInput(node, ret, i); | |
| 210 } | |
| 211 } | |
| 212 Node* outer_frame_state = NodeProperties::GetFrameStateInput(node, 0); | |
| 213 if (outer_frame_state->opcode() == IrOpcode::kFrameState) { | |
| 214 if (Node* ret = | |
| 215 ReduceFrameState(outer_frame_state, effect, node->UseCount() > 1)) { | |
| 216 if (node->UseCount() > 1 || multiple_users) { | |
| 217 if (FLAG_trace_turbo_escape) { | |
| 218 PrintF(" Cloning #%d", node->id()); | |
| 219 } | |
| 220 node = clone = jsgraph()->graph()->CloneNode(node); | |
| 221 if (FLAG_trace_turbo_escape) { | |
| 222 PrintF(" to #%d\n", node->id()); | |
| 223 } | |
| 224 multiple_users = false; | |
| 225 } | |
| 226 NodeProperties::ReplaceFrameStateInput(node, 0, ret); | |
| 227 } | |
| 228 } | |
| 229 return clone; | |
| 230 } | |
| 231 | |
| 232 | |
| 233 Node* EscapeAnalysisReducer::ReduceStateValueInputs(Node* node, Node* effect, | |
| 234 bool multiple_users) { | |
| 235 if (FLAG_trace_turbo_escape) { | |
| 236 PrintF("Reducing StateValue #%d\n", node->id()); | |
| 237 } | |
| 238 DCHECK(node->opcode() == IrOpcode::kStateValues); | |
| 239 DCHECK_NOT_NULL(effect); | |
| 240 Node* clone = nullptr; | |
| 241 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | |
| 242 if (Node* ret = ReduceStateValueInput(node, i, effect, multiple_users)) { | |
| 243 node = ret; | |
| 244 DCHECK_NULL(clone); | |
| 245 clone = ret; | |
| 246 multiple_users = false; | |
| 247 } | |
| 248 } | |
| 249 return clone; | |
| 250 } | |
| 251 | |
| 252 | |
| 253 // Return the clone if it duplicated the node, and null otherwise. | |
|
Jarin
2016/01/05 12:51:19
Maybe you want to add the same comment to the meth
sigurds
2016/01/05 13:08:57
Done.
| |
| 254 Node* EscapeAnalysisReducer::ReduceStateValueInput(Node* node, int node_index, | |
| 255 Node* effect, | |
| 256 bool multiple_users) { | |
| 257 Node* input = NodeProperties::GetValueInput(node, node_index); | |
| 258 if (FLAG_trace_turbo_escape) { | |
| 259 PrintF("Reducing State Input #%d (%s)\n", input->id(), | |
| 260 input->op()->mnemonic()); | |
| 261 } | |
| 262 Node* clone = nullptr; | |
| 263 if (input->opcode() == IrOpcode::kFinishRegion || | |
| 264 input->opcode() == IrOpcode::kAllocate) { | |
| 265 if (escape_analysis()->IsVirtual(input)) { | |
| 266 if (Node* object_state = | |
| 267 escape_analysis()->GetOrCreateObjectState(effect, input)) { | |
| 268 if (node->UseCount() > 1 || multiple_users) { | |
| 269 if (FLAG_trace_turbo_escape) { | |
| 270 PrintF("Cloning #%d", node->id()); | |
| 271 } | |
| 272 node = clone = jsgraph()->graph()->CloneNode(node); | |
| 273 if (FLAG_trace_turbo_escape) { | |
| 274 PrintF(" to #%d\n", node->id()); | |
| 275 } | |
| 276 } | |
| 277 NodeProperties::ReplaceValueInput(node, object_state, node_index); | |
| 278 if (FLAG_trace_turbo_escape) { | |
| 279 PrintF("Replaced state #%d input #%d with object state #%d\n", | |
| 280 node->id(), input->id(), object_state->id()); | |
| 281 } | |
| 282 } else { | |
| 283 if (FLAG_trace_turbo_escape) { | |
| 284 PrintF("No object state replacement available.\n"); | |
| 285 } | |
| 286 } | |
| 287 } | |
| 288 } | |
| 289 return clone; | |
| 290 } | |
| 291 | |
| 200 } // namespace compiler | 292 } // namespace compiler |
| 201 } // namespace internal | 293 } // namespace internal |
| 202 } // namespace v8 | 294 } // namespace v8 |
| OLD | NEW |