OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 | 89 |
90 // Emit all kMaterializeObject instructions describing objects to be | 90 // Emit all kMaterializeObject instructions describing objects to be |
91 // materialized on the deoptimization as a prefix to the deoptimization info. | 91 // materialized on the deoptimization as a prefix to the deoptimization info. |
92 EmitMaterializations(deopt_env_, builder); | 92 EmitMaterializations(deopt_env_, builder); |
93 | 93 |
94 // The real frame starts here. | 94 // The real frame starts here. |
95 builder->MarkFrameStart(); | 95 builder->MarkFrameStart(); |
96 | 96 |
97 Zone* zone = compiler->zone(); | 97 Zone* zone = compiler->zone(); |
98 | 98 |
99 // Current PP, FP, and PC. | 99 // Current PP, PC marker FP, and PC. |
| 100 // Callee's PC marker is not used anymore. Pass Function::null() to set to 0. |
100 builder->AddPp(current->function(), slot_ix++); | 101 builder->AddPp(current->function(), slot_ix++); |
| 102 builder->AddPcMarker(Function::Handle(zone), slot_ix++); |
101 builder->AddCallerFp(slot_ix++); | 103 builder->AddCallerFp(slot_ix++); |
102 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); | 104 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); |
103 | 105 |
104 // Callee's PC marker is not used anymore. Pass Code::null() to set to 0. | |
105 builder->AddPcMarker(Function::Handle(zone), slot_ix++); | |
106 | 106 |
107 // Emit all values that are needed for materialization as a part of the | 107 // Emit all values that are needed for materialization as a part of the |
108 // expression stack for the bottom-most frame. This guarantees that GC | 108 // expression stack for the bottom-most frame. This guarantees that GC |
109 // will be able to find them during materialization. | 109 // will be able to find them during materialization. |
110 slot_ix = builder->EmitMaterializationArguments(slot_ix); | 110 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
111 | 111 |
112 // For the innermost environment, set outgoing arguments and the locals. | 112 // For the innermost environment, set outgoing arguments and the locals. |
113 for (intptr_t i = current->Length() - 1; | 113 for (intptr_t i = current->Length() - 1; |
114 i >= current->fixed_parameter_count(); | 114 i >= current->fixed_parameter_count(); |
115 i--) { | 115 i--) { |
116 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); | 116 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
117 } | 117 } |
118 | 118 |
119 Environment* previous = current; | 119 Environment* previous = current; |
120 current = current->outer(); | 120 current = current->outer(); |
121 while (current != NULL) { | 121 while (current != NULL) { |
122 // PP, FP, and PC. | 122 // PP, PC marker, FP, and PC. |
123 builder->AddPp(current->function(), slot_ix++); | 123 builder->AddPp(current->function(), slot_ix++); |
| 124 builder->AddPcMarker(previous->function(), slot_ix++); |
124 builder->AddCallerFp(slot_ix++); | 125 builder->AddCallerFp(slot_ix++); |
125 | 126 |
126 // For any outer environment the deopt id is that of the call instruction | 127 // For any outer environment the deopt id is that of the call instruction |
127 // which is recorded in the outer environment. | 128 // which is recorded in the outer environment. |
128 builder->AddReturnAddress( | 129 builder->AddReturnAddress( |
129 current->function(), | 130 current->function(), |
130 Isolate::ToDeoptAfter(current->deopt_id()), | 131 Isolate::ToDeoptAfter(current->deopt_id()), |
131 slot_ix++); | 132 slot_ix++); |
132 | 133 |
133 // PC marker. | |
134 builder->AddPcMarker(previous->function(), slot_ix++); | |
135 | |
136 // The values of outgoing arguments can be changed from the inlined call so | 134 // The values of outgoing arguments can be changed from the inlined call so |
137 // we must read them from the previous environment. | 135 // we must read them from the previous environment. |
138 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 136 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
139 builder->AddCopy(previous->ValueAt(i), | 137 builder->AddCopy(previous->ValueAt(i), |
140 previous->LocationAt(i), | 138 previous->LocationAt(i), |
141 slot_ix++); | 139 slot_ix++); |
142 } | 140 } |
143 | 141 |
144 // Set the locals, note that outgoing arguments are not in the environment. | 142 // Set the locals, note that outgoing arguments are not in the environment. |
145 for (intptr_t i = current->Length() - 1; | 143 for (intptr_t i = current->Length() - 1; |
146 i >= current->fixed_parameter_count(); | 144 i >= current->fixed_parameter_count(); |
147 i--) { | 145 i--) { |
148 builder->AddCopy(current->ValueAt(i), | 146 builder->AddCopy(current->ValueAt(i), |
149 current->LocationAt(i), | 147 current->LocationAt(i), |
150 slot_ix++); | 148 slot_ix++); |
151 } | 149 } |
152 | 150 |
153 // Iterate on the outer environment. | 151 // Iterate on the outer environment. |
154 previous = current; | 152 previous = current; |
155 current = current->outer(); | 153 current = current->outer(); |
156 } | 154 } |
157 // The previous pointer is now the outermost environment. | 155 // The previous pointer is now the outermost environment. |
158 ASSERT(previous != NULL); | 156 ASSERT(previous != NULL); |
159 | 157 |
160 // For the outermost environment, set caller PC, caller PP, and caller FP. | 158 // For the outermost environment, set caller PC, PP, PC marker and caller FP. |
161 builder->AddCallerPp(slot_ix++); | 159 builder->AddCallerPp(slot_ix++); |
| 160 builder->AddPcMarker(previous->function(), slot_ix++); |
162 builder->AddCallerFp(slot_ix++); | 161 builder->AddCallerFp(slot_ix++); |
163 builder->AddCallerPc(slot_ix++); | 162 builder->AddCallerPc(slot_ix++); |
164 | 163 |
165 // PC marker. | |
166 builder->AddPcMarker(previous->function(), slot_ix++); | |
167 | |
168 // For the outermost environment, set the incoming arguments. | 164 // For the outermost environment, set the incoming arguments. |
169 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 165 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
170 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); | 166 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); |
171 } | 167 } |
172 | 168 |
173 return builder->CreateDeoptInfo(deopt_table); | 169 return builder->CreateDeoptInfo(deopt_table); |
174 } | 170 } |
175 | 171 |
176 | 172 |
177 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, | 173 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, |
178 intptr_t stub_ix) { | 174 intptr_t stub_ix) { |
179 // Calls do not need stubs, they share a deoptimization trampoline. | 175 // Calls do not need stubs, they share a deoptimization trampoline. |
180 ASSERT(reason() != ICData::kDeoptAtCall); | 176 ASSERT(reason() != ICData::kDeoptAtCall); |
181 Assembler* assem = compiler->assembler(); | 177 Assembler* assem = compiler->assembler(); |
182 #define __ assem-> | 178 #define __ assem-> |
183 __ Comment("%s", Name()); | 179 __ Comment("%s", Name()); |
184 __ Bind(entry_label()); | 180 __ Bind(entry_label()); |
185 if (FLAG_trap_on_deoptimization) { | 181 if (FLAG_trap_on_deoptimization) { |
186 __ break_(0); | 182 __ break_(0); |
187 } | 183 } |
188 | 184 |
189 ASSERT(deopt_env() != NULL); | 185 ASSERT(deopt_env() != NULL); |
190 | 186 __ Push(CODE_REG); |
191 __ BranchLink(*StubCode::Deoptimize_entry()); | 187 __ BranchLink(*StubCode::Deoptimize_entry()); |
192 set_pc_offset(assem->CodeSize()); | 188 set_pc_offset(assem->CodeSize()); |
193 #undef __ | 189 #undef __ |
194 } | 190 } |
195 | 191 |
196 | 192 |
197 #define __ assembler()-> | 193 #define __ assembler()-> |
198 | 194 |
199 | 195 |
200 // Fall through if bool_register contains null. | 196 // Fall through if bool_register contains null. |
(...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
921 if (check_correct_named_args) { | 917 if (check_correct_named_args) { |
922 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 918 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
923 __ SmiUntag(T1); | 919 __ SmiUntag(T1); |
924 // Check that T2 equals T1, i.e. no named arguments passed. | 920 // Check that T2 equals T1, i.e. no named arguments passed. |
925 __ beq(T2, T1, &all_arguments_processed); | 921 __ beq(T2, T1, &all_arguments_processed); |
926 } | 922 } |
927 } | 923 } |
928 | 924 |
929 __ Bind(&wrong_num_arguments); | 925 __ Bind(&wrong_num_arguments); |
930 if (function.IsClosureFunction()) { | 926 if (function.IsClosureFunction()) { |
931 __ LeaveDartFrame(); // The arguments are still on the stack. | 927 __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack. |
932 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); | 928 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); |
933 // The noSuchMethod call may return to the caller, but not here. | 929 // The noSuchMethod call may return to the caller, but not here. |
934 } else if (check_correct_named_args) { | 930 } else if (check_correct_named_args) { |
935 __ Stop("Wrong arguments"); | 931 __ Stop("Wrong arguments"); |
936 } | 932 } |
937 | 933 |
938 __ Bind(&all_arguments_processed); | 934 __ Bind(&all_arguments_processed); |
939 // Nullify originally passed arguments only after they have been copied and | 935 // Nullify originally passed arguments only after they have been copied and |
940 // checked, otherwise noSuchMethod would not see their original values. | 936 // checked, otherwise noSuchMethod would not see their original values. |
941 // This step can be skipped in case we decide that formal parameters are | 937 // This step can be skipped in case we decide that formal parameters are |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
979 // Sequence node has one store node and one return NULL node. | 975 // Sequence node has one store node and one return NULL node. |
980 __ Comment("Inlined Setter"); | 976 __ Comment("Inlined Setter"); |
981 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. | 977 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. |
982 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. | 978 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. |
983 __ StoreIntoObjectOffset(T0, offset, T1); | 979 __ StoreIntoObjectOffset(T0, offset, T1); |
984 __ LoadImmediate(V0, reinterpret_cast<int32_t>(Object::null())); | 980 __ LoadImmediate(V0, reinterpret_cast<int32_t>(Object::null())); |
985 __ Ret(); | 981 __ Ret(); |
986 } | 982 } |
987 | 983 |
988 | 984 |
| 985 static const Register new_pp = T7; |
| 986 |
| 987 |
989 void FlowGraphCompiler::EmitFrameEntry() { | 988 void FlowGraphCompiler::EmitFrameEntry() { |
990 const Function& function = parsed_function().function(); | 989 const Function& function = parsed_function().function(); |
991 if (CanOptimizeFunction() && | 990 if (CanOptimizeFunction() && |
992 function.IsOptimizable() && | 991 function.IsOptimizable() && |
993 (!is_optimizing() || may_reoptimize())) { | 992 (!is_optimizing() || may_reoptimize())) { |
994 const Register function_reg = T0; | 993 const Register function_reg = T0; |
995 | 994 |
996 __ GetNextPC(T2, TMP); | |
997 | |
998 // Calculate offset of pool pointer from the PC. | |
999 const intptr_t object_pool_pc_dist = | |
1000 Instructions::HeaderSize() - Instructions::object_pool_offset() + | |
1001 assembler()->CodeSize() - 1 * Instr::kInstrSize; | |
1002 | |
1003 // Preserve PP of caller. | |
1004 __ mov(T1, PP); | |
1005 // Temporarily setup pool pointer for this dart function. | 995 // Temporarily setup pool pointer for this dart function. |
1006 __ lw(PP, Address(T2, -object_pool_pc_dist)); | 996 __ LoadPoolPointer(new_pp); |
1007 // Load function object from object pool. | 997 // Load function object from object pool. |
1008 __ LoadObject(function_reg, function); // Uses PP. | 998 __ LoadFunctionFromCalleePool(function_reg, function, new_pp); |
1009 // Restore PP of caller. | |
1010 __ mov(PP, T1); | |
1011 | |
1012 // Patch point is after the eventually inlined function object. | |
1013 entry_patch_pc_offset_ = assembler()->CodeSize(); | |
1014 | 999 |
1015 __ lw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); | 1000 __ lw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); |
1016 // Reoptimization of an optimized function is triggered by counting in | 1001 // Reoptimization of an optimized function is triggered by counting in |
1017 // IC stubs, but not at the entry of the function. | 1002 // IC stubs, but not at the entry of the function. |
1018 if (!is_optimizing()) { | 1003 if (!is_optimizing()) { |
1019 __ addiu(T1, T1, Immediate(1)); | 1004 __ addiu(T1, T1, Immediate(1)); |
1020 __ sw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); | 1005 __ sw(T1, FieldAddress(function_reg, Function::usage_counter_offset())); |
1021 } | 1006 } |
1022 | 1007 |
1023 // Skip Branch if T1 is less than the threshold. | 1008 // Skip Branch if T1 is less than the threshold. |
1024 Label dont_branch; | 1009 Label dont_branch; |
1025 __ BranchSignedLess( | 1010 __ BranchSignedLess( |
1026 T1, Immediate(GetOptimizationThreshold()), &dont_branch); | 1011 T1, Immediate(GetOptimizationThreshold()), &dont_branch); |
1027 | 1012 |
1028 ASSERT(function_reg == T0); | 1013 ASSERT(function_reg == T0); |
1029 __ Branch(*StubCode::OptimizeFunction_entry()); | 1014 __ Branch(*StubCode::OptimizeFunction_entry(), new_pp); |
1030 | 1015 |
1031 __ Bind(&dont_branch); | 1016 __ Bind(&dont_branch); |
1032 | |
1033 } else if (!flow_graph().IsCompiledForOsr()) { | |
1034 entry_patch_pc_offset_ = assembler()->CodeSize(); | |
1035 } | 1017 } |
1036 __ Comment("Enter frame"); | 1018 __ Comment("Enter frame"); |
1037 if (flow_graph().IsCompiledForOsr()) { | 1019 if (flow_graph().IsCompiledForOsr()) { |
1038 intptr_t extra_slots = StackSize() | 1020 intptr_t extra_slots = StackSize() |
1039 - flow_graph().num_stack_locals() | 1021 - flow_graph().num_stack_locals() |
1040 - flow_graph().num_copied_params(); | 1022 - flow_graph().num_copied_params(); |
1041 ASSERT(extra_slots >= 0); | 1023 ASSERT(extra_slots >= 0); |
1042 __ EnterOsrFrame(extra_slots * kWordSize); | 1024 __ EnterOsrFrame(extra_slots * kWordSize); |
1043 } else { | 1025 } else { |
1044 ASSERT(StackSize() >= 0); | 1026 ASSERT(StackSize() >= 0); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1085 Label correct_num_arguments, wrong_num_arguments; | 1067 Label correct_num_arguments, wrong_num_arguments; |
1086 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 1068 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
1087 __ BranchNotEqual(T0, Immediate(Smi::RawValue(num_fixed_params)), | 1069 __ BranchNotEqual(T0, Immediate(Smi::RawValue(num_fixed_params)), |
1088 &wrong_num_arguments); | 1070 &wrong_num_arguments); |
1089 | 1071 |
1090 __ lw(T1, FieldAddress(S4, | 1072 __ lw(T1, FieldAddress(S4, |
1091 ArgumentsDescriptor::positional_count_offset())); | 1073 ArgumentsDescriptor::positional_count_offset())); |
1092 __ beq(T0, T1, &correct_num_arguments); | 1074 __ beq(T0, T1, &correct_num_arguments); |
1093 __ Bind(&wrong_num_arguments); | 1075 __ Bind(&wrong_num_arguments); |
1094 if (function.IsClosureFunction()) { | 1076 if (function.IsClosureFunction()) { |
1095 __ LeaveDartFrame(); // The arguments are still on the stack. | 1077 __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack. |
1096 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); | 1078 __ Branch(*StubCode::CallClosureNoSuchMethod_entry()); |
1097 // The noSuchMethod call may return to the caller, but not here. | 1079 // The noSuchMethod call may return to the caller, but not here. |
1098 } else { | 1080 } else { |
1099 __ Stop("Wrong number of arguments"); | 1081 __ Stop("Wrong number of arguments"); |
1100 } | 1082 } |
1101 __ Bind(&correct_num_arguments); | 1083 __ Bind(&correct_num_arguments); |
1102 } | 1084 } |
1103 } else if (!flow_graph().IsCompiledForOsr()) { | 1085 } else if (!flow_graph().IsCompiledForOsr()) { |
1104 CopyParameters(); | 1086 CopyParameters(); |
1105 } | 1087 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1138 ASSERT(num_locals > 1); | 1120 ASSERT(num_locals > 1); |
1139 __ sw(V0, Address(FP, (slot_base - i) * kWordSize)); | 1121 __ sw(V0, Address(FP, (slot_base - i) * kWordSize)); |
1140 } | 1122 } |
1141 } | 1123 } |
1142 } | 1124 } |
1143 | 1125 |
1144 VisitBlocks(); | 1126 VisitBlocks(); |
1145 | 1127 |
1146 __ break_(0); | 1128 __ break_(0); |
1147 GenerateDeferredCode(); | 1129 GenerateDeferredCode(); |
1148 // Emit function patching code. This will be swapped with the first 5 bytes | |
1149 // at entry point. | |
1150 patch_code_pc_offset_ = assembler()->CodeSize(); | |
1151 __ BranchPatchable(*StubCode::FixCallersTarget_entry()); | |
1152 | 1130 |
1153 if (is_optimizing()) { | 1131 if (is_optimizing()) { |
1154 lazy_deopt_pc_offset_ = assembler()->CodeSize(); | 1132 lazy_deopt_pc_offset_ = assembler()->CodeSize(); |
1155 __ Branch(*StubCode::DeoptimizeLazy_entry()); | 1133 __ Branch(*StubCode::DeoptimizeLazy_entry()); |
1156 } | 1134 } |
1157 } | 1135 } |
1158 | 1136 |
1159 | 1137 |
1160 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1138 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
1161 const StubEntry& stub_entry, | 1139 const StubEntry& stub_entry, |
(...skipping 697 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1859 __ AddImmediate(SP, kDoubleSize); | 1837 __ AddImmediate(SP, kDoubleSize); |
1860 } | 1838 } |
1861 | 1839 |
1862 | 1840 |
1863 #undef __ | 1841 #undef __ |
1864 | 1842 |
1865 | 1843 |
1866 } // namespace dart | 1844 } // namespace dart |
1867 | 1845 |
1868 #endif // defined TARGET_ARCH_MIPS | 1846 #endif // defined TARGET_ARCH_MIPS |
OLD | NEW |