OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/builtins/builtins-utils.h" |
5 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
6 #include "src/builtins/builtins-utils.h" | 7 #include "src/code-factory.h" |
7 | 8 |
8 namespace v8 { | 9 namespace v8 { |
9 namespace internal { | 10 namespace internal { |
10 | 11 |
11 // ----------------------------------------------------------------------------- | 12 // ----------------------------------------------------------------------------- |
12 // ES6 section 20.1 Number Objects | 13 // ES6 section 20.1 Number Objects |
13 | 14 |
14 // ES6 section 20.1.2.2 Number.isFinite ( number ) | 15 // ES6 section 20.1.2.2 Number.isFinite ( number ) |
15 void Builtins::Generate_NumberIsFinite(CodeStubAssembler* assembler) { | 16 void Builtins::Generate_NumberIsFinite(CodeStubAssembler* assembler) { |
16 typedef CodeStubAssembler::Label Label; | 17 typedef CodeStubAssembler::Label Label; |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 typedef compiler::Node Node; | 363 typedef compiler::Node Node; |
363 | 364 |
364 Node* receiver = assembler->Parameter(0); | 365 Node* receiver = assembler->Parameter(0); |
365 Node* context = assembler->Parameter(3); | 366 Node* context = assembler->Parameter(3); |
366 | 367 |
367 Node* result = assembler->ToThisValue( | 368 Node* result = assembler->ToThisValue( |
368 context, receiver, PrimitiveType::kNumber, "Number.prototype.valueOf"); | 369 context, receiver, PrimitiveType::kNumber, "Number.prototype.valueOf"); |
369 assembler->Return(result); | 370 assembler->Return(result); |
370 } | 371 } |
371 | 372 |
| 373 // static |
| 374 void Builtins::Generate_Add(CodeStubAssembler* assembler) { |
| 375 typedef CodeStubAssembler::Label Label; |
| 376 typedef compiler::Node Node; |
| 377 typedef CodeStubAssembler::Variable Variable; |
| 378 |
| 379 Node* left = assembler->Parameter(0); |
| 380 Node* right = assembler->Parameter(1); |
| 381 Node* context = assembler->Parameter(2); |
| 382 |
| 383 // Shared entry for floating point addition. |
| 384 Label do_fadd(assembler); |
| 385 Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64), |
| 386 var_fadd_rhs(assembler, MachineRepresentation::kFloat64); |
| 387 |
| 388 // We might need to loop several times due to ToPrimitive, ToString and/or |
| 389 // ToNumber conversions. |
| 390 Variable var_lhs(assembler, MachineRepresentation::kTagged), |
| 391 var_rhs(assembler, MachineRepresentation::kTagged), |
| 392 var_result(assembler, MachineRepresentation::kTagged); |
| 393 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
| 394 Label loop(assembler, 2, loop_vars), end(assembler), |
| 395 string_add_convert_left(assembler, Label::kDeferred), |
| 396 string_add_convert_right(assembler, Label::kDeferred); |
| 397 var_lhs.Bind(left); |
| 398 var_rhs.Bind(right); |
| 399 assembler->Goto(&loop); |
| 400 assembler->Bind(&loop); |
| 401 { |
| 402 // Load the current {lhs} and {rhs} values. |
| 403 Node* lhs = var_lhs.value(); |
| 404 Node* rhs = var_rhs.value(); |
| 405 |
| 406 // Check if the {lhs} is a Smi or a HeapObject. |
| 407 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
| 408 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
| 409 |
| 410 assembler->Bind(&if_lhsissmi); |
| 411 { |
| 412 // Check if the {rhs} is also a Smi. |
| 413 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
| 414 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
| 415 &if_rhsisnotsmi); |
| 416 |
| 417 assembler->Bind(&if_rhsissmi); |
| 418 { |
| 419 // Try fast Smi addition first. |
| 420 Node* pair = assembler->SmiAddWithOverflow(lhs, rhs); |
| 421 Node* overflow = assembler->Projection(1, pair); |
| 422 |
| 423 // Check if the Smi additon overflowed. |
| 424 Label if_overflow(assembler), if_notoverflow(assembler); |
| 425 assembler->Branch(overflow, &if_overflow, &if_notoverflow); |
| 426 |
| 427 assembler->Bind(&if_overflow); |
| 428 { |
| 429 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); |
| 430 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); |
| 431 assembler->Goto(&do_fadd); |
| 432 } |
| 433 |
| 434 assembler->Bind(&if_notoverflow); |
| 435 var_result.Bind(assembler->Projection(0, pair)); |
| 436 assembler->Goto(&end); |
| 437 } |
| 438 |
| 439 assembler->Bind(&if_rhsisnotsmi); |
| 440 { |
| 441 // Load the map of {rhs}. |
| 442 Node* rhs_map = assembler->LoadMap(rhs); |
| 443 |
| 444 // Check if the {rhs} is a HeapNumber. |
| 445 Label if_rhsisnumber(assembler), |
| 446 if_rhsisnotnumber(assembler, Label::kDeferred); |
| 447 Node* number_map = assembler->HeapNumberMapConstant(); |
| 448 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
| 449 &if_rhsisnumber, &if_rhsisnotnumber); |
| 450 |
| 451 assembler->Bind(&if_rhsisnumber); |
| 452 { |
| 453 var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs)); |
| 454 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
| 455 assembler->Goto(&do_fadd); |
| 456 } |
| 457 |
| 458 assembler->Bind(&if_rhsisnotnumber); |
| 459 { |
| 460 // Load the instance type of {rhs}. |
| 461 Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map); |
| 462 |
| 463 // Check if the {rhs} is a String. |
| 464 Label if_rhsisstring(assembler, Label::kDeferred), |
| 465 if_rhsisnotstring(assembler, Label::kDeferred); |
| 466 assembler->Branch(assembler->Int32LessThan( |
| 467 rhs_instance_type, |
| 468 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), |
| 469 &if_rhsisstring, &if_rhsisnotstring); |
| 470 |
| 471 assembler->Bind(&if_rhsisstring); |
| 472 { |
| 473 var_lhs.Bind(lhs); |
| 474 var_rhs.Bind(rhs); |
| 475 assembler->Goto(&string_add_convert_left); |
| 476 } |
| 477 |
| 478 assembler->Bind(&if_rhsisnotstring); |
| 479 { |
| 480 // Check if {rhs} is a JSReceiver. |
| 481 Label if_rhsisreceiver(assembler, Label::kDeferred), |
| 482 if_rhsisnotreceiver(assembler, Label::kDeferred); |
| 483 assembler->Branch( |
| 484 assembler->Int32LessThanOrEqual( |
| 485 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 486 rhs_instance_type), |
| 487 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 488 |
| 489 assembler->Bind(&if_rhsisreceiver); |
| 490 { |
| 491 // Convert {rhs} to a primitive first passing no hint. |
| 492 Callable callable = |
| 493 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); |
| 494 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
| 495 assembler->Goto(&loop); |
| 496 } |
| 497 |
| 498 assembler->Bind(&if_rhsisnotreceiver); |
| 499 { |
| 500 // Convert {rhs} to a Number first. |
| 501 Callable callable = |
| 502 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 503 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
| 504 assembler->Goto(&loop); |
| 505 } |
| 506 } |
| 507 } |
| 508 } |
| 509 } |
| 510 |
| 511 assembler->Bind(&if_lhsisnotsmi); |
| 512 { |
| 513 // Load the map and instance type of {lhs}. |
| 514 Node* lhs_instance_type = assembler->LoadInstanceType(lhs); |
| 515 |
| 516 // Check if {lhs} is a String. |
| 517 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); |
| 518 assembler->Branch(assembler->Int32LessThan( |
| 519 lhs_instance_type, |
| 520 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), |
| 521 &if_lhsisstring, &if_lhsisnotstring); |
| 522 |
| 523 assembler->Bind(&if_lhsisstring); |
| 524 { |
| 525 var_lhs.Bind(lhs); |
| 526 var_rhs.Bind(rhs); |
| 527 assembler->Goto(&string_add_convert_right); |
| 528 } |
| 529 |
| 530 assembler->Bind(&if_lhsisnotstring); |
| 531 { |
| 532 // Check if {rhs} is a Smi. |
| 533 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
| 534 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
| 535 &if_rhsisnotsmi); |
| 536 |
| 537 assembler->Bind(&if_rhsissmi); |
| 538 { |
| 539 // Check if {lhs} is a Number. |
| 540 Label if_lhsisnumber(assembler), |
| 541 if_lhsisnotnumber(assembler, Label::kDeferred); |
| 542 assembler->Branch(assembler->Word32Equal( |
| 543 lhs_instance_type, |
| 544 assembler->Int32Constant(HEAP_NUMBER_TYPE)), |
| 545 &if_lhsisnumber, &if_lhsisnotnumber); |
| 546 |
| 547 assembler->Bind(&if_lhsisnumber); |
| 548 { |
| 549 // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them. |
| 550 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); |
| 551 var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs)); |
| 552 assembler->Goto(&do_fadd); |
| 553 } |
| 554 |
| 555 assembler->Bind(&if_lhsisnotnumber); |
| 556 { |
| 557 // The {lhs} is neither a Number nor a String, and the {rhs} is a |
| 558 // Smi. |
| 559 Label if_lhsisreceiver(assembler, Label::kDeferred), |
| 560 if_lhsisnotreceiver(assembler, Label::kDeferred); |
| 561 assembler->Branch( |
| 562 assembler->Int32LessThanOrEqual( |
| 563 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 564 lhs_instance_type), |
| 565 &if_lhsisreceiver, &if_lhsisnotreceiver); |
| 566 |
| 567 assembler->Bind(&if_lhsisreceiver); |
| 568 { |
| 569 // Convert {lhs} to a primitive first passing no hint. |
| 570 Callable callable = |
| 571 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); |
| 572 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); |
| 573 assembler->Goto(&loop); |
| 574 } |
| 575 |
| 576 assembler->Bind(&if_lhsisnotreceiver); |
| 577 { |
| 578 // Convert {lhs} to a Number first. |
| 579 Callable callable = |
| 580 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 581 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); |
| 582 assembler->Goto(&loop); |
| 583 } |
| 584 } |
| 585 } |
| 586 |
| 587 assembler->Bind(&if_rhsisnotsmi); |
| 588 { |
| 589 // Load the instance type of {rhs}. |
| 590 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); |
| 591 |
| 592 // Check if {rhs} is a String. |
| 593 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); |
| 594 assembler->Branch(assembler->Int32LessThan( |
| 595 rhs_instance_type, |
| 596 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), |
| 597 &if_rhsisstring, &if_rhsisnotstring); |
| 598 |
| 599 assembler->Bind(&if_rhsisstring); |
| 600 { |
| 601 var_lhs.Bind(lhs); |
| 602 var_rhs.Bind(rhs); |
| 603 assembler->Goto(&string_add_convert_left); |
| 604 } |
| 605 |
| 606 assembler->Bind(&if_rhsisnotstring); |
| 607 { |
| 608 // Check if {lhs} is a HeapNumber. |
| 609 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); |
| 610 assembler->Branch(assembler->Word32Equal( |
| 611 lhs_instance_type, |
| 612 assembler->Int32Constant(HEAP_NUMBER_TYPE)), |
| 613 &if_lhsisnumber, &if_lhsisnotnumber); |
| 614 |
| 615 assembler->Bind(&if_lhsisnumber); |
| 616 { |
| 617 // Check if {rhs} is also a HeapNumber. |
| 618 Label if_rhsisnumber(assembler), |
| 619 if_rhsisnotnumber(assembler, Label::kDeferred); |
| 620 assembler->Branch(assembler->Word32Equal( |
| 621 rhs_instance_type, |
| 622 assembler->Int32Constant(HEAP_NUMBER_TYPE)), |
| 623 &if_rhsisnumber, &if_rhsisnotnumber); |
| 624 |
| 625 assembler->Bind(&if_rhsisnumber); |
| 626 { |
| 627 // Perform a floating point addition. |
| 628 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); |
| 629 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
| 630 assembler->Goto(&do_fadd); |
| 631 } |
| 632 |
| 633 assembler->Bind(&if_rhsisnotnumber); |
| 634 { |
| 635 // Check if {rhs} is a JSReceiver. |
| 636 Label if_rhsisreceiver(assembler, Label::kDeferred), |
| 637 if_rhsisnotreceiver(assembler, Label::kDeferred); |
| 638 assembler->Branch( |
| 639 assembler->Int32LessThanOrEqual( |
| 640 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 641 rhs_instance_type), |
| 642 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 643 |
| 644 assembler->Bind(&if_rhsisreceiver); |
| 645 { |
| 646 // Convert {rhs} to a primitive first passing no hint. |
| 647 Callable callable = CodeFactory::NonPrimitiveToPrimitive( |
| 648 assembler->isolate()); |
| 649 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
| 650 assembler->Goto(&loop); |
| 651 } |
| 652 |
| 653 assembler->Bind(&if_rhsisnotreceiver); |
| 654 { |
| 655 // Convert {rhs} to a Number first. |
| 656 Callable callable = |
| 657 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 658 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
| 659 assembler->Goto(&loop); |
| 660 } |
| 661 } |
| 662 } |
| 663 |
| 664 assembler->Bind(&if_lhsisnotnumber); |
| 665 { |
| 666 // Check if {lhs} is a JSReceiver. |
| 667 Label if_lhsisreceiver(assembler, Label::kDeferred), |
| 668 if_lhsisnotreceiver(assembler); |
| 669 assembler->Branch( |
| 670 assembler->Int32LessThanOrEqual( |
| 671 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 672 lhs_instance_type), |
| 673 &if_lhsisreceiver, &if_lhsisnotreceiver); |
| 674 |
| 675 assembler->Bind(&if_lhsisreceiver); |
| 676 { |
| 677 // Convert {lhs} to a primitive first passing no hint. |
| 678 Callable callable = |
| 679 CodeFactory::NonPrimitiveToPrimitive(assembler->isolate()); |
| 680 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); |
| 681 assembler->Goto(&loop); |
| 682 } |
| 683 |
| 684 assembler->Bind(&if_lhsisnotreceiver); |
| 685 { |
| 686 // Check if {rhs} is a JSReceiver. |
| 687 Label if_rhsisreceiver(assembler, Label::kDeferred), |
| 688 if_rhsisnotreceiver(assembler, Label::kDeferred); |
| 689 assembler->Branch( |
| 690 assembler->Int32LessThanOrEqual( |
| 691 assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE), |
| 692 rhs_instance_type), |
| 693 &if_rhsisreceiver, &if_rhsisnotreceiver); |
| 694 |
| 695 assembler->Bind(&if_rhsisreceiver); |
| 696 { |
| 697 // Convert {rhs} to a primitive first passing no hint. |
| 698 Callable callable = CodeFactory::NonPrimitiveToPrimitive( |
| 699 assembler->isolate()); |
| 700 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
| 701 assembler->Goto(&loop); |
| 702 } |
| 703 |
| 704 assembler->Bind(&if_rhsisnotreceiver); |
| 705 { |
| 706 // Convert {lhs} to a Number first. |
| 707 Callable callable = |
| 708 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 709 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); |
| 710 assembler->Goto(&loop); |
| 711 } |
| 712 } |
| 713 } |
| 714 } |
| 715 } |
| 716 } |
| 717 } |
| 718 } |
| 719 assembler->Bind(&string_add_convert_left); |
| 720 { |
| 721 // Convert {lhs}, which is a Smi, to a String and concatenate the |
| 722 // resulting string with the String {rhs}. |
| 723 Callable callable = CodeFactory::StringAdd( |
| 724 assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED); |
| 725 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), |
| 726 var_rhs.value())); |
| 727 assembler->Goto(&end); |
| 728 } |
| 729 |
| 730 assembler->Bind(&string_add_convert_right); |
| 731 { |
| 732 // Convert {lhs}, which is a Smi, to a String and concatenate the |
| 733 // resulting string with the String {rhs}. |
| 734 Callable callable = CodeFactory::StringAdd( |
| 735 assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED); |
| 736 var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(), |
| 737 var_rhs.value())); |
| 738 assembler->Goto(&end); |
| 739 } |
| 740 |
| 741 assembler->Bind(&do_fadd); |
| 742 { |
| 743 Node* lhs_value = var_fadd_lhs.value(); |
| 744 Node* rhs_value = var_fadd_rhs.value(); |
| 745 Node* value = assembler->Float64Add(lhs_value, rhs_value); |
| 746 Node* result = assembler->ChangeFloat64ToTagged(value); |
| 747 var_result.Bind(result); |
| 748 assembler->Goto(&end); |
| 749 } |
| 750 assembler->Bind(&end); |
| 751 assembler->Return(var_result.value()); |
| 752 } |
| 753 |
| 754 void Builtins::Generate_Subtract(CodeStubAssembler* assembler) { |
| 755 typedef CodeStubAssembler::Label Label; |
| 756 typedef compiler::Node Node; |
| 757 typedef CodeStubAssembler::Variable Variable; |
| 758 |
| 759 Node* left = assembler->Parameter(0); |
| 760 Node* right = assembler->Parameter(1); |
| 761 Node* context = assembler->Parameter(2); |
| 762 |
| 763 // Shared entry for floating point subtraction. |
| 764 Label do_fsub(assembler), end(assembler); |
| 765 Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64), |
| 766 var_fsub_rhs(assembler, MachineRepresentation::kFloat64); |
| 767 |
| 768 // We might need to loop several times due to ToPrimitive and/or ToNumber |
| 769 // conversions. |
| 770 Variable var_lhs(assembler, MachineRepresentation::kTagged), |
| 771 var_rhs(assembler, MachineRepresentation::kTagged), |
| 772 var_result(assembler, MachineRepresentation::kTagged); |
| 773 Variable* loop_vars[2] = {&var_lhs, &var_rhs}; |
| 774 Label loop(assembler, 2, loop_vars); |
| 775 var_lhs.Bind(left); |
| 776 var_rhs.Bind(right); |
| 777 assembler->Goto(&loop); |
| 778 assembler->Bind(&loop); |
| 779 { |
| 780 // Load the current {lhs} and {rhs} values. |
| 781 Node* lhs = var_lhs.value(); |
| 782 Node* rhs = var_rhs.value(); |
| 783 |
| 784 // Check if the {lhs} is a Smi or a HeapObject. |
| 785 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
| 786 assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi); |
| 787 |
| 788 assembler->Bind(&if_lhsissmi); |
| 789 { |
| 790 // Check if the {rhs} is also a Smi. |
| 791 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
| 792 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
| 793 &if_rhsisnotsmi); |
| 794 |
| 795 assembler->Bind(&if_rhsissmi); |
| 796 { |
| 797 // Try a fast Smi subtraction first. |
| 798 Node* pair = assembler->SmiSubWithOverflow(lhs, rhs); |
| 799 Node* overflow = assembler->Projection(1, pair); |
| 800 |
| 801 // Check if the Smi subtraction overflowed. |
| 802 Label if_overflow(assembler), if_notoverflow(assembler); |
| 803 assembler->Branch(overflow, &if_overflow, &if_notoverflow); |
| 804 |
| 805 assembler->Bind(&if_overflow); |
| 806 { |
| 807 // The result doesn't fit into Smi range. |
| 808 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); |
| 809 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); |
| 810 assembler->Goto(&do_fsub); |
| 811 } |
| 812 |
| 813 assembler->Bind(&if_notoverflow); |
| 814 var_result.Bind(assembler->Projection(0, pair)); |
| 815 assembler->Goto(&end); |
| 816 } |
| 817 |
| 818 assembler->Bind(&if_rhsisnotsmi); |
| 819 { |
| 820 // Load the map of the {rhs}. |
| 821 Node* rhs_map = assembler->LoadMap(rhs); |
| 822 |
| 823 // Check if {rhs} is a HeapNumber. |
| 824 Label if_rhsisnumber(assembler), |
| 825 if_rhsisnotnumber(assembler, Label::kDeferred); |
| 826 Node* number_map = assembler->HeapNumberMapConstant(); |
| 827 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
| 828 &if_rhsisnumber, &if_rhsisnotnumber); |
| 829 |
| 830 assembler->Bind(&if_rhsisnumber); |
| 831 { |
| 832 // Perform a floating point subtraction. |
| 833 var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs)); |
| 834 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
| 835 assembler->Goto(&do_fsub); |
| 836 } |
| 837 |
| 838 assembler->Bind(&if_rhsisnotnumber); |
| 839 { |
| 840 // Convert the {rhs} to a Number first. |
| 841 Callable callable = |
| 842 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 843 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
| 844 assembler->Goto(&loop); |
| 845 } |
| 846 } |
| 847 } |
| 848 |
| 849 assembler->Bind(&if_lhsisnotsmi); |
| 850 { |
| 851 // Load the map of the {lhs}. |
| 852 Node* lhs_map = assembler->LoadMap(lhs); |
| 853 |
| 854 // Check if the {lhs} is a HeapNumber. |
| 855 Label if_lhsisnumber(assembler), |
| 856 if_lhsisnotnumber(assembler, Label::kDeferred); |
| 857 Node* number_map = assembler->HeapNumberMapConstant(); |
| 858 assembler->Branch(assembler->WordEqual(lhs_map, number_map), |
| 859 &if_lhsisnumber, &if_lhsisnotnumber); |
| 860 |
| 861 assembler->Bind(&if_lhsisnumber); |
| 862 { |
| 863 // Check if the {rhs} is a Smi. |
| 864 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
| 865 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
| 866 &if_rhsisnotsmi); |
| 867 |
| 868 assembler->Bind(&if_rhsissmi); |
| 869 { |
| 870 // Perform a floating point subtraction. |
| 871 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); |
| 872 var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs)); |
| 873 assembler->Goto(&do_fsub); |
| 874 } |
| 875 |
| 876 assembler->Bind(&if_rhsisnotsmi); |
| 877 { |
| 878 // Load the map of the {rhs}. |
| 879 Node* rhs_map = assembler->LoadMap(rhs); |
| 880 |
| 881 // Check if the {rhs} is a HeapNumber. |
| 882 Label if_rhsisnumber(assembler), |
| 883 if_rhsisnotnumber(assembler, Label::kDeferred); |
| 884 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
| 885 &if_rhsisnumber, &if_rhsisnotnumber); |
| 886 |
| 887 assembler->Bind(&if_rhsisnumber); |
| 888 { |
| 889 // Perform a floating point subtraction. |
| 890 var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs)); |
| 891 var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs)); |
| 892 assembler->Goto(&do_fsub); |
| 893 } |
| 894 |
| 895 assembler->Bind(&if_rhsisnotnumber); |
| 896 { |
| 897 // Convert the {rhs} to a Number first. |
| 898 Callable callable = |
| 899 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 900 var_rhs.Bind(assembler->CallStub(callable, context, rhs)); |
| 901 assembler->Goto(&loop); |
| 902 } |
| 903 } |
| 904 } |
| 905 |
| 906 assembler->Bind(&if_lhsisnotnumber); |
| 907 { |
| 908 // Convert the {lhs} to a Number first. |
| 909 Callable callable = |
| 910 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 911 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); |
| 912 assembler->Goto(&loop); |
| 913 } |
| 914 } |
| 915 } |
| 916 |
| 917 assembler->Bind(&do_fsub); |
| 918 { |
| 919 Node* lhs_value = var_fsub_lhs.value(); |
| 920 Node* rhs_value = var_fsub_rhs.value(); |
| 921 Node* value = assembler->Float64Sub(lhs_value, rhs_value); |
| 922 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); |
| 923 assembler->Goto(&end); |
| 924 } |
| 925 assembler->Bind(&end); |
| 926 assembler->Return(var_result.value()); |
| 927 } |
| 928 |
| 929 void Builtins::Generate_Multiply(CodeStubAssembler* assembler) { |
| 930 typedef CodeStubAssembler::Label Label; |
| 931 typedef compiler::Node Node; |
| 932 typedef CodeStubAssembler::Variable Variable; |
| 933 |
| 934 Node* left = assembler->Parameter(0); |
| 935 Node* right = assembler->Parameter(1); |
| 936 Node* context = assembler->Parameter(2); |
| 937 |
| 938 // Shared entry point for floating point multiplication. |
| 939 Label do_fmul(assembler), return_result(assembler); |
| 940 Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64), |
| 941 var_rhs_float64(assembler, MachineRepresentation::kFloat64); |
| 942 |
| 943 Node* number_map = assembler->HeapNumberMapConstant(); |
| 944 |
| 945 // We might need to loop one or two times due to ToNumber conversions. |
| 946 Variable var_lhs(assembler, MachineRepresentation::kTagged), |
| 947 var_rhs(assembler, MachineRepresentation::kTagged), |
| 948 var_result(assembler, MachineRepresentation::kTagged); |
| 949 Variable* loop_variables[] = {&var_lhs, &var_rhs}; |
| 950 Label loop(assembler, 2, loop_variables); |
| 951 var_lhs.Bind(left); |
| 952 var_rhs.Bind(right); |
| 953 assembler->Goto(&loop); |
| 954 assembler->Bind(&loop); |
| 955 { |
| 956 Node* lhs = var_lhs.value(); |
| 957 Node* rhs = var_rhs.value(); |
| 958 |
| 959 Label lhs_is_smi(assembler), lhs_is_not_smi(assembler); |
| 960 assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi); |
| 961 |
| 962 assembler->Bind(&lhs_is_smi); |
| 963 { |
| 964 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); |
| 965 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, |
| 966 &rhs_is_not_smi); |
| 967 |
| 968 assembler->Bind(&rhs_is_smi); |
| 969 { |
| 970 // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi, |
| 971 // in case of overflow. |
| 972 var_result.Bind(assembler->SmiMul(lhs, rhs)); |
| 973 assembler->Goto(&return_result); |
| 974 } |
| 975 |
| 976 assembler->Bind(&rhs_is_not_smi); |
| 977 { |
| 978 Node* rhs_map = assembler->LoadMap(rhs); |
| 979 |
| 980 // Check if {rhs} is a HeapNumber. |
| 981 Label rhs_is_number(assembler), |
| 982 rhs_is_not_number(assembler, Label::kDeferred); |
| 983 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
| 984 &rhs_is_number, &rhs_is_not_number); |
| 985 |
| 986 assembler->Bind(&rhs_is_number); |
| 987 { |
| 988 // Convert {lhs} to a double and multiply it with the value of {rhs}. |
| 989 var_lhs_float64.Bind(assembler->SmiToFloat64(lhs)); |
| 990 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); |
| 991 assembler->Goto(&do_fmul); |
| 992 } |
| 993 |
| 994 assembler->Bind(&rhs_is_not_number); |
| 995 { |
| 996 // Multiplication is commutative, swap {lhs} with {rhs} and loop. |
| 997 var_lhs.Bind(rhs); |
| 998 var_rhs.Bind(lhs); |
| 999 assembler->Goto(&loop); |
| 1000 } |
| 1001 } |
| 1002 } |
| 1003 |
| 1004 assembler->Bind(&lhs_is_not_smi); |
| 1005 { |
| 1006 Node* lhs_map = assembler->LoadMap(lhs); |
| 1007 |
| 1008 // Check if {lhs} is a HeapNumber. |
| 1009 Label lhs_is_number(assembler), |
| 1010 lhs_is_not_number(assembler, Label::kDeferred); |
| 1011 assembler->Branch(assembler->WordEqual(lhs_map, number_map), |
| 1012 &lhs_is_number, &lhs_is_not_number); |
| 1013 |
| 1014 assembler->Bind(&lhs_is_number); |
| 1015 { |
| 1016 // Check if {rhs} is a Smi. |
| 1017 Label rhs_is_smi(assembler), rhs_is_not_smi(assembler); |
| 1018 assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi, |
| 1019 &rhs_is_not_smi); |
| 1020 |
| 1021 assembler->Bind(&rhs_is_smi); |
| 1022 { |
| 1023 // Convert {rhs} to a double and multiply it with the value of {lhs}. |
| 1024 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); |
| 1025 var_rhs_float64.Bind(assembler->SmiToFloat64(rhs)); |
| 1026 assembler->Goto(&do_fmul); |
| 1027 } |
| 1028 |
| 1029 assembler->Bind(&rhs_is_not_smi); |
| 1030 { |
| 1031 Node* rhs_map = assembler->LoadMap(rhs); |
| 1032 |
| 1033 // Check if {rhs} is a HeapNumber. |
| 1034 Label rhs_is_number(assembler), |
| 1035 rhs_is_not_number(assembler, Label::kDeferred); |
| 1036 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
| 1037 &rhs_is_number, &rhs_is_not_number); |
| 1038 |
| 1039 assembler->Bind(&rhs_is_number); |
| 1040 { |
| 1041 // Both {lhs} and {rhs} are HeapNumbers. Load their values and |
| 1042 // multiply them. |
| 1043 var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs)); |
| 1044 var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs)); |
| 1045 assembler->Goto(&do_fmul); |
| 1046 } |
| 1047 |
| 1048 assembler->Bind(&rhs_is_not_number); |
| 1049 { |
| 1050 // Multiplication is commutative, swap {lhs} with {rhs} and loop. |
| 1051 var_lhs.Bind(rhs); |
| 1052 var_rhs.Bind(lhs); |
| 1053 assembler->Goto(&loop); |
| 1054 } |
| 1055 } |
| 1056 } |
| 1057 |
| 1058 assembler->Bind(&lhs_is_not_number); |
| 1059 { |
| 1060 // Convert {lhs} to a Number and loop. |
| 1061 Callable callable = |
| 1062 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 1063 var_lhs.Bind(assembler->CallStub(callable, context, lhs)); |
| 1064 assembler->Goto(&loop); |
| 1065 } |
| 1066 } |
| 1067 } |
| 1068 |
| 1069 assembler->Bind(&do_fmul); |
| 1070 { |
| 1071 Node* value = |
| 1072 assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value()); |
| 1073 Node* result = assembler->ChangeFloat64ToTagged(value); |
| 1074 var_result.Bind(result); |
| 1075 assembler->Goto(&return_result); |
| 1076 } |
| 1077 |
| 1078 assembler->Bind(&return_result); |
| 1079 assembler->Return(var_result.value()); |
| 1080 } |
| 1081 |
| 1082 void Builtins::Generate_Divide(CodeStubAssembler* assembler) { |
| 1083 typedef CodeStubAssembler::Label Label; |
| 1084 typedef compiler::Node Node; |
| 1085 typedef CodeStubAssembler::Variable Variable; |
| 1086 |
| 1087 Node* left = assembler->Parameter(0); |
| 1088 Node* right = assembler->Parameter(1); |
| 1089 Node* context = assembler->Parameter(2); |
| 1090 |
| 1091 // Shared entry point for floating point division. |
| 1092 Label do_fdiv(assembler), end(assembler); |
| 1093 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), |
| 1094 var_divisor_float64(assembler, MachineRepresentation::kFloat64); |
| 1095 |
| 1096 Node* number_map = assembler->HeapNumberMapConstant(); |
| 1097 |
| 1098 // We might need to loop one or two times due to ToNumber conversions. |
| 1099 Variable var_dividend(assembler, MachineRepresentation::kTagged), |
| 1100 var_divisor(assembler, MachineRepresentation::kTagged), |
| 1101 var_result(assembler, MachineRepresentation::kTagged); |
| 1102 Variable* loop_variables[] = {&var_dividend, &var_divisor}; |
| 1103 Label loop(assembler, 2, loop_variables); |
| 1104 var_dividend.Bind(left); |
| 1105 var_divisor.Bind(right); |
| 1106 assembler->Goto(&loop); |
| 1107 assembler->Bind(&loop); |
| 1108 { |
| 1109 Node* dividend = var_dividend.value(); |
| 1110 Node* divisor = var_divisor.value(); |
| 1111 |
| 1112 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); |
| 1113 assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, |
| 1114 ÷nd_is_not_smi); |
| 1115 |
| 1116 assembler->Bind(÷nd_is_smi); |
| 1117 { |
| 1118 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); |
| 1119 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, |
| 1120 &divisor_is_not_smi); |
| 1121 |
| 1122 assembler->Bind(&divisor_is_smi); |
| 1123 { |
| 1124 Label bailout(assembler); |
| 1125 |
| 1126 // Do floating point division if {divisor} is zero. |
| 1127 assembler->GotoIf( |
| 1128 assembler->WordEqual(divisor, assembler->IntPtrConstant(0)), |
| 1129 &bailout); |
| 1130 |
| 1131 // Do floating point division {dividend} is zero and {divisor} is |
| 1132 // negative. |
| 1133 Label dividend_is_zero(assembler), dividend_is_not_zero(assembler); |
| 1134 assembler->Branch( |
| 1135 assembler->WordEqual(dividend, assembler->IntPtrConstant(0)), |
| 1136 ÷nd_is_zero, ÷nd_is_not_zero); |
| 1137 |
| 1138 assembler->Bind(÷nd_is_zero); |
| 1139 { |
| 1140 assembler->GotoIf( |
| 1141 assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)), |
| 1142 &bailout); |
| 1143 assembler->Goto(÷nd_is_not_zero); |
| 1144 } |
| 1145 assembler->Bind(÷nd_is_not_zero); |
| 1146 |
| 1147 Node* untagged_divisor = assembler->SmiUntag(divisor); |
| 1148 Node* untagged_dividend = assembler->SmiUntag(dividend); |
| 1149 |
| 1150 // Do floating point division if {dividend} is kMinInt (or kMinInt - 1 |
| 1151 // if the Smi size is 31) and {divisor} is -1. |
| 1152 Label divisor_is_minus_one(assembler), |
| 1153 divisor_is_not_minus_one(assembler); |
| 1154 assembler->Branch(assembler->Word32Equal(untagged_divisor, |
| 1155 assembler->Int32Constant(-1)), |
| 1156 &divisor_is_minus_one, &divisor_is_not_minus_one); |
| 1157 |
| 1158 assembler->Bind(&divisor_is_minus_one); |
| 1159 { |
| 1160 assembler->GotoIf( |
| 1161 assembler->Word32Equal( |
| 1162 untagged_dividend, |
| 1163 assembler->Int32Constant( |
| 1164 kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))), |
| 1165 &bailout); |
| 1166 assembler->Goto(&divisor_is_not_minus_one); |
| 1167 } |
| 1168 assembler->Bind(&divisor_is_not_minus_one); |
| 1169 |
| 1170 // TODO(epertoso): consider adding a machine instruction that returns |
| 1171 // both the result and the remainder. |
| 1172 Node* untagged_result = |
| 1173 assembler->Int32Div(untagged_dividend, untagged_divisor); |
| 1174 Node* truncated = |
| 1175 assembler->Int32Mul(untagged_result, untagged_divisor); |
| 1176 // Do floating point division if the remainder is not 0. |
| 1177 assembler->GotoIf( |
| 1178 assembler->Word32NotEqual(untagged_dividend, truncated), &bailout); |
| 1179 var_result.Bind(assembler->SmiTag(untagged_result)); |
| 1180 assembler->Goto(&end); |
| 1181 |
| 1182 // Bailout: convert {dividend} and {divisor} to double and do double |
| 1183 // division. |
| 1184 assembler->Bind(&bailout); |
| 1185 { |
| 1186 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); |
| 1187 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); |
| 1188 assembler->Goto(&do_fdiv); |
| 1189 } |
| 1190 } |
| 1191 |
| 1192 assembler->Bind(&divisor_is_not_smi); |
| 1193 { |
| 1194 Node* divisor_map = assembler->LoadMap(divisor); |
| 1195 |
| 1196 // Check if {divisor} is a HeapNumber. |
| 1197 Label divisor_is_number(assembler), |
| 1198 divisor_is_not_number(assembler, Label::kDeferred); |
| 1199 assembler->Branch(assembler->WordEqual(divisor_map, number_map), |
| 1200 &divisor_is_number, &divisor_is_not_number); |
| 1201 |
| 1202 assembler->Bind(&divisor_is_number); |
| 1203 { |
| 1204 // Convert {dividend} to a double and divide it with the value of |
| 1205 // {divisor}. |
| 1206 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); |
| 1207 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); |
| 1208 assembler->Goto(&do_fdiv); |
| 1209 } |
| 1210 |
| 1211 assembler->Bind(&divisor_is_not_number); |
| 1212 { |
| 1213 // Convert {divisor} to a number and loop. |
| 1214 Callable callable = |
| 1215 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 1216 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); |
| 1217 assembler->Goto(&loop); |
| 1218 } |
| 1219 } |
| 1220 } |
| 1221 |
| 1222 assembler->Bind(÷nd_is_not_smi); |
| 1223 { |
| 1224 Node* dividend_map = assembler->LoadMap(dividend); |
| 1225 |
| 1226 // Check if {dividend} is a HeapNumber. |
| 1227 Label dividend_is_number(assembler), |
| 1228 dividend_is_not_number(assembler, Label::kDeferred); |
| 1229 assembler->Branch(assembler->WordEqual(dividend_map, number_map), |
| 1230 ÷nd_is_number, ÷nd_is_not_number); |
| 1231 |
| 1232 assembler->Bind(÷nd_is_number); |
| 1233 { |
| 1234 // Check if {divisor} is a Smi. |
| 1235 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); |
| 1236 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, |
| 1237 &divisor_is_not_smi); |
| 1238 |
| 1239 assembler->Bind(&divisor_is_smi); |
| 1240 { |
| 1241 // Convert {divisor} to a double and use it for a floating point |
| 1242 // division. |
| 1243 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); |
| 1244 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); |
| 1245 assembler->Goto(&do_fdiv); |
| 1246 } |
| 1247 |
| 1248 assembler->Bind(&divisor_is_not_smi); |
| 1249 { |
| 1250 Node* divisor_map = assembler->LoadMap(divisor); |
| 1251 |
| 1252 // Check if {divisor} is a HeapNumber. |
| 1253 Label divisor_is_number(assembler), |
| 1254 divisor_is_not_number(assembler, Label::kDeferred); |
| 1255 assembler->Branch(assembler->WordEqual(divisor_map, number_map), |
| 1256 &divisor_is_number, &divisor_is_not_number); |
| 1257 |
| 1258 assembler->Bind(&divisor_is_number); |
| 1259 { |
| 1260 // Both {dividend} and {divisor} are HeapNumbers. Load their values |
| 1261 // and divide them. |
| 1262 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); |
| 1263 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); |
| 1264 assembler->Goto(&do_fdiv); |
| 1265 } |
| 1266 |
| 1267 assembler->Bind(&divisor_is_not_number); |
| 1268 { |
| 1269 // Convert {divisor} to a number and loop. |
| 1270 Callable callable = |
| 1271 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 1272 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); |
| 1273 assembler->Goto(&loop); |
| 1274 } |
| 1275 } |
| 1276 } |
| 1277 |
| 1278 assembler->Bind(÷nd_is_not_number); |
| 1279 { |
| 1280 // Convert {dividend} to a Number and loop. |
| 1281 Callable callable = |
| 1282 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 1283 var_dividend.Bind(assembler->CallStub(callable, context, dividend)); |
| 1284 assembler->Goto(&loop); |
| 1285 } |
| 1286 } |
| 1287 } |
| 1288 |
| 1289 assembler->Bind(&do_fdiv); |
| 1290 { |
| 1291 Node* value = assembler->Float64Div(var_dividend_float64.value(), |
| 1292 var_divisor_float64.value()); |
| 1293 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); |
| 1294 assembler->Goto(&end); |
| 1295 } |
| 1296 assembler->Bind(&end); |
| 1297 assembler->Return(var_result.value()); |
| 1298 } |
| 1299 |
| 1300 void Builtins::Generate_Modulus(CodeStubAssembler* assembler) { |
| 1301 typedef CodeStubAssembler::Label Label; |
| 1302 typedef compiler::Node Node; |
| 1303 typedef CodeStubAssembler::Variable Variable; |
| 1304 |
| 1305 Node* left = assembler->Parameter(0); |
| 1306 Node* right = assembler->Parameter(1); |
| 1307 Node* context = assembler->Parameter(2); |
| 1308 |
| 1309 Variable var_result(assembler, MachineRepresentation::kTagged); |
| 1310 Label return_result(assembler, &var_result); |
| 1311 |
| 1312 // Shared entry point for floating point modulus. |
| 1313 Label do_fmod(assembler); |
| 1314 Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64), |
| 1315 var_divisor_float64(assembler, MachineRepresentation::kFloat64); |
| 1316 |
| 1317 Node* number_map = assembler->HeapNumberMapConstant(); |
| 1318 |
| 1319 // We might need to loop one or two times due to ToNumber conversions. |
| 1320 Variable var_dividend(assembler, MachineRepresentation::kTagged), |
| 1321 var_divisor(assembler, MachineRepresentation::kTagged); |
| 1322 Variable* loop_variables[] = {&var_dividend, &var_divisor}; |
| 1323 Label loop(assembler, 2, loop_variables); |
| 1324 var_dividend.Bind(left); |
| 1325 var_divisor.Bind(right); |
| 1326 assembler->Goto(&loop); |
| 1327 assembler->Bind(&loop); |
| 1328 { |
| 1329 Node* dividend = var_dividend.value(); |
| 1330 Node* divisor = var_divisor.value(); |
| 1331 |
| 1332 Label dividend_is_smi(assembler), dividend_is_not_smi(assembler); |
| 1333 assembler->Branch(assembler->WordIsSmi(dividend), ÷nd_is_smi, |
| 1334 ÷nd_is_not_smi); |
| 1335 |
| 1336 assembler->Bind(÷nd_is_smi); |
| 1337 { |
| 1338 Label dividend_is_not_zero(assembler); |
| 1339 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); |
| 1340 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, |
| 1341 &divisor_is_not_smi); |
| 1342 |
| 1343 assembler->Bind(&divisor_is_smi); |
| 1344 { |
| 1345 // Compute the modulus of two Smis. |
| 1346 var_result.Bind(assembler->SmiMod(dividend, divisor)); |
| 1347 assembler->Goto(&return_result); |
| 1348 } |
| 1349 |
| 1350 assembler->Bind(&divisor_is_not_smi); |
| 1351 { |
| 1352 Node* divisor_map = assembler->LoadMap(divisor); |
| 1353 |
| 1354 // Check if {divisor} is a HeapNumber. |
| 1355 Label divisor_is_number(assembler), |
| 1356 divisor_is_not_number(assembler, Label::kDeferred); |
| 1357 assembler->Branch(assembler->WordEqual(divisor_map, number_map), |
| 1358 &divisor_is_number, &divisor_is_not_number); |
| 1359 |
| 1360 assembler->Bind(&divisor_is_number); |
| 1361 { |
| 1362 // Convert {dividend} to a double and compute its modulus with the |
| 1363 // value of {dividend}. |
| 1364 var_dividend_float64.Bind(assembler->SmiToFloat64(dividend)); |
| 1365 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); |
| 1366 assembler->Goto(&do_fmod); |
| 1367 } |
| 1368 |
| 1369 assembler->Bind(&divisor_is_not_number); |
| 1370 { |
| 1371 // Convert {divisor} to a number and loop. |
| 1372 Callable callable = |
| 1373 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 1374 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); |
| 1375 assembler->Goto(&loop); |
| 1376 } |
| 1377 } |
| 1378 } |
| 1379 |
| 1380 assembler->Bind(÷nd_is_not_smi); |
| 1381 { |
| 1382 Node* dividend_map = assembler->LoadMap(dividend); |
| 1383 |
| 1384 // Check if {dividend} is a HeapNumber. |
| 1385 Label dividend_is_number(assembler), |
| 1386 dividend_is_not_number(assembler, Label::kDeferred); |
| 1387 assembler->Branch(assembler->WordEqual(dividend_map, number_map), |
| 1388 ÷nd_is_number, ÷nd_is_not_number); |
| 1389 |
| 1390 assembler->Bind(÷nd_is_number); |
| 1391 { |
| 1392 // Check if {divisor} is a Smi. |
| 1393 Label divisor_is_smi(assembler), divisor_is_not_smi(assembler); |
| 1394 assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi, |
| 1395 &divisor_is_not_smi); |
| 1396 |
| 1397 assembler->Bind(&divisor_is_smi); |
| 1398 { |
| 1399 // Convert {divisor} to a double and compute {dividend}'s modulus with |
| 1400 // it. |
| 1401 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); |
| 1402 var_divisor_float64.Bind(assembler->SmiToFloat64(divisor)); |
| 1403 assembler->Goto(&do_fmod); |
| 1404 } |
| 1405 |
| 1406 assembler->Bind(&divisor_is_not_smi); |
| 1407 { |
| 1408 Node* divisor_map = assembler->LoadMap(divisor); |
| 1409 |
| 1410 // Check if {divisor} is a HeapNumber. |
| 1411 Label divisor_is_number(assembler), |
| 1412 divisor_is_not_number(assembler, Label::kDeferred); |
| 1413 assembler->Branch(assembler->WordEqual(divisor_map, number_map), |
| 1414 &divisor_is_number, &divisor_is_not_number); |
| 1415 |
| 1416 assembler->Bind(&divisor_is_number); |
| 1417 { |
| 1418 // Both {dividend} and {divisor} are HeapNumbers. Load their values |
| 1419 // and compute their modulus. |
| 1420 var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend)); |
| 1421 var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor)); |
| 1422 assembler->Goto(&do_fmod); |
| 1423 } |
| 1424 |
| 1425 assembler->Bind(&divisor_is_not_number); |
| 1426 { |
| 1427 // Convert {divisor} to a number and loop. |
| 1428 Callable callable = |
| 1429 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 1430 var_divisor.Bind(assembler->CallStub(callable, context, divisor)); |
| 1431 assembler->Goto(&loop); |
| 1432 } |
| 1433 } |
| 1434 } |
| 1435 |
| 1436 assembler->Bind(÷nd_is_not_number); |
| 1437 { |
| 1438 // Convert {dividend} to a Number and loop. |
| 1439 Callable callable = |
| 1440 CodeFactory::NonNumberToNumber(assembler->isolate()); |
| 1441 var_dividend.Bind(assembler->CallStub(callable, context, dividend)); |
| 1442 assembler->Goto(&loop); |
| 1443 } |
| 1444 } |
| 1445 } |
| 1446 |
| 1447 assembler->Bind(&do_fmod); |
| 1448 { |
| 1449 Node* value = assembler->Float64Mod(var_dividend_float64.value(), |
| 1450 var_divisor_float64.value()); |
| 1451 var_result.Bind(assembler->ChangeFloat64ToTagged(value)); |
| 1452 assembler->Goto(&return_result); |
| 1453 } |
| 1454 |
| 1455 assembler->Bind(&return_result); |
| 1456 assembler->Return(var_result.value()); |
| 1457 } |
| 1458 |
| 1459 void Builtins::Generate_ShiftLeft(CodeStubAssembler* assembler) { |
| 1460 compiler::Node* left = assembler->Parameter(0); |
| 1461 compiler::Node* right = assembler->Parameter(1); |
| 1462 compiler::Node* context = assembler->Parameter(2); |
| 1463 |
| 1464 using compiler::Node; |
| 1465 |
| 1466 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); |
| 1467 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); |
| 1468 Node* shift_count = |
| 1469 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); |
| 1470 Node* value = assembler->Word32Shl(lhs_value, shift_count); |
| 1471 Node* result = assembler->ChangeInt32ToTagged(value); |
| 1472 assembler->Return(result); |
| 1473 } |
| 1474 |
| 1475 void Builtins::Generate_ShiftRight(CodeStubAssembler* assembler) { |
| 1476 compiler::Node* left = assembler->Parameter(0); |
| 1477 compiler::Node* right = assembler->Parameter(1); |
| 1478 compiler::Node* context = assembler->Parameter(2); |
| 1479 |
| 1480 using compiler::Node; |
| 1481 |
| 1482 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); |
| 1483 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); |
| 1484 Node* shift_count = |
| 1485 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); |
| 1486 Node* value = assembler->Word32Sar(lhs_value, shift_count); |
| 1487 Node* result = assembler->ChangeInt32ToTagged(value); |
| 1488 assembler->Return(result); |
| 1489 } |
| 1490 |
| 1491 void Builtins::Generate_ShiftRightLogical(CodeStubAssembler* assembler) { |
| 1492 compiler::Node* left = assembler->Parameter(0); |
| 1493 compiler::Node* right = assembler->Parameter(1); |
| 1494 compiler::Node* context = assembler->Parameter(2); |
| 1495 |
| 1496 using compiler::Node; |
| 1497 |
| 1498 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); |
| 1499 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); |
| 1500 Node* shift_count = |
| 1501 assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f)); |
| 1502 Node* value = assembler->Word32Shr(lhs_value, shift_count); |
| 1503 Node* result = assembler->ChangeUint32ToTagged(value); |
| 1504 assembler->Return(result); |
| 1505 } |
| 1506 |
| 1507 void Builtins::Generate_BitwiseAnd(CodeStubAssembler* assembler) { |
| 1508 compiler::Node* left = assembler->Parameter(0); |
| 1509 compiler::Node* right = assembler->Parameter(1); |
| 1510 compiler::Node* context = assembler->Parameter(2); |
| 1511 |
| 1512 using compiler::Node; |
| 1513 |
| 1514 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); |
| 1515 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); |
| 1516 Node* value = assembler->Word32And(lhs_value, rhs_value); |
| 1517 Node* result = assembler->ChangeInt32ToTagged(value); |
| 1518 assembler->Return(result); |
| 1519 } |
| 1520 |
| 1521 void Builtins::Generate_BitwiseOr(CodeStubAssembler* assembler) { |
| 1522 compiler::Node* left = assembler->Parameter(0); |
| 1523 compiler::Node* right = assembler->Parameter(1); |
| 1524 compiler::Node* context = assembler->Parameter(2); |
| 1525 |
| 1526 using compiler::Node; |
| 1527 |
| 1528 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); |
| 1529 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); |
| 1530 Node* value = assembler->Word32Or(lhs_value, rhs_value); |
| 1531 Node* result = assembler->ChangeInt32ToTagged(value); |
| 1532 assembler->Return(result); |
| 1533 } |
| 1534 |
| 1535 void Builtins::Generate_BitwiseXor(CodeStubAssembler* assembler) { |
| 1536 compiler::Node* left = assembler->Parameter(0); |
| 1537 compiler::Node* right = assembler->Parameter(1); |
| 1538 compiler::Node* context = assembler->Parameter(2); |
| 1539 |
| 1540 using compiler::Node; |
| 1541 |
| 1542 Node* lhs_value = assembler->TruncateTaggedToWord32(context, left); |
| 1543 Node* rhs_value = assembler->TruncateTaggedToWord32(context, right); |
| 1544 Node* value = assembler->Word32Xor(lhs_value, rhs_value); |
| 1545 Node* result = assembler->ChangeInt32ToTagged(value); |
| 1546 assembler->Return(result); |
| 1547 } |
| 1548 |
| 1549 void Builtins::Generate_LessThan(CodeStubAssembler* assembler) { |
| 1550 compiler::Node* lhs = assembler->Parameter(0); |
| 1551 compiler::Node* rhs = assembler->Parameter(1); |
| 1552 compiler::Node* context = assembler->Parameter(2); |
| 1553 |
| 1554 assembler->Return(assembler->RelationalComparison( |
| 1555 CodeStubAssembler::kLessThan, lhs, rhs, context)); |
| 1556 } |
| 1557 |
| 1558 void Builtins::Generate_LessThanOrEqual(CodeStubAssembler* assembler) { |
| 1559 compiler::Node* lhs = assembler->Parameter(0); |
| 1560 compiler::Node* rhs = assembler->Parameter(1); |
| 1561 compiler::Node* context = assembler->Parameter(2); |
| 1562 |
| 1563 assembler->Return(assembler->RelationalComparison( |
| 1564 CodeStubAssembler::kLessThanOrEqual, lhs, rhs, context)); |
| 1565 } |
| 1566 |
| 1567 void Builtins::Generate_GreaterThan(CodeStubAssembler* assembler) { |
| 1568 compiler::Node* lhs = assembler->Parameter(0); |
| 1569 compiler::Node* rhs = assembler->Parameter(1); |
| 1570 compiler::Node* context = assembler->Parameter(2); |
| 1571 |
| 1572 assembler->Return(assembler->RelationalComparison( |
| 1573 CodeStubAssembler::kGreaterThan, lhs, rhs, context)); |
| 1574 } |
| 1575 |
| 1576 void Builtins::Generate_GreaterThanOrEqual(CodeStubAssembler* assembler) { |
| 1577 compiler::Node* lhs = assembler->Parameter(0); |
| 1578 compiler::Node* rhs = assembler->Parameter(1); |
| 1579 compiler::Node* context = assembler->Parameter(2); |
| 1580 |
| 1581 assembler->Return(assembler->RelationalComparison( |
| 1582 CodeStubAssembler::kGreaterThanOrEqual, lhs, rhs, context)); |
| 1583 } |
| 1584 |
| 1585 void Builtins::Generate_Equal(CodeStubAssembler* assembler) { |
| 1586 compiler::Node* lhs = assembler->Parameter(0); |
| 1587 compiler::Node* rhs = assembler->Parameter(1); |
| 1588 compiler::Node* context = assembler->Parameter(2); |
| 1589 |
| 1590 assembler->Return(assembler->Equal(CodeStubAssembler::kDontNegateResult, lhs, |
| 1591 rhs, context)); |
| 1592 } |
| 1593 |
| 1594 void Builtins::Generate_NotEqual(CodeStubAssembler* assembler) { |
| 1595 compiler::Node* lhs = assembler->Parameter(0); |
| 1596 compiler::Node* rhs = assembler->Parameter(1); |
| 1597 compiler::Node* context = assembler->Parameter(2); |
| 1598 |
| 1599 assembler->Return( |
| 1600 assembler->Equal(CodeStubAssembler::kNegateResult, lhs, rhs, context)); |
| 1601 } |
| 1602 |
| 1603 void Builtins::Generate_StrictEqual(CodeStubAssembler* assembler) { |
| 1604 compiler::Node* lhs = assembler->Parameter(0); |
| 1605 compiler::Node* rhs = assembler->Parameter(1); |
| 1606 compiler::Node* context = assembler->Parameter(2); |
| 1607 |
| 1608 assembler->Return(assembler->StrictEqual(CodeStubAssembler::kDontNegateResult, |
| 1609 lhs, rhs, context)); |
| 1610 } |
| 1611 |
| 1612 void Builtins::Generate_StrictNotEqual(CodeStubAssembler* assembler) { |
| 1613 compiler::Node* lhs = assembler->Parameter(0); |
| 1614 compiler::Node* rhs = assembler->Parameter(1); |
| 1615 compiler::Node* context = assembler->Parameter(2); |
| 1616 |
| 1617 assembler->Return(assembler->StrictEqual(CodeStubAssembler::kNegateResult, |
| 1618 lhs, rhs, context)); |
| 1619 } |
| 1620 |
372 } // namespace internal | 1621 } // namespace internal |
373 } // namespace v8 | 1622 } // namespace v8 |
OLD | NEW |