• 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