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/code-factory.h" 7 #include "src/compiler/access-builder.h" 8 #include "src/compiler/js-graph.h" 9 #include "src/compiler/js-operator.h" 10 #include "src/compiler/machine-operator.h" 11 #include "src/compiler/node-properties.h" 12 #include "src/compiler/operator-properties.h" 13 #include "src/isolate-inl.h" 14 #include "test/unittests/compiler/compiler-test-utils.h" 15 #include "test/unittests/compiler/graph-unittest.h" 16 #include "test/unittests/compiler/node-test-utils.h" 17 #include "testing/gmock-support.h" 18 19 using testing::_; 20 using testing::BitEq; 21 using testing::IsNaN; 22 23 namespace v8 { 24 namespace internal { 25 namespace compiler { 26 27 class JSCreateLoweringTest : public TypedGraphTest { 28 public: 29 JSCreateLoweringTest() 30 : TypedGraphTest(3), javascript_(zone()), deps_(isolate(), zone()) {} 31 ~JSCreateLoweringTest() override {} 32 33 protected: 34 Reduction Reduce(Node* node) { 35 MachineOperatorBuilder machine(zone()); 36 SimplifiedOperatorBuilder simplified(zone()); 37 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified, 38 &machine); 39 // TODO(titzer): mock the GraphReducer here for better unit testing. 40 GraphReducer graph_reducer(zone(), graph()); 41 JSCreateLowering reducer(&graph_reducer, &deps_, &jsgraph, 42 MaybeHandle<LiteralsArray>(), zone()); 43 return reducer.Reduce(node); 44 } 45 46 Node* FrameState(Handle<SharedFunctionInfo> shared, Node* outer_frame_state) { 47 Node* state_values = graph()->NewNode(common()->StateValues(0)); 48 return graph()->NewNode( 49 common()->FrameState( 50 BailoutId::None(), OutputFrameStateCombine::Ignore(), 51 common()->CreateFrameStateFunctionInfo( 52 FrameStateType::kJavaScriptFunction, 1, 0, shared)), 53 state_values, state_values, state_values, NumberConstant(0), 54 UndefinedConstant(), outer_frame_state); 55 } 56 57 JSOperatorBuilder* javascript() { return &javascript_; } 58 59 private: 60 JSOperatorBuilder javascript_; 61 CompilationDependencies deps_; 62 }; 63 64 TEST_F(JSCreateLoweringTest, JSCreate) { 65 Handle<JSFunction> function = isolate()->object_function(); 66 Node* const target = Parameter(Type::Constant(function, graph()->zone())); 67 Node* const context = Parameter(Type::Any()); 68 Node* const effect = graph()->start(); 69 Reduction r = Reduce(graph()->NewNode(javascript()->Create(), target, target, 70 context, EmptyFrameState(), effect)); 71 ASSERT_TRUE(r.Changed()); 72 EXPECT_THAT( 73 r.replacement(), 74 IsFinishRegion( 75 IsAllocate(IsNumberConstant(function->initial_map()->instance_size()), 76 IsBeginRegion(effect), _), 77 _)); 78 } 79 80 // ----------------------------------------------------------------------------- 81 // JSCreateArguments 82 83 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedMapped) { 84 Node* const closure = Parameter(Type::Any()); 85 Node* const context = UndefinedConstant(); 86 Node* const effect = graph()->start(); 87 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); 88 Node* const frame_state_outer = FrameState(shared, graph()->start()); 89 Node* const frame_state_inner = FrameState(shared, frame_state_outer); 90 Reduction r = Reduce(graph()->NewNode( 91 javascript()->CreateArguments(CreateArgumentsType::kMappedArguments), 92 closure, context, frame_state_inner, effect)); 93 ASSERT_TRUE(r.Changed()); 94 EXPECT_THAT( 95 r.replacement(), 96 IsFinishRegion( 97 IsAllocate(IsNumberConstant(JSSloppyArgumentsObject::kSize), _, _), 98 _)); 99 } 100 101 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedUnmapped) { 102 Node* const closure = Parameter(Type::Any()); 103 Node* const context = UndefinedConstant(); 104 Node* const effect = graph()->start(); 105 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); 106 Node* const frame_state_outer = FrameState(shared, graph()->start()); 107 Node* const frame_state_inner = FrameState(shared, frame_state_outer); 108 Reduction r = Reduce(graph()->NewNode( 109 javascript()->CreateArguments(CreateArgumentsType::kUnmappedArguments), 110 closure, context, frame_state_inner, effect)); 111 ASSERT_TRUE(r.Changed()); 112 EXPECT_THAT( 113 r.replacement(), 114 IsFinishRegion( 115 IsAllocate(IsNumberConstant(JSStrictArgumentsObject::kSize), _, _), 116 _)); 117 } 118 119 TEST_F(JSCreateLoweringTest, JSCreateArgumentsInlinedRestArray) { 120 Node* const closure = Parameter(Type::Any()); 121 Node* const context = UndefinedConstant(); 122 Node* const effect = graph()->start(); 123 Handle<SharedFunctionInfo> shared(isolate()->object_function()->shared()); 124 Node* const frame_state_outer = FrameState(shared, graph()->start()); 125 Node* const frame_state_inner = FrameState(shared, frame_state_outer); 126 Reduction r = Reduce(graph()->NewNode( 127 javascript()->CreateArguments(CreateArgumentsType::kRestParameter), 128 closure, context, frame_state_inner, effect)); 129 ASSERT_TRUE(r.Changed()); 130 EXPECT_THAT( 131 r.replacement(), 132 IsFinishRegion(IsAllocate(IsNumberConstant(JSArray::kSize), _, _), _)); 133 } 134 135 // ----------------------------------------------------------------------------- 136 // JSCreateClosure 137 138 TEST_F(JSCreateLoweringTest, JSCreateClosureViaInlinedAllocation) { 139 Node* const context = UndefinedConstant(); 140 Node* const effect = graph()->start(); 141 Node* const control = graph()->start(); 142 Handle<SharedFunctionInfo> shared(isolate()->number_function()->shared()); 143 Reduction r = 144 Reduce(graph()->NewNode(javascript()->CreateClosure(shared, NOT_TENURED), 145 context, effect, control)); 146 ASSERT_TRUE(r.Changed()); 147 EXPECT_THAT(r.replacement(), 148 IsFinishRegion(IsAllocate(IsNumberConstant(JSFunction::kSize), 149 IsBeginRegion(_), control), 150 _)); 151 } 152 153 // ----------------------------------------------------------------------------- 154 // JSCreateFunctionContext 155 156 TEST_F(JSCreateLoweringTest, JSCreateFunctionContextViaInlinedAllocation) { 157 Node* const closure = Parameter(Type::Any()); 158 Node* const context = Parameter(Type::Any()); 159 Node* const effect = graph()->start(); 160 Node* const control = graph()->start(); 161 Reduction const r = 162 Reduce(graph()->NewNode(javascript()->CreateFunctionContext(8), closure, 163 context, effect, control)); 164 ASSERT_TRUE(r.Changed()); 165 EXPECT_THAT(r.replacement(), 166 IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( 167 8 + Context::MIN_CONTEXT_SLOTS)), 168 IsBeginRegion(_), control), 169 _)); 170 } 171 172 // ----------------------------------------------------------------------------- 173 // JSCreateWithContext 174 175 TEST_F(JSCreateLoweringTest, JSCreateWithContext) { 176 Node* const object = Parameter(Type::Receiver()); 177 Node* const closure = Parameter(Type::Function()); 178 Node* const context = Parameter(Type::Any()); 179 Node* const effect = graph()->start(); 180 Node* const control = graph()->start(); 181 Reduction r = 182 Reduce(graph()->NewNode(javascript()->CreateWithContext(), object, 183 closure, context, effect, control)); 184 ASSERT_TRUE(r.Changed()); 185 EXPECT_THAT(r.replacement(), 186 IsFinishRegion(IsAllocate(IsNumberConstant(Context::SizeFor( 187 Context::MIN_CONTEXT_SLOTS)), 188 IsBeginRegion(_), control), 189 _)); 190 } 191 192 // ----------------------------------------------------------------------------- 193 // JSCreateCatchContext 194 195 TEST_F(JSCreateLoweringTest, JSCreateCatchContext) { 196 Handle<String> name = factory()->length_string(); 197 Node* const exception = Parameter(Type::Receiver()); 198 Node* const closure = Parameter(Type::Function()); 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(name), exception, 204 closure, 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