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