1// Copyright 2015 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-context-relaxation.h"
6#include "src/compiler/js-graph.h"
7#include "test/unittests/compiler/graph-unittest.h"
8#include "test/unittests/compiler/node-test-utils.h"
9
10namespace v8 {
11namespace internal {
12namespace compiler {
13
14class JSContextRelaxationTest : public GraphTest {
15 public:
16  JSContextRelaxationTest() : GraphTest(3), javascript_(zone()) {}
17  ~JSContextRelaxationTest() override {}
18
19 protected:
20  Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
21                                   MachineOperatorBuilder::kNoFlags) {
22    MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(),
23                                   flags);
24    JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr,
25                    &machine);
26    // TODO(titzer): mock the GraphReducer here for better unit testing.
27    GraphReducer graph_reducer(zone(), graph());
28    JSContextRelaxation reducer;
29    return reducer.Reduce(node);
30  }
31
32  Node* EmptyFrameState() {
33    MachineOperatorBuilder machine(zone());
34    JSGraph jsgraph(isolate(), graph(), common(), javascript(), nullptr,
35                    &machine);
36    return jsgraph.EmptyFrameState();
37  }
38
39  Node* ShallowFrameStateChain(Node* outer_context,
40                               ContextCallingMode context_calling_mode) {
41    const FrameStateFunctionInfo* const frame_state_function_info =
42        common()->CreateFrameStateFunctionInfo(
43            FrameStateType::kJavaScriptFunction, 3, 0,
44            Handle<SharedFunctionInfo>(), context_calling_mode);
45    const Operator* op = common()->FrameState(BailoutId::None(),
46                                              OutputFrameStateCombine::Ignore(),
47                                              frame_state_function_info);
48    return graph()->NewNode(op, graph()->start(), graph()->start(),
49                            graph()->start(), outer_context, graph()->start(),
50                            graph()->start());
51  }
52
53  Node* DeepFrameStateChain(Node* outer_context,
54                            ContextCallingMode context_calling_mode) {
55    const FrameStateFunctionInfo* const frame_state_function_info =
56        common()->CreateFrameStateFunctionInfo(
57            FrameStateType::kJavaScriptFunction, 3, 0,
58            Handle<SharedFunctionInfo>(), context_calling_mode);
59    const Operator* op = common()->FrameState(BailoutId::None(),
60                                              OutputFrameStateCombine::Ignore(),
61                                              frame_state_function_info);
62    Node* shallow_frame_state =
63        ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
64    return graph()->NewNode(op, graph()->start(), graph()->start(),
65                            graph()->start(), graph()->start(),
66                            graph()->start(), shallow_frame_state);
67  }
68
69  JSOperatorBuilder* javascript() { return &javascript_; }
70
71 private:
72  JSOperatorBuilder javascript_;
73};
74
75
76TEST_F(JSContextRelaxationTest,
77       RelaxJSCallFunctionShallowFrameStateChainNoCrossCtx) {
78  Node* const input0 = Parameter(0);
79  Node* const input1 = Parameter(1);
80  Node* const context = Parameter(2);
81  Node* const outer_context = Parameter(3);
82  Node* const frame_state =
83      ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
84  Node* const effect = graph()->start();
85  Node* const control = graph()->start();
86  Node* node = graph()->NewNode(
87      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
88      context, frame_state, frame_state, effect, control);
89  Reduction const r = Reduce(node);
90  EXPECT_TRUE(r.Changed());
91  EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
92}
93
94TEST_F(JSContextRelaxationTest,
95       RelaxJSCallFunctionShallowFrameStateChainCrossCtx) {
96  Node* const input0 = Parameter(0);
97  Node* const input1 = Parameter(1);
98  Node* const context = Parameter(2);
99  Node* const outer_context = Parameter(3);
100  Node* const frame_state =
101      ShallowFrameStateChain(outer_context, CALL_CHANGES_NATIVE_CONTEXT);
102  Node* const effect = graph()->start();
103  Node* const control = graph()->start();
104  Node* node = graph()->NewNode(
105      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
106      context, frame_state, frame_state, effect, control);
107  Reduction const r = Reduce(node);
108  EXPECT_FALSE(r.Changed());
109  EXPECT_EQ(context, NodeProperties::GetContextInput(node));
110}
111
112TEST_F(JSContextRelaxationTest,
113       RelaxJSCallFunctionDeepFrameStateChainNoCrossCtx) {
114  Node* const input0 = Parameter(0);
115  Node* const input1 = Parameter(1);
116  Node* const context = Parameter(2);
117  Node* const outer_context = Parameter(3);
118  Node* const frame_state =
119      DeepFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
120  Node* const effect = graph()->start();
121  Node* const control = graph()->start();
122  Node* node = graph()->NewNode(
123      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
124      context, frame_state, frame_state, effect, control);
125  Reduction const r = Reduce(node);
126  EXPECT_TRUE(r.Changed());
127  EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
128}
129
130TEST_F(JSContextRelaxationTest,
131       RelaxJSCallFunctionDeepFrameStateChainCrossCtx) {
132  Node* const input0 = Parameter(0);
133  Node* const input1 = Parameter(1);
134  Node* const context = Parameter(2);
135  Node* const outer_context = Parameter(3);
136  Node* const frame_state =
137      DeepFrameStateChain(outer_context, CALL_CHANGES_NATIVE_CONTEXT);
138  Node* const effect = graph()->start();
139  Node* const control = graph()->start();
140  Node* node = graph()->NewNode(
141      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
142      context, frame_state, frame_state, effect, control);
143  Reduction const r = Reduce(node);
144  EXPECT_FALSE(r.Changed());
145  EXPECT_EQ(context, NodeProperties::GetContextInput(node));
146}
147
148TEST_F(JSContextRelaxationTest,
149       RelaxJSCallFunctionDeepContextChainFullRelaxForCatch) {
150  Node* const input0 = Parameter(0);
151  Node* const input1 = Parameter(1);
152  Node* const context = Parameter(2);
153  Node* const outer_context = Parameter(3);
154  const Operator* op = javascript()->CreateCatchContext(Handle<String>());
155  Node* const effect = graph()->start();
156  Node* const control = graph()->start();
157  Node* nested_context = graph()->NewNode(
158      op, graph()->start(), graph()->start(), outer_context, effect, control);
159  Node* const frame_state_2 =
160      ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
161  Node* node = graph()->NewNode(
162      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
163      context, frame_state_2, frame_state_2, effect, control);
164  Reduction const r = Reduce(node);
165  EXPECT_TRUE(r.Changed());
166  EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
167}
168
169
170TEST_F(JSContextRelaxationTest,
171       RelaxJSCallFunctionDeepContextChainFullRelaxForWith) {
172  Node* const input0 = Parameter(0);
173  Node* const input1 = Parameter(1);
174  Node* const context = Parameter(2);
175  Node* const outer_context = Parameter(3);
176  const Operator* op = javascript()->CreateWithContext();
177  Node* const effect = graph()->start();
178  Node* const control = graph()->start();
179  Node* nested_context = graph()->NewNode(
180      op, graph()->start(), graph()->start(), outer_context, effect, control);
181  Node* const frame_state_2 =
182      ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
183  Node* node = graph()->NewNode(
184      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
185      context, frame_state_2, frame_state_2, effect, control);
186  Reduction const r = Reduce(node);
187  EXPECT_TRUE(r.Changed());
188  EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
189}
190
191
192TEST_F(JSContextRelaxationTest,
193       RelaxJSCallFunctionDeepContextChainFullRelaxForBlock) {
194  Node* const input0 = Parameter(0);
195  Node* const input1 = Parameter(1);
196  Node* const context = Parameter(2);
197  Node* const outer_context = Parameter(3);
198  Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::null();
199  const Operator* op = javascript()->CreateBlockContext(scope_info);
200  Node* const effect = graph()->start();
201  Node* const control = graph()->start();
202  Node* nested_context =
203      graph()->NewNode(op, graph()->start(), outer_context, effect, control);
204  Node* const frame_state_2 =
205      ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
206  Node* node = graph()->NewNode(
207      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
208      context, frame_state_2, frame_state_2, effect, control);
209  Reduction const r = Reduce(node);
210  EXPECT_TRUE(r.Changed());
211  EXPECT_EQ(outer_context, NodeProperties::GetContextInput(node));
212}
213
214
215TEST_F(JSContextRelaxationTest,
216       RelaxJSCallFunctionDeepContextChainPartialRelaxForScript) {
217  Node* const input0 = Parameter(0);
218  Node* const input1 = Parameter(1);
219  Node* const context = Parameter(2);
220  Node* const outer_context = Parameter(3);
221  Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::null();
222  const Operator* op = javascript()->CreateScriptContext(scope_info);
223  Node* const frame_state_1 =
224      ShallowFrameStateChain(outer_context, CALL_MAINTAINS_NATIVE_CONTEXT);
225  Node* const effect = graph()->start();
226  Node* const control = graph()->start();
227  Node* nested_context = graph()->NewNode(op, graph()->start(), outer_context,
228                                          frame_state_1, effect, control);
229  Node* const frame_state_2 =
230      ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
231  Node* node = graph()->NewNode(
232      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
233      context, frame_state_2, frame_state_2, effect, control);
234  Reduction const r = Reduce(node);
235  EXPECT_TRUE(r.Changed());
236  EXPECT_EQ(nested_context, NodeProperties::GetContextInput(node));
237}
238
239
240TEST_F(JSContextRelaxationTest,
241       RelaxJSCallFunctionDeepContextChainPartialRelaxForModule) {
242  Node* const input0 = Parameter(0);
243  Node* const input1 = Parameter(1);
244  Node* const context = Parameter(2);
245  Node* const outer_context = Parameter(3);
246  const Operator* op = javascript()->CreateModuleContext();
247  Node* const effect = graph()->start();
248  Node* const control = graph()->start();
249  Node* nested_context = graph()->NewNode(
250      op, graph()->start(), graph()->start(), outer_context, effect, control);
251  Node* const frame_state_2 =
252      ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
253  Node* node = graph()->NewNode(
254      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
255      context, frame_state_2, frame_state_2, effect, control);
256  Reduction const r = Reduce(node);
257  EXPECT_TRUE(r.Changed());
258  EXPECT_EQ(nested_context, NodeProperties::GetContextInput(node));
259}
260
261
262TEST_F(JSContextRelaxationTest,
263       RelaxJSCallFunctionDeepContextChainPartialNoRelax) {
264  Node* const input0 = Parameter(0);
265  Node* const input1 = Parameter(1);
266  Node* const context = Parameter(2);
267  Node* const outer_context = Parameter(3);
268  const Operator* op = javascript()->CreateFunctionContext(0);
269  Node* const effect = graph()->start();
270  Node* const control = graph()->start();
271  Node* nested_context =
272      graph()->NewNode(op, graph()->start(), outer_context, effect, control);
273  Node* const frame_state_2 =
274      ShallowFrameStateChain(nested_context, CALL_MAINTAINS_NATIVE_CONTEXT);
275  Node* node = graph()->NewNode(
276      javascript()->CallFunction(2, STRICT, VectorSlotPair()), input0, input1,
277      context, frame_state_2, frame_state_2, effect, control);
278  Reduction const r = Reduce(node);
279  EXPECT_FALSE(r.Changed());
280  EXPECT_EQ(context, NodeProperties::GetContextInput(node));
281}
282
283}  // namespace compiler
284}  // namespace internal
285}  // namespace v8
286