| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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/code_generator.h" | 8 #include "vm/code_generator.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function."); | 26 DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function."); |
| 27 DEFINE_FLAG(int, optimization_invocation_threshold, 1000, | 27 DEFINE_FLAG(int, optimization_invocation_threshold, 1000, |
| 28 "number of invocations before a function is optimized, -1 means never."); | 28 "number of invocations before a function is optimized, -1 means never."); |
| 29 DECLARE_FLAG(bool, enable_type_checks); | 29 DECLARE_FLAG(bool, enable_type_checks); |
| 30 DECLARE_FLAG(bool, report_invocation_count); | 30 DECLARE_FLAG(bool, report_invocation_count); |
| 31 DECLARE_FLAG(bool, trace_compiler); | 31 DECLARE_FLAG(bool, trace_compiler); |
| 32 | 32 |
| 33 #define __ assembler_-> | 33 #define __ assembler_-> |
| 34 | 34 |
| 35 | 35 |
| 36 class CodeGeneratorState : public StackResource { | 36 CodeGeneratorState::CodeGeneratorState(CodeGenerator* codegen) |
| 37 public: | 37 : StackResource(Isolate::Current()), |
| 38 explicit CodeGeneratorState(CodeGenerator* codegen) | 38 codegen_(codegen), |
| 39 : StackResource(Isolate::Current()), | 39 parent_(codegen->state()) { |
| 40 codegen_(codegen), | 40 if (parent_ != NULL) { |
| 41 parent_(codegen->state()) { | 41 root_node_ = parent_->root_node_; |
| 42 if (parent_ != NULL) { | 42 loop_level_ = parent_->loop_level_; |
| 43 root_node_ = parent_->root_node_; | 43 context_level_ = parent_->context_level_; |
| 44 loop_level_ = parent_->loop_level_; | 44 current_try_index_ = parent_->current_try_index_; |
| 45 context_level_ = parent_->context_level_; | 45 } else { |
| 46 current_try_index_ = parent_->current_try_index_; | 46 root_node_ = NULL; |
| 47 } else { | 47 loop_level_ = 0; |
| 48 root_node_ = NULL; | 48 context_level_ = 0; |
| 49 loop_level_ = 0; | 49 current_try_index_ = CatchClauseNode::kInvalidTryIndex; |
| 50 context_level_ = 0; | |
| 51 current_try_index_ = CatchClauseNode::kInvalidTryIndex; | |
| 52 } | |
| 53 codegen_->set_state(this); | |
| 54 } | 50 } |
| 55 virtual ~CodeGeneratorState() { | 51 codegen_->set_state(this); |
| 56 codegen_->set_state(parent_); | 52 } |
| 57 } | |
| 58 | 53 |
| 59 CodeGeneratorState* parent() const { return parent_; } | |
| 60 | 54 |
| 61 AstNode* root_node() const { return root_node_; } | 55 CodeGeneratorState::~CodeGeneratorState() { |
| 62 void set_root_node(AstNode* value) { root_node_ = value; } | 56 codegen_->set_state(parent_); |
| 63 bool IsRootNode(AstNode* node) const { | 57 } |
| 64 return root_node_ == node; | |
| 65 } | |
| 66 | |
| 67 int loop_level() const { return loop_level_; } | |
| 68 void set_loop_level(int loop_level) { | |
| 69 loop_level_ = loop_level; | |
| 70 } | |
| 71 | |
| 72 int context_level() const { return context_level_; } | |
| 73 void set_context_level(int context_level) { | |
| 74 context_level_ = context_level; | |
| 75 } | |
| 76 | |
| 77 int try_index() const { return current_try_index_; } | |
| 78 void set_try_index(int value) { | |
| 79 current_try_index_ = value; | |
| 80 } | |
| 81 | |
| 82 private: | |
| 83 CodeGenerator* codegen_; | |
| 84 CodeGeneratorState* parent_; | |
| 85 AstNode* root_node_; | |
| 86 | |
| 87 // The loop level reflects the lexical nesting of loop statements, regardless | |
| 88 // of the presence of captured variables. | |
| 89 int loop_level_; | |
| 90 | |
| 91 // The runtime context level is only incremented when a new context is | |
| 92 // allocated and chained to the list of contexts. This occurs when the scopes | |
| 93 // at the current loop level contain captured variables. | |
| 94 int context_level_; | |
| 95 | |
| 96 // We identify each try block in this function with an unique 'try index' | |
| 97 // value. | |
| 98 // The 'try index' is used to match the try blocks with the corresponding | |
| 99 // catch block (if one exists). The PC descriptors generated for | |
| 100 // statements in the try block use this index so that it can be matched | |
| 101 // to the appropriate catch block. | |
| 102 // The 'try index' value is generated by incrementing the try_index_ | |
| 103 // variable in the CodeGenerator object. | |
| 104 // We store the 'try index' of the block of code that we are | |
| 105 // currently generating code for in the current_try_index_ variable. | |
| 106 int current_try_index_; | |
| 107 | |
| 108 DISALLOW_IMPLICIT_CONSTRUCTORS(CodeGeneratorState); | |
| 109 }; | |
| 110 | 58 |
| 111 | 59 |
| 112 class CodeGenerator::DescriptorList : public ZoneAllocated { | 60 class CodeGenerator::DescriptorList : public ZoneAllocated { |
| 113 public: | 61 public: |
| 114 struct PcDesc { | 62 struct PcDesc { |
| 115 intptr_t pc_offset; // PC offset value of the descriptor. | 63 intptr_t pc_offset; // PC offset value of the descriptor. |
| 116 PcDescriptors::Kind kind; // Descriptor kind (kDeopt, kOther). | 64 PcDescriptors::Kind kind; // Descriptor kind (kDeopt, kOther). |
| 117 intptr_t node_id; // AST node id. | 65 intptr_t node_id; // AST node id. |
| 118 intptr_t token_index; // Token position in source of PC. | 66 intptr_t token_index; // Token position in source of PC. |
| 119 intptr_t try_index; // Try block index of PC. | 67 intptr_t try_index; // Try block index of PC. |
| (...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 760 // Consider emitting pushes instead of moves. | 708 // Consider emitting pushes instead of moves. |
| 761 for (int index = first_local_index; index > first_free_frame_index; index--) { | 709 for (int index = first_local_index; index > first_free_frame_index; index--) { |
| 762 if (index == first_local_index) { | 710 if (index == first_local_index) { |
| 763 __ movl(EAX, raw_null); | 711 __ movl(EAX, raw_null); |
| 764 } | 712 } |
| 765 __ movl(Address(EBP, index * kWordSize), EAX); | 713 __ movl(Address(EBP, index * kWordSize), EAX); |
| 766 } | 714 } |
| 767 } | 715 } |
| 768 | 716 |
| 769 | 717 |
| 718 void CodeGenerator::GenerateReturnEpilog() { |
| 719 // Unchain the context(s) up to context level 0. |
| 720 int context_level = state()->context_level(); |
| 721 ASSERT(context_level >= 0); |
| 722 while (context_level-- > 0) { |
| 723 __ movl(CTX, FieldAddress(CTX, Context::parent_offset())); |
| 724 } |
| 725 #ifdef DEBUG |
| 726 // Check that the entry stack size matches the exit stack size. |
| 727 __ movl(EDX, EBP); |
| 728 __ subl(EDX, ESP); |
| 729 ASSERT(locals_space_size() >= 0); |
| 730 __ cmpl(EDX, Immediate(locals_space_size())); |
| 731 Label wrong_stack; |
| 732 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); |
| 733 #endif // DEBUG. |
| 734 |
| 735 if (FLAG_trace_functions) { |
| 736 __ pushl(EAX); // Preserve result. |
| 737 const Function& function = |
| 738 Function::ZoneHandle(parsed_function_.function().raw()); |
| 739 __ LoadObject(EBX, function); |
| 740 __ pushl(EBX); |
| 741 GenerateCallRuntime(AstNode::kNoId, |
| 742 0, |
| 743 kTraceFunctionExitRuntimeEntry); |
| 744 __ popl(EAX); // Remove argument. |
| 745 __ popl(EAX); // Restore result. |
| 746 } |
| 747 __ LeaveFrame(); |
| 748 __ ret(); |
| 749 |
| 750 #ifdef DEBUG |
| 751 __ Bind(&wrong_stack); |
| 752 __ Stop("Exit stack size does not match the entry stack size."); |
| 753 #endif // DEBUG. |
| 754 } |
| 755 |
| 756 |
| 770 void CodeGenerator::VisitReturnNode(ReturnNode* node) { | 757 void CodeGenerator::VisitReturnNode(ReturnNode* node) { |
| 771 ASSERT(!IsResultNeeded(node)); | 758 ASSERT(!IsResultNeeded(node)); |
| 772 ASSERT(node->value() != NULL); | 759 ASSERT(node->value() != NULL); |
| 773 | 760 |
| 774 if (!node->value()->IsLiteralNode()) { | 761 if (!node->value()->IsLiteralNode()) { |
| 775 node->value()->Visit(this); | 762 node->value()->Visit(this); |
| 776 // The result of the return value is now on top of the stack. | 763 // The result of the return value is now on top of the stack. |
| 777 } | 764 } |
| 778 | 765 |
| 779 // Generate inlined code for all finally blocks as we are about to transfer | 766 // Generate inlined code for all finally blocks as we are about to transfer |
| (...skipping 21 matching lines...) Expand all Loading... |
| 801 // Implicit getters do not need a type check at return. | 788 // Implicit getters do not need a type check at return. |
| 802 if ((kind != RawFunction::kImplicitGetter) && | 789 if ((kind != RawFunction::kImplicitGetter) && |
| 803 (kind != RawFunction::kConstImplicitGetter)) { | 790 (kind != RawFunction::kConstImplicitGetter)) { |
| 804 GenerateAssertAssignable( | 791 GenerateAssertAssignable( |
| 805 node->id(), | 792 node->id(), |
| 806 node->value()->token_index(), | 793 node->value()->token_index(), |
| 807 Type::ZoneHandle(parsed_function().function().result_type()), | 794 Type::ZoneHandle(parsed_function().function().result_type()), |
| 808 String::ZoneHandle(String::NewSymbol("function result"))); | 795 String::ZoneHandle(String::NewSymbol("function result"))); |
| 809 } | 796 } |
| 810 } | 797 } |
| 811 // Unchain the context(s) up to context level 0. | 798 GenerateReturnEpilog(); |
| 812 int context_level = state()->context_level(); | |
| 813 ASSERT(context_level >= 0); | |
| 814 while (context_level-- > 0) { | |
| 815 __ movl(CTX, FieldAddress(CTX, Context::parent_offset())); | |
| 816 } | |
| 817 #ifdef DEBUG | |
| 818 // Check that the entry stack size matches the exit stack size. | |
| 819 __ movl(EDX, EBP); | |
| 820 __ subl(EDX, ESP); | |
| 821 ASSERT(locals_space_size() >= 0); | |
| 822 __ cmpl(EDX, Immediate(locals_space_size())); | |
| 823 Label wrong_stack; | |
| 824 __ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump); | |
| 825 #endif // DEBUG. | |
| 826 | |
| 827 if (FLAG_trace_functions) { | |
| 828 __ pushl(EAX); // Preserve result. | |
| 829 const Function& function = | |
| 830 Function::ZoneHandle(parsed_function_.function().raw()); | |
| 831 __ LoadObject(EBX, function); | |
| 832 __ pushl(EBX); | |
| 833 GenerateCallRuntime(AstNode::kNoId, | |
| 834 0, | |
| 835 kTraceFunctionExitRuntimeEntry); | |
| 836 __ popl(EAX); // Remove argument. | |
| 837 __ popl(EAX); // Restore result. | |
| 838 } | |
| 839 __ LeaveFrame(); | |
| 840 __ ret(); | |
| 841 | |
| 842 #ifdef DEBUG | |
| 843 __ Bind(&wrong_stack); | |
| 844 __ Stop("Exit stack size does not match the entry stack size."); | |
| 845 #endif // DEBUG. | |
| 846 } | 799 } |
| 847 | 800 |
| 848 | 801 |
| 849 void CodeGenerator::VisitLiteralNode(LiteralNode* node) { | 802 void CodeGenerator::VisitLiteralNode(LiteralNode* node) { |
| 850 if (!IsResultNeeded(node)) return; | 803 if (!IsResultNeeded(node)) return; |
| 851 const Object& literal = node->literal(); | 804 const Object& literal = node->literal(); |
| 852 if (literal.IsSmi()) { | 805 if (literal.IsSmi()) { |
| 853 __ pushl(Immediate(reinterpret_cast<int32_t>(literal.raw()))); | 806 __ pushl(Immediate(reinterpret_cast<int32_t>(literal.raw()))); |
| 854 } else { | 807 } else { |
| 855 __ PushObject(literal); | 808 __ PushObject(literal); |
| (...skipping 1908 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2764 message_buffer, kMessageBufferSize, | 2717 message_buffer, kMessageBufferSize, |
| 2765 format, args); | 2718 format, args); |
| 2766 va_end(args); | 2719 va_end(args); |
| 2767 Isolate::Current()->long_jump_base()->Jump(1, message_buffer); | 2720 Isolate::Current()->long_jump_base()->Jump(1, message_buffer); |
| 2768 UNREACHABLE(); | 2721 UNREACHABLE(); |
| 2769 } | 2722 } |
| 2770 | 2723 |
| 2771 } // namespace dart | 2724 } // namespace dart |
| 2772 | 2725 |
| 2773 #endif // defined TARGET_ARCH_IA32 | 2726 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |