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 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 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 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 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 ) 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) 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 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 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 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 540 Graph* JSCallReducer::graph() const { return jsgraph()->graph(); } 541 542 543 Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); } 544 545 546 CommonOperatorBuilder* JSCallReducer::common() const { 547 return jsgraph()->common(); 548 } 549 550 551 JSOperatorBuilder* JSCallReducer::javascript() const { 552 return jsgraph()->javascript(); 553 } 554 555 } // namespace compiler 556 } // namespace internal 557 } // namespace v8 558