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