Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: src/compiler/js-typed-lowering.cc

Issue 1678833002: [turbofan] Introduce JSCreateLowering for optimizing JSCreate nodes. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix length_type check. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/compilation-dependencies.h" 6 #include "src/compilation-dependencies.h"
7 #include "src/compiler/access-builder.h" 7 #include "src/compiler/access-builder.h"
8 #include "src/compiler/js-graph.h" 8 #include "src/compiler/js-graph.h"
9 #include "src/compiler/js-typed-lowering.h" 9 #include "src/compiler/js-typed-lowering.h"
10 #include "src/compiler/linkage.h" 10 #include "src/compiler/linkage.h"
11 #include "src/compiler/node-matchers.h" 11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/node-properties.h" 12 #include "src/compiler/node-properties.h"
13 #include "src/compiler/operator-properties.h" 13 #include "src/compiler/operator-properties.h"
14 #include "src/compiler/state-values-utils.h"
15 #include "src/type-cache.h" 14 #include "src/type-cache.h"
16 #include "src/types.h" 15 #include "src/types.h"
17 16
18 namespace v8 { 17 namespace v8 {
19 namespace internal { 18 namespace internal {
20 namespace compiler { 19 namespace compiler {
21 20
22 namespace {
23
24 // A helper class to construct inline allocations on the simplified operator
25 // level. This keeps track of the effect chain for initial stores on a newly
26 // allocated object and also provides helpers for commonly allocated objects.
27 class AllocationBuilder final {
28 public:
29 AllocationBuilder(JSGraph* jsgraph, Node* effect, Node* control)
30 : jsgraph_(jsgraph),
31 allocation_(nullptr),
32 effect_(effect),
33 control_(control) {}
34
35 // Primitive allocation of static size.
36 void Allocate(int size, PretenureFlag pretenure = NOT_TENURED) {
37 effect_ = graph()->NewNode(common()->BeginRegion(), effect_);
38 allocation_ =
39 graph()->NewNode(simplified()->Allocate(pretenure),
40 jsgraph()->Constant(size), effect_, control_);
41 effect_ = allocation_;
42 }
43
44 // Primitive store into a field.
45 void Store(const FieldAccess& access, Node* value) {
46 effect_ = graph()->NewNode(simplified()->StoreField(access), allocation_,
47 value, effect_, control_);
48 }
49
50 // Primitive store into an element.
51 void Store(ElementAccess const& access, Node* index, Node* value) {
52 effect_ = graph()->NewNode(simplified()->StoreElement(access), allocation_,
53 index, value, effect_, control_);
54 }
55
56 // Compound allocation of a FixedArray.
57 void AllocateArray(int length, Handle<Map> map,
58 PretenureFlag pretenure = NOT_TENURED) {
59 DCHECK(map->instance_type() == FIXED_ARRAY_TYPE ||
60 map->instance_type() == FIXED_DOUBLE_ARRAY_TYPE);
61 int size = (map->instance_type() == FIXED_ARRAY_TYPE)
62 ? FixedArray::SizeFor(length)
63 : FixedDoubleArray::SizeFor(length);
64 Allocate(size, pretenure);
65 Store(AccessBuilder::ForMap(), map);
66 Store(AccessBuilder::ForFixedArrayLength(), jsgraph()->Constant(length));
67 }
68
69 // Compound store of a constant into a field.
70 void Store(const FieldAccess& access, Handle<Object> value) {
71 Store(access, jsgraph()->Constant(value));
72 }
73
74 void FinishAndChange(Node* node) {
75 NodeProperties::SetType(allocation_, NodeProperties::GetType(node));
76 node->ReplaceInput(0, allocation_);
77 node->ReplaceInput(1, effect_);
78 node->TrimInputCount(2);
79 NodeProperties::ChangeOp(node, common()->FinishRegion());
80 }
81
82 Node* Finish() {
83 return graph()->NewNode(common()->FinishRegion(), allocation_, effect_);
84 }
85
86 protected:
87 JSGraph* jsgraph() { return jsgraph_; }
88 Graph* graph() { return jsgraph_->graph(); }
89 CommonOperatorBuilder* common() { return jsgraph_->common(); }
90 SimplifiedOperatorBuilder* simplified() { return jsgraph_->simplified(); }
91
92 private:
93 JSGraph* const jsgraph_;
94 Node* allocation_;
95 Node* effect_;
96 Node* control_;
97 };
98
99 } // namespace
100
101
102 // A helper class to simplify the process of reducing a single binop node with a 21 // A helper class to simplify the process of reducing a single binop node with a
103 // JSOperator. This class manages the rewriting of context, control, and effect 22 // JSOperator. This class manages the rewriting of context, control, and effect
104 // dependencies during lowering of a binop and contains numerous helper 23 // dependencies during lowering of a binop and contains numerous helper
105 // functions for matching the types of inputs to an operation. 24 // functions for matching the types of inputs to an operation.
106 class JSBinopReduction final { 25 class JSBinopReduction final {
107 public: 26 public:
108 JSBinopReduction(JSTypedLowering* lowering, Node* node) 27 JSBinopReduction(JSTypedLowering* lowering, Node* node)
109 : lowering_(lowering), node_(node) {} 28 : lowering_(lowering), node_(node) {}
110 29
111 void ConvertInputsToNumber(Node* frame_state) { 30 void ConvertInputsToNumber(Node* frame_state) {
(...skipping 1313 matching lines...) Expand 10 before | Expand all | Expand 10 after
1425 receiver = 1344 receiver =
1426 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1345 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
1427 rconvert, rglobal, control); 1346 rconvert, rglobal, control);
1428 } 1347 }
1429 } 1348 }
1430 ReplaceWithValue(node, receiver, effect, control); 1349 ReplaceWithValue(node, receiver, effect, control);
1431 return Changed(receiver); 1350 return Changed(receiver);
1432 } 1351 }
1433 1352
1434 1353
1435 namespace {
1436
1437 // Maximum instance size for which allocations will be inlined.
1438 const int kMaxInlineInstanceSize = 64 * kPointerSize;
1439
1440
1441 // Checks whether allocation using the given constructor can be inlined.
1442 bool IsAllocationInlineable(Handle<JSFunction> constructor) {
1443 // TODO(bmeurer): Further relax restrictions on inlining, i.e.
1444 // instance type and maybe instance size (inobject properties
1445 // are limited anyways by the runtime).
1446 return constructor->has_initial_map() &&
1447 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE &&
1448 constructor->initial_map()->instance_size() < kMaxInlineInstanceSize;
1449 }
1450
1451 } // namespace
1452
1453
1454 Reduction JSTypedLowering::ReduceJSCreate(Node* node) {
1455 DCHECK_EQ(IrOpcode::kJSCreate, node->opcode());
1456 Node* const target = NodeProperties::GetValueInput(node, 0);
1457 Type* const target_type = NodeProperties::GetType(target);
1458 Node* const new_target = NodeProperties::GetValueInput(node, 1);
1459 Node* const effect = NodeProperties::GetEffectInput(node);
1460 // TODO(turbofan): Add support for NewTarget passed to JSCreate.
1461 if (target != new_target) return NoChange();
1462 // Extract constructor function.
1463 if (target_type->IsConstant() &&
1464 target_type->AsConstant()->Value()->IsJSFunction()) {
1465 Handle<JSFunction> constructor =
1466 Handle<JSFunction>::cast(target_type->AsConstant()->Value());
1467 DCHECK(constructor->IsConstructor());
1468 // Force completion of inobject slack tracking before
1469 // generating code to finalize the instance size.
1470 constructor->CompleteInobjectSlackTrackingIfActive();
1471
1472 // TODO(bmeurer): We fall back to the runtime in case we cannot inline
1473 // the allocation here, which is sort of expensive. We should think about
1474 // a soft fallback to some NewObjectCodeStub.
1475 if (IsAllocationInlineable(constructor)) {
1476 // Compute instance size from initial map of {constructor}.
1477 Handle<Map> initial_map(constructor->initial_map(), isolate());
1478 int const instance_size = initial_map->instance_size();
1479
1480 // Add a dependency on the {initial_map} to make sure that this code is
1481 // deoptimized whenever the {initial_map} of the {constructor} changes.
1482 dependencies()->AssumeInitialMapCantChange(initial_map);
1483
1484 // Emit code to allocate the JSObject instance for the {constructor}.
1485 AllocationBuilder a(jsgraph(), effect, graph()->start());
1486 a.Allocate(instance_size);
1487 a.Store(AccessBuilder::ForMap(), initial_map);
1488 a.Store(AccessBuilder::ForJSObjectProperties(),
1489 jsgraph()->EmptyFixedArrayConstant());
1490 a.Store(AccessBuilder::ForJSObjectElements(),
1491 jsgraph()->EmptyFixedArrayConstant());
1492 for (int i = 0; i < initial_map->GetInObjectProperties(); ++i) {
1493 a.Store(AccessBuilder::ForJSObjectInObjectProperty(initial_map, i),
1494 jsgraph()->UndefinedConstant());
1495 }
1496 a.FinishAndChange(node);
1497 return Changed(node);
1498 }
1499 }
1500 return NoChange();
1501 }
1502
1503
1504 namespace {
1505
1506 // Retrieves the frame state holding actual argument values.
1507 Node* GetArgumentsFrameState(Node* frame_state) {
1508 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
1509 FrameStateInfo outer_state_info = OpParameter<FrameStateInfo>(outer_state);
1510 return outer_state_info.type() == FrameStateType::kArgumentsAdaptor
1511 ? outer_state
1512 : frame_state;
1513 }
1514
1515 } // namespace
1516
1517
1518 Reduction JSTypedLowering::ReduceJSCreateArguments(Node* node) {
1519 DCHECK_EQ(IrOpcode::kJSCreateArguments, node->opcode());
1520 CreateArgumentsType type = CreateArgumentsTypeOf(node->op());
1521 Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
1522 Node* const outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
1523 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
1524
1525 // Use the ArgumentsAccessStub for materializing both mapped and unmapped
1526 // arguments object, but only for non-inlined (i.e. outermost) frames.
1527 if (outer_state->opcode() != IrOpcode::kFrameState) {
1528 if (type != CreateArgumentsType::kRestParameter) {
1529 // TODO(bmeurer): Cleanup this mess at some point.
1530 Isolate* isolate = jsgraph()->isolate();
1531 int parameter_count = state_info.parameter_count() - 1;
1532 int parameter_offset = parameter_count * kPointerSize;
1533 int offset = StandardFrameConstants::kCallerSPOffset + parameter_offset;
1534 Node* parameter_pointer = graph()->NewNode(
1535 machine()->IntAdd(), graph()->NewNode(machine()->LoadFramePointer()),
1536 jsgraph()->IntPtrConstant(offset));
1537 Handle<SharedFunctionInfo> shared;
1538 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
1539 bool unmapped = type == CreateArgumentsType::kUnmappedArguments;
1540 Callable callable = CodeFactory::ArgumentsAccess(
1541 isolate, unmapped, shared->has_duplicate_parameters());
1542 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1543 isolate, graph()->zone(), callable.descriptor(), 0,
1544 CallDescriptor::kNeedsFrameState);
1545 const Operator* new_op = common()->Call(desc);
1546 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1547 node->InsertInput(graph()->zone(), 0, stub_code);
1548 node->InsertInput(graph()->zone(), 2,
1549 jsgraph()->Constant(parameter_count));
1550 node->InsertInput(graph()->zone(), 3, parameter_pointer);
1551 NodeProperties::ChangeOp(node, new_op);
1552 return Changed(node);
1553 } else {
1554 Callable callable = CodeFactory::FastNewRestParameter(isolate());
1555 CallDescriptor* desc = Linkage::GetStubCallDescriptor(
1556 isolate(), graph()->zone(), callable.descriptor(), 0,
1557 CallDescriptor::kNeedsFrameState);
1558 const Operator* new_op = common()->Call(desc);
1559 Node* stub_code = jsgraph()->HeapConstant(callable.code());
1560 node->InsertInput(graph()->zone(), 0, stub_code);
1561 NodeProperties::ChangeOp(node, new_op);
1562 return Changed(node);
1563 }
1564 } else if (outer_state->opcode() == IrOpcode::kFrameState) {
1565 // Use inline allocation for all mapped arguments objects within inlined
1566 // (i.e. non-outermost) frames, independent of the object size.
1567 if (type == CreateArgumentsType::kMappedArguments) {
1568 Handle<SharedFunctionInfo> shared;
1569 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
1570 Node* const callee = NodeProperties::GetValueInput(node, 0);
1571 Node* const control = NodeProperties::GetControlInput(node);
1572 Node* const context = NodeProperties::GetContextInput(node);
1573 Node* effect = NodeProperties::GetEffectInput(node);
1574 // TODO(mstarzinger): Duplicate parameters are not handled yet.
1575 if (shared->has_duplicate_parameters()) return NoChange();
1576 // Choose the correct frame state and frame state info depending on
1577 // whether there conceptually is an arguments adaptor frame in the call
1578 // chain.
1579 Node* const args_state = GetArgumentsFrameState(frame_state);
1580 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
1581 // Prepare element backing store to be used by arguments object.
1582 bool has_aliased_arguments = false;
1583 Node* const elements = AllocateAliasedArguments(
1584 effect, control, args_state, context, shared, &has_aliased_arguments);
1585 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
1586 // Load the arguments object map from the current native context.
1587 Node* const load_native_context = effect = graph()->NewNode(
1588 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1589 context, context, effect);
1590 Node* const load_arguments_map = effect = graph()->NewNode(
1591 simplified()->LoadField(AccessBuilder::ForContextSlot(
1592 has_aliased_arguments ? Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX
1593 : Context::SLOPPY_ARGUMENTS_MAP_INDEX)),
1594 load_native_context, effect, control);
1595 // Actually allocate and initialize the arguments object.
1596 AllocationBuilder a(jsgraph(), effect, control);
1597 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1598 int length = args_state_info.parameter_count() - 1; // Minus receiver.
1599 STATIC_ASSERT(Heap::kSloppyArgumentsObjectSize == 5 * kPointerSize);
1600 a.Allocate(Heap::kSloppyArgumentsObjectSize);
1601 a.Store(AccessBuilder::ForMap(), load_arguments_map);
1602 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
1603 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1604 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
1605 a.Store(AccessBuilder::ForArgumentsCallee(), callee);
1606 RelaxControls(node);
1607 a.FinishAndChange(node);
1608 return Changed(node);
1609 } else if (type == CreateArgumentsType::kUnmappedArguments) {
1610 // Use inline allocation for all unmapped arguments objects within inlined
1611 // (i.e. non-outermost) frames, independent of the object size.
1612 Node* const control = NodeProperties::GetControlInput(node);
1613 Node* const context = NodeProperties::GetContextInput(node);
1614 Node* effect = NodeProperties::GetEffectInput(node);
1615 // Choose the correct frame state and frame state info depending on
1616 // whether there conceptually is an arguments adaptor frame in the call
1617 // chain.
1618 Node* const args_state = GetArgumentsFrameState(frame_state);
1619 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
1620 // Prepare element backing store to be used by arguments object.
1621 Node* const elements = AllocateArguments(effect, control, args_state);
1622 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
1623 // Load the arguments object map from the current native context.
1624 Node* const load_native_context = effect = graph()->NewNode(
1625 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1626 context, context, effect);
1627 Node* const load_arguments_map = effect = graph()->NewNode(
1628 simplified()->LoadField(AccessBuilder::ForContextSlot(
1629 Context::STRICT_ARGUMENTS_MAP_INDEX)),
1630 load_native_context, effect, control);
1631 // Actually allocate and initialize the arguments object.
1632 AllocationBuilder a(jsgraph(), effect, control);
1633 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1634 int length = args_state_info.parameter_count() - 1; // Minus receiver.
1635 STATIC_ASSERT(Heap::kStrictArgumentsObjectSize == 4 * kPointerSize);
1636 a.Allocate(Heap::kStrictArgumentsObjectSize);
1637 a.Store(AccessBuilder::ForMap(), load_arguments_map);
1638 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
1639 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1640 a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length));
1641 RelaxControls(node);
1642 a.FinishAndChange(node);
1643 return Changed(node);
1644 } else if (type == CreateArgumentsType::kRestParameter) {
1645 Handle<SharedFunctionInfo> shared;
1646 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
1647 int start_index = shared->internal_formal_parameter_count();
1648 // Use inline allocation for all unmapped arguments objects within inlined
1649 // (i.e. non-outermost) frames, independent of the object size.
1650 Node* const control = NodeProperties::GetControlInput(node);
1651 Node* const context = NodeProperties::GetContextInput(node);
1652 Node* effect = NodeProperties::GetEffectInput(node);
1653 // Choose the correct frame state and frame state info depending on
1654 // whether there conceptually is an arguments adaptor frame in the call
1655 // chain.
1656 Node* const args_state = GetArgumentsFrameState(frame_state);
1657 FrameStateInfo args_state_info = OpParameter<FrameStateInfo>(args_state);
1658 // Prepare element backing store to be used by the rest array.
1659 Node* const elements =
1660 AllocateRestArguments(effect, control, args_state, start_index);
1661 effect = elements->op()->EffectOutputCount() > 0 ? elements : effect;
1662 // Load the JSArray object map from the current native context.
1663 Node* const load_native_context = effect = graph()->NewNode(
1664 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1665 context, context, effect);
1666 Node* const load_jsarray_map = effect = graph()->NewNode(
1667 simplified()->LoadField(AccessBuilder::ForContextSlot(
1668 Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX)),
1669 load_native_context, effect, control);
1670 // Actually allocate and initialize the jsarray.
1671 AllocationBuilder a(jsgraph(), effect, control);
1672 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1673
1674 // -1 to minus receiver
1675 int argument_count = args_state_info.parameter_count() - 1;
1676 int length = std::max(0, argument_count - start_index);
1677 STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
1678 a.Allocate(JSArray::kSize);
1679 a.Store(AccessBuilder::ForMap(), load_jsarray_map);
1680 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
1681 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1682 a.Store(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS),
1683 jsgraph()->Constant(length));
1684 RelaxControls(node);
1685 a.FinishAndChange(node);
1686 return Changed(node);
1687 }
1688 }
1689
1690 return NoChange();
1691 }
1692
1693
1694 Reduction JSTypedLowering::ReduceNewArray(Node* node, Node* length,
1695 int capacity,
1696 Handle<AllocationSite> site) {
1697 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
1698 Node* context = NodeProperties::GetContextInput(node);
1699 Node* effect = NodeProperties::GetEffectInput(node);
1700 Node* control = NodeProperties::GetControlInput(node);
1701
1702 // Extract transition and tenuring feedback from the {site} and add
1703 // appropriate code dependencies on the {site} if deoptimization is
1704 // enabled.
1705 PretenureFlag pretenure = site->GetPretenureMode();
1706 ElementsKind elements_kind = site->GetElementsKind();
1707 DCHECK(IsFastElementsKind(elements_kind));
1708 if (flags() & kDeoptimizationEnabled) {
1709 dependencies()->AssumeTenuringDecision(site);
1710 dependencies()->AssumeTransitionStable(site);
1711 }
1712
1713 // Retrieve the initial map for the array from the appropriate native context.
1714 Node* native_context = effect = graph()->NewNode(
1715 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1716 context, context, effect);
1717 Node* js_array_map = effect = graph()->NewNode(
1718 javascript()->LoadContext(0, Context::ArrayMapIndex(elements_kind), true),
1719 native_context, native_context, effect);
1720
1721 // Setup elements and properties.
1722 Node* elements;
1723 if (capacity == 0) {
1724 elements = jsgraph()->EmptyFixedArrayConstant();
1725 } else {
1726 elements = effect =
1727 AllocateElements(effect, control, elements_kind, capacity, pretenure);
1728 }
1729 Node* properties = jsgraph()->EmptyFixedArrayConstant();
1730
1731 // Perform the allocation of the actual JSArray object.
1732 AllocationBuilder a(jsgraph(), effect, control);
1733 a.Allocate(JSArray::kSize, pretenure);
1734 a.Store(AccessBuilder::ForMap(), js_array_map);
1735 a.Store(AccessBuilder::ForJSObjectProperties(), properties);
1736 a.Store(AccessBuilder::ForJSObjectElements(), elements);
1737 a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
1738 RelaxControls(node);
1739 a.FinishAndChange(node);
1740 return Changed(node);
1741 }
1742
1743
1744 Reduction JSTypedLowering::ReduceJSCreateArray(Node* node) {
1745 DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
1746 CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
1747 Node* target = NodeProperties::GetValueInput(node, 0);
1748 Node* new_target = NodeProperties::GetValueInput(node, 1);
1749
1750 // TODO(bmeurer): Optimize the subclassing case.
1751 if (target != new_target) return NoChange();
1752
1753 // Check if we have a feedback {site} on the {node}.
1754 Handle<AllocationSite> site = p.site();
1755 if (p.site().is_null()) return NoChange();
1756
1757 // Attempt to inline calls to the Array constructor for the relevant cases
1758 // where either no arguments are provided, or exactly one unsigned number
1759 // argument is given.
1760 if (site->CanInlineCall()) {
1761 if (p.arity() == 0) {
1762 Node* length = jsgraph()->ZeroConstant();
1763 int capacity = JSArray::kPreallocatedArrayElements;
1764 return ReduceNewArray(node, length, capacity, site);
1765 } else if (p.arity() == 1) {
1766 Node* length = NodeProperties::GetValueInput(node, 2);
1767 Type* length_type = NodeProperties::GetType(length);
1768 if (length_type->Is(type_cache_.kElementLoopUnrollType)) {
1769 int capacity = static_cast<int>(length_type->Max());
1770 return ReduceNewArray(node, length, capacity, site);
1771 }
1772 }
1773 }
1774
1775 return NoChange();
1776 }
1777
1778
1779 Reduction JSTypedLowering::ReduceJSCreateIterResultObject(Node* node) {
1780 DCHECK_EQ(IrOpcode::kJSCreateIterResultObject, node->opcode());
1781 Node* value = NodeProperties::GetValueInput(node, 0);
1782 Node* done = NodeProperties::GetValueInput(node, 1);
1783 Node* context = NodeProperties::GetContextInput(node);
1784 Node* effect = NodeProperties::GetEffectInput(node);
1785
1786 // Load the JSIteratorResult map for the {context}.
1787 Node* native_context = effect = graph()->NewNode(
1788 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1789 context, context, effect);
1790 Node* iterator_result_map = effect = graph()->NewNode(
1791 javascript()->LoadContext(0, Context::ITERATOR_RESULT_MAP_INDEX, true),
1792 native_context, native_context, effect);
1793
1794 // Emit code to allocate the JSIteratorResult instance.
1795 AllocationBuilder a(jsgraph(), effect, graph()->start());
1796 a.Allocate(JSIteratorResult::kSize);
1797 a.Store(AccessBuilder::ForMap(), iterator_result_map);
1798 a.Store(AccessBuilder::ForJSObjectProperties(),
1799 jsgraph()->EmptyFixedArrayConstant());
1800 a.Store(AccessBuilder::ForJSObjectElements(),
1801 jsgraph()->EmptyFixedArrayConstant());
1802 a.Store(AccessBuilder::ForJSIteratorResultValue(), value);
1803 a.Store(AccessBuilder::ForJSIteratorResultDone(), done);
1804 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
1805 a.FinishAndChange(node);
1806 return Changed(node);
1807 }
1808
1809
1810 Reduction JSTypedLowering::ReduceJSCreateFunctionContext(Node* node) {
1811 DCHECK_EQ(IrOpcode::kJSCreateFunctionContext, node->opcode());
1812 int slot_count = OpParameter<int>(node->op());
1813 Node* const closure = NodeProperties::GetValueInput(node, 0);
1814
1815 // Use inline allocation for function contexts up to a size limit.
1816 if (slot_count < kFunctionContextAllocationLimit) {
1817 // JSCreateFunctionContext[slot_count < limit]](fun)
1818 Node* effect = NodeProperties::GetEffectInput(node);
1819 Node* control = NodeProperties::GetControlInput(node);
1820 Node* context = NodeProperties::GetContextInput(node);
1821 Node* extension = jsgraph()->TheHoleConstant();
1822 Node* native_context = effect = graph()->NewNode(
1823 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1824 context, context, effect);
1825 AllocationBuilder a(jsgraph(), effect, control);
1826 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1827 int context_length = slot_count + Context::MIN_CONTEXT_SLOTS;
1828 a.AllocateArray(context_length, factory()->function_context_map());
1829 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1830 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1831 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1832 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1833 native_context);
1834 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1835 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1836 }
1837 RelaxControls(node);
1838 a.FinishAndChange(node);
1839 return Changed(node);
1840 }
1841
1842 return NoChange();
1843 }
1844
1845
1846 Reduction JSTypedLowering::ReduceJSCreateWithContext(Node* node) {
1847 DCHECK_EQ(IrOpcode::kJSCreateWithContext, node->opcode());
1848 Node* object = NodeProperties::GetValueInput(node, 0);
1849 Node* closure = NodeProperties::GetValueInput(node, 1);
1850 Node* effect = NodeProperties::GetEffectInput(node);
1851 Node* control = NodeProperties::GetControlInput(node);
1852 Node* context = NodeProperties::GetContextInput(node);
1853 Node* native_context = effect = graph()->NewNode(
1854 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1855 context, context, effect);
1856 AllocationBuilder a(jsgraph(), effect, control);
1857 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1858 a.AllocateArray(Context::MIN_CONTEXT_SLOTS, factory()->with_context_map());
1859 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1860 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1861 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), object);
1862 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1863 native_context);
1864 RelaxControls(node);
1865 a.FinishAndChange(node);
1866 return Changed(node);
1867 }
1868
1869
1870 Reduction JSTypedLowering::ReduceJSCreateCatchContext(Node* node) {
1871 DCHECK_EQ(IrOpcode::kJSCreateCatchContext, node->opcode());
1872 Handle<String> name = OpParameter<Handle<String>>(node);
1873 Node* exception = NodeProperties::GetValueInput(node, 0);
1874 Node* closure = NodeProperties::GetValueInput(node, 1);
1875 Node* effect = NodeProperties::GetEffectInput(node);
1876 Node* control = NodeProperties::GetControlInput(node);
1877 Node* context = NodeProperties::GetContextInput(node);
1878 Node* native_context = effect = graph()->NewNode(
1879 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1880 context, context, effect);
1881 AllocationBuilder a(jsgraph(), effect, control);
1882 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1883 a.AllocateArray(Context::MIN_CONTEXT_SLOTS + 1,
1884 factory()->catch_context_map());
1885 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1886 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1887 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), name);
1888 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1889 native_context);
1890 a.Store(AccessBuilder::ForContextSlot(Context::THROWN_OBJECT_INDEX),
1891 exception);
1892 RelaxControls(node);
1893 a.FinishAndChange(node);
1894 return Changed(node);
1895 }
1896
1897
1898 Reduction JSTypedLowering::ReduceJSCreateBlockContext(Node* node) {
1899 DCHECK_EQ(IrOpcode::kJSCreateBlockContext, node->opcode());
1900 Handle<ScopeInfo> scope_info = OpParameter<Handle<ScopeInfo>>(node);
1901 int context_length = scope_info->ContextLength();
1902 Node* const closure = NodeProperties::GetValueInput(node, 0);
1903
1904 // Use inline allocation for block contexts up to a size limit.
1905 if (context_length < kBlockContextAllocationLimit) {
1906 // JSCreateBlockContext[scope[length < limit]](fun)
1907 Node* effect = NodeProperties::GetEffectInput(node);
1908 Node* control = NodeProperties::GetControlInput(node);
1909 Node* context = NodeProperties::GetContextInput(node);
1910 Node* extension = jsgraph()->Constant(scope_info);
1911 Node* native_context = effect = graph()->NewNode(
1912 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
1913 context, context, effect);
1914 AllocationBuilder a(jsgraph(), effect, control);
1915 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 4); // Ensure fully covered.
1916 a.AllocateArray(context_length, factory()->block_context_map());
1917 a.Store(AccessBuilder::ForContextSlot(Context::CLOSURE_INDEX), closure);
1918 a.Store(AccessBuilder::ForContextSlot(Context::PREVIOUS_INDEX), context);
1919 a.Store(AccessBuilder::ForContextSlot(Context::EXTENSION_INDEX), extension);
1920 a.Store(AccessBuilder::ForContextSlot(Context::NATIVE_CONTEXT_INDEX),
1921 native_context);
1922 for (int i = Context::MIN_CONTEXT_SLOTS; i < context_length; ++i) {
1923 a.Store(AccessBuilder::ForContextSlot(i), jsgraph()->UndefinedConstant());
1924 }
1925 RelaxControls(node);
1926 a.FinishAndChange(node);
1927 return Changed(node);
1928 }
1929
1930 return NoChange();
1931 }
1932
1933
1934 Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) { 1354 Reduction JSTypedLowering::ReduceJSCallConstruct(Node* node) {
1935 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode()); 1355 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
1936 CallConstructParameters const& p = CallConstructParametersOf(node->op()); 1356 CallConstructParameters const& p = CallConstructParametersOf(node->op());
1937 DCHECK_LE(2u, p.arity()); 1357 DCHECK_LE(2u, p.arity());
1938 int const arity = static_cast<int>(p.arity() - 2); 1358 int const arity = static_cast<int>(p.arity() - 2);
1939 Node* target = NodeProperties::GetValueInput(node, 0); 1359 Node* target = NodeProperties::GetValueInput(node, 0);
1940 Type* target_type = NodeProperties::GetType(target); 1360 Type* target_type = NodeProperties::GetType(target);
1941 Node* new_target = NodeProperties::GetValueInput(node, arity + 1); 1361 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
1942 1362
1943 // Check if {target} is a known JSFunction. 1363 // Check if {target} is a known JSFunction.
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after
2306 case IrOpcode::kJSStoreProperty: 1726 case IrOpcode::kJSStoreProperty:
2307 return ReduceJSStoreProperty(node); 1727 return ReduceJSStoreProperty(node);
2308 case IrOpcode::kJSInstanceOf: 1728 case IrOpcode::kJSInstanceOf:
2309 return ReduceJSInstanceOf(node); 1729 return ReduceJSInstanceOf(node);
2310 case IrOpcode::kJSLoadContext: 1730 case IrOpcode::kJSLoadContext:
2311 return ReduceJSLoadContext(node); 1731 return ReduceJSLoadContext(node);
2312 case IrOpcode::kJSStoreContext: 1732 case IrOpcode::kJSStoreContext:
2313 return ReduceJSStoreContext(node); 1733 return ReduceJSStoreContext(node);
2314 case IrOpcode::kJSConvertReceiver: 1734 case IrOpcode::kJSConvertReceiver:
2315 return ReduceJSConvertReceiver(node); 1735 return ReduceJSConvertReceiver(node);
2316 case IrOpcode::kJSCreate:
2317 return ReduceJSCreate(node);
2318 case IrOpcode::kJSCreateArguments:
2319 return ReduceJSCreateArguments(node);
2320 case IrOpcode::kJSCreateArray:
2321 return ReduceJSCreateArray(node);
2322 case IrOpcode::kJSCreateIterResultObject:
2323 return ReduceJSCreateIterResultObject(node);
2324 case IrOpcode::kJSCreateFunctionContext:
2325 return ReduceJSCreateFunctionContext(node);
2326 case IrOpcode::kJSCreateWithContext:
2327 return ReduceJSCreateWithContext(node);
2328 case IrOpcode::kJSCreateCatchContext:
2329 return ReduceJSCreateCatchContext(node);
2330 case IrOpcode::kJSCreateBlockContext:
2331 return ReduceJSCreateBlockContext(node);
2332 case IrOpcode::kJSCallConstruct: 1736 case IrOpcode::kJSCallConstruct:
2333 return ReduceJSCallConstruct(node); 1737 return ReduceJSCallConstruct(node);
2334 case IrOpcode::kJSCallFunction: 1738 case IrOpcode::kJSCallFunction:
2335 return ReduceJSCallFunction(node); 1739 return ReduceJSCallFunction(node);
2336 case IrOpcode::kJSForInDone: 1740 case IrOpcode::kJSForInDone:
2337 return ReduceJSForInDone(node); 1741 return ReduceJSForInDone(node);
2338 case IrOpcode::kJSForInNext: 1742 case IrOpcode::kJSForInNext:
2339 return ReduceJSForInNext(node); 1743 return ReduceJSForInNext(node);
2340 case IrOpcode::kJSForInStep: 1744 case IrOpcode::kJSForInStep:
2341 return ReduceJSForInStep(node); 1745 return ReduceJSForInStep(node);
2342 case IrOpcode::kSelect: 1746 case IrOpcode::kSelect:
2343 return ReduceSelect(node); 1747 return ReduceSelect(node);
2344 default: 1748 default:
2345 break; 1749 break;
2346 } 1750 }
2347 return NoChange(); 1751 return NoChange();
2348 } 1752 }
2349 1753
2350 1754
2351 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) { 1755 Node* JSTypedLowering::Word32Shl(Node* const lhs, int32_t const rhs) {
2352 if (rhs == 0) return lhs; 1756 if (rhs == 0) return lhs;
2353 return graph()->NewNode(machine()->Word32Shl(), lhs, 1757 return graph()->NewNode(machine()->Word32Shl(), lhs,
2354 jsgraph()->Int32Constant(rhs)); 1758 jsgraph()->Int32Constant(rhs));
2355 } 1759 }
2356 1760
2357 1761
2358 // Helper that allocates a FixedArray holding argument values recorded in the
2359 // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
2360 Node* JSTypedLowering::AllocateArguments(Node* effect, Node* control,
2361 Node* frame_state) {
2362 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
2363 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
2364 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
2365
2366 // Prepare an iterator over argument values recorded in the frame state.
2367 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
2368 StateValuesAccess parameters_access(parameters);
2369 auto parameters_it = ++parameters_access.begin();
2370
2371 // Actually allocate the backing store.
2372 AllocationBuilder a(jsgraph(), effect, control);
2373 a.AllocateArray(argument_count, factory()->fixed_array_map());
2374 for (int i = 0; i < argument_count; ++i, ++parameters_it) {
2375 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
2376 }
2377 return a.Finish();
2378 }
2379
2380
2381 // Helper that allocates a FixedArray holding argument values recorded in the
2382 // given {frame_state}. Serves as backing store for JSCreateArguments nodes.
2383 Node* JSTypedLowering::AllocateRestArguments(Node* effect, Node* control,
2384 Node* frame_state,
2385 int start_index) {
2386 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
2387 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
2388 int num_elements = std::max(0, argument_count - start_index);
2389 if (num_elements == 0) return jsgraph()->EmptyFixedArrayConstant();
2390
2391 // Prepare an iterator over argument values recorded in the frame state.
2392 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
2393 StateValuesAccess parameters_access(parameters);
2394 auto parameters_it = ++parameters_access.begin();
2395
2396 // Skip unused arguments.
2397 for (int i = 0; i < start_index; i++) {
2398 ++parameters_it;
2399 }
2400
2401 // Actually allocate the backing store.
2402 AllocationBuilder a(jsgraph(), effect, control);
2403 a.AllocateArray(num_elements, factory()->fixed_array_map());
2404 for (int i = 0; i < num_elements; ++i, ++parameters_it) {
2405 a.Store(AccessBuilder::ForFixedArraySlot(i), (*parameters_it).node);
2406 }
2407 return a.Finish();
2408 }
2409
2410
2411 // Helper that allocates a FixedArray serving as a parameter map for values
2412 // recorded in the given {frame_state}. Some elements map to slots within the
2413 // given {context}. Serves as backing store for JSCreateArguments nodes.
2414 Node* JSTypedLowering::AllocateAliasedArguments(
2415 Node* effect, Node* control, Node* frame_state, Node* context,
2416 Handle<SharedFunctionInfo> shared, bool* has_aliased_arguments) {
2417 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
2418 int argument_count = state_info.parameter_count() - 1; // Minus receiver.
2419 if (argument_count == 0) return jsgraph()->EmptyFixedArrayConstant();
2420
2421 // If there is no aliasing, the arguments object elements are not special in
2422 // any way, we can just return an unmapped backing store instead.
2423 int parameter_count = shared->internal_formal_parameter_count();
2424 if (parameter_count == 0) {
2425 return AllocateArguments(effect, control, frame_state);
2426 }
2427
2428 // Calculate number of argument values being aliased/mapped.
2429 int mapped_count = Min(argument_count, parameter_count);
2430 *has_aliased_arguments = true;
2431
2432 // Prepare an iterator over argument values recorded in the frame state.
2433 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
2434 StateValuesAccess parameters_access(parameters);
2435 auto paratemers_it = ++parameters_access.begin();
2436
2437 // The unmapped argument values recorded in the frame state are stored yet
2438 // another indirection away and then linked into the parameter map below,
2439 // whereas mapped argument values are replaced with a hole instead.
2440 AllocationBuilder aa(jsgraph(), effect, control);
2441 aa.AllocateArray(argument_count, factory()->fixed_array_map());
2442 for (int i = 0; i < mapped_count; ++i, ++paratemers_it) {
2443 aa.Store(AccessBuilder::ForFixedArraySlot(i), jsgraph()->TheHoleConstant());
2444 }
2445 for (int i = mapped_count; i < argument_count; ++i, ++paratemers_it) {
2446 aa.Store(AccessBuilder::ForFixedArraySlot(i), (*paratemers_it).node);
2447 }
2448 Node* arguments = aa.Finish();
2449
2450 // Actually allocate the backing store.
2451 AllocationBuilder a(jsgraph(), arguments, control);
2452 a.AllocateArray(mapped_count + 2, factory()->sloppy_arguments_elements_map());
2453 a.Store(AccessBuilder::ForFixedArraySlot(0), context);
2454 a.Store(AccessBuilder::ForFixedArraySlot(1), arguments);
2455 for (int i = 0; i < mapped_count; ++i) {
2456 int idx = Context::MIN_CONTEXT_SLOTS + parameter_count - 1 - i;
2457 a.Store(AccessBuilder::ForFixedArraySlot(i + 2), jsgraph()->Constant(idx));
2458 }
2459 return a.Finish();
2460 }
2461
2462
2463 Node* JSTypedLowering::AllocateElements(Node* effect, Node* control,
2464 ElementsKind elements_kind,
2465 int capacity, PretenureFlag pretenure) {
2466 DCHECK_LE(1, capacity);
2467 DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
2468
2469 Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind)
2470 ? factory()->fixed_double_array_map()
2471 : factory()->fixed_array_map();
2472 ElementAccess access = IsFastDoubleElementsKind(elements_kind)
2473 ? AccessBuilder::ForFixedDoubleArrayElement()
2474 : AccessBuilder::ForFixedArrayElement();
2475 Node* value =
2476 IsFastDoubleElementsKind(elements_kind)
2477 ? jsgraph()->Float64Constant(bit_cast<double>(kHoleNanInt64))
2478 : jsgraph()->TheHoleConstant();
2479
2480 // Actually allocate the backing store.
2481 AllocationBuilder a(jsgraph(), effect, control);
2482 a.AllocateArray(capacity, elements_map, pretenure);
2483 for (int i = 0; i < capacity; ++i) {
2484 Node* index = jsgraph()->Constant(i);
2485 a.Store(access, index, value);
2486 }
2487 return a.Finish();
2488 }
2489
2490
2491 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } 1762 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); }
2492 1763
2493 1764
2494 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); } 1765 Graph* JSTypedLowering::graph() const { return jsgraph()->graph(); }
2495 1766
2496 1767
2497 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); } 1768 Isolate* JSTypedLowering::isolate() const { return jsgraph()->isolate(); }
2498 1769
2499 1770
2500 JSOperatorBuilder* JSTypedLowering::javascript() const { 1771 JSOperatorBuilder* JSTypedLowering::javascript() const {
(...skipping 16 matching lines...) Expand all
2517 } 1788 }
2518 1789
2519 1790
2520 CompilationDependencies* JSTypedLowering::dependencies() const { 1791 CompilationDependencies* JSTypedLowering::dependencies() const {
2521 return dependencies_; 1792 return dependencies_;
2522 } 1793 }
2523 1794
2524 } // namespace compiler 1795 } // namespace compiler
2525 } // namespace internal 1796 } // namespace internal
2526 } // namespace v8 1797 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698