| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| 11 #include "vm/ast_printer.h" | 11 #include "vm/ast_printer.h" |
| 12 #include "vm/dart_entry.h" |
| 12 #include "vm/il_printer.h" | 13 #include "vm/il_printer.h" |
| 13 #include "vm/locations.h" | 14 #include "vm/locations.h" |
| 14 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
| 15 #include "vm/parser.h" | 16 #include "vm/parser.h" |
| 16 #include "vm/stub_code.h" | 17 #include "vm/stub_code.h" |
| 17 #include "vm/symbols.h" | 18 #include "vm/symbols.h" |
| 18 | 19 |
| 19 namespace dart { | 20 namespace dart { |
| 20 | 21 |
| 21 DECLARE_FLAG(bool, print_ast); | 22 DECLARE_FLAG(bool, print_ast); |
| (...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 num_fixed_params + num_opt_pos_params + num_opt_named_params; | 629 num_fixed_params + num_opt_pos_params + num_opt_named_params; |
| 629 ASSERT(function.NumParameters() == num_params); | 630 ASSERT(function.NumParameters() == num_params); |
| 630 ASSERT(parsed_function().first_parameter_index() == | 631 ASSERT(parsed_function().first_parameter_index() == |
| 631 ParsedFunction::kFirstLocalSlotIndex); | 632 ParsedFunction::kFirstLocalSlotIndex); |
| 632 | 633 |
| 633 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, | 634 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, |
| 634 // where num_pos_args is the number of positional arguments passed in. | 635 // where num_pos_args is the number of positional arguments passed in. |
| 635 const int min_num_pos_args = num_fixed_params; | 636 const int min_num_pos_args = num_fixed_params; |
| 636 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; | 637 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; |
| 637 | 638 |
| 638 // Number of positional args is the second Smi in descriptor array (R10). | 639 __ movq(RCX, |
| 639 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); | 640 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
| 640 // Check that min_num_pos_args <= num_pos_args. | 641 // Check that min_num_pos_args <= num_pos_args. |
| 641 Label wrong_num_arguments; | 642 Label wrong_num_arguments; |
| 642 __ cmpq(RCX, Immediate(Smi::RawValue(min_num_pos_args))); | 643 __ cmpq(RCX, Immediate(Smi::RawValue(min_num_pos_args))); |
| 643 __ j(LESS, &wrong_num_arguments); | 644 __ j(LESS, &wrong_num_arguments); |
| 644 // Check that num_pos_args <= max_num_pos_args. | 645 // Check that num_pos_args <= max_num_pos_args. |
| 645 __ cmpq(RCX, Immediate(Smi::RawValue(max_num_pos_args))); | 646 __ cmpq(RCX, Immediate(Smi::RawValue(max_num_pos_args))); |
| 646 __ j(GREATER, &wrong_num_arguments); | 647 __ j(GREATER, &wrong_num_arguments); |
| 647 | 648 |
| 648 // Copy positional arguments. | 649 // Copy positional arguments. |
| 649 // Argument i passed at fp[1 + num_args - i] is copied | 650 // Argument i passed at fp[1 + num_args - i] is copied |
| 650 // to fp[ParsedFunction::kFirstLocalSlotIndex - i]. | 651 // to fp[ParsedFunction::kFirstLocalSlotIndex - i]. |
| 651 | 652 |
| 652 // Total number of args is the first Smi in args descriptor array (R10). | 653 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 653 __ movq(RBX, FieldAddress(R10, Array::data_offset())); | |
| 654 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. | 654 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. |
| 655 // Let RBX point to the last passed positional argument, i.e. to | 655 // Let RBX point to the last passed positional argument, i.e. to |
| 656 // fp[1 + num_args - (num_pos_args - 1)]. | 656 // fp[1 + num_args - (num_pos_args - 1)]. |
| 657 __ subq(RBX, RCX); | 657 __ subq(RBX, RCX); |
| 658 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize)); | 658 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize)); |
| 659 | 659 |
| 660 // Let RDI point to the last copied positional argument, i.e. to | 660 // Let RDI point to the last copied positional argument, i.e. to |
| 661 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. | 661 // fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)]. |
| 662 const int index = ParsedFunction::kFirstLocalSlotIndex + 1; | 662 const int index = ParsedFunction::kFirstLocalSlotIndex + 1; |
| 663 __ SmiUntag(RCX); | 663 __ SmiUntag(RCX); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | 697 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 698 ASSERT(result != 0); | 698 ASSERT(result != 0); |
| 699 if (result > 0) break; | 699 if (result > 0) break; |
| 700 opt_param[i + 1] = opt_param[i]; | 700 opt_param[i + 1] = opt_param[i]; |
| 701 opt_param_position[i + 1] = opt_param_position[i]; | 701 opt_param_position[i + 1] = opt_param_position[i]; |
| 702 } | 702 } |
| 703 opt_param[i + 1] = parameter; | 703 opt_param[i + 1] = parameter; |
| 704 opt_param_position[i + 1] = pos; | 704 opt_param_position[i + 1] = pos; |
| 705 } | 705 } |
| 706 // Generate code handling each optional parameter in alphabetical order. | 706 // Generate code handling each optional parameter in alphabetical order. |
| 707 // Total number of args is the first Smi in args descriptor array (R10). | 707 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 708 __ movq(RBX, FieldAddress(R10, Array::data_offset())); | 708 __ movq(RCX, |
| 709 // Number of positional args is the second Smi in descriptor array (R10). | 709 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
| 710 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); | |
| 711 __ SmiUntag(RCX); | 710 __ SmiUntag(RCX); |
| 712 // Let RBX point to the first passed argument, i.e. to fp[1 + argc - 0]. | 711 // Let RBX point to the first passed argument, i.e. to fp[1 + argc - 0]. |
| 713 __ leaq(RBX, Address(RBP, RBX, TIMES_4, kWordSize)); // RBX is Smi. | 712 __ leaq(RBX, Address(RBP, RBX, TIMES_4, kWordSize)); // RBX is Smi. |
| 714 // Let EDI point to the name/pos pair of the first named argument. | 713 // Let RDI point to the entry of the first named argument. |
| 715 __ leaq(RDI, FieldAddress(R10, Array::data_offset() + (2 * kWordSize))); | 714 __ leaq(RDI, |
| 715 FieldAddress(R10, ArgumentsDescriptor::first_named_entry_offset())); |
| 716 for (int i = 0; i < num_opt_named_params; i++) { | 716 for (int i = 0; i < num_opt_named_params; i++) { |
| 717 Label load_default_value, assign_optional_parameter, next_parameter; | 717 Label load_default_value, assign_optional_parameter, next_parameter; |
| 718 const int param_pos = opt_param_position[i]; | 718 const int param_pos = opt_param_position[i]; |
| 719 // Check if this named parameter was passed in. | 719 // Check if this named parameter was passed in. |
| 720 __ movq(RAX, Address(RDI, 0)); // Load RAX with the name of the argument. | 720 // Load RAX with the name of the argument. |
| 721 __ movq(RAX, Address(RDI, ArgumentsDescriptor::name_offset())); |
| 721 ASSERT(opt_param[i]->name().IsSymbol()); | 722 ASSERT(opt_param[i]->name().IsSymbol()); |
| 722 __ CompareObject(RAX, opt_param[i]->name()); | 723 __ CompareObject(RAX, opt_param[i]->name()); |
| 723 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); | 724 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 724 // Load RAX with passed-in argument at provided arg_pos, i.e. at | 725 // Load RAX with passed-in argument at provided arg_pos, i.e. at |
| 725 // fp[1 + argc - arg_pos]. | 726 // fp[1 + argc - arg_pos]. |
| 726 __ movq(RAX, Address(RDI, kWordSize)); // RAX is arg_pos as Smi. | 727 __ movq(RAX, Address(RDI, ArgumentsDescriptor::position_offset())); |
| 727 __ addq(RDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. | 728 // RAX is arg_pos as Smi. |
| 729 // Point to next named entry. |
| 730 __ addq(RDI, Immediate(ArgumentsDescriptor::named_entry_size())); |
| 728 __ negq(RAX); | 731 __ negq(RAX); |
| 729 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. | 732 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. |
| 730 __ movq(RAX, argument_addr); | 733 __ movq(RAX, argument_addr); |
| 731 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | 734 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 732 __ Bind(&load_default_value); | 735 __ Bind(&load_default_value); |
| 733 // Load RAX with default argument. | 736 // Load RAX with default argument. |
| 734 const Object& value = Object::ZoneHandle( | 737 const Object& value = Object::ZoneHandle( |
| 735 parsed_function().default_parameter_values().At( | 738 parsed_function().default_parameter_values().At( |
| 736 param_pos - num_fixed_params)); | 739 param_pos - num_fixed_params)); |
| 737 __ LoadObject(RAX, value); | 740 __ LoadObject(RAX, value); |
| 738 __ Bind(&assign_optional_parameter); | 741 __ Bind(&assign_optional_parameter); |
| 739 // Assign RAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. | 742 // Assign RAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. |
| 740 // We do not use the final allocation index of the variable here, i.e. | 743 // We do not use the final allocation index of the variable here, i.e. |
| 741 // scope->VariableAt(i)->index(), because captured variables still need | 744 // scope->VariableAt(i)->index(), because captured variables still need |
| 742 // to be copied to the context that is not yet allocated. | 745 // to be copied to the context that is not yet allocated. |
| 743 const intptr_t computed_param_pos = | 746 const intptr_t computed_param_pos = |
| 744 ParsedFunction::kFirstLocalSlotIndex - param_pos; | 747 ParsedFunction::kFirstLocalSlotIndex - param_pos; |
| 745 const Address param_addr(RBP, (computed_param_pos * kWordSize)); | 748 const Address param_addr(RBP, (computed_param_pos * kWordSize)); |
| 746 __ movq(param_addr, RAX); | 749 __ movq(param_addr, RAX); |
| 747 __ Bind(&next_parameter); | 750 __ Bind(&next_parameter); |
| 748 } | 751 } |
| 749 delete[] opt_param; | 752 delete[] opt_param; |
| 750 delete[] opt_param_position; | 753 delete[] opt_param_position; |
| 751 // Check that RDI now points to the null terminator in the array descriptor. | 754 // Check that RDI now points to the null terminator in the array descriptor. |
| 752 __ cmpq(Address(RDI, 0), raw_null); | 755 __ cmpq(Address(RDI, 0), raw_null); |
| 753 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 756 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 754 } else { | 757 } else { |
| 755 ASSERT(num_opt_pos_params > 0); | 758 ASSERT(num_opt_pos_params > 0); |
| 756 // Number of positional args is the second Smi in descriptor array (R10). | 759 __ movq(RCX, |
| 757 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); | 760 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
| 758 __ SmiUntag(RCX); | 761 __ SmiUntag(RCX); |
| 759 for (int i = 0; i < num_opt_pos_params; i++) { | 762 for (int i = 0; i < num_opt_pos_params; i++) { |
| 760 Label next_parameter; | 763 Label next_parameter; |
| 761 // Handle this optional positonal parameter only if k or fewer positional | 764 // Handle this optional positonal parameter only if k or fewer positional |
| 762 // arguments have been passed, where k is param_pos, the position of this | 765 // arguments have been passed, where k is param_pos, the position of this |
| 763 // optional parameter in the formal parameter list. | 766 // optional parameter in the formal parameter list. |
| 764 const int param_pos = num_fixed_params + i; | 767 const int param_pos = num_fixed_params + i; |
| 765 __ cmpq(RCX, Immediate(param_pos)); | 768 __ cmpq(RCX, Immediate(param_pos)); |
| 766 __ j(GREATER, &next_parameter, Assembler::kNearJump); | 769 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 767 // Load RAX with default argument. | 770 // Load RAX with default argument. |
| 768 const Object& value = Object::ZoneHandle( | 771 const Object& value = Object::ZoneHandle( |
| 769 parsed_function().default_parameter_values().At(i)); | 772 parsed_function().default_parameter_values().At(i)); |
| 770 __ LoadObject(RAX, value); | 773 __ LoadObject(RAX, value); |
| 771 // Assign RAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. | 774 // Assign RAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. |
| 772 // We do not use the final allocation index of the variable here, i.e. | 775 // We do not use the final allocation index of the variable here, i.e. |
| 773 // scope->VariableAt(i)->index(), because captured variables still need | 776 // scope->VariableAt(i)->index(), because captured variables still need |
| 774 // to be copied to the context that is not yet allocated. | 777 // to be copied to the context that is not yet allocated. |
| 775 const intptr_t computed_param_pos = | 778 const intptr_t computed_param_pos = |
| 776 ParsedFunction::kFirstLocalSlotIndex - param_pos; | 779 ParsedFunction::kFirstLocalSlotIndex - param_pos; |
| 777 const Address param_addr(RBP, (computed_param_pos * kWordSize)); | 780 const Address param_addr(RBP, (computed_param_pos * kWordSize)); |
| 778 __ movq(param_addr, RAX); | 781 __ movq(param_addr, RAX); |
| 779 __ Bind(&next_parameter); | 782 __ Bind(&next_parameter); |
| 780 } | 783 } |
| 781 // Total number of args is the first Smi in args descriptor array (R10). | 784 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 782 __ movq(RBX, FieldAddress(R10, Array::data_offset())); | |
| 783 __ SmiUntag(RBX); | 785 __ SmiUntag(RBX); |
| 784 // Check that RCX equals RBX, i.e. no named arguments passed. | 786 // Check that RCX equals RBX, i.e. no named arguments passed. |
| 785 __ cmpq(RCX, RBX); | 787 __ cmpq(RCX, RBX); |
| 786 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 788 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 787 } | 789 } |
| 788 | 790 |
| 789 __ Bind(&wrong_num_arguments); | 791 __ Bind(&wrong_num_arguments); |
| 790 if (StackSize() != 0) { | 792 if (StackSize() != 0) { |
| 791 // We need to unwind the space we reserved for locals and copied parameters. | 793 // We need to unwind the space we reserved for locals and copied parameters. |
| 792 // The NoSuchMethodFunction stub does not expect to see that area on the | 794 // The NoSuchMethodFunction stub does not expect to see that area on the |
| (...skipping 30 matching lines...) Expand all Loading... |
| 823 __ ret(); | 825 __ ret(); |
| 824 | 826 |
| 825 __ Bind(&all_arguments_processed); | 827 __ Bind(&all_arguments_processed); |
| 826 // Nullify originally passed arguments only after they have been copied and | 828 // Nullify originally passed arguments only after they have been copied and |
| 827 // checked, otherwise noSuchMethod would not see their original values. | 829 // checked, otherwise noSuchMethod would not see their original values. |
| 828 // This step can be skipped in case we decide that formal parameters are | 830 // This step can be skipped in case we decide that formal parameters are |
| 829 // implicitly final, since garbage collecting the unmodified value is not | 831 // implicitly final, since garbage collecting the unmodified value is not |
| 830 // an issue anymore. | 832 // an issue anymore. |
| 831 | 833 |
| 832 // R10 : arguments descriptor array. | 834 // R10 : arguments descriptor array. |
| 833 // Total number of args is the first Smi in args descriptor array (R10). | 835 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 834 __ movq(RCX, FieldAddress(R10, Array::data_offset())); | |
| 835 __ SmiUntag(RCX); | 836 __ SmiUntag(RCX); |
| 836 Label null_args_loop, null_args_loop_condition; | 837 Label null_args_loop, null_args_loop_condition; |
| 837 __ jmp(&null_args_loop_condition, Assembler::kNearJump); | 838 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 838 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize); | 839 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize); |
| 839 __ Bind(&null_args_loop); | 840 __ Bind(&null_args_loop); |
| 840 __ movq(original_argument_addr, raw_null); | 841 __ movq(original_argument_addr, raw_null); |
| 841 __ Bind(&null_args_loop_condition); | 842 __ Bind(&null_args_loop_condition); |
| 842 __ decq(RCX); | 843 __ decq(RCX); |
| 843 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); | 844 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 844 } | 845 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 908 #ifdef DEBUG | 909 #ifdef DEBUG |
| 909 ASSERT(!parsed_function().function().HasOptionalParameters()); | 910 ASSERT(!parsed_function().function().HasOptionalParameters()); |
| 910 const bool check_arguments = true; | 911 const bool check_arguments = true; |
| 911 #else | 912 #else |
| 912 const bool check_arguments = function.IsClosureFunction(); | 913 const bool check_arguments = function.IsClosureFunction(); |
| 913 #endif | 914 #endif |
| 914 if (check_arguments) { | 915 if (check_arguments) { |
| 915 __ Comment("Check argument count"); | 916 __ Comment("Check argument count"); |
| 916 // Check that num_fixed <= argc <= num_params. | 917 // Check that num_fixed <= argc <= num_params. |
| 917 Label argc_in_range; | 918 Label argc_in_range; |
| 918 // Total number of args is the first Smi in args descriptor array (R10). | 919 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 919 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | |
| 920 __ cmpq(RAX, Immediate(Smi::RawValue(num_fixed_params))); | 920 __ cmpq(RAX, Immediate(Smi::RawValue(num_fixed_params))); |
| 921 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 921 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
| 922 if (function.IsClosureFunction()) { | 922 if (function.IsClosureFunction()) { |
| 923 if (StackSize() != 0) { | 923 if (StackSize() != 0) { |
| 924 // We need to unwind the space we reserved for locals and copied | 924 // We need to unwind the space we reserved for locals and copied |
| 925 // parameters. The NoSuchMethodFunction stub does not expect to see | 925 // parameters. The NoSuchMethodFunction stub does not expect to see |
| 926 // that area on the stack. | 926 // that area on the stack. |
| 927 __ addq(RSP, Immediate(StackSize() * kWordSize)); | 927 __ addq(RSP, Immediate(StackSize() * kWordSize)); |
| 928 } | 928 } |
| 929 // The call below has an empty stackmap because we have just | 929 // The call below has an empty stackmap because we have just |
| (...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1409 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { | 1409 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { |
| 1410 __ Exchange(mem1, mem2); | 1410 __ Exchange(mem1, mem2); |
| 1411 } | 1411 } |
| 1412 | 1412 |
| 1413 | 1413 |
| 1414 #undef __ | 1414 #undef __ |
| 1415 | 1415 |
| 1416 } // namespace dart | 1416 } // namespace dart |
| 1417 | 1417 |
| 1418 #endif // defined TARGET_ARCH_X64 | 1418 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |