blob: ac9cc34dd9cd1ac577bf2bdf455e4c6fe3ff1d6a [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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"
Ben Murdoch097c5b22016-05-18 11:27:45 +01007#include "src/compiler/js-operator.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#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"
Ben Murdoch097c5b22016-05-18 11:27:45 +010012#include "src/handles-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013
14namespace v8 {
15namespace internal {
16namespace compiler {
17
18// static
19int NodeProperties::PastValueIndex(Node* node) {
20 return FirstValueIndex(node) + node->op()->ValueInputCount();
21}
22
23
24// static
25int NodeProperties::PastContextIndex(Node* node) {
26 return FirstContextIndex(node) +
27 OperatorProperties::GetContextInputCount(node->op());
28}
29
30
31// static
32int NodeProperties::PastFrameStateIndex(Node* node) {
33 return FirstFrameStateIndex(node) +
34 OperatorProperties::GetFrameStateInputCount(node->op());
35}
36
37
38// static
39int NodeProperties::PastEffectIndex(Node* node) {
40 return FirstEffectIndex(node) + node->op()->EffectInputCount();
41}
42
43
44// static
45int NodeProperties::PastControlIndex(Node* node) {
46 return FirstControlIndex(node) + node->op()->ControlInputCount();
47}
48
49
50// static
51Node* 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
58Node* NodeProperties::GetContextInput(Node* node) {
59 DCHECK(OperatorProperties::HasContextInput(node->op()));
60 return node->InputAt(FirstContextIndex(node));
61}
62
63
64// static
65Node* 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
72Node* 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
79Node* 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
86bool 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
94bool 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
102bool 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
110bool 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
118bool 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
126bool NodeProperties::IsExceptionalCall(Node* node) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100127 if (node->op()->HasProperty(Operator::kNoThrow)) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000128 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
137void 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
144void 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
155void NodeProperties::ReplaceContextInput(Node* node, Node* context) {
156 node->ReplaceInput(FirstContextIndex(node), context);
157}
158
159
160// static
161void NodeProperties::ReplaceControlInput(Node* node, Node* control) {
162 node->ReplaceInput(FirstControlIndex(node), control);
163}
164
165
166// static
167void NodeProperties::ReplaceEffectInput(Node* node, Node* effect, int index) {
168 DCHECK(index < node->op()->EffectInputCount());
169 return node->ReplaceInput(FirstEffectIndex(node) + index, effect);
170}
171
172
173// static
174void NodeProperties::ReplaceFrameStateInput(Node* node, int index,
175 Node* frame_state) {
176 DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
177 node->ReplaceInput(FirstFrameStateIndex(node) + index, frame_state);
178}
179
180
181// static
182void NodeProperties::RemoveFrameStateInput(Node* node, int index) {
183 DCHECK_LT(index, OperatorProperties::GetFrameStateInputCount(node->op()));
184 node->RemoveInput(FirstFrameStateIndex(node) + index);
185}
186
187
188// static
189void NodeProperties::RemoveNonValueInputs(Node* node) {
190 node->TrimInputCount(node->op()->ValueInputCount());
191}
192
193
194// static
195void NodeProperties::RemoveValueInputs(Node* node) {
196 int value_input_count = node->op()->ValueInputCount();
197 while (--value_input_count >= 0) {
198 node->RemoveInput(value_input_count);
199 }
200}
201
202
203void NodeProperties::MergeControlToEnd(Graph* graph,
204 CommonOperatorBuilder* common,
205 Node* node) {
206 graph->end()->AppendInput(graph->zone(), node);
207 graph->end()->set_op(common->End(graph->end()->InputCount()));
208}
209
210
211// static
212void NodeProperties::ReplaceUses(Node* node, Node* value, Node* effect,
213 Node* success, Node* exception) {
214 // Requires distinguishing between value, effect and control edges.
215 for (Edge edge : node->use_edges()) {
216 if (IsControlEdge(edge)) {
217 if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
218 DCHECK_NOT_NULL(success);
219 edge.UpdateTo(success);
220 } else if (edge.from()->opcode() == IrOpcode::kIfException) {
221 DCHECK_NOT_NULL(exception);
222 edge.UpdateTo(exception);
223 } else {
224 UNREACHABLE();
225 }
226 } else if (IsEffectEdge(edge)) {
227 DCHECK_NOT_NULL(effect);
228 edge.UpdateTo(effect);
229 } else {
230 DCHECK_NOT_NULL(value);
231 edge.UpdateTo(value);
232 }
233 }
234}
235
236
237// static
238void NodeProperties::ChangeOp(Node* node, const Operator* new_op) {
239 node->set_op(new_op);
240 Verifier::VerifyNode(node);
241}
242
243
244// static
245Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
246 for (auto use : node->uses()) {
247 if (use->opcode() == IrOpcode::kProjection &&
248 ProjectionIndexOf(use->op()) == projection_index) {
249 return use;
250 }
251 }
252 return nullptr;
253}
254
255
256// static
257void NodeProperties::CollectControlProjections(Node* node, Node** projections,
258 size_t projection_count) {
259#ifdef DEBUG
260 DCHECK_LE(static_cast<int>(projection_count), node->UseCount());
261 std::memset(projections, 0, sizeof(*projections) * projection_count);
262#endif
263 size_t if_value_index = 0;
264 for (Edge const edge : node->use_edges()) {
265 if (!IsControlEdge(edge)) continue;
266 Node* use = edge.from();
267 size_t index;
268 switch (use->opcode()) {
269 case IrOpcode::kIfTrue:
270 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
271 index = 0;
272 break;
273 case IrOpcode::kIfFalse:
274 DCHECK_EQ(IrOpcode::kBranch, node->opcode());
275 index = 1;
276 break;
277 case IrOpcode::kIfSuccess:
278 DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
279 index = 0;
280 break;
281 case IrOpcode::kIfException:
282 DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
283 index = 1;
284 break;
285 case IrOpcode::kIfValue:
286 DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
287 index = if_value_index++;
288 break;
289 case IrOpcode::kIfDefault:
290 DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
291 index = projection_count - 1;
292 break;
293 default:
294 continue;
295 }
296 DCHECK_LT(if_value_index, projection_count);
297 DCHECK_LT(index, projection_count);
298 DCHECK_NULL(projections[index]);
299 projections[index] = use;
300 }
301#ifdef DEBUG
302 for (size_t index = 0; index < projection_count; ++index) {
303 DCHECK_NOT_NULL(projections[index]);
304 }
305#endif
306}
307
308
309// static
310MaybeHandle<Context> NodeProperties::GetSpecializationContext(
311 Node* node, MaybeHandle<Context> context) {
312 switch (node->opcode()) {
313 case IrOpcode::kHeapConstant:
314 return Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
315 case IrOpcode::kParameter: {
316 Node* const start = NodeProperties::GetValueInput(node, 0);
317 DCHECK_EQ(IrOpcode::kStart, start->opcode());
318 int const index = ParameterIndexOf(node->op());
319 // The context is always the last parameter to a JavaScript function, and
320 // {Parameter} indices start at -1, so value outputs of {Start} look like
321 // this: closure, receiver, param0, ..., paramN, context.
322 if (index == start->op()->ValueOutputCount() - 2) {
323 return context;
324 }
325 break;
326 }
327 default:
328 break;
329 }
330 return MaybeHandle<Context>();
331}
332
333
334// static
335MaybeHandle<Context> NodeProperties::GetSpecializationNativeContext(
336 Node* node, MaybeHandle<Context> native_context) {
337 while (true) {
338 switch (node->opcode()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100339 case IrOpcode::kJSLoadContext: {
340 ContextAccess const& access = ContextAccessOf(node->op());
341 if (access.index() != Context::NATIVE_CONTEXT_INDEX) {
342 return MaybeHandle<Context>();
343 }
344 // Skip over the intermediate contexts, we're only interested in the
345 // very last context in the context chain anyway.
346 node = NodeProperties::GetContextInput(node);
347 break;
348 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349 case IrOpcode::kJSCreateBlockContext:
350 case IrOpcode::kJSCreateCatchContext:
351 case IrOpcode::kJSCreateFunctionContext:
352 case IrOpcode::kJSCreateModuleContext:
353 case IrOpcode::kJSCreateScriptContext:
354 case IrOpcode::kJSCreateWithContext: {
355 // Skip over the intermediate contexts, we're only interested in the
356 // very last context in the context chain anyway.
357 node = NodeProperties::GetContextInput(node);
358 break;
359 }
360 case IrOpcode::kHeapConstant: {
361 // Extract the native context from the actual {context}.
362 Handle<Context> context =
363 Handle<Context>::cast(OpParameter<Handle<HeapObject>>(node));
364 return handle(context->native_context());
365 }
366 case IrOpcode::kOsrValue: {
367 int const index = OpParameter<int>(node);
368 if (index == Linkage::kOsrContextSpillSlotIndex) {
369 return native_context;
370 }
371 return MaybeHandle<Context>();
372 }
373 case IrOpcode::kParameter: {
374 Node* const start = NodeProperties::GetValueInput(node, 0);
375 DCHECK_EQ(IrOpcode::kStart, start->opcode());
376 int const index = ParameterIndexOf(node->op());
377 // The context is always the last parameter to a JavaScript function,
378 // and {Parameter} indices start at -1, so value outputs of {Start}
379 // look like this: closure, receiver, param0, ..., paramN, context.
380 if (index == start->op()->ValueOutputCount() - 2) {
381 return native_context;
382 }
383 return MaybeHandle<Context>();
384 }
385 default:
386 return MaybeHandle<Context>();
387 }
388 }
389}
390
391
392// static
393MaybeHandle<JSGlobalObject> NodeProperties::GetSpecializationGlobalObject(
394 Node* node, MaybeHandle<Context> native_context) {
395 Handle<Context> context;
396 if (GetSpecializationNativeContext(node, native_context).ToHandle(&context)) {
397 return handle(context->global_object());
398 }
399 return MaybeHandle<JSGlobalObject>();
400}
401
402
403// static
404Type* NodeProperties::GetTypeOrAny(Node* node) {
405 return IsTyped(node) ? node->type() : Type::Any();
406}
407
408
409// static
410bool NodeProperties::AllValueInputsAreTyped(Node* node) {
411 int input_count = node->op()->ValueInputCount();
412 for (int index = 0; index < input_count; ++index) {
413 if (!IsTyped(GetValueInput(node, index))) return false;
414 }
415 return true;
416}
417
418
419// static
420bool NodeProperties::IsInputRange(Edge edge, int first, int num) {
421 if (num == 0) return false;
422 int const index = edge.index();
423 return first <= index && index < first + num;
424}
425
426} // namespace compiler
427} // namespace internal
428} // namespace v8