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