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 25 namespace v8 { 26 namespace internal { 27 namespace compiler { 28 CodeAssembler(Isolate * isolate,Zone * zone,const CallInterfaceDescriptor & descriptor,Code::Flags flags,const char * name,size_t result_size)29 CodeAssembler::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 CodeAssembler(Isolate * isolate,Zone * zone,int parameter_count,Code::Flags flags,const char * name)41 CodeAssembler::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 CodeAssembler(Isolate * isolate,Zone * zone,CallDescriptor * call_descriptor,Code::Flags flags,const char * name)48 CodeAssembler::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 ~CodeAssembler()60 CodeAssembler::~CodeAssembler() {} 61 CallPrologue()62 void CodeAssembler::CallPrologue() {} 63 CallEpilogue()64 void CodeAssembler::CallEpilogue() {} 65 GenerateCode()66 Handle<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 Is64() const78 bool CodeAssembler::Is64() const { return raw_assembler_->machine()->Is64(); } 79 IsFloat64RoundUpSupported() const80 bool CodeAssembler::IsFloat64RoundUpSupported() const { 81 return raw_assembler_->machine()->Float64RoundUp().IsSupported(); 82 } 83 IsFloat64RoundDownSupported() const84 bool CodeAssembler::IsFloat64RoundDownSupported() const { 85 return raw_assembler_->machine()->Float64RoundDown().IsSupported(); 86 } 87 IsFloat64RoundTruncateSupported() const88 bool CodeAssembler::IsFloat64RoundTruncateSupported() const { 89 return raw_assembler_->machine()->Float64RoundTruncate().IsSupported(); 90 } 91 Int32Constant(int32_t value)92 Node* CodeAssembler::Int32Constant(int32_t value) { 93 return raw_assembler_->Int32Constant(value); 94 } 95 Int64Constant(int64_t value)96 Node* CodeAssembler::Int64Constant(int64_t value) { 97 return raw_assembler_->Int64Constant(value); 98 } 99 IntPtrConstant(intptr_t value)100 Node* CodeAssembler::IntPtrConstant(intptr_t value) { 101 return raw_assembler_->IntPtrConstant(value); 102 } 103 NumberConstant(double value)104 Node* CodeAssembler::NumberConstant(double value) { 105 return raw_assembler_->NumberConstant(value); 106 } 107 SmiConstant(Smi * value)108 Node* CodeAssembler::SmiConstant(Smi* value) { 109 return IntPtrConstant(bit_cast<intptr_t>(value)); 110 } 111 HeapConstant(Handle<HeapObject> object)112 Node* CodeAssembler::HeapConstant(Handle<HeapObject> object) { 113 return raw_assembler_->HeapConstant(object); 114 } 115 BooleanConstant(bool value)116 Node* CodeAssembler::BooleanConstant(bool value) { 117 return raw_assembler_->BooleanConstant(value); 118 } 119 ExternalConstant(ExternalReference address)120 Node* CodeAssembler::ExternalConstant(ExternalReference address) { 121 return raw_assembler_->ExternalConstant(address); 122 } 123 Float64Constant(double value)124 Node* CodeAssembler::Float64Constant(double value) { 125 return raw_assembler_->Float64Constant(value); 126 } 127 NaNConstant()128 Node* CodeAssembler::NaNConstant() { 129 return LoadRoot(Heap::kNanValueRootIndex); 130 } 131 ToInt32Constant(Node * node,int32_t & out_value)132 bool 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 ToInt64Constant(Node * node,int64_t & out_value)144 bool 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 ToIntPtrConstant(Node * node,intptr_t & out_value)150 bool 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 Parameter(int value)156 Node* CodeAssembler::Parameter(int value) { 157 return raw_assembler_->Parameter(value); 158 } 159 Return(Node * value)160 void CodeAssembler::Return(Node* value) { 161 return raw_assembler_->Return(value); 162 } 163 DebugBreak()164 void CodeAssembler::DebugBreak() { raw_assembler_->DebugBreak(); } 165 Comment(const char * format,...)166 void 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 Bind(CodeAssembler::Label * label)186 void CodeAssembler::Bind(CodeAssembler::Label* label) { return label->Bind(); } 187 LoadFramePointer()188 Node* CodeAssembler::LoadFramePointer() { 189 return raw_assembler_->LoadFramePointer(); 190 } 191 LoadParentFramePointer()192 Node* CodeAssembler::LoadParentFramePointer() { 193 return raw_assembler_->LoadParentFramePointer(); 194 } 195 LoadStackPointer()196 Node* CodeAssembler::LoadStackPointer() { 197 return raw_assembler_->LoadStackPointer(); 198 } 199 SmiShiftBitsConstant()200 Node* 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 } CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)208 CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP) 209 #undef DEFINE_CODE_ASSEMBLER_BINARY_OP 210 211 Node* CodeAssembler::WordShl(Node* value, int shift) { 212 return raw_assembler_->WordShl(value, IntPtrConstant(shift)); 213 } 214 WordShr(Node * value,int shift)215 Node* CodeAssembler::WordShr(Node* value, int shift) { 216 return raw_assembler_->WordShr(value, IntPtrConstant(shift)); 217 } 218 ChangeUint32ToWord(Node * value)219 Node* CodeAssembler::ChangeUint32ToWord(Node* value) { 220 if (raw_assembler_->machine()->Is64()) { 221 value = raw_assembler_->ChangeUint32ToUint64(value); 222 } 223 return value; 224 } 225 ChangeInt32ToIntPtr(Node * value)226 Node* 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); } CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)235 CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP) 236 #undef DEFINE_CODE_ASSEMBLER_UNARY_OP 237 238 Node* CodeAssembler::Load(MachineType rep, Node* base) { 239 return raw_assembler_->Load(rep, base); 240 } 241 Load(MachineType rep,Node * base,Node * index)242 Node* CodeAssembler::Load(MachineType rep, Node* base, Node* index) { 243 return raw_assembler_->Load(rep, base, index); 244 } 245 AtomicLoad(MachineType rep,Node * base,Node * index)246 Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* index) { 247 return raw_assembler_->AtomicLoad(rep, base, index); 248 } 249 LoadRoot(Heap::RootListIndex root_index)250 Node* 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 Store(MachineRepresentation rep,Node * base,Node * value)266 Node* CodeAssembler::Store(MachineRepresentation rep, Node* base, Node* value) { 267 return raw_assembler_->Store(rep, base, value, kFullWriteBarrier); 268 } 269 Store(MachineRepresentation rep,Node * base,Node * index,Node * value)270 Node* CodeAssembler::Store(MachineRepresentation rep, Node* base, Node* index, 271 Node* value) { 272 return raw_assembler_->Store(rep, base, index, value, kFullWriteBarrier); 273 } 274 StoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * value)275 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base, 276 Node* value) { 277 return raw_assembler_->Store(rep, base, value, kNoWriteBarrier); 278 } 279 StoreNoWriteBarrier(MachineRepresentation rep,Node * base,Node * index,Node * value)280 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base, 281 Node* index, Node* value) { 282 return raw_assembler_->Store(rep, base, index, value, kNoWriteBarrier); 283 } 284 AtomicStore(MachineRepresentation rep,Node * base,Node * index,Node * value)285 Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base, 286 Node* index, Node* value) { 287 return raw_assembler_->AtomicStore(rep, base, index, value); 288 } 289 StoreRoot(Heap::RootListIndex root_index,Node * value)290 Node* 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 Projection(int index,Node * value)298 Node* CodeAssembler::Projection(int index, Node* value) { 299 return raw_assembler_->Projection(index, value); 300 } 301 BranchIf(Node * condition,Label * if_true,Label * if_false)302 void 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 CallN(CallDescriptor * descriptor,Node * code_target,Node ** args)311 Node* 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 TailCallN(CallDescriptor * descriptor,Node * code_target,Node ** args)319 Node* CodeAssembler::TailCallN(CallDescriptor* descriptor, Node* code_target, 320 Node** args) { 321 return raw_assembler_->TailCallN(descriptor, code_target, args); 322 } 323 CallRuntime(Runtime::FunctionId function_id,Node * context)324 Node* 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 CallRuntime(Runtime::FunctionId function_id,Node * context,Node * arg1)332 Node* 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 CallRuntime(Runtime::FunctionId function_id,Node * context,Node * arg1,Node * arg2)340 Node* 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 CallRuntime(Runtime::FunctionId function_id,Node * context,Node * arg1,Node * arg2,Node * arg3)349 Node* 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 CallRuntime(Runtime::FunctionId function_id,Node * context,Node * arg1,Node * arg2,Node * arg3,Node * arg4)358 Node* 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 TailCallRuntime(Runtime::FunctionId function_id,Node * context)368 Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function_id, 369 Node* context) { 370 return raw_assembler_->TailCallRuntime0(function_id, context); 371 } 372 TailCallRuntime(Runtime::FunctionId function_id,Node * context,Node * arg1)373 Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function_id, 374 Node* context, Node* arg1) { 375 return raw_assembler_->TailCallRuntime1(function_id, arg1, context); 376 } 377 TailCallRuntime(Runtime::FunctionId function_id,Node * context,Node * arg1,Node * arg2)378 Node* 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 TailCallRuntime(Runtime::FunctionId function_id,Node * context,Node * arg1,Node * arg2,Node * arg3)383 Node* 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 TailCallRuntime(Runtime::FunctionId function_id,Node * context,Node * arg1,Node * arg2,Node * arg3,Node * arg4)390 Node* 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 CallStub(Callable const & callable,Node * context,Node * arg1,size_t result_size)397 Node* 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 CallStub(Callable const & callable,Node * context,Node * arg1,Node * arg2,size_t result_size)403 Node* 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 CallStub(Callable const & callable,Node * context,Node * arg1,Node * arg2,Node * arg3,size_t result_size)410 Node* 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 CallStubN(Callable const & callable,Node ** args,size_t result_size)418 Node* 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 CallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,Node * arg1,size_t result_size)424 Node* 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 CallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,Node * arg1,Node * arg2,size_t result_size)439 Node* 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 CallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,Node * arg1,Node * arg2,Node * arg3,size_t result_size)455 Node* 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 CallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,Node * arg1,Node * arg2,Node * arg3,Node * arg4,size_t result_size)472 Node* 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 CallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,Node * arg1,Node * arg2,Node * arg3,Node * arg4,Node * arg5,size_t result_size)491 Node* 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 CallStubN(const CallInterfaceDescriptor & descriptor,Node * target,Node ** args,size_t result_size)511 Node* 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 TailCallStub(Callable const & callable,Node * context,Node * arg1,Node * arg2,size_t result_size)521 Node* 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 TailCallStub(Callable const & callable,Node * context,Node * arg1,Node * arg2,Node * arg3,size_t result_size)528 Node* 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 TailCallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,Node * arg1,Node * arg2,size_t result_size)536 Node* 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 TailCallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,Node * arg1,Node * arg2,Node * arg3,size_t result_size)552 Node* 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 TailCallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,Node * arg1,Node * arg2,Node * arg3,Node * arg4,size_t result_size)569 Node* 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 TailCallBytecodeDispatch(const CallInterfaceDescriptor & interface_descriptor,Node * code_target_address,Node ** args)588 Node* 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 CallJS(Callable const & callable,Node * context,Node * function,Node * receiver,size_t result_size)597 Node* 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 CallJS(Callable const & callable,Node * context,Node * function,Node * receiver,Node * arg1,size_t result_size)616 Node* 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 CallJS(Callable const & callable,Node * context,Node * function,Node * receiver,Node * arg1,Node * arg2,size_t result_size)636 Node* 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 Goto(CodeAssembler::Label * label)657 void CodeAssembler::Goto(CodeAssembler::Label* label) { 658 label->MergeVariables(); 659 raw_assembler_->Goto(label->label_); 660 } 661 GotoIf(Node * condition,Label * true_label)662 void 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 GotoUnless(Node * condition,Label * false_label)668 void 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 Branch(Node * condition,CodeAssembler::Label * true_label,CodeAssembler::Label * false_label)674 void 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 Switch(Node * index,Label * default_label,int32_t * case_values,Label ** case_labels,size_t case_count)682 void 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: isolate() const698 Isolate* CodeAssembler::isolate() const { return raw_assembler_->isolate(); } 699 factory() const700 Factory* CodeAssembler::factory() const { return isolate()->factory(); } 701 graph() const702 Graph* CodeAssembler::graph() const { return raw_assembler_->graph(); } 703 zone() const704 Zone* 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. 710 class CodeAssembler::Variable::Impl : public ZoneObject { 711 public: Impl(MachineRepresentation rep)712 explicit Impl(MachineRepresentation rep) : value_(nullptr), rep_(rep) {} 713 Node* value_; 714 MachineRepresentation rep_; 715 }; 716 Variable(CodeAssembler * assembler,MachineRepresentation rep)717 CodeAssembler::Variable::Variable(CodeAssembler* assembler, 718 MachineRepresentation rep) 719 : impl_(new (assembler->zone()) Impl(rep)), assembler_(assembler) { 720 assembler->variables_.insert(impl_); 721 } 722 ~Variable()723 CodeAssembler::Variable::~Variable() { assembler_->variables_.erase(impl_); } 724 Bind(Node * value)725 void CodeAssembler::Variable::Bind(Node* value) { impl_->value_ = value; } 726 value() const727 Node* CodeAssembler::Variable::value() const { 728 DCHECK_NOT_NULL(impl_->value_); 729 return impl_->value_; 730 } 731 rep() const732 MachineRepresentation CodeAssembler::Variable::rep() const { 733 return impl_->rep_; 734 } 735 IsBound() const736 bool CodeAssembler::Variable::IsBound() const { 737 return impl_->value_ != nullptr; 738 } 739 Label(CodeAssembler * assembler,int merged_value_count,CodeAssembler::Variable ** merged_variables,CodeAssembler::Label::Type type)740 CodeAssembler::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 MergeVariables()753 void 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 Bind()799 void 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