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/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 
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15 
16 namespace {
17 
CallCountFeedback(VectorSlotPair p)18 VectorSlotPair 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 
Reduce(Node * node)40 Reduction 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
ReduceArrayConstructor(Node * node)54 Reduction 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
ReduceNumberConstructor(Node * node)84 Reduction 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 )
ReduceFunctionPrototypeApply(Node * node)100 Reduction 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)
ReduceFunctionPrototypeCall(Node * node)180 Reduction 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 
ReduceJSCallFunction(Node * node)216 Reduction 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 
ReduceJSCallConstruct(Node * node)380 Reduction 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 
GetNativeContext(Node * node)533 MaybeHandle<Context> JSCallReducer::GetNativeContext(Node* node) {
534   Node* const context = NodeProperties::GetContextInput(node);
535   return NodeProperties::GetSpecializationNativeContext(context,
536                                                         native_context());
537 }
538 
539 
graph() const540 Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
541 
542 
isolate() const543 Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
544 
545 
common() const546 CommonOperatorBuilder* JSCallReducer::common() const {
547   return jsgraph()->common();
548 }
549 
550 
javascript() const551 JSOperatorBuilder* JSCallReducer::javascript() const {
552   return jsgraph()->javascript();
553 }
554 
555 }  // namespace compiler
556 }  // namespace internal
557 }  // namespace v8
558