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