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