blob: 892dcc70ce361a413bf4b9404560c77e38998648 [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}).
Ben Murdoch097c5b22016-05-18 11:27:45 +0100132 CreateArgumentsType type = CreateArgumentsTypeOf(arg_array->op());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133 Node* frame_state = NodeProperties::GetFrameStateInput(arg_array, 0);
134 Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
135 if (outer_state->opcode() != IrOpcode::kFrameState) return NoChange();
136 FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
137 if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
138 // Need to take the parameters from the arguments adaptor.
139 frame_state = outer_state;
140 }
141 FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100142 int start_index = 0;
143 if (type == CreateArgumentsType::kMappedArguments) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144 // 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();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100148 } else if (type == CreateArgumentsType::kRestParameter) {
149 Handle<SharedFunctionInfo> shared;
150 if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
151 start_index = shared->internal_formal_parameter_count();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 }
153 // Remove the argArray input from the {node}.
154 node->RemoveInput(static_cast<int>(--arity));
155 // Add the actual parameters to the {node}, skipping the receiver.
156 Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100157 for (int i = start_index + 1; i < state_info.parameter_count(); ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158 node->InsertInput(graph()->zone(), static_cast<int>(arity),
159 parameters->InputAt(i));
160 ++arity;
161 }
162 // Drop the {target} from the {node}.
163 node->RemoveInput(0);
164 --arity;
165 } else {
166 return NoChange();
167 }
168 // Change {node} to the new {JSCallFunction} operator.
169 NodeProperties::ChangeOp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100170 node, javascript()->CallFunction(arity, CallCountFeedback(p.feedback()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 convert_mode, p.tail_call_mode()));
172 // Change context of {node} to the Function.prototype.apply context,
173 // to ensure any exception is thrown in the correct context.
174 NodeProperties::ReplaceContextInput(
175 node, jsgraph()->HeapConstant(handle(apply->context(), isolate())));
176 // Try to further reduce the JSCallFunction {node}.
177 Reduction const reduction = ReduceJSCallFunction(node);
178 return reduction.Changed() ? reduction : Changed(node);
179}
180
181
182// ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
183Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
184 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
185 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
186 Handle<JSFunction> call = Handle<JSFunction>::cast(
187 HeapObjectMatcher(NodeProperties::GetValueInput(node, 0)).Value());
188 // Change context of {node} to the Function.prototype.call context,
189 // to ensure any exception is thrown in the correct context.
190 NodeProperties::ReplaceContextInput(
191 node, jsgraph()->HeapConstant(handle(call->context(), isolate())));
192 // Remove the target from {node} and use the receiver as target instead, and
193 // the thisArg becomes the new target. If thisArg was not provided, insert
194 // undefined instead.
195 size_t arity = p.arity();
196 DCHECK_LE(2u, arity);
197 ConvertReceiverMode convert_mode;
198 if (arity == 2) {
199 // The thisArg was not provided, use undefined as receiver.
200 convert_mode = ConvertReceiverMode::kNullOrUndefined;
201 node->ReplaceInput(0, node->InputAt(1));
202 node->ReplaceInput(1, jsgraph()->UndefinedConstant());
203 } else {
204 // Just remove the target, which is the first value input.
205 convert_mode = ConvertReceiverMode::kAny;
206 node->RemoveInput(0);
207 --arity;
208 }
209 NodeProperties::ChangeOp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100210 node, javascript()->CallFunction(arity, CallCountFeedback(p.feedback()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 convert_mode, p.tail_call_mode()));
212 // Try to further reduce the JSCallFunction {node}.
213 Reduction const reduction = ReduceJSCallFunction(node);
214 return reduction.Changed() ? reduction : Changed(node);
215}
216
217
218Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
219 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
220 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
221 Node* target = NodeProperties::GetValueInput(node, 0);
222 Node* context = NodeProperties::GetContextInput(node);
223 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
224 Node* control = NodeProperties::GetControlInput(node);
225 Node* effect = NodeProperties::GetEffectInput(node);
226
227 // Try to specialize JSCallFunction {node}s with constant {target}s.
228 HeapObjectMatcher m(target);
229 if (m.HasValue()) {
230 if (m.Value()->IsJSFunction()) {
231 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
232 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
233
234 // Raise a TypeError if the {target} is a "classConstructor".
235 if (IsClassConstructor(shared->kind())) {
236 NodeProperties::RemoveFrameStateInput(node, 0);
237 NodeProperties::ReplaceValueInputs(node, target);
238 NodeProperties::ChangeOp(
239 node, javascript()->CallRuntime(
240 Runtime::kThrowConstructorNonCallableError, 1));
241 return Changed(node);
242 }
243
244 // Check for known builtin functions.
245 if (shared->HasBuiltinFunctionId()) {
246 switch (shared->builtin_function_id()) {
247 case kFunctionApply:
248 return ReduceFunctionPrototypeApply(node);
249 case kFunctionCall:
250 return ReduceFunctionPrototypeCall(node);
251 default:
252 break;
253 }
254 }
255
256 // Check for the Array constructor.
257 if (*function == function->native_context()->array_function()) {
258 return ReduceArrayConstructor(node);
259 }
260
261 // Check for the Number constructor.
262 if (*function == function->native_context()->number_function()) {
263 return ReduceNumberConstructor(node);
264 }
265 } else if (m.Value()->IsJSBoundFunction()) {
266 Handle<JSBoundFunction> function =
267 Handle<JSBoundFunction>::cast(m.Value());
268 Handle<JSReceiver> bound_target_function(
269 function->bound_target_function(), isolate());
270 Handle<Object> bound_this(function->bound_this(), isolate());
271 Handle<FixedArray> bound_arguments(function->bound_arguments(),
272 isolate());
273 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
274 ConvertReceiverMode const convert_mode =
275 (bound_this->IsNull() || bound_this->IsUndefined())
276 ? ConvertReceiverMode::kNullOrUndefined
277 : ConvertReceiverMode::kNotNullOrUndefined;
278 size_t arity = p.arity();
279 DCHECK_LE(2u, arity);
280 // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
281 NodeProperties::ReplaceValueInput(
282 node, jsgraph()->Constant(bound_target_function), 0);
283 NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
284 1);
285 // Insert the [[BoundArguments]] for {node}.
286 for (int i = 0; i < bound_arguments->length(); ++i) {
287 node->InsertInput(
288 graph()->zone(), i + 2,
289 jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
290 arity++;
291 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100292 NodeProperties::ChangeOp(node, javascript()->CallFunction(
293 arity, CallCountFeedback(p.feedback()),
294 convert_mode, p.tail_call_mode()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 // Try to further reduce the JSCallFunction {node}.
296 Reduction const reduction = ReduceJSCallFunction(node);
297 return reduction.Changed() ? reduction : Changed(node);
298 }
299
300 // Don't mess with other {node}s that have a constant {target}.
301 // TODO(bmeurer): Also support proxies here.
302 return NoChange();
303 }
304
305 // Not much we can do if deoptimization support is disabled.
306 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
307
308 // Extract feedback from the {node} using the CallICNexus.
309 if (!p.feedback().IsValid()) return NoChange();
310 CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
311 Handle<Object> feedback(nexus.GetFeedback(), isolate());
312 if (feedback->IsAllocationSite()) {
313 // Retrieve the Array function from the {node}.
314 Node* array_function;
315 Handle<Context> native_context;
316 if (GetNativeContext(node).ToHandle(&native_context)) {
317 array_function = jsgraph()->HeapConstant(
318 handle(native_context->array_function(), isolate()));
319 } else {
320 Node* native_context = effect = graph()->NewNode(
321 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
322 context, context, effect);
323 array_function = effect = graph()->NewNode(
324 javascript()->LoadContext(0, Context::ARRAY_FUNCTION_INDEX, true),
325 native_context, native_context, effect);
326 }
327
328 // Check that the {target} is still the {array_function}.
329 Node* check = effect =
330 graph()->NewNode(javascript()->StrictEqual(), target, array_function,
331 context, effect, control);
Ben Murdochda12d292016-06-02 14:46:10 +0100332 control = graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
333 effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334
335 // Turn the {node} into a {JSCreateArray} call.
336 NodeProperties::ReplaceValueInput(node, array_function, 0);
337 NodeProperties::ReplaceEffectInput(node, effect);
338 NodeProperties::ReplaceControlInput(node, control);
339 return ReduceArrayConstructor(node);
340 } else if (feedback->IsWeakCell()) {
341 Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
342 if (cell->value()->IsJSFunction()) {
343 Node* target_function =
344 jsgraph()->Constant(handle(cell->value(), isolate()));
345
346 // Check that the {target} is still the {target_function}.
347 Node* check = effect =
348 graph()->NewNode(javascript()->StrictEqual(), target, target_function,
349 context, effect, control);
Ben Murdochda12d292016-06-02 14:46:10 +0100350 control = graph()->NewNode(common()->DeoptimizeUnless(), check,
351 frame_state, effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000352
353 // Specialize the JSCallFunction node to the {target_function}.
354 NodeProperties::ReplaceValueInput(node, target_function, 0);
355 NodeProperties::ReplaceEffectInput(node, effect);
356 NodeProperties::ReplaceControlInput(node, control);
357
358 // Try to further reduce the JSCallFunction {node}.
359 Reduction const reduction = ReduceJSCallFunction(node);
360 return reduction.Changed() ? reduction : Changed(node);
361 }
362 }
363 return NoChange();
364}
365
366
367Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
368 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
369 CallConstructParameters const& p = CallConstructParametersOf(node->op());
370 DCHECK_LE(2u, p.arity());
371 int const arity = static_cast<int>(p.arity() - 2);
372 Node* target = NodeProperties::GetValueInput(node, 0);
373 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
374 Node* context = NodeProperties::GetContextInput(node);
375 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
376 Node* effect = NodeProperties::GetEffectInput(node);
377 Node* control = NodeProperties::GetControlInput(node);
378
379 // Try to specialize JSCallConstruct {node}s with constant {target}s.
380 HeapObjectMatcher m(target);
381 if (m.HasValue()) {
382 if (m.Value()->IsJSFunction()) {
383 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
384
385 // Raise a TypeError if the {target} is not a constructor.
386 if (!function->IsConstructor()) {
387 // Drop the lazy bailout location and use the eager bailout point for
388 // the runtime function (actually as lazy bailout point). It doesn't
389 // really matter which bailout location we use since we never really
390 // go back after throwing the exception.
391 NodeProperties::RemoveFrameStateInput(node, 0);
392 NodeProperties::ReplaceValueInputs(node, target);
393 NodeProperties::ChangeOp(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100394 node, javascript()->CallRuntime(Runtime::kThrowCalledNonCallable));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 return Changed(node);
396 }
397
398 // Check for the ArrayConstructor.
399 if (*function == function->native_context()->array_function()) {
400 // Check if we have an allocation site.
401 Handle<AllocationSite> site;
402 if (p.feedback().IsValid()) {
403 Handle<Object> feedback(
404 p.feedback().vector()->Get(p.feedback().slot()), isolate());
405 if (feedback->IsAllocationSite()) {
406 site = Handle<AllocationSite>::cast(feedback);
407 }
408 }
409
410 // Turn the {node} into a {JSCreateArray} call.
411 NodeProperties::RemoveFrameStateInput(node, 1);
412 for (int i = arity; i > 0; --i) {
413 NodeProperties::ReplaceValueInput(
414 node, NodeProperties::GetValueInput(node, i), i + 1);
415 }
416 NodeProperties::ReplaceValueInput(node, new_target, 1);
417 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
418 return Changed(node);
419 }
420 }
421
422 // Don't mess with other {node}s that have a constant {target}.
423 // TODO(bmeurer): Also support optimizing bound functions and proxies here.
424 return NoChange();
425 }
426
427 // Not much we can do if deoptimization support is disabled.
428 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
429
430 // TODO(mvstanton): Use ConstructICNexus here, once available.
431 Handle<Object> feedback;
432 if (!p.feedback().IsValid()) return NoChange();
433 feedback = handle(p.feedback().vector()->Get(p.feedback().slot()), isolate());
434 if (feedback->IsAllocationSite()) {
435 // The feedback is an AllocationSite, which means we have called the
436 // Array function and collected transition (and pretenuring) feedback
437 // for the resulting arrays. This has to be kept in sync with the
438 // implementation of the CallConstructStub.
439 Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback);
440
441 // Retrieve the Array function from the {node}.
442 Node* array_function;
443 Handle<Context> native_context;
444 if (GetNativeContext(node).ToHandle(&native_context)) {
445 array_function = jsgraph()->HeapConstant(
446 handle(native_context->array_function(), isolate()));
447 } else {
448 Node* native_context = effect = graph()->NewNode(
449 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
450 context, context, effect);
451 array_function = effect = graph()->NewNode(
452 javascript()->LoadContext(0, Context::ARRAY_FUNCTION_INDEX, true),
453 native_context, native_context, effect);
454 }
455
456 // Check that the {target} is still the {array_function}.
457 Node* check = effect =
458 graph()->NewNode(javascript()->StrictEqual(), target, array_function,
459 context, effect, control);
Ben Murdochda12d292016-06-02 14:46:10 +0100460 control = graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state,
461 effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462
463 // Turn the {node} into a {JSCreateArray} call.
464 NodeProperties::ReplaceEffectInput(node, effect);
465 NodeProperties::ReplaceControlInput(node, control);
466 NodeProperties::RemoveFrameStateInput(node, 1);
467 for (int i = arity; i > 0; --i) {
468 NodeProperties::ReplaceValueInput(
469 node, NodeProperties::GetValueInput(node, i), i + 1);
470 }
471 NodeProperties::ReplaceValueInput(node, new_target, 1);
472 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
473 return Changed(node);
474 } else if (feedback->IsWeakCell()) {
475 Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
476 if (cell->value()->IsJSFunction()) {
477 Node* target_function =
478 jsgraph()->Constant(handle(cell->value(), isolate()));
479
480 // Check that the {target} is still the {target_function}.
481 Node* check = effect =
482 graph()->NewNode(javascript()->StrictEqual(), target, target_function,
483 context, effect, control);
Ben Murdochda12d292016-06-02 14:46:10 +0100484 control = graph()->NewNode(common()->DeoptimizeUnless(), check,
485 frame_state, effect, control);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486
487 // Specialize the JSCallConstruct node to the {target_function}.
488 NodeProperties::ReplaceValueInput(node, target_function, 0);
489 NodeProperties::ReplaceEffectInput(node, effect);
490 NodeProperties::ReplaceControlInput(node, control);
491 if (target == new_target) {
492 NodeProperties::ReplaceValueInput(node, target_function, arity + 1);
493 }
494
495 // Try to further reduce the JSCallConstruct {node}.
496 Reduction const reduction = ReduceJSCallConstruct(node);
497 return reduction.Changed() ? reduction : Changed(node);
498 }
499 }
500
501 return NoChange();
502}
503
504
505MaybeHandle<Context> JSCallReducer::GetNativeContext(Node* node) {
506 Node* const context = NodeProperties::GetContextInput(node);
507 return NodeProperties::GetSpecializationNativeContext(context,
508 native_context());
509}
510
511
512Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
513
514
515Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
516
517
518CommonOperatorBuilder* JSCallReducer::common() const {
519 return jsgraph()->common();
520}
521
522
523JSOperatorBuilder* JSCallReducer::javascript() const {
524 return jsgraph()->javascript();
525}
526
527} // namespace compiler
528} // namespace internal
529} // namespace v8