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/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
| 10 #include "src/compiler/access-builder.h" |
10 #include "src/compiler/js-graph.h" | 11 #include "src/compiler/js-graph.h" |
11 #include "src/compiler/linkage.h" | 12 #include "src/compiler/linkage.h" |
12 #include "src/compiler/node-matchers.h" | 13 #include "src/compiler/node-matchers.h" |
13 #include "src/compiler/simplified-operator.h" | 14 #include "src/compiler/simplified-operator.h" |
14 #include "src/feedback-vector-inl.h" | 15 #include "src/feedback-vector-inl.h" |
15 #include "src/ic/call-optimization.h" | 16 #include "src/ic/call-optimization.h" |
16 #include "src/objects-inl.h" | 17 #include "src/objects-inl.h" |
17 | 18 |
18 namespace v8 { | 19 namespace v8 { |
19 namespace internal { | 20 namespace internal { |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 | 337 |
337 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target ) | 338 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target ) |
338 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) { | 339 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) { |
339 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); | 340 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
340 Node* target = (node->op()->ValueInputCount() >= 3) | 341 Node* target = (node->op()->ValueInputCount() >= 3) |
341 ? NodeProperties::GetValueInput(node, 2) | 342 ? NodeProperties::GetValueInput(node, 2) |
342 : jsgraph()->UndefinedConstant(); | 343 : jsgraph()->UndefinedConstant(); |
343 return ReduceObjectGetPrototype(node, target); | 344 return ReduceObjectGetPrototype(node, target); |
344 } | 345 } |
345 | 346 |
| 347 Reduction JSCallReducer::ReduceArrayForEach(Handle<SharedFunctionInfo> shared, |
| 348 Node* node) { |
| 349 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
| 350 Node* outer_frame_state = NodeProperties::GetFrameStateInput(node); |
| 351 Node* effect = NodeProperties::GetEffectInput(node); |
| 352 Node* control = NodeProperties::GetControlInput(node); |
| 353 Node* context = NodeProperties::GetContextInput(node); |
| 354 |
| 355 // Try to determine the {receiver} map. |
| 356 Node* receiver = NodeProperties::GetValueInput(node, 1); |
| 357 Node* fncallback = node->op()->ValueInputCount() > 2 |
| 358 ? NodeProperties::GetValueInput(node, 2) |
| 359 : jsgraph()->UndefinedConstant(); |
| 360 Node* this_arg = node->op()->ValueInputCount() > 3 |
| 361 ? NodeProperties::GetValueInput(node, 3) |
| 362 : jsgraph()->UndefinedConstant(); |
| 363 ZoneHandleSet<Map> receiver_maps; |
| 364 if (!NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps)) { |
| 365 return NoChange(); |
| 366 } |
| 367 if (receiver_maps.size() != 1) return NoChange(); |
| 368 Handle<Map> receiver_map(receiver_maps[0]); |
| 369 ElementsKind kind = receiver_map->elements_kind(); |
| 370 // TODO(danno): Handle holey Smi and Object fast elements kinds and double |
| 371 // packed. |
| 372 if (!IsFastPackedElementsKind(kind) || IsFastDoubleElementsKind(kind)) { |
| 373 return NoChange(); |
| 374 } |
| 375 |
| 376 Node* k = jsgraph()->Constant(0); |
| 377 |
| 378 Node* original_length = graph()->NewNode( |
| 379 simplified()->LoadField(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)), |
| 380 receiver, effect, control); |
| 381 |
| 382 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); |
| 383 Node* eloop = effect = |
| 384 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); |
| 385 Node* vloop = k = graph()->NewNode( |
| 386 common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop); |
| 387 |
| 388 control = loop; |
| 389 effect = eloop; |
| 390 |
| 391 Node* continue_test = |
| 392 graph()->NewNode(simplified()->NumberLessThan(), k, original_length); |
| 393 Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 394 continue_test, control); |
| 395 |
| 396 Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); |
| 397 Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch); |
| 398 control = if_true; |
| 399 |
| 400 NodeVector checkpoint_params(local_zone_); |
| 401 checkpoint_params.push_back(receiver); |
| 402 checkpoint_params.push_back(fncallback); |
| 403 checkpoint_params.push_back(this_arg); |
| 404 checkpoint_params.push_back(k); |
| 405 checkpoint_params.push_back(original_length); |
| 406 const int stack_parameters = static_cast<int>(checkpoint_params.size()); |
| 407 |
| 408 Node* frame_state; |
| 409 std::tie(frame_state, effect) = CreateJavaScriptBuiltinContinuationFrameState( |
| 410 jsgraph(), shared, Builtins::kArrayForEachLoopEagerDeoptContinuation, |
| 411 node->InputAt(0), context, &checkpoint_params[0], stack_parameters, |
| 412 effect, control, outer_frame_state, CREATE_CHECKPOINT); |
| 413 |
| 414 // Make sure the map hasn't changed during the iteration |
| 415 Node* orig_map = jsgraph()->HeapConstant(receiver_map); |
| 416 Node* array_map = effect = |
| 417 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 418 receiver, effect, control); |
| 419 Node* check_map = |
| 420 graph()->NewNode(simplified()->ReferenceEqual(), array_map, orig_map); |
| 421 effect = |
| 422 graph()->NewNode(simplified()->CheckIf(), check_map, effect, control); |
| 423 |
| 424 // Make sure that the access is still in bounds, since the callback could have |
| 425 // changed the array's size. |
| 426 Node* length = graph()->NewNode( |
| 427 simplified()->LoadField(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)), |
| 428 receiver, effect, control); |
| 429 k = effect = |
| 430 graph()->NewNode(simplified()->CheckBounds(), k, length, effect, control); |
| 431 USE(length); |
| 432 |
| 433 // Reload the elements pointer before calling the callback, since the previous |
| 434 // callback might have resized the array causing the elements buffer to be |
| 435 // re-allocated. |
| 436 Node* elements = graph()->NewNode( |
| 437 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, |
| 438 effect, control); |
| 439 |
| 440 Node* element = graph()->NewNode( |
| 441 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), |
| 442 elements, k, effect, control); |
| 443 |
| 444 Node* next_k = |
| 445 graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->Constant(1)); |
| 446 checkpoint_params[3] = next_k; |
| 447 std::tie(frame_state, effect) = CreateJavaScriptBuiltinContinuationFrameState( |
| 448 jsgraph(), shared, Builtins::kArrayForEachLoopLazyDeoptContinuation, |
| 449 node->InputAt(0), context, &checkpoint_params[0], stack_parameters, |
| 450 effect, control, outer_frame_state, DONT_CREATE_CHECKPOINT); |
| 451 |
| 452 Node* call_back = control = effect = |
| 453 graph()->NewNode(javascript()->Call(5, 1), fncallback, this_arg, element, |
| 454 k, receiver, context, frame_state, effect, control); |
| 455 USE(call_back); |
| 456 USE(this_arg); |
| 457 |
| 458 k = next_k; |
| 459 |
| 460 loop->ReplaceInput(1, control); |
| 461 vloop->ReplaceInput(1, k); |
| 462 eloop->ReplaceInput(1, effect); |
| 463 |
| 464 control = if_false; |
| 465 effect = eloop; |
| 466 |
| 467 NodeProperties::ReplaceUses(node, jsgraph()->UndefinedConstant(), effect, |
| 468 control); |
| 469 |
| 470 node->TrimInputCount(0); |
| 471 NodeProperties::ChangeOp(node, common()->Dead()); |
| 472 return Changed(node); |
| 473 } |
| 474 |
346 Reduction JSCallReducer::ReduceCallApiFunction( | 475 Reduction JSCallReducer::ReduceCallApiFunction( |
347 Node* node, Handle<FunctionTemplateInfo> function_template_info) { | 476 Node* node, Handle<FunctionTemplateInfo> function_template_info) { |
348 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); | 477 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
349 CallParameters const& p = CallParametersOf(node->op()); | 478 CallParameters const& p = CallParametersOf(node->op()); |
350 int const argc = static_cast<int>(p.arity()) - 2; | 479 int const argc = static_cast<int>(p.arity()) - 2; |
351 Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) | 480 Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) |
352 ? jsgraph()->HeapConstant(global_proxy()) | 481 ? jsgraph()->HeapConstant(global_proxy()) |
353 : NodeProperties::GetValueInput(node, 1); | 482 : NodeProperties::GetValueInput(node, 1); |
354 Node* effect = NodeProperties::GetEffectInput(node); | 483 Node* effect = NodeProperties::GetEffectInput(node); |
355 | 484 |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 case Builtins::kFunctionPrototypeHasInstance: | 697 case Builtins::kFunctionPrototypeHasInstance: |
569 return ReduceFunctionPrototypeHasInstance(node); | 698 return ReduceFunctionPrototypeHasInstance(node); |
570 case Builtins::kNumberConstructor: | 699 case Builtins::kNumberConstructor: |
571 return ReduceNumberConstructor(node); | 700 return ReduceNumberConstructor(node); |
572 case Builtins::kObjectGetPrototypeOf: | 701 case Builtins::kObjectGetPrototypeOf: |
573 return ReduceObjectGetPrototypeOf(node); | 702 return ReduceObjectGetPrototypeOf(node); |
574 case Builtins::kObjectPrototypeGetProto: | 703 case Builtins::kObjectPrototypeGetProto: |
575 return ReduceObjectPrototypeGetProto(node); | 704 return ReduceObjectPrototypeGetProto(node); |
576 case Builtins::kReflectGetPrototypeOf: | 705 case Builtins::kReflectGetPrototypeOf: |
577 return ReduceReflectGetPrototypeOf(node); | 706 return ReduceReflectGetPrototypeOf(node); |
| 707 case Builtins::kArrayForEach: |
| 708 return ReduceArrayForEach(shared, node); |
578 default: | 709 default: |
579 break; | 710 break; |
580 } | 711 } |
581 | 712 |
582 // Check for the Array constructor. | 713 // Check for the Array constructor. |
583 if (*function == function->native_context()->array_function()) { | 714 if (*function == function->native_context()->array_function()) { |
584 return ReduceArrayConstructor(node); | 715 return ReduceArrayConstructor(node); |
585 } | 716 } |
586 | 717 |
587 if (!FLAG_runtime_stats && shared->IsApiFunction()) { | 718 if (!FLAG_runtime_stats && shared->IsApiFunction()) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 return jsgraph()->javascript(); | 982 return jsgraph()->javascript(); |
852 } | 983 } |
853 | 984 |
854 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { | 985 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { |
855 return jsgraph()->simplified(); | 986 return jsgraph()->simplified(); |
856 } | 987 } |
857 | 988 |
858 } // namespace compiler | 989 } // namespace compiler |
859 } // namespace internal | 990 } // namespace internal |
860 } // namespace v8 | 991 } // namespace v8 |
OLD | NEW |