1 // Copyright 2014 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/raw-machine-assembler.h" 6 7 #include "src/code-factory.h" 8 #include "src/compiler/node-properties.h" 9 #include "src/compiler/pipeline.h" 10 #include "src/compiler/scheduler.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace compiler { 15 16 RawMachineAssembler::RawMachineAssembler(Isolate* isolate, Graph* graph, 17 CallDescriptor* call_descriptor, 18 MachineRepresentation word, 19 MachineOperatorBuilder::Flags flags) 20 : isolate_(isolate), 21 graph_(graph), 22 schedule_(new (zone()) Schedule(zone())), 23 machine_(zone(), word, flags), 24 common_(zone()), 25 call_descriptor_(call_descriptor), 26 parameters_(parameter_count(), zone()), 27 current_block_(schedule()->start()) { 28 int param_count = static_cast<int>(parameter_count()); 29 // Add an extra input for the JSFunction parameter to the start node. 30 graph->SetStart(graph->NewNode(common_.Start(param_count + 1))); 31 for (size_t i = 0; i < parameter_count(); ++i) { 32 parameters_[i] = 33 AddNode(common()->Parameter(static_cast<int>(i)), graph->start()); 34 } 35 graph->SetEnd(graph->NewNode(common_.End(0))); 36 } 37 38 39 Schedule* RawMachineAssembler::Export() { 40 // Compute the correct codegen order. 41 DCHECK(schedule_->rpo_order()->empty()); 42 Scheduler::ComputeSpecialRPO(zone(), schedule_); 43 // Invalidate RawMachineAssembler. 44 Schedule* schedule = schedule_; 45 schedule_ = nullptr; 46 return schedule; 47 } 48 49 50 Node* RawMachineAssembler::Parameter(size_t index) { 51 DCHECK(index < parameter_count()); 52 return parameters_[index]; 53 } 54 55 56 void RawMachineAssembler::Goto(RawMachineLabel* label) { 57 DCHECK(current_block_ != schedule()->end()); 58 schedule()->AddGoto(CurrentBlock(), Use(label)); 59 current_block_ = nullptr; 60 } 61 62 63 void RawMachineAssembler::Branch(Node* condition, RawMachineLabel* true_val, 64 RawMachineLabel* false_val) { 65 DCHECK(current_block_ != schedule()->end()); 66 Node* branch = AddNode(common()->Branch(), condition); 67 schedule()->AddBranch(CurrentBlock(), branch, Use(true_val), Use(false_val)); 68 current_block_ = nullptr; 69 } 70 71 72 void RawMachineAssembler::Switch(Node* index, RawMachineLabel* default_label, 73 int32_t* case_values, 74 RawMachineLabel** case_labels, 75 size_t case_count) { 76 DCHECK_NE(schedule()->end(), current_block_); 77 size_t succ_count = case_count + 1; 78 Node* switch_node = AddNode(common()->Switch(succ_count), index); 79 BasicBlock** succ_blocks = zone()->NewArray<BasicBlock*>(succ_count); 80 for (size_t index = 0; index < case_count; ++index) { 81 int32_t case_value = case_values[index]; 82 BasicBlock* case_block = Use(case_labels[index]); 83 Node* case_node = 84 graph()->NewNode(common()->IfValue(case_value), switch_node); 85 schedule()->AddNode(case_block, case_node); 86 succ_blocks[index] = case_block; 87 } 88 BasicBlock* default_block = Use(default_label); 89 Node* default_node = graph()->NewNode(common()->IfDefault(), switch_node); 90 schedule()->AddNode(default_block, default_node); 91 succ_blocks[case_count] = default_block; 92 schedule()->AddSwitch(CurrentBlock(), switch_node, succ_blocks, succ_count); 93 current_block_ = nullptr; 94 } 95 96 97 void RawMachineAssembler::Return(Node* value) { 98 Node* ret = MakeNode(common()->Return(), 1, &value); 99 NodeProperties::MergeControlToEnd(graph(), common(), ret); 100 schedule()->AddReturn(CurrentBlock(), ret); 101 current_block_ = nullptr; 102 } 103 104 105 void RawMachineAssembler::Return(Node* v1, Node* v2) { 106 Node* values[] = {v1, v2}; 107 Node* ret = MakeNode(common()->Return(2), 2, values); 108 NodeProperties::MergeControlToEnd(graph(), common(), ret); 109 schedule()->AddReturn(CurrentBlock(), ret); 110 current_block_ = nullptr; 111 } 112 113 114 void RawMachineAssembler::Return(Node* v1, Node* v2, Node* v3) { 115 Node* values[] = {v1, v2, v3}; 116 Node* ret = MakeNode(common()->Return(3), 3, values); 117 NodeProperties::MergeControlToEnd(graph(), common(), ret); 118 schedule()->AddReturn(CurrentBlock(), ret); 119 current_block_ = nullptr; 120 } 121 122 123 Node* RawMachineAssembler::CallN(CallDescriptor* desc, Node* function, 124 Node** args) { 125 int param_count = 126 static_cast<int>(desc->GetMachineSignature()->parameter_count()); 127 int input_count = param_count + 1; 128 Node** buffer = zone()->NewArray<Node*>(input_count); 129 int index = 0; 130 buffer[index++] = function; 131 for (int i = 0; i < param_count; i++) { 132 buffer[index++] = args[i]; 133 } 134 return AddNode(common()->Call(desc), input_count, buffer); 135 } 136 137 138 Node* RawMachineAssembler::CallNWithFrameState(CallDescriptor* desc, 139 Node* function, Node** args, 140 Node* frame_state) { 141 DCHECK(desc->NeedsFrameState()); 142 int param_count = 143 static_cast<int>(desc->GetMachineSignature()->parameter_count()); 144 int input_count = param_count + 2; 145 Node** buffer = zone()->NewArray<Node*>(input_count); 146 int index = 0; 147 buffer[index++] = function; 148 for (int i = 0; i < param_count; i++) { 149 buffer[index++] = args[i]; 150 } 151 buffer[index++] = frame_state; 152 return AddNode(common()->Call(desc), input_count, buffer); 153 } 154 155 156 Node* RawMachineAssembler::CallRuntime1(Runtime::FunctionId function, 157 Node* arg1, Node* context) { 158 CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor( 159 zone(), function, 1, Operator::kNoProperties, CallDescriptor::kNoFlags); 160 int return_count = static_cast<int>(descriptor->ReturnCount()); 161 162 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode()); 163 Node* ref = AddNode( 164 common()->ExternalConstant(ExternalReference(function, isolate()))); 165 Node* arity = Int32Constant(1); 166 167 return AddNode(common()->Call(descriptor), centry, arg1, ref, arity, context); 168 } 169 170 171 Node* RawMachineAssembler::CallRuntime2(Runtime::FunctionId function, 172 Node* arg1, Node* arg2, Node* context) { 173 CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor( 174 zone(), function, 2, Operator::kNoProperties, CallDescriptor::kNoFlags); 175 int return_count = static_cast<int>(descriptor->ReturnCount()); 176 177 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode()); 178 Node* ref = AddNode( 179 common()->ExternalConstant(ExternalReference(function, isolate()))); 180 Node* arity = Int32Constant(2); 181 182 return AddNode(common()->Call(descriptor), centry, arg1, arg2, ref, arity, 183 context); 184 } 185 186 187 Node* RawMachineAssembler::CallRuntime4(Runtime::FunctionId function, 188 Node* arg1, Node* arg2, Node* arg3, 189 Node* arg4, Node* context) { 190 CallDescriptor* descriptor = Linkage::GetRuntimeCallDescriptor( 191 zone(), function, 4, Operator::kNoProperties, CallDescriptor::kNoFlags); 192 int return_count = static_cast<int>(descriptor->ReturnCount()); 193 194 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode()); 195 Node* ref = AddNode( 196 common()->ExternalConstant(ExternalReference(function, isolate()))); 197 Node* arity = Int32Constant(4); 198 199 return AddNode(common()->Call(descriptor), centry, arg1, arg2, arg3, arg4, 200 ref, arity, context); 201 } 202 203 204 Node* RawMachineAssembler::TailCallN(CallDescriptor* desc, Node* function, 205 Node** args) { 206 int param_count = 207 static_cast<int>(desc->GetMachineSignature()->parameter_count()); 208 int input_count = param_count + 1; 209 Node** buffer = zone()->NewArray<Node*>(input_count); 210 int index = 0; 211 buffer[index++] = function; 212 for (int i = 0; i < param_count; i++) { 213 buffer[index++] = args[i]; 214 } 215 Node* tail_call = MakeNode(common()->TailCall(desc), input_count, buffer); 216 NodeProperties::MergeControlToEnd(graph(), common(), tail_call); 217 schedule()->AddTailCall(CurrentBlock(), tail_call); 218 current_block_ = nullptr; 219 return tail_call; 220 } 221 222 223 Node* RawMachineAssembler::TailCallRuntime1(Runtime::FunctionId function, 224 Node* arg1, Node* context) { 225 const int kArity = 1; 226 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( 227 zone(), function, kArity, Operator::kNoProperties, 228 CallDescriptor::kSupportsTailCalls); 229 int return_count = static_cast<int>(desc->ReturnCount()); 230 231 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode()); 232 Node* ref = AddNode( 233 common()->ExternalConstant(ExternalReference(function, isolate()))); 234 Node* arity = Int32Constant(kArity); 235 236 Node* nodes[] = {centry, arg1, ref, arity, context}; 237 Node* tail_call = MakeNode(common()->TailCall(desc), arraysize(nodes), nodes); 238 239 NodeProperties::MergeControlToEnd(graph(), common(), tail_call); 240 schedule()->AddTailCall(CurrentBlock(), tail_call); 241 current_block_ = nullptr; 242 return tail_call; 243 } 244 245 246 Node* RawMachineAssembler::TailCallRuntime2(Runtime::FunctionId function, 247 Node* arg1, Node* arg2, 248 Node* context) { 249 const int kArity = 2; 250 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( 251 zone(), function, kArity, Operator::kNoProperties, 252 CallDescriptor::kSupportsTailCalls); 253 int return_count = static_cast<int>(desc->ReturnCount()); 254 255 Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode()); 256 Node* ref = AddNode( 257 common()->ExternalConstant(ExternalReference(function, isolate()))); 258 Node* arity = Int32Constant(kArity); 259 260 Node* nodes[] = {centry, arg1, arg2, ref, arity, context}; 261 Node* tail_call = MakeNode(common()->TailCall(desc), arraysize(nodes), nodes); 262 263 NodeProperties::MergeControlToEnd(graph(), common(), tail_call); 264 schedule()->AddTailCall(CurrentBlock(), tail_call); 265 current_block_ = nullptr; 266 return tail_call; 267 } 268 269 270 Node* RawMachineAssembler::CallCFunction0(MachineType return_type, 271 Node* function) { 272 MachineSignature::Builder builder(zone(), 1, 0); 273 builder.AddReturn(return_type); 274 const CallDescriptor* descriptor = 275 Linkage::GetSimplifiedCDescriptor(zone(), builder.Build()); 276 277 return AddNode(common()->Call(descriptor), function); 278 } 279 280 281 Node* RawMachineAssembler::CallCFunction1(MachineType return_type, 282 MachineType arg0_type, Node* function, 283 Node* arg0) { 284 MachineSignature::Builder builder(zone(), 1, 1); 285 builder.AddReturn(return_type); 286 builder.AddParam(arg0_type); 287 const CallDescriptor* descriptor = 288 Linkage::GetSimplifiedCDescriptor(zone(), builder.Build()); 289 290 return AddNode(common()->Call(descriptor), function, arg0); 291 } 292 293 294 Node* RawMachineAssembler::CallCFunction2(MachineType return_type, 295 MachineType arg0_type, 296 MachineType arg1_type, Node* function, 297 Node* arg0, Node* arg1) { 298 MachineSignature::Builder builder(zone(), 1, 2); 299 builder.AddReturn(return_type); 300 builder.AddParam(arg0_type); 301 builder.AddParam(arg1_type); 302 const CallDescriptor* descriptor = 303 Linkage::GetSimplifiedCDescriptor(zone(), builder.Build()); 304 305 return AddNode(common()->Call(descriptor), function, arg0, arg1); 306 } 307 308 309 Node* RawMachineAssembler::CallCFunction8( 310 MachineType return_type, MachineType arg0_type, MachineType arg1_type, 311 MachineType arg2_type, MachineType arg3_type, MachineType arg4_type, 312 MachineType arg5_type, MachineType arg6_type, MachineType arg7_type, 313 Node* function, Node* arg0, Node* arg1, Node* arg2, Node* arg3, Node* arg4, 314 Node* arg5, Node* arg6, Node* arg7) { 315 MachineSignature::Builder builder(zone(), 1, 8); 316 builder.AddReturn(return_type); 317 builder.AddParam(arg0_type); 318 builder.AddParam(arg1_type); 319 builder.AddParam(arg2_type); 320 builder.AddParam(arg3_type); 321 builder.AddParam(arg4_type); 322 builder.AddParam(arg5_type); 323 builder.AddParam(arg6_type); 324 builder.AddParam(arg7_type); 325 Node* args[] = {function, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7}; 326 const CallDescriptor* descriptor = 327 Linkage::GetSimplifiedCDescriptor(zone(), builder.Build()); 328 return AddNode(common()->Call(descriptor), arraysize(args), args); 329 } 330 331 332 void RawMachineAssembler::Bind(RawMachineLabel* label) { 333 DCHECK(current_block_ == nullptr); 334 DCHECK(!label->bound_); 335 label->bound_ = true; 336 current_block_ = EnsureBlock(label); 337 } 338 339 340 BasicBlock* RawMachineAssembler::Use(RawMachineLabel* label) { 341 label->used_ = true; 342 return EnsureBlock(label); 343 } 344 345 346 BasicBlock* RawMachineAssembler::EnsureBlock(RawMachineLabel* label) { 347 if (label->block_ == nullptr) label->block_ = schedule()->NewBasicBlock(); 348 return label->block_; 349 } 350 351 352 BasicBlock* RawMachineAssembler::CurrentBlock() { 353 DCHECK(current_block_); 354 return current_block_; 355 } 356 357 358 Node* RawMachineAssembler::AddNode(const Operator* op, int input_count, 359 Node** inputs) { 360 DCHECK_NOT_NULL(schedule_); 361 DCHECK_NOT_NULL(current_block_); 362 Node* node = MakeNode(op, input_count, inputs); 363 schedule()->AddNode(CurrentBlock(), node); 364 return node; 365 } 366 367 368 Node* RawMachineAssembler::MakeNode(const Operator* op, int input_count, 369 Node** inputs) { 370 // The raw machine assembler nodes do not have effect and control inputs, 371 // so we disable checking input counts here. 372 return graph()->NewNodeUnchecked(op, input_count, inputs); 373 } 374 375 376 RawMachineLabel::RawMachineLabel() 377 : block_(nullptr), used_(false), bound_(false) {} 378 379 380 RawMachineLabel::~RawMachineLabel() { DCHECK(bound_ || !used_); } 381 382 } // namespace compiler 383 } // namespace internal 384 } // namespace v8 385