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/code-assembler.h" 6 7 #include <ostream> 8 9 #include "src/code-factory.h" 10 #include "src/compiler/graph.h" 11 #include "src/compiler/instruction-selector.h" 12 #include "src/compiler/linkage.h" 13 #include "src/compiler/node-matchers.h" 14 #include "src/compiler/pipeline.h" 15 #include "src/compiler/raw-machine-assembler.h" 16 #include "src/compiler/schedule.h" 17 #include "src/frames.h" 18 #include "src/interface-descriptors.h" 19 #include "src/interpreter/bytecodes.h" 20 #include "src/machine-type.h" 21 #include "src/macro-assembler.h" 22 #include "src/objects-inl.h" 23 #include "src/utils.h" 24 #include "src/zone/zone.h" 25 26 #define REPEAT_1_TO_2(V, T) V(T) V(T, T) 27 #define REPEAT_1_TO_3(V, T) REPEAT_1_TO_2(V, T) V(T, T, T) 28 #define REPEAT_1_TO_4(V, T) REPEAT_1_TO_3(V, T) V(T, T, T, T) 29 #define REPEAT_1_TO_5(V, T) REPEAT_1_TO_4(V, T) V(T, T, T, T, T) 30 #define REPEAT_1_TO_6(V, T) REPEAT_1_TO_5(V, T) V(T, T, T, T, T, T) 31 #define REPEAT_1_TO_7(V, T) REPEAT_1_TO_6(V, T) V(T, T, T, T, T, T, T) 32 #define REPEAT_1_TO_8(V, T) REPEAT_1_TO_7(V, T) V(T, T, T, T, T, T, T, T) 33 #define REPEAT_1_TO_9(V, T) REPEAT_1_TO_8(V, T) V(T, T, T, T, T, T, T, T, T) 34 35 namespace v8 { 36 namespace internal { 37 namespace compiler { 38 39 CodeAssemblerState::CodeAssemblerState( 40 Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor, 41 Code::Flags flags, const char* name, size_t result_size) 42 : CodeAssemblerState( 43 isolate, zone, 44 Linkage::GetStubCallDescriptor( 45 isolate, zone, descriptor, descriptor.GetStackParameterCount(), 46 CallDescriptor::kNoFlags, Operator::kNoProperties, 47 MachineType::AnyTagged(), result_size), 48 flags, name) {} 49 50 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone, 51 int parameter_count, Code::Flags flags, 52 const char* name) 53 : CodeAssemblerState(isolate, zone, 54 Linkage::GetJSCallDescriptor( 55 zone, false, parameter_count, 56 Code::ExtractKindFromFlags(flags) == Code::BUILTIN 57 ? CallDescriptor::kPushArgumentCount 58 : CallDescriptor::kNoFlags), 59 flags, name) {} 60 61 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone, 62 CallDescriptor* call_descriptor, 63 Code::Flags flags, const char* name) 64 : raw_assembler_(new RawMachineAssembler( 65 isolate, new (zone) Graph(zone), call_descriptor, 66 MachineType::PointerRepresentation(), 67 InstructionSelector::SupportedMachineOperatorFlags(), 68 InstructionSelector::AlignmentRequirements())), 69 flags_(flags), 70 name_(name), 71 code_generated_(false), 72 variables_(zone) {} 73 74 CodeAssemblerState::~CodeAssemblerState() {} 75 76 int CodeAssemblerState::parameter_count() const { 77 return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount()); 78 } 79 80 CodeAssembler::~CodeAssembler() {} 81 82 class BreakOnNodeDecorator final : public GraphDecorator { 83 public: 84 explicit BreakOnNodeDecorator(NodeId node_id) : node_id_(node_id) {} 85 86 void Decorate(Node* node) final { 87 if (node->id() == node_id_) { 88 base::OS::DebugBreak(); 89 } 90 } 91 92 private: 93 NodeId node_id_; 94 }; 95 96 void CodeAssembler::BreakOnNode(int node_id) { 97 Graph* graph = raw_assembler()->graph(); 98 Zone* zone = graph->zone(); 99 GraphDecorator* decorator = 100 new (zone) BreakOnNodeDecorator(static_cast<NodeId>(node_id)); 101 graph->AddDecorator(decorator); 102 } 103 104 void CodeAssembler::RegisterCallGenerationCallbacks( 105 const CodeAssemblerCallback& call_prologue, 106 const CodeAssemblerCallback& call_epilogue) { 107 // The callback can be registered only once. 108 DCHECK(!state_->call_prologue_); 109 DCHECK(!state_->call_epilogue_); 110 state_->call_prologue_ = call_prologue; 111 state_->call_epilogue_ = call_epilogue; 112 } 113 114 void CodeAssembler::UnregisterCallGenerationCallbacks() { 115 state_->call_prologue_ = nullptr; 116 state_->call_epilogue_ = nullptr; 117 } 118 119 void CodeAssembler::CallPrologue() { 120 if (state_->call_prologue_) { 121 state_->call_prologue_(); 122 } 123 } 124 125 void CodeAssembler::CallEpilogue() { 126 if (state_->call_epilogue_) { 127 state_->call_epilogue_(); 128 } 129 } 130 131 // static 132 Handle<Code> CodeAssembler::GenerateCode(CodeAssemblerState* state) { 133 DCHECK(!state->code_generated_); 134 135 RawMachineAssembler* rasm = state->raw_assembler_.get(); 136 Schedule* schedule = rasm->Export(); 137 Handle<Code> code = Pipeline::GenerateCodeForCodeStub( 138 rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule, 139 state->flags_, state->name_); 140 141 state->code_generated_ = true; 142 return code; 143 } 144 145 bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); } 146 147 bool CodeAssembler::IsFloat64RoundUpSupported() const { 148 return raw_assembler()->machine()->Float64RoundUp().IsSupported(); 149 } 150 151 bool CodeAssembler::IsFloat64RoundDownSupported() const { 152 return raw_assembler()->machine()->Float64RoundDown().IsSupported(); 153 } 154 155 bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const { 156 return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported(); 157 } 158 159 bool CodeAssembler::IsFloat64RoundTruncateSupported() const { 160 return raw_assembler()->machine()->Float64RoundTruncate().IsSupported(); 161 } 162 163 Node* CodeAssembler::Int32Constant(int32_t value) { 164 return raw_assembler()->Int32Constant(value); 165 } 166 167 Node* CodeAssembler::Int64Constant(int64_t value) { 168 return raw_assembler()->Int64Constant(value); 169 } 170 171 Node* CodeAssembler::IntPtrConstant(intptr_t value) { 172 return raw_assembler()->IntPtrConstant(value); 173 } 174 175 Node* CodeAssembler::NumberConstant(double value) { 176 return raw_assembler()->NumberConstant(value); 177 } 178 179 Node* CodeAssembler::SmiConstant(Smi* value) { 180 return BitcastWordToTaggedSigned(IntPtrConstant(bit_cast<intptr_t>(value))); 181 } 182 183 Node* CodeAssembler::SmiConstant(int value) { 184 return SmiConstant(Smi::FromInt(value)); 185 } 186 187 Node* CodeAssembler::HeapConstant(Handle<HeapObject> object) { 188 return raw_assembler()->HeapConstant(object); 189 } 190 191 Node* CodeAssembler::CStringConstant(const char* str) { 192 return HeapConstant(factory()->NewStringFromAsciiChecked(str, TENURED)); 193 } 194 195 Node* CodeAssembler::BooleanConstant(bool value) { 196 return raw_assembler()->BooleanConstant(value); 197 } 198 199 Node* CodeAssembler::ExternalConstant(ExternalReference address) { 200 return raw_assembler()->ExternalConstant(address); 201 } 202 203 Node* CodeAssembler::Float64Constant(double value) { 204 return raw_assembler()->Float64Constant(value); 205 } 206 207 Node* CodeAssembler::NaNConstant() { 208 return LoadRoot(Heap::kNanValueRootIndex); 209 } 210 211 bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) { 212 Int64Matcher m(node); 213 if (m.HasValue() && 214 m.IsInRange(std::numeric_limits<int32_t>::min(), 215 std::numeric_limits<int32_t>::max())) { 216 out_value = static_cast<int32_t>(m.Value()); 217 return true; 218 } 219 220 return false; 221 } 222 223 bool CodeAssembler::ToInt64Constant(Node* node, int64_t& out_value) { 224 Int64Matcher m(node); 225 if (m.HasValue()) out_value = m.Value(); 226 return m.HasValue(); 227 } 228 229 bool CodeAssembler::ToSmiConstant(Node* node, Smi*& out_value) { 230 if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned) { 231 node = node->InputAt(0); 232 } else { 233 return false; 234 } 235 IntPtrMatcher m(node); 236 if (m.HasValue()) { 237 out_value = Smi::cast(bit_cast<Object*>(m.Value())); 238 return true; 239 } 240 return false; 241 } 242 243 bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t& out_value) { 244 if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned || 245 node->opcode() == IrOpcode::kBitcastWordToTagged) { 246 node = node->InputAt(0); 247 } 248 IntPtrMatcher m(node); 249 if (m.HasValue()) out_value = m.Value(); 250 return m.HasValue(); 251 } 252 253 Node* CodeAssembler::Parameter(int value) { 254 return raw_assembler()->Parameter(value); 255 } 256 257 Node* CodeAssembler::GetJSContextParameter() { 258 CallDescriptor* desc = raw_assembler()->call_descriptor(); 259 DCHECK(desc->IsJSFunctionCall()); 260 return Parameter(Linkage::GetJSCallContextParamIndex( 261 static_cast<int>(desc->JSParameterCount()))); 262 } 263 264 void CodeAssembler::Return(Node* value) { 265 return raw_assembler()->Return(value); 266 } 267 268 void CodeAssembler::Return(Node* value1, Node* value2) { 269 return raw_assembler()->Return(value1, value2); 270 } 271 272 void CodeAssembler::Return(Node* value1, Node* value2, Node* value3) { 273 return raw_assembler()->Return(value1, value2, value3); 274 } 275 276 void CodeAssembler::PopAndReturn(Node* pop, Node* value) { 277 return raw_assembler()->PopAndReturn(pop, value); 278 } 279 280 void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); } 281 282 void CodeAssembler::Unreachable() { 283 DebugBreak(); 284 raw_assembler()->Unreachable(); 285 } 286 287 void CodeAssembler::Comment(const char* format, ...) { 288 if (!FLAG_code_comments) return; 289 char buffer[4 * KB]; 290 StringBuilder builder(buffer, arraysize(buffer)); 291 va_list arguments; 292 va_start(arguments, format); 293 builder.AddFormattedList(format, arguments); 294 va_end(arguments); 295 296 // Copy the string before recording it in the assembler to avoid 297 // issues when the stack allocated buffer goes out of scope. 298 const int prefix_len = 2; 299 int length = builder.position() + 1; 300 char* copy = reinterpret_cast<char*>(malloc(length + prefix_len)); 301 MemCopy(copy + prefix_len, builder.Finalize(), length); 302 copy[0] = ';'; 303 copy[1] = ' '; 304 raw_assembler()->Comment(copy); 305 } 306 307 void CodeAssembler::Bind(Label* label) { return label->Bind(); } 308 309 Node* CodeAssembler::LoadFramePointer() { 310 return raw_assembler()->LoadFramePointer(); 311 } 312 313 Node* CodeAssembler::LoadParentFramePointer() { 314 return raw_assembler()->LoadParentFramePointer(); 315 } 316 317 Node* CodeAssembler::LoadStackPointer() { 318 return raw_assembler()->LoadStackPointer(); 319 } 320 321 #define DEFINE_CODE_ASSEMBLER_BINARY_OP(name) \ 322 Node* CodeAssembler::name(Node* a, Node* b) { \ 323 return raw_assembler()->name(a, b); \ 324 } 325 CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP) 326 #undef DEFINE_CODE_ASSEMBLER_BINARY_OP 327 328 Node* CodeAssembler::IntPtrAdd(Node* left, Node* right) { 329 intptr_t left_constant; 330 bool is_left_constant = ToIntPtrConstant(left, left_constant); 331 intptr_t right_constant; 332 bool is_right_constant = ToIntPtrConstant(right, right_constant); 333 if (is_left_constant) { 334 if (is_right_constant) { 335 return IntPtrConstant(left_constant + right_constant); 336 } 337 if (left_constant == 0) { 338 return right; 339 } 340 } else if (is_right_constant) { 341 if (right_constant == 0) { 342 return left; 343 } 344 } 345 return raw_assembler()->IntPtrAdd(left, right); 346 } 347 348 Node* CodeAssembler::IntPtrSub(Node* left, Node* right) { 349 intptr_t left_constant; 350 bool is_left_constant = ToIntPtrConstant(left, left_constant); 351 intptr_t right_constant; 352 bool is_right_constant = ToIntPtrConstant(right, right_constant); 353 if (is_left_constant) { 354 if (is_right_constant) { 355 return IntPtrConstant(left_constant - right_constant); 356 } 357 } else if (is_right_constant) { 358 if (right_constant == 0) { 359 return left; 360 } 361 } 362 return raw_assembler()->IntPtrSub(left, right); 363 } 364 365 Node* CodeAssembler::WordShl(Node* value, int shift) { 366 return (shift != 0) ? raw_assembler()->WordShl(value, IntPtrConstant(shift)) 367 : value; 368 } 369 370 Node* CodeAssembler::WordShr(Node* value, int shift) { 371 return (shift != 0) ? raw_assembler()->WordShr(value, IntPtrConstant(shift)) 372 : value; 373 } 374 375 Node* CodeAssembler::Word32Shr(Node* value, int shift) { 376 return (shift != 0) ? raw_assembler()->Word32Shr(value, Int32Constant(shift)) 377 : value; 378 } 379 380 Node* CodeAssembler::ChangeUint32ToWord(Node* value) { 381 if (raw_assembler()->machine()->Is64()) { 382 value = raw_assembler()->ChangeUint32ToUint64(value); 383 } 384 return value; 385 } 386 387 Node* CodeAssembler::ChangeInt32ToIntPtr(Node* value) { 388 if (raw_assembler()->machine()->Is64()) { 389 value = raw_assembler()->ChangeInt32ToInt64(value); 390 } 391 return value; 392 } 393 394 Node* CodeAssembler::RoundIntPtrToFloat64(Node* value) { 395 if (raw_assembler()->machine()->Is64()) { 396 return raw_assembler()->RoundInt64ToFloat64(value); 397 } 398 return raw_assembler()->ChangeInt32ToFloat64(value); 399 } 400 401 #define DEFINE_CODE_ASSEMBLER_UNARY_OP(name) \ 402 Node* CodeAssembler::name(Node* a) { return raw_assembler()->name(a); } 403 CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP) 404 #undef DEFINE_CODE_ASSEMBLER_UNARY_OP 405 406 Node* CodeAssembler::Load(MachineType rep, Node* base) { 407 return raw_assembler()->Load(rep, base); 408 } 409 410 Node* CodeAssembler::Load(MachineType rep, Node* base, Node* offset) { 411 return raw_assembler()->Load(rep, base, offset); 412 } 413 414 Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* offset) { 415 return raw_assembler()->AtomicLoad(rep, base, offset); 416 } 417 418 Node* CodeAssembler::LoadRoot(Heap::RootListIndex root_index) { 419 if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) { 420 Handle<Object> root = isolate()->heap()->root_handle(root_index); 421 if (root->IsSmi()) { 422 return SmiConstant(Smi::cast(*root)); 423 } else { 424 return HeapConstant(Handle<HeapObject>::cast(root)); 425 } 426 } 427 428 Node* roots_array_start = 429 ExternalConstant(ExternalReference::roots_array_start(isolate())); 430 return Load(MachineType::AnyTagged(), roots_array_start, 431 IntPtrConstant(root_index * kPointerSize)); 432 } 433 434 Node* CodeAssembler::Store(Node* base, Node* value) { 435 return raw_assembler()->Store(MachineRepresentation::kTagged, base, value, 436 kFullWriteBarrier); 437 } 438 439 Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) { 440 return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, 441 value, kFullWriteBarrier); 442 } 443 444 Node* CodeAssembler::StoreWithMapWriteBarrier(Node* base, Node* offset, 445 Node* value) { 446 return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, 447 value, kMapWriteBarrier); 448 } 449 450 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base, 451 Node* value) { 452 return raw_assembler()->Store(rep, base, value, kNoWriteBarrier); 453 } 454 455 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base, 456 Node* offset, Node* value) { 457 return raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier); 458 } 459 460 Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base, 461 Node* offset, Node* value) { 462 return raw_assembler()->AtomicStore(rep, base, offset, value); 463 } 464 465 Node* CodeAssembler::StoreRoot(Heap::RootListIndex root_index, Node* value) { 466 DCHECK(Heap::RootCanBeWrittenAfterInitialization(root_index)); 467 Node* roots_array_start = 468 ExternalConstant(ExternalReference::roots_array_start(isolate())); 469 return StoreNoWriteBarrier(MachineRepresentation::kTagged, roots_array_start, 470 IntPtrConstant(root_index * kPointerSize), value); 471 } 472 473 Node* CodeAssembler::Retain(Node* value) { 474 return raw_assembler()->Retain(value); 475 } 476 477 Node* CodeAssembler::Projection(int index, Node* value) { 478 return raw_assembler()->Projection(index, value); 479 } 480 481 void CodeAssembler::GotoIfException(Node* node, Label* if_exception, 482 Variable* exception_var) { 483 Label success(this), exception(this, Label::kDeferred); 484 success.MergeVariables(); 485 exception.MergeVariables(); 486 DCHECK(!node->op()->HasProperty(Operator::kNoThrow)); 487 488 raw_assembler()->Continuations(node, success.label_, exception.label_); 489 490 Bind(&exception); 491 const Operator* op = raw_assembler()->common()->IfException(); 492 Node* exception_value = raw_assembler()->AddNode(op, node, node); 493 if (exception_var != nullptr) { 494 exception_var->Bind(exception_value); 495 } 496 Goto(if_exception); 497 498 Bind(&success); 499 } 500 501 template <class... TArgs> 502 Node* CodeAssembler::CallRuntime(Runtime::FunctionId function, Node* context, 503 TArgs... args) { 504 int argc = static_cast<int>(sizeof...(args)); 505 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( 506 zone(), function, argc, Operator::kNoProperties, 507 CallDescriptor::kNoFlags); 508 int return_count = static_cast<int>(desc->ReturnCount()); 509 510 Node* centry = 511 HeapConstant(CodeFactory::RuntimeCEntry(isolate(), return_count)); 512 Node* ref = ExternalConstant(ExternalReference(function, isolate())); 513 Node* arity = Int32Constant(argc); 514 515 Node* nodes[] = {centry, args..., ref, arity, context}; 516 517 CallPrologue(); 518 Node* return_value = raw_assembler()->CallN(desc, arraysize(nodes), nodes); 519 CallEpilogue(); 520 return return_value; 521 } 522 523 // Instantiate CallRuntime() with up to 6 arguments. 524 #define INSTANTIATE(...) \ 525 template V8_EXPORT_PRIVATE Node* CodeAssembler::CallRuntime( \ 526 Runtime::FunctionId, __VA_ARGS__); 527 REPEAT_1_TO_7(INSTANTIATE, Node*) 528 #undef INSTANTIATE 529 530 template <class... TArgs> 531 Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function, 532 Node* context, TArgs... args) { 533 int argc = static_cast<int>(sizeof...(args)); 534 CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( 535 zone(), function, argc, Operator::kNoProperties, 536 CallDescriptor::kSupportsTailCalls); 537 int return_count = static_cast<int>(desc->ReturnCount()); 538 539 Node* centry = 540 HeapConstant(CodeFactory::RuntimeCEntry(isolate(), return_count)); 541 Node* ref = ExternalConstant(ExternalReference(function, isolate())); 542 Node* arity = Int32Constant(argc); 543 544 Node* nodes[] = {centry, args..., ref, arity, context}; 545 546 return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes); 547 } 548 549 // Instantiate TailCallRuntime() with up to 6 arguments. 550 #define INSTANTIATE(...) \ 551 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallRuntime( \ 552 Runtime::FunctionId, __VA_ARGS__); 553 REPEAT_1_TO_7(INSTANTIATE, Node*) 554 #undef INSTANTIATE 555 556 template <class... TArgs> 557 Node* CodeAssembler::CallStubR(const CallInterfaceDescriptor& descriptor, 558 size_t result_size, Node* target, Node* context, 559 TArgs... args) { 560 Node* nodes[] = {target, args..., context}; 561 return CallStubN(descriptor, result_size, arraysize(nodes), nodes); 562 } 563 564 // Instantiate CallStubR() with up to 6 arguments. 565 #define INSTANTIATE(...) \ 566 template V8_EXPORT_PRIVATE Node* CodeAssembler::CallStubR( \ 567 const CallInterfaceDescriptor& descriptor, size_t, Node*, __VA_ARGS__); 568 REPEAT_1_TO_7(INSTANTIATE, Node*) 569 #undef INSTANTIATE 570 571 Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor, 572 size_t result_size, int input_count, 573 Node* const* inputs) { 574 // 2 is for target and context. 575 DCHECK_LE(2, input_count); 576 int argc = input_count - 2; 577 DCHECK_LE(descriptor.GetParameterCount(), argc); 578 // Extra arguments not mentioned in the descriptor are passed on the stack. 579 int stack_parameter_count = argc - descriptor.GetRegisterParameterCount(); 580 DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count); 581 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 582 isolate(), zone(), descriptor, stack_parameter_count, 583 CallDescriptor::kNoFlags, Operator::kNoProperties, 584 MachineType::AnyTagged(), result_size); 585 586 CallPrologue(); 587 Node* return_value = raw_assembler()->CallN(desc, input_count, inputs); 588 CallEpilogue(); 589 return return_value; 590 } 591 592 template <class... TArgs> 593 Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor, 594 Node* target, Node* context, TArgs... args) { 595 DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args)); 596 size_t result_size = 1; 597 CallDescriptor* desc = Linkage::GetStubCallDescriptor( 598 isolate(), zone(), descriptor, descriptor.GetStackParameterCount(), 599 CallDescriptor::kSupportsTailCalls, Operator::kNoProperties, 600 MachineType::AnyTagged(), result_size); 601 602 Node* nodes[] = {target, args..., context}; 603 604 return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes); 605 } 606 607 // Instantiate TailCallStub() with up to 6 arguments. 608 #define INSTANTIATE(...) \ 609 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallStub( \ 610 const CallInterfaceDescriptor& descriptor, Node*, __VA_ARGS__); 611 REPEAT_1_TO_7(INSTANTIATE, Node*) 612 #undef INSTANTIATE 613 614 template <class... TArgs> 615 Node* CodeAssembler::TailCallBytecodeDispatch( 616 const CallInterfaceDescriptor& descriptor, Node* target, TArgs... args) { 617 DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args)); 618 CallDescriptor* desc = Linkage::GetBytecodeDispatchCallDescriptor( 619 isolate(), zone(), descriptor, descriptor.GetStackParameterCount()); 620 621 Node* nodes[] = {target, args...}; 622 return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes); 623 } 624 625 // Instantiate TailCallBytecodeDispatch() with 4 arguments. 626 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallBytecodeDispatch( 627 const CallInterfaceDescriptor& descriptor, Node* target, Node*, Node*, 628 Node*, Node*); 629 630 Node* CodeAssembler::CallCFunctionN(Signature<MachineType>* signature, 631 int input_count, Node* const* inputs) { 632 CallDescriptor* desc = Linkage::GetSimplifiedCDescriptor(zone(), signature); 633 return raw_assembler()->CallN(desc, input_count, inputs); 634 } 635 636 Node* CodeAssembler::CallCFunction2(MachineType return_type, 637 MachineType arg0_type, 638 MachineType arg1_type, Node* function, 639 Node* arg0, Node* arg1) { 640 return raw_assembler()->CallCFunction2(return_type, arg0_type, arg1_type, 641 function, arg0, arg1); 642 } 643 644 Node* CodeAssembler::CallCFunction3(MachineType return_type, 645 MachineType arg0_type, 646 MachineType arg1_type, 647 MachineType arg2_type, Node* function, 648 Node* arg0, Node* arg1, Node* arg2) { 649 return raw_assembler()->CallCFunction3(return_type, arg0_type, arg1_type, 650 arg2_type, function, arg0, arg1, arg2); 651 } 652 653 void CodeAssembler::Goto(Label* label) { 654 label->MergeVariables(); 655 raw_assembler()->Goto(label->label_); 656 } 657 658 void CodeAssembler::GotoIf(Node* condition, Label* true_label) { 659 Label false_label(this); 660 Branch(condition, true_label, &false_label); 661 Bind(&false_label); 662 } 663 664 void CodeAssembler::GotoIfNot(Node* condition, Label* false_label) { 665 Label true_label(this); 666 Branch(condition, &true_label, false_label); 667 Bind(&true_label); 668 } 669 670 void CodeAssembler::Branch(Node* condition, Label* true_label, 671 Label* false_label) { 672 true_label->MergeVariables(); 673 false_label->MergeVariables(); 674 return raw_assembler()->Branch(condition, true_label->label_, 675 false_label->label_); 676 } 677 678 void CodeAssembler::Switch(Node* index, Label* default_label, 679 const int32_t* case_values, Label** case_labels, 680 size_t case_count) { 681 RawMachineLabel** labels = 682 new (zone()->New(sizeof(RawMachineLabel*) * case_count)) 683 RawMachineLabel*[case_count]; 684 for (size_t i = 0; i < case_count; ++i) { 685 labels[i] = case_labels[i]->label_; 686 case_labels[i]->MergeVariables(); 687 default_label->MergeVariables(); 688 } 689 return raw_assembler()->Switch(index, default_label->label_, case_values, 690 labels, case_count); 691 } 692 693 // RawMachineAssembler delegate helpers: 694 Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); } 695 696 Factory* CodeAssembler::factory() const { return isolate()->factory(); } 697 698 Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); } 699 700 RawMachineAssembler* CodeAssembler::raw_assembler() const { 701 return state_->raw_assembler_.get(); 702 } 703 704 // The core implementation of Variable is stored through an indirection so 705 // that it can outlive the often block-scoped Variable declarations. This is 706 // needed to ensure that variable binding and merging through phis can 707 // properly be verified. 708 class CodeAssemblerVariable::Impl : public ZoneObject { 709 public: 710 explicit Impl(MachineRepresentation rep) : value_(nullptr), rep_(rep) {} 711 Node* value_; 712 MachineRepresentation rep_; 713 }; 714 715 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler, 716 MachineRepresentation rep) 717 : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) { 718 state_->variables_.insert(impl_); 719 } 720 721 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler, 722 MachineRepresentation rep, 723 Node* initial_value) 724 : CodeAssemblerVariable(assembler, rep) { 725 Bind(initial_value); 726 } 727 728 CodeAssemblerVariable::~CodeAssemblerVariable() { 729 state_->variables_.erase(impl_); 730 } 731 732 void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; } 733 734 Node* CodeAssemblerVariable::value() const { 735 DCHECK_NOT_NULL(impl_->value_); 736 return impl_->value_; 737 } 738 739 MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; } 740 741 bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; } 742 743 CodeAssemblerLabel::CodeAssemblerLabel(CodeAssembler* assembler, 744 size_t vars_count, 745 CodeAssemblerVariable** vars, 746 CodeAssemblerLabel::Type type) 747 : bound_(false), 748 merge_count_(0), 749 state_(assembler->state()), 750 label_(nullptr) { 751 void* buffer = assembler->zone()->New(sizeof(RawMachineLabel)); 752 label_ = new (buffer) 753 RawMachineLabel(type == kDeferred ? RawMachineLabel::kDeferred 754 : RawMachineLabel::kNonDeferred); 755 for (size_t i = 0; i < vars_count; ++i) { 756 variable_phis_[vars[i]->impl_] = nullptr; 757 } 758 } 759 760 CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); } 761 762 void CodeAssemblerLabel::MergeVariables() { 763 ++merge_count_; 764 for (auto var : state_->variables_) { 765 size_t count = 0; 766 Node* node = var->value_; 767 if (node != nullptr) { 768 auto i = variable_merges_.find(var); 769 if (i != variable_merges_.end()) { 770 i->second.push_back(node); 771 count = i->second.size(); 772 } else { 773 count = 1; 774 variable_merges_[var] = std::vector<Node*>(1, node); 775 } 776 } 777 // If the following asserts, then you've jumped to a label without a bound 778 // variable along that path that expects to merge its value into a phi. 779 DCHECK(variable_phis_.find(var) == variable_phis_.end() || 780 count == merge_count_); 781 USE(count); 782 783 // If the label is already bound, we already know the set of variables to 784 // merge and phi nodes have already been created. 785 if (bound_) { 786 auto phi = variable_phis_.find(var); 787 if (phi != variable_phis_.end()) { 788 DCHECK_NOT_NULL(phi->second); 789 state_->raw_assembler_->AppendPhiInput(phi->second, node); 790 } else { 791 auto i = variable_merges_.find(var); 792 if (i != variable_merges_.end()) { 793 // If the following assert fires, then you've declared a variable that 794 // has the same bound value along all paths up until the point you 795 // bound this label, but then later merged a path with a new value for 796 // the variable after the label bind (it's not possible to add phis to 797 // the bound label after the fact, just make sure to list the variable 798 // in the label's constructor's list of merged variables). 799 DCHECK(find_if(i->second.begin(), i->second.end(), 800 [node](Node* e) -> bool { return node != e; }) == 801 i->second.end()); 802 } 803 } 804 } 805 } 806 } 807 808 void CodeAssemblerLabel::Bind() { 809 DCHECK(!bound_); 810 state_->raw_assembler_->Bind(label_); 811 812 // Make sure that all variables that have changed along any path up to this 813 // point are marked as merge variables. 814 for (auto var : state_->variables_) { 815 Node* shared_value = nullptr; 816 auto i = variable_merges_.find(var); 817 if (i != variable_merges_.end()) { 818 for (auto value : i->second) { 819 DCHECK(value != nullptr); 820 if (value != shared_value) { 821 if (shared_value == nullptr) { 822 shared_value = value; 823 } else { 824 variable_phis_[var] = nullptr; 825 } 826 } 827 } 828 } 829 } 830 831 for (auto var : variable_phis_) { 832 CodeAssemblerVariable::Impl* var_impl = var.first; 833 auto i = variable_merges_.find(var_impl); 834 // If the following asserts fire, then a variable that has been marked as 835 // being merged at the label--either by explicitly marking it so in the 836 // label constructor or by having seen different bound values at branches 837 // into the label--doesn't have a bound value along all of the paths that 838 // have been merged into the label up to this point. 839 DCHECK(i != variable_merges_.end()); 840 DCHECK_EQ(i->second.size(), merge_count_); 841 Node* phi = state_->raw_assembler_->Phi( 842 var.first->rep_, static_cast<int>(merge_count_), &(i->second[0])); 843 variable_phis_[var_impl] = phi; 844 } 845 846 // Bind all variables to a merge phi, the common value along all paths or 847 // null. 848 for (auto var : state_->variables_) { 849 auto i = variable_phis_.find(var); 850 if (i != variable_phis_.end()) { 851 var->value_ = i->second; 852 } else { 853 auto j = variable_merges_.find(var); 854 if (j != variable_merges_.end() && j->second.size() == merge_count_) { 855 var->value_ = j->second.back(); 856 } else { 857 var->value_ = nullptr; 858 } 859 } 860 } 861 862 bound_ = true; 863 } 864 865 } // namespace compiler 866 } // namespace internal 867 } // namespace v8 868