| 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/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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |