blob: a15d6fd6fdd29aa42fdae6c69eabd9d147f214c6 [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/js-call-reducer.h"
6
7#include "src/compiler/js-graph.h"
8#include "src/compiler/node-matchers.h"
9#include "src/objects-inl.h"
10#include "src/type-feedback-vector-inl.h"
11
12namespace v8 {
13namespace internal {
14namespace compiler {
15
16namespace {
17
18VectorSlotPair CallCountFeedback(VectorSlotPair p) {
19 // Extract call count from {p}.
20 if (!p.IsValid()) return VectorSlotPair();
21 CallICNexus n(p.vector(), p.slot());
22 int const call_count = n.ExtractCallCount();
23 if (call_count <= 0) return VectorSlotPair();
24
25 // Create megamorphic CallIC feedback with the given {call_count}.
26 StaticFeedbackVectorSpec spec;
27 FeedbackVectorSlot slot = spec.AddCallICSlot();
28 Handle<TypeFeedbackMetadata> metadata =
29 TypeFeedbackMetadata::New(n.GetIsolate(), &spec);
30 Handle<TypeFeedbackVector> vector =
31 TypeFeedbackVector::New(n.GetIsolate(), metadata);
32 CallICNexus nexus(vector, slot);
33 nexus.ConfigureMegamorphic(call_count);
34 return VectorSlotPair(vector, slot);
35}
36
37} // namespace
38
39
40Reduction JSCallReducer::Reduce(Node* node) {
41 switch (node->opcode()) {
42 case IrOpcode::kJSCallConstruct:
43 return ReduceJSCallConstruct(node);
44 case IrOpcode::kJSCallFunction:
45 return ReduceJSCallFunction(node);
46 default:
47 break;
48 }
49 return NoChange();
50}
51
52
53// ES6 section 22.1.1 The Array Constructor
54Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
55 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
56 Node* target = NodeProperties::GetValueInput(node, 0);
57 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
58
59 // Check if we have an allocation site from the CallIC.
60 Handle<AllocationSite> site;
61 if (p.feedback().IsValid()) {
62 CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
63 Handle<Object> feedback(nexus.GetFeedback(), isolate());
64 if (feedback->IsAllocationSite()) {
65 site = Handle<AllocationSite>::cast(feedback);
66 }
67 }
68
69 // Turn the {node} into a {JSCreateArray} call.
70 DCHECK_LE(2u, p.arity());
71 size_t const arity = p.arity() - 2;
72 NodeProperties::ReplaceValueInput(node, target, 0);
73 NodeProperties::ReplaceValueInput(node, target, 1);
74 NodeProperties::RemoveFrameStateInput(node, 1);
75 // TODO(bmeurer): We might need to propagate the tail call mode to
76 // the JSCreateArray operator, because an Array call in tail call
77 // position must always properly consume the parent stack frame.
78 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
79 return Changed(node);
80}
81
82
83// ES6 section 20.1.1 The Number Constructor
84Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
85 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
86 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
87
88 // Turn the {node} into a {JSToNumber} call.
89 DCHECK_LE(2u, p.arity());
90 Node* value = (p.arity() == 2) ? jsgraph()->ZeroConstant()
91 : NodeProperties::GetValueInput(node, 2);
92 NodeProperties::RemoveFrameStateInput(node, 1);
93 NodeProperties::ReplaceValueInputs(node, value);
94 NodeProperties::ChangeOp(node, javascript()->ToNumber());
95 return Changed(node);
96}
97
98
99// ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
100Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
101 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
102 Node* target = NodeProperties::GetValueInput(node, 0);
103 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
104 Handle<JSFunction> apply =
105 Handle<JSFunction>::cast(HeapObjectMatcher(target).Value());
106 size_t arity = p.arity();
107 DCHECK_LE(2u, arity);
108 ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
109 if (arity == 2) {
110 // Neither thisArg nor argArray was provided.
111 convert_mode = ConvertReceiverMode::kNullOrUndefined;
112 node->ReplaceInput(0, node->InputAt(1));
113 node->ReplaceInput(1, jsgraph()->UndefinedConstant());
114 } else if (arity == 3) {
115 // The argArray was not provided, just remove the {target}.
116 node->RemoveInput(0);
117 --arity;
118 } else if (arity == 4) {
119 // Check if argArray is an arguments object, and {node} is the only value
120 // user of argArray (except for value uses in frame states).
121 Node* arg_array = NodeProperties::GetValueInput(node, 3);
122 if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
123 for (Edge edge : arg_array->use_edges()) {
124 if (edge.from()->opcode() == IrOpcode::kStateValues) continue;
125 if (!NodeProperties::IsValueEdge(edge)) continue;
126 if (edge.from() == node) continue;
127 return NoChange();
128 }
129 // Get to the actual frame state from which to extract the arguments;
130 // we can only optimize this in case the {node} was already inlined into
131 // some other function (and same for the {arg_array}).
132 CreateArgumentsParameters const& p =
133 CreateArgumentsParametersOf(arg_array->op());
134 Node* frame_state = NodeProperties::GetFrameStateInput(arg_array, 0);
135 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
136 if (outer_state->opcode() != IrOpcode::kFrameState) return NoChange();
137 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
138 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
139 // Need to take the parameters from the arguments adaptor.
140 frame_state = outer_state;
141 }
142 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
143 if (p.type() == CreateArgumentsParameters::kMappedArguments) {
144 // Mapped arguments (sloppy mode) cannot be handled if they are aliased.
145 Handle<SharedFunctionInfo> shared;
146 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
147 if (shared->internal_formal_parameter_count() != 0) return NoChange();
148 }
149 // Remove the argArray input from the {node}.
150 node->RemoveInput(static_cast<int>(--arity));
151 // Add the actual parameters to the {node}, skipping the receiver.
152 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
153 for (int i = p.start_index() + 1; i < state_info.parameter_count(); ++i) {
154 node->InsertInput(graph()->zone(), static_cast<int>(arity),
155 parameters->InputAt(i));
156 ++arity;
157 }
158 // Drop the {target} from the {node}.
159 node->RemoveInput(0);
160 --arity;
161 } else {
162 return NoChange();
163 }
164 // Change {node} to the new {JSCallFunction} operator.
165 NodeProperties::ChangeOp(
166 node, javascript()->CallFunction(arity, p.language_mode(),
167 CallCountFeedback(p.feedback()),
168 convert_mode, p.tail_call_mode()));
169 // Change context of {node} to the Function.prototype.apply context,
170 // to ensure any exception is thrown in the correct context.
171 NodeProperties::ReplaceContextInput(
172 node, jsgraph()->HeapConstant(handle(apply->context(), isolate())));
173 // Try to further reduce the JSCallFunction {node}.
174 Reduction const reduction = ReduceJSCallFunction(node);
175 return reduction.Changed() ? reduction : Changed(node);
176}
177
178
179// ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
180Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
181 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
182 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
183 Handle<JSFunction> call = Handle<JSFunction>::cast(
184 HeapObjectMatcher(NodeProperties::GetValueInput(node, 0)).Value());
185 // Change context of {node} to the Function.prototype.call context,
186 // to ensure any exception is thrown in the correct context.
187 NodeProperties::ReplaceContextInput(
188 node, jsgraph()->HeapConstant(handle(call->context(), isolate())));
189 // Remove the target from {node} and use the receiver as target instead, and
190 // the thisArg becomes the new target. If thisArg was not provided, insert
191 // undefined instead.
192 size_t arity = p.arity();
193 DCHECK_LE(2u, arity);
194 ConvertReceiverMode convert_mode;
195 if (arity == 2) {
196 // The thisArg was not provided, use undefined as receiver.
197 convert_mode = ConvertReceiverMode::kNullOrUndefined;
198 node->ReplaceInput(0, node->InputAt(1));
199 node->ReplaceInput(1, jsgraph()->UndefinedConstant());
200 } else {
201 // Just remove the target, which is the first value input.
202 convert_mode = ConvertReceiverMode::kAny;
203 node->RemoveInput(0);
204 --arity;
205 }
206 NodeProperties::ChangeOp(
207 node, javascript()->CallFunction(arity, p.language_mode(),
208 CallCountFeedback(p.feedback()),
209 convert_mode, p.tail_call_mode()));
210 // Try to further reduce the JSCallFunction {node}.
211 Reduction const reduction = ReduceJSCallFunction(node);
212 return reduction.Changed() ? reduction : Changed(node);
213}
214
215
216Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
217 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
218 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
219 Node* target = NodeProperties::GetValueInput(node, 0);
220 Node* context = NodeProperties::GetContextInput(node);
221 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
222 Node* control = NodeProperties::GetControlInput(node);
223 Node* effect = NodeProperties::GetEffectInput(node);
224
225 // Try to specialize JSCallFunction {node}s with constant {target}s.
226 HeapObjectMatcher m(target);
227 if (m.HasValue()) {
228 if (m.Value()->IsJSFunction()) {
229 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
230 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
231
232 // Raise a TypeError if the {target} is a "classConstructor".
233 if (IsClassConstructor(shared->kind())) {
234 NodeProperties::RemoveFrameStateInput(node, 0);
235 NodeProperties::ReplaceValueInputs(node, target);
236 NodeProperties::ChangeOp(
237 node, javascript()->CallRuntime(
238 Runtime::kThrowConstructorNonCallableError, 1));
239 return Changed(node);
240 }
241
242 // Check for known builtin functions.
243 if (shared->HasBuiltinFunctionId()) {
244 switch (shared->builtin_function_id()) {
245 case kFunctionApply:
246 return ReduceFunctionPrototypeApply(node);
247 case kFunctionCall:
248 return ReduceFunctionPrototypeCall(node);
249 default:
250 break;
251 }
252 }
253
254 // Check for the Array constructor.
255 if (*function == function->native_context()->array_function()) {
256 return ReduceArrayConstructor(node);
257 }
258
259 // Check for the Number constructor.
260 if (*function == function->native_context()->number_function()) {
261 return ReduceNumberConstructor(node);
262 }
263 } else if (m.Value()->IsJSBoundFunction()) {
264 Handle<JSBoundFunction> function =
265 Handle<JSBoundFunction>::cast(m.Value());
266 Handle<JSReceiver> bound_target_function(
267 function->bound_target_function(), isolate());
268 Handle<Object> bound_this(function->bound_this(), isolate());
269 Handle<FixedArray> bound_arguments(function->bound_arguments(),
270 isolate());
271 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
272 ConvertReceiverMode const convert_mode =
273 (bound_this->IsNull() || bound_this->IsUndefined())
274 ? ConvertReceiverMode::kNullOrUndefined
275 : ConvertReceiverMode::kNotNullOrUndefined;
276 size_t arity = p.arity();
277 DCHECK_LE(2u, arity);
278 // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
279 NodeProperties::ReplaceValueInput(
280 node, jsgraph()->Constant(bound_target_function), 0);
281 NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
282 1);
283 // Insert the [[BoundArguments]] for {node}.
284 for (int i = 0; i < bound_arguments->length(); ++i) {
285 node->InsertInput(
286 graph()->zone(), i + 2,
287 jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
288 arity++;
289 }
290 NodeProperties::ChangeOp(
291 node, javascript()->CallFunction(arity, p.language_mode(),
292 CallCountFeedback(p.feedback()),
293 convert_mode, p.tail_call_mode()));
294 // Try to further reduce the JSCallFunction {node}.
295 Reduction const reduction = ReduceJSCallFunction(node);
296 return reduction.Changed() ? reduction : Changed(node);
297 }
298
299 // Don't mess with other {node}s that have a constant {target}.
300 // TODO(bmeurer): Also support proxies here.
301 return NoChange();
302 }
303
304 // Not much we can do if deoptimization support is disabled.
305 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
306
307 // Extract feedback from the {node} using the CallICNexus.
308 if (!p.feedback().IsValid()) return NoChange();
309 CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
310 Handle<Object> feedback(nexus.GetFeedback(), isolate());
311 if (feedback->IsAllocationSite()) {
312 // Retrieve the Array function from the {node}.
313 Node* array_function;
314 Handle<Context> native_context;
315 if (GetNativeContext(node).ToHandle(&native_context)) {
316 array_function = jsgraph()->HeapConstant(
317 handle(native_context->array_function(), isolate()));
318 } else {
319 Node* native_context = effect = graph()->NewNode(
320 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
321 context, context, effect);
322 array_function = effect = graph()->NewNode(
323 javascript()->LoadContext(0, Context::ARRAY_FUNCTION_INDEX, true),
324 native_context, native_context, effect);
325 }
326
327 // Check that the {target} is still the {array_function}.
328 Node* check = effect =
329 graph()->NewNode(javascript()->StrictEqual(), target, array_function,
330 context, effect, control);
331 Node* branch =
332 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
333 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
334 Node* deoptimize =
335 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
336 frame_state, effect, if_false);
337 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
338 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
339 control = graph()->NewNode(common()->IfTrue(), branch);
340
341 // Turn the {node} into a {JSCreateArray} call.
342 NodeProperties::ReplaceValueInput(node, array_function, 0);
343 NodeProperties::ReplaceEffectInput(node, effect);
344 NodeProperties::ReplaceControlInput(node, control);
345 return ReduceArrayConstructor(node);
346 } else if (feedback->IsWeakCell()) {
347 Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
348 if (cell->value()->IsJSFunction()) {
349 Node* target_function =
350 jsgraph()->Constant(handle(cell->value(), isolate()));
351
352 // Check that the {target} is still the {target_function}.
353 Node* check = effect =
354 graph()->NewNode(javascript()->StrictEqual(), target, target_function,
355 context, effect, control);
356 Node* branch =
357 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
358 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
359 Node* deoptimize =
360 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
361 frame_state, effect, if_false);
362 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
363 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
364 control = graph()->NewNode(common()->IfTrue(), branch);
365
366 // Specialize the JSCallFunction node to the {target_function}.
367 NodeProperties::ReplaceValueInput(node, target_function, 0);
368 NodeProperties::ReplaceEffectInput(node, effect);
369 NodeProperties::ReplaceControlInput(node, control);
370
371 // Try to further reduce the JSCallFunction {node}.
372 Reduction const reduction = ReduceJSCallFunction(node);
373 return reduction.Changed() ? reduction : Changed(node);
374 }
375 }
376 return NoChange();
377}
378
379
380Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
381 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
382 CallConstructParameters const& p = CallConstructParametersOf(node->op());
383 DCHECK_LE(2u, p.arity());
384 int const arity = static_cast<int>(p.arity() - 2);
385 Node* target = NodeProperties::GetValueInput(node, 0);
386 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
387 Node* context = NodeProperties::GetContextInput(node);
388 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
389 Node* effect = NodeProperties::GetEffectInput(node);
390 Node* control = NodeProperties::GetControlInput(node);
391
392 // Try to specialize JSCallConstruct {node}s with constant {target}s.
393 HeapObjectMatcher m(target);
394 if (m.HasValue()) {
395 if (m.Value()->IsJSFunction()) {
396 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
397
398 // Raise a TypeError if the {target} is not a constructor.
399 if (!function->IsConstructor()) {
400 // Drop the lazy bailout location and use the eager bailout point for
401 // the runtime function (actually as lazy bailout point). It doesn't
402 // really matter which bailout location we use since we never really
403 // go back after throwing the exception.
404 NodeProperties::RemoveFrameStateInput(node, 0);
405 NodeProperties::ReplaceValueInputs(node, target);
406 NodeProperties::ChangeOp(
407 node,
408 javascript()->CallRuntime(Runtime::kThrowCalledNonCallable, 1));
409 return Changed(node);
410 }
411
412 // Check for the ArrayConstructor.
413 if (*function == function->native_context()->array_function()) {
414 // Check if we have an allocation site.
415 Handle<AllocationSite> site;
416 if (p.feedback().IsValid()) {
417 Handle<Object> feedback(
418 p.feedback().vector()->Get(p.feedback().slot()), isolate());
419 if (feedback->IsAllocationSite()) {
420 site = Handle<AllocationSite>::cast(feedback);
421 }
422 }
423
424 // Turn the {node} into a {JSCreateArray} call.
425 NodeProperties::RemoveFrameStateInput(node, 1);
426 for (int i = arity; i > 0; --i) {
427 NodeProperties::ReplaceValueInput(
428 node, NodeProperties::GetValueInput(node, i), i + 1);
429 }
430 NodeProperties::ReplaceValueInput(node, new_target, 1);
431 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
432 return Changed(node);
433 }
434 }
435
436 // Don't mess with other {node}s that have a constant {target}.
437 // TODO(bmeurer): Also support optimizing bound functions and proxies here.
438 return NoChange();
439 }
440
441 // Not much we can do if deoptimization support is disabled.
442 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
443
444 // TODO(mvstanton): Use ConstructICNexus here, once available.
445 Handle<Object> feedback;
446 if (!p.feedback().IsValid()) return NoChange();
447 feedback = handle(p.feedback().vector()->Get(p.feedback().slot()), isolate());
448 if (feedback->IsAllocationSite()) {
449 // The feedback is an AllocationSite, which means we have called the
450 // Array function and collected transition (and pretenuring) feedback
451 // for the resulting arrays. This has to be kept in sync with the
452 // implementation of the CallConstructStub.
453 Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback);
454
455 // Retrieve the Array function from the {node}.
456 Node* array_function;
457 Handle<Context> native_context;
458 if (GetNativeContext(node).ToHandle(&native_context)) {
459 array_function = jsgraph()->HeapConstant(
460 handle(native_context->array_function(), isolate()));
461 } else {
462 Node* native_context = effect = graph()->NewNode(
463 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
464 context, context, effect);
465 array_function = effect = graph()->NewNode(
466 javascript()->LoadContext(0, Context::ARRAY_FUNCTION_INDEX, true),
467 native_context, native_context, effect);
468 }
469
470 // Check that the {target} is still the {array_function}.
471 Node* check = effect =
472 graph()->NewNode(javascript()->StrictEqual(), target, array_function,
473 context, effect, control);
474 Node* branch =
475 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
476 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
477 Node* deoptimize =
478 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
479 frame_state, effect, if_false);
480 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
481 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
482 control = graph()->NewNode(common()->IfTrue(), branch);
483
484 // Turn the {node} into a {JSCreateArray} call.
485 NodeProperties::ReplaceEffectInput(node, effect);
486 NodeProperties::ReplaceControlInput(node, control);
487 NodeProperties::RemoveFrameStateInput(node, 1);
488 for (int i = arity; i > 0; --i) {
489 NodeProperties::ReplaceValueInput(
490 node, NodeProperties::GetValueInput(node, i), i + 1);
491 }
492 NodeProperties::ReplaceValueInput(node, new_target, 1);
493 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
494 return Changed(node);
495 } else if (feedback->IsWeakCell()) {
496 Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
497 if (cell->value()->IsJSFunction()) {
498 Node* target_function =
499 jsgraph()->Constant(handle(cell->value(), isolate()));
500
501 // Check that the {target} is still the {target_function}.
502 Node* check = effect =
503 graph()->NewNode(javascript()->StrictEqual(), target, target_function,
504 context, effect, control);
505 Node* branch =
506 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
507 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
508 Node* deoptimize =
509 graph()->NewNode(common()->Deoptimize(DeoptimizeKind::kEager),
510 frame_state, effect, if_false);
511 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
512 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
513 control = graph()->NewNode(common()->IfTrue(), branch);
514
515 // Specialize the JSCallConstruct node to the {target_function}.
516 NodeProperties::ReplaceValueInput(node, target_function, 0);
517 NodeProperties::ReplaceEffectInput(node, effect);
518 NodeProperties::ReplaceControlInput(node, control);
519 if (target == new_target) {
520 NodeProperties::ReplaceValueInput(node, target_function, arity + 1);
521 }
522
523 // Try to further reduce the JSCallConstruct {node}.
524 Reduction const reduction = ReduceJSCallConstruct(node);
525 return reduction.Changed() ? reduction : Changed(node);
526 }
527 }
528
529 return NoChange();
530}
531
532
533MaybeHandle<Context> JSCallReducer::GetNativeContext(Node* node) {
534 Node* const context = NodeProperties::GetContextInput(node);
535 return NodeProperties::GetSpecializationNativeContext(context,
536 native_context());
537}
538
539
540Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
541
542
543Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
544
545
546CommonOperatorBuilder* JSCallReducer::common() const {
547 return jsgraph()->common();
548}
549
550
551JSOperatorBuilder* JSCallReducer::javascript() const {
552 return jsgraph()->javascript();
553}
554
555} // namespace compiler
556} // namespace internal
557} // namespace v8