| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 Assembler* assem = compiler->assembler(); | 156 Assembler* assem = compiler->assembler(); |
| 157 #define __ assem-> | 157 #define __ assem-> |
| 158 __ Comment("Deopt stub for id %" Pd "", deopt_id()); | 158 __ Comment("Deopt stub for id %" Pd "", deopt_id()); |
| 159 __ Bind(entry_label()); | 159 __ Bind(entry_label()); |
| 160 if (FLAG_trap_on_deoptimization) { | 160 if (FLAG_trap_on_deoptimization) { |
| 161 __ brk(0); | 161 __ brk(0); |
| 162 } | 162 } |
| 163 | 163 |
| 164 ASSERT(deopt_env() != NULL); | 164 ASSERT(deopt_env() != NULL); |
| 165 | 165 |
| 166 __ BranchLink(&StubCode::DeoptimizeLabel(), PP); | 166 StubCode* stub_code = compiler->isolate()->stub_code(); |
| 167 __ BranchLink(&stub_code->DeoptimizeLabel(), PP); |
| 167 set_pc_offset(assem->CodeSize()); | 168 set_pc_offset(assem->CodeSize()); |
| 168 #undef __ | 169 #undef __ |
| 169 } | 170 } |
| 170 | 171 |
| 171 | 172 |
| 172 #define __ assembler()-> | 173 #define __ assembler()-> |
| 173 | 174 |
| 174 | 175 |
| 175 // Fall through if bool_register contains null. | 176 // Fall through if bool_register contains null. |
| 176 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 177 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 192 TypeTestStubKind test_kind, | 193 TypeTestStubKind test_kind, |
| 193 Register instance_reg, | 194 Register instance_reg, |
| 194 Register type_arguments_reg, | 195 Register type_arguments_reg, |
| 195 Register temp_reg, | 196 Register temp_reg, |
| 196 Label* is_instance_lbl, | 197 Label* is_instance_lbl, |
| 197 Label* is_not_instance_lbl) { | 198 Label* is_not_instance_lbl) { |
| 198 ASSERT(instance_reg == R0); | 199 ASSERT(instance_reg == R0); |
| 199 ASSERT(temp_reg == kNoRegister); // Unused on ARM. | 200 ASSERT(temp_reg == kNoRegister); // Unused on ARM. |
| 200 const SubtypeTestCache& type_test_cache = | 201 const SubtypeTestCache& type_test_cache = |
| 201 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 202 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 203 StubCode* stub_code = isolate()->stub_code(); |
| 202 __ LoadObject(R2, type_test_cache, PP); | 204 __ LoadObject(R2, type_test_cache, PP); |
| 203 if (test_kind == kTestTypeOneArg) { | 205 if (test_kind == kTestTypeOneArg) { |
| 204 ASSERT(type_arguments_reg == kNoRegister); | 206 ASSERT(type_arguments_reg == kNoRegister); |
| 205 __ LoadObject(R1, Object::null_object(), PP); | 207 __ LoadObject(R1, Object::null_object(), PP); |
| 206 __ BranchLink(&StubCode::Subtype1TestCacheLabel(), PP); | 208 __ BranchLink(&stub_code->Subtype1TestCacheLabel(), PP); |
| 207 } else if (test_kind == kTestTypeTwoArgs) { | 209 } else if (test_kind == kTestTypeTwoArgs) { |
| 208 ASSERT(type_arguments_reg == kNoRegister); | 210 ASSERT(type_arguments_reg == kNoRegister); |
| 209 __ LoadObject(R1, Object::null_object(), PP); | 211 __ LoadObject(R1, Object::null_object(), PP); |
| 210 __ BranchLink(&StubCode::Subtype2TestCacheLabel(), PP); | 212 __ BranchLink(&stub_code->Subtype2TestCacheLabel(), PP); |
| 211 } else if (test_kind == kTestTypeThreeArgs) { | 213 } else if (test_kind == kTestTypeThreeArgs) { |
| 212 ASSERT(type_arguments_reg == R1); | 214 ASSERT(type_arguments_reg == R1); |
| 213 __ BranchLink(&StubCode::Subtype3TestCacheLabel(), PP); | 215 __ BranchLink(&stub_code->Subtype3TestCacheLabel(), PP); |
| 214 } else { | 216 } else { |
| 215 UNREACHABLE(); | 217 UNREACHABLE(); |
| 216 } | 218 } |
| 217 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. | 219 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. |
| 218 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); | 220 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); |
| 219 return type_test_cache.raw(); | 221 return type_test_cache.raw(); |
| 220 } | 222 } |
| 221 | 223 |
| 222 | 224 |
| 223 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 225 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| (...skipping 662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 886 __ SmiUntag(R7); | 888 __ SmiUntag(R7); |
| 887 // Check that R8 equals R7, i.e. no named arguments passed. | 889 // Check that R8 equals R7, i.e. no named arguments passed. |
| 888 __ CompareRegisters(R8, R7); | 890 __ CompareRegisters(R8, R7); |
| 889 __ b(&all_arguments_processed, EQ); | 891 __ b(&all_arguments_processed, EQ); |
| 890 } | 892 } |
| 891 } | 893 } |
| 892 | 894 |
| 893 __ Bind(&wrong_num_arguments); | 895 __ Bind(&wrong_num_arguments); |
| 894 if (function.IsClosureFunction()) { | 896 if (function.IsClosureFunction()) { |
| 895 // Invoke noSuchMethod function passing "call" as the original name. | 897 // Invoke noSuchMethod function passing "call" as the original name. |
| 898 StubCode* stub_code = isolate()->stub_code(); |
| 896 const int kNumArgsChecked = 1; | 899 const int kNumArgsChecked = 1; |
| 897 const ICData& ic_data = ICData::ZoneHandle( | 900 const ICData& ic_data = ICData::ZoneHandle( |
| 898 ICData::New(function, Symbols::Call(), Object::empty_array(), | 901 ICData::New(function, Symbols::Call(), Object::empty_array(), |
| 899 Isolate::kNoDeoptId, kNumArgsChecked)); | 902 Isolate::kNoDeoptId, kNumArgsChecked)); |
| 900 __ LoadObject(R5, ic_data, PP); | 903 __ LoadObject(R5, ic_data, PP); |
| 901 __ LeaveDartFrame(); // The arguments are still on the stack. | 904 __ LeaveDartFrame(); // The arguments are still on the stack. |
| 902 __ BranchPatchable(&StubCode::CallNoSuchMethodFunctionLabel()); | 905 __ BranchPatchable(&stub_code->CallNoSuchMethodFunctionLabel()); |
| 903 // The noSuchMethod call may return to the caller, but not here. | 906 // The noSuchMethod call may return to the caller, but not here. |
| 904 __ brk(0); | 907 __ brk(0); |
| 905 } else if (check_correct_named_args) { | 908 } else if (check_correct_named_args) { |
| 906 __ Stop("Wrong arguments"); | 909 __ Stop("Wrong arguments"); |
| 907 } | 910 } |
| 908 | 911 |
| 909 __ Bind(&all_arguments_processed); | 912 __ Bind(&all_arguments_processed); |
| 910 // Nullify originally passed arguments only after they have been copied and | 913 // Nullify originally passed arguments only after they have been copied and |
| 911 // checked, otherwise noSuchMethod would not see their original values. | 914 // checked, otherwise noSuchMethod would not see their original values. |
| 912 // This step can be skipped in case we decide that formal parameters are | 915 // This step can be skipped in case we decide that formal parameters are |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 954 } | 957 } |
| 955 | 958 |
| 956 | 959 |
| 957 void FlowGraphCompiler::EmitFrameEntry() { | 960 void FlowGraphCompiler::EmitFrameEntry() { |
| 958 const Function& function = parsed_function().function(); | 961 const Function& function = parsed_function().function(); |
| 959 Register new_pp = kNoPP; | 962 Register new_pp = kNoPP; |
| 960 if (CanOptimizeFunction() && | 963 if (CanOptimizeFunction() && |
| 961 function.IsOptimizable() && | 964 function.IsOptimizable() && |
| 962 (!is_optimizing() || may_reoptimize())) { | 965 (!is_optimizing() || may_reoptimize())) { |
| 963 const Register function_reg = R6; | 966 const Register function_reg = R6; |
| 967 StubCode* stub_code = isolate()->stub_code(); |
| 964 new_pp = R13; | 968 new_pp = R13; |
| 965 | 969 |
| 966 // Set up pool pointer in new_pp. | 970 // Set up pool pointer in new_pp. |
| 967 __ LoadPoolPointer(new_pp); | 971 __ LoadPoolPointer(new_pp); |
| 968 | 972 |
| 969 // Load function object using the callee's pool pointer. | 973 // Load function object using the callee's pool pointer. |
| 970 __ LoadObject(function_reg, function, new_pp); | 974 __ LoadObject(function_reg, function, new_pp); |
| 971 | 975 |
| 972 // Patch point is after the eventually inlined function object. | 976 // Patch point is after the eventually inlined function object. |
| 973 entry_patch_pc_offset_ = assembler()->CodeSize(); | 977 entry_patch_pc_offset_ = assembler()->CodeSize(); |
| 974 | 978 |
| 975 intptr_t threshold = FLAG_optimization_counter_threshold; | 979 intptr_t threshold = FLAG_optimization_counter_threshold; |
| 976 __ LoadFieldFromOffset( | 980 __ LoadFieldFromOffset( |
| 977 R7, function_reg, Function::usage_counter_offset(), new_pp, kWord); | 981 R7, function_reg, Function::usage_counter_offset(), new_pp, kWord); |
| 978 if (is_optimizing()) { | 982 if (is_optimizing()) { |
| 979 // Reoptimization of an optimized function is triggered by counting in | 983 // Reoptimization of an optimized function is triggered by counting in |
| 980 // IC stubs, but not at the entry of the function. | 984 // IC stubs, but not at the entry of the function. |
| 981 threshold = FLAG_reoptimization_counter_threshold; | 985 threshold = FLAG_reoptimization_counter_threshold; |
| 982 } else { | 986 } else { |
| 983 __ add(R7, R7, Operand(1)); | 987 __ add(R7, R7, Operand(1)); |
| 984 __ StoreFieldToOffset( | 988 __ StoreFieldToOffset( |
| 985 R7, function_reg, Function::usage_counter_offset(), new_pp, kWord); | 989 R7, function_reg, Function::usage_counter_offset(), new_pp, kWord); |
| 986 } | 990 } |
| 987 __ CompareImmediate(R7, threshold, new_pp); | 991 __ CompareImmediate(R7, threshold, new_pp); |
| 988 ASSERT(function_reg == R6); | 992 ASSERT(function_reg == R6); |
| 989 Label dont_optimize; | 993 Label dont_optimize; |
| 990 __ b(&dont_optimize, LT); | 994 __ b(&dont_optimize, LT); |
| 991 __ Branch(&StubCode::OptimizeFunctionLabel(), new_pp); | 995 __ Branch(&stub_code->OptimizeFunctionLabel(), new_pp); |
| 992 __ Bind(&dont_optimize); | 996 __ Bind(&dont_optimize); |
| 993 } else if (!flow_graph().IsCompiledForOsr()) { | 997 } else if (!flow_graph().IsCompiledForOsr()) { |
| 994 // We have to load the PP here too because a load of an external label | 998 // We have to load the PP here too because a load of an external label |
| 995 // may be patched at the AddCurrentDescriptor below. | 999 // may be patched at the AddCurrentDescriptor below. |
| 996 new_pp = R13; | 1000 new_pp = R13; |
| 997 | 1001 |
| 998 // Set up pool pointer in new_pp. | 1002 // Set up pool pointer in new_pp. |
| 999 __ LoadPoolPointer(new_pp); | 1003 __ LoadPoolPointer(new_pp); |
| 1000 | 1004 |
| 1001 entry_patch_pc_offset_ = assembler()->CodeSize(); | 1005 entry_patch_pc_offset_ = assembler()->CodeSize(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1026 | 1030 |
| 1027 TryIntrinsify(); | 1031 TryIntrinsify(); |
| 1028 | 1032 |
| 1029 EmitFrameEntry(); | 1033 EmitFrameEntry(); |
| 1030 | 1034 |
| 1031 const Function& function = parsed_function().function(); | 1035 const Function& function = parsed_function().function(); |
| 1032 | 1036 |
| 1033 const int num_fixed_params = function.num_fixed_parameters(); | 1037 const int num_fixed_params = function.num_fixed_parameters(); |
| 1034 const int num_copied_params = parsed_function().num_copied_params(); | 1038 const int num_copied_params = parsed_function().num_copied_params(); |
| 1035 const int num_locals = parsed_function().num_stack_locals(); | 1039 const int num_locals = parsed_function().num_stack_locals(); |
| 1040 StubCode* stub_code = isolate()->stub_code(); |
| 1036 | 1041 |
| 1037 // We check the number of passed arguments when we have to copy them due to | 1042 // We check the number of passed arguments when we have to copy them due to |
| 1038 // the presence of optional parameters. | 1043 // the presence of optional parameters. |
| 1039 // No such checking code is generated if only fixed parameters are declared, | 1044 // No such checking code is generated if only fixed parameters are declared, |
| 1040 // unless we are in debug mode or unless we are compiling a closure. | 1045 // unless we are in debug mode or unless we are compiling a closure. |
| 1041 if (num_copied_params == 0) { | 1046 if (num_copied_params == 0) { |
| 1042 #ifdef DEBUG | 1047 #ifdef DEBUG |
| 1043 ASSERT(!parsed_function().function().HasOptionalParameters()); | 1048 ASSERT(!parsed_function().function().HasOptionalParameters()); |
| 1044 const bool check_arguments = !flow_graph().IsCompiledForOsr(); | 1049 const bool check_arguments = !flow_graph().IsCompiledForOsr(); |
| 1045 #else | 1050 #else |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1064 const String& name = | 1069 const String& name = |
| 1065 String::Handle(function.IsClosureFunction() | 1070 String::Handle(function.IsClosureFunction() |
| 1066 ? Symbols::Call().raw() | 1071 ? Symbols::Call().raw() |
| 1067 : function.name()); | 1072 : function.name()); |
| 1068 const int kNumArgsChecked = 1; | 1073 const int kNumArgsChecked = 1; |
| 1069 const ICData& ic_data = ICData::ZoneHandle( | 1074 const ICData& ic_data = ICData::ZoneHandle( |
| 1070 ICData::New(function, name, Object::empty_array(), | 1075 ICData::New(function, name, Object::empty_array(), |
| 1071 Isolate::kNoDeoptId, kNumArgsChecked)); | 1076 Isolate::kNoDeoptId, kNumArgsChecked)); |
| 1072 __ LoadObject(R5, ic_data, PP); | 1077 __ LoadObject(R5, ic_data, PP); |
| 1073 __ LeaveDartFrame(); // The arguments are still on the stack. | 1078 __ LeaveDartFrame(); // The arguments are still on the stack. |
| 1074 __ BranchPatchable(&StubCode::CallNoSuchMethodFunctionLabel()); | 1079 __ BranchPatchable(&stub_code->CallNoSuchMethodFunctionLabel()); |
| 1075 // The noSuchMethod call may return to the caller, but not here. | 1080 // The noSuchMethod call may return to the caller, but not here. |
| 1076 __ brk(0); | 1081 __ brk(0); |
| 1077 } else { | 1082 } else { |
| 1078 __ Stop("Wrong number of arguments"); | 1083 __ Stop("Wrong number of arguments"); |
| 1079 } | 1084 } |
| 1080 __ Bind(&correct_num_arguments); | 1085 __ Bind(&correct_num_arguments); |
| 1081 } | 1086 } |
| 1082 } else if (!flow_graph().IsCompiledForOsr()) { | 1087 } else if (!flow_graph().IsCompiledForOsr()) { |
| 1083 CopyParameters(); | 1088 CopyParameters(); |
| 1084 } | 1089 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1096 } | 1101 } |
| 1097 | 1102 |
| 1098 VisitBlocks(); | 1103 VisitBlocks(); |
| 1099 | 1104 |
| 1100 __ brk(0); | 1105 __ brk(0); |
| 1101 GenerateDeferredCode(); | 1106 GenerateDeferredCode(); |
| 1102 | 1107 |
| 1103 // Emit function patching code. This will be swapped with the first 3 | 1108 // Emit function patching code. This will be swapped with the first 3 |
| 1104 // instructions at entry point. | 1109 // instructions at entry point. |
| 1105 patch_code_pc_offset_ = assembler()->CodeSize(); | 1110 patch_code_pc_offset_ = assembler()->CodeSize(); |
| 1106 __ BranchPatchable(&StubCode::FixCallersTargetLabel()); | 1111 __ BranchPatchable(&stub_code->FixCallersTargetLabel()); |
| 1107 | 1112 |
| 1108 if (is_optimizing()) { | 1113 if (is_optimizing()) { |
| 1109 lazy_deopt_pc_offset_ = assembler()->CodeSize(); | 1114 lazy_deopt_pc_offset_ = assembler()->CodeSize(); |
| 1110 __ BranchPatchable(&StubCode::DeoptimizeLazyLabel()); | 1115 __ BranchPatchable(&stub_code->DeoptimizeLazyLabel()); |
| 1111 } | 1116 } |
| 1112 } | 1117 } |
| 1113 | 1118 |
| 1114 | 1119 |
| 1115 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1120 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
| 1116 const ExternalLabel* label, | 1121 const ExternalLabel* label, |
| 1117 PcDescriptors::Kind kind, | 1122 PcDescriptors::Kind kind, |
| 1118 LocationSummary* locs) { | 1123 LocationSummary* locs) { |
| 1119 __ BranchLinkPatchable(label); | 1124 __ BranchLinkPatchable(label); |
| 1120 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); | 1125 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1290 } | 1295 } |
| 1291 | 1296 |
| 1292 | 1297 |
| 1293 void FlowGraphCompiler::EmitUnoptimizedStaticCall( | 1298 void FlowGraphCompiler::EmitUnoptimizedStaticCall( |
| 1294 intptr_t argument_count, | 1299 intptr_t argument_count, |
| 1295 intptr_t deopt_id, | 1300 intptr_t deopt_id, |
| 1296 intptr_t token_pos, | 1301 intptr_t token_pos, |
| 1297 LocationSummary* locs, | 1302 LocationSummary* locs, |
| 1298 const ICData& ic_data) { | 1303 const ICData& ic_data) { |
| 1299 uword label_address = 0; | 1304 uword label_address = 0; |
| 1305 StubCode* stub_code = isolate()->stub_code(); |
| 1300 if (ic_data.NumArgsTested() == 0) { | 1306 if (ic_data.NumArgsTested() == 0) { |
| 1301 label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint(); | 1307 label_address = stub_code->ZeroArgsUnoptimizedStaticCallEntryPoint(); |
| 1302 } else if (ic_data.NumArgsTested() == 2) { | 1308 } else if (ic_data.NumArgsTested() == 2) { |
| 1303 label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint(); | 1309 label_address = stub_code->TwoArgsUnoptimizedStaticCallEntryPoint(); |
| 1304 } else { | 1310 } else { |
| 1305 UNIMPLEMENTED(); | 1311 UNIMPLEMENTED(); |
| 1306 } | 1312 } |
| 1307 ExternalLabel target_label(label_address); | 1313 ExternalLabel target_label(label_address); |
| 1308 __ LoadImmediate(R4, 0, kNoPP); | 1314 __ LoadImmediate(R4, 0, kNoPP); |
| 1309 __ LoadObject(R5, ic_data, PP); | 1315 __ LoadObject(R5, ic_data, PP); |
| 1310 GenerateDartCall(deopt_id, | 1316 GenerateDartCall(deopt_id, |
| 1311 token_pos, | 1317 token_pos, |
| 1312 &target_label, | 1318 &target_label, |
| 1313 PcDescriptors::kUnoptStaticCall, | 1319 PcDescriptors::kUnoptStaticCall, |
| 1314 locs); | 1320 locs); |
| 1315 #if defined(DEBUG) | 1321 #if defined(DEBUG) |
| 1316 __ LoadImmediate(R5, kInvalidObjectPointer, kNoPP); | 1322 __ LoadImmediate(R5, kInvalidObjectPointer, kNoPP); |
| 1317 #endif | 1323 #endif |
| 1318 __ Drop(argument_count); | 1324 __ Drop(argument_count); |
| 1319 } | 1325 } |
| 1320 | 1326 |
| 1321 | 1327 |
| 1322 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1328 void FlowGraphCompiler::EmitOptimizedStaticCall( |
| 1323 const Function& function, | 1329 const Function& function, |
| 1324 const Array& arguments_descriptor, | 1330 const Array& arguments_descriptor, |
| 1325 intptr_t argument_count, | 1331 intptr_t argument_count, |
| 1326 intptr_t deopt_id, | 1332 intptr_t deopt_id, |
| 1327 intptr_t token_pos, | 1333 intptr_t token_pos, |
| 1328 LocationSummary* locs) { | 1334 LocationSummary* locs) { |
| 1335 StubCode* stub_code = isolate()->stub_code(); |
| 1329 __ LoadObject(R4, arguments_descriptor, PP); | 1336 __ LoadObject(R4, arguments_descriptor, PP); |
| 1330 // Do not use the code from the function, but let the code be patched so that | 1337 // Do not use the code from the function, but let the code be patched so that |
| 1331 // we can record the outgoing edges to other code. | 1338 // we can record the outgoing edges to other code. |
| 1332 GenerateDartCall(deopt_id, | 1339 GenerateDartCall(deopt_id, |
| 1333 token_pos, | 1340 token_pos, |
| 1334 &StubCode::CallStaticFunctionLabel(), | 1341 &stub_code->CallStaticFunctionLabel(), |
| 1335 PcDescriptors::kOptStaticCall, | 1342 PcDescriptors::kOptStaticCall, |
| 1336 locs); | 1343 locs); |
| 1337 AddStaticCallTarget(function); | 1344 AddStaticCallTarget(function); |
| 1338 __ Drop(argument_count); | 1345 __ Drop(argument_count); |
| 1339 } | 1346 } |
| 1340 | 1347 |
| 1341 | 1348 |
| 1342 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, | 1349 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, |
| 1343 const Object& obj, | 1350 const Object& obj, |
| 1344 bool needs_number_check, | 1351 bool needs_number_check, |
| 1345 intptr_t token_pos) { | 1352 intptr_t token_pos) { |
| 1346 if (needs_number_check) { | 1353 if (needs_number_check) { |
| 1354 StubCode* stub_code = isolate()->stub_code(); |
| 1347 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); | 1355 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); |
| 1348 __ Push(reg); | 1356 __ Push(reg); |
| 1349 __ PushObject(obj, PP); | 1357 __ PushObject(obj, PP); |
| 1350 if (is_optimizing()) { | 1358 if (is_optimizing()) { |
| 1351 __ BranchLinkPatchable( | 1359 __ BranchLinkPatchable( |
| 1352 &StubCode::OptimizedIdenticalWithNumberCheckLabel()); | 1360 &stub_code->OptimizedIdenticalWithNumberCheckLabel()); |
| 1353 } else { | 1361 } else { |
| 1354 __ BranchLinkPatchable( | 1362 __ BranchLinkPatchable( |
| 1355 &StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); | 1363 &stub_code->UnoptimizedIdenticalWithNumberCheckLabel()); |
| 1356 } | 1364 } |
| 1357 if (token_pos != Scanner::kNoSourcePos) { | 1365 if (token_pos != Scanner::kNoSourcePos) { |
| 1358 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1366 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1359 Isolate::kNoDeoptId, | 1367 Isolate::kNoDeoptId, |
| 1360 token_pos); | 1368 token_pos); |
| 1361 } | 1369 } |
| 1362 __ Drop(1); // Discard constant. | 1370 __ Drop(1); // Discard constant. |
| 1363 __ Pop(reg); // Restore 'reg'. | 1371 __ Pop(reg); // Restore 'reg'. |
| 1364 return; | 1372 return; |
| 1365 } | 1373 } |
| 1366 | 1374 |
| 1367 __ CompareObject(reg, obj, PP); | 1375 __ CompareObject(reg, obj, PP); |
| 1368 } | 1376 } |
| 1369 | 1377 |
| 1370 | 1378 |
| 1371 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1379 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
| 1372 Register right, | 1380 Register right, |
| 1373 bool needs_number_check, | 1381 bool needs_number_check, |
| 1374 intptr_t token_pos) { | 1382 intptr_t token_pos) { |
| 1375 if (needs_number_check) { | 1383 if (needs_number_check) { |
| 1384 StubCode* stub_code = isolate()->stub_code(); |
| 1376 __ Push(left); | 1385 __ Push(left); |
| 1377 __ Push(right); | 1386 __ Push(right); |
| 1378 if (is_optimizing()) { | 1387 if (is_optimizing()) { |
| 1379 __ BranchLinkPatchable( | 1388 __ BranchLinkPatchable( |
| 1380 &StubCode::OptimizedIdenticalWithNumberCheckLabel()); | 1389 &stub_code->OptimizedIdenticalWithNumberCheckLabel()); |
| 1381 } else { | 1390 } else { |
| 1382 __ LoadImmediate(R4, 0, kNoPP); | 1391 __ LoadImmediate(R4, 0, kNoPP); |
| 1383 __ LoadImmediate(R5, 0, kNoPP); | 1392 __ LoadImmediate(R5, 0, kNoPP); |
| 1384 __ BranchLinkPatchable( | 1393 __ BranchLinkPatchable( |
| 1385 &StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); | 1394 &stub_code->UnoptimizedIdenticalWithNumberCheckLabel()); |
| 1386 } | 1395 } |
| 1387 if (token_pos != Scanner::kNoSourcePos) { | 1396 if (token_pos != Scanner::kNoSourcePos) { |
| 1388 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1397 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1389 Isolate::kNoDeoptId, | 1398 Isolate::kNoDeoptId, |
| 1390 token_pos); | 1399 token_pos); |
| 1391 } | 1400 } |
| 1392 #if defined(DEBUG) | 1401 #if defined(DEBUG) |
| 1393 if (!is_optimizing()) { | 1402 if (!is_optimizing()) { |
| 1394 // Do this *after* adding the pc descriptor! | 1403 // Do this *after* adding the pc descriptor! |
| 1395 __ LoadImmediate(R4, kInvalidObjectPointer, kNoPP); | 1404 __ LoadImmediate(R4, kInvalidObjectPointer, kNoPP); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1468 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); | 1477 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 1469 Label match_found; | 1478 Label match_found; |
| 1470 const intptr_t len = ic_data.NumberOfChecks(); | 1479 const intptr_t len = ic_data.NumberOfChecks(); |
| 1471 GrowableArray<CidTarget> sorted(len); | 1480 GrowableArray<CidTarget> sorted(len); |
| 1472 SortICDataByCount(ic_data, &sorted); | 1481 SortICDataByCount(ic_data, &sorted); |
| 1473 ASSERT(class_id_reg != R4); | 1482 ASSERT(class_id_reg != R4); |
| 1474 ASSERT(len > 0); // Why bother otherwise. | 1483 ASSERT(len > 0); // Why bother otherwise. |
| 1475 const Array& arguments_descriptor = | 1484 const Array& arguments_descriptor = |
| 1476 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 1485 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
| 1477 argument_names)); | 1486 argument_names)); |
| 1487 StubCode* stub_code = isolate()->stub_code(); |
| 1488 |
| 1478 __ LoadObject(R4, arguments_descriptor, PP); | 1489 __ LoadObject(R4, arguments_descriptor, PP); |
| 1479 for (intptr_t i = 0; i < len; i++) { | 1490 for (intptr_t i = 0; i < len; i++) { |
| 1480 const bool is_last_check = (i == (len - 1)); | 1491 const bool is_last_check = (i == (len - 1)); |
| 1481 Label next_test; | 1492 Label next_test; |
| 1482 __ CompareImmediate(class_id_reg, sorted[i].cid, PP); | 1493 __ CompareImmediate(class_id_reg, sorted[i].cid, PP); |
| 1483 if (is_last_check) { | 1494 if (is_last_check) { |
| 1484 __ b(deopt, NE); | 1495 __ b(deopt, NE); |
| 1485 } else { | 1496 } else { |
| 1486 __ b(&next_test, NE); | 1497 __ b(&next_test, NE); |
| 1487 } | 1498 } |
| 1488 // Do not use the code from the function, but let the code be patched so | 1499 // Do not use the code from the function, but let the code be patched so |
| 1489 // that we can record the outgoing edges to other code. | 1500 // that we can record the outgoing edges to other code. |
| 1490 GenerateDartCall(deopt_id, | 1501 GenerateDartCall(deopt_id, |
| 1491 token_index, | 1502 token_index, |
| 1492 &StubCode::CallStaticFunctionLabel(), | 1503 &stub_code->CallStaticFunctionLabel(), |
| 1493 PcDescriptors::kOptStaticCall, | 1504 PcDescriptors::kOptStaticCall, |
| 1494 locs); | 1505 locs); |
| 1495 const Function& function = *sorted[i].target; | 1506 const Function& function = *sorted[i].target; |
| 1496 AddStaticCallTarget(function); | 1507 AddStaticCallTarget(function); |
| 1497 __ Drop(argument_count); | 1508 __ Drop(argument_count); |
| 1498 if (!is_last_check) { | 1509 if (!is_last_check) { |
| 1499 __ b(&match_found); | 1510 __ b(&match_found); |
| 1500 } | 1511 } |
| 1501 __ Bind(&next_test); | 1512 __ Bind(&next_test); |
| 1502 } | 1513 } |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1726 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1737 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1727 UNIMPLEMENTED(); | 1738 UNIMPLEMENTED(); |
| 1728 } | 1739 } |
| 1729 | 1740 |
| 1730 | 1741 |
| 1731 #undef __ | 1742 #undef __ |
| 1732 | 1743 |
| 1733 } // namespace dart | 1744 } // namespace dart |
| 1734 | 1745 |
| 1735 #endif // defined TARGET_ARCH_ARM64 | 1746 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |