Commit 930f2654 authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

[turbofan] Move large array allocation bailout earlier

The CanAllocateArray used to be executed during JSCreateLowering,
leading to bailouts when large arrays are passed as arguments to
an async function or a bound function. This meant that
JSCreateAsyncFunctionObject or JSCreateBoundFunction will reach
JSGenericLowering, where they are not lowered. This CL moves
the checks earlier in the pipeline during JSNativeContextSpecialization
and JSCallReducer respectively, so that those operators are not
created at all in such cases and we bail out to the runtime instead.

Bug: v8:11564
Change-Id: I232ce7d9378730ae0cc8690e52fde840a484e069
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2807609
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73928}
parent 524f41db
......@@ -15,6 +15,7 @@
#include "src/codegen/tnode.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/access-info.h"
#include "src/compiler/allocation-builder-inl.h"
#include "src/compiler/allocation-builder.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/feedback-source.h"
......@@ -2677,6 +2678,15 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
static constexpr int kBoundThis = 1;
static constexpr int kReceiverContextEffectAndControl = 4;
int const arity = n.ArgumentCount();
if (arity > 0) {
MapRef fixed_array_map(broker(), factory()->fixed_array_map());
AllocationBuilder ab(jsgraph(), effect, control);
if (!ab.CanAllocateArray(arity, fixed_array_map)) {
return NoChange();
}
}
int const arity_with_bound_this = std::max(arity, kBoundThis);
int const input_count =
arity_with_bound_this + kReceiverContextEffectAndControl;
......
......@@ -777,9 +777,7 @@ Reduction JSCreateLowering::ReduceJSCreateAsyncFunctionObject(Node* node) {
// Create the register file.
MapRef fixed_array_map(broker(), factory()->fixed_array_map());
AllocationBuilder ab(jsgraph(), effect, control);
if (!ab.CanAllocateArray(register_count, fixed_array_map)) {
return NoChange();
}
CHECK(ab.CanAllocateArray(register_count, fixed_array_map));
ab.AllocateArray(register_count, fixed_array_map);
for (int i = 0; i < register_count; ++i) {
ab.Store(AccessBuilder::ForFixedArraySlot(i),
......@@ -892,9 +890,7 @@ Reduction JSCreateLowering::ReduceJSCreateBoundFunction(Node* node) {
if (arity > 0) {
MapRef fixed_array_map(broker(), factory()->fixed_array_map());
AllocationBuilder ab(jsgraph(), effect, control);
if (!ab.CanAllocateArray(arity, fixed_array_map)) {
return NoChange();
}
CHECK(ab.CanAllocateArray(arity, fixed_array_map));
ab.AllocateArray(arity, fixed_array_map);
for (int i = 0; i < arity; ++i) {
ab.Store(AccessBuilder::ForFixedArraySlot(i),
......
......@@ -10,6 +10,7 @@
#include "src/codegen/string-constants.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/access-info.h"
#include "src/compiler/allocation-builder-inl.h"
#include "src/compiler/allocation-builder.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/js-graph.h"
......@@ -234,6 +235,11 @@ Reduction JSNativeContextSpecialization::ReduceJSAsyncFunctionEnter(
DCHECK(shared.is_compiled());
int register_count = shared.internal_formal_parameter_count() +
shared.GetBytecodeArray().register_count();
MapRef fixed_array_map(broker(), factory()->fixed_array_map());
AllocationBuilder ab(jsgraph(), effect, control);
if (!ab.CanAllocateArray(register_count, fixed_array_map)) {
return NoChange();
}
Node* value = effect =
graph()->NewNode(javascript()->CreateAsyncFunctionObject(register_count),
closure, receiver, promise, context, effect, control);
......
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --max-optimized-bytecode-size=300000
const args = new Array(35000).fill('arg');
// Regression test for ReduceJSCreateAsyncFunctionObject.
function outer_async() {
async function g(replace_me) {}
%PrepareFunctionForOptimization(g);
%OptimizeFunctionOnNextCall(g);
new Promise(g);
}
const outer_async_many_args = outer_async.toLocaleString().replace('replace_me', args);
eval(outer_async_many_args);
outer_async();
// Regression test for ReduceJSCreateBoundFunction.
function outer_bind(arg) {
function b() { return 42; };
return b.bind(null, replace_me);
}
const outer_bind_many_args = outer_bind.toLocaleString().replace('replace_me', args);
eval(outer_bind_many_args);
%PrepareFunctionForOptimization(outer_bind);
outer_bind();
%OptimizeFunctionOnNextCall(outer_bind);
outer_bind();
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