Commit 245ab01a authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Inline Array constructor calls with multiple parameters.

BUG=v8:6262
R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2821273002
Cr-Commit-Position: refs/heads/master@{#44688}
parent 0cc0c130
......@@ -594,6 +594,66 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length,
return Changed(node);
}
Reduction JSCreateLowering::ReduceNewArray(Node* node,
std::vector<Node*> values,
Handle<AllocationSite> site) {
DCHECK_EQ(IrOpcode::kJSCreateArray, node->opcode());
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
// Extract transition and tenuring feedback from the {site} and add
// appropriate code dependencies on the {site} if deoptimization is
// enabled.
PretenureFlag pretenure = site->GetPretenureMode();
ElementsKind elements_kind = site->GetElementsKind();
DCHECK(IsFastElementsKind(elements_kind));
dependencies()->AssumeTenuringDecision(site);
dependencies()->AssumeTransitionStable(site);
// Check {values} based on the {elements_kind}. These checks are guarded
// by the {elements_kind} feedback on the {site}, so it's safe to just
// deoptimize in this case.
if (IsFastSmiElementsKind(elements_kind)) {
for (auto& value : values) {
if (!NodeProperties::GetType(value)->Is(Type::SignedSmall())) {
value = effect =
graph()->NewNode(simplified()->CheckSmi(), value, effect, control);
}
}
} else if (IsFastDoubleElementsKind(elements_kind)) {
for (auto& value : values) {
if (!NodeProperties::GetType(value)->Is(Type::Number())) {
value = effect = graph()->NewNode(simplified()->CheckNumber(), value,
effect, control);
}
// Make sure we do not store signaling NaNs into double arrays.
value = graph()->NewNode(simplified()->NumberSilenceNaN(), value);
}
}
// Retrieve the initial map for the array.
int const array_map_index = Context::ArrayMapIndex(elements_kind);
Node* js_array_map = jsgraph()->HeapConstant(
handle(Map::cast(native_context()->get(array_map_index)), isolate()));
// Setup elements, properties and length.
Node* elements = effect =
AllocateElements(effect, control, elements_kind, values, pretenure);
Node* properties = jsgraph()->EmptyFixedArrayConstant();
Node* length = jsgraph()->Constant(static_cast<int>(values.size()));
// Perform the allocation of the actual JSArray object.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(JSArray::kSize, pretenure);
a.Store(AccessBuilder::ForMap(), js_array_map);
a.Store(AccessBuilder::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectElements(), elements);
a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length);
RelaxControls(node);
a.FinishAndChange(node);
return Changed(node);
}
Reduction JSCreateLowering::ReduceNewArrayToStubCall(
Node* node, Handle<AllocationSite> site) {
CreateArrayParameters const& p = CreateArrayParametersOf(node->op());
......@@ -755,12 +815,25 @@ Reduction JSCreateLowering::ReduceJSCreateArray(Node* node) {
} else if (p.arity() == 1) {
Node* length = NodeProperties::GetValueInput(node, 2);
Type* length_type = NodeProperties::GetType(length);
if (!length_type->Maybe(Type::Unsigned32())) {
// Handle the single argument case, where we know that the value
// cannot be a valid Array length.
return ReduceNewArray(node, {length}, site);
}
if (length_type->Is(Type::SignedSmall()) && length_type->Min() >= 0 &&
length_type->Max() <= kElementLoopUnrollLimit &&
length_type->Min() == length_type->Max()) {
int capacity = static_cast<int>(length_type->Max());
return ReduceNewArray(node, length, capacity, site);
}
} else if (p.arity() <= JSArray::kInitialMaxFastElementArray) {
std::vector<Node*> values;
values.reserve(p.arity());
for (size_t i = 0; i < p.arity(); ++i) {
values.push_back(
NodeProperties::GetValueInput(node, static_cast<int>(2 + i)));
}
return ReduceNewArray(node, values, site);
}
}
......@@ -1125,6 +1198,31 @@ Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
return a.Finish();
}
Node* JSCreateLowering::AllocateElements(Node* effect, Node* control,
ElementsKind elements_kind,
std::vector<Node*> const& values,
PretenureFlag pretenure) {
int const capacity = static_cast<int>(values.size());
DCHECK_LE(1, capacity);
DCHECK_LE(capacity, JSArray::kInitialMaxFastElementArray);
Handle<Map> elements_map = IsFastDoubleElementsKind(elements_kind)
? factory()->fixed_double_array_map()
: factory()->fixed_array_map();
ElementAccess access = IsFastDoubleElementsKind(elements_kind)
? AccessBuilder::ForFixedDoubleArrayElement()
: AccessBuilder::ForFixedArrayElement();
// Actually allocate the backing store.
AllocationBuilder a(jsgraph(), effect, control);
a.AllocateArray(capacity, elements_map, pretenure);
for (int i = 0; i < capacity; ++i) {
Node* index = jsgraph()->Constant(i);
a.Store(access, index, values[i]);
}
return a.Finish();
}
Node* JSCreateLowering::AllocateFastLiteral(
Node* effect, Node* control, Handle<JSObject> boilerplate,
AllocationSiteUsageContext* site_context) {
......
......@@ -59,6 +59,8 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Reduction ReduceJSCreateBlockContext(Node* node);
Reduction ReduceNewArray(Node* node, Node* length, int capacity,
Handle<AllocationSite> site);
Reduction ReduceNewArray(Node* node, std::vector<Node*> values,
Handle<AllocationSite> site);
Node* AllocateArguments(Node* effect, Node* control, Node* frame_state);
Node* AllocateRestArguments(Node* effect, Node* control, Node* frame_state,
......@@ -69,6 +71,10 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Node* AllocateElements(Node* effect, Node* control,
ElementsKind elements_kind, int capacity,
PretenureFlag pretenure);
Node* AllocateElements(Node* effect, Node* control,
ElementsKind elements_kind,
std::vector<Node*> const& values,
PretenureFlag pretenure);
Node* AllocateFastLiteral(Node* effect, Node* control,
Handle<JSObject> boilerplate,
AllocationSiteUsageContext* site_context);
......
......@@ -119,10 +119,13 @@ function assertKind(expected, obj, name_opt) {
return new Array(one, two, three);
}
barn(1, 2, 3);
barn(1, 2, 3);
a = barn(1, 2, 3);
a[1] = "a string";
a = barn(1, 2, 3);
assertKind(elements_kind.fast, a);
%OptimizeFunctionOnNextCall(barn);
barn(1, 2, 3);
a = barn(1, 2, 3);
assertKind(elements_kind.fast, a);
assertOptimized(barn);
a = barn(1, "oops", 3);
assertOptimized(barn);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment