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