V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
graph-assembler.h
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/compiler/js-graph.h"
9 #include "src/compiler/node.h"
10 #include "src/compiler/simplified-operator.h"
11 #include "src/vector-slot-pair.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 class JSGraph;
17 class Graph;
18 
19 namespace compiler {
20 
21 #define PURE_ASSEMBLER_MACH_UNOP_LIST(V) \
22  V(ChangeInt32ToInt64) \
23  V(ChangeInt32ToFloat64) \
24  V(ChangeInt64ToFloat64) \
25  V(ChangeUint32ToFloat64) \
26  V(ChangeUint32ToUint64) \
27  V(ChangeFloat64ToInt32) \
28  V(ChangeFloat64ToInt64) \
29  V(ChangeFloat64ToUint32) \
30  V(TruncateInt64ToInt32) \
31  V(RoundFloat64ToInt32) \
32  V(TruncateFloat64ToInt64) \
33  V(TruncateFloat64ToWord32) \
34  V(Float64ExtractLowWord32) \
35  V(Float64ExtractHighWord32) \
36  V(BitcastInt32ToFloat32) \
37  V(BitcastInt64ToFloat64) \
38  V(BitcastFloat32ToInt32) \
39  V(BitcastFloat64ToInt64) \
40  V(Float64Abs) \
41  V(Word32ReverseBytes) \
42  V(Word64ReverseBytes)
43 
44 #define PURE_ASSEMBLER_MACH_BINOP_LIST(V) \
45  V(WordShl) \
46  V(WordSar) \
47  V(WordAnd) \
48  V(Word32Or) \
49  V(Word32And) \
50  V(Word32Xor) \
51  V(Word32Shr) \
52  V(Word32Shl) \
53  V(Word32Sar) \
54  V(IntAdd) \
55  V(IntSub) \
56  V(IntMul) \
57  V(IntLessThan) \
58  V(UintLessThan) \
59  V(Int32Add) \
60  V(Int32Sub) \
61  V(Int32Mul) \
62  V(Int32LessThanOrEqual) \
63  V(Uint32LessThan) \
64  V(Uint32LessThanOrEqual) \
65  V(Uint64LessThan) \
66  V(Uint64LessThanOrEqual) \
67  V(Int32LessThan) \
68  V(Float64Add) \
69  V(Float64Sub) \
70  V(Float64Div) \
71  V(Float64Mod) \
72  V(Float64Equal) \
73  V(Float64LessThan) \
74  V(Float64LessThanOrEqual) \
75  V(Float64InsertLowWord32) \
76  V(Float64InsertHighWord32) \
77  V(Word32Equal) \
78  V(Word64Equal) \
79  V(WordEqual)
80 
81 #define CHECKED_ASSEMBLER_MACH_BINOP_LIST(V) \
82  V(Int32AddWithOverflow) \
83  V(Int32SubWithOverflow) \
84  V(Int32MulWithOverflow) \
85  V(Int32Mod) \
86  V(Int32Div) \
87  V(Uint32Mod) \
88  V(Uint32Div)
89 
90 #define JSGRAPH_SINGLETON_CONSTANT_LIST(V) \
91  V(TrueConstant) \
92  V(FalseConstant) \
93  V(NullConstant) \
94  V(BooleanMapConstant) \
95  V(HeapNumberMapConstant) \
96  V(NoContextConstant) \
97  V(EmptyStringConstant) \
98  V(UndefinedConstant) \
99  V(TheHoleConstant) \
100  V(FixedArrayMapConstant) \
101  V(FixedDoubleArrayMapConstant) \
102  V(ToNumberBuiltinConstant) \
103  V(AllocateInNewSpaceStubConstant) \
104  V(AllocateInOldSpaceStubConstant)
105 
106 class GraphAssembler;
107 
108 enum class GraphAssemblerLabelType { kDeferred, kNonDeferred, kLoop };
109 
110 // Label with statically known count of incoming branches and phis.
111 template <size_t VarCount>
113  public:
114  Node* PhiAt(size_t index);
115 
116  template <typename... Reps>
117  explicit GraphAssemblerLabel(GraphAssemblerLabelType type, Reps... reps)
118  : type_(type) {
119  STATIC_ASSERT(VarCount == sizeof...(reps));
120  MachineRepresentation reps_array[] = {MachineRepresentation::kNone,
121  reps...};
122  for (size_t i = 0; i < VarCount; i++) {
123  representations_[i] = reps_array[i + 1];
124  }
125  }
126 
127  ~GraphAssemblerLabel() { DCHECK(IsBound() || merged_count_ == 0); }
128 
129  private:
130  friend class GraphAssembler;
131 
132  void SetBound() {
133  DCHECK(!IsBound());
134  is_bound_ = true;
135  }
136  bool IsBound() const { return is_bound_; }
137  bool IsDeferred() const {
138  return type_ == GraphAssemblerLabelType::kDeferred;
139  }
140  bool IsLoop() const { return type_ == GraphAssemblerLabelType::kLoop; }
141 
142  bool is_bound_ = false;
143  GraphAssemblerLabelType const type_;
144  size_t merged_count_ = 0;
145  Node* effect_;
146  Node* control_;
147  Node* bindings_[VarCount + 1];
148  MachineRepresentation representations_[VarCount + 1];
149 };
150 
152  public:
153  GraphAssembler(JSGraph* jsgraph, Node* effect, Node* control, Zone* zone);
154 
155  void Reset(Node* effect, Node* control);
156 
157  // Create label.
158  template <typename... Reps>
159  static GraphAssemblerLabel<sizeof...(Reps)> MakeLabelFor(
160  GraphAssemblerLabelType type, Reps... reps) {
161  return GraphAssemblerLabel<sizeof...(Reps)>(type, reps...);
162  }
163 
164  // Convenience wrapper for creating non-deferred labels.
165  template <typename... Reps>
166  static GraphAssemblerLabel<sizeof...(Reps)> MakeLabel(Reps... reps) {
167  return MakeLabelFor(GraphAssemblerLabelType::kNonDeferred, reps...);
168  }
169 
170  // Convenience wrapper for creating loop labels.
171  template <typename... Reps>
172  static GraphAssemblerLabel<sizeof...(Reps)> MakeLoopLabel(Reps... reps) {
173  return MakeLabelFor(GraphAssemblerLabelType::kLoop, reps...);
174  }
175 
176  // Convenience wrapper for creating deferred labels.
177  template <typename... Reps>
178  static GraphAssemblerLabel<sizeof...(Reps)> MakeDeferredLabel(Reps... reps) {
179  return MakeLabelFor(GraphAssemblerLabelType::kDeferred, reps...);
180  }
181 
182  // Value creation.
183  Node* IntPtrConstant(intptr_t value);
184  Node* Uint32Constant(int32_t value);
185  Node* Int32Constant(int32_t value);
186  Node* Int64Constant(int64_t value);
187  Node* UniqueIntPtrConstant(intptr_t value);
188  Node* SmiConstant(int32_t value);
189  Node* Float64Constant(double value);
190  Node* Projection(int index, Node* value);
191  Node* HeapConstant(Handle<HeapObject> object);
192  Node* CEntryStubConstant(int result_size);
193  Node* ExternalConstant(ExternalReference ref);
194 
195  Node* LoadFramePointer();
196 
197 #define SINGLETON_CONST_DECL(Name) Node* Name();
198  JSGRAPH_SINGLETON_CONSTANT_LIST(SINGLETON_CONST_DECL)
199 #undef SINGLETON_CONST_DECL
200 
201 #define PURE_UNOP_DECL(Name) Node* Name(Node* input);
202  PURE_ASSEMBLER_MACH_UNOP_LIST(PURE_UNOP_DECL)
203 #undef PURE_UNOP_DECL
204 
205 #define BINOP_DECL(Name) Node* Name(Node* left, Node* right);
206  PURE_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
207  CHECKED_ASSEMBLER_MACH_BINOP_LIST(BINOP_DECL)
208 #undef BINOP_DECL
209 
210  // Debugging
211  Node* DebugBreak();
212 
213  Node* Unreachable();
214 
215  Node* Float64RoundDown(Node* value);
216  Node* Float64RoundTruncate(Node* value);
217 
218  Node* ToNumber(Node* value);
219  Node* BitcastWordToTagged(Node* value);
220  Node* Allocate(PretenureFlag pretenure, Node* size);
221  Node* LoadField(FieldAccess const&, Node* object);
222  Node* LoadElement(ElementAccess const&, Node* object, Node* index);
223  Node* StoreField(FieldAccess const&, Node* object, Node* value);
224  Node* StoreElement(ElementAccess const&, Node* object, Node* index,
225  Node* value);
226 
227  Node* Store(StoreRepresentation rep, Node* object, Node* offset, Node* value);
228  Node* Load(MachineType rep, Node* object, Node* offset);
229 
230  Node* StoreUnaligned(MachineRepresentation rep, Node* object, Node* offset,
231  Node* value);
232  Node* LoadUnaligned(MachineType rep, Node* object, Node* offset);
233 
234  Node* Retain(Node* buffer);
235  Node* UnsafePointerAdd(Node* base, Node* external);
236 
237  Node* Word32PoisonOnSpeculation(Node* value);
238 
239  Node* DeoptimizeIf(
240  DeoptimizeReason reason, VectorSlotPair const& feedback, Node* condition,
241  Node* frame_state,
242  IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
243  Node* DeoptimizeIfNot(
244  DeoptimizeReason reason, VectorSlotPair const& feedback, Node* condition,
245  Node* frame_state,
246  IsSafetyCheck is_safety_check = IsSafetyCheck::kSafetyCheck);
247  template <typename... Args>
248  Node* Call(const CallDescriptor* call_descriptor, Args... args);
249  template <typename... Args>
250  Node* Call(const Operator* op, Args... args);
251 
252  // Basic control operations.
253  template <size_t VarCount>
254  void Bind(GraphAssemblerLabel<VarCount>* label);
255 
256  template <typename... Vars>
257  void Goto(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars...);
258 
259  void Branch(Node* condition, GraphAssemblerLabel<0u>* if_true,
260  GraphAssemblerLabel<0u>* if_false,
261  IsSafetyCheck is_safety_check = IsSafetyCheck::kNoSafetyCheck);
262 
263  // Control helpers.
264  // {GotoIf(c, l)} is equivalent to {Branch(c, l, templ);Bind(templ)}.
265  template <typename... Vars>
266  void GotoIf(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
267  Vars...);
268 
269  // {GotoIfNot(c, l)} is equivalent to {Branch(c, templ, l);Bind(templ)}.
270  template <typename... Vars>
271  void GotoIfNot(Node* condition, GraphAssemblerLabel<sizeof...(Vars)>* label,
272  Vars...);
273 
274  // Extractors (should be only used when destructing/resetting the assembler).
275  Node* ExtractCurrentControl();
276  Node* ExtractCurrentEffect();
277 
278  private:
279  template <typename... Vars>
280  void MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label, Vars... vars);
281 
282  Operator const* ToNumberOperator();
283 
284  JSGraph* jsgraph() const { return jsgraph_; }
285  Isolate* isolate() const { return jsgraph_->isolate(); }
286  Graph* graph() const { return jsgraph_->graph(); }
287  Zone* temp_zone() const { return temp_zone_; }
288  CommonOperatorBuilder* common() const { return jsgraph()->common(); }
289  MachineOperatorBuilder* machine() const { return jsgraph()->machine(); }
290  SimplifiedOperatorBuilder* simplified() const {
291  return jsgraph()->simplified();
292  }
293 
294  SetOncePointer<Operator const> to_number_operator_;
295  Zone* temp_zone_;
296  JSGraph* jsgraph_;
297  Node* current_effect_;
298  Node* current_control_;
299 };
300 
301 template <size_t VarCount>
303  DCHECK(IsBound());
304  DCHECK_LT(index, VarCount);
305  return bindings_[index];
306 }
307 
308 template <typename... Vars>
309 void GraphAssembler::MergeState(GraphAssemblerLabel<sizeof...(Vars)>* label,
310  Vars... vars) {
311  int merged_count = static_cast<int>(label->merged_count_);
312  Node* var_array[] = {nullptr, vars...};
313  if (label->IsLoop()) {
314  if (merged_count == 0) {
315  DCHECK(!label->IsBound());
316  label->control_ = graph()->NewNode(common()->Loop(2), current_control_,
317  current_control_);
318  label->effect_ = graph()->NewNode(common()->EffectPhi(2), current_effect_,
319  current_effect_, label->control_);
320  Node* terminate = graph()->NewNode(common()->Terminate(), label->effect_,
321  label->control_);
322  NodeProperties::MergeControlToEnd(graph(), common(), terminate);
323  for (size_t i = 0; i < sizeof...(vars); i++) {
324  label->bindings_[i] = graph()->NewNode(
325  common()->Phi(label->representations_[i], 2), var_array[i + 1],
326  var_array[i + 1], label->control_);
327  }
328  } else {
329  DCHECK(label->IsBound());
330  DCHECK_EQ(1, merged_count);
331  label->control_->ReplaceInput(1, current_control_);
332  label->effect_->ReplaceInput(1, current_effect_);
333  for (size_t i = 0; i < sizeof...(vars); i++) {
334  label->bindings_[i]->ReplaceInput(1, var_array[i + 1]);
335  }
336  }
337  } else {
338  DCHECK(!label->IsBound());
339  if (merged_count == 0) {
340  // Just set the control, effect and variables directly.
341  DCHECK(!label->IsBound());
342  label->control_ = current_control_;
343  label->effect_ = current_effect_;
344  for (size_t i = 0; i < sizeof...(vars); i++) {
345  label->bindings_[i] = var_array[i + 1];
346  }
347  } else if (merged_count == 1) {
348  // Create merge, effect phi and a phi for each variable.
349  label->control_ = graph()->NewNode(common()->Merge(2), label->control_,
350  current_control_);
351  label->effect_ = graph()->NewNode(common()->EffectPhi(2), label->effect_,
352  current_effect_, label->control_);
353  for (size_t i = 0; i < sizeof...(vars); i++) {
354  label->bindings_[i] = graph()->NewNode(
355  common()->Phi(label->representations_[i], 2), label->bindings_[i],
356  var_array[i + 1], label->control_);
357  }
358  } else {
359  // Append to the merge, effect phi and phis.
360  DCHECK_EQ(IrOpcode::kMerge, label->control_->opcode());
361  label->control_->AppendInput(graph()->zone(), current_control_);
362  NodeProperties::ChangeOp(label->control_,
363  common()->Merge(merged_count + 1));
364 
365  DCHECK_EQ(IrOpcode::kEffectPhi, label->effect_->opcode());
366  label->effect_->ReplaceInput(merged_count, current_effect_);
367  label->effect_->AppendInput(graph()->zone(), label->control_);
368  NodeProperties::ChangeOp(label->effect_,
369  common()->EffectPhi(merged_count + 1));
370 
371  for (size_t i = 0; i < sizeof...(vars); i++) {
372  DCHECK_EQ(IrOpcode::kPhi, label->bindings_[i]->opcode());
373  label->bindings_[i]->ReplaceInput(merged_count, var_array[i + 1]);
374  label->bindings_[i]->AppendInput(graph()->zone(), label->control_);
375  NodeProperties::ChangeOp(
376  label->bindings_[i],
377  common()->Phi(label->representations_[i], merged_count + 1));
378  }
379  }
380  }
381  label->merged_count_++;
382 }
383 
384 template <size_t VarCount>
385 void GraphAssembler::Bind(GraphAssemblerLabel<VarCount>* label) {
386  DCHECK_NULL(current_control_);
387  DCHECK_NULL(current_effect_);
388  DCHECK_LT(0, label->merged_count_);
389 
390  current_control_ = label->control_;
391  current_effect_ = label->effect_;
392 
393  label->SetBound();
394 }
395 
396 template <typename... Vars>
397 void GraphAssembler::Goto(GraphAssemblerLabel<sizeof...(Vars)>* label,
398  Vars... vars) {
399  DCHECK_NOT_NULL(current_control_);
400  DCHECK_NOT_NULL(current_effect_);
401  MergeState(label, vars...);
402  current_control_ = nullptr;
403  current_effect_ = nullptr;
404 }
405 
406 template <typename... Vars>
407 void GraphAssembler::GotoIf(Node* condition,
408  GraphAssemblerLabel<sizeof...(Vars)>* label,
409  Vars... vars) {
410  BranchHint hint =
411  label->IsDeferred() ? BranchHint::kFalse : BranchHint::kNone;
412  Node* branch =
413  graph()->NewNode(common()->Branch(hint), condition, current_control_);
414 
415  current_control_ = graph()->NewNode(common()->IfTrue(), branch);
416  MergeState(label, vars...);
417 
418  current_control_ = graph()->NewNode(common()->IfFalse(), branch);
419 }
420 
421 template <typename... Vars>
422 void GraphAssembler::GotoIfNot(Node* condition,
423  GraphAssemblerLabel<sizeof...(Vars)>* label,
424  Vars... vars) {
425  BranchHint hint = label->IsDeferred() ? BranchHint::kTrue : BranchHint::kNone;
426  Node* branch =
427  graph()->NewNode(common()->Branch(hint), condition, current_control_);
428 
429  current_control_ = graph()->NewNode(common()->IfFalse(), branch);
430  MergeState(label, vars...);
431 
432  current_control_ = graph()->NewNode(common()->IfTrue(), branch);
433 }
434 
435 template <typename... Args>
436 Node* GraphAssembler::Call(const CallDescriptor* call_descriptor,
437  Args... args) {
438  const Operator* op = common()->Call(call_descriptor);
439  return Call(op, args...);
440 }
441 
442 template <typename... Args>
443 Node* GraphAssembler::Call(const Operator* op, Args... args) {
444  DCHECK_EQ(IrOpcode::kCall, op->opcode());
445  Node* args_array[] = {args..., current_effect_, current_control_};
446  int size = static_cast<int>(sizeof...(args)) + op->EffectInputCount() +
447  op->ControlInputCount();
448  Node* call = graph()->NewNode(op, size, args_array);
449  DCHECK_EQ(0, op->ControlOutputCount());
450  current_effect_ = call;
451  return call;
452 }
453 
454 } // namespace compiler
455 } // namespace internal
456 } // namespace v8
457 
458 #endif // V8_COMPILER_GRAPH_ASSEMBLER_H_
Definition: libplatform.h:13