| 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 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 (EDX). | 639 __ movl(ECX, |
| 639 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); | 640 FieldAddress(EDX, 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 __ cmpl(ECX, Immediate(Smi::RawValue(min_num_pos_args))); | 643 __ cmpl(ECX, 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 __ cmpl(ECX, Immediate(Smi::RawValue(max_num_pos_args))); | 646 __ cmpl(ECX, 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 (EDX). | 653 __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
| 653 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); | |
| 654 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. | 654 // Since EBX and ECX are Smi, use TIMES_2 instead of TIMES_4. |
| 655 // Let EBX point to the last passed positional argument, i.e. to | 655 // Let EBX 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 __ subl(EBX, ECX); | 657 __ subl(EBX, ECX); |
| 658 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); | 658 __ leal(EBX, Address(EBP, EBX, TIMES_2, 2 * kWordSize)); |
| 659 | 659 |
| 660 // Let EDI point to the last copied positional argument, i.e. to | 660 // Let EDI 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 __ leal(EDI, Address(EBP, (index * kWordSize))); | 663 __ leal(EDI, Address(EBP, (index * kWordSize))); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 695 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | 695 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 696 ASSERT(result != 0); | 696 ASSERT(result != 0); |
| 697 if (result > 0) break; | 697 if (result > 0) break; |
| 698 opt_param[i + 1] = opt_param[i]; | 698 opt_param[i + 1] = opt_param[i]; |
| 699 opt_param_position[i + 1] = opt_param_position[i]; | 699 opt_param_position[i + 1] = opt_param_position[i]; |
| 700 } | 700 } |
| 701 opt_param[i + 1] = parameter; | 701 opt_param[i + 1] = parameter; |
| 702 opt_param_position[i + 1] = pos; | 702 opt_param_position[i + 1] = pos; |
| 703 } | 703 } |
| 704 // Generate code handling each optional parameter in alphabetical order. | 704 // Generate code handling each optional parameter in alphabetical order. |
| 705 // Total number of args is the first Smi in args descriptor array (EDX). | 705 __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
| 706 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); | 706 __ movl(ECX, |
| 707 // Number of positional args is the second Smi in descriptor array (EDX). | 707 FieldAddress(EDX, ArgumentsDescriptor::positional_count_offset())); |
| 708 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); | |
| 709 __ SmiUntag(ECX); | 708 __ SmiUntag(ECX); |
| 710 // Let EBX point to the first passed argument, i.e. to fp[1 + argc - 0]. | 709 // Let EBX point to the first passed argument, i.e. to fp[1 + argc - 0]. |
| 711 __ leal(EBX, Address(EBP, EBX, TIMES_2, kWordSize)); // EBX is Smi. | 710 __ leal(EBX, Address(EBP, EBX, TIMES_2, kWordSize)); // EBX is Smi. |
| 712 // Let EDI point to the name/pos pair of the first named argument. | 711 // Let EDI point to the entry of the first named argument. |
| 713 __ leal(EDI, FieldAddress(EDX, Array::data_offset() + (2 * kWordSize))); | 712 __ leal(EDI, |
| 713 FieldAddress(EDX, ArgumentsDescriptor::first_named_entry_offset())); |
| 714 for (int i = 0; i < num_opt_named_params; i++) { | 714 for (int i = 0; i < num_opt_named_params; i++) { |
| 715 Label load_default_value, assign_optional_parameter, next_parameter; | 715 Label load_default_value, assign_optional_parameter, next_parameter; |
| 716 const int param_pos = opt_param_position[i]; | 716 const int param_pos = opt_param_position[i]; |
| 717 // Check if this named parameter was passed in. | 717 // Check if this named parameter was passed in. |
| 718 __ movl(EAX, Address(EDI, 0)); // Load EAX with the name of the argument. | 718 // Load EAX with the name of the argument. |
| 719 __ movl(EAX, Address(EDI, ArgumentsDescriptor::name_offset())); |
| 719 ASSERT(opt_param[i]->name().IsSymbol()); | 720 ASSERT(opt_param[i]->name().IsSymbol()); |
| 720 __ CompareObject(EAX, opt_param[i]->name()); | 721 __ CompareObject(EAX, opt_param[i]->name()); |
| 721 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); | 722 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 722 // Load EAX with passed-in argument at provided arg_pos, i.e. at | 723 // Load EAX with passed-in argument at provided arg_pos, i.e. at |
| 723 // fp[1 + argc - arg_pos]. | 724 // fp[1 + argc - arg_pos]. |
| 724 __ movl(EAX, Address(EDI, kWordSize)); // EAX is arg_pos as Smi. | 725 __ movl(EAX, Address(EDI, ArgumentsDescriptor::position_offset())); |
| 725 __ addl(EDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. | 726 // EAX is arg_pos as Smi. |
| 727 // Point to next named entry. |
| 728 __ addl(EDI, Immediate(ArgumentsDescriptor::named_entry_size())); |
| 726 __ negl(EAX); | 729 __ negl(EAX); |
| 727 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. | 730 Address argument_addr(EBX, EAX, TIMES_2, 0); // EAX is a negative Smi. |
| 728 __ movl(EAX, argument_addr); | 731 __ movl(EAX, argument_addr); |
| 729 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | 732 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 730 __ Bind(&load_default_value); | 733 __ Bind(&load_default_value); |
| 731 // Load EAX with default argument. | 734 // Load EAX with default argument. |
| 732 const Object& value = Object::ZoneHandle( | 735 const Object& value = Object::ZoneHandle( |
| 733 parsed_function().default_parameter_values().At( | 736 parsed_function().default_parameter_values().At( |
| 734 param_pos - num_fixed_params)); | 737 param_pos - num_fixed_params)); |
| 735 __ LoadObject(EAX, value); | 738 __ LoadObject(EAX, value); |
| 736 __ Bind(&assign_optional_parameter); | 739 __ Bind(&assign_optional_parameter); |
| 737 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. | 740 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. |
| 738 // We do not use the final allocation index of the variable here, i.e. | 741 // We do not use the final allocation index of the variable here, i.e. |
| 739 // scope->VariableAt(i)->index(), because captured variables still need | 742 // scope->VariableAt(i)->index(), because captured variables still need |
| 740 // to be copied to the context that is not yet allocated. | 743 // to be copied to the context that is not yet allocated. |
| 741 const intptr_t computed_param_pos = | 744 const intptr_t computed_param_pos = |
| 742 ParsedFunction::kFirstLocalSlotIndex - param_pos; | 745 ParsedFunction::kFirstLocalSlotIndex - param_pos; |
| 743 const Address param_addr(EBP, (computed_param_pos * kWordSize)); | 746 const Address param_addr(EBP, (computed_param_pos * kWordSize)); |
| 744 __ movl(param_addr, EAX); | 747 __ movl(param_addr, EAX); |
| 745 __ Bind(&next_parameter); | 748 __ Bind(&next_parameter); |
| 746 } | 749 } |
| 747 delete[] opt_param; | 750 delete[] opt_param; |
| 748 delete[] opt_param_position; | 751 delete[] opt_param_position; |
| 749 // Check that EDI now points to the null terminator in the array descriptor. | 752 // Check that EDI now points to the null terminator in the array descriptor. |
| 750 __ cmpl(Address(EDI, 0), raw_null); | 753 __ cmpl(Address(EDI, 0), raw_null); |
| 751 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 754 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 752 } else { | 755 } else { |
| 753 ASSERT(num_opt_pos_params > 0); | 756 ASSERT(num_opt_pos_params > 0); |
| 754 // Number of positional args is the second Smi in descriptor array (EDX). | 757 __ movl(ECX, |
| 755 __ movl(ECX, FieldAddress(EDX, Array::data_offset() + (1 * kWordSize))); | 758 FieldAddress(EDX, ArgumentsDescriptor::positional_count_offset())); |
| 756 __ SmiUntag(ECX); | 759 __ SmiUntag(ECX); |
| 757 for (int i = 0; i < num_opt_pos_params; i++) { | 760 for (int i = 0; i < num_opt_pos_params; i++) { |
| 758 Label next_parameter; | 761 Label next_parameter; |
| 759 // Handle this optional positonal parameter only if k or fewer positional | 762 // Handle this optional positonal parameter only if k or fewer positional |
| 760 // arguments have been passed, where k is param_pos, the position of this | 763 // arguments have been passed, where k is param_pos, the position of this |
| 761 // optional parameter in the formal parameter list. | 764 // optional parameter in the formal parameter list. |
| 762 const int param_pos = num_fixed_params + i; | 765 const int param_pos = num_fixed_params + i; |
| 763 __ cmpl(ECX, Immediate(param_pos)); | 766 __ cmpl(ECX, Immediate(param_pos)); |
| 764 __ j(GREATER, &next_parameter, Assembler::kNearJump); | 767 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 765 // Load RAX with default argument. | 768 // Load RAX with default argument. |
| 766 const Object& value = Object::ZoneHandle( | 769 const Object& value = Object::ZoneHandle( |
| 767 parsed_function().default_parameter_values().At(i)); | 770 parsed_function().default_parameter_values().At(i)); |
| 768 __ LoadObject(EAX, value); | 771 __ LoadObject(EAX, value); |
| 769 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. | 772 // Assign EAX to fp[ParsedFunction::kFirstLocalSlotIndex - param_pos]. |
| 770 // We do not use the final allocation index of the variable here, i.e. | 773 // We do not use the final allocation index of the variable here, i.e. |
| 771 // scope->VariableAt(i)->index(), because captured variables still need | 774 // scope->VariableAt(i)->index(), because captured variables still need |
| 772 // to be copied to the context that is not yet allocated. | 775 // to be copied to the context that is not yet allocated. |
| 773 const intptr_t computed_param_pos = | 776 const intptr_t computed_param_pos = |
| 774 ParsedFunction::kFirstLocalSlotIndex - param_pos; | 777 ParsedFunction::kFirstLocalSlotIndex - param_pos; |
| 775 const Address param_addr(EBP, (computed_param_pos * kWordSize)); | 778 const Address param_addr(EBP, (computed_param_pos * kWordSize)); |
| 776 __ movl(param_addr, EAX); | 779 __ movl(param_addr, EAX); |
| 777 __ Bind(&next_parameter); | 780 __ Bind(&next_parameter); |
| 778 } | 781 } |
| 779 // Total number of args is the first Smi in args descriptor array (EDX). | 782 __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
| 780 __ movl(EBX, FieldAddress(EDX, Array::data_offset())); | |
| 781 __ SmiUntag(EBX); | 783 __ SmiUntag(EBX); |
| 782 // Check that ECX equals EBX, i.e. no named arguments passed. | 784 // Check that ECX equals EBX, i.e. no named arguments passed. |
| 783 __ cmpl(ECX, EBX); | 785 __ cmpl(ECX, EBX); |
| 784 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 786 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 785 } | 787 } |
| 786 | 788 |
| 787 __ Bind(&wrong_num_arguments); | 789 __ Bind(&wrong_num_arguments); |
| 788 if (StackSize() != 0) { | 790 if (StackSize() != 0) { |
| 789 // We need to unwind the space we reserved for locals and copied parameters. | 791 // We need to unwind the space we reserved for locals and copied parameters. |
| 790 // The NoSuchMethodFunction stub does not expect to see that area on the | 792 // The NoSuchMethodFunction stub does not expect to see that area on the |
| (...skipping 30 matching lines...) Expand all Loading... |
| 821 __ ret(); | 823 __ ret(); |
| 822 | 824 |
| 823 __ Bind(&all_arguments_processed); | 825 __ Bind(&all_arguments_processed); |
| 824 // Nullify originally passed arguments only after they have been copied and | 826 // Nullify originally passed arguments only after they have been copied and |
| 825 // checked, otherwise noSuchMethod would not see their original values. | 827 // checked, otherwise noSuchMethod would not see their original values. |
| 826 // This step can be skipped in case we decide that formal parameters are | 828 // This step can be skipped in case we decide that formal parameters are |
| 827 // implicitly final, since garbage collecting the unmodified value is not | 829 // implicitly final, since garbage collecting the unmodified value is not |
| 828 // an issue anymore. | 830 // an issue anymore. |
| 829 | 831 |
| 830 // EDX : arguments descriptor array. | 832 // EDX : arguments descriptor array. |
| 831 // Total number of args is the first Smi in args descriptor array (EDX). | 833 __ movl(ECX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
| 832 __ movl(ECX, FieldAddress(EDX, Array::data_offset())); | |
| 833 __ SmiUntag(ECX); | 834 __ SmiUntag(ECX); |
| 834 Label null_args_loop, null_args_loop_condition; | 835 Label null_args_loop, null_args_loop_condition; |
| 835 __ jmp(&null_args_loop_condition, Assembler::kNearJump); | 836 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 836 const Address original_argument_addr(EBP, ECX, TIMES_4, 2 * kWordSize); | 837 const Address original_argument_addr(EBP, ECX, TIMES_4, 2 * kWordSize); |
| 837 __ Bind(&null_args_loop); | 838 __ Bind(&null_args_loop); |
| 838 __ movl(original_argument_addr, raw_null); | 839 __ movl(original_argument_addr, raw_null); |
| 839 __ Bind(&null_args_loop_condition); | 840 __ Bind(&null_args_loop_condition); |
| 840 __ decl(ECX); | 841 __ decl(ECX); |
| 841 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); | 842 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 842 } | 843 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 905 #ifdef DEBUG | 906 #ifdef DEBUG |
| 906 ASSERT(!parsed_function().function().HasOptionalParameters()); | 907 ASSERT(!parsed_function().function().HasOptionalParameters()); |
| 907 const bool check_arguments = true; | 908 const bool check_arguments = true; |
| 908 #else | 909 #else |
| 909 const bool check_arguments = function.IsClosureFunction(); | 910 const bool check_arguments = function.IsClosureFunction(); |
| 910 #endif | 911 #endif |
| 911 if (check_arguments) { | 912 if (check_arguments) { |
| 912 __ Comment("Check argument count"); | 913 __ Comment("Check argument count"); |
| 913 // Check that num_fixed <= argc <= num_params. | 914 // Check that num_fixed <= argc <= num_params. |
| 914 Label argc_in_range; | 915 Label argc_in_range; |
| 915 // Total number of args is the first Smi in args descriptor array (EDX). | 916 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
| 916 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); | |
| 917 __ cmpl(EAX, Immediate(Smi::RawValue(num_fixed_params))); | 917 __ cmpl(EAX, Immediate(Smi::RawValue(num_fixed_params))); |
| 918 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 918 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
| 919 if (function.IsClosureFunction()) { | 919 if (function.IsClosureFunction()) { |
| 920 if (StackSize() != 0) { | 920 if (StackSize() != 0) { |
| 921 // We need to unwind the space we reserved for locals and copied | 921 // We need to unwind the space we reserved for locals and copied |
| 922 // parameters. The NoSuchMethodFunction stub does not expect to see | 922 // parameters. The NoSuchMethodFunction stub does not expect to see |
| 923 // that area on the stack. | 923 // that area on the stack. |
| 924 __ addl(ESP, Immediate(StackSize() * kWordSize)); | 924 __ addl(ESP, Immediate(StackSize() * kWordSize)); |
| 925 } | 925 } |
| 926 // The call below has an empty stackmap because we have just | 926 // The call below has an empty stackmap because we have just |
| (...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1431 __ popl(ECX); | 1431 __ popl(ECX); |
| 1432 __ popl(EAX); | 1432 __ popl(EAX); |
| 1433 } | 1433 } |
| 1434 | 1434 |
| 1435 | 1435 |
| 1436 #undef __ | 1436 #undef __ |
| 1437 | 1437 |
| 1438 } // namespace dart | 1438 } // namespace dart |
| 1439 | 1439 |
| 1440 #endif // defined TARGET_ARCH_IA32 | 1440 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |