36ed494784
This introduces new maps to track whether we have created at most one closure. If we have created just one closure, Turbofan will specialize the code to its context. Review-Url: https://codereview.chromium.org/2680313002 Cr-Commit-Position: refs/heads/master@{#43108}
209 lines
8.2 KiB
C++
209 lines
8.2 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/feedback-vector.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<FeedbackVector>(), native_context(),
|
|
zone());
|
|
return reducer.Reduce(node);
|
|
}
|
|
|
|
Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) {
|
|
Node* state_values =
|
|
graph()->NewNode(common()->StateValues(0, SparseInputMask::Dense()));
|
|
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_;
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// JSCreate
|
|
|
|
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();
|
|
Node* const control = graph()->start();
|
|
Reduction r =
|
|
Reduce(graph()->NewNode(javascript()->Create(), target, target, context,
|
|
EmptyFrameState(), effect, control));
|
|
ASSERT_TRUE(r.Changed());
|
|
EXPECT_THAT(
|
|
r.replacement(),
|
|
IsFinishRegion(
|
|
IsAllocate(IsNumberConstant(function->initial_map()->instance_size()),
|
|
IsBeginRegion(effect), control),
|
|
_));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// 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), _, _), _));
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// 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
|