[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: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#73928}
This commit is contained in:
parent
524f41db67
commit
930f26549f
@ -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);
|
||||
|
32
test/mjsunit/compiler/regress-crbug-11564.js
Normal file
32
test/mjsunit/compiler/regress-crbug-11564.js
Normal file
@ -0,0 +1,32 @@
|
||||
// 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();
|
Loading…
Reference in New Issue
Block a user