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