aa8a208a47
Reason for revert:
Speculative revert because of blocked roll: https://codereview.chromium.org/2596013002/
Original issue's description:
> [TypeFeedbackVector] Root literal arrays in function literals slots
>
> Literal arrays and feedback vectors for a function can be garbage
> collected if we don't have a rooted closure for the function, which
> happens often. It's expensive to come back from this (recreating
> boilerplates and gathering feedback again), and the cost is
> disproportionate if the function was inlined into optimized code.
>
> To guard against losing these arrays when we need them, we'll now
> create literal arrays when creating the feedback vector for the outer
> closure, and root them strongly in that vector.
>
> BUG=v8:5456
>
> Review-Url: https://codereview.chromium.org/2504153002
> Cr-Commit-Position: refs/heads/master@{#41893}
> Committed: 93df094081
TBR=bmeurer@chromium.org,mlippautz@chromium.org,mvstanton@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:5456
Review-Url: https://codereview.chromium.org/2597163002
Cr-Commit-Position: refs/heads/master@{#41917}
220 lines
8.8 KiB
C++
220 lines
8.8 KiB
C++
// Copyright 2016 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.
|
|
|
|
#include "src/compiler/js-create-lowering.h"
|
|
#include "src/code-factory.h"
|
|
#include "src/compilation-dependencies.h"
|
|
#include "src/compiler/access-builder.h"
|
|
#include "src/compiler/js-graph.h"
|
|
#include "src/compiler/js-operator.h"
|
|
#include "src/compiler/machine-operator.h"
|
|
#include "src/compiler/node-properties.h"
|
|
#include "src/compiler/operator-properties.h"
|
|
#include "src/isolate-inl.h"
|
|
#include "test/unittests/compiler/compiler-test-utils.h"
|
|
#include "test/unittests/compiler/graph-unittest.h"
|
|
#include "test/unittests/compiler/node-test-utils.h"
|
|
#include "testing/gmock-support.h"
|
|
|
|
using testing::_;
|
|
using testing::BitEq;
|
|
using testing::IsNaN;
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
class JSCreateLoweringTest : public TypedGraphTest {
|
|
public:
|
|
JSCreateLoweringTest()
|
|
: TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {}
|
|
~JSCreateLoweringTest() override {}
|
|
|
|
protected:
|
|
Reduction Reduce(Node* node) {
|
|
MachineOperatorBuilder machine(zone());
|
|
SimplifiedOperatorBuilder simplified(zone());
|
|
JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
|
|
&machine);
|
|
// TODO(titzer): mock the GraphReducer here for better unit testing.
|
|
GraphReducer graph_reducer(zone(), graph());
|
|
JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph,
|
|
MaybeHandle<LiteralsArray>(), native_context(),
|
|
zone());
|
|
return reducer.Reduce(node);
|
|
}
|
|
|
|
Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) {
|
|
Node* state_values = graph()->NewNode(common()->StateValues(0));
|
|
return graph()->NewNode(
|
|
common()->FrameState(
|
|
BailoutId::None(), OutputFrameStateCombine::Ignore(),
|
|
common()->CreateFrameStateFunctionInfo(
|
|
FrameStateType::kJavaScriptFunction, 1, 0, shared)),
|
|
state_values, state_values, state_values, NumberConstant(0),
|
|
UndefinedConstant(), outer_frame_state);
|
|
}
|
|
|
|
JSOperatorBuilder* javascript() { return &javascript_; }
|
|
|
|
private:
|
|
JSOperatorBuilder javascript_;
|
|
CompilationDependencies deps_;
|
|
};
|
|
|
|
TEST_F(JSCreateLoweringTest, JSCreate) {
|
|
Handle<JSFunction> function = isolate()->object_function();
|
|
Node* const target = Parameter(Type::HeapConstant(function, graph()->zone()));
|
|
Node* const context = Parameter(Type::Any());
|
|
Node* const effect = graph()->start();
|
|
Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target,
|
|
context, EmptyFrameState(), effect));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(
|
|
r.replacement(),
|
|
IsFinishRegion(
|
|
IsAllocate(IsNumberConstant(function->initial_map()->instance_size()),
|
|
IsBeginRegion(effect), _),
|
|
_));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// JSCreateArguments
|
|
|
|
TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedMapped) {
|
|
Node* const closure = Parameter(Type::Any());
|
|
Node* const context = UndefinedConstant();
|
|
Node* const effect = graph()->start();
|
|
Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
|
|
Node* const frame_state_outer = FrameState(shared, graph()->start());
|
|
Node* const frame_state_inner = FrameState(shared, frame_state_outer);
|
|
Reduction r = Reduce(graph()->NewNode(
|
|
javascript()->CreateArguments(CreateArgumentsType::kMappedArguments),
|
|
closure, context, frame_state_inner, effect));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(
|
|
r.replacement(),
|
|
IsFinishRegion(
|
|
IsAllocate(IsNumberConstant(JSSloppyArgumentsObject::kSize), _, _),
|
|
_));
|
|
}
|
|
|
|
TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedUnmapped) {
|
|
Node* const closure = Parameter(Type::Any());
|
|
Node* const context = UndefinedConstant();
|
|
Node* const effect = graph()->start();
|
|
Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
|
|
Node* const frame_state_outer = FrameState(shared, graph()->start());
|
|
Node* const frame_state_inner = FrameState(shared, frame_state_outer);
|
|
Reduction r = Reduce(graph()->NewNode(
|
|
javascript()->CreateArguments(CreateArgumentsType::kUnmappedArguments),
|
|
closure, context, frame_state_inner, effect));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(
|
|
r.replacement(),
|
|
IsFinishRegion(
|
|
IsAllocate(IsNumberConstant(JSStrictArgumentsObject::kSize), _, _),
|
|
_));
|
|
}
|
|
|
|
TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedRestArray) {
|
|
Node* const closure = Parameter(Type::Any());
|
|
Node* const context = UndefinedConstant();
|
|
Node* const effect = graph()->start();
|
|
Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared());
|
|
Node* const frame_state_outer = FrameState(shared, graph()->start());
|
|
Node* const frame_state_inner = FrameState(shared, frame_state_outer);
|
|
Reduction r = Reduce(graph()->NewNode(
|
|
javascript()->CreateArguments(CreateArgumentsType::kRestParameter),
|
|
closure, context, frame_state_inner, effect));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(
|
|
r.replacement(),
|
|
IsFinishRegion(IsAllocate(IsNumberConstant(JSArray::kSize), _, _), _));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// JSCreateClosure
|
|
|
|
TEST_F(JSCreateLoweringTest, JSCreateClosureViaInlinedAllocation) {
|
|
Node* const context = UndefinedConstant();
|
|
Node* const effect = graph()->start();
|
|
Node* const control = graph()->start();
|
|
Handle<SharedFunctionInfo> shared(isolate()->number_function()->shared());
|
|
Reduction r =
|
|
Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED),
|
|
context, effect, control));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(r.replacement(),
|
|
IsFinishRegion(IsAllocate(IsNumberConstant(JSFunction::kSize),
|
|
IsBeginRegion(_), control),
|
|
_));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// JSCreateFunctionContext
|
|
|
|
TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) {
|
|
Node* const closure = Parameter(Type::Any());
|
|
Node* const context = Parameter(Type::Any());
|
|
Node* const effect = graph()->start();
|
|
Node* const control = graph()->start();
|
|
Reduction const r = Reduce(
|
|
graph()->NewNode(javascript()->CreateFunctionContext(8, FUNCTION_SCOPE),
|
|
closure, context, effect, control));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(r.replacement(),
|
|
IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
|
|
8 + Context::MIN_CONTEXT_SLOTS)),
|
|
IsBeginRegion(_), control),
|
|
_));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// JSCreateWithContext
|
|
|
|
TEST_F(JSCreateLoweringTest, JSCreateWithContext) {
|
|
Handle<ScopeInfo> scope_info(factory()->NewScopeInfo(1));
|
|
Node* const object = Parameter(Type::Receiver());
|
|
Node* const closure = Parameter(Type::Function());
|
|
Node* const context = Parameter(Type::Any());
|
|
Node* const effect = graph()->start();
|
|
Node* const control = graph()->start();
|
|
Reduction r =
|
|
Reduce(graph()->NewNode(javascript()->CreateWithContext(scope_info),
|
|
object, closure, context, effect, control));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(r.replacement(),
|
|
IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
|
|
Context::MIN_CONTEXT_SLOTS)),
|
|
IsBeginRegion(_), control),
|
|
_));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// JSCreateCatchContext
|
|
|
|
TEST_F(JSCreateLoweringTest, JSCreateCatchContext) {
|
|
Handle<String> name = factory()->length_string();
|
|
Handle<ScopeInfo> scope_info(factory()->NewScopeInfo(1));
|
|
Node* const exception = Parameter(Type::Receiver());
|
|
Node* const closure = Parameter(Type::Function());
|
|
Node* const context = Parameter(Type::Any());
|
|
Node* const effect = graph()->start();
|
|
Node* const control = graph()->start();
|
|
Reduction r = Reduce(
|
|
graph()->NewNode(javascript()->CreateCatchContext(name, scope_info),
|
|
exception, closure, context, effect, control));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(r.replacement(),
|
|
IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
|
|
Context::MIN_CONTEXT_SLOTS + 1)),
|
|
IsBeginRegion(_), control),
|
|
_));
|
|
}
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|