• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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