1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/js-create-lowering.h"
6 #include "src/codegen/code-factory.h"
7 #include "src/codegen/tick-counter.h"
8 #include "src/compiler/access-builder.h"
9 #include "src/compiler/compilation-dependencies.h"
10 #include "src/compiler/js-graph.h"
11 #include "src/compiler/js-operator.h"
12 #include "src/compiler/machine-operator.h"
13 #include "src/compiler/node-properties.h"
14 #include "src/compiler/operator-properties.h"
15 #include "src/execution/isolate-inl.h"
16 #include "src/objects/arguments.h"
17 #include "src/objects/feedback-vector.h"
18 #include "test/unittests/compiler/compiler-test-utils.h"
19 #include "test/unittests/compiler/graph-unittest.h"
20 #include "test/unittests/compiler/node-test-utils.h"
21 #include "testing/gmock-support.h"
22 
23 using testing::_;
24 using testing::BitEq;
25 using testing::IsNaN;
26 
27 namespace v8 {
28 namespace internal {
29 namespace compiler {
30 
31 class JSCreateLoweringTest : public TypedGraphTest {
32  public:
JSCreateLoweringTest()33   JSCreateLoweringTest()
34       : TypedGraphTest(3),
35         javascript_(zone()),
36         deps_(broker(), zone()),
37         handle_scope_(isolate()) {}
38   ~JSCreateLoweringTest() override = default;
39 
40  protected:
Reduce(Node * node)41   Reduction Reduce(Node* node) {
42     MachineOperatorBuilder machine(zone());
43     SimplifiedOperatorBuilder simplified(zone());
44     JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
45                     &machine);
46     GraphReducer graph_reducer(zone(), graph(), tick_counter(), broker());
47     JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph, broker(),
48                              zone());
49     return reducer.Reduce(node);
50   }
51 
FrameState(Handle<SharedFunctionInfo> shared,Node * outer_frame_state)52   Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) {
53     Node* state_values =
54         graph()->NewNode(common()->StateValues(0, SparseInputMask::Dense()));
55     return graph()->NewNode(
56         common()->FrameState(
57             BytecodeOffset::None(), OutputFrameStateCombine::Ignore(),
58             common()->CreateFrameStateFunctionInfo(
59                 FrameStateType::kUnoptimizedFunction, 1, 0, shared)),
60         state_values, state_values, state_values, NumberConstant(0),
61         UndefinedConstant(), outer_frame_state);
62   }
63 
javascript()64   JSOperatorBuilder* javascript() { return &javascript_; }
65 
66  private:
67   JSOperatorBuilder javascript_;
68   CompilationDependencies deps_;
69   CanonicalHandleScope handle_scope_;
70 };
71 
72 // -----------------------------------------------------------------------------
73 // JSCreate
74 
TEST_F(JSCreateLoweringTest,JSCreate)75 TEST_F(JSCreateLoweringTest, JSCreate) {
76   Handle<JSFunction> function = isolate()->object_function();
77   Node* const target = graph()->NewNode(common()->HeapConstant(function));
78   Node* const context = Parameter(Type::Any());
79   Node* const effect = graph()->start();
80   Node* const control = graph()->start();
81   Reduction r =
82       Reduce(graph()->NewNode(javascript()->Create(), target, target, context,
83                               EmptyFrameState(), effect, control));
84   ASSERT_TRUE(r.Changed());
85   EXPECT_THAT(
86       r.replacement(),
87       IsFinishRegion(
88           IsAllocate(IsNumberConstant(function->initial_map().instance_size()),
89                      IsBeginRegion(effect), control),
90           _));
91 }
92 
93 // -----------------------------------------------------------------------------
94 // JSCreateArguments
95 
TEST_F(JSCreateLoweringTest,JSCreateArgumentsInlinedMapped)96 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedMapped) {
97   Node* const closure = Parameter(Type::Any());
98   Node* const context = UndefinedConstant();
99   Node* const effect = graph()->start();
100   Handle<SharedFunctionInfo> shared(isolate()->regexp_function()->shared(),
101                                     isolate());
102   Node* const frame_state_outer = FrameState(shared, graph()->start());
103   Node* const frame_state_inner = FrameState(shared, frame_state_outer);
104   Reduction r = Reduce(graph()->NewNode(
105       javascript()->CreateArguments(CreateArgumentsType::kMappedArguments),
106       closure, context, frame_state_inner, effect));
107   ASSERT_TRUE(r.Changed());
108   EXPECT_THAT(
109       r.replacement(),
110       IsFinishRegion(
111           IsAllocate(IsNumberConstant(JSSloppyArgumentsObject::kSize), _, _),
112           _));
113 }
114 
TEST_F(JSCreateLoweringTest,JSCreateArgumentsInlinedUnmapped)115 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedUnmapped) {
116   Node* const closure = Parameter(Type::Any());
117   Node* const context = UndefinedConstant();
118   Node* const effect = graph()->start();
119   Handle<SharedFunctionInfo> shared(isolate()->regexp_function()->shared(),
120                                     isolate());
121   Node* const frame_state_outer = FrameState(shared, graph()->start());
122   Node* const frame_state_inner = FrameState(shared, frame_state_outer);
123   Reduction r = Reduce(graph()->NewNode(
124       javascript()->CreateArguments(CreateArgumentsType::kUnmappedArguments),
125       closure, context, frame_state_inner, effect));
126   ASSERT_TRUE(r.Changed());
127   EXPECT_THAT(
128       r.replacement(),
129       IsFinishRegion(
130           IsAllocate(IsNumberConstant(JSStrictArgumentsObject::kSize), _, _),
131           _));
132 }
133 
TEST_F(JSCreateLoweringTest,JSCreateArgumentsInlinedRestArray)134 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedRestArray) {
135   Node* const closure = Parameter(Type::Any());
136   Node* const context = UndefinedConstant();
137   Node* const effect = graph()->start();
138   Handle<SharedFunctionInfo> shared(isolate()->regexp_function()->shared(),
139                                     isolate());
140   Node* const frame_state_outer = FrameState(shared, graph()->start());
141   Node* const frame_state_inner = FrameState(shared, frame_state_outer);
142   Reduction r = Reduce(graph()->NewNode(
143       javascript()->CreateArguments(CreateArgumentsType::kRestParameter),
144       closure, context, frame_state_inner, effect));
145   ASSERT_TRUE(r.Changed());
146   EXPECT_THAT(r.replacement(),
147               IsFinishRegion(
148                   IsAllocate(IsNumberConstant(JSArray::kHeaderSize), _, _), _));
149 }
150 
151 // -----------------------------------------------------------------------------
152 // JSCreateFunctionContext
153 
TEST_F(JSCreateLoweringTest,JSCreateFunctionContextViaInlinedAllocation)154 TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) {
155   Node* const context = Parameter(Type::Any());
156   Node* const effect = graph()->start();
157   Node* const control = graph()->start();
158   Reduction const r = Reduce(graph()->NewNode(
159       javascript()->CreateFunctionContext(
160           MakeRef(broker(), ScopeInfo::Empty(isolate())), 8, FUNCTION_SCOPE),
161       context, effect, control));
162   ASSERT_TRUE(r.Changed());
163   EXPECT_THAT(r.replacement(),
164               IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
165                                             8 + Context::MIN_CONTEXT_SLOTS)),
166                                         IsBeginRegion(_), control),
167                              _));
168 }
169 
170 // -----------------------------------------------------------------------------
171 // JSCreateWithContext
172 
TEST_F(JSCreateLoweringTest,JSCreateWithContext)173 TEST_F(JSCreateLoweringTest, JSCreateWithContext) {
174   ScopeInfoRef scope_info =
175       MakeRef(broker(), ReadOnlyRoots(isolate()).empty_function_scope_info());
176   Node* const object = Parameter(Type::Receiver());
177   Node* const context = Parameter(Type::Any());
178   Node* const effect = graph()->start();
179   Node* const control = graph()->start();
180   Reduction r =
181       Reduce(graph()->NewNode(javascript()->CreateWithContext(scope_info),
182                               object, context, effect, control));
183   ASSERT_TRUE(r.Changed());
184   EXPECT_THAT(
185       r.replacement(),
186       IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
187                                     Context::MIN_CONTEXT_EXTENDED_SLOTS)),
188                                 IsBeginRegion(_), control),
189                      _));
190 }
191 
192 // -----------------------------------------------------------------------------
193 // JSCreateCatchContext
194 
TEST_F(JSCreateLoweringTest,JSCreateCatchContext)195 TEST_F(JSCreateLoweringTest, JSCreateCatchContext) {
196   ScopeInfoRef scope_info =
197       MakeRef(broker(), ReadOnlyRoots(isolate()).empty_function_scope_info());
198   Node* const exception = Parameter(Type::Receiver());
199   Node* const context = Parameter(Type::Any());
200   Node* const effect = graph()->start();
201   Node* const control = graph()->start();
202   Reduction r =
203       Reduce(graph()->NewNode(javascript()->CreateCatchContext(scope_info),
204                               exception, context, effect, control));
205   ASSERT_TRUE(r.Changed());
206   EXPECT_THAT(r.replacement(),
207               IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor(
208                                             Context::MIN_CONTEXT_SLOTS + 1)),
209                                         IsBeginRegion(_), control),
210                              _));
211 }
212 
213 }  // namespace compiler
214 }  // namespace internal
215 }  // namespace v8
216