| 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 "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 FlowGraphCompiler::~FlowGraphCompiler() { | 40 FlowGraphCompiler::~FlowGraphCompiler() { |
| 41 // BlockInfos are zone-allocated, so their destructors are not called. | 41 // BlockInfos are zone-allocated, so their destructors are not called. |
| 42 // Verify the labels explicitly here. | 42 // Verify the labels explicitly here. |
| 43 for (int i = 0; i < block_info_.length(); ++i) { | 43 for (int i = 0; i < block_info_.length(); ++i) { |
| 44 ASSERT(!block_info_[i]->label.IsLinked()); | 44 ASSERT(!block_info_[i]->label.IsLinked()); |
| 45 ASSERT(!block_info_[i]->label.HasNear()); | 45 ASSERT(!block_info_[i]->label.HasNear()); |
| 46 } | 46 } |
| 47 } | 47 } |
| 48 | 48 |
| 49 | 49 |
| 50 intptr_t FlowGraphCompiler::StackSize() const { |
| 51 return parsed_function_.stack_local_count() + |
| 52 parsed_function_.copied_parameter_count(); |
| 53 } |
| 54 |
| 55 |
| 50 void FlowGraphCompiler::Bailout(const char* reason) { | 56 void FlowGraphCompiler::Bailout(const char* reason) { |
| 51 const char* kFormat = "FlowGraphCompiler Bailout: %s %s."; | 57 const char* kFormat = "FlowGraphCompiler Bailout: %s %s."; |
| 52 const char* function_name = parsed_function_.function().ToCString(); | 58 const char* function_name = parsed_function_.function().ToCString(); |
| 53 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | 59 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |
| 54 char* chars = reinterpret_cast<char*>( | 60 char* chars = reinterpret_cast<char*>( |
| 55 Isolate::Current()->current_zone()->Allocate(len)); | 61 Isolate::Current()->current_zone()->Allocate(len)); |
| 56 OS::SNPrint(chars, len, kFormat, function_name, reason); | 62 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 57 const Error& error = Error::Handle( | 63 const Error& error = Error::Handle( |
| 58 LanguageError::New(String::Handle(String::New(chars)))); | 64 LanguageError::New(String::Handle(String::New(chars)))); |
| 59 Isolate::Current()->long_jump_base()->Jump(1, error); | 65 Isolate::Current()->long_jump_base()->Jump(1, error); |
| (...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 } | 656 } |
| 651 | 657 |
| 652 | 658 |
| 653 void FlowGraphCompiler::VisitReturn(ReturnInstr* instr) { | 659 void FlowGraphCompiler::VisitReturn(ReturnInstr* instr) { |
| 654 LoadValue(RAX, instr->value()); | 660 LoadValue(RAX, instr->value()); |
| 655 | 661 |
| 656 #ifdef DEBUG | 662 #ifdef DEBUG |
| 657 // Check that the entry stack size matches the exit stack size. | 663 // Check that the entry stack size matches the exit stack size. |
| 658 __ movq(R10, RBP); | 664 __ movq(R10, RBP); |
| 659 __ subq(R10, RSP); | 665 __ subq(R10, RSP); |
| 660 __ cmpq(R10, Immediate(parsed_function_.stack_local_count() * kWordSize)); | 666 __ cmpq(R10, Immediate(StackSize() * kWordSize)); |
| 661 Label stack_ok; | 667 Label stack_ok; |
| 662 __ j(EQUAL, &stack_ok, Assembler::kNearJump); | 668 __ j(EQUAL, &stack_ok, Assembler::kNearJump); |
| 663 __ Stop("Exit stack size does not match the entry stack size."); | 669 __ Stop("Exit stack size does not match the entry stack size."); |
| 664 __ Bind(&stack_ok); | 670 __ Bind(&stack_ok); |
| 665 #endif // DEBUG. | 671 #endif // DEBUG. |
| 666 | 672 |
| 667 if (FLAG_trace_functions) { | 673 if (FLAG_trace_functions) { |
| 668 __ pushq(RAX); // Preserve result. | 674 __ pushq(RAX); // Preserve result. |
| 669 const Function& function = | 675 const Function& function = |
| 670 Function::ZoneHandle(parsed_function_.function().raw()); | 676 Function::ZoneHandle(parsed_function_.function().raw()); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 __ cmpq(RAX, RDX); | 715 __ cmpq(RAX, RDX); |
| 710 if (negated) { | 716 if (negated) { |
| 711 __ j(EQUAL, &block_info_[instr->true_successor()->block_number()]->label); | 717 __ j(EQUAL, &block_info_[instr->true_successor()->block_number()]->label); |
| 712 } else { | 718 } else { |
| 713 __ j(NOT_EQUAL, | 719 __ j(NOT_EQUAL, |
| 714 &block_info_[instr->false_successor()->block_number()]->label); | 720 &block_info_[instr->false_successor()->block_number()]->label); |
| 715 } | 721 } |
| 716 } | 722 } |
| 717 | 723 |
| 718 | 724 |
| 725 // Coped from CodeGenerator::CopyParameters (CodeGenerator will be deprecated). |
| 726 void FlowGraphCompiler::CopyParameters() { |
| 727 const Function& function = parsed_function_.function(); |
| 728 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 729 const int num_fixed_params = function.num_fixed_parameters(); |
| 730 const int num_opt_params = function.num_optional_parameters(); |
| 731 ASSERT(parsed_function_.first_parameter_index() == -1); |
| 732 // Copy positional arguments. |
| 733 // Check that no fewer than num_fixed_params positional arguments are passed |
| 734 // in and that no more than num_params arguments are passed in. |
| 735 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i]. |
| 736 const int num_params = num_fixed_params + num_opt_params; |
| 737 |
| 738 // Total number of args is the first Smi in args descriptor array (R10). |
| 739 __ movq(RBX, FieldAddress(R10, Array::data_offset())); |
| 740 // Check that num_args <= num_params. |
| 741 Label wrong_num_arguments; |
| 742 __ cmpq(RBX, Immediate(Smi::RawValue(num_params))); |
| 743 __ j(GREATER, &wrong_num_arguments); |
| 744 // Number of positional args is the second Smi in descriptor array (R10). |
| 745 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); |
| 746 // Check that num_pos_args >= num_fixed_params. |
| 747 __ cmpq(RCX, Immediate(Smi::RawValue(num_fixed_params))); |
| 748 __ j(LESS, &wrong_num_arguments); |
| 749 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. |
| 750 // Let RBX point to the last passed positional argument, i.e. to |
| 751 // fp[1 + num_args - (num_pos_args - 1)]. |
| 752 __ subq(RBX, RCX); |
| 753 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize)); |
| 754 // Let RDI point to the last copied positional argument, i.e. to |
| 755 // fp[-1 - (num_pos_args - 1)]. |
| 756 __ SmiUntag(RCX); |
| 757 __ movq(RAX, RCX); |
| 758 __ negq(RAX); |
| 759 __ leaq(RDI, Address(RBP, RAX, TIMES_8, 0)); |
| 760 Label loop, loop_condition; |
| 761 __ jmp(&loop_condition, Assembler::kNearJump); |
| 762 // We do not use the final allocation index of the variable here, i.e. |
| 763 // scope->VariableAt(i)->index(), because captured variables still need |
| 764 // to be copied to the context that is not yet allocated. |
| 765 const Address argument_addr(RBX, RCX, TIMES_8, 0); |
| 766 const Address copy_addr(RDI, RCX, TIMES_8, 0); |
| 767 __ Bind(&loop); |
| 768 __ movq(RAX, argument_addr); |
| 769 __ movq(copy_addr, RAX); |
| 770 __ Bind(&loop_condition); |
| 771 __ decq(RCX); |
| 772 __ j(POSITIVE, &loop, Assembler::kNearJump); |
| 773 |
| 774 // Copy or initialize optional named arguments. |
| 775 ASSERT(num_opt_params > 0); // Or we would not have to copy arguments. |
| 776 // Start by alphabetically sorting the names of the optional parameters. |
| 777 LocalVariable** opt_param = new LocalVariable*[num_opt_params]; |
| 778 int* opt_param_position = new int[num_opt_params]; |
| 779 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 780 LocalVariable* parameter = scope->VariableAt(pos); |
| 781 const String& opt_param_name = parameter->name(); |
| 782 int i = pos - num_fixed_params; |
| 783 while (--i >= 0) { |
| 784 LocalVariable* param_i = opt_param[i]; |
| 785 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 786 ASSERT(result != 0); |
| 787 if (result > 0) break; |
| 788 opt_param[i + 1] = opt_param[i]; |
| 789 opt_param_position[i + 1] = opt_param_position[i]; |
| 790 } |
| 791 opt_param[i + 1] = parameter; |
| 792 opt_param_position[i + 1] = pos; |
| 793 } |
| 794 // Generate code handling each optional parameter in alphabetical order. |
| 795 // Total number of args is the first Smi in args descriptor array (R10). |
| 796 __ movq(RBX, FieldAddress(R10, Array::data_offset())); |
| 797 // Number of positional args is the second Smi in descriptor array (R10). |
| 798 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); |
| 799 __ SmiUntag(RCX); |
| 800 // Let RBX point to the first passed argument, i.e. to fp[1 + argc - 0]. |
| 801 __ leaq(RBX, Address(RBP, RBX, TIMES_4, kWordSize)); // RBX is Smi. |
| 802 // Let EDI point to the name/pos pair of the first named argument. |
| 803 __ leaq(RDI, FieldAddress(R10, Array::data_offset() + (2 * kWordSize))); |
| 804 for (int i = 0; i < num_opt_params; i++) { |
| 805 // Handle this optional parameter only if k or fewer positional arguments |
| 806 // have been passed, where k is the position of this optional parameter in |
| 807 // the formal parameter list. |
| 808 Label load_default_value, assign_optional_parameter, next_parameter; |
| 809 const int param_pos = opt_param_position[i]; |
| 810 __ cmpq(RCX, Immediate(param_pos)); |
| 811 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 812 // Check if this named parameter was passed in. |
| 813 __ movq(RAX, Address(RDI, 0)); // Load RAX with the name of the argument. |
| 814 __ CompareObject(RAX, opt_param[i]->name()); |
| 815 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 816 // Load RAX with passed-in argument at provided arg_pos, i.e. at |
| 817 // fp[1 + argc - arg_pos]. |
| 818 __ movq(RAX, Address(RDI, kWordSize)); // RAX is arg_pos as Smi. |
| 819 __ addq(RDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. |
| 820 __ negq(RAX); |
| 821 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. |
| 822 __ movq(RAX, argument_addr); |
| 823 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 824 __ Bind(&load_default_value); |
| 825 // Load RAX with default argument at pos. |
| 826 const Object& value = Object::ZoneHandle( |
| 827 parsed_function_.default_parameter_values().At( |
| 828 param_pos - num_fixed_params)); |
| 829 __ LoadObject(RAX, value); |
| 830 __ Bind(&assign_optional_parameter); |
| 831 // Assign RAX to fp[-1 - param_pos]. |
| 832 // We do not use the final allocation index of the variable here, i.e. |
| 833 // scope->VariableAt(i)->index(), because captured variables still need |
| 834 // to be copied to the context that is not yet allocated. |
| 835 const Address param_addr(RBP, (-1 - param_pos) * kWordSize); |
| 836 __ movq(param_addr, RAX); |
| 837 __ Bind(&next_parameter); |
| 838 } |
| 839 delete[] opt_param; |
| 840 delete[] opt_param_position; |
| 841 // Check that RDI now points to the null terminator in the array descriptor. |
| 842 const Immediate raw_null = |
| 843 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 844 Label all_arguments_processed; |
| 845 __ cmpq(Address(RDI, 0), raw_null); |
| 846 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 847 |
| 848 __ Bind(&wrong_num_arguments); |
| 849 if (function.IsClosureFunction()) { |
| 850 GenerateCallRuntime(AstNode::kNoId, |
| 851 0, |
| 852 kClosureArgumentMismatchRuntimeEntry); |
| 853 } else { |
| 854 // Invoke noSuchMethod function. |
| 855 const int kNumArgsChecked = 1; |
| 856 ICData& ic_data = ICData::ZoneHandle(); |
| 857 ic_data = ICData::New(parsed_function_.function(), |
| 858 String::Handle(function.name()), |
| 859 AstNode::kNoId, |
| 860 kNumArgsChecked); |
| 861 __ LoadObject(RBX, ic_data); |
| 862 // RBP : points to previous frame pointer. |
| 863 // RBP + 8 : points to return address. |
| 864 // RBP + 16 : address of last argument (arg n-1). |
| 865 // RSP + 16 + 8*(n-1) : address of first argument (arg 0). |
| 866 // RBX : ic-data. |
| 867 // R10 : arguments descriptor array. |
| 868 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); |
| 869 } |
| 870 |
| 871 if (FLAG_trace_functions) { |
| 872 __ pushq(RAX); // Preserve result. |
| 873 __ PushObject(Function::ZoneHandle(function.raw())); |
| 874 GenerateCallRuntime(AstNode::kNoId, |
| 875 0, |
| 876 kTraceFunctionExitRuntimeEntry); |
| 877 __ popq(RAX); // Remove argument. |
| 878 __ popq(RAX); // Restore result. |
| 879 } |
| 880 __ LeaveFrame(); |
| 881 __ ret(); |
| 882 |
| 883 __ Bind(&all_arguments_processed); |
| 884 // Nullify originally passed arguments only after they have been copied and |
| 885 // checked, otherwise noSuchMethod would not see their original values. |
| 886 // This step can be skipped in case we decide that formal parameters are |
| 887 // implicitly final, since garbage collecting the unmodified value is not |
| 888 // an issue anymore. |
| 889 |
| 890 // R10 : arguments descriptor array. |
| 891 // Total number of args is the first Smi in args descriptor array (R10). |
| 892 __ movq(RCX, FieldAddress(R10, Array::data_offset())); |
| 893 __ SmiUntag(RCX); |
| 894 Label null_args_loop, null_args_loop_condition; |
| 895 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 896 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize); |
| 897 __ Bind(&null_args_loop); |
| 898 __ movq(original_argument_addr, raw_null); |
| 899 __ Bind(&null_args_loop_condition); |
| 900 __ decq(RCX); |
| 901 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 902 } |
| 903 |
| 904 |
| 905 // TODO(srdjan): Investigate where to put the argument type checks for |
| 906 // checked mode. |
| 719 void FlowGraphCompiler::CompileGraph() { | 907 void FlowGraphCompiler::CompileGraph() { |
| 720 // Specialized version of entry code from CodeGenerator::GenerateEntryCode. | 908 // Specialized version of entry code from CodeGenerator::GenerateEntryCode. |
| 721 const Function& function = parsed_function_.function(); | 909 const Function& function = parsed_function_.function(); |
| 722 | 910 |
| 723 // We don't implement copied parameters yet and should have bailed out | |
| 724 // from the graph builder. | |
| 725 ASSERT(function.num_optional_parameters() == 0); | |
| 726 const int parameter_count = function.num_fixed_parameters(); | 911 const int parameter_count = function.num_fixed_parameters(); |
| 912 const int num_opt_params = function.num_optional_parameters(); |
| 913 const int num_copied_params = parsed_function_.copied_parameter_count(); |
| 727 const int local_count = parsed_function_.stack_local_count(); | 914 const int local_count = parsed_function_.stack_local_count(); |
| 728 __ EnterFrame(local_count * kWordSize); | 915 __ EnterFrame(StackSize() * kWordSize); |
| 916 |
| 917 // We check the number of passed arguments when we have to copy them due to |
| 918 // the presence of optional named parameters. |
| 919 // No such checking code is generated if only fixed parameters are declared, |
| 920 // unless we are debug mode or unless we are compiling a closure. |
| 921 if (num_copied_params == 0) { |
| 729 #ifdef DEBUG | 922 #ifdef DEBUG |
| 730 const bool check_arguments = true; | 923 const bool check_arguments = true; |
| 731 #else | 924 #else |
| 732 const bool check_arguments = function.IsClosureFunction(); | 925 const bool check_arguments = function.IsClosureFunction(); |
| 733 #endif | 926 #endif |
| 734 if (check_arguments) { | 927 if (check_arguments) { |
| 735 // Check that num_fixed <= argc <= num_params. | 928 // Check that num_fixed <= argc <= num_params. |
| 736 Label argc_in_range; | 929 Label argc_in_range; |
| 737 // Total number of args is the first Smi in args descriptor array (R10). | 930 // Total number of args is the first Smi in args descriptor array (R10). |
| 738 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | 931 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 739 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count))); | 932 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count))); |
| 740 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 933 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
| 741 if (function.IsClosureFunction()) { | 934 if (function.IsClosureFunction()) { |
| 742 GenerateCallRuntime(AstNode::kNoId, | 935 GenerateCallRuntime(AstNode::kNoId, |
| 743 function.token_index(), | 936 function.token_index(), |
| 744 kClosureArgumentMismatchRuntimeEntry); | 937 kClosureArgumentMismatchRuntimeEntry); |
| 745 } else { | 938 } else { |
| 746 __ Stop("Wrong number of arguments"); | 939 __ Stop("Wrong number of arguments"); |
| 940 } |
| 941 __ Bind(&argc_in_range); |
| 747 } | 942 } |
| 748 __ Bind(&argc_in_range); | 943 } else { |
| 944 CopyParameters(); |
| 749 } | 945 } |
| 750 | 946 |
| 751 // Initialize locals to null. | 947 // Initialize locals to null. |
| 752 if (local_count > 0) { | 948 if (local_count > 0) { |
| 753 __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null()))); | 949 __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null()))); |
| 754 const int base = parsed_function_.first_stack_local_index(); | 950 const int base = parsed_function_.first_stack_local_index(); |
| 755 for (int i = 0; i < local_count; ++i) { | 951 for (int i = 0; i < local_count; ++i) { |
| 756 // Subtract index i (locals lie at lower addresses than RBP). | 952 // Subtract index i (locals lie at lower addresses than RBP). |
| 757 __ movq(Address(RBP, (base - i) * kWordSize), RAX); | 953 __ movq(Address(RBP, (base - i) * kWordSize), RAX); |
| 758 } | 954 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 840 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { | 1036 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { |
| 841 // We don't compile exception handlers yet. | 1037 // We don't compile exception handlers yet. |
| 842 code.set_exception_handlers( | 1038 code.set_exception_handlers( |
| 843 ExceptionHandlers::Handle(ExceptionHandlers::New(0))); | 1039 ExceptionHandlers::Handle(ExceptionHandlers::New(0))); |
| 844 } | 1040 } |
| 845 | 1041 |
| 846 | 1042 |
| 847 } // namespace dart | 1043 } // namespace dart |
| 848 | 1044 |
| 849 #endif // defined TARGET_ARCH_X64 | 1045 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |