1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/common-operator.h"
6 #include "src/compiler/graph.h"
7 #include "src/compiler/js-operator.h"
8 #include "src/compiler/linkage.h"
9 #include "src/compiler/node-properties.h"
10 #include "src/compiler/operator-properties.h"
11 #include "src/compiler/verifier.h"
12 #include "src/handles-inl.h"
13 
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17 
18 // static
PastValueIndex(Node * node)19 int NodeProperties::PastValueIndex(Node* node) {
20   return FirstValueIndex(node) + node->op()->ValueInputCount();
21 }
22 
23 
24 // static
PastContextIndex(Node * node)25 int NodeProperties::PastContextIndex(Node* node) {
26   return FirstContextIndex(node) +
27          OperatorProperties::GetContextInputCount(node->op());
28 }
29 
30 
31 // static
PastFrameStateIndex(Node * node)32 int NodeProperties::PastFrameStateIndex(Node* node) {
33   return FirstFrameStateIndex(node) +
34          OperatorProperties::GetFrameStateInputCount(node->op());
35 }
36 
37 
38 // static
PastEffectIndex(Node * node)39 int NodeProperties::PastEffectIndex(Node* node) {
40   return FirstEffectIndex(node) + node->op()->EffectInputCount();
41 }
42 
43 
44 // static
PastControlIndex(Node * node)45 int NodeProperties::PastControlIndex(Node* node) {
46   return FirstControlIndex(node) + node->op()->ControlInputCount();
47 }
48 
49 
50 // static
GetValueInput(Node * node,int index)51 Node* NodeProperties::GetValueInput(Node* node, int index) {
52   DCHECK(0 <= index && index < node->op()->ValueInputCount());
53   return node->InputAt(FirstValueIndex(node) + index);
54 }
55 
56 
57 // static
GetContextInput(Node * node)58 Node* NodeProperties::GetContextInput(Node* node) {
59   DCHECK(OperatorProperties::HasContextInput(node->op()));
60   return node->InputAt(FirstContextIndex(node));
61 }
62 
63 
64 // static
GetFrameStateInput(Node * node)65 Node* NodeProperties::GetFrameStateInput(Node* node) {
66   DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
67   return node->InputAt(FirstFrameStateIndex(node));
68 }
69 
70 
71 // static
GetEffectInput(Node * node,int index)72 Node* NodeProperties::GetEffectInput(Node* node, int index) {
73   DCHECK(0 <= index && index < node->op()->EffectInputCount());
74   return node->InputAt(FirstEffectIndex(node) + index);
75 }
76 
77 
78 // static
GetControlInput(Node * node,int index)79 Node* NodeProperties::GetControlInput(Node* node, int index) {
80   DCHECK(0 <= index && index < node->op()->ControlInputCount());
81   return node->InputAt(FirstControlIndex(node) + index);
82 }
83 
84 
85 // static
IsValueEdge(Edge edge)86 bool NodeProperties::IsValueEdge(Edge edge) {
87   Node* const node = edge.from();
88   return IsInputRange(edge, FirstValueIndex(node),
89                       node->op()->ValueInputCount());
90 }
91 
92 
93 // static
IsContextEdge(Edge edge)94 bool NodeProperties::IsContextEdge(Edge edge) {
95   Node* const node = edge.from();
96   return IsInputRange(edge, FirstContextIndex(node),
97                       OperatorProperties::GetContextInputCount(node->op()));
98 }
99 
100 
101 // static
IsFrameStateEdge(Edge edge)102 bool NodeProperties::IsFrameStateEdge(Edge edge) {
103   Node* const node = edge.from();
104   return IsInputRange(edge, FirstFrameStateIndex(node),
105                       OperatorProperties::GetFrameStateInputCount(node->op()));
106 }
107 
108 
109 // static
IsEffectEdge(Edge edge)110 bool NodeProperties::IsEffectEdge(Edge edge) {
111   Node* const node = edge.from();
112   return IsInputRange(edge, FirstEffectIndex(node),
113                       node->op()->EffectInputCount());
114 }
115 
116 
117 // static
IsControlEdge(Edge edge)118 bool NodeProperties::IsControlEdge(Edge edge) {
119   Node* const node = edge.from();
120   return IsInputRange(edge, FirstControlIndex(node),
121                       node->op()->ControlInputCount());
122 }
123 
124 
125 // static
IsExceptionalCall(Node * node)126 bool NodeProperties::IsExceptionalCall(Node* node) {
127   if (node->op()->HasProperty(Operator::kNoThrow)) return false;
128   for (Edge const edge : node->use_edges()) {
129     if (!NodeProperties::IsControlEdge(edge)) continue;
130     if (edge.from()->opcode() == IrOpcode::kIfException) return true;
131   }
132   return false;
133 }
134 
135 
136 // static
ReplaceValueInput(Node * node,Node * value,int index)137 void NodeProperties::ReplaceValueInput(Node* node, Node* value, int index) {
138   DCHECK(index < node->op()->ValueInputCount());
139   node->ReplaceInput(FirstValueIndex(node) + index, value);
140 }
141 
142 
143 // static
ReplaceValueInputs(Node * node,Node * value)144 void NodeProperties::ReplaceValueInputs(Node* node, Node* value) {
145   int value_input_count = node->op()->ValueInputCount();
146   DCHECK_LE(1, value_input_count);
147   node->ReplaceInput(0, value);
148   while (--value_input_count > 0) {
149     node->RemoveInput(value_input_count);
150   }
151 }
152 
153 
154 // static
ReplaceContextInput(Node * node,Node * context)155 void NodeProperties::ReplaceContextInput(Node* node, Node* context) {
156   node->ReplaceInput(FirstContextIndex(node), context);
157 }
158 
159 
160 // static
ReplaceControlInput(Node * node,Node * control,int index)161 void NodeProperties::ReplaceControlInput(Node* node, Node* control, int index) {
162   DCHECK(index < node->op()->ControlInputCount());
163   node->ReplaceInput(FirstControlIndex(node) + index, control);
164 }
165 
166 
167 // static
ReplaceEffectInput(Node * node,Node * effect,int index)168 void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) {
169   DCHECK(index < node->op()->EffectInputCount());
170   return node->ReplaceInput(FirstEffectIndex(node) + index, effect);
171 }
172 
173 
174 // static
ReplaceFrameStateInput(Node * node,Node * frame_state)175 void NodeProperties::ReplaceFrameStateInput(Node* node, Node* frame_state) {
176   DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
177   node->ReplaceInput(FirstFrameStateIndex(node), frame_state);
178 }
179 
180 
181 // static
RemoveNonValueInputs(Node * node)182 void NodeProperties::RemoveNonValueInputs(Node* node) {
183   node->TrimInputCount(node->op()->ValueInputCount());
184 }
185 
186 
187 // static
RemoveValueInputs(Node * node)188 void NodeProperties::RemoveValueInputs(Node* node) {
189   int value_input_count = node->op()->ValueInputCount();
190   while (--value_input_count >= 0) {
191     node->RemoveInput(value_input_count);
192   }
193 }
194 
195 
MergeControlToEnd(Graph * graph,CommonOperatorBuilder * common,Node * node)196 void NodeProperties::MergeControlToEnd(Graph* graph,
197                                        CommonOperatorBuilder* common,
198                                        Node* node) {
199   graph->end()->AppendInput(graph->zone(), node);
200   graph->end()->set_op(common->End(graph->end()->InputCount()));
201 }
202 
203 
204 // static
ReplaceUses(Node * node,Node * value,Node * effect,Node * success,Node * exception)205 void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect,
206                                  Node* success, Node* exception) {
207   // Requires distinguishing between value, effect and control edges.
208   for (Edge edge : node->use_edges()) {
209     if (IsControlEdge(edge)) {
210       if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
211         DCHECK_NOT_NULL(success);
212         edge.UpdateTo(success);
213       } else if (edge.from()->opcode() == IrOpcode::kIfException) {
214         DCHECK_NOT_NULL(exception);
215         edge.UpdateTo(exception);
216       } else {
217         DCHECK_NOT_NULL(success);
218         edge.UpdateTo(success);
219       }
220     } else if (IsEffectEdge(edge)) {
221       DCHECK_NOT_NULL(effect);
222       edge.UpdateTo(effect);
223     } else {
224       DCHECK_NOT_NULL(value);
225       edge.UpdateTo(value);
226     }
227   }
228 }
229 
230 
231 // static
ChangeOp(Node * node,const Operator * new_op)232 void NodeProperties::ChangeOp(Node* node, const Operator* new_op) {
233   node->set_op(new_op);
234   Verifier::VerifyNode(node);
235 }
236 
237 
238 // static
FindFrameStateBefore(Node * node)239 Node* NodeProperties::FindFrameStateBefore(Node* node) {
240   Node* effect = NodeProperties::GetEffectInput(node);
241   while (effect->opcode() != IrOpcode::kCheckpoint) {
242     if (effect->opcode() == IrOpcode::kDead) return effect;
243     DCHECK_EQ(1, effect->op()->EffectInputCount());
244     effect = NodeProperties::GetEffectInput(effect);
245   }
246   Node* frame_state = GetFrameStateInput(effect);
247   return frame_state;
248 }
249 
250 // static
FindProjection(Node * node,size_t projection_index)251 Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
252   for (auto use : node->uses()) {
253     if (use->opcode() == IrOpcode::kProjection &&
254         ProjectionIndexOf(use->op()) == projection_index) {
255       return use;
256     }
257   }
258   return nullptr;
259 }
260 
261 
262 // static
CollectControlProjections(Node * node,Node ** projections,size_t projection_count)263 void NodeProperties::CollectControlProjections(Node* node, Node** projections,
264                                                size_t projection_count) {
265 #ifdef DEBUG
266   DCHECK_LE(static_cast<int>(projection_count), node->UseCount());
267   std::memset(projections, 0, sizeof(*projections) * projection_count);
268 #endif
269   size_t if_value_index = 0;
270   for (Edge const edge : node->use_edges()) {
271     if (!IsControlEdge(edge)) continue;
272     Node* use = edge.from();
273     size_t index;
274     switch (use->opcode()) {
275       case IrOpcode::kIfTrue:
276         DCHECK_EQ(IrOpcode::kBranch, node->opcode());
277         index = 0;
278         break;
279       case IrOpcode::kIfFalse:
280         DCHECK_EQ(IrOpcode::kBranch, node->opcode());
281         index = 1;
282         break;
283       case IrOpcode::kIfSuccess:
284         DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
285         index = 0;
286         break;
287       case IrOpcode::kIfException:
288         DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
289         index = 1;
290         break;
291       case IrOpcode::kIfValue:
292         DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
293         index = if_value_index++;
294         break;
295       case IrOpcode::kIfDefault:
296         DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
297         index = projection_count - 1;
298         break;
299       default:
300         continue;
301     }
302     DCHECK_LT(if_value_index, projection_count);
303     DCHECK_LT(index, projection_count);
304     DCHECK_NULL(projections[index]);
305     projections[index] = use;
306   }
307 #ifdef DEBUG
308   for (size_t index = 0; index < projection_count; ++index) {
309     DCHECK_NOT_NULL(projections[index]);
310   }
311 #endif
312 }
313 
314 
315 // static
GetSpecializationContext(Node * node,MaybeHandle<Context> context)316 MaybeHandle<Context> NodeProperties::GetSpecializationContext(
317     Node* node, MaybeHandle<Context> context) {
318   switch (node->opcode()) {
319     case IrOpcode::kHeapConstant:
320       return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
321     case IrOpcode::kParameter: {
322       Node* const start = NodeProperties::GetValueInput(node, 0);
323       DCHECK_EQ(IrOpcode::kStart, start->opcode());
324       int const index = ParameterIndexOf(node->op());
325       // The context is always the last parameter to a JavaScript function, and
326       // {Parameter} indices start at -1, so value outputs of {Start} look like
327       // this: closure, receiver, param0, ..., paramN, context.
328       if (index == start->op()->ValueOutputCount() - 2) {
329         return context;
330       }
331       break;
332     }
333     default:
334       break;
335   }
336   return MaybeHandle<Context>();
337 }
338 
339 
340 // static
GetTypeOrAny(Node * node)341 Type* NodeProperties::GetTypeOrAny(Node* node) {
342   return IsTyped(node) ? node->type() : Type::Any();
343 }
344 
345 
346 // static
AllValueInputsAreTyped(Node * node)347 bool NodeProperties::AllValueInputsAreTyped(Node* node) {
348   int input_count = node->op()->ValueInputCount();
349   for (int index = 0; index < input_count; ++index) {
350     if (!IsTyped(GetValueInput(node, index))) return false;
351   }
352   return true;
353 }
354 
355 
356 // static
IsInputRange(Edge edge,int first,int num)357 bool NodeProperties::IsInputRange(Edge edge, int first, int num) {
358   if (num == 0) return false;
359   int const index = edge.index();
360   return first <= index && index < first + num;
361 }
362 
363 }  // namespace compiler
364 }  // namespace internal
365 }  // namespace v8
366