1 // Copyright 2016 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 #ifndef V8_COMPILER_GRAPH_ASSEMBLER_H_
6 #define V8_COMPILER_GRAPH_ASSEMBLER_H_
7 
8 #include "src/codegen/tnode.h"
9 #include "src/compiler/feedback-source.h"
10 #include "src/compiler/js-graph.h"
11 #include "src/compiler/node.h"
12 #include "src/compiler/simplified-operator.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 class JSGraph;
18 class Graph;
19 class Oddball;
20 
21 // TODO(jgruber): Currently this is too permissive, but at least it lets us
22 // document which functions expect JS booleans. If a real Boolean type becomes
23 // possible in the future, use that instead.
24 using Boolean = Oddball;
25 
26 namespace compiler {
27 
28 class Schedule;
29 class BasicBlock;
30 
31 #define PURE_ASSEMBLER_MACH_UNOP_LIST(V) \
32   V(BitcastFloat32ToInt32)               \
33   V(BitcastFloat64ToInt64)               \
34   V(BitcastInt32ToFloat32)               \
35   V(BitcastWord32ToWord64)               \
36   V(BitcastInt64ToFloat64)               \
37   V(ChangeFloat64ToInt32)                \
38   V(ChangeFloat64ToInt64)                \
39   V(ChangeFloat64ToUint32)               \
40   V(ChangeInt32ToFloat64)                \
41   V(ChangeInt32ToInt64)                  \
42   V(ChangeInt64ToFloat64)                \
43   V(ChangeUint32ToFloat64)               \
44   V(ChangeUint32ToUint64)                \
45   V(Float64Abs)                          \
46   V(Float64ExtractHighWord32)            \
47   V(Float64ExtractLowWord32)             \
48   V(Float64SilenceNaN)                   \
49   V(RoundFloat64ToInt32)                 \
50   V(TruncateFloat64ToInt64)              \
51   V(TruncateFloat64ToWord32)             \
52   V(TruncateInt64ToInt32)                \
53   V(Word32ReverseBytes)                  \
54   V(Word64ReverseBytes)
55 
56 #define PURE_ASSEMBLER_MACH_BINOP_LIST(V) \
57   V(Float64Add)                           \
58   V(Float64Div)                           \
59   V(Float64Equal)                         \
60   V(Float64InsertHighWord32)              \
61   V(Float64InsertLowWord32)               \
62   V(Float64LessThan)                      \
63   V(Float64LessThanOrEqual)               \
64   V(Float64Mod)                           \
65   V(Float64Sub)                           \
66   V(Int32Add)                             \
67   V(Int32LessThan)                        \
68   V(Int32LessThanOrEqual)                 \
69   V(Int32Mul)                             \
70   V(Int32Sub)                             \
71   V(Int64Sub)                             \
72   V(IntAdd)                               \
73   V(IntLessThan)                          \
74   V(IntMul)                               \
75   V(IntSub)                               \
76   V(Uint32LessThan)                       \
77   V(Uint32LessThanOrEqual)                \
78   V(Uint64LessThan)                       \
79   V(Uint64LessThanOrEqual)                \
80   V(UintLessThan)                         \
81   V(Word32And)                            \
82   V(Word32Equal)                          \
83   V(Word32Or)                             \
84   V(Word32Sar)                            \
85   V(Word32Shl)                            \
86   V(Word32Shr)                            \
87   V(Word32Xor)                            \
88   V(Word64And)                            \
89   V(Word64Equal)                          \
90   V(Word64Or)                             \
91   V(WordAnd)                              \
92   V(WordEqual)                            \
93   V(WordSar)                              \
94   V(WordShl)
95 
96 #define CHECKED_ASSEMBLER_MACH_BINOP_LIST(V) \
97   V(Int32AddWithOverflow)                    \
98   V(Int32Div)                                \
99   V(Int32Mod)                                \
100   V(Int32MulWithOverflow)                    \
101   V(Int32SubWithOverflow)                    \
102   V(Uint32Div)                               \
103   V(Uint32Mod)
104 
105 #define JSGRAPH_SINGLETON_CONSTANT_LIST(V)      \
106   V(AllocateInOldGenerationStub, Code)          \
107   V(AllocateInYoungGenerationStub, Code)        \
108   V(AllocateRegularInOldGenerationStub, Code)   \
109   V(AllocateRegularInYoungGenerationStub, Code) \
110   V(BigIntMap, Map)                             \
111   V(BooleanMap, Map)                            \
112   V(EmptyString, String)                        \
113   V(False, Boolean)                             \
114   V(FixedArrayMap, Map)                         \
115   V(FixedDoubleArrayMap, Map)                   \
116   V(HeapNumberMap, Map)                         \
117   V(MinusOne, Number)                           \
118   V(NaN, Number)                                \
119   V(NoContext, Object)                          \
120   V(Null, Oddball)                              \
121   V(One, Number)                                \
122   V(TheHole, Oddball)                           \
123   V(ToNumberBuiltin, Code)                      \
124   V(True, Boolean)                              \
125   V(Undefined, Oddball)                         \
126   V(Zero, Number)
127 
128 class GraphAssembler;
129 
130 // Wrapper classes for special node/edge types (effect, control, frame states)
131 // that otherwise don't fit into the type system.
132 
133 class NodeWrapper {
134  public:
NodeWrapper(Node * node)135   explicit constexpr NodeWrapper(Node* node) : node_(node) {}
136   operator Node*() const { return node_; }
137   Node* operator->() const { return node_; }
138 
139  private:
140   Node* node_;
141 };
142 
143 class Effect : public NodeWrapper {
144  public:
Effect(Node * node)145   explicit constexpr Effect(Node* node) : NodeWrapper(node) {
146     // TODO(jgruber): Remove the End special case.
147     SLOW_DCHECK(node == nullptr || node->op()->opcode() == IrOpcode::kEnd ||
148                 node->op()->EffectOutputCount() > 0);
149   }
150 };
151 
152 class Control : public NodeWrapper {
153  public:
Control(Node * node)154   explicit constexpr Control(Node* node) : NodeWrapper(node) {
155     // TODO(jgruber): Remove the End special case.
156     SLOW_DCHECK(node == nullptr || node->opcode() == IrOpcode::kEnd ||
157                 node->op()->ControlOutputCount() > 0);
158   }
159 };
160 
161 class FrameState : public NodeWrapper {
162  public:
FrameState(Node * node)163   explicit constexpr FrameState(Node* node) : NodeWrapper(node) {
164     // TODO(jgruber): Disallow kStart (needed for PromiseConstructorBasic unit
165     // test, among others).
166     SLOW_DCHECK(node->opcode() == IrOpcode::kFrameState ||
167                 node->opcode() == IrOpcode::kStart);
168   }
169 };
170 
171 enum class GraphAssemblerLabelType { kDeferred, kNonDeferred, kLoop };
172 
173 // Label with statically known count of incoming branches and phis.
174 template <size_t VarCount>
175 class GraphAssemblerLabel {
176  public:
177   Node* PhiAt(size_t index);
178 
179   template <typename T>
PhiAt(size_t index)180   TNode<T> PhiAt(size_t index) {
181     // TODO(jgruber): Investigate issues on ptr compression bots and enable.
182     // DCHECK(IsMachineRepresentationOf<T>(representations_[index]));
183     return TNode<T>::UncheckedCast(PhiAt(index));
184   }
185 
GraphAssemblerLabel(GraphAssemblerLabelType type,BasicBlock * basic_block,int loop_nesting_level,const std::array<MachineRepresentation,VarCount> & reps)186   GraphAssemblerLabel(GraphAssemblerLabelType type, BasicBlock* basic_block,
187                       int loop_nesting_level,
188                       const std::array<MachineRepresentation, VarCount>& reps)
189       : type_(type),
190         basic_block_(basic_block),
191         loop_nesting_level_(loop_nesting_level),
192         representations_(reps) {}
193 
~GraphAssemblerLabel()194   ~GraphAssemblerLabel() { DCHECK(IsBound() || merged_count_ == 0); }
195 
196  private:
197   friend class GraphAssembler;
198 
SetBound()199   void SetBound() {
200     DCHECK(!IsBound());
201     is_bound_ = true;
202   }
IsBound()203   bool IsBound() const { return is_bound_; }
IsDeferred()204   bool IsDeferred() const {
205     return type_ == GraphAssemblerLabelType::kDeferred;
206   }
IsLoop()207   bool IsLoop() const { return type_ == GraphAssemblerLabelType::kLoop; }
basic_block()208   BasicBlock* basic_block() { return basic_block_; }
209 
210   bool is_bound_ = false;
211   const GraphAssemblerLabelType type_;
212   BasicBlock* const basic_block_;
213   const int loop_nesting_level_;
214   size_t merged_count_ = 0;
215   Node* effect_;
216   Node* control_;
217   std::array<Node*, VarCount> bindings_;
218   const std::array<MachineRepresentation, VarCount> representations_;
219 };
220 
221 class V8_EXPORT_PRIVATE GraphAssembler {
222  public:
223   // Constructs a GraphAssembler. If {schedule} is not null, the graph assembler
224   // will maintain the schedule as it updates blocks.
225   GraphAssembler(MachineGraph* jsgraph, Zone* zone,
226                  Schedule* schedule = nullptr, bool mark_loop_exits = false);
227   virtual ~GraphAssembler();
228 
229   void Reset(BasicBlock* block);
230   void InitializeEffectControl(Node* effect, Node* control);
231 
232   // Create label.
233   template <typename... Reps>
MakeLabelFor(GraphAssemblerLabelType type,Reps...reps)234   GraphAssemblerLabel<sizeof...(Reps)> MakeLabelFor(
235       GraphAssemblerLabelType type, Reps... reps) {
236     std::array<MachineRepresentation, sizeof...(Reps)> reps_array = {reps...};
237     return MakeLabel<sizeof...(Reps)>(reps_array, type);
238   }
239 
240   // As above, but with an std::array of machine representations.
241   template <int VarCount>
MakeLabel(std::array<MachineRepresentation,VarCount> reps_array,GraphAssemblerLabelType type)242   GraphAssemblerLabel<VarCount> MakeLabel(
243       std::array<MachineRepresentation, VarCount> reps_array,
244       GraphAssemblerLabelType type) {
245     return GraphAssemblerLabel<VarCount>(
246         type, NewBasicBlock(type == GraphAssemblerLabelType::kDeferred),
247         loop_nesting_level_, reps_array);
248   }
249 
250   // Convenience wrapper for creating non-deferred labels.
251   template <typename... Reps>
MakeLabel(Reps...reps)252   GraphAssemblerLabel<sizeof...(Reps)> MakeLabel(Reps... reps) {
253     return MakeLabelFor(GraphAssemblerLabelType::kNonDeferred, reps...);
254   }
255 
256   // Convenience wrapper for creating loop labels.
257   template <typename... Reps>
MakeLoopLabel(Reps...reps)258   GraphAssemblerLabel<sizeof...(Reps)> MakeLoopLabel(Reps... reps) {
259     return MakeLabelFor(GraphAssemblerLabelType::kLoop, reps...);
260   }
261 
262   // Convenience wrapper for creating deferred labels.
263   template <typename... Reps>
MakeDeferredLabel(Reps...reps)264   GraphAssemblerLabel<sizeof...(Reps)> MakeDeferredLabel(Reps... reps) {
265     return MakeLabelFor(GraphAssemblerLabelType::kDeferred, reps...);
266   }
267 
268   // Value creation.
269   Node* IntPtrConstant(intptr_t value);
270   Node* Uint32Constant(uint32_t value);
271   Node* Int32Constant(int32_t value);
272   Node* Int64Constant(int64_t value);
273   Node* UniqueIntPtrConstant(intptr_t value);
274   Node* Float64Constant(double value);
275   Node* Projection(int index, Node* value);
276   Node* ExternalConstant(ExternalReference ref);
277 
278   Node* LoadFramePointer();
279 
280   Node* LoadHeapNumberValue(Node* heap_number);
281 
282 #define PURE_UNOP_DECL(Name) Node* Name(Node* input);
283   PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL)
284 #undef PURE_UNOP_DECL
285 
286 #define BINOP_DECL(Name) Node* Name(Node* left, Node* right);
287   PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
288   CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
289 #undef BINOP_DECL
290 
291   // Debugging
292   Node* DebugBreak();
293 
294   Node* Unreachable();
295 
296   Node* IntPtrEqual(Node* left, Node* right);
297   Node* TaggedEqual(Node* left, Node* right);
298 
299   Node* SmiSub(Node* left, Node* right);
300   Node* SmiLessThan(Node* left, Node* right);
301 
302   Node* Float64RoundDown(Node* value);
303   Node* Float64RoundTruncate(Node* value);
304 
305   Node* BitcastWordToTagged(Node* value);
306   Node* BitcastWordToTaggedSigned(Node* value);
307   Node* BitcastTaggedToWord(Node* value);
308   Node* BitcastTaggedToWordForTagAndSmiBits(Node* value);
309 
310   Node* TypeGuard(Type type, Node* value);
311   Node* Checkpoint(FrameState frame_state);
312 
313   Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value);
314   Node* Store(StoreRepresentation rep, Node* object, int offset, Node* value);
315   Node* Load(MachineType type, Node* object, Node* offset);
316   Node* Load(MachineType type, Node* object, int offset);
317 
318   Node* StoreUnaligned(MachineRepresentation rep, Node* object, Node* offset,
319                        Node* value);
320   Node* LoadUnaligned(MachineType type, Node* object, Node* offset);
321 
322   Node* Retain(Node* buffer);
323   Node* UnsafePointerAdd(Node* base, Node* external);
324 
325   Node* Word32PoisonOnSpeculation(Node* value);
326 
327   Node* DeoptimizeIf(
328       DeoptimizeReason reason, FeedbackSource const& feedback, Node* condition,
329       Node* frame_state,
330       IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
331   Node* DeoptimizeIfNot(
332       DeoptimizeReason reason, FeedbackSource const& feedback, Node* condition,
333       Node* frame_state,
334       IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
335   template <typename... Args>
336   Node* Call(const CallDescriptor* call_descriptor, Args... args);
337   template <typename... Args>
338   Node* Call(const Operator* op, Args... args);
339 
340   // Basic control operations.
341   template <size_t VarCount>
342   void Bind(GraphAssemblerLabel<VarCount>* label);
343 
344   template <typename... Vars>
345   void Goto(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars...);
346 
347   // Branch hints are inferred from if_true/if_false deferred states.
348   void BranchWithCriticalSafetyCheck(Node* condition,
349                                      GraphAssemblerLabel<0u>* if_true,
350                                      GraphAssemblerLabel<0u>* if_false);
351 
352   // Branch hints are inferred from if_true/if_false deferred states.
353   template <typename... Vars>
354   void Branch(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* if_true,
355               GraphAssemblerLabel<sizeof...(Vars)>* if_false, Vars...);
356 
357   template <typename... Vars>
358   void BranchWithHint(Node* condition,
359                       GraphAssemblerLabel<sizeof...(Vars)>* if_true,
360                       GraphAssemblerLabel<sizeof...(Vars)>* if_false,
361                       BranchHint hint, Vars...);
362 
363   // Control helpers.
364   // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}.
365   template <typename... Vars>
366   void GotoIf(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
367               Vars...);
368 
369   // {GotoIfNot(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}.
370   template <typename... Vars>
371   void GotoIfNot(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
372                  Vars...);
373 
374   // Updates current effect and control based on outputs of {node}.
UpdateEffectControlWith(Node * node)375   V8_INLINE void UpdateEffectControlWith(Node* node) {
376     if (node->op()->EffectOutputCount() > 0) {
377       effect_ = node;
378     }
379     if (node->op()->ControlOutputCount() > 0) {
380       control_ = node;
381     }
382   }
383 
384   // Adds {node} to the current position and updates assembler's current effect
385   // and control.
386   Node* AddNode(Node* node);
387 
388   template <typename T>
AddNode(Node * node)389   TNode<T> AddNode(Node* node) {
390     return TNode<T>::UncheckedCast(AddNode(node));
391   }
392 
393   // Finalizes the {block} being processed by the assembler, returning the
394   // finalized block (which may be different from the original block).
395   BasicBlock* FinalizeCurrentBlock(BasicBlock* block);
396 
397   void ConnectUnreachableToEnd();
398 
control()399   Control control() { return Control(control_); }
effect()400   Effect effect() { return Effect(effect_); }
401 
402  protected:
403   class BasicBlockUpdater;
404 
405   template <typename... Vars>
406   void MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars... vars);
407   BasicBlock* NewBasicBlock(bool deferred);
408   void BindBasicBlock(BasicBlock* block);
409   void GotoBasicBlock(BasicBlock* block);
410   void GotoIfBasicBlock(BasicBlock* block, Node* branch,
411                         IrOpcode::Value goto_if);
412 
413   V8_INLINE Node* AddClonedNode(Node* node);
414 
mcgraph()415   MachineGraph* mcgraph() const { return mcgraph_; }
graph()416   Graph* graph() const { return mcgraph_->graph(); }
temp_zone()417   Zone* temp_zone() const { return temp_zone_; }
common()418   CommonOperatorBuilder* common() const { return mcgraph()->common(); }
machine()419   MachineOperatorBuilder* machine() const { return mcgraph()->machine(); }
420 
421   // Updates machinery for creating {LoopExit,LoopExitEffect,LoopExitValue}
422   // nodes on loop exits (which are necessary for loop peeling).
423   //
424   // All labels created while a LoopScope is live are considered to be inside
425   // the loop.
426   template <MachineRepresentation... Reps>
427   class LoopScope final {
428    private:
429     // The internal scope is only here to increment the graph assembler's
430     // nesting level prior to `loop_header_label` creation below.
431     class LoopScopeInternal {
432      public:
LoopScopeInternal(GraphAssembler * gasm)433       explicit LoopScopeInternal(GraphAssembler* gasm)
434           : previous_loop_nesting_level_(gasm->loop_nesting_level_),
435             gasm_(gasm) {
436         gasm->loop_nesting_level_++;
437       }
438 
~LoopScopeInternal()439       ~LoopScopeInternal() {
440         gasm_->loop_nesting_level_--;
441         DCHECK_EQ(gasm_->loop_nesting_level_, previous_loop_nesting_level_);
442       }
443 
444      private:
445       const int previous_loop_nesting_level_;
446       GraphAssembler* const gasm_;
447     };
448 
449    public:
LoopScope(GraphAssembler * gasm)450     explicit LoopScope(GraphAssembler* gasm)
451         : internal_scope_(gasm),
452           gasm_(gasm),
453           loop_header_label_(gasm->MakeLoopLabel(Reps...)) {
454       // This feature may only be used if it has been enabled.
455       DCHECK(gasm_->mark_loop_exits_);
456       gasm->loop_headers_.push_back(&loop_header_label_.control_);
457       DCHECK_EQ(static_cast<int>(gasm_->loop_headers_.size()),
458                 gasm_->loop_nesting_level_);
459     }
460 
~LoopScope()461     ~LoopScope() {
462       DCHECK_EQ(static_cast<int>(gasm_->loop_headers_.size()),
463                 gasm_->loop_nesting_level_);
464       gasm_->loop_headers_.pop_back();
465     }
466 
loop_header_label()467     GraphAssemblerLabel<sizeof...(Reps)>* loop_header_label() {
468       return &loop_header_label_;
469     }
470 
471    private:
472     const LoopScopeInternal internal_scope_;
473     GraphAssembler* const gasm_;
474     GraphAssemblerLabel<sizeof...(Reps)> loop_header_label_;
475   };
476 
477   // Upon destruction, restores effect and control to the state at construction.
478   class RestoreEffectControlScope {
479    public:
RestoreEffectControlScope(GraphAssembler * gasm)480     explicit RestoreEffectControlScope(GraphAssembler* gasm)
481         : gasm_(gasm), effect_(gasm->effect()), control_(gasm->control()) {}
482 
~RestoreEffectControlScope()483     ~RestoreEffectControlScope() {
484       gasm_->effect_ = effect_;
485       gasm_->control_ = control_;
486     }
487 
488    private:
489     GraphAssembler* const gasm_;
490     const Effect effect_;
491     const Control control_;
492   };
493 
494  private:
495   template <typename... Vars>
496   void BranchImpl(Node* condition,
497                   GraphAssemblerLabel<sizeof...(Vars)>* if_true,
498                   GraphAssemblerLabel<sizeof...(Vars)>* if_false,
499                   BranchHint hint, IsSafetyCheck is_safety_check, Vars...);
500   void RecordBranchInBlockUpdater(Node* branch, Node* if_true_control,
501                                   Node* if_false_control,
502                                   BasicBlock* if_true_block,
503                                   BasicBlock* if_false_block);
504 
505   Zone* temp_zone_;
506   MachineGraph* mcgraph_;
507   Node* effect_;
508   Node* control_;
509   std::unique_ptr<BasicBlockUpdater> block_updater_;
510 
511   // Track loop information in order to properly mark loop exits with
512   // {LoopExit,LoopExitEffect,LoopExitValue} nodes. The outermost level has
513   // a nesting level of 0. See also GraphAssembler::LoopScope.
514   int loop_nesting_level_ = 0;
515   ZoneVector<Node**> loop_headers_;
516 
517   // Feature configuration. As more features are added, this should be turned
518   // into a bitfield.
519   const bool mark_loop_exits_;
520 };
521 
522 template <size_t VarCount>
PhiAt(size_t index)523 Node* GraphAssemblerLabel<VarCount>::PhiAt(size_t index) {
524   DCHECK(IsBound());
525   DCHECK_LT(index, VarCount);
526   return bindings_[index];
527 }
528 
529 template <typename... Vars>
MergeState(GraphAssemblerLabel<sizeof...(Vars)> * label,Vars...vars)530 void GraphAssembler::MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label,
531                                 Vars... vars) {
532   RestoreEffectControlScope restore_effect_control_scope(this);
533 
534   const int merged_count = static_cast<int>(label->merged_count_);
535   static constexpr int kVarCount = sizeof...(vars);
536   std::array<Node*, kVarCount> var_array = {vars...};
537 
538   const bool is_loop_exit = label->loop_nesting_level_ != loop_nesting_level_;
539   if (is_loop_exit) {
540     // This feature may only be used if it has been enabled.
541     USE(mark_loop_exits_);
542     DCHECK(mark_loop_exits_);
543     // Jumping from loops to loops not supported.
544     DCHECK(!label->IsLoop());
545     // Currently only the simple case of jumping one level is supported.
546     DCHECK_EQ(label->loop_nesting_level_, loop_nesting_level_ - 1);
547     DCHECK(!loop_headers_.empty());
548     DCHECK_NOT_NULL(*loop_headers_.back());
549 
550     // Mark this exit to enable loop peeling.
551     AddNode(graph()->NewNode(common()->LoopExit(), control(),
552                              *loop_headers_.back()));
553     AddNode(graph()->NewNode(common()->LoopExitEffect(), effect(), control()));
554     for (size_t i = 0; i < kVarCount; i++) {
555       var_array[i] = AddNode(
556           graph()->NewNode(common()->LoopExitValue(), var_array[i], control()));
557     }
558   }
559 
560   if (label->IsLoop()) {
561     if (merged_count == 0) {
562       DCHECK(!label->IsBound());
563       label->control_ =
564           graph()->NewNode(common()->Loop(2), control(), control());
565       label->effect_ = graph()->NewNode(common()->EffectPhi(2), effect(),
566                                         effect(), label->control_);
567       Node* terminate = graph()->NewNode(common()->Terminate(), label->effect_,
568                                          label->control_);
569       NodeProperties::MergeControlToEnd(graph(), common(), terminate);
570       for (size_t i = 0; i < kVarCount; i++) {
571         label->bindings_[i] =
572             graph()->NewNode(common()->Phi(label->representations_[i], 2),
573                              var_array[i], var_array[i], label->control_);
574       }
575     } else {
576       DCHECK(label->IsBound());
577       DCHECK_EQ(1, merged_count);
578       label->control_->ReplaceInput(1, control());
579       label->effect_->ReplaceInput(1, effect());
580       for (size_t i = 0; i < kVarCount; i++) {
581         label->bindings_[i]->ReplaceInput(1, var_array[i]);
582       }
583     }
584   } else {
585     DCHECK(!label->IsLoop());
586     DCHECK(!label->IsBound());
587     if (merged_count == 0) {
588       // Just set the control, effect and variables directly.
589       label->control_ = control();
590       label->effect_ = effect();
591       for (size_t i = 0; i < kVarCount; i++) {
592         label->bindings_[i] = var_array[i];
593       }
594     } else if (merged_count == 1) {
595       // Create merge, effect phi and a phi for each variable.
596       label->control_ =
597           graph()->NewNode(common()->Merge(2), label->control_, control());
598       label->effect_ = graph()->NewNode(common()->EffectPhi(2), label->effect_,
599                                         effect(), label->control_);
600       for (size_t i = 0; i < kVarCount; i++) {
601         label->bindings_[i] = graph()->NewNode(
602             common()->Phi(label->representations_[i], 2), label->bindings_[i],
603             var_array[i], label->control_);
604       }
605     } else {
606       // Append to the merge, effect phi and phis.
607       DCHECK_EQ(IrOpcode::kMerge, label->control_->opcode());
608       label->control_->AppendInput(graph()->zone(), control());
609       NodeProperties::ChangeOp(label->control_,
610                                common()->Merge(merged_count + 1));
611 
612       DCHECK_EQ(IrOpcode::kEffectPhi, label->effect_->opcode());
613       label->effect_->ReplaceInput(merged_count, effect());
614       label->effect_->AppendInput(graph()->zone(), label->control_);
615       NodeProperties::ChangeOp(label->effect_,
616                                common()->EffectPhi(merged_count + 1));
617 
618       for (size_t i = 0; i < kVarCount; i++) {
619         DCHECK_EQ(IrOpcode::kPhi, label->bindings_[i]->opcode());
620         label->bindings_[i]->ReplaceInput(merged_count, var_array[i]);
621         label->bindings_[i]->AppendInput(graph()->zone(), label->control_);
622         NodeProperties::ChangeOp(
623             label->bindings_[i],
624             common()->Phi(label->representations_[i], merged_count + 1));
625       }
626     }
627   }
628   label->merged_count_++;
629 }
630 
631 template <size_t VarCount>
Bind(GraphAssemblerLabel<VarCount> * label)632 void GraphAssembler::Bind(GraphAssemblerLabel<VarCount>* label) {
633   DCHECK_NULL(control());
634   DCHECK_NULL(effect());
635   DCHECK_LT(0, label->merged_count_);
636   DCHECK_EQ(label->loop_nesting_level_, loop_nesting_level_);
637 
638   control_ = label->control_;
639   effect_ = label->effect_;
640   BindBasicBlock(label->basic_block());
641 
642   label->SetBound();
643 
644   if (label->merged_count_ > 1 || label->IsLoop()) {
645     AddNode(label->control_);
646     AddNode(label->effect_);
647     for (size_t i = 0; i < VarCount; i++) {
648       AddNode(label->bindings_[i]);
649     }
650   } else {
651     // If the basic block does not have a control node, insert a dummy
652     // Merge node, so that other passes have a control node to start from.
653     control_ = AddNode(graph()->NewNode(common()->Merge(1), control()));
654   }
655 }
656 
657 template <typename... Vars>
Branch(Node * condition,GraphAssemblerLabel<sizeof...(Vars)> * if_true,GraphAssemblerLabel<sizeof...(Vars)> * if_false,Vars...vars)658 void GraphAssembler::Branch(Node* condition,
659                             GraphAssemblerLabel<sizeof...(Vars)>* if_true,
660                             GraphAssemblerLabel<sizeof...(Vars)>* if_false,
661                             Vars... vars) {
662   BranchHint hint = BranchHint::kNone;
663   if (if_true->IsDeferred() != if_false->IsDeferred()) {
664     hint = if_false->IsDeferred() ? BranchHint::kTrue : BranchHint::kFalse;
665   }
666 
667   BranchImpl(condition, if_true, if_false, hint, IsSafetyCheck::kNoSafetyCheck,
668              vars...);
669 }
670 
671 template <typename... Vars>
BranchWithHint(Node * condition,GraphAssemblerLabel<sizeof...(Vars)> * if_true,GraphAssemblerLabel<sizeof...(Vars)> * if_false,BranchHint hint,Vars...vars)672 void GraphAssembler::BranchWithHint(
673     Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* if_true,
674     GraphAssemblerLabel<sizeof...(Vars)>* if_false, BranchHint hint,
675     Vars... vars) {
676   BranchImpl(condition, if_true, if_false, hint, IsSafetyCheck::kNoSafetyCheck,
677              vars...);
678 }
679 
680 template <typename... Vars>
BranchImpl(Node * condition,GraphAssemblerLabel<sizeof...(Vars)> * if_true,GraphAssemblerLabel<sizeof...(Vars)> * if_false,BranchHint hint,IsSafetyCheck is_safety_check,Vars...vars)681 void GraphAssembler::BranchImpl(Node* condition,
682                                 GraphAssemblerLabel<sizeof...(Vars)>* if_true,
683                                 GraphAssemblerLabel<sizeof...(Vars)>* if_false,
684                                 BranchHint hint, IsSafetyCheck is_safety_check,
685                                 Vars... vars) {
686   DCHECK_NOT_NULL(control());
687 
688   Node* branch = graph()->NewNode(common()->Branch(hint, is_safety_check),
689                                   condition, control());
690 
691   Node* if_true_control = control_ =
692       graph()->NewNode(common()->IfTrue(), branch);
693   MergeState(if_true, vars...);
694 
695   Node* if_false_control = control_ =
696       graph()->NewNode(common()->IfFalse(), branch);
697   MergeState(if_false, vars...);
698 
699   if (block_updater_) {
700     RecordBranchInBlockUpdater(branch, if_true_control, if_false_control,
701                                if_true->basic_block(), if_false->basic_block());
702   }
703 
704   control_ = nullptr;
705   effect_ = nullptr;
706 }
707 
708 template <typename... Vars>
Goto(GraphAssemblerLabel<sizeof...(Vars)> * label,Vars...vars)709 void GraphAssembler::Goto(GraphAssemblerLabel<sizeof...(Vars)>* label,
710                           Vars... vars) {
711   DCHECK_NOT_NULL(control());
712   DCHECK_NOT_NULL(effect());
713   MergeState(label, vars...);
714   GotoBasicBlock(label->basic_block());
715 
716   control_ = nullptr;
717   effect_ = nullptr;
718 }
719 
720 template <typename... Vars>
GotoIf(Node * condition,GraphAssemblerLabel<sizeof...(Vars)> * label,Vars...vars)721 void GraphAssembler::GotoIf(Node* condition,
722                             GraphAssemblerLabel<sizeof...(Vars)>* label,
723                             Vars... vars) {
724   BranchHint hint =
725       label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone;
726   Node* branch = graph()->NewNode(common()->Branch(hint), condition, control());
727 
728   control_ = graph()->NewNode(common()->IfTrue(), branch);
729   MergeState(label, vars...);
730 
731   GotoIfBasicBlock(label->basic_block(), branch, IrOpcode::kIfTrue);
732   control_ = AddNode(graph()->NewNode(common()->IfFalse(), branch));
733 }
734 
735 template <typename... Vars>
GotoIfNot(Node * condition,GraphAssemblerLabel<sizeof...(Vars)> * label,Vars...vars)736 void GraphAssembler::GotoIfNot(Node* condition,
737                                GraphAssemblerLabel<sizeof...(Vars)>* label,
738                                Vars... vars) {
739   BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone;
740   Node* branch = graph()->NewNode(common()->Branch(hint), condition, control());
741 
742   control_ = graph()->NewNode(common()->IfFalse(), branch);
743   MergeState(label, vars...);
744 
745   GotoIfBasicBlock(label->basic_block(), branch, IrOpcode::kIfFalse);
746   control_ = AddNode(graph()->NewNode(common()->IfTrue(), branch));
747 }
748 
749 template <typename... Args>
Call(const CallDescriptor * call_descriptor,Args...args)750 Node* GraphAssembler::Call(const CallDescriptor* call_descriptor,
751                            Args... args) {
752   const Operator* op = common()->Call(call_descriptor);
753   return Call(op, args...);
754 }
755 
756 template <typename... Args>
Call(const Operator * op,Args...args)757 Node* GraphAssembler::Call(const Operator* op, Args... args) {
758   DCHECK_EQ(IrOpcode::kCall, op->opcode());
759   Node* args_array[] = {args..., effect(), control()};
760   int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() +
761              op->ControlInputCount();
762   return AddNode(graph()->NewNode(op, size, args_array));
763 }
764 
765 class V8_EXPORT_PRIVATE JSGraphAssembler : public GraphAssembler {
766  public:
767   // Constructs a JSGraphAssembler. If {schedule} is not null, the graph
768   // assembler will maintain the schedule as it updates blocks.
769   JSGraphAssembler(JSGraph* jsgraph, Zone* zone, Schedule* schedule = nullptr,
770                    bool mark_loop_exits = false)
GraphAssembler(jsgraph,zone,schedule,mark_loop_exits)771       : GraphAssembler(jsgraph, zone, schedule, mark_loop_exits),
772         jsgraph_(jsgraph) {}
773 
774   Node* SmiConstant(int32_t value);
775   TNode<HeapObject> HeapConstant(Handle<HeapObject> object);
776   TNode<Object> Constant(const ObjectRef& ref);
777   TNode<Number> NumberConstant(double value);
778   Node* CEntryStubConstant(int result_size);
779 
780 #define SINGLETON_CONST_DECL(Name, Type) TNode<Type> Name##Constant();
781   JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL)
782 #undef SINGLETON_CONST_DECL
783 
784 #define SINGLETON_CONST_TEST_DECL(Name, ...) \
785   TNode<Boolean> Is##Name(TNode<Object> value);
786   JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_TEST_DECL)
787 #undef SINGLETON_CONST_TEST_DECL
788 
789   Node* Allocate(AllocationType allocation, Node* size);
790   Node* LoadField(FieldAccess const&, Node* object);
791   template <typename T>
LoadField(FieldAccess const & access,TNode<HeapObject> object)792   TNode<T> LoadField(FieldAccess const& access, TNode<HeapObject> object) {
793     // TODO(jgruber): Investigate issues on ptr compression bots and enable.
794     // DCHECK(IsMachineRepresentationOf<T>(
795     //     access.machine_type.representation()));
796     return TNode<T>::UncheckedCast(LoadField(access, object));
797   }
798   Node* LoadElement(ElementAccess const&, Node* object, Node* index);
799   template <typename T>
LoadElement(ElementAccess const & access,TNode<HeapObject> object,TNode<Number> index)800   TNode<T> LoadElement(ElementAccess const& access, TNode<HeapObject> object,
801                        TNode<Number> index) {
802     // TODO(jgruber): Investigate issues on ptr compression bots and enable.
803     // DCHECK(IsMachineRepresentationOf<T>(
804     //     access.machine_type.representation()));
805     return TNode<T>::UncheckedCast(LoadElement(access, object, index));
806   }
807   Node* StoreField(FieldAccess const&, Node* object, Node* value);
808   Node* StoreElement(ElementAccess const&, Node* object, Node* index,
809                      Node* value);
810   void TransitionAndStoreElement(MapRef double_map, MapRef fast_map,
811                                  TNode<HeapObject> object, TNode<Number> index,
812                                  TNode<Object> value);
813   TNode<Number> StringLength(TNode<String> string);
814   TNode<Boolean> ReferenceEqual(TNode<Object> lhs, TNode<Object> rhs);
815   TNode<Number> PlainPrimitiveToNumber(TNode<Object> value);
816   TNode<Number> NumberMin(TNode<Number> lhs, TNode<Number> rhs);
817   TNode<Number> NumberMax(TNode<Number> lhs, TNode<Number> rhs);
818   TNode<Boolean> NumberLessThan(TNode<Number> lhs, TNode<Number> rhs);
819   TNode<Boolean> NumberLessThanOrEqual(TNode<Number> lhs, TNode<Number> rhs);
820   TNode<Number> NumberAdd(TNode<Number> lhs, TNode<Number> rhs);
821   TNode<Number> NumberSubtract(TNode<Number> lhs, TNode<Number> rhs);
822   TNode<String> StringSubstring(TNode<String> string, TNode<Number> from,
823                                 TNode<Number> to);
824   TNode<Boolean> ObjectIsCallable(TNode<Object> value);
825   Node* CheckIf(Node* cond, DeoptimizeReason reason);
826   TNode<Boolean> NumberIsFloat64Hole(TNode<Number> value);
827   TNode<Boolean> ToBoolean(TNode<Object> value);
828   TNode<Object> ConvertTaggedHoleToUndefined(TNode<Object> value);
829   TNode<FixedArrayBase> MaybeGrowFastElements(ElementsKind kind,
830                                               const FeedbackSource& feedback,
831                                               TNode<JSArray> array,
832                                               TNode<FixedArrayBase> elements,
833                                               TNode<Number> new_length,
834                                               TNode<Number> old_length);
835 
jsgraph()836   JSGraph* jsgraph() const { return jsgraph_; }
isolate()837   Isolate* isolate() const { return jsgraph()->isolate(); }
simplified()838   SimplifiedOperatorBuilder* simplified() const {
839     return jsgraph()->simplified();
840   }
841 
842  protected:
843   Operator const* PlainPrimitiveToNumberOperator();
844 
845  private:
846   JSGraph* jsgraph_;
847   SetOncePointer<Operator const> to_number_operator_;
848 };
849 
850 }  // namespace compiler
851 }  // namespace internal
852 }  // namespace v8
853 
854 #endif  // V8_COMPILER_GRAPH_ASSEMBLER_H_
855