• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,int index)65 Node* NodeProperties::GetFrameStateInput(Node* node, int index) {
66   DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
67   return node->InputAt(FirstFrameStateIndex(node) + index);
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,int index,Node * frame_state)175 void NodeProperties::ReplaceFrameStateInput(Node* node, int index,
176                                             Node* frame_state) {
177   DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
178   node->ReplaceInput(FirstFrameStateIndex(node) + index, frame_state);
179 }
180 
181 
182 // static
RemoveNonValueInputs(Node * node)183 void NodeProperties::RemoveNonValueInputs(Node* node) {
184   node->TrimInputCount(node->op()->ValueInputCount());
185 }
186 
187 
188 // static
RemoveValueInputs(Node * node)189 void NodeProperties::RemoveValueInputs(Node* node) {
190   int value_input_count = node->op()->ValueInputCount();
191   while (--value_input_count >= 0) {
192     node->RemoveInput(value_input_count);
193   }
194 }
195 
196 
MergeControlToEnd(Graph * graph,CommonOperatorBuilder * common,Node * node)197 void NodeProperties::MergeControlToEnd(Graph* graph,
198                                        CommonOperatorBuilder* common,
199                                        Node* node) {
200   graph->end()->AppendInput(graph->zone(), node);
201   graph->end()->set_op(common->End(graph->end()->InputCount()));
202 }
203 
204 
205 // static
ReplaceUses(Node * node,Node * value,Node * effect,Node * success,Node * exception)206 void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect,
207                                  Node* success, Node* exception) {
208   // Requires distinguishing between value, effect and control edges.
209   for (Edge edge : node->use_edges()) {
210     if (IsControlEdge(edge)) {
211       if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
212         DCHECK_NOT_NULL(success);
213         edge.UpdateTo(success);
214       } else if (edge.from()->opcode() == IrOpcode::kIfException) {
215         DCHECK_NOT_NULL(exception);
216         edge.UpdateTo(exception);
217       } else {
218         DCHECK_NOT_NULL(success);
219         edge.UpdateTo(success);
220       }
221     } else if (IsEffectEdge(edge)) {
222       DCHECK_NOT_NULL(effect);
223       edge.UpdateTo(effect);
224     } else {
225       DCHECK_NOT_NULL(value);
226       edge.UpdateTo(value);
227     }
228   }
229 }
230 
231 
232 // static
ChangeOp(Node * node,const Operator * new_op)233 void NodeProperties::ChangeOp(Node* node, const Operator* new_op) {
234   node->set_op(new_op);
235   Verifier::VerifyNode(node);
236 }
237 
238 
239 // static
FindFrameStateBefore(Node * node)240 Node* NodeProperties::FindFrameStateBefore(Node* node) {
241   Node* effect = NodeProperties::GetEffectInput(node);
242   while (effect->opcode() != IrOpcode::kCheckpoint) {
243     if (effect->opcode() == IrOpcode::kDead) return effect;
244     DCHECK_EQ(1, effect->op()->EffectInputCount());
245     effect = NodeProperties::GetEffectInput(effect);
246   }
247   Node* frame_state = GetFrameStateInput(effect, 0);
248   return frame_state;
249 }
250 
251 // static
FindProjection(Node * node,size_t projection_index)252 Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
253   for (auto use : node->uses()) {
254     if (use->opcode() == IrOpcode::kProjection &&
255         ProjectionIndexOf(use->op()) == projection_index) {
256       return use;
257     }
258   }
259   return nullptr;
260 }
261 
262 
263 // static
CollectControlProjections(Node * node,Node ** projections,size_t projection_count)264 void NodeProperties::CollectControlProjections(Node* node, Node** projections,
265                                                size_t projection_count) {
266 #ifdef DEBUG
267   DCHECK_LE(static_cast<int>(projection_count), node->UseCount());
268   std::memset(projections, 0, sizeof(*projections) * projection_count);
269 #endif
270   size_t if_value_index = 0;
271   for (Edge const edge : node->use_edges()) {
272     if (!IsControlEdge(edge)) continue;
273     Node* use = edge.from();
274     size_t index;
275     switch (use->opcode()) {
276       case IrOpcode::kIfTrue:
277         DCHECK_EQ(IrOpcode::kBranch, node->opcode());
278         index = 0;
279         break;
280       case IrOpcode::kIfFalse:
281         DCHECK_EQ(IrOpcode::kBranch, node->opcode());
282         index = 1;
283         break;
284       case IrOpcode::kIfSuccess:
285         DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
286         index = 0;
287         break;
288       case IrOpcode::kIfException:
289         DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
290         index = 1;
291         break;
292       case IrOpcode::kIfValue:
293         DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
294         index = if_value_index++;
295         break;
296       case IrOpcode::kIfDefault:
297         DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
298         index = projection_count - 1;
299         break;
300       default:
301         continue;
302     }
303     DCHECK_LT(if_value_index, projection_count);
304     DCHECK_LT(index, projection_count);
305     DCHECK_NULL(projections[index]);
306     projections[index] = use;
307   }
308 #ifdef DEBUG
309   for (size_t index = 0; index < projection_count; ++index) {
310     DCHECK_NOT_NULL(projections[index]);
311   }
312 #endif
313 }
314 
315 
316 // static
GetSpecializationContext(Node * node,MaybeHandle<Context> context)317 MaybeHandle<Context> NodeProperties::GetSpecializationContext(
318     Node* node, MaybeHandle<Context> context) {
319   switch (node->opcode()) {
320     case IrOpcode::kHeapConstant:
321       return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
322     case IrOpcode::kParameter: {
323       Node* const start = NodeProperties::GetValueInput(node, 0);
324       DCHECK_EQ(IrOpcode::kStart, start->opcode());
325       int const index = ParameterIndexOf(node->op());
326       // The context is always the last parameter to a JavaScript function, and
327       // {Parameter} indices start at -1, so value outputs of {Start} look like
328       // this: closure, receiver, param0, ..., paramN, context.
329       if (index == start->op()->ValueOutputCount() - 2) {
330         return context;
331       }
332       break;
333     }
334     default:
335       break;
336   }
337   return MaybeHandle<Context>();
338 }
339 
340 
341 // static
GetSpecializationNativeContext(Node * node,MaybeHandle<Context> native_context)342 MaybeHandle<Context> NodeProperties::GetSpecializationNativeContext(
343     Node* node, MaybeHandle<Context> native_context) {
344   while (true) {
345     switch (node->opcode()) {
346       case IrOpcode::kJSLoadContext: {
347         ContextAccess const& access = ContextAccessOf(node->op());
348         if (access.index() != Context::NATIVE_CONTEXT_INDEX) {
349           return MaybeHandle<Context>();
350         }
351         // Skip over the intermediate contexts, we're only interested in the
352         // very last context in the context chain anyway.
353         node = NodeProperties::GetContextInput(node);
354         break;
355       }
356       case IrOpcode::kJSCreateBlockContext:
357       case IrOpcode::kJSCreateCatchContext:
358       case IrOpcode::kJSCreateFunctionContext:
359       case IrOpcode::kJSCreateModuleContext:
360       case IrOpcode::kJSCreateScriptContext:
361       case IrOpcode::kJSCreateWithContext: {
362         // Skip over the intermediate contexts, we're only interested in the
363         // very last context in the context chain anyway.
364         node = NodeProperties::GetContextInput(node);
365         break;
366       }
367       case IrOpcode::kHeapConstant: {
368         // Extract the native context from the actual {context}.
369         Handle<Context> context =
370             Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
371         return handle(context->native_context());
372       }
373       case IrOpcode::kOsrValue: {
374         int const index = OpParameter<int>(node);
375         if (index == Linkage::kOsrContextSpillSlotIndex) {
376           return native_context;
377         }
378         return MaybeHandle<Context>();
379       }
380       case IrOpcode::kParameter: {
381         Node* const start = NodeProperties::GetValueInput(node, 0);
382         DCHECK_EQ(IrOpcode::kStart, start->opcode());
383         int const index = ParameterIndexOf(node->op());
384         // The context is always the last parameter to a JavaScript function,
385         // and {Parameter} indices start at -1, so value outputs of {Start}
386         // look like this: closure, receiver, param0, ..., paramN, context.
387         if (index == start->op()->ValueOutputCount() - 2) {
388           return native_context;
389         }
390         return MaybeHandle<Context>();
391       }
392       default:
393         return MaybeHandle<Context>();
394     }
395   }
396 }
397 
398 
399 // static
GetSpecializationGlobalObject(Node * node,MaybeHandle<Context> native_context)400 MaybeHandle<JSGlobalObject> NodeProperties::GetSpecializationGlobalObject(
401     Node* node, MaybeHandle<Context> native_context) {
402   Handle<Context> context;
403   if (GetSpecializationNativeContext(node, native_context).ToHandle(&context)) {
404     return handle(context->global_object());
405   }
406   return MaybeHandle<JSGlobalObject>();
407 }
408 
409 
410 // static
GetTypeOrAny(Node * node)411 Type* NodeProperties::GetTypeOrAny(Node* node) {
412   return IsTyped(node) ? node->type() : Type::Any();
413 }
414 
415 
416 // static
AllValueInputsAreTyped(Node * node)417 bool NodeProperties::AllValueInputsAreTyped(Node* node) {
418   int input_count = node->op()->ValueInputCount();
419   for (int index = 0; index < input_count; ++index) {
420     if (!IsTyped(GetValueInput(node, index))) return false;
421   }
422   return true;
423 }
424 
425 
426 // static
IsInputRange(Edge edge,int first,int num)427 bool NodeProperties::IsInputRange(Edge edge, int first, int num) {
428   if (num == 0) return false;
429   int const index = edge.index();
430   return first <= index && index < first + num;
431 }
432 
433 }  // namespace compiler
434 }  // namespace internal
435 }  // namespace v8
436