OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/js-call-reducer.h" | 5 #include "src/compiler/js-call-reducer.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stubs.h" | 8 #include "src/code-stubs.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
| 10 #include "src/compiler/access-builder.h" |
10 #include "src/compiler/js-graph.h" | 11 #include "src/compiler/js-graph.h" |
11 #include "src/compiler/linkage.h" | 12 #include "src/compiler/linkage.h" |
12 #include "src/compiler/node-matchers.h" | 13 #include "src/compiler/node-matchers.h" |
13 #include "src/compiler/simplified-operator.h" | 14 #include "src/compiler/simplified-operator.h" |
14 #include "src/feedback-vector-inl.h" | 15 #include "src/feedback-vector-inl.h" |
15 #include "src/ic/call-optimization.h" | 16 #include "src/ic/call-optimization.h" |
16 #include "src/objects-inl.h" | 17 #include "src/objects-inl.h" |
17 | 18 |
18 namespace v8 { | 19 namespace v8 { |
19 namespace internal { | 20 namespace internal { |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 | 337 |
337 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target ) | 338 // ES6 section 26.1.7 Reflect.getPrototypeOf ( target ) |
338 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) { | 339 Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) { |
339 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); | 340 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
340 Node* target = (node->op()->ValueInputCount() >= 3) | 341 Node* target = (node->op()->ValueInputCount() >= 3) |
341 ? NodeProperties::GetValueInput(node, 2) | 342 ? NodeProperties::GetValueInput(node, 2) |
342 : jsgraph()->UndefinedConstant(); | 343 : jsgraph()->UndefinedConstant(); |
343 return ReduceObjectGetPrototype(node, target); | 344 return ReduceObjectGetPrototype(node, target); |
344 } | 345 } |
345 | 346 |
| 347 std::pair<Node*, Node*> |
| 348 JSCallReducer::CreateJavaScriptBuiltinContinuationFrameState( |
| 349 Handle<SharedFunctionInfo> shared, Builtins::Name name, Node* target, |
| 350 Node* context, Node** stack_parameters, int stack_parameter_count, |
| 351 Node* effect, Node* control, Node* outer_frame_state, CheckpointMode mode) { |
| 352 BailoutId bailout_id = Builtins::GetContinuationBailoutId(name); |
| 353 Callable callable = Builtins::CallableFor(isolate(), name); |
| 354 |
| 355 // Lazy deopt points where the frame state is assocated with a call get an |
| 356 // additional parameter for the return result from the call that's added by |
| 357 // the deoptimizer and not explicitly specified in the frame state. Check that |
| 358 // there is not a mismatch between the number of frame state parameters and |
| 359 // the stack parameters required by the builtin taking this into account. |
| 360 DCHECK_EQ( |
| 361 Builtins::GetStackParameterCount(isolate(), name) + 1, // add receiver |
| 362 stack_parameter_count + (mode == CREATE_CHECKPOINT ? 0 : 1)); |
| 363 |
| 364 NodeVector params(local_zone_); |
| 365 // target |
| 366 params.push_back(target); |
| 367 // new target |
| 368 params.push_back(jsgraph()->UndefinedConstant()); |
| 369 // argc, remove receiver and add in return value for lazy deopts from calls |
| 370 params.push_back(jsgraph()->Constant(stack_parameter_count - |
| 371 (mode == CREATE_CHECKPOINT ? 1 : 0))); |
| 372 // context |
| 373 params.push_back(context); |
| 374 |
| 375 for (int i = 0; i < stack_parameter_count; ++i) { |
| 376 params.push_back(stack_parameters[i]); |
| 377 } |
| 378 |
| 379 const Operator* op_param = common()->StateValues( |
| 380 static_cast<int>(params.size()), SparseInputMask::Dense()); |
| 381 Node* params_node = graph()->NewNode( |
| 382 op_param, static_cast<int>(params.size()), ¶ms.front()); |
| 383 |
| 384 // Add the context to the total parameter count, it is implicit in the |
| 385 // descriptor. |
| 386 const int total_parameter_count = |
| 387 stack_parameter_count + |
| 388 callable.descriptor().GetRegisterParameterCount() + 1; |
| 389 const FrameStateFunctionInfo* state_info = |
| 390 common()->CreateFrameStateFunctionInfo( |
| 391 FrameStateType::kBuiltinContinuation, total_parameter_count, 0, |
| 392 shared); |
| 393 const Operator* op = common()->FrameState( |
| 394 bailout_id, OutputFrameStateCombine::Ignore(), state_info); |
| 395 const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense()); |
| 396 Node* node0 = graph()->NewNode(op0); |
| 397 |
| 398 Node* frame_state = graph()->NewNode(op, params_node, node0, node0, |
| 399 jsgraph()->UndefinedConstant(), target, |
| 400 outer_frame_state); |
| 401 |
| 402 return std::make_pair( |
| 403 frame_state, mode == CREATE_CHECKPOINT |
| 404 ? graph()->NewNode(common()->Checkpoint(), frame_state, |
| 405 effect, control) |
| 406 : effect); |
| 407 } |
| 408 |
| 409 Reduction JSCallReducer::ReduceArrayForEach(Handle<SharedFunctionInfo> shared, |
| 410 Node* node) { |
| 411 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
| 412 Node* outer_frame_state = NodeProperties::GetFrameStateInput(node); |
| 413 Node* effect = NodeProperties::GetEffectInput(node); |
| 414 Node* control = NodeProperties::GetControlInput(node); |
| 415 Node* context = NodeProperties::GetContextInput(node); |
| 416 |
| 417 // Try to determine the {receiver} map. |
| 418 Node* receiver = NodeProperties::GetValueInput(node, 1); |
| 419 Node* fncallback = node->op()->ValueInputCount() > 2 |
| 420 ? NodeProperties::GetValueInput(node, 2) |
| 421 : jsgraph()->UndefinedConstant(); |
| 422 Node* this_arg = node->op()->ValueInputCount() > 3 |
| 423 ? NodeProperties::GetValueInput(node, 3) |
| 424 : jsgraph()->UndefinedConstant(); |
| 425 ZoneHandleSet<Map> receiver_maps; |
| 426 if (!NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps)) { |
| 427 return NoChange(); |
| 428 } |
| 429 if (receiver_maps.size() != 1) return NoChange(); |
| 430 Handle<Map> receiver_map(receiver_maps[0]); |
| 431 ElementsKind kind = receiver_map->elements_kind(); |
| 432 // TODO(danno): Handle holey Smi and Object fast elements kinds and double |
| 433 // packed. |
| 434 if (!IsFastPackedElementsKind(kind) || IsFastDoubleElementsKind(kind)) { |
| 435 return NoChange(); |
| 436 } |
| 437 |
| 438 Node* k = jsgraph()->Constant(0); |
| 439 |
| 440 Node* original_length = graph()->NewNode( |
| 441 simplified()->LoadField(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)), |
| 442 receiver, effect, control); |
| 443 |
| 444 Node* loop = control = graph()->NewNode(common()->Loop(2), control, control); |
| 445 Node* eloop = effect = |
| 446 graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); |
| 447 Node* vloop = k = graph()->NewNode( |
| 448 common()->Phi(MachineRepresentation::kTagged, 2), k, k, loop); |
| 449 |
| 450 control = loop; |
| 451 effect = eloop; |
| 452 |
| 453 Node* continue_test = |
| 454 graph()->NewNode(simplified()->NumberLessThan(), k, original_length); |
| 455 Node* continue_branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 456 continue_test, control); |
| 457 |
| 458 Node* if_true = graph()->NewNode(common()->IfTrue(), continue_branch); |
| 459 Node* if_false = graph()->NewNode(common()->IfFalse(), continue_branch); |
| 460 control = if_true; |
| 461 |
| 462 NodeVector checkpoint_params(local_zone_); |
| 463 checkpoint_params.push_back(receiver); |
| 464 checkpoint_params.push_back(fncallback); |
| 465 checkpoint_params.push_back(this_arg); |
| 466 checkpoint_params.push_back(k); |
| 467 checkpoint_params.push_back(original_length); |
| 468 const int stack_parameters = static_cast<int>(checkpoint_params.size()); |
| 469 |
| 470 Node* frame_state; |
| 471 std::tie(frame_state, effect) = CreateJavaScriptBuiltinContinuationFrameState( |
| 472 shared, Builtins::kArrayForEachLoopEagerDeoptContinuation, |
| 473 node->InputAt(0), context, &checkpoint_params[0], stack_parameters, |
| 474 effect, control, outer_frame_state, CREATE_CHECKPOINT); |
| 475 |
| 476 // Make sure the map hasn't changed during the iteration |
| 477 Node* orig_map = jsgraph()->HeapConstant(receiver_map); |
| 478 Node* array_map = effect = |
| 479 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 480 receiver, effect, control); |
| 481 Node* check_map = |
| 482 graph()->NewNode(simplified()->ReferenceEqual(), array_map, orig_map); |
| 483 effect = |
| 484 graph()->NewNode(simplified()->CheckIf(), check_map, effect, control); |
| 485 |
| 486 // Make sure that the access is still in bounds, since the callback could have |
| 487 // changed the array's size. |
| 488 Node* length = graph()->NewNode( |
| 489 simplified()->LoadField(AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)), |
| 490 receiver, effect, control); |
| 491 k = effect = |
| 492 graph()->NewNode(simplified()->CheckBounds(), k, length, effect, control); |
| 493 USE(length); |
| 494 |
| 495 // Reload the elements pointer before calling the callback, since the previous |
| 496 // callback might have resized the array causing the elements buffer to be |
| 497 // re-allocated. |
| 498 Node* elements = graph()->NewNode( |
| 499 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, |
| 500 effect, control); |
| 501 |
| 502 Node* element = graph()->NewNode( |
| 503 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), |
| 504 elements, k, effect, control); |
| 505 |
| 506 Node* next_k = |
| 507 graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->Constant(1)); |
| 508 checkpoint_params[3] = next_k; |
| 509 std::tie(frame_state, effect) = CreateJavaScriptBuiltinContinuationFrameState( |
| 510 shared, Builtins::kArrayForEachLoopLazyDeoptContinuation, |
| 511 node->InputAt(0), context, &checkpoint_params[0], stack_parameters, |
| 512 effect, control, outer_frame_state, DONT_CREATE_CHECKPOINT); |
| 513 |
| 514 Node* call_back = control = effect = |
| 515 graph()->NewNode(javascript()->Call(5, 1), fncallback, this_arg, element, |
| 516 k, receiver, context, frame_state, effect, control); |
| 517 USE(call_back); |
| 518 USE(this_arg); |
| 519 |
| 520 k = next_k; |
| 521 |
| 522 loop->ReplaceInput(1, control); |
| 523 vloop->ReplaceInput(1, k); |
| 524 eloop->ReplaceInput(1, effect); |
| 525 |
| 526 control = if_false; |
| 527 effect = eloop; |
| 528 |
| 529 NodeProperties::ReplaceUses(node, jsgraph()->UndefinedConstant(), effect, |
| 530 control); |
| 531 |
| 532 node->TrimInputCount(0); |
| 533 NodeProperties::ChangeOp(node, common()->Dead()); |
| 534 return Changed(node); |
| 535 } |
| 536 |
346 Reduction JSCallReducer::ReduceCallApiFunction( | 537 Reduction JSCallReducer::ReduceCallApiFunction( |
347 Node* node, Handle<FunctionTemplateInfo> function_template_info) { | 538 Node* node, Handle<FunctionTemplateInfo> function_template_info) { |
348 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); | 539 DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); |
349 CallParameters const& p = CallParametersOf(node->op()); | 540 CallParameters const& p = CallParametersOf(node->op()); |
350 int const argc = static_cast<int>(p.arity()) - 2; | 541 int const argc = static_cast<int>(p.arity()) - 2; |
351 Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) | 542 Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) |
352 ? jsgraph()->HeapConstant(global_proxy()) | 543 ? jsgraph()->HeapConstant(global_proxy()) |
353 : NodeProperties::GetValueInput(node, 1); | 544 : NodeProperties::GetValueInput(node, 1); |
354 Node* effect = NodeProperties::GetEffectInput(node); | 545 Node* effect = NodeProperties::GetEffectInput(node); |
355 | 546 |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
568 case Builtins::kFunctionPrototypeHasInstance: | 759 case Builtins::kFunctionPrototypeHasInstance: |
569 return ReduceFunctionPrototypeHasInstance(node); | 760 return ReduceFunctionPrototypeHasInstance(node); |
570 case Builtins::kNumberConstructor: | 761 case Builtins::kNumberConstructor: |
571 return ReduceNumberConstructor(node); | 762 return ReduceNumberConstructor(node); |
572 case Builtins::kObjectGetPrototypeOf: | 763 case Builtins::kObjectGetPrototypeOf: |
573 return ReduceObjectGetPrototypeOf(node); | 764 return ReduceObjectGetPrototypeOf(node); |
574 case Builtins::kObjectPrototypeGetProto: | 765 case Builtins::kObjectPrototypeGetProto: |
575 return ReduceObjectPrototypeGetProto(node); | 766 return ReduceObjectPrototypeGetProto(node); |
576 case Builtins::kReflectGetPrototypeOf: | 767 case Builtins::kReflectGetPrototypeOf: |
577 return ReduceReflectGetPrototypeOf(node); | 768 return ReduceReflectGetPrototypeOf(node); |
| 769 case Builtins::kArrayForEach: |
| 770 return ReduceArrayForEach(shared, node); |
578 default: | 771 default: |
579 break; | 772 break; |
580 } | 773 } |
581 | 774 |
582 // Check for the Array constructor. | 775 // Check for the Array constructor. |
583 if (*function == function->native_context()->array_function()) { | 776 if (*function == function->native_context()->array_function()) { |
584 return ReduceArrayConstructor(node); | 777 return ReduceArrayConstructor(node); |
585 } | 778 } |
586 | 779 |
587 if (!FLAG_runtime_stats && shared->IsApiFunction()) { | 780 if (!FLAG_runtime_stats && shared->IsApiFunction()) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 return jsgraph()->javascript(); | 1044 return jsgraph()->javascript(); |
852 } | 1045 } |
853 | 1046 |
854 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { | 1047 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { |
855 return jsgraph()->simplified(); | 1048 return jsgraph()->simplified(); |
856 } | 1049 } |
857 | 1050 |
858 } // namespace compiler | 1051 } // namespace compiler |
859 } // namespace internal | 1052 } // namespace internal |
860 } // namespace v8 | 1053 } // namespace v8 |
OLD | NEW |