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