| 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/js-call-reducer.h" | 5 #include "src/compiler/js-call-reducer.h" |
| 6 | 6 |
| 7 #include "src/compiler/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
| 8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
| 9 #include "src/objects-inl.h" | 9 #include "src/objects-inl.h" |
| 10 #include "src/type-feedback-vector-inl.h" | 10 #include "src/type-feedback-vector-inl.h" |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 // TODO(bmeurer): Also support optimizing bound functions and proxies here. | 245 // TODO(bmeurer): Also support optimizing bound functions and proxies here. |
| 246 return NoChange(); | 246 return NoChange(); |
| 247 } | 247 } |
| 248 | 248 |
| 249 // Not much we can do if deoptimization support is disabled. | 249 // Not much we can do if deoptimization support is disabled. |
| 250 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 250 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
| 251 | 251 |
| 252 // Extract feedback from the {node} using the CallICNexus. | 252 // Extract feedback from the {node} using the CallICNexus. |
| 253 if (!p.feedback().IsValid()) return NoChange(); | 253 if (!p.feedback().IsValid()) return NoChange(); |
| 254 CallICNexus nexus(p.feedback().vector(), p.feedback().slot()); | 254 CallICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
| 255 Handle<Object> feedback(nexus.GetFeedback(), isolate()); | 255 Handle<Object> feedback = nexus.GetCallFeedback(); |
| 256 if (feedback->IsAllocationSite()) { | 256 if (feedback->IsAllocationSite()) { |
| 257 // Retrieve the Array function from the {node}. | 257 // Retrieve the Array function from the {node}. |
| 258 Node* array_function; | 258 Node* array_function; |
| 259 Handle<Context> native_context; | 259 Handle<Context> native_context; |
| 260 if (GetNativeContext(node).ToHandle(&native_context)) { | 260 if (GetNativeContext(node).ToHandle(&native_context)) { |
| 261 array_function = jsgraph()->HeapConstant( | 261 array_function = jsgraph()->HeapConstant( |
| 262 handle(native_context->array_function(), isolate())); | 262 handle(native_context->array_function(), isolate())); |
| 263 } else { | 263 } else { |
| 264 Node* native_context = effect = graph()->NewNode( | 264 Node* native_context = effect = graph()->NewNode( |
| 265 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), | 265 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true), |
| (...skipping 14 matching lines...) Expand all Loading... |
| 280 graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_false); | 280 graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_false); |
| 281 // TODO(bmeurer): This should be on the AdvancedReducer somehow. | 281 // TODO(bmeurer): This should be on the AdvancedReducer somehow. |
| 282 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); | 282 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |
| 283 control = graph()->NewNode(common()->IfTrue(), branch); | 283 control = graph()->NewNode(common()->IfTrue(), branch); |
| 284 | 284 |
| 285 // Turn the {node} into a {JSCreateArray} call. | 285 // Turn the {node} into a {JSCreateArray} call. |
| 286 NodeProperties::ReplaceValueInput(node, array_function, 0); | 286 NodeProperties::ReplaceValueInput(node, array_function, 0); |
| 287 NodeProperties::ReplaceEffectInput(node, effect); | 287 NodeProperties::ReplaceEffectInput(node, effect); |
| 288 NodeProperties::ReplaceControlInput(node, control); | 288 NodeProperties::ReplaceControlInput(node, control); |
| 289 return ReduceArrayConstructor(node); | 289 return ReduceArrayConstructor(node); |
| 290 } else if (feedback->IsWeakCell()) { | 290 } else if (feedback->IsJSFunction()) { |
| 291 Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback); | 291 Node* target_function = jsgraph()->Constant(feedback); |
| 292 if (cell->value()->IsJSFunction()) { | |
| 293 Node* target_function = | |
| 294 jsgraph()->Constant(handle(cell->value(), isolate())); | |
| 295 | 292 |
| 296 // Check that the {target} is still the {target_function}. | 293 // Check that the {target} is still the {target_function}. |
| 297 Node* check = effect = | 294 Node* check = effect = |
| 298 graph()->NewNode(javascript()->StrictEqual(), target, target_function, | 295 graph()->NewNode(javascript()->StrictEqual(), target, target_function, |
| 299 context, effect, control); | 296 context, effect, control); |
| 300 Node* branch = | 297 Node* branch = |
| 301 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); | 298 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 302 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); | 299 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 303 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, | 300 Node* deoptimize = |
| 304 effect, if_false); | 301 graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_false); |
| 305 // TODO(bmeurer): This should be on the AdvancedReducer somehow. | 302 // TODO(bmeurer): This should be on the AdvancedReducer somehow. |
| 306 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); | 303 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |
| 307 control = graph()->NewNode(common()->IfTrue(), branch); | 304 control = graph()->NewNode(common()->IfTrue(), branch); |
| 308 | 305 |
| 309 // Specialize the JSCallFunction node to the {target_function}. | 306 // Specialize the JSCallFunction node to the {target_function}. |
| 310 NodeProperties::ReplaceValueInput(node, target_function, 0); | 307 NodeProperties::ReplaceValueInput(node, target_function, 0); |
| 311 NodeProperties::ReplaceEffectInput(node, effect); | 308 NodeProperties::ReplaceEffectInput(node, effect); |
| 312 NodeProperties::ReplaceControlInput(node, control); | 309 NodeProperties::ReplaceControlInput(node, control); |
| 313 | 310 |
| 314 // Try to further reduce the JSCallFunction {node}. | 311 // Try to further reduce the JSCallFunction {node}. |
| 315 Reduction const reduction = ReduceJSCallFunction(node); | 312 Reduction const reduction = ReduceJSCallFunction(node); |
| 316 return reduction.Changed() ? reduction : Changed(node); | 313 return reduction.Changed() ? reduction : Changed(node); |
| 317 } | |
| 318 } | 314 } |
| 319 return NoChange(); | 315 return NoChange(); |
| 320 } | 316 } |
| 321 | 317 |
| 322 | 318 |
| 323 Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) { | 319 Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) { |
| 324 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode()); | 320 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode()); |
| 325 CallConstructParameters const& p = CallConstructParametersOf(node->op()); | 321 CallConstructParameters const& p = CallConstructParametersOf(node->op()); |
| 326 DCHECK_LE(2u, p.arity()); | 322 DCHECK_LE(2u, p.arity()); |
| 327 int const arity = static_cast<int>(p.arity() - 2); | 323 int const arity = static_cast<int>(p.arity() - 2); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 | 374 |
| 379 // Don't mess with other {node}s that have a constant {target}. | 375 // Don't mess with other {node}s that have a constant {target}. |
| 380 // TODO(bmeurer): Also support optimizing bound functions and proxies here. | 376 // TODO(bmeurer): Also support optimizing bound functions and proxies here. |
| 381 return NoChange(); | 377 return NoChange(); |
| 382 } | 378 } |
| 383 | 379 |
| 384 // Not much we can do if deoptimization support is disabled. | 380 // Not much we can do if deoptimization support is disabled. |
| 385 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 381 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
| 386 | 382 |
| 387 // TODO(mvstanton): Use ConstructICNexus here, once available. | 383 // TODO(mvstanton): Use ConstructICNexus here, once available. |
| 388 Handle<Object> feedback; | |
| 389 if (!p.feedback().IsValid()) return NoChange(); | 384 if (!p.feedback().IsValid()) return NoChange(); |
| 390 feedback = handle(p.feedback().vector()->Get(p.feedback().slot()), isolate()); | 385 ConstructICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
| 386 Handle<Object> feedback = nexus.GetCallFeedback(); |
| 391 if (feedback->IsAllocationSite()) { | 387 if (feedback->IsAllocationSite()) { |
| 392 // The feedback is an AllocationSite, which means we have called the | 388 // The feedback is an AllocationSite, which means we have called the |
| 393 // Array function and collected transition (and pretenuring) feedback | 389 // Array function and collected transition (and pretenuring) feedback |
| 394 // for the resulting arrays. This has to be kept in sync with the | 390 // for the resulting arrays. This has to be kept in sync with the |
| 395 // implementation of the CallConstructStub. | 391 // implementation of the CallConstructStub. |
| 396 Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback); | 392 Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback); |
| 397 | 393 |
| 398 // Retrieve the Array function from the {node}. | 394 // Retrieve the Array function from the {node}. |
| 399 Node* array_function; | 395 Node* array_function; |
| 400 Handle<Context> native_context; | 396 Handle<Context> native_context; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 427 NodeProperties::ReplaceEffectInput(node, effect); | 423 NodeProperties::ReplaceEffectInput(node, effect); |
| 428 NodeProperties::ReplaceControlInput(node, control); | 424 NodeProperties::ReplaceControlInput(node, control); |
| 429 NodeProperties::RemoveFrameStateInput(node, 1); | 425 NodeProperties::RemoveFrameStateInput(node, 1); |
| 430 for (int i = arity; i > 0; --i) { | 426 for (int i = arity; i > 0; --i) { |
| 431 NodeProperties::ReplaceValueInput( | 427 NodeProperties::ReplaceValueInput( |
| 432 node, NodeProperties::GetValueInput(node, i), i + 1); | 428 node, NodeProperties::GetValueInput(node, i), i + 1); |
| 433 } | 429 } |
| 434 NodeProperties::ReplaceValueInput(node, new_target, 1); | 430 NodeProperties::ReplaceValueInput(node, new_target, 1); |
| 435 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site)); | 431 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site)); |
| 436 return Changed(node); | 432 return Changed(node); |
| 437 } else if (feedback->IsWeakCell()) { | 433 } else if (feedback->IsJSFunction()) { |
| 438 Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback); | 434 Node* target_function = jsgraph()->Constant(feedback); |
| 439 if (cell->value()->IsJSFunction()) { | |
| 440 Node* target_function = | |
| 441 jsgraph()->Constant(handle(cell->value(), isolate())); | |
| 442 | 435 |
| 443 // Check that the {target} is still the {target_function}. | 436 // Check that the {target} is still the {target_function}. |
| 444 Node* check = effect = | 437 Node* check = effect = |
| 445 graph()->NewNode(javascript()->StrictEqual(), target, target_function, | 438 graph()->NewNode(javascript()->StrictEqual(), target, target_function, |
| 446 context, effect, control); | 439 context, effect, control); |
| 447 Node* branch = | 440 Node* branch = |
| 448 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); | 441 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
| 449 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); | 442 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 450 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, | 443 Node* deoptimize = |
| 451 effect, if_false); | 444 graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_false); |
| 452 // TODO(bmeurer): This should be on the AdvancedReducer somehow. | 445 // TODO(bmeurer): This should be on the AdvancedReducer somehow. |
| 453 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); | 446 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); |
| 454 control = graph()->NewNode(common()->IfTrue(), branch); | 447 control = graph()->NewNode(common()->IfTrue(), branch); |
| 455 | 448 |
| 456 // Specialize the JSCallConstruct node to the {target_function}. | 449 // Specialize the JSCallConstruct node to the {target_function}. |
| 457 NodeProperties::ReplaceValueInput(node, target_function, 0); | 450 NodeProperties::ReplaceValueInput(node, target_function, 0); |
| 458 NodeProperties::ReplaceEffectInput(node, effect); | 451 NodeProperties::ReplaceEffectInput(node, effect); |
| 459 NodeProperties::ReplaceControlInput(node, control); | 452 NodeProperties::ReplaceControlInput(node, control); |
| 460 if (target == new_target) { | 453 if (target == new_target) { |
| 461 NodeProperties::ReplaceValueInput(node, target_function, arity + 1); | 454 NodeProperties::ReplaceValueInput(node, target_function, arity + 1); |
| 462 } | 455 } |
| 463 | 456 |
| 464 // Try to further reduce the JSCallConstruct {node}. | 457 // Try to further reduce the JSCallConstruct {node}. |
| 465 Reduction const reduction = ReduceJSCallConstruct(node); | 458 Reduction const reduction = ReduceJSCallConstruct(node); |
| 466 return reduction.Changed() ? reduction : Changed(node); | 459 return reduction.Changed() ? reduction : Changed(node); |
| 467 } | |
| 468 } | 460 } |
| 469 | 461 |
| 470 return NoChange(); | 462 return NoChange(); |
| 471 } | 463 } |
| 472 | 464 |
| 473 | 465 |
| 474 MaybeHandle<Context> JSCallReducer::GetNativeContext(Node* node) { | 466 MaybeHandle<Context> JSCallReducer::GetNativeContext(Node* node) { |
| 475 Node* const context = NodeProperties::GetContextInput(node); | 467 Node* const context = NodeProperties::GetContextInput(node); |
| 476 return NodeProperties::GetSpecializationNativeContext(context, | 468 return NodeProperties::GetSpecializationNativeContext(context, |
| 477 native_context()); | 469 native_context()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 489 } | 481 } |
| 490 | 482 |
| 491 | 483 |
| 492 JSOperatorBuilder* JSCallReducer::javascript() const { | 484 JSOperatorBuilder* JSCallReducer::javascript() const { |
| 493 return jsgraph()->javascript(); | 485 return jsgraph()->javascript(); |
| 494 } | 486 } |
| 495 | 487 |
| 496 } // namespace compiler | 488 } // namespace compiler |
| 497 } // namespace internal | 489 } // namespace internal |
| 498 } // namespace v8 | 490 } // namespace v8 |
| OLD | NEW |