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 |