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 35namespace v8 { 36namespace internal { 37namespace compiler { 38 39CodeAssemblerState::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 50CodeAssemblerState::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 61CodeAssemblerState::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 74CodeAssemblerState::~CodeAssemblerState() {} 75 76int CodeAssemblerState::parameter_count() const { 77 return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount()); 78} 79 80CodeAssembler::~CodeAssembler() {} 81 82class 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 96void 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 104void 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 114void CodeAssembler::UnregisterCallGenerationCallbacks() { 115 state_->call_prologue_ = nullptr; 116 state_->call_epilogue_ = nullptr; 117} 118 119void CodeAssembler::CallPrologue() { 120 if (state_->call_prologue_) { 121 state_->call_prologue_(); 122 } 123} 124 125void CodeAssembler::CallEpilogue() { 126 if (state_->call_epilogue_) { 127 state_->call_epilogue_(); 128 } 129} 130 131// static 132Handle<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 145bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); } 146 147bool CodeAssembler::IsFloat64RoundUpSupported() const { 148 return raw_assembler()->machine()->Float64RoundUp().IsSupported(); 149} 150 151bool CodeAssembler::IsFloat64RoundDownSupported() const { 152 return raw_assembler()->machine()->Float64RoundDown().IsSupported(); 153} 154 155bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const { 156 return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported(); 157} 158 159bool CodeAssembler::IsFloat64RoundTruncateSupported() const { 160 return raw_assembler()->machine()->Float64RoundTruncate().IsSupported(); 161} 162 163Node* CodeAssembler::Int32Constant(int32_t value) { 164 return raw_assembler()->Int32Constant(value); 165} 166 167Node* CodeAssembler::Int64Constant(int64_t value) { 168 return raw_assembler()->Int64Constant(value); 169} 170 171Node* CodeAssembler::IntPtrConstant(intptr_t value) { 172 return raw_assembler()->IntPtrConstant(value); 173} 174 175Node* CodeAssembler::NumberConstant(double value) { 176 return raw_assembler()->NumberConstant(value); 177} 178 179Node* CodeAssembler::SmiConstant(Smi* value) { 180 return BitcastWordToTaggedSigned(IntPtrConstant(bit_cast<intptr_t>(value))); 181} 182 183Node* CodeAssembler::SmiConstant(int value) { 184 return SmiConstant(Smi::FromInt(value)); 185} 186 187Node* CodeAssembler::HeapConstant(Handle<HeapObject> object) { 188 return raw_assembler()->HeapConstant(object); 189} 190 191Node* CodeAssembler::CStringConstant(const char* str) { 192 return HeapConstant(factory()->NewStringFromAsciiChecked(str, TENURED)); 193} 194 195Node* CodeAssembler::BooleanConstant(bool value) { 196 return raw_assembler()->BooleanConstant(value); 197} 198 199Node* CodeAssembler::ExternalConstant(ExternalReference address) { 200 return raw_assembler()->ExternalConstant(address); 201} 202 203Node* CodeAssembler::Float64Constant(double value) { 204 return raw_assembler()->Float64Constant(value); 205} 206 207Node* CodeAssembler::NaNConstant() { 208 return LoadRoot(Heap::kNanValueRootIndex); 209} 210 211bool 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 223bool 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 229bool 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 243bool 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 253Node* CodeAssembler::Parameter(int value) { 254 return raw_assembler()->Parameter(value); 255} 256 257Node* 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 264void CodeAssembler::Return(Node* value) { 265 return raw_assembler()->Return(value); 266} 267 268void CodeAssembler::Return(Node* value1, Node* value2) { 269 return raw_assembler()->Return(value1, value2); 270} 271 272void CodeAssembler::Return(Node* value1, Node* value2, Node* value3) { 273 return raw_assembler()->Return(value1, value2, value3); 274} 275 276void CodeAssembler::PopAndReturn(Node* pop, Node* value) { 277 return raw_assembler()->PopAndReturn(pop, value); 278} 279 280void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); } 281 282void CodeAssembler::Unreachable() { 283 DebugBreak(); 284 raw_assembler()->Unreachable(); 285} 286 287void 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 307void CodeAssembler::Bind(Label* label) { return label->Bind(); } 308 309Node* CodeAssembler::LoadFramePointer() { 310 return raw_assembler()->LoadFramePointer(); 311} 312 313Node* CodeAssembler::LoadParentFramePointer() { 314 return raw_assembler()->LoadParentFramePointer(); 315} 316 317Node* 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 } 325CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP) 326#undef DEFINE_CODE_ASSEMBLER_BINARY_OP 327 328Node* 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 348Node* 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 365Node* CodeAssembler::WordShl(Node* value, int shift) { 366 return (shift != 0) ? raw_assembler()->WordShl(value, IntPtrConstant(shift)) 367 : value; 368} 369 370Node* CodeAssembler::WordShr(Node* value, int shift) { 371 return (shift != 0) ? raw_assembler()->WordShr(value, IntPtrConstant(shift)) 372 : value; 373} 374 375Node* CodeAssembler::Word32Shr(Node* value, int shift) { 376 return (shift != 0) ? raw_assembler()->Word32Shr(value, Int32Constant(shift)) 377 : value; 378} 379 380Node* CodeAssembler::ChangeUint32ToWord(Node* value) { 381 if (raw_assembler()->machine()->Is64()) { 382 value = raw_assembler()->ChangeUint32ToUint64(value); 383 } 384 return value; 385} 386 387Node* CodeAssembler::ChangeInt32ToIntPtr(Node* value) { 388 if (raw_assembler()->machine()->Is64()) { 389 value = raw_assembler()->ChangeInt32ToInt64(value); 390 } 391 return value; 392} 393 394Node* 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); } 403CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP) 404#undef DEFINE_CODE_ASSEMBLER_UNARY_OP 405 406Node* CodeAssembler::Load(MachineType rep, Node* base) { 407 return raw_assembler()->Load(rep, base); 408} 409 410Node* CodeAssembler::Load(MachineType rep, Node* base, Node* offset) { 411 return raw_assembler()->Load(rep, base, offset); 412} 413 414Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* offset) { 415 return raw_assembler()->AtomicLoad(rep, base, offset); 416} 417 418Node* 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 434Node* CodeAssembler::Store(Node* base, Node* value) { 435 return raw_assembler()->Store(MachineRepresentation::kTagged, base, value, 436 kFullWriteBarrier); 437} 438 439Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) { 440 return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, 441 value, kFullWriteBarrier); 442} 443 444Node* CodeAssembler::StoreWithMapWriteBarrier(Node* base, Node* offset, 445 Node* value) { 446 return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset, 447 value, kMapWriteBarrier); 448} 449 450Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base, 451 Node* value) { 452 return raw_assembler()->Store(rep, base, value, kNoWriteBarrier); 453} 454 455Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base, 456 Node* offset, Node* value) { 457 return raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier); 458} 459 460Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base, 461 Node* offset, Node* value) { 462 return raw_assembler()->AtomicStore(rep, base, offset, value); 463} 464 465Node* 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 473Node* CodeAssembler::Retain(Node* value) { 474 return raw_assembler()->Retain(value); 475} 476 477Node* CodeAssembler::Projection(int index, Node* value) { 478 return raw_assembler()->Projection(index, value); 479} 480 481void 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 501template <class... TArgs> 502Node* 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__); 527REPEAT_1_TO_7(INSTANTIATE, Node*) 528#undef INSTANTIATE 529 530template <class... TArgs> 531Node* 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__); 553REPEAT_1_TO_7(INSTANTIATE, Node*) 554#undef INSTANTIATE 555 556template <class... TArgs> 557Node* 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__); 568REPEAT_1_TO_7(INSTANTIATE, Node*) 569#undef INSTANTIATE 570 571Node* 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 592template <class... TArgs> 593Node* 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__); 611REPEAT_1_TO_7(INSTANTIATE, Node*) 612#undef INSTANTIATE 613 614template <class... TArgs> 615Node* 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. 626template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallBytecodeDispatch( 627 const CallInterfaceDescriptor& descriptor, Node* target, Node*, Node*, 628 Node*, Node*); 629 630Node* 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 636Node* 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 644Node* 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 653void CodeAssembler::Goto(Label* label) { 654 label->MergeVariables(); 655 raw_assembler()->Goto(label->label_); 656} 657 658void 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 664void 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 670void 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 678void 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: 694Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); } 695 696Factory* CodeAssembler::factory() const { return isolate()->factory(); } 697 698Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); } 699 700RawMachineAssembler* 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. 708class CodeAssemblerVariable::Impl : public ZoneObject { 709 public: 710 explicit Impl(MachineRepresentation rep) : value_(nullptr), rep_(rep) {} 711 Node* value_; 712 MachineRepresentation rep_; 713}; 714 715CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler, 716 MachineRepresentation rep) 717 : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) { 718 state_->variables_.insert(impl_); 719} 720 721CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler, 722 MachineRepresentation rep, 723 Node* initial_value) 724 : CodeAssemblerVariable(assembler, rep) { 725 Bind(initial_value); 726} 727 728CodeAssemblerVariable::~CodeAssemblerVariable() { 729 state_->variables_.erase(impl_); 730} 731 732void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; } 733 734Node* CodeAssemblerVariable::value() const { 735 DCHECK_NOT_NULL(impl_->value_); 736 return impl_->value_; 737} 738 739MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; } 740 741bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; } 742 743CodeAssemblerLabel::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 760CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); } 761 762void 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 808void 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