OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/code-factory.h" | 5 #include "src/code-factory.h" |
6 #include "src/code-stubs.h" | 6 #include "src/code-stubs.h" |
7 #include "src/compiler/common-operator.h" | 7 #include "src/compiler/common-operator.h" |
8 #include "src/compiler/js-generic-lowering.h" | 8 #include "src/compiler/js-generic-lowering.h" |
9 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
10 #include "src/compiler/machine-operator.h" | 10 #include "src/compiler/machine-operator.h" |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThan, Token::GT) | 109 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThan, Token::GT) |
110 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSLessThanOrEqual, Token::LTE) | 110 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSLessThanOrEqual, Token::LTE) |
111 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThanOrEqual, Token::GTE) | 111 REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE(JSGreaterThanOrEqual, Token::GTE) |
112 #undef REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE | 112 #undef REPLACE_COMPARE_IC_CALL_WITH_LANGUAGE_MODE |
113 | 113 |
114 | 114 |
115 #define REPLACE_RUNTIME_CALL(op, fun) \ | 115 #define REPLACE_RUNTIME_CALL(op, fun) \ |
116 void JSGenericLowering::Lower##op(Node* node) { \ | 116 void JSGenericLowering::Lower##op(Node* node) { \ |
117 ReplaceWithRuntimeCall(node, fun); \ | 117 ReplaceWithRuntimeCall(node, fun); \ |
118 } | 118 } |
119 REPLACE_RUNTIME_CALL(JSCreateFunctionContext, Runtime::kNewFunctionContext) | |
120 REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext) | 119 REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext) |
121 REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext) | 120 REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext) |
122 REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver) | 121 REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver) |
123 #undef REPLACE_RUNTIME | 122 #undef REPLACE_RUNTIME |
124 | 123 |
125 | 124 |
126 static CallDescriptor::Flags FlagsForNode(Node* node) { | 125 static CallDescriptor::Flags FlagsForNode(Node* node) { |
127 CallDescriptor::Flags result = CallDescriptor::kNoFlags; | 126 CallDescriptor::Flags result = CallDescriptor::kNoFlags; |
128 if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { | 127 if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { |
129 result |= CallDescriptor::kNeedsFrameState; | 128 result |= CallDescriptor::kNeedsFrameState; |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 node->InsertInput(zone(), 1, jsgraph()->Constant(p.start_index())); | 467 node->InsertInput(zone(), 1, jsgraph()->Constant(p.start_index())); |
469 ReplaceWithRuntimeCall(node, Runtime::kNewRestArguments_Generic); | 468 ReplaceWithRuntimeCall(node, Runtime::kNewRestArguments_Generic); |
470 break; | 469 break; |
471 } | 470 } |
472 } | 471 } |
473 | 472 |
474 | 473 |
475 void JSGenericLowering::LowerJSCreateArray(Node* node) { | 474 void JSGenericLowering::LowerJSCreateArray(Node* node) { |
476 CreateArrayParameters const& p = CreateArrayParametersOf(node->op()); | 475 CreateArrayParameters const& p = CreateArrayParametersOf(node->op()); |
477 int const arity = static_cast<int>(p.arity()); | 476 int const arity = static_cast<int>(p.arity()); |
478 Node* new_target = node->InputAt(1); | 477 Handle<AllocationSite> const site = p.site(); |
| 478 |
479 // TODO(turbofan): We embed the AllocationSite from the Operator at this | 479 // TODO(turbofan): We embed the AllocationSite from the Operator at this |
480 // point, which we should not do once we want to both consume the feedback | 480 // point, which we should not do once we want to both consume the feedback |
481 // but at the same time shared the optimized code across native contexts, | 481 // but at the same time shared the optimized code across native contexts, |
482 // as the AllocationSite is associated with a single native context (it's | 482 // as the AllocationSite is associated with a single native context (it's |
483 // stored in the type feedback vector after all). Once we go for cross | 483 // stored in the type feedback vector after all). Once we go for cross |
484 // context code generation, we should somehow find a way to get to the | 484 // context code generation, we should somehow find a way to get to the |
485 // allocation site for the actual native context at runtime. | 485 // allocation site for the actual native context at runtime. |
486 Node* type_info = p.site().is_null() ? jsgraph()->UndefinedConstant() | 486 if (!site.is_null()) { |
487 : jsgraph()->HeapConstant(p.site()); | 487 // Reduce {node} to the appropriate ArrayConstructorStub backend. |
488 node->RemoveInput(1); | 488 // Note that these stubs "behave" like JSFunctions, which means they |
489 node->InsertInput(zone(), 1 + arity, new_target); | 489 // expect a receiver on the stack, which they remove. We just push |
490 node->InsertInput(zone(), 2 + arity, type_info); | 490 // undefined for the receiver. |
491 ReplaceWithRuntimeCall(node, Runtime::kNewArray, arity + 3); | 491 ElementsKind elements_kind = site->GetElementsKind(); |
| 492 AllocationSiteOverrideMode override_mode = |
| 493 (AllocationSite::GetMode(elements_kind) == TRACK_ALLOCATION_SITE) |
| 494 ? DISABLE_ALLOCATION_SITES |
| 495 : DONT_OVERRIDE; |
| 496 if (arity == 0) { |
| 497 ArrayNoArgumentConstructorStub stub(isolate(), elements_kind, |
| 498 override_mode); |
| 499 CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
| 500 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 1, |
| 501 CallDescriptor::kNeedsFrameState); |
| 502 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); |
| 503 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); |
| 504 node->InsertInput(graph()->zone(), 3, jsgraph()->UndefinedConstant()); |
| 505 NodeProperties::ChangeOp(node, common()->Call(desc)); |
| 506 } else if (arity == 1) { |
| 507 // TODO(bmeurer): Optimize for the 0 length non-holey case? |
| 508 ArraySingleArgumentConstructorStub stub( |
| 509 isolate(), GetHoleyElementsKind(elements_kind), override_mode); |
| 510 CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
| 511 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), 2, |
| 512 CallDescriptor::kNeedsFrameState); |
| 513 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); |
| 514 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); |
| 515 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(1)); |
| 516 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); |
| 517 NodeProperties::ChangeOp(node, common()->Call(desc)); |
| 518 } else { |
| 519 ArrayNArgumentsConstructorStub stub(isolate(), elements_kind, |
| 520 override_mode); |
| 521 CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
| 522 isolate(), graph()->zone(), stub.GetCallInterfaceDescriptor(), |
| 523 arity + 1, CallDescriptor::kNeedsFrameState); |
| 524 node->ReplaceInput(0, jsgraph()->HeapConstant(stub.GetCode())); |
| 525 node->InsertInput(graph()->zone(), 2, jsgraph()->HeapConstant(site)); |
| 526 node->InsertInput(graph()->zone(), 3, jsgraph()->Int32Constant(arity)); |
| 527 node->InsertInput(graph()->zone(), 4, jsgraph()->UndefinedConstant()); |
| 528 NodeProperties::ChangeOp(node, common()->Call(desc)); |
| 529 } |
| 530 } else { |
| 531 Node* new_target = node->InputAt(1); |
| 532 Node* type_info = site.is_null() ? jsgraph()->UndefinedConstant() |
| 533 : jsgraph()->HeapConstant(site); |
| 534 node->RemoveInput(1); |
| 535 node->InsertInput(zone(), 1 + arity, new_target); |
| 536 node->InsertInput(zone(), 2 + arity, type_info); |
| 537 ReplaceWithRuntimeCall(node, Runtime::kNewArray, arity + 3); |
| 538 } |
492 } | 539 } |
493 | 540 |
494 | 541 |
495 void JSGenericLowering::LowerJSCreateClosure(Node* node) { | 542 void JSGenericLowering::LowerJSCreateClosure(Node* node) { |
496 CreateClosureParameters p = CreateClosureParametersOf(node->op()); | 543 CreateClosureParameters const& p = CreateClosureParametersOf(node->op()); |
497 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(p.shared_info())); | 544 CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
498 ReplaceWithRuntimeCall(node, (p.pretenure() == TENURED) | 545 Handle<SharedFunctionInfo> const shared_info = p.shared_info(); |
499 ? Runtime::kNewClosure_Tenured | 546 node->InsertInput(zone(), 0, jsgraph()->HeapConstant(shared_info)); |
500 : Runtime::kNewClosure); | 547 |
| 548 // Use the FastNewClosureStub that allocates in new space only for nested |
| 549 // functions that don't need literals cloning. |
| 550 if (p.pretenure() == NOT_TENURED && shared_info->num_literals() == 0) { |
| 551 Callable callable = CodeFactory::FastNewClosure( |
| 552 isolate(), shared_info->language_mode(), shared_info->kind()); |
| 553 ReplaceWithStubCall(node, callable, flags); |
| 554 } else { |
| 555 ReplaceWithRuntimeCall(node, (p.pretenure() == TENURED) |
| 556 ? Runtime::kNewClosure_Tenured |
| 557 : Runtime::kNewClosure); |
| 558 } |
501 } | 559 } |
502 | 560 |
503 | 561 |
| 562 void JSGenericLowering::LowerJSCreateFunctionContext(Node* node) { |
| 563 int const slot_count = OpParameter<int>(node->op()); |
| 564 CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
| 565 |
| 566 // Use the FastNewContextStub only for function contexts up maximum size. |
| 567 if (slot_count <= FastNewContextStub::kMaximumSlots) { |
| 568 Callable callable = CodeFactory::FastNewContext(isolate(), slot_count); |
| 569 ReplaceWithStubCall(node, callable, flags); |
| 570 } else { |
| 571 ReplaceWithRuntimeCall(node, Runtime::kNewFunctionContext); |
| 572 } |
| 573 } |
| 574 |
| 575 |
504 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) { | 576 void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) { |
505 ReplaceWithRuntimeCall(node, Runtime::kCreateIterResultObject); | 577 ReplaceWithRuntimeCall(node, Runtime::kCreateIterResultObject); |
506 } | 578 } |
507 | 579 |
508 | 580 |
509 void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) { | 581 void JSGenericLowering::LowerJSCreateLiteralArray(Node* node) { |
510 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); | 582 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); |
| 583 CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
| 584 int const length = Handle<FixedArray>::cast(p.constant())->length(); |
511 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index())); | 585 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index())); |
512 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); | 586 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); |
513 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags())); | 587 |
514 ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral); | 588 // Use the FastCloneShallowArrayStub only for shallow boilerplates up to the |
| 589 // initial length limit for arrays with "fast" elements kind. |
| 590 if ((p.flags() & ArrayLiteral::kShallowElements) != 0 && |
| 591 (p.flags() & ArrayLiteral::kIsStrong) == 0 && |
| 592 length < JSArray::kInitialMaxFastElementArray) { |
| 593 Callable callable = CodeFactory::FastCloneShallowArray(isolate()); |
| 594 ReplaceWithStubCall(node, callable, flags); |
| 595 } else { |
| 596 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags())); |
| 597 ReplaceWithRuntimeCall(node, Runtime::kCreateArrayLiteral); |
| 598 } |
515 } | 599 } |
516 | 600 |
517 | 601 |
518 void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) { | 602 void JSGenericLowering::LowerJSCreateLiteralObject(Node* node) { |
519 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); | 603 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); |
| 604 CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
| 605 int const length = Handle<FixedArray>::cast(p.constant())->length(); |
520 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index())); | 606 node->InsertInput(zone(), 1, jsgraph()->SmiConstant(p.index())); |
521 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); | 607 node->InsertInput(zone(), 2, jsgraph()->HeapConstant(p.constant())); |
522 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags())); | 608 node->InsertInput(zone(), 3, jsgraph()->SmiConstant(p.flags())); |
523 ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral); | 609 |
| 610 // Use the FastCloneShallowObjectStub only for shallow boilerplates without |
| 611 // elements up to the number of properties that the stubs can handle. |
| 612 if ((p.flags() & ObjectLiteral::kShallowProperties) != 0 && |
| 613 length <= FastCloneShallowObjectStub::kMaximumClonedProperties) { |
| 614 Callable callable = CodeFactory::FastCloneShallowObject(isolate(), length); |
| 615 ReplaceWithStubCall(node, callable, flags); |
| 616 } else { |
| 617 ReplaceWithRuntimeCall(node, Runtime::kCreateObjectLiteral); |
| 618 } |
524 } | 619 } |
525 | 620 |
526 | 621 |
527 void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) { | 622 void JSGenericLowering::LowerJSCreateLiteralRegExp(Node* node) { |
528 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); | 623 CreateLiteralParameters const& p = CreateLiteralParametersOf(node->op()); |
529 CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); | 624 CallDescriptor::Flags flags = AdjustFrameStatesForCall(node); |
530 Callable callable = CodeFactory::FastCloneRegExp(isolate()); | 625 Callable callable = CodeFactory::FastCloneRegExp(isolate()); |
531 Node* literal_index = jsgraph()->SmiConstant(p.index()); | 626 Node* literal_index = jsgraph()->SmiConstant(p.index()); |
532 Node* literal_flags = jsgraph()->SmiConstant(p.flags()); | 627 Node* literal_flags = jsgraph()->SmiConstant(p.flags()); |
533 Node* pattern = jsgraph()->HeapConstant(p.constant()); | 628 Node* pattern = jsgraph()->HeapConstant(p.constant()); |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 } | 802 } |
708 | 803 |
709 | 804 |
710 MachineOperatorBuilder* JSGenericLowering::machine() const { | 805 MachineOperatorBuilder* JSGenericLowering::machine() const { |
711 return jsgraph()->machine(); | 806 return jsgraph()->machine(); |
712 } | 807 } |
713 | 808 |
714 } // namespace compiler | 809 } // namespace compiler |
715 } // namespace internal | 810 } // namespace internal |
716 } // namespace v8 | 811 } // namespace v8 |
OLD | NEW |