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