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 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
202 __ b(&fall_through, EQ); | 202 __ b(&fall_through, EQ); |
203 __ CompareObject(bool_register, Bool::True()); | 203 __ CompareObject(bool_register, Bool::True()); |
204 __ b(is_true, EQ); | 204 __ b(is_true, EQ); |
205 __ b(is_false); | 205 __ b(is_false); |
206 __ Bind(&fall_through); | 206 __ Bind(&fall_through); |
207 } | 207 } |
208 | 208 |
209 | 209 |
210 // R0: instance (must be preserved). | 210 // R0: instance (must be preserved). |
211 // R1: instantiator type arguments (if used). | 211 // R1: instantiator type arguments (if used). |
212 // R2: function type arguments (if used). | |
213 // R3: type test cache. | |
212 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 214 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
213 TypeTestStubKind test_kind, | 215 TypeTestStubKind test_kind, |
214 Register instance_reg, | 216 Register instance_reg, |
215 Register type_arguments_reg, | 217 Register instantiator_type_arguments_reg, |
218 Register function_type_arguments_reg, | |
216 Register temp_reg, | 219 Register temp_reg, |
217 Label* is_instance_lbl, | 220 Label* is_instance_lbl, |
218 Label* is_not_instance_lbl) { | 221 Label* is_not_instance_lbl) { |
219 ASSERT(instance_reg == R0); | 222 ASSERT(instance_reg == R0); |
220 ASSERT(temp_reg == kNoRegister); // Unused on ARM. | 223 ASSERT(temp_reg == kNoRegister); // Unused on ARM. |
221 const SubtypeTestCache& type_test_cache = | 224 const SubtypeTestCache& type_test_cache = |
222 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); | 225 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
223 __ LoadUniqueObject(R2, type_test_cache); | 226 __ LoadUniqueObject(R3, type_test_cache); |
224 if (test_kind == kTestTypeOneArg) { | 227 if (test_kind == kTestTypeOneArg) { |
225 ASSERT(type_arguments_reg == kNoRegister); | 228 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
226 __ LoadObject(R1, Object::null_object()); | 229 ASSERT(function_type_arguments_reg == kNoRegister); |
227 __ BranchLink(*StubCode::Subtype1TestCache_entry()); | 230 __ BranchLink(*StubCode::Subtype1TestCache_entry()); |
228 } else if (test_kind == kTestTypeTwoArgs) { | 231 } else if (test_kind == kTestTypeTwoArgs) { |
229 ASSERT(type_arguments_reg == kNoRegister); | 232 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
230 __ LoadObject(R1, Object::null_object()); | 233 ASSERT(function_type_arguments_reg == kNoRegister); |
231 __ BranchLink(*StubCode::Subtype2TestCache_entry()); | 234 __ BranchLink(*StubCode::Subtype2TestCache_entry()); |
232 } else if (test_kind == kTestTypeThreeArgs) { | 235 } else if (test_kind == kTestTypeFourArgs) { |
233 ASSERT(type_arguments_reg == R1); | 236 ASSERT(instantiator_type_arguments_reg == R1); |
234 __ BranchLink(*StubCode::Subtype3TestCache_entry()); | 237 ASSERT(function_type_arguments_reg == R2); |
238 __ BranchLink(*StubCode::Subtype4TestCache_entry()); | |
235 } else { | 239 } else { |
236 UNREACHABLE(); | 240 UNREACHABLE(); |
237 } | 241 } |
238 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. | 242 // Result is in R1: null -> not found, otherwise Bool::True or Bool::False. |
239 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); | 243 GenerateBoolToJump(R1, is_instance_lbl, is_not_instance_lbl); |
240 return type_test_cache.raw(); | 244 return type_test_cache.raw(); |
241 } | 245 } |
242 | 246 |
243 | 247 |
244 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 248 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
245 // type test is conclusive, otherwise fallthrough if a type test could not | 249 // type test is conclusive, otherwise fallthrough if a type test could not |
246 // be completed. | 250 // be completed. |
247 // R0: instance being type checked (preserved). | 251 // R0: instance being type checked (preserved). |
248 // Clobbers R2. | 252 // Clobbers R1, R2. |
249 RawSubtypeTestCache* | 253 RawSubtypeTestCache* |
250 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 254 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
251 TokenPosition token_pos, | 255 TokenPosition token_pos, |
252 const AbstractType& type, | 256 const AbstractType& type, |
253 Label* is_instance_lbl, | 257 Label* is_instance_lbl, |
254 Label* is_not_instance_lbl) { | 258 Label* is_not_instance_lbl) { |
255 __ Comment("InstantiatedTypeWithArgumentsTest"); | 259 __ Comment("InstantiatedTypeWithArgumentsTest"); |
256 ASSERT(type.IsInstantiated()); | 260 ASSERT(type.IsInstantiated()); |
257 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); | 261 const Class& type_class = Class::ZoneHandle(zone(), type.type_class()); |
258 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); | 262 ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0)); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 306 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
303 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 307 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
304 // Instance class test only necessary. | 308 // Instance class test only necessary. |
305 return GenerateSubtype1TestCacheLookup( | 309 return GenerateSubtype1TestCacheLookup( |
306 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 310 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
307 } | 311 } |
308 } | 312 } |
309 } | 313 } |
310 } | 314 } |
311 // Regular subtype test cache involving instance's type arguments. | 315 // Regular subtype test cache involving instance's type arguments. |
312 const Register kTypeArgumentsReg = kNoRegister; | 316 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
317 const Register kFunctionTypeArgumentsReg = kNoRegister; | |
313 const Register kTempReg = kNoRegister; | 318 const Register kTempReg = kNoRegister; |
314 // R0: instance (must be preserved). | 319 // R0: instance (must be preserved). |
315 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, | 320 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
316 kTypeArgumentsReg, kTempReg, | 321 kInstantiatorTypeArgumentsReg, |
322 kFunctionTypeArgumentsReg, kTempReg, | |
317 is_instance_lbl, is_not_instance_lbl); | 323 is_instance_lbl, is_not_instance_lbl); |
318 } | 324 } |
319 | 325 |
320 | 326 |
321 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 327 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
322 const GrowableArray<intptr_t>& class_ids, | 328 const GrowableArray<intptr_t>& class_ids, |
323 Label* is_equal_lbl, | 329 Label* is_equal_lbl, |
324 Label* is_not_equal_lbl) { | 330 Label* is_not_equal_lbl) { |
325 for (intptr_t i = 0; i < class_ids.length(); i++) { | 331 for (intptr_t i = 0; i < class_ids.length(); i++) { |
326 __ CompareImmediate(class_id_reg, class_ids[i]); | 332 __ CompareImmediate(class_id_reg, class_ids[i]); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
393 __ CompareImmediate(kClassIdReg, type_class.id()); | 399 __ CompareImmediate(kClassIdReg, type_class.id()); |
394 __ b(is_instance_lbl, EQ); | 400 __ b(is_instance_lbl, EQ); |
395 } | 401 } |
396 // Otherwise fallthrough. | 402 // Otherwise fallthrough. |
397 return true; | 403 return true; |
398 } | 404 } |
399 | 405 |
400 | 406 |
401 // Uses SubtypeTestCache to store instance class and result. | 407 // Uses SubtypeTestCache to store instance class and result. |
402 // R0: instance to test. | 408 // R0: instance to test. |
403 // Clobbers R1-R4,R9. | 409 // Clobbers R1-R4, R8, R9. |
404 // Immediate class test already done. | 410 // Immediate class test already done. |
405 // TODO(srdjan): Implement a quicker subtype check, as type test | 411 // TODO(srdjan): Implement a quicker subtype check, as type test |
406 // arrays can grow too high, but they may be useful when optimizing | 412 // arrays can grow too high, but they may be useful when optimizing |
407 // code (type-feedback). | 413 // code (type-feedback). |
408 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 414 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
409 TokenPosition token_pos, | 415 TokenPosition token_pos, |
410 const Class& type_class, | 416 const Class& type_class, |
411 Label* is_instance_lbl, | 417 Label* is_instance_lbl, |
412 Label* is_not_instance_lbl) { | 418 Label* is_not_instance_lbl) { |
413 __ Comment("Subtype1TestCacheLookup"); | 419 __ Comment("Subtype1TestCacheLookup"); |
414 const Register kInstanceReg = R0; | 420 const Register kInstanceReg = R0; |
415 __ LoadClass(R1, kInstanceReg, R2); | 421 __ LoadClass(R1, kInstanceReg, R2); |
416 // R1: instance class. | 422 // R1: instance class. |
417 // Check immediate superclass equality. | 423 // Check immediate superclass equality. |
418 __ ldr(R2, FieldAddress(R1, Class::super_type_offset())); | 424 __ ldr(R2, FieldAddress(R1, Class::super_type_offset())); |
419 __ ldr(R2, FieldAddress(R2, Type::type_class_id_offset())); | 425 __ ldr(R2, FieldAddress(R2, Type::type_class_id_offset())); |
420 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); | 426 __ CompareImmediate(R2, Smi::RawValue(type_class.id())); |
421 __ b(is_instance_lbl, EQ); | 427 __ b(is_instance_lbl, EQ); |
422 | 428 |
423 const Register kTypeArgumentsReg = kNoRegister; | 429 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
430 const Register kFunctionTypeArgumentsReg = kNoRegister; | |
424 const Register kTempReg = kNoRegister; | 431 const Register kTempReg = kNoRegister; |
425 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, | 432 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
426 kTypeArgumentsReg, kTempReg, | 433 kInstantiatorTypeArgumentsReg, |
434 kFunctionTypeArgumentsReg, kTempReg, | |
427 is_instance_lbl, is_not_instance_lbl); | 435 is_instance_lbl, is_not_instance_lbl); |
428 } | 436 } |
429 | 437 |
430 | 438 |
431 // Generates inlined check if 'type' is a type parameter or type itself | 439 // Generates inlined check if 'type' is a type parameter or type itself |
432 // R0: instance (preserved). | 440 // R0: instance (preserved). |
433 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 441 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
434 TokenPosition token_pos, | 442 TokenPosition token_pos, |
435 const AbstractType& type, | 443 const AbstractType& type, |
436 Label* is_instance_lbl, | 444 Label* is_instance_lbl, |
437 Label* is_not_instance_lbl) { | 445 Label* is_not_instance_lbl) { |
438 __ Comment("UninstantiatedTypeTest"); | 446 __ Comment("UninstantiatedTypeTest"); |
439 ASSERT(!type.IsInstantiated()); | 447 ASSERT(!type.IsInstantiated()); |
440 // Skip check if destination is a dynamic type. | 448 // Skip check if destination is a dynamic type. |
441 if (type.IsTypeParameter()) { | 449 if (type.IsTypeParameter()) { |
442 const TypeParameter& type_param = TypeParameter::Cast(type); | 450 const TypeParameter& type_param = TypeParameter::Cast(type); |
443 // Load instantiator type arguments on stack. | 451 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
zra
2017/04/07 17:36:29
Could you use an ldm that doesn't adjust SP?
regis
2017/04/11 04:23:07
I'd prefer now, as I would need to renumber the re
| |
444 __ ldr(R1, Address(SP, 0)); // Get instantiator type arguments. | 452 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
445 // R1: instantiator type arguments. | 453 // R1: instantiator type arguments. |
454 // R2: function type arguments. | |
455 const Register kTypeArgumentsReg = | |
456 type_param.IsClassTypeParameter() ? R1 : R2; | |
446 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 457 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
447 __ CompareObject(R1, Object::null_object()); | 458 __ CompareObject(kTypeArgumentsReg, Object::null_object()); |
448 __ b(is_instance_lbl, EQ); | 459 __ b(is_instance_lbl, EQ); |
449 __ ldr(R2, | 460 __ ldr(R3, FieldAddress(kTypeArgumentsReg, |
450 FieldAddress(R1, TypeArguments::type_at_offset(type_param.index()))); | 461 TypeArguments::type_at_offset(type_param.index()))); |
451 // R2: concrete type of type. | 462 // R3: concrete type of type. |
452 // Check if type argument is dynamic. | 463 // Check if type argument is dynamic. |
453 __ CompareObject(R2, Object::dynamic_type()); | 464 __ CompareObject(R3, Object::dynamic_type()); |
454 __ b(is_instance_lbl, EQ); | 465 __ b(is_instance_lbl, EQ); |
455 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::ObjectType())); | 466 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::ObjectType())); |
456 __ b(is_instance_lbl, EQ); | 467 __ b(is_instance_lbl, EQ); |
468 // TODO(regis): Optimize void type as well once allowed as type argument. | |
457 | 469 |
458 // For Smi check quickly against int and num interfaces. | 470 // For Smi check quickly against int and num interfaces. |
459 Label not_smi; | 471 Label not_smi; |
460 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? | 472 __ tst(R0, Operand(kSmiTagMask)); // Value is Smi? |
461 __ b(¬_smi, NE); | 473 __ b(¬_smi, NE); |
462 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::IntType())); | 474 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::IntType())); |
463 __ b(is_instance_lbl, EQ); | 475 __ b(is_instance_lbl, EQ); |
464 __ CompareObject(R2, Type::ZoneHandle(zone(), Type::Number())); | 476 __ CompareObject(R3, Type::ZoneHandle(zone(), Type::Number())); |
465 __ b(is_instance_lbl, EQ); | 477 __ b(is_instance_lbl, EQ); |
466 // Smi must be handled in runtime. | 478 // Smi must be handled in runtime. |
467 Label fall_through; | 479 Label fall_through; |
468 __ b(&fall_through); | 480 __ b(&fall_through); |
469 | 481 |
470 __ Bind(¬_smi); | 482 __ Bind(¬_smi); |
483 // R0: instance. | |
471 // R1: instantiator type arguments. | 484 // R1: instantiator type arguments. |
472 // R0: instance. | 485 // R2: function type arguments. |
473 const Register kInstanceReg = R0; | 486 const Register kInstanceReg = R0; |
474 const Register kTypeArgumentsReg = R1; | 487 const Register kInstantiatorTypeArgumentsReg = R1; |
488 const Register kFunctionTypeArgumentsReg = R2; | |
475 const Register kTempReg = kNoRegister; | 489 const Register kTempReg = kNoRegister; |
476 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( | 490 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
477 zone(), GenerateCallSubtypeTestStub( | 491 zone(), GenerateCallSubtypeTestStub( |
478 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, | 492 kTestTypeFourArgs, kInstanceReg, |
493 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, | |
479 kTempReg, is_instance_lbl, is_not_instance_lbl)); | 494 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
480 __ Bind(&fall_through); | 495 __ Bind(&fall_through); |
481 return type_test_cache.raw(); | 496 return type_test_cache.raw(); |
482 } | 497 } |
483 if (type.IsType()) { | 498 if (type.IsType()) { |
484 const Register kInstanceReg = R0; | 499 const Register kInstanceReg = R0; |
485 const Register kTypeArgumentsReg = R1; | 500 const Register kInstantiatorTypeArgumentsReg = R1; |
501 const Register kFunctionTypeArgumentsReg = R2; | |
486 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? | 502 __ tst(kInstanceReg, Operand(kSmiTagMask)); // Is instance Smi? |
487 __ b(is_not_instance_lbl, EQ); | 503 __ b(is_not_instance_lbl, EQ); |
488 __ ldr(kTypeArgumentsReg, Address(SP, 0)); // Instantiator type args. | 504 __ ldr(kInstantiatorTypeArgumentsReg, Address(SP, 1 * kWordSize)); |
zra
2017/04/07 17:36:30
ditto if these are adjacent registers.
regis
2017/04/11 04:23:07
ditto
| |
505 __ ldr(kFunctionTypeArgumentsReg, Address(SP, 0 * kWordSize)); | |
489 // Uninstantiated type class is known at compile time, but the type | 506 // Uninstantiated type class is known at compile time, but the type |
490 // arguments are determined at runtime by the instantiator. | 507 // arguments are determined at runtime by the instantiator(s). |
491 const Register kTempReg = kNoRegister; | 508 const Register kTempReg = kNoRegister; |
492 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, | 509 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
493 kTypeArgumentsReg, kTempReg, | 510 kInstantiatorTypeArgumentsReg, |
511 kFunctionTypeArgumentsReg, kTempReg, | |
494 is_instance_lbl, is_not_instance_lbl); | 512 is_instance_lbl, is_not_instance_lbl); |
495 } | 513 } |
496 return SubtypeTestCache::null(); | 514 return SubtypeTestCache::null(); |
497 } | 515 } |
498 | 516 |
499 | 517 |
500 // Inputs: | 518 // Inputs: |
501 // - R0: instance being type checked (preserved). | 519 // - R0: instance being type checked (preserved). |
502 // - R1: optional instantiator type arguments (preserved). | 520 // - R1: optional instantiator type arguments (preserved). |
503 // Clobbers R2, R3. | 521 // - R2: optional function type arguments (preserved). |
522 // Clobbers R3, R4, R8, R9. | |
504 // Returns: | 523 // Returns: |
505 // - preserved instance in R0 and optional instantiator type arguments in R1. | 524 // - preserved instance in R0, optional instantiator type arguments in R1, and |
525 // optional function type arguments in R2. | |
506 // Note that this inlined code must be followed by the runtime_call code, as it | 526 // Note that this inlined code must be followed by the runtime_call code, as it |
507 // may fall through to it. Otherwise, this inline code will jump to the label | 527 // may fall through to it. Otherwise, this inline code will jump to the label |
508 // is_instance or to the label is_not_instance. | 528 // is_instance or to the label is_not_instance. |
509 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 529 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
510 TokenPosition token_pos, | 530 TokenPosition token_pos, |
511 const AbstractType& type, | 531 const AbstractType& type, |
512 Label* is_instance_lbl, | 532 Label* is_instance_lbl, |
513 Label* is_not_instance_lbl) { | 533 Label* is_not_instance_lbl) { |
514 __ Comment("InlineInstanceof"); | 534 __ Comment("InlineInstanceof"); |
515 if (type.IsVoidType()) { | 535 if (type.IsVoidType()) { |
(...skipping 28 matching lines...) Expand all Loading... | |
544 | 564 |
545 | 565 |
546 // If instanceof type test cannot be performed successfully at compile time and | 566 // If instanceof type test cannot be performed successfully at compile time and |
547 // therefore eliminated, optimize it by adding inlined tests for: | 567 // therefore eliminated, optimize it by adding inlined tests for: |
548 // - NULL -> return type == Null (type is not Object or dynamic). | 568 // - NULL -> return type == Null (type is not Object or dynamic). |
549 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 569 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
550 // - Class equality (only if class is not parameterized). | 570 // - Class equality (only if class is not parameterized). |
551 // Inputs: | 571 // Inputs: |
552 // - R0: object. | 572 // - R0: object. |
553 // - R1: instantiator type arguments or raw_null. | 573 // - R1: instantiator type arguments or raw_null. |
574 // - R2: function type arguments or raw_null. | |
554 // Returns: | 575 // Returns: |
555 // - true or false in R0. | 576 // - true or false in R0. |
556 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, | 577 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
557 intptr_t deopt_id, | 578 intptr_t deopt_id, |
558 const AbstractType& type, | 579 const AbstractType& type, |
559 LocationSummary* locs) { | 580 LocationSummary* locs) { |
560 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 581 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
561 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); | 582 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); |
562 | 583 |
563 // Preserve instantiator type arguments (R1). | 584 __ Push(R1); // Store instantiator type arguments. |
zra
2017/04/07 17:36:30
PushList
regis
2017/04/11 04:23:07
Added TODO.
| |
564 __ Push(R1); | 585 __ Push(R2); // Store function type arguments. |
565 | 586 |
566 Label is_instance, is_not_instance; | 587 Label is_instance, is_not_instance; |
567 // If type is instantiated and non-parameterized, we can inline code | 588 // If type is instantiated and non-parameterized, we can inline code |
568 // checking whether the tested instance is a Smi. | 589 // checking whether the tested instance is a Smi. |
569 if (type.IsInstantiated()) { | 590 if (type.IsInstantiated()) { |
570 // A null object is only an instance of Null, Object, and dynamic. | 591 // A null object is only an instance of Null, Object, and dynamic. |
571 // Object and dynamic have already been checked above (if the type is | 592 // Object and dynamic have already been checked above (if the type is |
572 // instantiated). So we can return false here if the instance is null, | 593 // instantiated). So we can return false here if the instance is null, |
573 // unless the type is Null (and if the type is instantiated). | 594 // unless the type is Null (and if the type is instantiated). |
574 // We can only inline this null check if the type is instantiated at compile | 595 // We can only inline this null check if the type is instantiated at compile |
575 // time, since an uninstantiated type at compile time could be Null, Object, | 596 // time, since an uninstantiated type at compile time could be Null, Object, |
576 // or dynamic at run time. | 597 // or dynamic at run time. |
577 __ CompareObject(R0, Object::null_object()); | 598 __ CompareObject(R0, Object::null_object()); |
578 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 599 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
579 } | 600 } |
580 | 601 |
581 // Generate inline instanceof test. | 602 // Generate inline instanceof test. |
582 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 603 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
583 test_cache = | 604 test_cache = |
584 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); | 605 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
585 | 606 |
586 // test_cache is null if there is no fall-through. | 607 // test_cache is null if there is no fall-through. |
587 Label done; | 608 Label done; |
588 if (!test_cache.IsNull()) { | 609 if (!test_cache.IsNull()) { |
589 // Generate runtime call. | 610 // Generate runtime call. |
590 // Load instantiator type arguments (R1). | 611 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
zra
2017/04/07 17:36:30
ldm?
regis
2017/04/11 04:23:07
ditto
| |
591 __ ldr(R1, Address(SP, 0 * kWordSize)); | 612 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
592 __ PushObject(Object::null_object()); // Make room for the result. | 613 __ PushObject(Object::null_object()); // Make room for the result. |
593 __ Push(R0); // Push the instance. | 614 __ Push(R0); // Push the instance. |
594 __ PushObject(type); // Push the type. | 615 __ PushObject(type); // Push the type. |
595 __ Push(R1); // Push instantiator type arguments (R1). | 616 __ Push(R1); // Instantiator type arguments. |
zra
2017/04/07 17:36:30
PushList
regis
2017/04/11 04:23:07
ditto
| |
617 __ Push(R2); // Function type arguments. | |
596 __ LoadUniqueObject(R0, test_cache); | 618 __ LoadUniqueObject(R0, test_cache); |
597 __ Push(R0); | 619 __ Push(R0); |
598 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); | 620 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
599 // Pop the parameters supplied to the runtime entry. The result of the | 621 // Pop the parameters supplied to the runtime entry. The result of the |
600 // instanceof runtime call will be left as the result of the operation. | 622 // instanceof runtime call will be left as the result of the operation. |
601 __ Drop(4); | 623 __ Drop(5); |
602 __ Pop(R0); | 624 __ Pop(R0); |
603 __ b(&done); | 625 __ b(&done); |
604 } | 626 } |
605 __ Bind(&is_not_instance); | 627 __ Bind(&is_not_instance); |
606 __ LoadObject(R0, Bool::Get(false)); | 628 __ LoadObject(R0, Bool::Get(false)); |
607 __ b(&done); | 629 __ b(&done); |
608 | 630 |
609 __ Bind(&is_instance); | 631 __ Bind(&is_instance); |
610 __ LoadObject(R0, Bool::Get(true)); | 632 __ LoadObject(R0, Bool::Get(true)); |
611 __ Bind(&done); | 633 __ Bind(&done); |
612 // Remove instantiator type arguments (R1). | 634 // Remove instantiator type arguments and function type arguments. |
613 __ Drop(1); | 635 __ Drop(2); |
614 } | 636 } |
615 | 637 |
616 | 638 |
617 // Optimize assignable type check by adding inlined tests for: | 639 // Optimize assignable type check by adding inlined tests for: |
618 // - NULL -> return NULL. | 640 // - NULL -> return NULL. |
619 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 641 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
620 // - Class equality (only if class is not parameterized). | 642 // - Class equality (only if class is not parameterized). |
621 // Inputs: | 643 // Inputs: |
622 // - R0: instance being type checked. | 644 // - R0: instance being type checked. |
623 // - R1: instantiator type arguments or raw_null. | 645 // - R1: instantiator type arguments or raw_null. |
646 // - R2: function type arguments or raw_null. | |
624 // Returns: | 647 // Returns: |
625 // - object in R0 for successful assignable check (or throws TypeError). | 648 // - object in R0 for successful assignable check (or throws TypeError). |
626 // Performance notes: positive checks must be quick, negative checks can be slow | 649 // Performance notes: positive checks must be quick, negative checks can be slow |
627 // as they throw an exception. | 650 // as they throw an exception. |
628 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, | 651 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
629 intptr_t deopt_id, | 652 intptr_t deopt_id, |
630 const AbstractType& dst_type, | 653 const AbstractType& dst_type, |
631 const String& dst_name, | 654 const String& dst_name, |
632 LocationSummary* locs) { | 655 LocationSummary* locs) { |
633 ASSERT(!token_pos.IsClassifying()); | 656 ASSERT(!token_pos.IsClassifying()); |
634 ASSERT(!dst_type.IsNull()); | 657 ASSERT(!dst_type.IsNull()); |
635 ASSERT(dst_type.IsFinalized()); | 658 ASSERT(dst_type.IsFinalized()); |
636 // Assignable check is skipped in FlowGraphBuilder, not here. | 659 // Assignable check is skipped in FlowGraphBuilder, not here. |
637 ASSERT(dst_type.IsMalformedOrMalbounded() || | 660 ASSERT(dst_type.IsMalformedOrMalbounded() || |
638 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 661 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
639 // Preserve instantiator type arguments (R1). | 662 __ Push(R1); // Store instantiator type arguments. |
zra
2017/04/07 17:36:29
PushList
regis
2017/04/11 04:23:07
ditto
| |
640 __ Push(R1); | 663 __ Push(R2); // Store function type arguments. |
641 // A null object is always assignable and is returned as result. | 664 // A null object is always assignable and is returned as result. |
642 Label is_assignable, runtime_call; | 665 Label is_assignable, runtime_call; |
643 __ CompareObject(R0, Object::null_object()); | 666 __ CompareObject(R0, Object::null_object()); |
644 __ b(&is_assignable, EQ); | 667 __ b(&is_assignable, EQ); |
645 | 668 |
646 // Generate throw new TypeError() if the type is malformed or malbounded. | 669 // Generate throw new TypeError() if the type is malformed or malbounded. |
647 if (dst_type.IsMalformedOrMalbounded()) { | 670 if (dst_type.IsMalformedOrMalbounded()) { |
648 __ PushObject(Object::null_object()); // Make room for the result. | 671 __ PushObject(Object::null_object()); // Make room for the result. |
649 __ Push(R0); // Push the source object. | 672 __ Push(R0); // Push the source object. |
650 __ PushObject(dst_name); // Push the name of the destination. | 673 __ PushObject(dst_name); // Push the name of the destination. |
651 __ PushObject(dst_type); // Push the type of the destination. | 674 __ PushObject(dst_type); // Push the type of the destination. |
652 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, | 675 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
653 locs); | 676 locs); |
654 // We should never return here. | 677 // We should never return here. |
655 __ bkpt(0); | 678 __ bkpt(0); |
656 | 679 |
657 __ Bind(&is_assignable); // For a null object. | 680 __ Bind(&is_assignable); // For a null object. |
658 // Restore instantiator type arguments (R1). | 681 __ Pop(R2); // Remove pushed function type arguments. |
zra
2017/04/07 17:36:29
PopList
regis
2017/04/11 04:23:07
ditto
| |
659 __ Pop(R1); | 682 __ Pop(R1); // Remove pushed instantiator type arguments. |
660 return; | 683 return; |
661 } | 684 } |
662 | 685 |
663 // Generate inline type check, linking to runtime call if not assignable. | 686 // Generate inline type check, linking to runtime call if not assignable. |
664 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 687 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
665 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, | 688 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
666 &runtime_call); | 689 &runtime_call); |
667 | 690 |
668 __ Bind(&runtime_call); | 691 __ Bind(&runtime_call); |
669 // Load instantiator type arguments (R1). | 692 __ ldr(R1, Address(SP, 1 * kWordSize)); // Get instantiator type args. |
zra
2017/04/07 17:36:29
ldm?
regis
2017/04/11 04:23:07
ditto
| |
670 __ ldr(R1, Address(SP, 0 * kWordSize)); | 693 __ ldr(R2, Address(SP, 0 * kWordSize)); // Get function type args. |
671 __ PushObject(Object::null_object()); // Make room for the result. | 694 __ PushObject(Object::null_object()); // Make room for the result. |
672 __ Push(R0); // Push the source object. | 695 __ Push(R0); // Push the source object. |
673 __ PushObject(dst_type); // Push the type of the destination. | 696 __ PushObject(dst_type); // Push the type of the destination. |
674 __ Push(R1); // Push instantiator type arguments (R1). | 697 __ Push(R1); // Instantiator type arguments. |
zra
2017/04/07 17:36:30
PushList
regis
2017/04/11 04:23:07
ditto
| |
675 __ PushObject(dst_name); // Push the name of the destination. | 698 __ Push(R2); // Function type arguments. |
699 __ PushObject(dst_name); // Push the name of the destination. | |
676 __ LoadUniqueObject(R0, test_cache); | 700 __ LoadUniqueObject(R0, test_cache); |
677 __ Push(R0); | 701 __ Push(R0); |
678 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 702 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
679 // Pop the parameters supplied to the runtime entry. The result of the | 703 // Pop the parameters supplied to the runtime entry. The result of the |
680 // type check runtime call is the checked value. | 704 // type check runtime call is the checked value. |
681 __ Drop(5); | 705 __ Drop(6); |
682 __ Pop(R0); | 706 __ Pop(R0); |
683 | 707 |
684 __ Bind(&is_assignable); | 708 __ Bind(&is_assignable); |
685 // Restore instantiator type arguments (R1). | 709 __ Pop(R2); // Remove pushed function type arguments. |
zra
2017/04/07 17:36:30
PopList
regis
2017/04/11 04:23:07
ditto
| |
686 __ Pop(R1); | 710 __ Pop(R1); // Remove pushed instantiator type arguments. |
687 } | 711 } |
688 | 712 |
689 | 713 |
690 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 714 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
691 if (is_optimizing()) { | 715 if (is_optimizing()) { |
692 return; | 716 return; |
693 } | 717 } |
694 Definition* defn = instr->AsDefinition(); | 718 Definition* defn = instr->AsDefinition(); |
695 if ((defn != NULL) && defn->HasTemp()) { | 719 if ((defn != NULL) && defn->HasTemp()) { |
696 __ Push(defn->locs()->out(0).reg()); | 720 __ Push(defn->locs()->out(0).reg()); |
(...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1889 DRegister dreg = EvenDRegisterOf(reg); | 1913 DRegister dreg = EvenDRegisterOf(reg); |
1890 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1914 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
1891 } | 1915 } |
1892 | 1916 |
1893 | 1917 |
1894 #undef __ | 1918 #undef __ |
1895 | 1919 |
1896 } // namespace dart | 1920 } // namespace dart |
1897 | 1921 |
1898 #endif // defined TARGET_ARCH_ARM | 1922 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |