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