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 |