• 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/graph-assembler.h"
6 
7 #include "src/codegen/code-factory.h"
8 #include "src/compiler/linkage.h"
9 #include "src/compiler/schedule.h"
10 // For TNode types.
11 #include "src/objects/heap-number.h"
12 #include "src/objects/oddball.h"
13 #include "src/objects/smi.h"
14 #include "src/objects/string.h"
15 
16 namespace v8 {
17 namespace internal {
18 namespace compiler {
19 
20 class GraphAssembler::BasicBlockUpdater {
21  public:
22   BasicBlockUpdater(Schedule* schedule, Graph* graph,
23                     CommonOperatorBuilder* common, Zone* temp_zone);
24 
25   Node* AddNode(Node* node);
26   Node* AddNode(Node* node, BasicBlock* to);
27   Node* AddClonedNode(Node* node);
28 
29   BasicBlock* NewBasicBlock(bool deferred);
30   BasicBlock* SplitBasicBlock();
31   void AddBind(BasicBlock* block);
32   void AddBranch(Node* branch, BasicBlock* tblock, BasicBlock* fblock);
33   void AddGoto(BasicBlock* to);
34   void AddGoto(BasicBlock* from, BasicBlock* to);
35   void AddTailCall(Node* node);
36 
37   void StartBlock(BasicBlock* block);
38   BasicBlock* Finalize(BasicBlock* original);
39 
original_block()40   BasicBlock* original_block() { return original_block_; }
original_control()41   BasicBlock::Control original_control() { return original_control_; }
original_control_input()42   Node* original_control_input() { return original_control_input_; }
43 
44  private:
45   enum State { kUnchanged, kChanged };
46 
temp_zone()47   Zone* temp_zone() { return temp_zone_; }
48 
49   bool IsOriginalNode(Node* node);
50   void UpdateSuccessors(BasicBlock* block);
51   void SetBlockDeferredFromPredecessors();
52   void RemoveSuccessorsFromSchedule();
53   void CopyForChange();
54 
55   Zone* temp_zone_;
56 
57   // Current basic block we are scheduling.
58   BasicBlock* current_block_;
59 
60   // The original block that we are lowering.
61   BasicBlock* original_block_;
62 
63   // Position in the current block, only applicable in the 'unchanged' state.
64   BasicBlock::iterator node_it_;
65   BasicBlock::iterator end_it_;
66 
67   Schedule* schedule_;
68   Graph* graph_;
69   CommonOperatorBuilder* common_;
70 
71   // The nodes in the original block if we are in 'changed' state. Retained to
72   // avoid invalidating iterators that are iterating over the original nodes of
73   // the block.
74   NodeVector saved_nodes_;
75 
76   // The original control, control input and successors, to enable recovery of
77   // them when we finalize the block.
78   struct SuccessorInfo {
79     BasicBlock* block;
80     size_t index;
81   };
82   ZoneVector<SuccessorInfo> saved_successors_;
83   BasicBlock::Control original_control_;
84   Node* original_control_input_;
85   bool original_deferred_;
86   size_t original_node_count_;
87 
88   State state_;
89 };
90 
BasicBlockUpdater(Schedule * schedule,Graph * graph,CommonOperatorBuilder * common,Zone * temp_zone)91 GraphAssembler::BasicBlockUpdater::BasicBlockUpdater(
92     Schedule* schedule, Graph* graph, CommonOperatorBuilder* common,
93     Zone* temp_zone)
94     : temp_zone_(temp_zone),
95       current_block_(nullptr),
96       original_block_(nullptr),
97       schedule_(schedule),
98       graph_(graph),
99       common_(common),
100       saved_nodes_(schedule->zone()),
101       saved_successors_(schedule->zone()),
102       original_control_(BasicBlock::kNone),
103       original_control_input_(nullptr),
104       original_deferred_(false),
105       original_node_count_(graph->NodeCount()),
106       state_(kUnchanged) {}
107 
AddNode(Node * node)108 Node* GraphAssembler::BasicBlockUpdater::AddNode(Node* node) {
109   return AddNode(node, current_block_);
110 }
111 
AddNode(Node * node,BasicBlock * to)112 Node* GraphAssembler::BasicBlockUpdater::AddNode(Node* node, BasicBlock* to) {
113   if (state_ == kUnchanged) {
114     DCHECK_EQ(to, original_block());
115 
116     if (node_it_ != end_it_ && *node_it_ == node) {
117       node_it_++;
118       return node;
119     }
120 
121     CopyForChange();
122   }
123 
124   // Add the node to the basic block.
125   DCHECK(!schedule_->IsScheduled(node));
126   schedule_->AddNode(to, node);
127   return node;
128 }
129 
AddClonedNode(Node * node)130 Node* GraphAssembler::BasicBlockUpdater::AddClonedNode(Node* node) {
131   DCHECK(node->op()->HasProperty(Operator::kPure));
132   if (state_ == kUnchanged) {
133     CopyForChange();
134   }
135 
136   if (schedule_->IsScheduled(node) &&
137       schedule_->block(node) == current_block_) {
138     // Node is already scheduled for the current block, don't add it again.
139     return node;
140   } else if (!schedule_->IsScheduled(node) && !IsOriginalNode(node)) {
141     // Node is not scheduled yet, so we can add it directly.
142     return AddNode(node);
143   } else {
144     // TODO(9684): Potentially add some per-block caching so we can avoid
145     // cloning if we've already cloned for this block.
146     return AddNode(graph_->CloneNode(node));
147   }
148 }
149 
IsOriginalNode(Node * node)150 bool GraphAssembler::BasicBlockUpdater::IsOriginalNode(Node* node) {
151   // Return true if node was part of the original schedule and might currently
152   // be re-added to the schedule after a CopyForChange.
153   return node->id() < original_node_count_;
154 }
155 
CopyForChange()156 void GraphAssembler::BasicBlockUpdater::CopyForChange() {
157   DCHECK_EQ(kUnchanged, state_);
158 
159   // Save successor.
160   DCHECK(saved_successors_.empty());
161   for (BasicBlock* successor : original_block()->successors()) {
162     for (size_t i = 0; i < successor->PredecessorCount(); i++) {
163       if (successor->PredecessorAt(i) == original_block()) {
164         saved_successors_.push_back({successor, i});
165         break;
166       }
167     }
168   }
169   DCHECK_EQ(saved_successors_.size(), original_block()->SuccessorCount());
170 
171   // Save control.
172   original_control_ = original_block()->control();
173   original_control_input_ = original_block()->control_input();
174 
175   // Save original nodes (to allow them to continue to be iterated by the user
176   // of graph assembler).
177   original_block()->nodes()->swap(saved_nodes_);
178   DCHECK(original_block()->nodes()->empty());
179 
180   // Re-insert the nodes from the front of the block.
181   original_block()->InsertNodes(original_block()->begin(), saved_nodes_.begin(),
182                                 node_it_);
183 
184   // Remove the tail from the schedule.
185   for (; node_it_ != end_it_; node_it_++) {
186     schedule_->SetBlockForNode(nullptr, *node_it_);
187   }
188 
189   // Reset the control.
190   if (original_block()->control() != BasicBlock::kGoto) {
191     schedule_->SetBlockForNode(nullptr, original_block()->control_input());
192   }
193   original_block()->set_control_input(nullptr);
194   original_block()->set_control(BasicBlock::kNone);
195   original_block()->ClearSuccessors();
196 
197   state_ = kChanged;
198   end_it_ = {};
199   node_it_ = {};
200 }
201 
NewBasicBlock(bool deferred)202 BasicBlock* GraphAssembler::BasicBlockUpdater::NewBasicBlock(bool deferred) {
203   BasicBlock* block = schedule_->NewBasicBlock();
204   block->set_deferred(deferred || original_deferred_);
205   return block;
206 }
207 
SplitBasicBlock()208 BasicBlock* GraphAssembler::BasicBlockUpdater::SplitBasicBlock() {
209   return NewBasicBlock(current_block_->deferred());
210 }
211 
AddBind(BasicBlock * to)212 void GraphAssembler::BasicBlockUpdater::AddBind(BasicBlock* to) {
213   DCHECK_NOT_NULL(to);
214   current_block_ = to;
215   // Basic block should only have the control node, if any.
216   DCHECK_LE(current_block_->NodeCount(), 1);
217   SetBlockDeferredFromPredecessors();
218 }
219 
SetBlockDeferredFromPredecessors()220 void GraphAssembler::BasicBlockUpdater::SetBlockDeferredFromPredecessors() {
221   if (!current_block_->deferred()) {
222     bool deferred = true;
223     for (BasicBlock* pred : current_block_->predecessors()) {
224       if (!pred->deferred()) {
225         deferred = false;
226         break;
227       }
228     }
229     current_block_->set_deferred(deferred);
230   }
231 }
232 
AddBranch(Node * node,BasicBlock * tblock,BasicBlock * fblock)233 void GraphAssembler::BasicBlockUpdater::AddBranch(Node* node,
234                                                   BasicBlock* tblock,
235                                                   BasicBlock* fblock) {
236   if (state_ == kUnchanged) {
237     DCHECK_EQ(current_block_, original_block());
238     CopyForChange();
239   }
240 
241   DCHECK_EQ(state_, kChanged);
242   schedule_->AddBranch(current_block_, node, tblock, fblock);
243   current_block_ = nullptr;
244 }
245 
AddGoto(BasicBlock * to)246 void GraphAssembler::BasicBlockUpdater::AddGoto(BasicBlock* to) {
247   DCHECK_NOT_NULL(current_block_);
248   AddGoto(current_block_, to);
249 }
250 
AddGoto(BasicBlock * from,BasicBlock * to)251 void GraphAssembler::BasicBlockUpdater::AddGoto(BasicBlock* from,
252                                                 BasicBlock* to) {
253   if (state_ == kUnchanged) {
254     CopyForChange();
255   }
256 
257   if (to->deferred() && !from->deferred()) {
258     // Add a new block with the correct deferred hint to avoid merges into the
259     // target block with different deferred hints.
260     // TODO(9684): Only split the current basic block if the label's target
261     // block has multiple merges.
262     BasicBlock* new_block = NewBasicBlock(to->deferred());
263     schedule_->AddGoto(from, new_block);
264     from = new_block;
265   }
266 
267   schedule_->AddGoto(from, to);
268   current_block_ = nullptr;
269 }
270 
AddTailCall(Node * node)271 void GraphAssembler::BasicBlockUpdater::AddTailCall(Node* node) {
272   DCHECK_EQ(node->opcode(), IrOpcode::kTailCall);
273   DCHECK_NOT_NULL(current_block_);
274 
275   if (state_ == kUnchanged) {
276     CopyForChange();
277   }
278 
279   schedule_->AddTailCall(current_block_, node);
280   current_block_ = nullptr;
281 }
282 
UpdateSuccessors(BasicBlock * block)283 void GraphAssembler::BasicBlockUpdater::UpdateSuccessors(BasicBlock* block) {
284   for (SuccessorInfo succ : saved_successors_) {
285     (succ.block->predecessors())[succ.index] = block;
286     block->AddSuccessor(succ.block);
287   }
288   saved_successors_.clear();
289   block->set_control(original_control_);
290   block->set_control_input(original_control_input_);
291   if (original_control_input_ != nullptr) {
292     schedule_->SetBlockForNode(block, original_control_input_);
293   } else {
294     DCHECK_EQ(BasicBlock::kGoto, original_control_);
295   }
296 }
297 
StartBlock(BasicBlock * block)298 void GraphAssembler::BasicBlockUpdater::StartBlock(BasicBlock* block) {
299   DCHECK_NULL(current_block_);
300   DCHECK_NULL(original_block_);
301   DCHECK(saved_nodes_.empty());
302   block->ResetRPOInfo();
303   current_block_ = block;
304   original_block_ = block;
305   original_deferred_ = block->deferred();
306   node_it_ = block->begin();
307   end_it_ = block->end();
308   state_ = kUnchanged;
309 }
310 
Finalize(BasicBlock * original)311 BasicBlock* GraphAssembler::BasicBlockUpdater::Finalize(BasicBlock* original) {
312   DCHECK_EQ(original, original_block());
313   BasicBlock* block = current_block_;
314   if (state_ == kChanged) {
315     UpdateSuccessors(block);
316   } else {
317     DCHECK_EQ(block, original_block());
318     if (node_it_ != end_it_) {
319       // We have not got to the end of the node list, we need to trim.
320       block->TrimNodes(node_it_);
321     }
322   }
323   original_control_ = BasicBlock::kNone;
324   saved_nodes_.clear();
325   original_deferred_ = false;
326   original_control_input_ = nullptr;
327   original_block_ = nullptr;
328   current_block_ = nullptr;
329   return block;
330 }
331 
GraphAssembler(MachineGraph * mcgraph,Zone * zone,base::Optional<NodeChangedCallback> node_changed_callback,Schedule * schedule,bool mark_loop_exits)332 GraphAssembler::GraphAssembler(
333     MachineGraph* mcgraph, Zone* zone,
334     base::Optional<NodeChangedCallback> node_changed_callback,
335     Schedule* schedule, bool mark_loop_exits)
336     : temp_zone_(zone),
337       mcgraph_(mcgraph),
338       effect_(nullptr),
339       control_(nullptr),
340       node_changed_callback_(node_changed_callback),
341       block_updater_(schedule != nullptr
342                          ? new BasicBlockUpdater(schedule, mcgraph->graph(),
343                                                  mcgraph->common(), zone)
344                          : nullptr),
345       loop_headers_(zone),
346       mark_loop_exits_(mark_loop_exits) {}
347 
~GraphAssembler()348 GraphAssembler::~GraphAssembler() { DCHECK_EQ(loop_nesting_level_, 0); }
349 
IntPtrConstant(intptr_t value)350 Node* GraphAssembler::IntPtrConstant(intptr_t value) {
351   return AddClonedNode(mcgraph()->IntPtrConstant(value));
352 }
353 
UintPtrConstant(uintptr_t value)354 Node* GraphAssembler::UintPtrConstant(uintptr_t value) {
355   return AddClonedNode(mcgraph()->UintPtrConstant(value));
356 }
357 
Int32Constant(int32_t value)358 Node* GraphAssembler::Int32Constant(int32_t value) {
359   return AddClonedNode(mcgraph()->Int32Constant(value));
360 }
361 
Int64Constant(int64_t value)362 Node* GraphAssembler::Int64Constant(int64_t value) {
363   return AddClonedNode(mcgraph()->Int64Constant(value));
364 }
365 
UniqueIntPtrConstant(intptr_t value)366 Node* GraphAssembler::UniqueIntPtrConstant(intptr_t value) {
367   return AddNode(graph()->NewNode(
368       machine()->Is64()
369           ? common()->Int64Constant(value)
370           : common()->Int32Constant(static_cast<int32_t>(value))));
371 }
372 
SmiConstant(int32_t value)373 Node* JSGraphAssembler::SmiConstant(int32_t value) {
374   return AddClonedNode(jsgraph()->SmiConstant(value));
375 }
376 
Uint32Constant(uint32_t value)377 Node* GraphAssembler::Uint32Constant(uint32_t value) {
378   return AddClonedNode(mcgraph()->Uint32Constant(value));
379 }
380 
Float64Constant(double value)381 Node* GraphAssembler::Float64Constant(double value) {
382   return AddClonedNode(mcgraph()->Float64Constant(value));
383 }
384 
HeapConstant(Handle<HeapObject> object)385 TNode<HeapObject> JSGraphAssembler::HeapConstant(Handle<HeapObject> object) {
386   return TNode<HeapObject>::UncheckedCast(
387       AddClonedNode(jsgraph()->HeapConstant(object)));
388 }
389 
Constant(const ObjectRef & ref)390 TNode<Object> JSGraphAssembler::Constant(const ObjectRef& ref) {
391   return TNode<Object>::UncheckedCast(AddClonedNode(jsgraph()->Constant(ref)));
392 }
393 
NumberConstant(double value)394 TNode<Number> JSGraphAssembler::NumberConstant(double value) {
395   return TNode<Number>::UncheckedCast(
396       AddClonedNode(jsgraph()->Constant(value)));
397 }
398 
ExternalConstant(ExternalReference ref)399 Node* GraphAssembler::ExternalConstant(ExternalReference ref) {
400   return AddClonedNode(mcgraph()->ExternalConstant(ref));
401 }
402 
Parameter(int index)403 Node* GraphAssembler::Parameter(int index) {
404   return AddNode(
405       graph()->NewNode(common()->Parameter(index), graph()->start()));
406 }
407 
CEntryStubConstant(int result_size)408 Node* JSGraphAssembler::CEntryStubConstant(int result_size) {
409   return AddClonedNode(jsgraph()->CEntryStubConstant(result_size));
410 }
411 
LoadFramePointer()412 Node* GraphAssembler::LoadFramePointer() {
413   return AddNode(graph()->NewNode(machine()->LoadFramePointer()));
414 }
415 
LoadHeapNumberValue(Node * heap_number)416 Node* GraphAssembler::LoadHeapNumberValue(Node* heap_number) {
417   return Load(MachineType::Float64(), heap_number,
418               IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag));
419 }
420 
421 #define SINGLETON_CONST_DEF(Name, Type)              \
422   TNode<Type> JSGraphAssembler::Name##Constant() {   \
423     return TNode<Type>::UncheckedCast(               \
424         AddClonedNode(jsgraph()->Name##Constant())); \
425   }
426 JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DEF)
427 #undef SINGLETON_CONST_DEF
428 
429 #define SINGLETON_CONST_TEST_DEF(Name, ...)                        \
430   TNode<Boolean> JSGraphAssembler::Is##Name(TNode<Object> value) { \
431     return TNode<Boolean>::UncheckedCast(                          \
432         ReferenceEqual(value, Name##Constant()));                  \
433   }
JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_TEST_DEF)434 JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_TEST_DEF)
435 #undef SINGLETON_CONST_TEST_DEF
436 
437 #define PURE_UNOP_DEF(Name)                                     \
438   Node* GraphAssembler::Name(Node* input) {                     \
439     return AddNode(graph()->NewNode(machine()->Name(), input)); \
440   }
441 PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DEF)
442 #undef PURE_UNOP_DEF
443 
444 #define PURE_BINOP_DEF(Name)                                          \
445   Node* GraphAssembler::Name(Node* left, Node* right) {               \
446     return AddNode(graph()->NewNode(machine()->Name(), left, right)); \
447   }
448 PURE_ASSEMBLER_MACH_BINOP_LIST(PURE_BINOP_DEF)
449 #undef PURE_BINOP_DEF
450 
451 #define CHECKED_BINOP_DEF(Name)                                       \
452   Node* GraphAssembler::Name(Node* left, Node* right) {               \
453     return AddNode(                                                   \
454         graph()->NewNode(machine()->Name(), left, right, control())); \
455   }
456 CHECKED_ASSEMBLER_MACH_BINOP_LIST(CHECKED_BINOP_DEF)
457 #undef CHECKED_BINOP_DEF
458 
459 Node* GraphAssembler::IntPtrEqual(Node* left, Node* right) {
460   return WordEqual(left, right);
461 }
462 
TaggedEqual(Node * left,Node * right)463 Node* GraphAssembler::TaggedEqual(Node* left, Node* right) {
464   if (COMPRESS_POINTERS_BOOL) {
465     return Word32Equal(left, right);
466   } else {
467     return WordEqual(left, right);
468   }
469 }
470 
SmiSub(Node * left,Node * right)471 Node* GraphAssembler::SmiSub(Node* left, Node* right) {
472   if (COMPRESS_POINTERS_BOOL) {
473     return Int32Sub(left, right);
474   } else {
475     return IntSub(left, right);
476   }
477 }
478 
SmiLessThan(Node * left,Node * right)479 Node* GraphAssembler::SmiLessThan(Node* left, Node* right) {
480   if (COMPRESS_POINTERS_BOOL) {
481     return Int32LessThan(left, right);
482   } else {
483     return IntLessThan(left, right);
484   }
485 }
486 
Float64RoundDown(Node * value)487 Node* GraphAssembler::Float64RoundDown(Node* value) {
488   CHECK(machine()->Float64RoundDown().IsSupported());
489   return AddNode(graph()->NewNode(machine()->Float64RoundDown().op(), value));
490 }
491 
Float64RoundTruncate(Node * value)492 Node* GraphAssembler::Float64RoundTruncate(Node* value) {
493   CHECK(machine()->Float64RoundTruncate().IsSupported());
494   return AddNode(
495       graph()->NewNode(machine()->Float64RoundTruncate().op(), value));
496 }
497 
Projection(int index,Node * value)498 Node* GraphAssembler::Projection(int index, Node* value) {
499   return AddNode(
500       graph()->NewNode(common()->Projection(index), value, control()));
501 }
502 
Allocate(AllocationType allocation,Node * size)503 Node* JSGraphAssembler::Allocate(AllocationType allocation, Node* size) {
504   return AddNode(
505       graph()->NewNode(simplified()->AllocateRaw(Type::Any(), allocation), size,
506                        effect(), control()));
507 }
508 
LoadField(FieldAccess const & access,Node * object)509 Node* JSGraphAssembler::LoadField(FieldAccess const& access, Node* object) {
510   Node* value = AddNode(graph()->NewNode(simplified()->LoadField(access),
511                                          object, effect(), control()));
512   return value;
513 }
514 
LoadElement(ElementAccess const & access,Node * object,Node * index)515 Node* JSGraphAssembler::LoadElement(ElementAccess const& access, Node* object,
516                                     Node* index) {
517   Node* value = AddNode(graph()->NewNode(simplified()->LoadElement(access),
518                                          object, index, effect(), control()));
519   return value;
520 }
521 
StoreField(FieldAccess const & access,Node * object,Node * value)522 Node* JSGraphAssembler::StoreField(FieldAccess const& access, Node* object,
523                                    Node* value) {
524   return AddNode(graph()->NewNode(simplified()->StoreField(access), object,
525                                   value, effect(), control()));
526 }
527 
StoreElement(ElementAccess const & access,Node * object,Node * index,Node * value)528 Node* JSGraphAssembler::StoreElement(ElementAccess const& access, Node* object,
529                                      Node* index, Node* value) {
530   return AddNode(graph()->NewNode(simplified()->StoreElement(access), object,
531                                   index, value, effect(), control()));
532 }
533 
TransitionAndStoreElement(MapRef double_map,MapRef fast_map,TNode<HeapObject> object,TNode<Number> index,TNode<Object> value)534 void JSGraphAssembler::TransitionAndStoreElement(MapRef double_map,
535                                                  MapRef fast_map,
536                                                  TNode<HeapObject> object,
537                                                  TNode<Number> index,
538                                                  TNode<Object> value) {
539   AddNode(graph()->NewNode(simplified()->TransitionAndStoreElement(
540                                double_map.object(), fast_map.object()),
541                            object, index, value, effect(), control()));
542 }
543 
StringLength(TNode<String> string)544 TNode<Number> JSGraphAssembler::StringLength(TNode<String> string) {
545   return AddNode<Number>(
546       graph()->NewNode(simplified()->StringLength(), string));
547 }
548 
ReferenceEqual(TNode<Object> lhs,TNode<Object> rhs)549 TNode<Boolean> JSGraphAssembler::ReferenceEqual(TNode<Object> lhs,
550                                                 TNode<Object> rhs) {
551   return AddNode<Boolean>(
552       graph()->NewNode(simplified()->ReferenceEqual(), lhs, rhs));
553 }
554 
NumberMin(TNode<Number> lhs,TNode<Number> rhs)555 TNode<Number> JSGraphAssembler::NumberMin(TNode<Number> lhs,
556                                           TNode<Number> rhs) {
557   return AddNode<Number>(graph()->NewNode(simplified()->NumberMin(), lhs, rhs));
558 }
559 
NumberMax(TNode<Number> lhs,TNode<Number> rhs)560 TNode<Number> JSGraphAssembler::NumberMax(TNode<Number> lhs,
561                                           TNode<Number> rhs) {
562   return AddNode<Number>(graph()->NewNode(simplified()->NumberMax(), lhs, rhs));
563 }
564 
NumberAdd(TNode<Number> lhs,TNode<Number> rhs)565 TNode<Number> JSGraphAssembler::NumberAdd(TNode<Number> lhs,
566                                           TNode<Number> rhs) {
567   return AddNode<Number>(graph()->NewNode(simplified()->NumberAdd(), lhs, rhs));
568 }
569 
NumberSubtract(TNode<Number> lhs,TNode<Number> rhs)570 TNode<Number> JSGraphAssembler::NumberSubtract(TNode<Number> lhs,
571                                                TNode<Number> rhs) {
572   return AddNode<Number>(
573       graph()->NewNode(simplified()->NumberSubtract(), lhs, rhs));
574 }
575 
NumberLessThan(TNode<Number> lhs,TNode<Number> rhs)576 TNode<Boolean> JSGraphAssembler::NumberLessThan(TNode<Number> lhs,
577                                                 TNode<Number> rhs) {
578   return AddNode<Boolean>(
579       graph()->NewNode(simplified()->NumberLessThan(), lhs, rhs));
580 }
581 
NumberLessThanOrEqual(TNode<Number> lhs,TNode<Number> rhs)582 TNode<Boolean> JSGraphAssembler::NumberLessThanOrEqual(TNode<Number> lhs,
583                                                        TNode<Number> rhs) {
584   return AddNode<Boolean>(
585       graph()->NewNode(simplified()->NumberLessThanOrEqual(), lhs, rhs));
586 }
587 
StringSubstring(TNode<String> string,TNode<Number> from,TNode<Number> to)588 TNode<String> JSGraphAssembler::StringSubstring(TNode<String> string,
589                                                 TNode<Number> from,
590                                                 TNode<Number> to) {
591   return AddNode<String>(graph()->NewNode(
592       simplified()->StringSubstring(), string, from, to, effect(), control()));
593 }
594 
ObjectIsCallable(TNode<Object> value)595 TNode<Boolean> JSGraphAssembler::ObjectIsCallable(TNode<Object> value) {
596   return AddNode<Boolean>(
597       graph()->NewNode(simplified()->ObjectIsCallable(), value));
598 }
599 
ObjectIsUndetectable(TNode<Object> value)600 TNode<Boolean> JSGraphAssembler::ObjectIsUndetectable(TNode<Object> value) {
601   return AddNode<Boolean>(
602       graph()->NewNode(simplified()->ObjectIsUndetectable(), value));
603 }
604 
CheckIf(Node * cond,DeoptimizeReason reason)605 Node* JSGraphAssembler::CheckIf(Node* cond, DeoptimizeReason reason) {
606   return AddNode(graph()->NewNode(simplified()->CheckIf(reason), cond, effect(),
607                                   control()));
608 }
609 
NumberIsFloat64Hole(TNode<Number> value)610 TNode<Boolean> JSGraphAssembler::NumberIsFloat64Hole(TNode<Number> value) {
611   return AddNode<Boolean>(
612       graph()->NewNode(simplified()->NumberIsFloat64Hole(), value));
613 }
614 
ToBoolean(TNode<Object> value)615 TNode<Boolean> JSGraphAssembler::ToBoolean(TNode<Object> value) {
616   return AddNode<Boolean>(graph()->NewNode(simplified()->ToBoolean(), value));
617 }
618 
ConvertTaggedHoleToUndefined(TNode<Object> value)619 TNode<Object> JSGraphAssembler::ConvertTaggedHoleToUndefined(
620     TNode<Object> value) {
621   return AddNode<Object>(
622       graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value));
623 }
624 
MaybeGrowFastElements(ElementsKind kind,const FeedbackSource & feedback,TNode<JSArray> array,TNode<FixedArrayBase> elements,TNode<Number> new_length,TNode<Number> old_length)625 TNode<FixedArrayBase> JSGraphAssembler::MaybeGrowFastElements(
626     ElementsKind kind, const FeedbackSource& feedback, TNode<JSArray> array,
627     TNode<FixedArrayBase> elements, TNode<Number> new_length,
628     TNode<Number> old_length) {
629   GrowFastElementsMode mode = IsDoubleElementsKind(kind)
630                                   ? GrowFastElementsMode::kDoubleElements
631                                   : GrowFastElementsMode::kSmiOrObjectElements;
632   return AddNode<FixedArrayBase>(graph()->NewNode(
633       simplified()->MaybeGrowFastElements(mode, feedback), array, elements,
634       new_length, old_length, effect(), control()));
635 }
636 
TypeGuard(Type type,Node * value)637 Node* GraphAssembler::TypeGuard(Type type, Node* value) {
638   return AddNode(
639       graph()->NewNode(common()->TypeGuard(type), value, effect(), control()));
640 }
641 
Checkpoint(FrameState frame_state)642 Node* GraphAssembler::Checkpoint(FrameState frame_state) {
643   return AddNode(graph()->NewNode(common()->Checkpoint(), frame_state, effect(),
644                                   control()));
645 }
646 
DebugBreak()647 Node* GraphAssembler::DebugBreak() {
648   return AddNode(
649       graph()->NewNode(machine()->DebugBreak(), effect(), control()));
650 }
651 
Unreachable(GraphAssemblerLabel<0u> * block_updater_successor)652 Node* GraphAssembler::Unreachable(
653     GraphAssemblerLabel<0u>* block_updater_successor) {
654   Node* result = UnreachableWithoutConnectToEnd();
655   if (block_updater_ == nullptr) {
656     ConnectUnreachableToEnd();
657     InitializeEffectControl(nullptr, nullptr);
658   } else {
659     DCHECK_NOT_NULL(block_updater_successor);
660     Goto(block_updater_successor);
661   }
662   return result;
663 }
664 
UnreachableWithoutConnectToEnd()665 Node* GraphAssembler::UnreachableWithoutConnectToEnd() {
666   return AddNode(
667       graph()->NewNode(common()->Unreachable(), effect(), control()));
668 }
669 
StackSlot(int size,int alignment)670 TNode<RawPtrT> GraphAssembler::StackSlot(int size, int alignment) {
671   return AddNode<RawPtrT>(
672       graph()->NewNode(machine()->StackSlot(size, alignment)));
673 }
674 
Store(StoreRepresentation rep,Node * object,Node * offset,Node * value)675 Node* GraphAssembler::Store(StoreRepresentation rep, Node* object, Node* offset,
676                             Node* value) {
677   return AddNode(graph()->NewNode(machine()->Store(rep), object, offset, value,
678                                   effect(), control()));
679 }
680 
Store(StoreRepresentation rep,Node * object,int offset,Node * value)681 Node* GraphAssembler::Store(StoreRepresentation rep, Node* object, int offset,
682                             Node* value) {
683   return Store(rep, object, Int32Constant(offset), value);
684 }
685 
Load(MachineType type,Node * object,Node * offset)686 Node* GraphAssembler::Load(MachineType type, Node* object, Node* offset) {
687   return AddNode(graph()->NewNode(machine()->Load(type), object, offset,
688                                   effect(), control()));
689 }
690 
Load(MachineType type,Node * object,int offset)691 Node* GraphAssembler::Load(MachineType type, Node* object, int offset) {
692   return Load(type, object, Int32Constant(offset));
693 }
694 
StoreUnaligned(MachineRepresentation rep,Node * object,Node * offset,Node * value)695 Node* GraphAssembler::StoreUnaligned(MachineRepresentation rep, Node* object,
696                                      Node* offset, Node* value) {
697   Operator const* const op =
698       (rep == MachineRepresentation::kWord8 ||
699        machine()->UnalignedStoreSupported(rep))
700           ? machine()->Store(StoreRepresentation(rep, kNoWriteBarrier))
701           : machine()->UnalignedStore(rep);
702   return AddNode(
703       graph()->NewNode(op, object, offset, value, effect(), control()));
704 }
705 
LoadUnaligned(MachineType type,Node * object,Node * offset)706 Node* GraphAssembler::LoadUnaligned(MachineType type, Node* object,
707                                     Node* offset) {
708   Operator const* const op =
709       (type.representation() == MachineRepresentation::kWord8 ||
710        machine()->UnalignedLoadSupported(type.representation()))
711           ? machine()->Load(type)
712           : machine()->UnalignedLoad(type);
713   return AddNode(graph()->NewNode(op, object, offset, effect(), control()));
714 }
715 
ProtectedStore(MachineRepresentation rep,Node * object,Node * offset,Node * value)716 Node* GraphAssembler::ProtectedStore(MachineRepresentation rep, Node* object,
717                                      Node* offset, Node* value) {
718   return AddNode(graph()->NewNode(machine()->ProtectedStore(rep), object,
719                                   offset, value, effect(), control()));
720 }
721 
ProtectedLoad(MachineType type,Node * object,Node * offset)722 Node* GraphAssembler::ProtectedLoad(MachineType type, Node* object,
723                                     Node* offset) {
724   return AddNode(graph()->NewNode(machine()->ProtectedLoad(type), object,
725                                   offset, effect(), control()));
726 }
727 
Retain(Node * buffer)728 Node* GraphAssembler::Retain(Node* buffer) {
729   return AddNode(graph()->NewNode(common()->Retain(), buffer, effect()));
730 }
731 
UnsafePointerAdd(Node * base,Node * external)732 Node* GraphAssembler::UnsafePointerAdd(Node* base, Node* external) {
733   return AddNode(graph()->NewNode(machine()->UnsafePointerAdd(), base, external,
734                                   effect(), control()));
735 }
736 
PlainPrimitiveToNumber(TNode<Object> value)737 TNode<Number> JSGraphAssembler::PlainPrimitiveToNumber(TNode<Object> value) {
738   return AddNode<Number>(graph()->NewNode(
739       PlainPrimitiveToNumberOperator(), PlainPrimitiveToNumberBuiltinConstant(),
740       value, effect()));
741 }
742 
BitcastWordToTaggedSigned(Node * value)743 Node* GraphAssembler::BitcastWordToTaggedSigned(Node* value) {
744   return AddNode(
745       graph()->NewNode(machine()->BitcastWordToTaggedSigned(), value));
746 }
747 
BitcastWordToTagged(Node * value)748 Node* GraphAssembler::BitcastWordToTagged(Node* value) {
749   return AddNode(graph()->NewNode(machine()->BitcastWordToTagged(), value,
750                                   effect(), control()));
751 }
752 
BitcastTaggedToWord(Node * value)753 Node* GraphAssembler::BitcastTaggedToWord(Node* value) {
754   return AddNode(graph()->NewNode(machine()->BitcastTaggedToWord(), value,
755                                   effect(), control()));
756 }
757 
BitcastTaggedToWordForTagAndSmiBits(Node * value)758 Node* GraphAssembler::BitcastTaggedToWordForTagAndSmiBits(Node* value) {
759   return AddNode(graph()->NewNode(
760       machine()->BitcastTaggedToWordForTagAndSmiBits(), value));
761 }
762 
BitcastMaybeObjectToWord(Node * value)763 Node* GraphAssembler::BitcastMaybeObjectToWord(Node* value) {
764   return AddNode(graph()->NewNode(machine()->BitcastMaybeObjectToWord(), value,
765                                   effect(), control()));
766 }
767 
Word32PoisonOnSpeculation(Node * value)768 Node* GraphAssembler::Word32PoisonOnSpeculation(Node* value) {
769   return AddNode(graph()->NewNode(machine()->Word32PoisonOnSpeculation(), value,
770                                   effect(), control()));
771 }
772 
DeoptimizeIf(DeoptimizeReason reason,FeedbackSource const & feedback,Node * condition,Node * frame_state,IsSafetyCheck is_safety_check)773 Node* GraphAssembler::DeoptimizeIf(DeoptimizeReason reason,
774                                    FeedbackSource const& feedback,
775                                    Node* condition, Node* frame_state,
776                                    IsSafetyCheck is_safety_check) {
777   return AddNode(
778       graph()->NewNode(common()->DeoptimizeIf(DeoptimizeKind::kEager, reason,
779                                               feedback, is_safety_check),
780                        condition, frame_state, effect(), control()));
781 }
782 
DeoptimizeIf(DeoptimizeKind kind,DeoptimizeReason reason,FeedbackSource const & feedback,Node * condition,Node * frame_state,IsSafetyCheck is_safety_check)783 Node* GraphAssembler::DeoptimizeIf(DeoptimizeKind kind, DeoptimizeReason reason,
784                                    FeedbackSource const& feedback,
785                                    Node* condition, Node* frame_state,
786                                    IsSafetyCheck is_safety_check) {
787   return AddNode(graph()->NewNode(
788       common()->DeoptimizeIf(kind, reason, feedback, is_safety_check),
789       condition, frame_state, effect(), control()));
790 }
791 
DeoptimizeIfNot(DeoptimizeKind kind,DeoptimizeReason reason,FeedbackSource const & feedback,Node * condition,Node * frame_state,IsSafetyCheck is_safety_check)792 Node* GraphAssembler::DeoptimizeIfNot(DeoptimizeKind kind,
793                                       DeoptimizeReason reason,
794                                       FeedbackSource const& feedback,
795                                       Node* condition, Node* frame_state,
796                                       IsSafetyCheck is_safety_check) {
797   return AddNode(graph()->NewNode(
798       common()->DeoptimizeUnless(kind, reason, feedback, is_safety_check),
799       condition, frame_state, effect(), control()));
800 }
801 
DeoptimizeIfNot(DeoptimizeReason reason,FeedbackSource const & feedback,Node * condition,Node * frame_state,IsSafetyCheck is_safety_check)802 Node* GraphAssembler::DeoptimizeIfNot(DeoptimizeReason reason,
803                                       FeedbackSource const& feedback,
804                                       Node* condition, Node* frame_state,
805                                       IsSafetyCheck is_safety_check) {
806   return DeoptimizeIfNot(DeoptimizeKind::kEager, reason, feedback, condition,
807                          frame_state, is_safety_check);
808 }
809 
Call(const CallDescriptor * call_descriptor,int inputs_size,Node ** inputs)810 TNode<Object> GraphAssembler::Call(const CallDescriptor* call_descriptor,
811                                    int inputs_size, Node** inputs) {
812   return Call(common()->Call(call_descriptor), inputs_size, inputs);
813 }
814 
Call(const Operator * op,int inputs_size,Node ** inputs)815 TNode<Object> GraphAssembler::Call(const Operator* op, int inputs_size,
816                                    Node** inputs) {
817   DCHECK_EQ(IrOpcode::kCall, op->opcode());
818   return AddNode<Object>(graph()->NewNode(op, inputs_size, inputs));
819 }
820 
TailCall(const CallDescriptor * call_descriptor,int inputs_size,Node ** inputs)821 void GraphAssembler::TailCall(const CallDescriptor* call_descriptor,
822                               int inputs_size, Node** inputs) {
823 #ifdef DEBUG
824   static constexpr int kTargetEffectControl = 3;
825   DCHECK_EQ(inputs_size,
826             call_descriptor->ParameterCount() + kTargetEffectControl);
827 #endif  // DEBUG
828 
829   Node* node = AddNode(graph()->NewNode(common()->TailCall(call_descriptor),
830                                         inputs_size, inputs));
831 
832   if (block_updater_) block_updater_->AddTailCall(node);
833 
834   // Unlike ConnectUnreachableToEnd, the TailCall node terminates a block; to
835   // keep it live, it *must* be connected to End (also in Turboprop schedules).
836   NodeProperties::MergeControlToEnd(graph(), common(), node);
837 
838   // Setting effect, control to nullptr effectively terminates the current block
839   // by disallowing the addition of new nodes until a new label has been bound.
840   InitializeEffectControl(nullptr, nullptr);
841 }
842 
BranchWithCriticalSafetyCheck(Node * condition,GraphAssemblerLabel<0u> * if_true,GraphAssemblerLabel<0u> * if_false)843 void GraphAssembler::BranchWithCriticalSafetyCheck(
844     Node* condition, GraphAssemblerLabel<0u>* if_true,
845     GraphAssemblerLabel<0u>* if_false) {
846   BranchHint hint = BranchHint::kNone;
847   if (if_true->IsDeferred() != if_false->IsDeferred()) {
848     hint = if_false->IsDeferred() ? BranchHint::kTrue : BranchHint::kFalse;
849   }
850 
851   BranchImpl(condition, if_true, if_false, hint,
852              IsSafetyCheck::kCriticalSafetyCheck);
853 }
854 
RecordBranchInBlockUpdater(Node * branch,Node * if_true_control,Node * if_false_control,BasicBlock * if_true_block,BasicBlock * if_false_block)855 void GraphAssembler::RecordBranchInBlockUpdater(Node* branch,
856                                                 Node* if_true_control,
857                                                 Node* if_false_control,
858                                                 BasicBlock* if_true_block,
859                                                 BasicBlock* if_false_block) {
860   DCHECK_NOT_NULL(block_updater_);
861   // TODO(9684): Only split the current basic block if the label's target
862   // block has multiple merges.
863   BasicBlock* if_true_target = block_updater_->SplitBasicBlock();
864   BasicBlock* if_false_target = block_updater_->SplitBasicBlock();
865 
866   block_updater_->AddBranch(branch, if_true_target, if_false_target);
867 
868   block_updater_->AddNode(if_true_control, if_true_target);
869   block_updater_->AddGoto(if_true_target, if_true_block);
870 
871   block_updater_->AddNode(if_false_control, if_false_target);
872   block_updater_->AddGoto(if_false_target, if_false_block);
873 }
874 
BindBasicBlock(BasicBlock * block)875 void GraphAssembler::BindBasicBlock(BasicBlock* block) {
876   if (block_updater_) {
877     block_updater_->AddBind(block);
878   }
879 }
880 
NewBasicBlock(bool deferred)881 BasicBlock* GraphAssembler::NewBasicBlock(bool deferred) {
882   if (!block_updater_) return nullptr;
883   return block_updater_->NewBasicBlock(deferred);
884 }
885 
GotoBasicBlock(BasicBlock * block)886 void GraphAssembler::GotoBasicBlock(BasicBlock* block) {
887   if (block_updater_) {
888     block_updater_->AddGoto(block);
889   }
890 }
891 
GotoIfBasicBlock(BasicBlock * block,Node * branch,IrOpcode::Value goto_if)892 void GraphAssembler::GotoIfBasicBlock(BasicBlock* block, Node* branch,
893                                       IrOpcode::Value goto_if) {
894   if (block_updater_) {
895     // TODO(9684): Only split the current basic block for the goto_target
896     // if block has multiple merges.
897     BasicBlock* goto_target = block_updater_->SplitBasicBlock();
898     BasicBlock* fallthrough_target = block_updater_->SplitBasicBlock();
899 
900     if (goto_if == IrOpcode::kIfTrue) {
901       block_updater_->AddBranch(branch, goto_target, fallthrough_target);
902     } else {
903       DCHECK_EQ(goto_if, IrOpcode::kIfFalse);
904       block_updater_->AddBranch(branch, fallthrough_target, goto_target);
905     }
906 
907     block_updater_->AddNode(control(), goto_target);
908     block_updater_->AddGoto(goto_target, block);
909 
910     block_updater_->AddBind(fallthrough_target);
911   }
912 }
913 
FinalizeCurrentBlock(BasicBlock * block)914 BasicBlock* GraphAssembler::FinalizeCurrentBlock(BasicBlock* block) {
915   if (block_updater_) {
916     block = block_updater_->Finalize(block);
917     if (control() == mcgraph()->Dead()) {
918       // If the block's end is unreachable, then reset current effect and
919       // control to that of the block's throw control node.
920       DCHECK(block->control() == BasicBlock::kThrow);
921       Node* throw_node = block->control_input();
922       control_ = NodeProperties::GetControlInput(throw_node);
923       effect_ = NodeProperties::GetEffectInput(throw_node);
924     }
925   }
926   return block;
927 }
928 
ConnectUnreachableToEnd()929 void GraphAssembler::ConnectUnreachableToEnd() {
930   DCHECK_EQ(effect()->opcode(), IrOpcode::kUnreachable);
931   // When maintaining the schedule we can't easily rewire the successor blocks
932   // to disconnect them from the graph, so we just leave the unreachable nodes
933   // in the schedule.
934   // TODO(9684): Add a scheduled dead-code elimination phase to remove all the
935   // subsequent unreachable code from the schedule.
936   if (!block_updater_) {
937     Node* throw_node = graph()->NewNode(common()->Throw(), effect(), control());
938     NodeProperties::MergeControlToEnd(graph(), common(), throw_node);
939     if (node_changed_callback_.has_value()) {
940       (*node_changed_callback_)(graph()->end());
941     }
942     effect_ = control_ = mcgraph()->Dead();
943   }
944 }
945 
AddClonedNode(Node * node)946 Node* GraphAssembler::AddClonedNode(Node* node) {
947   DCHECK(node->op()->HasProperty(Operator::kPure));
948   if (block_updater_) {
949     node = block_updater_->AddClonedNode(node);
950   }
951 
952   UpdateEffectControlWith(node);
953   return node;
954 }
955 
AddNode(Node * node)956 Node* GraphAssembler::AddNode(Node* node) {
957   if (block_updater_) {
958     block_updater_->AddNode(node);
959   }
960 
961   if (node->opcode() == IrOpcode::kTerminate) {
962     return node;
963   }
964 
965   UpdateEffectControlWith(node);
966   return node;
967 }
968 
Reset(BasicBlock * block)969 void GraphAssembler::Reset(BasicBlock* block) {
970   effect_ = nullptr;
971   control_ = nullptr;
972   if (block_updater_) {
973     block_updater_->StartBlock(block);
974   }
975 }
976 
InitializeEffectControl(Node * effect,Node * control)977 void GraphAssembler::InitializeEffectControl(Node* effect, Node* control) {
978   effect_ = effect;
979   control_ = control;
980 }
981 
PlainPrimitiveToNumberOperator()982 Operator const* JSGraphAssembler::PlainPrimitiveToNumberOperator() {
983   if (!to_number_operator_.is_set()) {
984     Callable callable =
985         Builtins::CallableFor(isolate(), Builtins::kPlainPrimitiveToNumber);
986     CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
987     auto call_descriptor = Linkage::GetStubCallDescriptor(
988         graph()->zone(), callable.descriptor(),
989         callable.descriptor().GetStackParameterCount(), flags,
990         Operator::kEliminatable);
991     to_number_operator_.set(common()->Call(call_descriptor));
992   }
993   return to_number_operator_.get();
994 }
995 
996 }  // namespace compiler
997 }  // namespace internal
998 }  // namespace v8
999