| 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 12 matching lines...) Expand all Loading... |
| 23 | 23 |
| 24 FlowGraphCompiler::FlowGraphCompiler( | 24 FlowGraphCompiler::FlowGraphCompiler( |
| 25 Assembler* assembler, | 25 Assembler* assembler, |
| 26 const ParsedFunction& parsed_function, | 26 const ParsedFunction& parsed_function, |
| 27 const GrowableArray<BlockEntryInstr*>* blocks) | 27 const GrowableArray<BlockEntryInstr*>* blocks) |
| 28 : assembler_(assembler), | 28 : assembler_(assembler), |
| 29 parsed_function_(parsed_function), | 29 parsed_function_(parsed_function), |
| 30 blocks_(blocks), | 30 blocks_(blocks), |
| 31 block_info_(blocks->length()), | 31 block_info_(blocks->length()), |
| 32 current_block_(NULL), | 32 current_block_(NULL), |
| 33 pc_descriptors_list_(new CodeGenerator::DescriptorList()), | 33 pc_descriptors_list_(new CodeGenerator::DescriptorList()) { |
| 34 stack_local_count_(0) { | |
| 35 for (int i = 0; i < blocks->length(); ++i) { | 34 for (int i = 0; i < blocks->length(); ++i) { |
| 36 block_info_.Add(new BlockInfo()); | 35 block_info_.Add(new BlockInfo()); |
| 37 } | 36 } |
| 38 } | 37 } |
| 39 | 38 |
| 40 | 39 |
| 41 FlowGraphCompiler::~FlowGraphCompiler() { | 40 FlowGraphCompiler::~FlowGraphCompiler() { |
| 42 // BlockInfos are zone-allocated, so their destructors are not called. | 41 // BlockInfos are zone-allocated, so their destructors are not called. |
| 43 // Verify the labels explicitly here. | 42 // Verify the labels explicitly here. |
| 44 for (int i = 0; i < block_info_.length(); ++i) { | 43 for (int i = 0; i < block_info_.length(); ++i) { |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 default: | 157 default: |
| 159 UNIMPLEMENTED(); | 158 UNIMPLEMENTED(); |
| 160 } | 159 } |
| 161 ExternalLabel target_label("InlineCache", label_address); | 160 ExternalLabel target_label("InlineCache", label_address); |
| 162 __ call(&target_label); | 161 __ call(&target_label); |
| 163 AddCurrentDescriptor(PcDescriptors::kIcCall, node_id, token_index); | 162 AddCurrentDescriptor(PcDescriptors::kIcCall, node_id, token_index); |
| 164 __ addq(RSP, Immediate(argument_count * kWordSize)); | 163 __ addq(RSP, Immediate(argument_count * kWordSize)); |
| 165 } | 164 } |
| 166 | 165 |
| 167 | 166 |
| 167 void FlowGraphCompiler::VisitCurrentContext(CurrentContextComp* comp) { |
| 168 __ movq(RAX, CTX); |
| 169 } |
| 170 |
| 171 |
| 172 void FlowGraphCompiler::VisitClosureCall(ClosureCallComp* comp) { |
| 173 ASSERT(comp->context()->IsTemp()); |
| 174 ASSERT(VerifyCallComputation(comp)); |
| 175 // The arguments to the stub include the closure. The arguments |
| 176 // descriptor describes the closure's arguments (and so does not include |
| 177 // the closure). |
| 178 int argument_count = comp->ArgumentCount(); |
| 179 const Array& arguments_descriptor = |
| 180 CodeGenerator::ArgumentsDescriptor(argument_count - 1, |
| 181 comp->argument_names()); |
| 182 __ LoadObject(R10, arguments_descriptor); |
| 183 |
| 184 GenerateCall(comp->token_index(), |
| 185 &StubCode::CallClosureFunctionLabel(), |
| 186 PcDescriptors::kOther); |
| 187 __ addq(RSP, Immediate(argument_count * kWordSize)); |
| 188 __ popq(CTX); |
| 189 } |
| 190 |
| 191 |
| 168 void FlowGraphCompiler::VisitInstanceCall(InstanceCallComp* comp) { | 192 void FlowGraphCompiler::VisitInstanceCall(InstanceCallComp* comp) { |
| 169 ASSERT(VerifyCallComputation(comp)); | 193 ASSERT(VerifyCallComputation(comp)); |
| 170 EmitInstanceCall(comp->node_id(), | 194 EmitInstanceCall(comp->node_id(), |
| 171 comp->token_index(), | 195 comp->token_index(), |
| 172 comp->function_name(), | 196 comp->function_name(), |
| 173 comp->ArgumentCount(), | 197 comp->ArgumentCount(), |
| 174 comp->argument_names(), | 198 comp->argument_names(), |
| 175 comp->checked_argument_count()); | 199 comp->checked_argument_count()); |
| 176 } | 200 } |
| 177 | 201 |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 if (comp->ElementAt(i)->IsTemp()) { | 559 if (comp->ElementAt(i)->IsTemp()) { |
| 536 __ popq(Address(RCX, i * kWordSize)); | 560 __ popq(Address(RCX, i * kWordSize)); |
| 537 } else { | 561 } else { |
| 538 LoadValue(RDX, comp->ElementAt(i)); | 562 LoadValue(RDX, comp->ElementAt(i)); |
| 539 __ movq(Address(RCX, i * kWordSize), RDX); | 563 __ movq(Address(RCX, i * kWordSize), RDX); |
| 540 } | 564 } |
| 541 } | 565 } |
| 542 } | 566 } |
| 543 | 567 |
| 544 | 568 |
| 569 void FlowGraphCompiler::VisitCreateClosure(CreateClosureComp* comp) { |
| 570 const Function& function = comp->function(); |
| 571 const Code& stub = Code::Handle( |
| 572 StubCode::GetAllocationStubForClosure(function)); |
| 573 const ExternalLabel label(function.ToCString(), stub.EntryPoint()); |
| 574 GenerateCall(comp->token_index(), &label, PcDescriptors::kOther); |
| 575 |
| 576 const Class& cls = Class::Handle(function.signature_class()); |
| 577 if (cls.HasTypeArguments()) { |
| 578 __ popq(RCX); // Discard type arguments. |
| 579 } |
| 580 if (function.IsImplicitInstanceClosureFunction()) { |
| 581 __ popq(RCX); // Discard receiver. |
| 582 } |
| 583 } |
| 584 |
| 585 |
| 545 void FlowGraphCompiler::VisitBlocks( | 586 void FlowGraphCompiler::VisitBlocks( |
| 546 const GrowableArray<BlockEntryInstr*>& blocks) { | 587 const GrowableArray<BlockEntryInstr*>& blocks) { |
| 547 for (intptr_t i = blocks.length() - 1; i >= 0; --i) { | 588 for (intptr_t i = blocks.length() - 1; i >= 0; --i) { |
| 548 // Compile the block entry. | 589 // Compile the block entry. |
| 549 current_block_ = blocks[i]; | 590 current_block_ = blocks[i]; |
| 550 Instruction* instr = current_block()->Accept(this); | 591 Instruction* instr = current_block()->Accept(this); |
| 551 // Compile all successors until an exit, branch, or a block entry. | 592 // Compile all successors until an exit, branch, or a block entry. |
| 552 while ((instr != NULL) && !instr->IsBlockEntry()) { | 593 while ((instr != NULL) && !instr->IsBlockEntry()) { |
| 553 instr = instr->Accept(this); | 594 instr = instr->Accept(this); |
| 554 } | 595 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 609 } | 650 } |
| 610 | 651 |
| 611 | 652 |
| 612 void FlowGraphCompiler::VisitReturn(ReturnInstr* instr) { | 653 void FlowGraphCompiler::VisitReturn(ReturnInstr* instr) { |
| 613 LoadValue(RAX, instr->value()); | 654 LoadValue(RAX, instr->value()); |
| 614 | 655 |
| 615 #ifdef DEBUG | 656 #ifdef DEBUG |
| 616 // Check that the entry stack size matches the exit stack size. | 657 // Check that the entry stack size matches the exit stack size. |
| 617 __ movq(R10, RBP); | 658 __ movq(R10, RBP); |
| 618 __ subq(R10, RSP); | 659 __ subq(R10, RSP); |
| 619 __ cmpq(R10, Immediate(stack_local_count() * kWordSize)); | 660 __ cmpq(R10, Immediate(parsed_function_.local_count() * kWordSize)); |
| 620 Label stack_ok; | 661 Label stack_ok; |
| 621 __ j(EQUAL, &stack_ok, Assembler::kNearJump); | 662 __ j(EQUAL, &stack_ok, Assembler::kNearJump); |
| 622 __ Stop("Exit stack size does not match the entry stack size."); | 663 __ Stop("Exit stack size does not match the entry stack size."); |
| 623 __ Bind(&stack_ok); | 664 __ Bind(&stack_ok); |
| 624 #endif // DEBUG. | 665 #endif // DEBUG. |
| 625 | 666 |
| 626 if (FLAG_trace_functions) { | 667 if (FLAG_trace_functions) { |
| 627 __ pushq(RAX); // Preserve result. | 668 __ pushq(RAX); // Preserve result. |
| 628 const Function& function = | 669 const Function& function = |
| 629 Function::ZoneHandle(parsed_function_.function().raw()); | 670 Function::ZoneHandle(parsed_function_.function().raw()); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 668 __ cmpq(RAX, RDX); | 709 __ cmpq(RAX, RDX); |
| 669 if (negated) { | 710 if (negated) { |
| 670 __ j(EQUAL, &block_info_[instr->true_successor()->block_number()]->label); | 711 __ j(EQUAL, &block_info_[instr->true_successor()->block_number()]->label); |
| 671 } else { | 712 } else { |
| 672 __ j(NOT_EQUAL, | 713 __ j(NOT_EQUAL, |
| 673 &block_info_[instr->false_successor()->block_number()]->label); | 714 &block_info_[instr->false_successor()->block_number()]->label); |
| 674 } | 715 } |
| 675 } | 716 } |
| 676 | 717 |
| 677 | 718 |
| 719 // Coped from CodeGenerator::CopyParameters (CodeGenerator will be deprecated). |
| 720 void FlowGraphCompiler::CopyParameters() { |
| 721 const Function& function = parsed_function_.function(); |
| 722 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 723 const int num_fixed_params = function.num_fixed_parameters(); |
| 724 const int num_opt_params = function.num_optional_parameters(); |
| 725 ASSERT(parsed_function_.first_parameter_index() == -1); |
| 726 // Copy positional arguments. |
| 727 // Check that no fewer than num_fixed_params positional arguments are passed |
| 728 // in and that no more than num_params arguments are passed in. |
| 729 // Passed argument i at fp[1 + argc - i] copied to fp[-1 - i]. |
| 730 const int num_params = num_fixed_params + num_opt_params; |
| 731 |
| 732 // Total number of args is the first Smi in args descriptor array (R10). |
| 733 __ movq(RBX, FieldAddress(R10, Array::data_offset())); |
| 734 // Check that num_args <= num_params. |
| 735 Label wrong_num_arguments; |
| 736 __ cmpq(RBX, Immediate(Smi::RawValue(num_params))); |
| 737 __ j(GREATER, &wrong_num_arguments); |
| 738 // Number of positional args is the second Smi in descriptor array (R10). |
| 739 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); |
| 740 // Check that num_pos_args >= num_fixed_params. |
| 741 __ cmpq(RCX, Immediate(Smi::RawValue(num_fixed_params))); |
| 742 __ j(LESS, &wrong_num_arguments); |
| 743 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. |
| 744 // Let RBX point to the last passed positional argument, i.e. to |
| 745 // fp[1 + num_args - (num_pos_args - 1)]. |
| 746 __ subq(RBX, RCX); |
| 747 __ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize)); |
| 748 // Let RDI point to the last copied positional argument, i.e. to |
| 749 // fp[-1 - (num_pos_args - 1)]. |
| 750 __ SmiUntag(RCX); |
| 751 __ movq(RAX, RCX); |
| 752 __ negq(RAX); |
| 753 __ leaq(RDI, Address(RBP, RAX, TIMES_8, 0)); |
| 754 Label loop, loop_condition; |
| 755 __ jmp(&loop_condition, Assembler::kNearJump); |
| 756 // We do not use the final allocation index of the variable here, i.e. |
| 757 // scope->VariableAt(i)->index(), because captured variables still need |
| 758 // to be copied to the context that is not yet allocated. |
| 759 const Address argument_addr(RBX, RCX, TIMES_8, 0); |
| 760 const Address copy_addr(RDI, RCX, TIMES_8, 0); |
| 761 __ Bind(&loop); |
| 762 __ movq(RAX, argument_addr); |
| 763 __ movq(copy_addr, RAX); |
| 764 __ Bind(&loop_condition); |
| 765 __ decq(RCX); |
| 766 __ j(POSITIVE, &loop, Assembler::kNearJump); |
| 767 |
| 768 // Copy or initialize optional named arguments. |
| 769 ASSERT(num_opt_params > 0); // Or we would not have to copy arguments. |
| 770 // Start by alphabetically sorting the names of the optional parameters. |
| 771 LocalVariable** opt_param = new LocalVariable*[num_opt_params]; |
| 772 int* opt_param_position = new int[num_opt_params]; |
| 773 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 774 LocalVariable* parameter = scope->VariableAt(pos); |
| 775 const String& opt_param_name = parameter->name(); |
| 776 int i = pos - num_fixed_params; |
| 777 while (--i >= 0) { |
| 778 LocalVariable* param_i = opt_param[i]; |
| 779 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| 780 ASSERT(result != 0); |
| 781 if (result > 0) break; |
| 782 opt_param[i + 1] = opt_param[i]; |
| 783 opt_param_position[i + 1] = opt_param_position[i]; |
| 784 } |
| 785 opt_param[i + 1] = parameter; |
| 786 opt_param_position[i + 1] = pos; |
| 787 } |
| 788 // Generate code handling each optional parameter in alphabetical order. |
| 789 // Total number of args is the first Smi in args descriptor array (R10). |
| 790 __ movq(RBX, FieldAddress(R10, Array::data_offset())); |
| 791 // Number of positional args is the second Smi in descriptor array (R10). |
| 792 __ movq(RCX, FieldAddress(R10, Array::data_offset() + (1 * kWordSize))); |
| 793 __ SmiUntag(RCX); |
| 794 // Let RBX point to the first passed argument, i.e. to fp[1 + argc - 0]. |
| 795 __ leaq(RBX, Address(RBP, RBX, TIMES_4, kWordSize)); // RBX is Smi. |
| 796 // Let EDI point to the name/pos pair of the first named argument. |
| 797 __ leaq(RDI, FieldAddress(R10, Array::data_offset() + (2 * kWordSize))); |
| 798 for (int i = 0; i < num_opt_params; i++) { |
| 799 // Handle this optional parameter only if k or fewer positional arguments |
| 800 // have been passed, where k is the position of this optional parameter in |
| 801 // the formal parameter list. |
| 802 Label load_default_value, assign_optional_parameter, next_parameter; |
| 803 const int param_pos = opt_param_position[i]; |
| 804 __ cmpq(RCX, Immediate(param_pos)); |
| 805 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 806 // Check if this named parameter was passed in. |
| 807 __ movq(RAX, Address(RDI, 0)); // Load RAX with the name of the argument. |
| 808 __ CompareObject(RAX, opt_param[i]->name()); |
| 809 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 810 // Load RAX with passed-in argument at provided arg_pos, i.e. at |
| 811 // fp[1 + argc - arg_pos]. |
| 812 __ movq(RAX, Address(RDI, kWordSize)); // RAX is arg_pos as Smi. |
| 813 __ addq(RDI, Immediate(2 * kWordSize)); // Point to next name/pos pair. |
| 814 __ negq(RAX); |
| 815 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. |
| 816 __ movq(RAX, argument_addr); |
| 817 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 818 __ Bind(&load_default_value); |
| 819 // Load RAX with default argument at pos. |
| 820 const Object& value = Object::ZoneHandle( |
| 821 parsed_function_.default_parameter_values().At( |
| 822 param_pos - num_fixed_params)); |
| 823 __ LoadObject(RAX, value); |
| 824 __ Bind(&assign_optional_parameter); |
| 825 // Assign RAX to fp[-1 - param_pos]. |
| 826 // We do not use the final allocation index of the variable here, i.e. |
| 827 // scope->VariableAt(i)->index(), because captured variables still need |
| 828 // to be copied to the context that is not yet allocated. |
| 829 const Address param_addr(RBP, (-1 - param_pos) * kWordSize); |
| 830 __ movq(param_addr, RAX); |
| 831 __ Bind(&next_parameter); |
| 832 } |
| 833 delete[] opt_param; |
| 834 delete[] opt_param_position; |
| 835 // Check that RDI now points to the null terminator in the array descriptor. |
| 836 const Immediate raw_null = |
| 837 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 838 Label all_arguments_processed; |
| 839 __ cmpq(Address(RDI, 0), raw_null); |
| 840 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| 841 |
| 842 __ Bind(&wrong_num_arguments); |
| 843 if (function.IsClosureFunction()) { |
| 844 GenerateCallRuntime(AstNode::kNoId, |
| 845 0, |
| 846 kClosureArgumentMismatchRuntimeEntry); |
| 847 } else { |
| 848 // Invoke noSuchMethod function. |
| 849 const int kNumArgsChecked = 1; |
| 850 ICData& ic_data = ICData::ZoneHandle(); |
| 851 ic_data = ICData::New(parsed_function_.function(), |
| 852 String::Handle(function.name()), |
| 853 AstNode::kNoId, |
| 854 kNumArgsChecked); |
| 855 __ LoadObject(RBX, ic_data); |
| 856 // RBP : points to previous frame pointer. |
| 857 // RBP + 8 : points to return address. |
| 858 // RBP + 16 : address of last argument (arg n-1). |
| 859 // RSP + 16 + 8*(n-1) : address of first argument (arg 0). |
| 860 // RBX : ic-data. |
| 861 // R10 : arguments descriptor array. |
| 862 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); |
| 863 } |
| 864 |
| 865 if (FLAG_trace_functions) { |
| 866 __ pushq(RAX); // Preserve result. |
| 867 __ PushObject(Function::ZoneHandle(function.raw())); |
| 868 GenerateCallRuntime(AstNode::kNoId, |
| 869 0, |
| 870 kTraceFunctionExitRuntimeEntry); |
| 871 __ popq(RAX); // Remove argument. |
| 872 __ popq(RAX); // Restore result. |
| 873 } |
| 874 __ LeaveFrame(); |
| 875 __ ret(); |
| 876 |
| 877 __ Bind(&all_arguments_processed); |
| 878 // Nullify originally passed arguments only after they have been copied and |
| 879 // checked, otherwise noSuchMethod would not see their original values. |
| 880 // This step can be skipped in case we decide that formal parameters are |
| 881 // implicitly final, since garbage collecting the unmodified value is not |
| 882 // an issue anymore. |
| 883 |
| 884 // R10 : arguments descriptor array. |
| 885 // Total number of args is the first Smi in args descriptor array (R10). |
| 886 __ movq(RCX, FieldAddress(R10, Array::data_offset())); |
| 887 __ SmiUntag(RCX); |
| 888 Label null_args_loop, null_args_loop_condition; |
| 889 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
| 890 const Address original_argument_addr(RBP, RCX, TIMES_8, 2 * kWordSize); |
| 891 __ Bind(&null_args_loop); |
| 892 __ movq(original_argument_addr, raw_null); |
| 893 __ Bind(&null_args_loop_condition); |
| 894 __ decq(RCX); |
| 895 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
| 896 } |
| 897 |
| 898 |
| 899 // TODO(srdjan): Investigate where to put the argument type checks for |
| 900 // checked mode. |
| 678 void FlowGraphCompiler::CompileGraph() { | 901 void FlowGraphCompiler::CompileGraph() { |
| 902 // Specialized version of entry code from CodeGenerator::GenerateEntryCode. |
| 679 const Function& function = parsed_function_.function(); | 903 const Function& function = parsed_function_.function(); |
| 904 |
| 905 // We don't implement copied parameters yet and should have bailed out |
| 906 // from the graph builder. |
| 680 if ((function.num_optional_parameters() != 0)) { | 907 if ((function.num_optional_parameters() != 0)) { |
| 681 Bailout("function has optional parameters"); | 908 // Bailout("function has optional parameters"); |
| 682 } | 909 } |
| 683 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 910 |
| 684 LocalScope* context_owner = NULL; | |
| 685 const int parameter_count = function.num_fixed_parameters(); | 911 const int parameter_count = function.num_fixed_parameters(); |
| 686 const int first_parameter_index = 1 + parameter_count; | 912 const int num_opt_params = function.num_optional_parameters(); |
| 687 const int first_local_index = -1; | 913 const int num_copied_params = parsed_function_.copied_parameter_count(); |
| 688 int first_free_frame_index = | 914 |
| 689 scope->AllocateVariables(first_parameter_index, | 915 const int local_count = parsed_function_.local_count(); |
| 690 parameter_count, | 916 __ EnterFrame(local_count * kWordSize); |
| 691 first_local_index, | 917 |
| 692 scope, | 918 // We check the number of passed arguments when we have to copy them due to |
| 693 &context_owner); | 919 // the presence of optional named parameters. |
| 694 set_stack_local_count(first_local_index - first_free_frame_index); | 920 // No such checking code is generated if only fixed parameters are declared, |
| 695 | 921 // unless we are debug mode or unless we are compiling a closure. |
| 696 // Specialized version of entry code from CodeGenerator::GenerateEntryCode. | 922 if (num_copied_params == 0) { |
| 697 __ EnterFrame(stack_local_count() * kWordSize); | |
| 698 #ifdef DEBUG | 923 #ifdef DEBUG |
| 699 const bool check_arguments = true; | 924 const bool check_arguments = true; |
| 700 #else | 925 #else |
| 701 const bool check_arguments = function.IsClosureFunction(); | 926 const bool check_arguments = function.IsClosureFunction(); |
| 702 #endif | 927 #endif |
| 703 if (check_arguments) { | 928 if (check_arguments) { |
| 704 // Check that num_fixed <= argc <= num_params. | 929 // Check that num_fixed <= argc <= num_params. |
| 705 Label argc_in_range; | 930 Label argc_in_range; |
| 706 // Total number of args is the first Smi in args descriptor array (R10). | 931 // Total number of args is the first Smi in args descriptor array (R10). |
| 707 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | 932 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 708 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count))); | 933 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count))); |
| 709 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 934 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
| 710 if (function.IsClosureFunction()) { | 935 if (function.IsClosureFunction()) { |
| 711 GenerateCallRuntime(AstNode::kNoId, | 936 GenerateCallRuntime(AstNode::kNoId, |
| 712 function.token_index(), | 937 function.token_index(), |
| 713 kClosureArgumentMismatchRuntimeEntry); | 938 kClosureArgumentMismatchRuntimeEntry); |
| 714 } else { | 939 } else { |
| 715 __ Stop("Wrong number of arguments"); | 940 __ Stop("Wrong number of arguments"); |
| 941 } |
| 942 __ Bind(&argc_in_range); |
| 716 } | 943 } |
| 717 __ Bind(&argc_in_range); | 944 } else { |
| 945 CopyParameters(); |
| 718 } | 946 } |
| 719 | 947 |
| 720 // Initialize locals to null. | 948 // Initialize locals to null. |
| 721 if (stack_local_count() > 0) { | 949 if (local_count > 0) { |
| 722 __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null()))); | 950 __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null()))); |
| 723 for (int i = 0; i < stack_local_count(); ++i) { | 951 const int base = parsed_function_.first_local_index(); |
| 952 for (int i = 0; i < local_count; ++i) { |
| 724 // Subtract index i (locals lie at lower addresses than RBP). | 953 // Subtract index i (locals lie at lower addresses than RBP). |
| 725 __ movq(Address(RBP, (first_local_index - i) * kWordSize), RAX); | 954 __ movq(Address(RBP, (base - i) * kWordSize), RAX); |
| 726 } | 955 } |
| 727 } | 956 } |
| 728 | 957 |
| 729 // Generate stack overflow check. | 958 // Generate stack overflow check. |
| 730 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address())); | 959 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address())); |
| 731 __ cmpq(RSP, Address(TMP, 0)); | 960 __ cmpq(RSP, Address(TMP, 0)); |
| 732 Label no_stack_overflow; | 961 Label no_stack_overflow; |
| 733 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); | 962 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); |
| 734 GenerateCallRuntime(AstNode::kNoId, | 963 GenerateCallRuntime(AstNode::kNoId, |
| 735 function.token_index(), | 964 function.token_index(), |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 808 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { | 1037 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { |
| 809 // We don't compile exception handlers yet. | 1038 // We don't compile exception handlers yet. |
| 810 code.set_exception_handlers( | 1039 code.set_exception_handlers( |
| 811 ExceptionHandlers::Handle(ExceptionHandlers::New(0))); | 1040 ExceptionHandlers::Handle(ExceptionHandlers::New(0))); |
| 812 } | 1041 } |
| 813 | 1042 |
| 814 | 1043 |
| 815 } // namespace dart | 1044 } // namespace dart |
| 816 | 1045 |
| 817 #endif // defined TARGET_ARCH_X64 | 1046 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |