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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
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 10 matching lines...) Expand all Loading... |
21 #include "vm/stub_code.h" | 21 #include "vm/stub_code.h" |
22 #include "vm/symbols.h" | 22 #include "vm/symbols.h" |
23 | 23 |
24 namespace dart { | 24 namespace dart { |
25 | 25 |
26 DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization."); | 26 DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization."); |
27 DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic."); | 27 DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic."); |
28 DEFINE_FLAG(bool, unbox_doubles, true, "Optimize double arithmetic."); | 28 DEFINE_FLAG(bool, unbox_doubles, true, "Optimize double arithmetic."); |
29 DECLARE_FLAG(bool, enable_simd_inline); | 29 DECLARE_FLAG(bool, enable_simd_inline); |
30 | 30 |
31 | |
32 FlowGraphCompiler::~FlowGraphCompiler() { | 31 FlowGraphCompiler::~FlowGraphCompiler() { |
33 // BlockInfos are zone-allocated, so their destructors are not called. | 32 // BlockInfos are zone-allocated, so their destructors are not called. |
34 // Verify the labels explicitly here. | 33 // Verify the labels explicitly here. |
35 for (int i = 0; i < block_info_.length(); ++i) { | 34 for (int i = 0; i < block_info_.length(); ++i) { |
36 ASSERT(!block_info_[i]->jump_label()->IsLinked()); | 35 ASSERT(!block_info_[i]->jump_label()->IsLinked()); |
37 } | 36 } |
38 } | 37 } |
39 | 38 |
40 | |
41 bool FlowGraphCompiler::SupportsUnboxedDoubles() { | 39 bool FlowGraphCompiler::SupportsUnboxedDoubles() { |
42 return TargetCPUFeatures::vfp_supported() && FLAG_unbox_doubles; | 40 return TargetCPUFeatures::vfp_supported() && FLAG_unbox_doubles; |
43 } | 41 } |
44 | 42 |
45 | |
46 bool FlowGraphCompiler::SupportsUnboxedMints() { | 43 bool FlowGraphCompiler::SupportsUnboxedMints() { |
47 return FLAG_unbox_mints; | 44 return FLAG_unbox_mints; |
48 } | 45 } |
49 | 46 |
50 | |
51 bool FlowGraphCompiler::SupportsUnboxedSimd128() { | 47 bool FlowGraphCompiler::SupportsUnboxedSimd128() { |
52 return TargetCPUFeatures::neon_supported() && FLAG_enable_simd_inline; | 48 return TargetCPUFeatures::neon_supported() && FLAG_enable_simd_inline; |
53 } | 49 } |
54 | 50 |
55 | |
56 bool FlowGraphCompiler::SupportsHardwareDivision() { | 51 bool FlowGraphCompiler::SupportsHardwareDivision() { |
57 return TargetCPUFeatures::can_divide(); | 52 return TargetCPUFeatures::can_divide(); |
58 } | 53 } |
59 | 54 |
60 | |
61 bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() { | 55 bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() { |
62 // ARM does not have a short instruction sequence for converting int64 to | 56 // ARM does not have a short instruction sequence for converting int64 to |
63 // double. | 57 // double. |
64 return false; | 58 return false; |
65 } | 59 } |
66 | 60 |
67 | |
68 void FlowGraphCompiler::EnterIntrinsicMode() { | 61 void FlowGraphCompiler::EnterIntrinsicMode() { |
69 ASSERT(!intrinsic_mode()); | 62 ASSERT(!intrinsic_mode()); |
70 intrinsic_mode_ = true; | 63 intrinsic_mode_ = true; |
71 ASSERT(!assembler()->constant_pool_allowed()); | 64 ASSERT(!assembler()->constant_pool_allowed()); |
72 } | 65 } |
73 | 66 |
74 | |
75 void FlowGraphCompiler::ExitIntrinsicMode() { | 67 void FlowGraphCompiler::ExitIntrinsicMode() { |
76 ASSERT(intrinsic_mode()); | 68 ASSERT(intrinsic_mode()); |
77 intrinsic_mode_ = false; | 69 intrinsic_mode_ = false; |
78 } | 70 } |
79 | 71 |
80 | |
81 RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, | 72 RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, |
82 DeoptInfoBuilder* builder, | 73 DeoptInfoBuilder* builder, |
83 const Array& deopt_table) { | 74 const Array& deopt_table) { |
84 if (deopt_env_ == NULL) { | 75 if (deopt_env_ == NULL) { |
85 ++builder->current_info_number_; | 76 ++builder->current_info_number_; |
86 return TypedData::null(); | 77 return TypedData::null(); |
87 } | 78 } |
88 | 79 |
89 intptr_t stack_height = compiler->StackSize(); | 80 intptr_t stack_height = compiler->StackSize(); |
90 AllocateIncomingParametersRecursive(deopt_env_, &stack_height); | 81 AllocateIncomingParametersRecursive(deopt_env_, &stack_height); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 builder->AddCallerPc(slot_ix++); | 148 builder->AddCallerPc(slot_ix++); |
158 | 149 |
159 // For the outermost environment, set the incoming arguments. | 150 // For the outermost environment, set the incoming arguments. |
160 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { | 151 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
161 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); | 152 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); |
162 } | 153 } |
163 | 154 |
164 return builder->CreateDeoptInfo(deopt_table); | 155 return builder->CreateDeoptInfo(deopt_table); |
165 } | 156 } |
166 | 157 |
167 | |
168 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, | 158 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, |
169 intptr_t stub_ix) { | 159 intptr_t stub_ix) { |
170 // Calls do not need stubs, they share a deoptimization trampoline. | 160 // Calls do not need stubs, they share a deoptimization trampoline. |
171 ASSERT(reason() != ICData::kDeoptAtCall); | 161 ASSERT(reason() != ICData::kDeoptAtCall); |
172 Assembler* assembler = compiler->assembler(); | 162 Assembler* assembler = compiler->assembler(); |
173 #define __ assembler-> | 163 #define __ assembler-> |
174 __ Comment("%s", Name()); | 164 __ Comment("%s", Name()); |
175 __ Bind(entry_label()); | 165 __ Bind(entry_label()); |
176 if (FLAG_trap_on_deoptimization) { | 166 if (FLAG_trap_on_deoptimization) { |
177 __ bkpt(0); | 167 __ bkpt(0); |
178 } | 168 } |
179 | 169 |
180 ASSERT(deopt_env() != NULL); | 170 ASSERT(deopt_env() != NULL); |
181 | 171 |
182 // LR may be live. It will be clobbered by BranchLink, so cache it in IP. | 172 // LR may be live. It will be clobbered by BranchLink, so cache it in IP. |
183 // It will be restored at the top of the deoptimization stub, specifically in | 173 // It will be restored at the top of the deoptimization stub, specifically in |
184 // GenerateDeoptimizationSequence in stub_code_arm.cc. | 174 // GenerateDeoptimizationSequence in stub_code_arm.cc. |
185 __ Push(CODE_REG); | 175 __ Push(CODE_REG); |
186 __ mov(IP, Operand(LR)); | 176 __ mov(IP, Operand(LR)); |
187 __ BranchLink(*StubCode::Deoptimize_entry()); | 177 __ BranchLink(*StubCode::Deoptimize_entry()); |
188 set_pc_offset(assembler->CodeSize()); | 178 set_pc_offset(assembler->CodeSize()); |
189 #undef __ | 179 #undef __ |
190 } | 180 } |
191 | 181 |
192 | |
193 #define __ assembler()-> | 182 #define __ assembler()-> |
194 | 183 |
195 | |
196 // Fall through if bool_register contains null. | 184 // Fall through if bool_register contains null. |
197 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 185 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
198 Label* is_true, | 186 Label* is_true, |
199 Label* is_false) { | 187 Label* is_false) { |
200 Label fall_through; | 188 Label fall_through; |
201 __ CompareObject(bool_register, Object::null_object()); | 189 __ CompareObject(bool_register, Object::null_object()); |
202 __ b(&fall_through, EQ); | 190 __ b(&fall_through, EQ); |
203 __ CompareObject(bool_register, Bool::True()); | 191 __ CompareObject(bool_register, Bool::True()); |
204 __ b(is_true, EQ); | 192 __ b(is_true, EQ); |
205 __ b(is_false); | 193 __ b(is_false); |
206 __ Bind(&fall_through); | 194 __ Bind(&fall_through); |
207 } | 195 } |
208 | 196 |
209 | |
210 // R0: instance (must be preserved). | 197 // R0: instance (must be preserved). |
211 // R2: instantiator type arguments (if used). | 198 // R2: instantiator type arguments (if used). |
212 // R1: function type arguments (if used). | 199 // R1: function type arguments (if used). |
213 // R3: type test cache. | 200 // R3: type test cache. |
214 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 201 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
215 TypeTestStubKind test_kind, | 202 TypeTestStubKind test_kind, |
216 Register instance_reg, | 203 Register instance_reg, |
217 Register instantiator_type_arguments_reg, | 204 Register instantiator_type_arguments_reg, |
218 Register function_type_arguments_reg, | 205 Register function_type_arguments_reg, |
219 Register temp_reg, | 206 Register temp_reg, |
(...skipping 17 matching lines...) Expand all Loading... |
237 ASSERT(function_type_arguments_reg == R1); | 224 ASSERT(function_type_arguments_reg == R1); |
238 __ BranchLink(*StubCode::Subtype4TestCache_entry()); | 225 __ BranchLink(*StubCode::Subtype4TestCache_entry()); |
239 } else { | 226 } else { |
240 UNREACHABLE(); | 227 UNREACHABLE(); |
241 } | 228 } |
242 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. | 229 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. |
243 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); | 230 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); |
244 return type_test_cache.raw(); | 231 return type_test_cache.raw(); |
245 } | 232 } |
246 | 233 |
247 | |
248 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 234 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
249 // type test is conclusive, otherwise fallthrough if a type test could not | 235 // type test is conclusive, otherwise fallthrough if a type test could not |
250 // be completed. | 236 // be completed. |
251 // R0: instance being type checked (preserved). | 237 // R0: instance being type checked (preserved). |
252 // Clobbers R1, R2. | 238 // Clobbers R1, R2. |
253 RawSubtypeTestCache* | 239 RawSubtypeTestCache* |
254 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 240 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
255 TokenPosition token_pos, | 241 TokenPosition token_pos, |
256 const AbstractType& type, | 242 const AbstractType& type, |
257 Label* is_instance_lbl, | 243 Label* is_instance_lbl, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 const Register kInstantiatorTypeArgumentsReg = kNoRegister; | 302 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
317 const Register kFunctionTypeArgumentsReg = kNoRegister; | 303 const Register kFunctionTypeArgumentsReg = kNoRegister; |
318 const Register kTempReg = kNoRegister; | 304 const Register kTempReg = kNoRegister; |
319 // R0: instance (must be preserved). | 305 // R0: instance (must be preserved). |
320 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, | 306 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
321 kInstantiatorTypeArgumentsReg, | 307 kInstantiatorTypeArgumentsReg, |
322 kFunctionTypeArgumentsReg, kTempReg, | 308 kFunctionTypeArgumentsReg, kTempReg, |
323 is_instance_lbl, is_not_instance_lbl); | 309 is_instance_lbl, is_not_instance_lbl); |
324 } | 310 } |
325 | 311 |
326 | |
327 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 312 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
328 const GrowableArray<intptr_t>& class_ids, | 313 const GrowableArray<intptr_t>& class_ids, |
329 Label* is_equal_lbl, | 314 Label* is_equal_lbl, |
330 Label* is_not_equal_lbl) { | 315 Label* is_not_equal_lbl) { |
331 for (intptr_t i = 0; i < class_ids.length(); i++) { | 316 for (intptr_t i = 0; i < class_ids.length(); i++) { |
332 __ CompareImmediate(class_id_reg, class_ids[i]); | 317 __ CompareImmediate(class_id_reg, class_ids[i]); |
333 __ b(is_equal_lbl, EQ); | 318 __ b(is_equal_lbl, EQ); |
334 } | 319 } |
335 __ b(is_not_equal_lbl); | 320 __ b(is_not_equal_lbl); |
336 } | 321 } |
337 | 322 |
338 | |
339 // Testing against an instantiated type with no arguments, without | 323 // Testing against an instantiated type with no arguments, without |
340 // SubtypeTestCache. | 324 // SubtypeTestCache. |
341 // R0: instance being type checked (preserved). | 325 // R0: instance being type checked (preserved). |
342 // Clobbers R2, R3. | 326 // Clobbers R2, R3. |
343 // Returns true if there is a fallthrough. | 327 // Returns true if there is a fallthrough. |
344 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 328 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
345 TokenPosition token_pos, | 329 TokenPosition token_pos, |
346 const AbstractType& type, | 330 const AbstractType& type, |
347 Label* is_instance_lbl, | 331 Label* is_instance_lbl, |
348 Label* is_not_instance_lbl) { | 332 Label* is_not_instance_lbl) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 } | 380 } |
397 // Compare if the classes are equal. | 381 // Compare if the classes are equal. |
398 if (!type_class.is_abstract()) { | 382 if (!type_class.is_abstract()) { |
399 __ CompareImmediate(kClassIdReg, type_class.id()); | 383 __ CompareImmediate(kClassIdReg, type_class.id()); |
400 __ b(is_instance_lbl, EQ); | 384 __ b(is_instance_lbl, EQ); |
401 } | 385 } |
402 // Otherwise fallthrough. | 386 // Otherwise fallthrough. |
403 return true; | 387 return true; |
404 } | 388 } |
405 | 389 |
406 | |
407 // Uses SubtypeTestCache to store instance class and result. | 390 // Uses SubtypeTestCache to store instance class and result. |
408 // R0: instance to test. | 391 // R0: instance to test. |
409 // Clobbers R1-R4, R8, R9. | 392 // Clobbers R1-R4, R8, R9. |
410 // Immediate class test already done. | 393 // Immediate class test already done. |
411 // TODO(srdjan): Implement a quicker subtype check, as type test | 394 // TODO(srdjan): Implement a quicker subtype check, as type test |
412 // arrays can grow too high, but they may be useful when optimizing | 395 // arrays can grow too high, but they may be useful when optimizing |
413 // code (type-feedback). | 396 // code (type-feedback). |
414 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 397 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
415 TokenPosition token_pos, | 398 TokenPosition token_pos, |
416 const Class& type_class, | 399 const Class& type_class, |
(...skipping 11 matching lines...) Expand all Loading... |
428 | 411 |
429 const Register kInstantiatorTypeArgumentsReg = kNoRegister; | 412 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
430 const Register kFunctionTypeArgumentsReg = kNoRegister; | 413 const Register kFunctionTypeArgumentsReg = kNoRegister; |
431 const Register kTempReg = kNoRegister; | 414 const Register kTempReg = kNoRegister; |
432 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, | 415 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
433 kInstantiatorTypeArgumentsReg, | 416 kInstantiatorTypeArgumentsReg, |
434 kFunctionTypeArgumentsReg, kTempReg, | 417 kFunctionTypeArgumentsReg, kTempReg, |
435 is_instance_lbl, is_not_instance_lbl); | 418 is_instance_lbl, is_not_instance_lbl); |
436 } | 419 } |
437 | 420 |
438 | |
439 // Generates inlined check if 'type' is a type parameter or type itself | 421 // Generates inlined check if 'type' is a type parameter or type itself |
440 // R0: instance (preserved). | 422 // R0: instance (preserved). |
441 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 423 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
442 TokenPosition token_pos, | 424 TokenPosition token_pos, |
443 const AbstractType& type, | 425 const AbstractType& type, |
444 Label* is_instance_lbl, | 426 Label* is_instance_lbl, |
445 Label* is_not_instance_lbl) { | 427 Label* is_not_instance_lbl) { |
446 __ Comment("UninstantiatedTypeTest"); | 428 __ Comment("UninstantiatedTypeTest"); |
447 ASSERT(!type.IsInstantiated()); | 429 ASSERT(!type.IsInstantiated()); |
448 // Skip check if destination is a dynamic type. | 430 // Skip check if destination is a dynamic type. |
449 if (type.IsTypeParameter()) { | 431 if (type.IsTypeParameter()) { |
450 const TypeParameter& type_param = TypeParameter::Cast(type); | 432 const TypeParameter& type_param = TypeParameter::Cast(type); |
451 const Register kInstantiatorTypeArgumentsReg = R2; | 433 const Register kInstantiatorTypeArgumentsReg = R2; |
452 const Register kFunctionTypeArgumentsReg = R1; | 434 const Register kFunctionTypeArgumentsReg = R1; |
453 __ ldm(IA, SP, (1 << kFunctionTypeArgumentsReg) | | 435 __ ldm(IA, SP, |
454 (1 << kInstantiatorTypeArgumentsReg)); | 436 (1 << kFunctionTypeArgumentsReg) | |
| 437 (1 << kInstantiatorTypeArgumentsReg)); |
455 // R2: instantiator type arguments. | 438 // R2: instantiator type arguments. |
456 // R1: function type arguments. | 439 // R1: function type arguments. |
457 const Register kTypeArgumentsReg = | 440 const Register kTypeArgumentsReg = |
458 type_param.IsClassTypeParameter() ? R2 : R1; | 441 type_param.IsClassTypeParameter() ? R2 : R1; |
459 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 442 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
460 __ CompareObject(kTypeArgumentsReg, Object::null_object()); | 443 __ CompareObject(kTypeArgumentsReg, Object::null_object()); |
461 __ b(is_instance_lbl, EQ); | 444 __ b(is_instance_lbl, EQ); |
462 __ ldr(R3, FieldAddress(kTypeArgumentsReg, | 445 __ ldr(R3, FieldAddress(kTypeArgumentsReg, |
463 TypeArguments::type_at_offset(type_param.index()))); | 446 TypeArguments::type_at_offset(type_param.index()))); |
464 // R3: concrete type of type. | 447 // R3: concrete type of type. |
(...skipping 29 matching lines...) Expand all Loading... |
494 kTempReg, is_instance_lbl, is_not_instance_lbl)); | 477 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
495 __ Bind(&fall_through); | 478 __ Bind(&fall_through); |
496 return type_test_cache.raw(); | 479 return type_test_cache.raw(); |
497 } | 480 } |
498 if (type.IsType()) { | 481 if (type.IsType()) { |
499 const Register kInstanceReg = R0; | 482 const Register kInstanceReg = R0; |
500 const Register kInstantiatorTypeArgumentsReg = R2; | 483 const Register kInstantiatorTypeArgumentsReg = R2; |
501 const Register kFunctionTypeArgumentsReg = R1; | 484 const Register kFunctionTypeArgumentsReg = R1; |
502 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? | 485 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? |
503 __ b(is_not_instance_lbl, EQ); | 486 __ b(is_not_instance_lbl, EQ); |
504 __ ldm(IA, SP, (1 << kFunctionTypeArgumentsReg) | | 487 __ ldm(IA, SP, |
505 (1 << kInstantiatorTypeArgumentsReg)); | 488 (1 << kFunctionTypeArgumentsReg) | |
| 489 (1 << kInstantiatorTypeArgumentsReg)); |
506 // Uninstantiated type class is known at compile time, but the type | 490 // Uninstantiated type class is known at compile time, but the type |
507 // arguments are determined at runtime by the instantiator(s). | 491 // arguments are determined at runtime by the instantiator(s). |
508 const Register kTempReg = kNoRegister; | 492 const Register kTempReg = kNoRegister; |
509 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, | 493 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
510 kInstantiatorTypeArgumentsReg, | 494 kInstantiatorTypeArgumentsReg, |
511 kFunctionTypeArgumentsReg, kTempReg, | 495 kFunctionTypeArgumentsReg, kTempReg, |
512 is_instance_lbl, is_not_instance_lbl); | 496 is_instance_lbl, is_not_instance_lbl); |
513 } | 497 } |
514 return SubtypeTestCache::null(); | 498 return SubtypeTestCache::null(); |
515 } | 499 } |
516 | 500 |
517 | |
518 // Inputs: | 501 // Inputs: |
519 // - R0: instance being type checked (preserved). | 502 // - R0: instance being type checked (preserved). |
520 // - R2: optional instantiator type arguments (preserved). | 503 // - R2: optional instantiator type arguments (preserved). |
521 // - R1: optional function type arguments (preserved). | 504 // - R1: optional function type arguments (preserved). |
522 // Clobbers R3, R4, R8, R9. | 505 // Clobbers R3, R4, R8, R9. |
523 // Returns: | 506 // Returns: |
524 // - preserved instance in R0, optional instantiator type arguments in R2, and | 507 // - preserved instance in R0, optional instantiator type arguments in R2, and |
525 // optional function type arguments in R1. | 508 // optional function type arguments in R1. |
526 // Note that this inlined code must be followed by the runtime_call code, as it | 509 // Note that this inlined code must be followed by the runtime_call code, as it |
527 // may fall through to it. Otherwise, this inline code will jump to the label | 510 // may fall through to it. Otherwise, this inline code will jump to the label |
(...skipping 22 matching lines...) Expand all Loading... |
550 return GenerateSubtype1TestCacheLookup( | 533 return GenerateSubtype1TestCacheLookup( |
551 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 534 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
552 } else { | 535 } else { |
553 return SubtypeTestCache::null(); | 536 return SubtypeTestCache::null(); |
554 } | 537 } |
555 } | 538 } |
556 return GenerateUninstantiatedTypeTest(token_pos, type, is_instance_lbl, | 539 return GenerateUninstantiatedTypeTest(token_pos, type, is_instance_lbl, |
557 is_not_instance_lbl); | 540 is_not_instance_lbl); |
558 } | 541 } |
559 | 542 |
560 | |
561 // If instanceof type test cannot be performed successfully at compile time and | 543 // If instanceof type test cannot be performed successfully at compile time and |
562 // therefore eliminated, optimize it by adding inlined tests for: | 544 // therefore eliminated, optimize it by adding inlined tests for: |
563 // - NULL -> return type == Null (type is not Object or dynamic). | 545 // - NULL -> return type == Null (type is not Object or dynamic). |
564 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 546 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
565 // - Class equality (only if class is not parameterized). | 547 // - Class equality (only if class is not parameterized). |
566 // Inputs: | 548 // Inputs: |
567 // - R0: object. | 549 // - R0: object. |
568 // - R2: instantiator type arguments or raw_null. | 550 // - R2: instantiator type arguments or raw_null. |
569 // - R1: function type arguments or raw_null. | 551 // - R1: function type arguments or raw_null. |
570 // Returns: | 552 // Returns: |
(...skipping 25 matching lines...) Expand all Loading... |
596 | 578 |
597 // Generate inline instanceof test. | 579 // Generate inline instanceof test. |
598 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 580 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
599 test_cache = | 581 test_cache = |
600 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); | 582 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
601 | 583 |
602 // test_cache is null if there is no fall-through. | 584 // test_cache is null if there is no fall-through. |
603 Label done; | 585 Label done; |
604 if (!test_cache.IsNull()) { | 586 if (!test_cache.IsNull()) { |
605 // Generate runtime call. | 587 // Generate runtime call. |
606 __ ldm(IA, SP, (1 << kFunctionTypeArgumentsReg) | | 588 __ ldm(IA, SP, |
607 (1 << kInstantiatorTypeArgumentsReg)); | 589 (1 << kFunctionTypeArgumentsReg) | |
| 590 (1 << kInstantiatorTypeArgumentsReg)); |
608 __ PushObject(Object::null_object()); // Make room for the result. | 591 __ PushObject(Object::null_object()); // Make room for the result. |
609 __ Push(R0); // Push the instance. | 592 __ Push(R0); // Push the instance. |
610 __ PushObject(type); // Push the type. | 593 __ PushObject(type); // Push the type. |
611 __ PushList((1 << kInstantiatorTypeArgumentsReg) | | 594 __ PushList((1 << kInstantiatorTypeArgumentsReg) | |
612 (1 << kFunctionTypeArgumentsReg)); | 595 (1 << kFunctionTypeArgumentsReg)); |
613 __ LoadUniqueObject(R0, test_cache); | 596 __ LoadUniqueObject(R0, test_cache); |
614 __ Push(R0); | 597 __ Push(R0); |
615 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); | 598 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
616 // Pop the parameters supplied to the runtime entry. The result of the | 599 // Pop the parameters supplied to the runtime entry. The result of the |
617 // instanceof runtime call will be left as the result of the operation. | 600 // instanceof runtime call will be left as the result of the operation. |
618 __ Drop(5); | 601 __ Drop(5); |
619 __ Pop(R0); | 602 __ Pop(R0); |
620 __ b(&done); | 603 __ b(&done); |
621 } | 604 } |
622 __ Bind(&is_not_instance); | 605 __ Bind(&is_not_instance); |
623 __ LoadObject(R0, Bool::Get(false)); | 606 __ LoadObject(R0, Bool::Get(false)); |
624 __ b(&done); | 607 __ b(&done); |
625 | 608 |
626 __ Bind(&is_instance); | 609 __ Bind(&is_instance); |
627 __ LoadObject(R0, Bool::Get(true)); | 610 __ LoadObject(R0, Bool::Get(true)); |
628 __ Bind(&done); | 611 __ Bind(&done); |
629 // Remove instantiator type arguments and function type arguments. | 612 // Remove instantiator type arguments and function type arguments. |
630 __ Drop(2); | 613 __ Drop(2); |
631 } | 614 } |
632 | 615 |
633 | |
634 // Optimize assignable type check by adding inlined tests for: | 616 // Optimize assignable type check by adding inlined tests for: |
635 // - NULL -> return NULL. | 617 // - NULL -> return NULL. |
636 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 618 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
637 // - Class equality (only if class is not parameterized). | 619 // - Class equality (only if class is not parameterized). |
638 // Inputs: | 620 // Inputs: |
639 // - R0: instance being type checked. | 621 // - R0: instance being type checked. |
640 // - R2: instantiator type arguments or raw_null. | 622 // - R2: instantiator type arguments or raw_null. |
641 // - R1: function type arguments or raw_null. | 623 // - R1: function type arguments or raw_null. |
642 // Returns: | 624 // Returns: |
643 // - object in R0 for successful assignable check (or throws TypeError). | 625 // - object in R0 for successful assignable check (or throws TypeError). |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 (1 << kInstantiatorTypeArgumentsReg)); | 662 (1 << kInstantiatorTypeArgumentsReg)); |
681 return; | 663 return; |
682 } | 664 } |
683 | 665 |
684 // Generate inline type check, linking to runtime call if not assignable. | 666 // Generate inline type check, linking to runtime call if not assignable. |
685 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 667 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
686 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, | 668 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
687 &runtime_call); | 669 &runtime_call); |
688 | 670 |
689 __ Bind(&runtime_call); | 671 __ Bind(&runtime_call); |
690 __ ldm(IA, SP, (1 << kFunctionTypeArgumentsReg) | | 672 __ ldm( |
691 (1 << kInstantiatorTypeArgumentsReg)); | 673 IA, SP, |
| 674 (1 << kFunctionTypeArgumentsReg) | (1 << kInstantiatorTypeArgumentsReg)); |
692 __ PushObject(Object::null_object()); // Make room for the result. | 675 __ PushObject(Object::null_object()); // Make room for the result. |
693 __ Push(R0); // Push the source object. | 676 __ Push(R0); // Push the source object. |
694 __ PushObject(dst_type); // Push the type of the destination. | 677 __ PushObject(dst_type); // Push the type of the destination. |
695 __ PushList((1 << kInstantiatorTypeArgumentsReg) | | 678 __ PushList((1 << kInstantiatorTypeArgumentsReg) | |
696 (1 << kFunctionTypeArgumentsReg)); | 679 (1 << kFunctionTypeArgumentsReg)); |
697 __ PushObject(dst_name); // Push the name of the destination. | 680 __ PushObject(dst_name); // Push the name of the destination. |
698 __ LoadUniqueObject(R0, test_cache); | 681 __ LoadUniqueObject(R0, test_cache); |
699 __ Push(R0); | 682 __ Push(R0); |
700 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); | 683 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
701 // Pop the parameters supplied to the runtime entry. The result of the | 684 // Pop the parameters supplied to the runtime entry. The result of the |
702 // type check runtime call is the checked value. | 685 // type check runtime call is the checked value. |
703 __ Drop(6); | 686 __ Drop(6); |
704 __ Pop(R0); | 687 __ Pop(R0); |
705 | 688 |
706 __ Bind(&is_assignable); | 689 __ Bind(&is_assignable); |
707 __ PopList((1 << kFunctionTypeArgumentsReg) | | 690 __ PopList((1 << kFunctionTypeArgumentsReg) | |
708 (1 << kInstantiatorTypeArgumentsReg)); | 691 (1 << kInstantiatorTypeArgumentsReg)); |
709 } | 692 } |
710 | 693 |
711 | |
712 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 694 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
713 if (is_optimizing()) { | 695 if (is_optimizing()) { |
714 return; | 696 return; |
715 } | 697 } |
716 Definition* defn = instr->AsDefinition(); | 698 Definition* defn = instr->AsDefinition(); |
717 if ((defn != NULL) && defn->HasTemp()) { | 699 if ((defn != NULL) && defn->HasTemp()) { |
718 __ Push(defn->locs()->out(0).reg()); | 700 __ Push(defn->locs()->out(0).reg()); |
719 } | 701 } |
720 } | 702 } |
721 | 703 |
722 | |
723 // Input parameters: | 704 // Input parameters: |
724 // R4: arguments descriptor array. | 705 // R4: arguments descriptor array. |
725 void FlowGraphCompiler::CopyParameters() { | 706 void FlowGraphCompiler::CopyParameters() { |
726 __ Comment("Copy parameters"); | 707 __ Comment("Copy parameters"); |
727 const Function& function = parsed_function().function(); | 708 const Function& function = parsed_function().function(); |
728 LocalScope* scope = parsed_function().node_sequence()->scope(); | 709 LocalScope* scope = parsed_function().node_sequence()->scope(); |
729 const int num_fixed_params = function.num_fixed_parameters(); | 710 const int num_fixed_params = function.num_fixed_parameters(); |
730 const int num_opt_pos_params = function.NumOptionalPositionalParameters(); | 711 const int num_opt_pos_params = function.NumOptionalPositionalParameters(); |
731 const int num_opt_named_params = function.NumOptionalNamedParameters(); | 712 const int num_opt_named_params = function.NumOptionalNamedParameters(); |
732 const int num_params = | 713 const int num_params = |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 opt_param[i + 1] = parameter; | 786 opt_param[i + 1] = parameter; |
806 opt_param_position[i + 1] = pos; | 787 opt_param_position[i + 1] = pos; |
807 } | 788 } |
808 // Generate code handling each optional parameter in alphabetical order. | 789 // Generate code handling each optional parameter in alphabetical order. |
809 __ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 790 __ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
810 // Let NOTFP point to the first passed argument, i.e. to | 791 // Let NOTFP point to the first passed argument, i.e. to |
811 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (NOTFP) is Smi. | 792 // fp[kParamEndSlotFromFp + num_args - 0]; num_args (NOTFP) is Smi. |
812 __ add(NOTFP, FP, Operand(NOTFP, LSL, 1)); | 793 __ add(NOTFP, FP, Operand(NOTFP, LSL, 1)); |
813 __ AddImmediate(NOTFP, NOTFP, kParamEndSlotFromFp * kWordSize); | 794 __ AddImmediate(NOTFP, NOTFP, kParamEndSlotFromFp * kWordSize); |
814 // Let R8 point to the entry of the first named argument. | 795 // Let R8 point to the entry of the first named argument. |
815 __ add(R8, R4, Operand(ArgumentsDescriptor::first_named_entry_offset() - | 796 __ add(R8, R4, |
816 kHeapObjectTag)); | 797 Operand(ArgumentsDescriptor::first_named_entry_offset() - |
| 798 kHeapObjectTag)); |
817 for (int i = 0; i < num_opt_named_params; i++) { | 799 for (int i = 0; i < num_opt_named_params; i++) { |
818 Label load_default_value, assign_optional_parameter; | 800 Label load_default_value, assign_optional_parameter; |
819 const int param_pos = opt_param_position[i]; | 801 const int param_pos = opt_param_position[i]; |
820 // Check if this named parameter was passed in. | 802 // Check if this named parameter was passed in. |
821 // Load R9 with the name of the argument. | 803 // Load R9 with the name of the argument. |
822 __ ldr(R9, Address(R8, ArgumentsDescriptor::name_offset())); | 804 __ ldr(R9, Address(R8, ArgumentsDescriptor::name_offset())); |
823 ASSERT(opt_param[i]->name().IsSymbol()); | 805 ASSERT(opt_param[i]->name().IsSymbol()); |
824 __ CompareObject(R9, opt_param[i]->name()); | 806 __ CompareObject(R9, opt_param[i]->name()); |
825 __ b(&load_default_value, NE); | 807 __ b(&load_default_value, NE); |
826 // Load R9 with passed-in argument at provided arg_pos, i.e. at | 808 // Load R9 with passed-in argument at provided arg_pos, i.e. at |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
914 __ LoadObject(IP, Object::null_object()); | 896 __ LoadObject(IP, Object::null_object()); |
915 Label null_args_loop, null_args_loop_condition; | 897 Label null_args_loop, null_args_loop_condition; |
916 __ b(&null_args_loop_condition); | 898 __ b(&null_args_loop_condition); |
917 __ Bind(&null_args_loop); | 899 __ Bind(&null_args_loop); |
918 __ str(IP, original_argument_addr); | 900 __ str(IP, original_argument_addr); |
919 __ Bind(&null_args_loop_condition); | 901 __ Bind(&null_args_loop_condition); |
920 __ subs(R6, R6, Operand(1)); | 902 __ subs(R6, R6, Operand(1)); |
921 __ b(&null_args_loop, PL); | 903 __ b(&null_args_loop, PL); |
922 } | 904 } |
923 | 905 |
924 | |
925 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 906 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
926 // LR: return address. | 907 // LR: return address. |
927 // SP: receiver. | 908 // SP: receiver. |
928 // Sequence node has one return node, its input is load field node. | 909 // Sequence node has one return node, its input is load field node. |
929 __ Comment("Inlined Getter"); | 910 __ Comment("Inlined Getter"); |
930 __ ldr(R0, Address(SP, 0 * kWordSize)); | 911 __ ldr(R0, Address(SP, 0 * kWordSize)); |
931 __ LoadFieldFromOffset(kWord, R0, R0, offset); | 912 __ LoadFieldFromOffset(kWord, R0, R0, offset); |
932 __ Ret(); | 913 __ Ret(); |
933 } | 914 } |
934 | 915 |
935 | |
936 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 916 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
937 // LR: return address. | 917 // LR: return address. |
938 // SP+1: receiver. | 918 // SP+1: receiver. |
939 // SP+0: value. | 919 // SP+0: value. |
940 // Sequence node has one store node and one return NULL node. | 920 // Sequence node has one store node and one return NULL node. |
941 __ Comment("Inlined Setter"); | 921 __ Comment("Inlined Setter"); |
942 __ ldr(R0, Address(SP, 1 * kWordSize)); // Receiver. | 922 __ ldr(R0, Address(SP, 1 * kWordSize)); // Receiver. |
943 __ ldr(R1, Address(SP, 0 * kWordSize)); // Value. | 923 __ ldr(R1, Address(SP, 0 * kWordSize)); // Value. |
944 __ StoreIntoObjectOffset(R0, offset, R1); | 924 __ StoreIntoObjectOffset(R0, offset, R1); |
945 __ LoadObject(R0, Object::null_object()); | 925 __ LoadObject(R0, Object::null_object()); |
946 __ Ret(); | 926 __ Ret(); |
947 } | 927 } |
948 | 928 |
949 | |
950 static const Register new_pp = NOTFP; | 929 static const Register new_pp = NOTFP; |
951 | 930 |
952 | |
953 void FlowGraphCompiler::EmitFrameEntry() { | 931 void FlowGraphCompiler::EmitFrameEntry() { |
954 const Function& function = parsed_function().function(); | 932 const Function& function = parsed_function().function(); |
955 if (CanOptimizeFunction() && function.IsOptimizable() && | 933 if (CanOptimizeFunction() && function.IsOptimizable() && |
956 (!is_optimizing() || may_reoptimize())) { | 934 (!is_optimizing() || may_reoptimize())) { |
957 __ Comment("Invocation Count Check"); | 935 __ Comment("Invocation Count Check"); |
958 const Register function_reg = R8; | 936 const Register function_reg = R8; |
959 // The pool pointer is not setup before entering the Dart frame. | 937 // The pool pointer is not setup before entering the Dart frame. |
960 // Temporarily setup pool pointer for this dart function. | 938 // Temporarily setup pool pointer for this dart function. |
961 __ LoadPoolPointer(new_pp); | 939 __ LoadPoolPointer(new_pp); |
962 // Load function object from object pool. | 940 // Load function object from object pool. |
(...skipping 15 matching lines...) Expand all Loading... |
978 intptr_t extra_slots = StackSize() - flow_graph().num_stack_locals() - | 956 intptr_t extra_slots = StackSize() - flow_graph().num_stack_locals() - |
979 flow_graph().num_copied_params(); | 957 flow_graph().num_copied_params(); |
980 ASSERT(extra_slots >= 0); | 958 ASSERT(extra_slots >= 0); |
981 __ EnterOsrFrame(extra_slots * kWordSize); | 959 __ EnterOsrFrame(extra_slots * kWordSize); |
982 } else { | 960 } else { |
983 ASSERT(StackSize() >= 0); | 961 ASSERT(StackSize() >= 0); |
984 __ EnterDartFrame(StackSize() * kWordSize); | 962 __ EnterDartFrame(StackSize() * kWordSize); |
985 } | 963 } |
986 } | 964 } |
987 | 965 |
988 | |
989 // Input parameters: | 966 // Input parameters: |
990 // LR: return address. | 967 // LR: return address. |
991 // SP: address of last argument. | 968 // SP: address of last argument. |
992 // FP: caller's frame pointer. | 969 // FP: caller's frame pointer. |
993 // PP: caller's pool pointer. | 970 // PP: caller's pool pointer. |
994 // R9: ic-data. | 971 // R9: ic-data. |
995 // R4: arguments descriptor array. | 972 // R4: arguments descriptor array. |
996 void FlowGraphCompiler::CompileGraph() { | 973 void FlowGraphCompiler::CompileGraph() { |
997 InitCompiler(); | 974 InitCompiler(); |
998 const Function& function = parsed_function().function(); | 975 const Function& function = parsed_function().function(); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1113 // checked during resolution. | 1090 // checked during resolution. |
1114 | 1091 |
1115 EndCodeSourceRange(TokenPosition::kDartCodePrologue); | 1092 EndCodeSourceRange(TokenPosition::kDartCodePrologue); |
1116 VisitBlocks(); | 1093 VisitBlocks(); |
1117 | 1094 |
1118 __ bkpt(0); | 1095 __ bkpt(0); |
1119 ASSERT(assembler()->constant_pool_allowed()); | 1096 ASSERT(assembler()->constant_pool_allowed()); |
1120 GenerateDeferredCode(); | 1097 GenerateDeferredCode(); |
1121 } | 1098 } |
1122 | 1099 |
1123 | |
1124 void FlowGraphCompiler::GenerateCall(TokenPosition token_pos, | 1100 void FlowGraphCompiler::GenerateCall(TokenPosition token_pos, |
1125 const StubEntry& stub_entry, | 1101 const StubEntry& stub_entry, |
1126 RawPcDescriptors::Kind kind, | 1102 RawPcDescriptors::Kind kind, |
1127 LocationSummary* locs) { | 1103 LocationSummary* locs) { |
1128 __ BranchLink(stub_entry); | 1104 __ BranchLink(stub_entry); |
1129 EmitCallsiteMetaData(token_pos, Thread::kNoDeoptId, kind, locs); | 1105 EmitCallsiteMetaData(token_pos, Thread::kNoDeoptId, kind, locs); |
1130 } | 1106 } |
1131 | 1107 |
1132 | |
1133 void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos, | 1108 void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos, |
1134 const StubEntry& stub_entry, | 1109 const StubEntry& stub_entry, |
1135 RawPcDescriptors::Kind kind, | 1110 RawPcDescriptors::Kind kind, |
1136 LocationSummary* locs) { | 1111 LocationSummary* locs) { |
1137 __ BranchLinkPatchable(stub_entry); | 1112 __ BranchLinkPatchable(stub_entry); |
1138 EmitCallsiteMetaData(token_pos, Thread::kNoDeoptId, kind, locs); | 1113 EmitCallsiteMetaData(token_pos, Thread::kNoDeoptId, kind, locs); |
1139 } | 1114 } |
1140 | 1115 |
1141 | |
1142 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, | 1116 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, |
1143 TokenPosition token_pos, | 1117 TokenPosition token_pos, |
1144 const StubEntry& stub_entry, | 1118 const StubEntry& stub_entry, |
1145 RawPcDescriptors::Kind kind, | 1119 RawPcDescriptors::Kind kind, |
1146 LocationSummary* locs) { | 1120 LocationSummary* locs) { |
1147 __ BranchLinkPatchable(stub_entry); | 1121 __ BranchLinkPatchable(stub_entry); |
1148 EmitCallsiteMetaData(token_pos, deopt_id, kind, locs); | 1122 EmitCallsiteMetaData(token_pos, deopt_id, kind, locs); |
1149 // Marks either the continuation point in unoptimized code or the | 1123 // Marks either the continuation point in unoptimized code or the |
1150 // deoptimization point in optimized code, after call. | 1124 // deoptimization point in optimized code, after call. |
1151 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1125 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1152 if (is_optimizing()) { | 1126 if (is_optimizing()) { |
1153 AddDeoptIndexAtCall(deopt_id_after); | 1127 AddDeoptIndexAtCall(deopt_id_after); |
1154 } else { | 1128 } else { |
1155 // Add deoptimization continuation point after the call and before the | 1129 // Add deoptimization continuation point after the call and before the |
1156 // arguments are removed. | 1130 // arguments are removed. |
1157 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1131 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1158 } | 1132 } |
1159 } | 1133 } |
1160 | 1134 |
1161 | |
1162 void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id, | 1135 void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id, |
1163 TokenPosition token_pos, | 1136 TokenPosition token_pos, |
1164 const StubEntry& stub_entry, | 1137 const StubEntry& stub_entry, |
1165 RawPcDescriptors::Kind kind, | 1138 RawPcDescriptors::Kind kind, |
1166 LocationSummary* locs, | 1139 LocationSummary* locs, |
1167 const Function& target) { | 1140 const Function& target) { |
1168 // Call sites to the same target can share object pool entries. These | 1141 // Call sites to the same target can share object pool entries. These |
1169 // call sites are never patched for breakpoints: the function is deoptimized | 1142 // call sites are never patched for breakpoints: the function is deoptimized |
1170 // and the unoptimized code with IC calls for static calls is patched instead. | 1143 // and the unoptimized code with IC calls for static calls is patched instead. |
1171 ASSERT(is_optimizing()); | 1144 ASSERT(is_optimizing()); |
1172 __ BranchLinkWithEquivalence(stub_entry, target); | 1145 __ BranchLinkWithEquivalence(stub_entry, target); |
1173 | 1146 |
1174 EmitCallsiteMetaData(token_pos, deopt_id, kind, locs); | 1147 EmitCallsiteMetaData(token_pos, deopt_id, kind, locs); |
1175 // Marks either the continuation point in unoptimized code or the | 1148 // Marks either the continuation point in unoptimized code or the |
1176 // deoptimization point in optimized code, after call. | 1149 // deoptimization point in optimized code, after call. |
1177 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1150 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1178 if (is_optimizing()) { | 1151 if (is_optimizing()) { |
1179 AddDeoptIndexAtCall(deopt_id_after); | 1152 AddDeoptIndexAtCall(deopt_id_after); |
1180 } else { | 1153 } else { |
1181 // Add deoptimization continuation point after the call and before the | 1154 // Add deoptimization continuation point after the call and before the |
1182 // arguments are removed. | 1155 // arguments are removed. |
1183 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1156 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1184 } | 1157 } |
1185 AddStaticCallTarget(target); | 1158 AddStaticCallTarget(target); |
1186 } | 1159 } |
1187 | 1160 |
1188 | |
1189 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos, | 1161 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos, |
1190 intptr_t deopt_id, | 1162 intptr_t deopt_id, |
1191 const RuntimeEntry& entry, | 1163 const RuntimeEntry& entry, |
1192 intptr_t argument_count, | 1164 intptr_t argument_count, |
1193 LocationSummary* locs) { | 1165 LocationSummary* locs) { |
1194 __ CallRuntime(entry, argument_count); | 1166 __ CallRuntime(entry, argument_count); |
1195 EmitCallsiteMetaData(token_pos, deopt_id, RawPcDescriptors::kOther, locs); | 1167 EmitCallsiteMetaData(token_pos, deopt_id, RawPcDescriptors::kOther, locs); |
1196 if (deopt_id != Thread::kNoDeoptId) { | 1168 if (deopt_id != Thread::kNoDeoptId) { |
1197 // Marks either the continuation point in unoptimized code or the | 1169 // Marks either the continuation point in unoptimized code or the |
1198 // deoptimization point in optimized code, after call. | 1170 // deoptimization point in optimized code, after call. |
1199 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1171 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1200 if (is_optimizing()) { | 1172 if (is_optimizing()) { |
1201 AddDeoptIndexAtCall(deopt_id_after); | 1173 AddDeoptIndexAtCall(deopt_id_after); |
1202 } else { | 1174 } else { |
1203 // Add deoptimization continuation point after the call and before the | 1175 // Add deoptimization continuation point after the call and before the |
1204 // arguments are removed. | 1176 // arguments are removed. |
1205 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1177 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1206 } | 1178 } |
1207 } | 1179 } |
1208 } | 1180 } |
1209 | 1181 |
1210 | |
1211 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { | 1182 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { |
1212 // We do not check for overflow when incrementing the edge counter. The | 1183 // We do not check for overflow when incrementing the edge counter. The |
1213 // function should normally be optimized long before the counter can | 1184 // function should normally be optimized long before the counter can |
1214 // overflow; and though we do not reset the counters when we optimize or | 1185 // overflow; and though we do not reset the counters when we optimize or |
1215 // deoptimize, there is a bound on the number of | 1186 // deoptimize, there is a bound on the number of |
1216 // optimization/deoptimization cycles we will attempt. | 1187 // optimization/deoptimization cycles we will attempt. |
1217 ASSERT(!edge_counters_array_.IsNull()); | 1188 ASSERT(!edge_counters_array_.IsNull()); |
1218 ASSERT(assembler_->constant_pool_allowed()); | 1189 ASSERT(assembler_->constant_pool_allowed()); |
1219 __ Comment("Edge counter"); | 1190 __ Comment("Edge counter"); |
1220 __ LoadObject(R0, edge_counters_array_); | 1191 __ LoadObject(R0, edge_counters_array_); |
1221 #if defined(DEBUG) | 1192 #if defined(DEBUG) |
1222 bool old_use_far_branches = assembler_->use_far_branches(); | 1193 bool old_use_far_branches = assembler_->use_far_branches(); |
1223 assembler_->set_use_far_branches(true); | 1194 assembler_->set_use_far_branches(true); |
1224 #endif // DEBUG | 1195 #endif // DEBUG |
1225 __ LoadFieldFromOffset(kWord, R1, R0, Array::element_offset(edge_id)); | 1196 __ LoadFieldFromOffset(kWord, R1, R0, Array::element_offset(edge_id)); |
1226 __ add(R1, R1, Operand(Smi::RawValue(1))); | 1197 __ add(R1, R1, Operand(Smi::RawValue(1))); |
1227 __ StoreIntoObjectNoBarrierOffset(R0, Array::element_offset(edge_id), R1); | 1198 __ StoreIntoObjectNoBarrierOffset(R0, Array::element_offset(edge_id), R1); |
1228 #if defined(DEBUG) | 1199 #if defined(DEBUG) |
1229 assembler_->set_use_far_branches(old_use_far_branches); | 1200 assembler_->set_use_far_branches(old_use_far_branches); |
1230 #endif // DEBUG | 1201 #endif // DEBUG |
1231 } | 1202 } |
1232 | 1203 |
1233 | |
1234 void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry, | 1204 void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry, |
1235 const ICData& ic_data, | 1205 const ICData& ic_data, |
1236 intptr_t argument_count, | 1206 intptr_t argument_count, |
1237 intptr_t deopt_id, | 1207 intptr_t deopt_id, |
1238 TokenPosition token_pos, | 1208 TokenPosition token_pos, |
1239 LocationSummary* locs) { | 1209 LocationSummary* locs) { |
1240 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1210 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
1241 // Each ICData propagated from unoptimized to optimized code contains the | 1211 // Each ICData propagated from unoptimized to optimized code contains the |
1242 // function that corresponds to the Dart function of that IC call. Due | 1212 // function that corresponds to the Dart function of that IC call. Due |
1243 // to inlining in optimized code, that function may not correspond to the | 1213 // to inlining in optimized code, that function may not correspond to the |
1244 // top-level function (parsed_function().function()) which could be | 1214 // top-level function (parsed_function().function()) which could be |
1245 // reoptimized and which counter needs to be incremented. | 1215 // reoptimized and which counter needs to be incremented. |
1246 // Pass the function explicitly, it is used in IC stub. | 1216 // Pass the function explicitly, it is used in IC stub. |
1247 | 1217 |
1248 __ LoadObject(R8, parsed_function().function()); | 1218 __ LoadObject(R8, parsed_function().function()); |
1249 __ LoadUniqueObject(R9, ic_data); | 1219 __ LoadUniqueObject(R9, ic_data); |
1250 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, | 1220 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
1251 locs); | 1221 locs); |
1252 __ Drop(argument_count); | 1222 __ Drop(argument_count); |
1253 } | 1223 } |
1254 | 1224 |
1255 | |
1256 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, | 1225 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, |
1257 const ICData& ic_data, | 1226 const ICData& ic_data, |
1258 intptr_t argument_count, | 1227 intptr_t argument_count, |
1259 intptr_t deopt_id, | 1228 intptr_t deopt_id, |
1260 TokenPosition token_pos, | 1229 TokenPosition token_pos, |
1261 LocationSummary* locs) { | 1230 LocationSummary* locs) { |
1262 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); | 1231 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); |
1263 __ LoadUniqueObject(R9, ic_data); | 1232 __ LoadUniqueObject(R9, ic_data); |
1264 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, | 1233 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, |
1265 locs); | 1234 locs); |
1266 __ Drop(argument_count); | 1235 __ Drop(argument_count); |
1267 } | 1236 } |
1268 | 1237 |
1269 | |
1270 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1238 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
1271 const String& name, | 1239 const String& name, |
1272 const Array& arguments_descriptor, | 1240 const Array& arguments_descriptor, |
1273 intptr_t argument_count, | 1241 intptr_t argument_count, |
1274 intptr_t deopt_id, | 1242 intptr_t deopt_id, |
1275 TokenPosition token_pos, | 1243 TokenPosition token_pos, |
1276 LocationSummary* locs, | 1244 LocationSummary* locs, |
1277 intptr_t try_index, | 1245 intptr_t try_index, |
1278 intptr_t slow_path_argument_count) { | 1246 intptr_t slow_path_argument_count) { |
1279 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1247 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
(...skipping 26 matching lines...) Expand all Loading... |
1306 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, | 1274 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, |
1307 token_pos); | 1275 token_pos); |
1308 // Add deoptimization continuation point after the call and before the | 1276 // Add deoptimization continuation point after the call and before the |
1309 // arguments are removed. | 1277 // arguments are removed. |
1310 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1278 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1311 } | 1279 } |
1312 EmitCatchEntryState(pending_deoptimization_env_, try_index); | 1280 EmitCatchEntryState(pending_deoptimization_env_, try_index); |
1313 __ Drop(argument_count); | 1281 __ Drop(argument_count); |
1314 } | 1282 } |
1315 | 1283 |
1316 | |
1317 void FlowGraphCompiler::EmitSwitchableInstanceCall(const ICData& ic_data, | 1284 void FlowGraphCompiler::EmitSwitchableInstanceCall(const ICData& ic_data, |
1318 intptr_t argument_count, | 1285 intptr_t argument_count, |
1319 intptr_t deopt_id, | 1286 intptr_t deopt_id, |
1320 TokenPosition token_pos, | 1287 TokenPosition token_pos, |
1321 LocationSummary* locs) { | 1288 LocationSummary* locs) { |
1322 ASSERT(ic_data.NumArgsTested() == 1); | 1289 ASSERT(ic_data.NumArgsTested() == 1); |
1323 const Code& initial_stub = | 1290 const Code& initial_stub = |
1324 Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code()); | 1291 Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code()); |
1325 | 1292 |
1326 __ Comment("SwitchableCall"); | 1293 __ Comment("SwitchableCall"); |
(...skipping 10 matching lines...) Expand all Loading... |
1337 if (is_optimizing()) { | 1304 if (is_optimizing()) { |
1338 AddDeoptIndexAtCall(deopt_id_after); | 1305 AddDeoptIndexAtCall(deopt_id_after); |
1339 } else { | 1306 } else { |
1340 // Add deoptimization continuation point after the call and before the | 1307 // Add deoptimization continuation point after the call and before the |
1341 // arguments are removed. | 1308 // arguments are removed. |
1342 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1309 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1343 } | 1310 } |
1344 __ Drop(argument_count); | 1311 __ Drop(argument_count); |
1345 } | 1312 } |
1346 | 1313 |
1347 | |
1348 void FlowGraphCompiler::EmitUnoptimizedStaticCall(intptr_t argument_count, | 1314 void FlowGraphCompiler::EmitUnoptimizedStaticCall(intptr_t argument_count, |
1349 intptr_t deopt_id, | 1315 intptr_t deopt_id, |
1350 TokenPosition token_pos, | 1316 TokenPosition token_pos, |
1351 LocationSummary* locs, | 1317 LocationSummary* locs, |
1352 const ICData& ic_data) { | 1318 const ICData& ic_data) { |
1353 const StubEntry* stub_entry = | 1319 const StubEntry* stub_entry = |
1354 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); | 1320 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); |
1355 __ LoadObject(R9, ic_data); | 1321 __ LoadObject(R9, ic_data); |
1356 GenerateDartCall(deopt_id, token_pos, *stub_entry, | 1322 GenerateDartCall(deopt_id, token_pos, *stub_entry, |
1357 RawPcDescriptors::kUnoptStaticCall, locs); | 1323 RawPcDescriptors::kUnoptStaticCall, locs); |
1358 __ Drop(argument_count); | 1324 __ Drop(argument_count); |
1359 } | 1325 } |
1360 | 1326 |
1361 | |
1362 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1327 void FlowGraphCompiler::EmitOptimizedStaticCall( |
1363 const Function& function, | 1328 const Function& function, |
1364 const Array& arguments_descriptor, | 1329 const Array& arguments_descriptor, |
1365 intptr_t argument_count, | 1330 intptr_t argument_count, |
1366 intptr_t deopt_id, | 1331 intptr_t deopt_id, |
1367 TokenPosition token_pos, | 1332 TokenPosition token_pos, |
1368 LocationSummary* locs) { | 1333 LocationSummary* locs) { |
1369 ASSERT(!function.IsClosureFunction()); | 1334 ASSERT(!function.IsClosureFunction()); |
1370 if (function.HasOptionalParameters() || | 1335 if (function.HasOptionalParameters() || |
1371 (FLAG_reify_generic_functions && function.IsGeneric())) { | 1336 (FLAG_reify_generic_functions && function.IsGeneric())) { |
1372 __ LoadObject(R4, arguments_descriptor); | 1337 __ LoadObject(R4, arguments_descriptor); |
1373 } else { | 1338 } else { |
1374 __ LoadImmediate(R4, 0); // GC safe smi zero because of stub. | 1339 __ LoadImmediate(R4, 0); // GC safe smi zero because of stub. |
1375 } | 1340 } |
1376 // Do not use the code from the function, but let the code be patched so that | 1341 // Do not use the code from the function, but let the code be patched so that |
1377 // we can record the outgoing edges to other code. | 1342 // we can record the outgoing edges to other code. |
1378 GenerateStaticDartCall(deopt_id, token_pos, | 1343 GenerateStaticDartCall(deopt_id, token_pos, |
1379 *StubCode::CallStaticFunction_entry(), | 1344 *StubCode::CallStaticFunction_entry(), |
1380 RawPcDescriptors::kOther, locs, function); | 1345 RawPcDescriptors::kOther, locs, function); |
1381 __ Drop(argument_count); | 1346 __ Drop(argument_count); |
1382 } | 1347 } |
1383 | 1348 |
1384 | |
1385 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( | 1349 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( |
1386 Register reg, | 1350 Register reg, |
1387 const Object& obj, | 1351 const Object& obj, |
1388 bool needs_number_check, | 1352 bool needs_number_check, |
1389 TokenPosition token_pos, | 1353 TokenPosition token_pos, |
1390 intptr_t deopt_id) { | 1354 intptr_t deopt_id) { |
1391 if (needs_number_check) { | 1355 if (needs_number_check) { |
1392 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); | 1356 ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()); |
1393 __ Push(reg); | 1357 __ Push(reg); |
1394 __ PushObject(obj); | 1358 __ PushObject(obj); |
1395 if (is_optimizing()) { | 1359 if (is_optimizing()) { |
1396 __ BranchLinkPatchable( | 1360 __ BranchLinkPatchable( |
1397 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1361 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1398 } else { | 1362 } else { |
1399 __ BranchLinkPatchable( | 1363 __ BranchLinkPatchable( |
1400 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1364 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1401 } | 1365 } |
1402 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos); | 1366 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos); |
1403 // Stub returns result in flags (result of a cmp, we need Z computed). | 1367 // Stub returns result in flags (result of a cmp, we need Z computed). |
1404 __ Drop(1); // Discard constant. | 1368 __ Drop(1); // Discard constant. |
1405 __ Pop(reg); // Restore 'reg'. | 1369 __ Pop(reg); // Restore 'reg'. |
1406 } else { | 1370 } else { |
1407 __ CompareObject(reg, obj); | 1371 __ CompareObject(reg, obj); |
1408 } | 1372 } |
1409 return EQ; | 1373 return EQ; |
1410 } | 1374 } |
1411 | 1375 |
1412 | |
1413 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1376 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
1414 Register right, | 1377 Register right, |
1415 bool needs_number_check, | 1378 bool needs_number_check, |
1416 TokenPosition token_pos, | 1379 TokenPosition token_pos, |
1417 intptr_t deopt_id) { | 1380 intptr_t deopt_id) { |
1418 if (needs_number_check) { | 1381 if (needs_number_check) { |
1419 __ Push(left); | 1382 __ Push(left); |
1420 __ Push(right); | 1383 __ Push(right); |
1421 if (is_optimizing()) { | 1384 if (is_optimizing()) { |
1422 __ BranchLinkPatchable( | 1385 __ BranchLinkPatchable( |
1423 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); | 1386 *StubCode::OptimizedIdenticalWithNumberCheck_entry()); |
1424 } else { | 1387 } else { |
1425 __ BranchLinkPatchable( | 1388 __ BranchLinkPatchable( |
1426 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); | 1389 *StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); |
1427 } | 1390 } |
1428 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos); | 1391 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos); |
1429 // Stub returns result in flags (result of a cmp, we need Z computed). | 1392 // Stub returns result in flags (result of a cmp, we need Z computed). |
1430 __ Pop(right); | 1393 __ Pop(right); |
1431 __ Pop(left); | 1394 __ Pop(left); |
1432 } else { | 1395 } else { |
1433 __ cmp(left, Operand(right)); | 1396 __ cmp(left, Operand(right)); |
1434 } | 1397 } |
1435 return EQ; | 1398 return EQ; |
1436 } | 1399 } |
1437 | 1400 |
1438 | |
1439 // This function must be in sync with FlowGraphCompiler::RecordSafepoint and | 1401 // This function must be in sync with FlowGraphCompiler::RecordSafepoint and |
1440 // FlowGraphCompiler::SlowPathEnvironmentFor. | 1402 // FlowGraphCompiler::SlowPathEnvironmentFor. |
1441 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { | 1403 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { |
1442 #if defined(DEBUG) | 1404 #if defined(DEBUG) |
1443 locs->CheckWritableInputs(); | 1405 locs->CheckWritableInputs(); |
1444 ClobberDeadTempRegisters(locs); | 1406 ClobberDeadTempRegisters(locs); |
1445 #endif | 1407 #endif |
1446 | 1408 |
1447 // TODO(vegorov): consider saving only caller save (volatile) registers. | 1409 // TODO(vegorov): consider saving only caller save (volatile) registers. |
1448 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount(); | 1410 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount(); |
(...skipping 23 matching lines...) Expand all Loading... |
1472 Register reg = static_cast<Register>(i); | 1434 Register reg = static_cast<Register>(i); |
1473 if (locs->live_registers()->ContainsRegister(reg)) { | 1435 if (locs->live_registers()->ContainsRegister(reg)) { |
1474 reg_list |= (1 << reg); | 1436 reg_list |= (1 << reg); |
1475 } | 1437 } |
1476 } | 1438 } |
1477 if (reg_list != 0) { | 1439 if (reg_list != 0) { |
1478 __ PushList(reg_list); | 1440 __ PushList(reg_list); |
1479 } | 1441 } |
1480 } | 1442 } |
1481 | 1443 |
1482 | |
1483 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { | 1444 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { |
1484 RegList reg_list = 0; | 1445 RegList reg_list = 0; |
1485 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) { | 1446 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; --i) { |
1486 Register reg = static_cast<Register>(i); | 1447 Register reg = static_cast<Register>(i); |
1487 if (locs->live_registers()->ContainsRegister(reg)) { | 1448 if (locs->live_registers()->ContainsRegister(reg)) { |
1488 reg_list |= (1 << reg); | 1449 reg_list |= (1 << reg); |
1489 } | 1450 } |
1490 } | 1451 } |
1491 if (reg_list != 0) { | 1452 if (reg_list != 0) { |
1492 __ PopList(reg_list); | 1453 __ PopList(reg_list); |
1493 } | 1454 } |
1494 | 1455 |
1495 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount(); | 1456 const intptr_t fpu_regs_count = locs->live_registers()->FpuRegisterCount(); |
1496 if (fpu_regs_count > 0) { | 1457 if (fpu_regs_count > 0) { |
1497 // Fpu registers have the lowest register number at the lowest address. | 1458 // Fpu registers have the lowest register number at the lowest address. |
1498 intptr_t offset = 0; | 1459 intptr_t offset = 0; |
1499 for (intptr_t i = 0; i < kNumberOfFpuRegisters; ++i) { | 1460 for (intptr_t i = 0; i < kNumberOfFpuRegisters; ++i) { |
1500 QRegister fpu_reg = static_cast<QRegister>(i); | 1461 QRegister fpu_reg = static_cast<QRegister>(i); |
1501 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { | 1462 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { |
1502 DRegister d = EvenDRegisterOf(fpu_reg); | 1463 DRegister d = EvenDRegisterOf(fpu_reg); |
1503 ASSERT(d + 1 == OddDRegisterOf(fpu_reg)); | 1464 ASSERT(d + 1 == OddDRegisterOf(fpu_reg)); |
1504 __ vldmd(IA_W, SP, d, 2); | 1465 __ vldmd(IA_W, SP, d, 2); |
1505 offset += kFpuRegisterSize; | 1466 offset += kFpuRegisterSize; |
1506 } | 1467 } |
1507 } | 1468 } |
1508 ASSERT(offset == (fpu_regs_count * kFpuRegisterSize)); | 1469 ASSERT(offset == (fpu_regs_count * kFpuRegisterSize)); |
1509 } | 1470 } |
1510 } | 1471 } |
1511 | 1472 |
1512 | |
1513 #if defined(DEBUG) | 1473 #if defined(DEBUG) |
1514 void FlowGraphCompiler::ClobberDeadTempRegisters(LocationSummary* locs) { | 1474 void FlowGraphCompiler::ClobberDeadTempRegisters(LocationSummary* locs) { |
1515 // Clobber temporaries that have not been manually preserved. | 1475 // Clobber temporaries that have not been manually preserved. |
1516 for (intptr_t i = 0; i < locs->temp_count(); ++i) { | 1476 for (intptr_t i = 0; i < locs->temp_count(); ++i) { |
1517 Location tmp = locs->temp(i); | 1477 Location tmp = locs->temp(i); |
1518 // TODO(zerny): clobber non-live temporary FPU registers. | 1478 // TODO(zerny): clobber non-live temporary FPU registers. |
1519 if (tmp.IsRegister() && | 1479 if (tmp.IsRegister() && |
1520 !locs->live_registers()->ContainsRegister(tmp.reg())) { | 1480 !locs->live_registers()->ContainsRegister(tmp.reg())) { |
1521 __ mov(tmp.reg(), Operand(0xf7)); | 1481 __ mov(tmp.reg(), Operand(0xf7)); |
1522 } | 1482 } |
1523 } | 1483 } |
1524 } | 1484 } |
1525 #endif | 1485 #endif |
1526 | 1486 |
1527 | |
1528 void FlowGraphCompiler::EmitTestAndCallLoadReceiver( | 1487 void FlowGraphCompiler::EmitTestAndCallLoadReceiver( |
1529 intptr_t argument_count, | 1488 intptr_t argument_count, |
1530 const Array& arguments_descriptor) { | 1489 const Array& arguments_descriptor) { |
1531 __ Comment("EmitTestAndCall"); | 1490 __ Comment("EmitTestAndCall"); |
1532 // Load receiver into R0. | 1491 // Load receiver into R0. |
1533 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1492 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
1534 __ LoadObject(R4, arguments_descriptor); | 1493 __ LoadObject(R4, arguments_descriptor); |
1535 } | 1494 } |
1536 | 1495 |
1537 | |
1538 void FlowGraphCompiler::EmitTestAndCallSmiBranch(Label* label, bool if_smi) { | 1496 void FlowGraphCompiler::EmitTestAndCallSmiBranch(Label* label, bool if_smi) { |
1539 __ tst(R0, Operand(kSmiTagMask)); | 1497 __ tst(R0, Operand(kSmiTagMask)); |
1540 // Jump if receiver is not Smi. | 1498 // Jump if receiver is not Smi. |
1541 __ b(label, if_smi ? EQ : NE); | 1499 __ b(label, if_smi ? EQ : NE); |
1542 } | 1500 } |
1543 | 1501 |
1544 | |
1545 void FlowGraphCompiler::EmitTestAndCallLoadCid() { | 1502 void FlowGraphCompiler::EmitTestAndCallLoadCid() { |
1546 __ LoadClassId(R2, R0); | 1503 __ LoadClassId(R2, R0); |
1547 } | 1504 } |
1548 | 1505 |
1549 | |
1550 int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label, | 1506 int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label, |
1551 const CidRange& range, | 1507 const CidRange& range, |
1552 int bias) { | 1508 int bias) { |
1553 intptr_t cid_start = range.cid_start; | 1509 intptr_t cid_start = range.cid_start; |
1554 if (range.IsSingleCid()) { | 1510 if (range.IsSingleCid()) { |
1555 __ CompareImmediate(R2, cid_start - bias); | 1511 __ CompareImmediate(R2, cid_start - bias); |
1556 __ b(next_label, NE); | 1512 __ b(next_label, NE); |
1557 } else { | 1513 } else { |
1558 __ AddImmediate(R2, R2, bias - cid_start); | 1514 __ AddImmediate(R2, R2, bias - cid_start); |
1559 bias = cid_start; | 1515 bias = cid_start; |
1560 __ CompareImmediate(R2, range.Extent()); | 1516 __ CompareImmediate(R2, range.Extent()); |
1561 __ b(next_label, HI); // Unsigned higher. | 1517 __ b(next_label, HI); // Unsigned higher. |
1562 } | 1518 } |
1563 return bias; | 1519 return bias; |
1564 } | 1520 } |
1565 | 1521 |
1566 | |
1567 #undef __ | 1522 #undef __ |
1568 #define __ compiler_->assembler()-> | 1523 #define __ compiler_->assembler()-> |
1569 | 1524 |
1570 | |
1571 void ParallelMoveResolver::EmitMove(int index) { | 1525 void ParallelMoveResolver::EmitMove(int index) { |
1572 MoveOperands* move = moves_[index]; | 1526 MoveOperands* move = moves_[index]; |
1573 const Location source = move->src(); | 1527 const Location source = move->src(); |
1574 const Location destination = move->dest(); | 1528 const Location destination = move->dest(); |
1575 | 1529 |
1576 if (source.IsRegister()) { | 1530 if (source.IsRegister()) { |
1577 if (destination.IsRegister()) { | 1531 if (destination.IsRegister()) { |
1578 __ mov(destination.reg(), Operand(source.reg())); | 1532 __ mov(destination.reg(), Operand(source.reg())); |
1579 } else { | 1533 } else { |
1580 ASSERT(destination.IsStackSlot()); | 1534 ASSERT(destination.IsStackSlot()); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1681 } else { | 1635 } else { |
1682 __ LoadObject(TMP, constant); | 1636 __ LoadObject(TMP, constant); |
1683 } | 1637 } |
1684 __ StoreToOffset(kWord, TMP, destination.base_reg(), dest_offset); | 1638 __ StoreToOffset(kWord, TMP, destination.base_reg(), dest_offset); |
1685 } | 1639 } |
1686 } | 1640 } |
1687 | 1641 |
1688 move->Eliminate(); | 1642 move->Eliminate(); |
1689 } | 1643 } |
1690 | 1644 |
1691 | |
1692 void ParallelMoveResolver::EmitSwap(int index) { | 1645 void ParallelMoveResolver::EmitSwap(int index) { |
1693 MoveOperands* move = moves_[index]; | 1646 MoveOperands* move = moves_[index]; |
1694 const Location source = move->src(); | 1647 const Location source = move->src(); |
1695 const Location destination = move->dest(); | 1648 const Location destination = move->dest(); |
1696 | 1649 |
1697 if (source.IsRegister() && destination.IsRegister()) { | 1650 if (source.IsRegister() && destination.IsRegister()) { |
1698 ASSERT(source.reg() != IP); | 1651 ASSERT(source.reg() != IP); |
1699 ASSERT(destination.reg() != IP); | 1652 ASSERT(destination.reg() != IP); |
1700 __ mov(IP, Operand(source.reg())); | 1653 __ mov(IP, Operand(source.reg())); |
1701 __ mov(source.reg(), Operand(destination.reg())); | 1654 __ mov(source.reg(), Operand(destination.reg())); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1780 for (int i = 0; i < moves_.length(); ++i) { | 1733 for (int i = 0; i < moves_.length(); ++i) { |
1781 const MoveOperands& other_move = *moves_[i]; | 1734 const MoveOperands& other_move = *moves_[i]; |
1782 if (other_move.Blocks(source)) { | 1735 if (other_move.Blocks(source)) { |
1783 moves_[i]->set_src(destination); | 1736 moves_[i]->set_src(destination); |
1784 } else if (other_move.Blocks(destination)) { | 1737 } else if (other_move.Blocks(destination)) { |
1785 moves_[i]->set_src(source); | 1738 moves_[i]->set_src(source); |
1786 } | 1739 } |
1787 } | 1740 } |
1788 } | 1741 } |
1789 | 1742 |
1790 | |
1791 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, | 1743 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, |
1792 const Address& src) { | 1744 const Address& src) { |
1793 UNREACHABLE(); | 1745 UNREACHABLE(); |
1794 } | 1746 } |
1795 | 1747 |
1796 | |
1797 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { | 1748 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { |
1798 UNREACHABLE(); | 1749 UNREACHABLE(); |
1799 } | 1750 } |
1800 | 1751 |
1801 | |
1802 // Do not call or implement this function. Instead, use the form below that | 1752 // Do not call or implement this function. Instead, use the form below that |
1803 // uses an offset from the frame pointer instead of an Address. | 1753 // uses an offset from the frame pointer instead of an Address. |
1804 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { | 1754 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { |
1805 UNREACHABLE(); | 1755 UNREACHABLE(); |
1806 } | 1756 } |
1807 | 1757 |
1808 | |
1809 // Do not call or implement this function. Instead, use the form below that | 1758 // Do not call or implement this function. Instead, use the form below that |
1810 // uses offsets from the frame pointer instead of Addresses. | 1759 // uses offsets from the frame pointer instead of Addresses. |
1811 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { | 1760 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { |
1812 UNREACHABLE(); | 1761 UNREACHABLE(); |
1813 } | 1762 } |
1814 | 1763 |
1815 | |
1816 void ParallelMoveResolver::Exchange(Register reg, | 1764 void ParallelMoveResolver::Exchange(Register reg, |
1817 Register base_reg, | 1765 Register base_reg, |
1818 intptr_t stack_offset) { | 1766 intptr_t stack_offset) { |
1819 ScratchRegisterScope tmp(this, reg); | 1767 ScratchRegisterScope tmp(this, reg); |
1820 __ mov(tmp.reg(), Operand(reg)); | 1768 __ mov(tmp.reg(), Operand(reg)); |
1821 __ LoadFromOffset(kWord, reg, base_reg, stack_offset); | 1769 __ LoadFromOffset(kWord, reg, base_reg, stack_offset); |
1822 __ StoreToOffset(kWord, tmp.reg(), base_reg, stack_offset); | 1770 __ StoreToOffset(kWord, tmp.reg(), base_reg, stack_offset); |
1823 } | 1771 } |
1824 | 1772 |
1825 | |
1826 void ParallelMoveResolver::Exchange(Register base_reg1, | 1773 void ParallelMoveResolver::Exchange(Register base_reg1, |
1827 intptr_t stack_offset1, | 1774 intptr_t stack_offset1, |
1828 Register base_reg2, | 1775 Register base_reg2, |
1829 intptr_t stack_offset2) { | 1776 intptr_t stack_offset2) { |
1830 ScratchRegisterScope tmp1(this, kNoRegister); | 1777 ScratchRegisterScope tmp1(this, kNoRegister); |
1831 ScratchRegisterScope tmp2(this, tmp1.reg()); | 1778 ScratchRegisterScope tmp2(this, tmp1.reg()); |
1832 __ LoadFromOffset(kWord, tmp1.reg(), base_reg1, stack_offset1); | 1779 __ LoadFromOffset(kWord, tmp1.reg(), base_reg1, stack_offset1); |
1833 __ LoadFromOffset(kWord, tmp2.reg(), base_reg2, stack_offset2); | 1780 __ LoadFromOffset(kWord, tmp2.reg(), base_reg2, stack_offset2); |
1834 __ StoreToOffset(kWord, tmp1.reg(), base_reg2, stack_offset2); | 1781 __ StoreToOffset(kWord, tmp1.reg(), base_reg2, stack_offset2); |
1835 __ StoreToOffset(kWord, tmp2.reg(), base_reg1, stack_offset1); | 1782 __ StoreToOffset(kWord, tmp2.reg(), base_reg1, stack_offset1); |
1836 } | 1783 } |
1837 | 1784 |
1838 | |
1839 void ParallelMoveResolver::SpillScratch(Register reg) { | 1785 void ParallelMoveResolver::SpillScratch(Register reg) { |
1840 __ Push(reg); | 1786 __ Push(reg); |
1841 } | 1787 } |
1842 | 1788 |
1843 | |
1844 void ParallelMoveResolver::RestoreScratch(Register reg) { | 1789 void ParallelMoveResolver::RestoreScratch(Register reg) { |
1845 __ Pop(reg); | 1790 __ Pop(reg); |
1846 } | 1791 } |
1847 | 1792 |
1848 | |
1849 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { | 1793 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { |
1850 DRegister dreg = EvenDRegisterOf(reg); | 1794 DRegister dreg = EvenDRegisterOf(reg); |
1851 __ vstrd(dreg, Address(SP, -kDoubleSize, Address::PreIndex)); | 1795 __ vstrd(dreg, Address(SP, -kDoubleSize, Address::PreIndex)); |
1852 } | 1796 } |
1853 | 1797 |
1854 | |
1855 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1798 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
1856 DRegister dreg = EvenDRegisterOf(reg); | 1799 DRegister dreg = EvenDRegisterOf(reg); |
1857 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1800 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
1858 } | 1801 } |
1859 | 1802 |
1860 | |
1861 #undef __ | 1803 #undef __ |
1862 | 1804 |
1863 } // namespace dart | 1805 } // namespace dart |
1864 | 1806 |
1865 #endif // defined TARGET_ARCH_ARM | 1807 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |