| 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 "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 380 } | 380 } |
| 381 | 381 |
| 382 | 382 |
| 383 // Generates inlined check if 'type' is a type parameter or type itself | 383 // Generates inlined check if 'type' is a type parameter or type itself |
| 384 // A0: instance (preserved). | 384 // A0: instance (preserved). |
| 385 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 385 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 386 intptr_t token_pos, | 386 intptr_t token_pos, |
| 387 const AbstractType& type, | 387 const AbstractType& type, |
| 388 Label* is_instance_lbl, | 388 Label* is_instance_lbl, |
| 389 Label* is_not_instance_lbl) { | 389 Label* is_not_instance_lbl) { |
| 390 __ TraceSimMsg("UninstantiatedTypeTest"); |
| 390 __ Comment("UninstantiatedTypeTest"); | 391 __ Comment("UninstantiatedTypeTest"); |
| 391 ASSERT(!type.IsInstantiated()); | 392 ASSERT(!type.IsInstantiated()); |
| 392 // Skip check if destination is a dynamic type. | 393 // Skip check if destination is a dynamic type. |
| 393 if (type.IsTypeParameter()) { | 394 if (type.IsTypeParameter()) { |
| 394 const TypeParameter& type_param = TypeParameter::Cast(type); | 395 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 395 // Load instantiator (or null) and instantiator type arguments on stack. | 396 // Load instantiator (or null) and instantiator type arguments on stack. |
| 396 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. | 397 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. |
| 397 // A1: instantiator type arguments. | 398 // A1: instantiator type arguments. |
| 398 // Check if type argument is dynamic. | 399 // Check if type argument is dynamic. |
| 399 __ beq(A1, NULLREG, is_instance_lbl); | 400 __ beq(A1, NULLREG, is_instance_lbl); |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 __ subu(T1, T1, T2); | 711 __ subu(T1, T1, T2); |
| 711 __ sll(T1, T1, 1); | 712 __ sll(T1, T1, 1); |
| 712 __ addu(T1, FP, T1); | 713 __ addu(T1, FP, T1); |
| 713 __ AddImmediate(T1, (kParamEndSlotFromFp + 1) * kWordSize); | 714 __ AddImmediate(T1, (kParamEndSlotFromFp + 1) * kWordSize); |
| 714 | 715 |
| 715 // Let T0 point to the last copied positional argument, i.e. to | 716 // Let T0 point to the last copied positional argument, i.e. to |
| 716 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. | 717 // fp[kFirstLocalSlotFromFp - (num_pos_args - 1)]. |
| 717 __ AddImmediate(T0, FP, (kFirstLocalSlotFromFp + 1) * kWordSize); | 718 __ AddImmediate(T0, FP, (kFirstLocalSlotFromFp + 1) * kWordSize); |
| 718 __ sll(T2, T2, 1); // T2 is a Smi. | 719 __ sll(T2, T2, 1); // T2 is a Smi. |
| 719 | 720 |
| 721 __ Comment("Argument Copy Loop"); |
| 720 Label loop, loop_exit; | 722 Label loop, loop_exit; |
| 721 __ blez(T2, &loop_exit); | 723 __ blez(T2, &loop_exit); |
| 722 __ delay_slot()->subu(T0, T0, T2); | 724 __ delay_slot()->subu(T0, T0, T2); |
| 723 __ Bind(&loop); | 725 __ Bind(&loop); |
| 724 __ addu(T4, T1, T2); | 726 __ addu(T4, T1, T2); |
| 725 __ lw(T3, Address(T4, -kWordSize)); | 727 __ lw(T3, Address(T4, -kWordSize)); |
| 726 __ addiu(T2, T2, Immediate(-kWordSize)); | 728 __ addiu(T2, T2, Immediate(-kWordSize)); |
| 727 __ addu(T5, T0, T2); | 729 __ addu(T5, T0, T2); |
| 728 __ bgtz(T2, &loop); | 730 __ bgtz(T2, &loop); |
| 729 __ delay_slot()->sw(T3, Address(T5)); | 731 __ delay_slot()->sw(T3, Address(T5)); |
| 730 __ Bind(&loop_exit); | 732 __ Bind(&loop_exit); |
| 731 | 733 |
| 732 // Copy or initialize optional named arguments. | 734 // Copy or initialize optional named arguments. |
| 733 Label all_arguments_processed; | 735 Label all_arguments_processed; |
| 734 if (num_opt_named_params > 0) { | 736 if (num_opt_named_params > 0) { |
| 737 __ Comment("There are named parameters"); |
| 735 // Start by alphabetically sorting the names of the optional parameters. | 738 // Start by alphabetically sorting the names of the optional parameters. |
| 736 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; | 739 LocalVariable** opt_param = new LocalVariable*[num_opt_named_params]; |
| 737 int* opt_param_position = new int[num_opt_named_params]; | 740 int* opt_param_position = new int[num_opt_named_params]; |
| 738 for (int pos = num_fixed_params; pos < num_params; pos++) { | 741 for (int pos = num_fixed_params; pos < num_params; pos++) { |
| 739 LocalVariable* parameter = scope->VariableAt(pos); | 742 LocalVariable* parameter = scope->VariableAt(pos); |
| 740 const String& opt_param_name = parameter->name(); | 743 const String& opt_param_name = parameter->name(); |
| 741 int i = pos - num_fixed_params; | 744 int i = pos - num_fixed_params; |
| 742 while (--i >= 0) { | 745 while (--i >= 0) { |
| 743 LocalVariable* param_i = opt_param[i]; | 746 LocalVariable* param_i = opt_param[i]; |
| 744 const intptr_t result = opt_param_name.CompareTo(param_i->name()); | 747 const intptr_t result = opt_param_name.CompareTo(param_i->name()); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 800 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 798 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); | 801 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); |
| 799 } | 802 } |
| 800 delete[] opt_param; | 803 delete[] opt_param; |
| 801 delete[] opt_param_position; | 804 delete[] opt_param_position; |
| 802 // Check that T0 now points to the null terminator in the array descriptor. | 805 // Check that T0 now points to the null terminator in the array descriptor. |
| 803 __ lw(T3, Address(T0)); | 806 __ lw(T3, Address(T0)); |
| 804 __ beq(T3, NULLREG, &all_arguments_processed); | 807 __ beq(T3, NULLREG, &all_arguments_processed); |
| 805 } else { | 808 } else { |
| 806 ASSERT(num_opt_pos_params > 0); | 809 ASSERT(num_opt_pos_params > 0); |
| 810 __ Comment("There are optional positional parameters"); |
| 807 __ lw(T2, | 811 __ lw(T2, |
| 808 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); | 812 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); |
| 809 __ SmiUntag(T2); | 813 __ SmiUntag(T2); |
| 810 for (int i = 0; i < num_opt_pos_params; i++) { | 814 for (int i = 0; i < num_opt_pos_params; i++) { |
| 811 Label next_parameter; | 815 Label next_parameter; |
| 812 // Handle this optional positional parameter only if k or fewer positional | 816 // Handle this optional positional parameter only if k or fewer positional |
| 813 // arguments have been passed, where k is param_pos, the position of this | 817 // arguments have been passed, where k is param_pos, the position of this |
| 814 // optional parameter in the formal parameter list. | 818 // optional parameter in the formal parameter list. |
| 815 const int param_pos = num_fixed_params + i; | 819 const int param_pos = num_fixed_params + i; |
| 816 __ BranchSignedGreater(T2, param_pos, &next_parameter); | 820 __ BranchSignedGreater(T2, param_pos, &next_parameter); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 875 // Nullify originally passed arguments only after they have been copied and | 879 // Nullify originally passed arguments only after they have been copied and |
| 876 // checked, otherwise noSuchMethod would not see their original values. | 880 // checked, otherwise noSuchMethod would not see their original values. |
| 877 // This step can be skipped in case we decide that formal parameters are | 881 // This step can be skipped in case we decide that formal parameters are |
| 878 // implicitly final, since garbage collecting the unmodified value is not | 882 // implicitly final, since garbage collecting the unmodified value is not |
| 879 // an issue anymore. | 883 // an issue anymore. |
| 880 | 884 |
| 881 // S4 : arguments descriptor array. | 885 // S4 : arguments descriptor array. |
| 882 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 886 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 883 __ sll(T2, T2, 1); // T2 is a Smi. | 887 __ sll(T2, T2, 1); // T2 is a Smi. |
| 884 | 888 |
| 889 __ Comment("Null arguments loop"); |
| 885 Label null_args_loop, null_args_loop_exit; | 890 Label null_args_loop, null_args_loop_exit; |
| 886 __ blez(T2, &null_args_loop_exit); | 891 __ blez(T2, &null_args_loop_exit); |
| 887 __ delay_slot()->addiu(T1, FP, | 892 __ delay_slot()->addiu(T1, FP, |
| 888 Immediate((kParamEndSlotFromFp + 1) * kWordSize)); | 893 Immediate((kParamEndSlotFromFp + 1) * kWordSize)); |
| 889 __ Bind(&null_args_loop); | 894 __ Bind(&null_args_loop); |
| 890 __ addiu(T2, T2, Immediate(-kWordSize)); | 895 __ addiu(T2, T2, Immediate(-kWordSize)); |
| 891 __ addu(T3, T1, T2); | 896 __ addu(T3, T1, T2); |
| 892 __ bgtz(T2, &null_args_loop); | 897 __ bgtz(T2, &null_args_loop); |
| 893 __ delay_slot()->sw(NULLREG, Address(T3)); | 898 __ delay_slot()->sw(NULLREG, Address(T3)); |
| 894 __ Bind(&null_args_loop_exit); | 899 __ Bind(&null_args_loop_exit); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 912 // Sequence node has one store node and one return NULL node. | 917 // Sequence node has one store node and one return NULL node. |
| 913 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. | 918 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. |
| 914 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. | 919 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. |
| 915 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); | 920 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); |
| 916 __ Ret(); | 921 __ Ret(); |
| 917 __ delay_slot()->mov(V0, NULLREG); | 922 __ delay_slot()->mov(V0, NULLREG); |
| 918 } | 923 } |
| 919 | 924 |
| 920 | 925 |
| 921 void FlowGraphCompiler::EmitFrameEntry() { | 926 void FlowGraphCompiler::EmitFrameEntry() { |
| 922 __ TraceSimMsg("FrameEntry"); | |
| 923 const Function& function = parsed_function().function(); | 927 const Function& function = parsed_function().function(); |
| 924 if (CanOptimizeFunction() && function.is_optimizable()) { | 928 if (CanOptimizeFunction() && function.is_optimizable()) { |
| 925 const bool can_optimize = !is_optimizing() || may_reoptimize(); | 929 const bool can_optimize = !is_optimizing() || may_reoptimize(); |
| 926 const Register function_reg = T0; | 930 const Register function_reg = T0; |
| 927 if (can_optimize) { | 931 if (can_optimize) { |
| 928 Label next; | 932 Label next; |
| 929 // The pool pointer is not setup before entering the Dart frame. | 933 // The pool pointer is not setup before entering the Dart frame. |
| 930 | 934 |
| 931 __ mov(TMP1, RA); // Save RA. | 935 __ mov(TMP1, RA); // Save RA. |
| 932 __ bal(&next); // Branch and link to next instruction to get PC in RA. | 936 __ bal(&next); // Branch and link to next instruction to get PC in RA. |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 Isolate::kNoDeoptId, | 1141 Isolate::kNoDeoptId, |
| 1138 0); // No token position. | 1142 0); // No token position. |
| 1139 __ Branch(&StubCode::DeoptimizeLazyLabel()); | 1143 __ Branch(&StubCode::DeoptimizeLazyLabel()); |
| 1140 } | 1144 } |
| 1141 | 1145 |
| 1142 | 1146 |
| 1143 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1147 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
| 1144 const ExternalLabel* label, | 1148 const ExternalLabel* label, |
| 1145 PcDescriptors::Kind kind, | 1149 PcDescriptors::Kind kind, |
| 1146 LocationSummary* locs) { | 1150 LocationSummary* locs) { |
| 1147 __ TraceSimMsg("Call"); | |
| 1148 __ BranchLinkPatchable(label); | 1151 __ BranchLinkPatchable(label); |
| 1149 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); | 1152 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); |
| 1150 RecordSafepoint(locs); | 1153 RecordSafepoint(locs); |
| 1151 } | 1154 } |
| 1152 | 1155 |
| 1153 | 1156 |
| 1154 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, | 1157 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, |
| 1155 intptr_t token_pos, | 1158 intptr_t token_pos, |
| 1156 const ExternalLabel* label, | 1159 const ExternalLabel* label, |
| 1157 PcDescriptors::Kind kind, | 1160 PcDescriptors::Kind kind, |
| 1158 LocationSummary* locs) { | 1161 LocationSummary* locs) { |
| 1159 __ TraceSimMsg("DartCall"); | |
| 1160 __ BranchLinkPatchable(label); | 1162 __ BranchLinkPatchable(label); |
| 1161 AddCurrentDescriptor(kind, deopt_id, token_pos); | 1163 AddCurrentDescriptor(kind, deopt_id, token_pos); |
| 1162 RecordSafepoint(locs); | 1164 RecordSafepoint(locs); |
| 1163 // Marks either the continuation point in unoptimized code or the | 1165 // Marks either the continuation point in unoptimized code or the |
| 1164 // deoptimization point in optimized code, after call. | 1166 // deoptimization point in optimized code, after call. |
| 1165 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); | 1167 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); |
| 1166 if (is_optimizing()) { | 1168 if (is_optimizing()) { |
| 1167 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 1169 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
| 1168 } else { | 1170 } else { |
| 1169 // Add deoptimization continuation point after the call and before the | 1171 // Add deoptimization continuation point after the call and before the |
| 1170 // arguments are removed. | 1172 // arguments are removed. |
| 1171 AddCurrentDescriptor(PcDescriptors::kDeopt, | 1173 AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 1172 deopt_id_after, | 1174 deopt_id_after, |
| 1173 token_pos); | 1175 token_pos); |
| 1174 } | 1176 } |
| 1175 } | 1177 } |
| 1176 | 1178 |
| 1177 | 1179 |
| 1178 void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos, | 1180 void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos, |
| 1179 intptr_t deopt_id, | 1181 intptr_t deopt_id, |
| 1180 const RuntimeEntry& entry, | 1182 const RuntimeEntry& entry, |
| 1181 LocationSummary* locs) { | 1183 LocationSummary* locs) { |
| 1182 __ TraceSimMsg("CallRuntime"); | |
| 1183 __ CallRuntime(entry); | 1184 __ CallRuntime(entry); |
| 1184 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); | 1185 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); |
| 1185 RecordSafepoint(locs); | 1186 RecordSafepoint(locs); |
| 1186 if (deopt_id != Isolate::kNoDeoptId) { | 1187 if (deopt_id != Isolate::kNoDeoptId) { |
| 1187 // Marks either the continuation point in unoptimized code or the | 1188 // Marks either the continuation point in unoptimized code or the |
| 1188 // deoptimization point in optimized code, after call. | 1189 // deoptimization point in optimized code, after call. |
| 1189 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); | 1190 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); |
| 1190 if (is_optimizing()) { | 1191 if (is_optimizing()) { |
| 1191 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 1192 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
| 1192 } else { | 1193 } else { |
| 1193 // Add deoptimization continuation point after the call and before the | 1194 // Add deoptimization continuation point after the call and before the |
| 1194 // arguments are removed. | 1195 // arguments are removed. |
| 1195 AddCurrentDescriptor(PcDescriptors::kDeopt, | 1196 AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 1196 deopt_id_after, | 1197 deopt_id_after, |
| 1197 token_pos); | 1198 token_pos); |
| 1198 } | 1199 } |
| 1199 } | 1200 } |
| 1200 __ TraceSimMsg("CallRuntime return"); | |
| 1201 } | 1201 } |
| 1202 | 1202 |
| 1203 | 1203 |
| 1204 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 1204 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 1205 ExternalLabel* target_label, | 1205 ExternalLabel* target_label, |
| 1206 const ICData& ic_data, | 1206 const ICData& ic_data, |
| 1207 const Array& arguments_descriptor, | 1207 const Array& arguments_descriptor, |
| 1208 intptr_t argument_count, | 1208 intptr_t argument_count, |
| 1209 intptr_t deopt_id, | 1209 intptr_t deopt_id, |
| 1210 intptr_t token_pos, | 1210 intptr_t token_pos, |
| 1211 LocationSummary* locs) { | 1211 LocationSummary* locs) { |
| 1212 // Each ICData propagated from unoptimized to optimized code contains the | 1212 // Each ICData propagated from unoptimized to optimized code contains the |
| 1213 // function that corresponds to the Dart function of that IC call. Due | 1213 // function that corresponds to the Dart function of that IC call. Due |
| 1214 // to inlining in optimized code, that function may not correspond to the | 1214 // to inlining in optimized code, that function may not correspond to the |
| 1215 // top-level function (parsed_function().function()) which could be | 1215 // top-level function (parsed_function().function()) which could be |
| 1216 // reoptimized and which counter needs to be incremented. | 1216 // reoptimized and which counter needs to be incremented. |
| 1217 // Pass the function explicitly, it is used in IC stub. | 1217 // Pass the function explicitly, it is used in IC stub. |
| 1218 __ TraceSimMsg("OptimizedInstanceCall"); |
| 1218 __ LoadObject(T0, parsed_function().function()); | 1219 __ LoadObject(T0, parsed_function().function()); |
| 1219 __ LoadObject(S4, arguments_descriptor); | 1220 __ LoadObject(S4, arguments_descriptor); |
| 1220 __ LoadObject(S5, ic_data); | 1221 __ LoadObject(S5, ic_data); |
| 1221 GenerateDartCall(deopt_id, | 1222 GenerateDartCall(deopt_id, |
| 1222 token_pos, | 1223 token_pos, |
| 1223 target_label, | 1224 target_label, |
| 1224 PcDescriptors::kIcCall, | 1225 PcDescriptors::kIcCall, |
| 1225 locs); | 1226 locs); |
| 1226 __ Drop(argument_count); | 1227 __ Drop(argument_count); |
| 1227 } | 1228 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1247 } | 1248 } |
| 1248 | 1249 |
| 1249 | 1250 |
| 1250 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1251 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 1251 const ICData& ic_data, | 1252 const ICData& ic_data, |
| 1252 const Array& arguments_descriptor, | 1253 const Array& arguments_descriptor, |
| 1253 intptr_t argument_count, | 1254 intptr_t argument_count, |
| 1254 intptr_t deopt_id, | 1255 intptr_t deopt_id, |
| 1255 intptr_t token_pos, | 1256 intptr_t token_pos, |
| 1256 LocationSummary* locs) { | 1257 LocationSummary* locs) { |
| 1257 UNIMPLEMENTED(); | 1258 MegamorphicCacheTable* table = Isolate::Current()->megamorphic_cache_table(); |
| 1259 const String& name = String::Handle(ic_data.target_name()); |
| 1260 const MegamorphicCache& cache = |
| 1261 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); |
| 1262 Label not_smi, load_cache; |
| 1263 __ TraceSimMsg("MegamorphicInstanceCall"); |
| 1264 __ lw(T0, Address(SP, (argument_count - 1) * kWordSize)); |
| 1265 __ andi(CMPRES, T0, Immediate(kSmiTagMask)); |
| 1266 __ bne(CMPRES, ZR, ¬_smi); |
| 1267 __ LoadImmediate(T0, Smi::RawValue(kSmiCid)); |
| 1268 __ b(&load_cache); |
| 1269 |
| 1270 __ Bind(¬_smi); |
| 1271 __ LoadClassId(T0, T0); |
| 1272 __ SmiTag(T0); |
| 1273 |
| 1274 // T0: class ID of the receiver (smi). |
| 1275 __ Bind(&load_cache); |
| 1276 __ LoadObject(T1, cache); |
| 1277 __ lw(T2, FieldAddress(T1, MegamorphicCache::buckets_offset())); |
| 1278 __ lw(T1, FieldAddress(T1, MegamorphicCache::mask_offset())); |
| 1279 // T2: cache buckets array. |
| 1280 // T1: mask. |
| 1281 __ mov(T3, T0); |
| 1282 |
| 1283 Label loop, update, call_target_function; |
| 1284 __ b(&loop); |
| 1285 |
| 1286 __ Bind(&update); |
| 1287 __ addiu(T3, T3, Immediate(Smi::RawValue(1))); |
| 1288 __ Bind(&loop); |
| 1289 __ and_(T3, T3, T1); |
| 1290 const intptr_t base = Array::data_offset(); |
| 1291 // T3 is smi tagged, but table entries are two words, so LSL 2. |
| 1292 __ sll(TMP1, T3, 2); |
| 1293 __ addu(TMP1, T2, TMP1); |
| 1294 __ lw(T4, FieldAddress(TMP, base)); |
| 1295 |
| 1296 ASSERT(kIllegalCid == 0); |
| 1297 __ beq(T4, ZR, &call_target_function); |
| 1298 __ bne(T4, T0, &update); |
| 1299 |
| 1300 __ Bind(&call_target_function); |
| 1301 // Call the target found in the cache. For a class id match, this is a |
| 1302 // proper target for the given name and arguments descriptor. If the |
| 1303 // illegal class id was found, the target is a cache miss handler that can |
| 1304 // be invoked as a normal Dart function. |
| 1305 __ sll(TMP1, T3, 2); |
| 1306 __ addu(TMP1, T2, TMP1); |
| 1307 __ lw(T0, FieldAddress(TMP, base + kWordSize)); |
| 1308 __ lw(T0, FieldAddress(T0, Function::code_offset())); |
| 1309 __ lw(T0, FieldAddress(T0, Code::instructions_offset())); |
| 1310 __ LoadObject(S5, ic_data); |
| 1311 __ LoadObject(S4, arguments_descriptor); |
| 1312 __ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag); |
| 1313 __ jalr(T0); |
| 1314 AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos); |
| 1315 RecordSafepoint(locs); |
| 1316 AddDeoptIndexAtCall(Isolate::ToDeoptAfter(deopt_id), token_pos); |
| 1317 __ Drop(argument_count); |
| 1258 } | 1318 } |
| 1259 | 1319 |
| 1260 | 1320 |
| 1261 void FlowGraphCompiler::EmitStaticCall(const Function& function, | 1321 void FlowGraphCompiler::EmitStaticCall(const Function& function, |
| 1262 const Array& arguments_descriptor, | 1322 const Array& arguments_descriptor, |
| 1263 intptr_t argument_count, | 1323 intptr_t argument_count, |
| 1264 intptr_t deopt_id, | 1324 intptr_t deopt_id, |
| 1265 intptr_t token_pos, | 1325 intptr_t token_pos, |
| 1266 LocationSummary* locs) { | 1326 LocationSummary* locs) { |
| 1267 __ TraceSimMsg("StaticCall"); | 1327 __ TraceSimMsg("StaticCall"); |
| 1268 __ LoadObject(S4, arguments_descriptor); | 1328 __ LoadObject(S4, arguments_descriptor); |
| 1269 // Do not use the code from the function, but let the code be patched so that | 1329 // Do not use the code from the function, but let the code be patched so that |
| 1270 // we can record the outgoing edges to other code. | 1330 // we can record the outgoing edges to other code. |
| 1271 GenerateDartCall(deopt_id, | 1331 GenerateDartCall(deopt_id, |
| 1272 token_pos, | 1332 token_pos, |
| 1273 &StubCode::CallStaticFunctionLabel(), | 1333 &StubCode::CallStaticFunctionLabel(), |
| 1274 PcDescriptors::kFuncCall, | 1334 PcDescriptors::kFuncCall, |
| 1275 locs); | 1335 locs); |
| 1276 AddStaticCallTarget(function); | 1336 AddStaticCallTarget(function); |
| 1277 __ Drop(argument_count); | 1337 __ Drop(argument_count); |
| 1278 } | 1338 } |
| 1279 | 1339 |
| 1280 | 1340 |
| 1281 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, | 1341 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, |
| 1282 const Object& obj, | 1342 const Object& obj, |
| 1283 bool needs_number_check, | 1343 bool needs_number_check, |
| 1284 intptr_t token_pos) { | 1344 intptr_t token_pos) { |
| 1345 __ TraceSimMsg("EqualityRegConstCompare"); |
| 1285 if (needs_number_check && | 1346 if (needs_number_check && |
| 1286 (obj.IsMint() || obj.IsDouble() || obj.IsBigint())) { | 1347 (obj.IsMint() || obj.IsDouble() || obj.IsBigint())) { |
| 1287 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1348 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1288 __ sw(reg, Address(SP, 1 * kWordSize)); | 1349 __ sw(reg, Address(SP, 1 * kWordSize)); |
| 1289 __ LoadObject(TMP1, obj); | 1350 __ LoadObject(TMP1, obj); |
| 1290 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); | 1351 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); |
| 1291 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1352 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1292 Isolate::kNoDeoptId, | 1353 Isolate::kNoDeoptId, |
| 1293 token_pos); | 1354 token_pos); |
| 1294 __ delay_slot()->sw(TMP1, Address(SP, 0 * kWordSize)); | 1355 __ delay_slot()->sw(TMP1, Address(SP, 0 * kWordSize)); |
| 1356 __ TraceSimMsg("EqualityRegConstCompare return"); |
| 1295 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. | 1357 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. |
| 1296 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. | 1358 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. |
| 1297 return; | 1359 return; |
| 1298 } | 1360 } |
| 1299 __ CompareObject(CMPRES, TMP1, reg, obj); | 1361 __ CompareObject(CMPRES, TMP1, reg, obj); |
| 1300 } | 1362 } |
| 1301 | 1363 |
| 1302 | 1364 |
| 1303 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1365 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
| 1304 Register right, | 1366 Register right, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1318 __ lw(right, Address(SP, 0 * kWordSize)); | 1380 __ lw(right, Address(SP, 0 * kWordSize)); |
| 1319 __ lw(left, Address(SP, 1 * kWordSize)); | 1381 __ lw(left, Address(SP, 1 * kWordSize)); |
| 1320 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1382 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1321 } else { | 1383 } else { |
| 1322 __ slt(CMPRES, left, right); | 1384 __ slt(CMPRES, left, right); |
| 1323 __ slt(TMP1, right, left); | 1385 __ slt(TMP1, right, left); |
| 1324 } | 1386 } |
| 1325 } | 1387 } |
| 1326 | 1388 |
| 1327 | 1389 |
| 1390 // Implement equality spec: if any of the arguments is null do identity check. |
| 1391 // Fallthrough calls super equality. |
| 1328 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, | 1392 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, |
| 1329 Label* skip_call) { | 1393 Label* skip_call) { |
| 1330 UNIMPLEMENTED(); | 1394 Label check_identity, is_false, fall_through; |
| 1395 __ TraceSimMsg("SuperEqualityCallPrologue"); |
| 1396 __ lw(result, Address(SP, 0 * kWordSize)); // Load right operand. |
| 1397 __ lw(TMP1, Address(SP, 1 * kWordSize)); // Load left operand. |
| 1398 __ beq(result, NULLREG, &check_identity); // Is right null? |
| 1399 __ bne(TMP1, NULLREG, &fall_through); // If right is non-null, check left. |
| 1400 |
| 1401 __ Bind(&check_identity); |
| 1402 __ bne(result, TMP1, &is_false); |
| 1403 __ LoadObject(result, Bool::True()); |
| 1404 __ Drop(2); |
| 1405 __ b(skip_call); |
| 1406 __ Bind(&is_false); |
| 1407 __ LoadObject(result, Bool::False()); |
| 1408 __ Drop(2); |
| 1409 __ b(skip_call); |
| 1410 __ Bind(&fall_through); |
| 1331 } | 1411 } |
| 1332 | 1412 |
| 1333 | 1413 |
| 1334 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { | 1414 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { |
| 1335 __ TraceSimMsg("SaveLiveRegisters"); | 1415 __ TraceSimMsg("SaveLiveRegisters"); |
| 1336 // TODO(vegorov): consider saving only caller save (volatile) registers. | 1416 // TODO(vegorov): consider saving only caller save (volatile) registers. |
| 1337 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); | 1417 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); |
| 1338 if (fpu_registers > 0) { | 1418 if (fpu_registers > 0) { |
| 1339 UNIMPLEMENTED(); | 1419 UNIMPLEMENTED(); |
| 1340 } | 1420 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1377 | 1457 |
| 1378 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); | 1458 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); |
| 1379 if (fpu_registers > 0) { | 1459 if (fpu_registers > 0) { |
| 1380 UNIMPLEMENTED(); | 1460 UNIMPLEMENTED(); |
| 1381 } | 1461 } |
| 1382 } | 1462 } |
| 1383 | 1463 |
| 1384 | 1464 |
| 1385 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1465 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
| 1386 Register class_id_reg, | 1466 Register class_id_reg, |
| 1387 intptr_t arg_count, | 1467 intptr_t argument_count, |
| 1388 const Array& arg_names, | 1468 const Array& argument_names, |
| 1389 Label* deopt, | 1469 Label* deopt, |
| 1390 intptr_t deopt_id, | 1470 intptr_t deopt_id, |
| 1391 intptr_t token_index, | 1471 intptr_t token_index, |
| 1392 LocationSummary* locs) { | 1472 LocationSummary* locs) { |
| 1393 UNIMPLEMENTED(); | 1473 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 1474 Label match_found; |
| 1475 const intptr_t len = ic_data.NumberOfChecks(); |
| 1476 GrowableArray<CidTarget> sorted(len); |
| 1477 SortICDataByCount(ic_data, &sorted); |
| 1478 ASSERT(class_id_reg != S4); |
| 1479 ASSERT(len > 0); // Why bother otherwise. |
| 1480 const Array& arguments_descriptor = |
| 1481 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
| 1482 argument_names)); |
| 1483 __ TraceSimMsg("EmitTestAndCall"); |
| 1484 __ LoadObject(S4, arguments_descriptor); |
| 1485 for (intptr_t i = 0; i < len; i++) { |
| 1486 const bool is_last_check = (i == (len - 1)); |
| 1487 Label next_test; |
| 1488 if (is_last_check) { |
| 1489 __ BranchNotEqual(class_id_reg, sorted[i].cid, deopt); |
| 1490 } else { |
| 1491 __ BranchNotEqual(class_id_reg, sorted[i].cid, &next_test); |
| 1492 } |
| 1493 // Do not use the code from the function, but let the code be patched so |
| 1494 // that we can record the outgoing edges to other code. |
| 1495 GenerateDartCall(deopt_id, |
| 1496 token_index, |
| 1497 &StubCode::CallStaticFunctionLabel(), |
| 1498 PcDescriptors::kFuncCall, |
| 1499 locs); |
| 1500 const Function& function = *sorted[i].target; |
| 1501 AddStaticCallTarget(function); |
| 1502 __ Drop(argument_count); |
| 1503 if (!is_last_check) { |
| 1504 __ b(&match_found); |
| 1505 } |
| 1506 __ Bind(&next_test); |
| 1507 } |
| 1508 __ Bind(&match_found); |
| 1394 } | 1509 } |
| 1395 | 1510 |
| 1396 | 1511 |
| 1397 void FlowGraphCompiler::EmitDoubleCompareBranch(Condition true_condition, | 1512 void FlowGraphCompiler::EmitDoubleCompareBranch(Condition true_condition, |
| 1398 FpuRegister left, | 1513 FpuRegister left, |
| 1399 FpuRegister right, | 1514 FpuRegister right, |
| 1400 BranchInstr* branch) { | 1515 BranchInstr* branch) { |
| 1401 UNIMPLEMENTED(); | 1516 UNIMPLEMENTED(); |
| 1402 } | 1517 } |
| 1403 | 1518 |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1641 __ AddImmediate(SP, kDoubleSize); | 1756 __ AddImmediate(SP, kDoubleSize); |
| 1642 } | 1757 } |
| 1643 | 1758 |
| 1644 | 1759 |
| 1645 #undef __ | 1760 #undef __ |
| 1646 | 1761 |
| 1647 | 1762 |
| 1648 } // namespace dart | 1763 } // namespace dart |
| 1649 | 1764 |
| 1650 #endif // defined TARGET_ARCH_MIPS | 1765 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |