OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
7 | 7 |
8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
9 | 9 |
10 #include "lib/error.h" | 10 #include "lib/error.h" |
11 #include "vm/ast_printer.h" | 11 #include "vm/ast_printer.h" |
12 #include "vm/compiler_stats.h" | 12 #include "vm/compiler_stats.h" |
13 #include "vm/il_printer.h" | 13 #include "vm/il_printer.h" |
14 #include "vm/locations.h" | 14 #include "vm/locations.h" |
| 15 #include "vm/object_store.h" |
15 #include "vm/stub_code.h" | 16 #include "vm/stub_code.h" |
16 | 17 |
17 namespace dart { | 18 namespace dart { |
18 | 19 |
19 DECLARE_FLAG(bool, code_comments); | 20 DECLARE_FLAG(bool, code_comments); |
20 DECLARE_FLAG(bool, compiler_stats); | 21 DECLARE_FLAG(bool, compiler_stats); |
21 DECLARE_FLAG(bool, enable_type_checks); | 22 DECLARE_FLAG(bool, enable_type_checks); |
22 DECLARE_FLAG(bool, print_ast); | 23 DECLARE_FLAG(bool, print_ast); |
23 DECLARE_FLAG(bool, print_scopes); | 24 DECLARE_FLAG(bool, print_scopes); |
24 DECLARE_FLAG(bool, trace_functions); | 25 DECLARE_FLAG(bool, trace_functions); |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
402 | 403 |
403 void FlowGraphCompiler::GenerateCall(intptr_t token_index, | 404 void FlowGraphCompiler::GenerateCall(intptr_t token_index, |
404 intptr_t try_index, | 405 intptr_t try_index, |
405 const ExternalLabel* label, | 406 const ExternalLabel* label, |
406 PcDescriptors::Kind kind) { | 407 PcDescriptors::Kind kind) { |
407 __ call(label); | 408 __ call(label); |
408 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); | 409 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); |
409 } | 410 } |
410 | 411 |
411 | 412 |
| 413 // Fall through if bool_register contains null. |
| 414 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| 415 Label* is_true, |
| 416 Label* is_false) { |
| 417 const Immediate raw_null = |
| 418 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 419 Label fall_through; |
| 420 __ cmpl(bool_register, raw_null); |
| 421 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 422 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 423 __ CompareObject(bool_register, bool_true); |
| 424 __ j(EQUAL, is_true); |
| 425 __ jmp(is_false); |
| 426 __ Bind(&fall_through); |
| 427 } |
| 428 |
| 429 |
| 430 // Clobbers ECX. |
| 431 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 432 TypeTestStubKind test_kind, |
| 433 Register instance_reg, |
| 434 Register type_arguments_reg, |
| 435 Register temp_reg, |
| 436 Label* is_instance_lbl, |
| 437 Label* is_not_instance_lbl) { |
| 438 const SubtypeTestCache& type_test_cache = |
| 439 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 440 const Immediate raw_null = |
| 441 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 442 __ LoadObject(temp_reg, type_test_cache); |
| 443 __ pushl(temp_reg); // Subtype test cache. |
| 444 __ pushl(instance_reg); // Instance. |
| 445 if (test_kind == kTestTypeOneArg) { |
| 446 ASSERT(type_arguments_reg == kNoRegister); |
| 447 __ pushl(raw_null); |
| 448 __ call(&StubCode::Subtype1TestCacheLabel()); |
| 449 } else if (test_kind == kTestTypeTwoArgs) { |
| 450 ASSERT(type_arguments_reg == kNoRegister); |
| 451 __ pushl(raw_null); |
| 452 __ call(&StubCode::Subtype2TestCacheLabel()); |
| 453 } else if (test_kind == kTestTypeThreeArgs) { |
| 454 __ pushl(type_arguments_reg); |
| 455 __ call(&StubCode::Subtype3TestCacheLabel()); |
| 456 } else { |
| 457 UNREACHABLE(); |
| 458 } |
| 459 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 460 ASSERT(instance_reg != ECX); |
| 461 ASSERT(temp_reg != ECX); |
| 462 __ popl(instance_reg); // Discard. |
| 463 __ popl(instance_reg); // Restore receiver. |
| 464 __ popl(temp_reg); // Discard. |
| 465 GenerateBoolToJump(ECX, is_instance_lbl, is_not_instance_lbl); |
| 466 return type_test_cache.raw(); |
| 467 } |
| 468 |
| 469 |
| 470 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 471 // type test is conclusive, otherwise fallthrough if a type test could not |
| 472 // be completed. |
| 473 // EAX: instance (must survive), clobbers ECX, EDI |
| 474 RawSubtypeTestCache* |
| 475 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| 476 intptr_t cid, |
| 477 intptr_t token_index, |
| 478 const AbstractType& type, |
| 479 Label* is_instance_lbl, |
| 480 Label* is_not_instance_lbl) { |
| 481 ASSERT(type.IsInstantiated()); |
| 482 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 483 ASSERT(type_class.HasTypeArguments()); |
| 484 const Register kInstanceReg = EAX; |
| 485 // A Smi object cannot be the instance of a parameterized class. |
| 486 __ testl(kInstanceReg, Immediate(kSmiTagMask)); |
| 487 __ j(ZERO, is_not_instance_lbl); |
| 488 const AbstractTypeArguments& type_arguments = |
| 489 AbstractTypeArguments::ZoneHandle(type.arguments()); |
| 490 const bool is_raw_type = type_arguments.IsNull() || |
| 491 type_arguments.IsRaw(type_arguments.Length()); |
| 492 if (is_raw_type) { |
| 493 const Register kClassIdReg = ECX; |
| 494 // Dynamic type argument, check only classes. |
| 495 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 496 if (!type_class.is_interface()) { |
| 497 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
| 498 __ j(EQUAL, is_instance_lbl); |
| 499 } |
| 500 if (type.IsListInterface()) { |
| 501 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
| 502 } |
| 503 return GenerateSubtype1TestCacheLookup( |
| 504 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); |
| 505 } |
| 506 // If one type argument only, check if type argument is Object or Dynamic. |
| 507 if (type_arguments.Length() == 1) { |
| 508 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| 509 type_arguments.TypeAt(0)); |
| 510 ASSERT(!tp_argument.IsMalformed()); |
| 511 if (tp_argument.IsType()) { |
| 512 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 513 // Check if type argument is dynamic or Object. |
| 514 const Type& object_type = |
| 515 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 516 Error& malformed_error = Error::Handle(); |
| 517 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { |
| 518 // Instance class test only necessary. |
| 519 return GenerateSubtype1TestCacheLookup( |
| 520 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); |
| 521 } |
| 522 } |
| 523 } |
| 524 // Regular subtype test cache involving instance's type arguments. |
| 525 const Register kTypeArgumentsReg = kNoRegister; |
| 526 const Register kTempReg = EDI; |
| 527 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, |
| 528 kInstanceReg, |
| 529 kTypeArgumentsReg, |
| 530 kTempReg, |
| 531 is_instance_lbl, |
| 532 is_not_instance_lbl); |
| 533 } |
| 534 |
| 535 |
| 536 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
| 537 const GrowableArray<intptr_t>& class_ids, |
| 538 Label* is_equal_lbl, |
| 539 Label* is_not_equal_lbl) { |
| 540 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 541 __ cmpl(class_id_reg, Immediate(class_ids[i])); |
| 542 __ j(EQUAL, is_equal_lbl); |
| 543 } |
| 544 __ jmp(is_not_equal_lbl); |
| 545 } |
| 546 |
| 547 |
| 548 // Testing against an instantiated type with no arguments, without |
| 549 // SubtypeTestCache. |
| 550 // EAX: instance to test against (preserved). Clobbers ECX, EDI. |
| 551 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 552 intptr_t cid, |
| 553 intptr_t token_index, |
| 554 const AbstractType& type, |
| 555 Label* is_instance_lbl, |
| 556 Label* is_not_instance_lbl) { |
| 557 ASSERT(type.IsInstantiated()); |
| 558 const Class& type_class = Class::Handle(type.type_class()); |
| 559 ASSERT(!type_class.HasTypeArguments()); |
| 560 |
| 561 const Register kInstanceReg = EAX; |
| 562 Label compare_classes; |
| 563 __ testl(kInstanceReg, Immediate(kSmiTagMask)); |
| 564 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 565 // Instance is Smi, check directly. |
| 566 const Class& smi_class = Class::Handle(Smi::Class()); |
| 567 // TODO(regis): We should introduce a SmiType. |
| 568 Error& malformed_error = Error::Handle(); |
| 569 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 570 type_class, |
| 571 TypeArguments::Handle(), |
| 572 &malformed_error)) { |
| 573 __ jmp(is_instance_lbl); |
| 574 } else { |
| 575 __ jmp(is_not_instance_lbl); |
| 576 } |
| 577 // Compare if the classes are equal. |
| 578 __ Bind(&compare_classes); |
| 579 const Register kClassIdReg = ECX; |
| 580 __ LoadClassId(kClassIdReg, kInstanceReg); |
| 581 // If type is an interface, we can skip the class equality check. |
| 582 if (!type_class.is_interface()) { |
| 583 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
| 584 __ j(EQUAL, is_instance_lbl); |
| 585 } |
| 586 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces). |
| 587 // Bool interface can be implemented only by core class Bool. |
| 588 if (type.IsBoolInterface()) { |
| 589 __ cmpl(kClassIdReg, Immediate(kBool)); |
| 590 __ j(EQUAL, is_instance_lbl); |
| 591 __ jmp(is_not_instance_lbl); |
| 592 return; |
| 593 } |
| 594 if (type.IsFunctionInterface()) { |
| 595 // Check if instance is a closure. |
| 596 const Immediate raw_null = |
| 597 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 598 __ LoadClassById(EDI, kClassIdReg); |
| 599 __ movl(EDI, FieldAddress(EDI, Class::signature_function_offset())); |
| 600 __ cmpl(EDI, raw_null); |
| 601 __ j(NOT_EQUAL, is_instance_lbl); |
| 602 __ jmp(is_not_instance_lbl); |
| 603 return; |
| 604 } |
| 605 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 606 // Note that instance is not Smi(checked above). |
| 607 if (type.IsSubtypeOf( |
| 608 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 609 GenerateNumberTypeCheck( |
| 610 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 611 return; |
| 612 } |
| 613 if (type.IsStringInterface()) { |
| 614 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| 615 return; |
| 616 } |
| 617 } |
| 618 |
| 619 |
| 620 // Generates inlined check if 'type' is a type parameter or type itsef |
| 621 // EAX: instance (preserved). Clobbers EDX, EDI, ECX. |
| 622 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 623 intptr_t cid, |
| 624 intptr_t token_index, |
| 625 const AbstractType& type, |
| 626 Label* is_instance_lbl, |
| 627 Label* is_not_instance_lbl) { |
| 628 ASSERT(!type.IsInstantiated()); |
| 629 // Skip check if destination is a dynamic type. |
| 630 const Immediate raw_null = |
| 631 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 632 if (type.IsTypeParameter()) { |
| 633 // Load instantiator (or null) and instantiator type arguments on stack. |
| 634 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 635 // EDX: instantiator type arguments. |
| 636 // Check if type argument is Dynamic. |
| 637 __ cmpl(EDX, raw_null); |
| 638 __ j(EQUAL, is_instance_lbl); |
| 639 // Can handle only type arguments that are instances of TypeArguments. |
| 640 // (runtime checks canonicalize type arguments). |
| 641 Label fall_through; |
| 642 __ CompareClassId(EDX, kTypeArguments, EDI); |
| 643 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 644 |
| 645 __ movl(EDI, |
| 646 FieldAddress(EDX, TypeArguments::type_at_offset(type.Index()))); |
| 647 // EDI: concrete type of type. |
| 648 // Check if type argument is dynamic. |
| 649 __ CompareObject(EDI, Type::ZoneHandle(Type::DynamicType())); |
| 650 __ j(EQUAL, is_instance_lbl); |
| 651 __ cmpl(EDI, raw_null); |
| 652 __ j(EQUAL, is_instance_lbl); |
| 653 const Type& object_type = |
| 654 Type::ZoneHandle(Isolate::Current()->object_store()->object_type()); |
| 655 __ CompareObject(EDI, object_type); |
| 656 __ j(EQUAL, is_instance_lbl); |
| 657 |
| 658 // For Smi check quickly against int and num interfaces. |
| 659 Label not_smi; |
| 660 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 661 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 662 __ CompareObject(EDI, Type::ZoneHandle(Type::IntInterface())); |
| 663 __ j(EQUAL, is_instance_lbl); |
| 664 __ CompareObject(EDI, Type::ZoneHandle(Type::NumberInterface())); |
| 665 __ j(EQUAL, is_instance_lbl); |
| 666 // Smi must be handled in runtime. |
| 667 __ jmp(&fall_through); |
| 668 |
| 669 __ Bind(¬_smi); |
| 670 // EDX: instantiator type arguments. |
| 671 // EAX: instance. |
| 672 const Register kInstanceReg = EAX; |
| 673 const Register kTypeArgumentsReg = EDX; |
| 674 const Register kTempReg = EDI; |
| 675 const SubtypeTestCache& type_test_cache = |
| 676 SubtypeTestCache::ZoneHandle( |
| 677 GenerateCallSubtypeTestStub(kTestTypeThreeArgs, |
| 678 kInstanceReg, |
| 679 kTypeArgumentsReg, |
| 680 kTempReg, |
| 681 is_instance_lbl, |
| 682 is_not_instance_lbl)); |
| 683 __ Bind(&fall_through); |
| 684 return type_test_cache.raw(); |
| 685 } |
| 686 if (type.IsType()) { |
| 687 const Register kInstanceReg = EAX; |
| 688 const Register kTypeArgumentsReg = EDX; |
| 689 __ testl(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? |
| 690 __ j(ZERO, is_not_instance_lbl); |
| 691 __ movl(kTypeArgumentsReg, Address(ESP, 0)); // Instantiator type args. |
| 692 // Uninstantiated type class is known at compile time, but the type |
| 693 // arguments are determined at runtime by the instantiator. |
| 694 const Register kTempReg = EDI; |
| 695 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, |
| 696 kInstanceReg, |
| 697 kTypeArgumentsReg, |
| 698 kTempReg, |
| 699 is_instance_lbl, |
| 700 is_not_instance_lbl); |
| 701 } |
| 702 return SubtypeTestCache::null(); |
| 703 } |
| 704 |
| 705 |
| 706 // Uses SubtypeTestCache to store instance class and result. |
| 707 // EAX: instance to test. Clobbers EDI, ECX. |
| 708 // Immediate class test already done. |
| 709 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 710 // arrays can grow too high, but they may be useful when optimizing |
| 711 // code (type-feedback). |
| 712 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
| 713 intptr_t cid, |
| 714 intptr_t token_index, |
| 715 const Class& type_class, |
| 716 Label* is_instance_lbl, |
| 717 Label* is_not_instance_lbl) { |
| 718 const Register kInstanceReg = EAX; |
| 719 __ LoadClass(ECX, kInstanceReg, EDI); |
| 720 // ECX: instance class. |
| 721 // Check immediate superclass equality. |
| 722 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
| 723 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
| 724 __ CompareObject(EDI, type_class); |
| 725 __ j(EQUAL, is_instance_lbl); |
| 726 |
| 727 const Register kTypeArgumentsReg = kNoRegister; |
| 728 const Register kTempReg = EDI; |
| 729 return GenerateCallSubtypeTestStub(kTestTypeOneArg, |
| 730 kInstanceReg, |
| 731 kTypeArgumentsReg, |
| 732 kTempReg, |
| 733 is_instance_lbl, |
| 734 is_not_instance_lbl); |
| 735 } |
| 736 |
| 737 |
| 738 // Inputs: |
| 739 // - EAX: instance to test against (preserved). |
| 740 // - EDX: optional instantiator type arguments (preserved). |
| 741 // Returns: |
| 742 // - preserved instance in EAX and optional instantiator type arguments in EDX. |
| 743 // Note that this inlined code must be followed by the runtime_call code, as it |
| 744 // may fall through to it. Otherwise, this inline code will jump to the label |
| 745 // is_instance or to the label is_not_instance. |
| 746 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
| 747 intptr_t cid, |
| 748 intptr_t token_index, |
| 749 const AbstractType& type, |
| 750 Label* is_instance_lbl, |
| 751 Label* is_not_instance_lbl) { |
| 752 if (type.IsInstantiated()) { |
| 753 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 754 // A Smi object cannot be the instance of a parameterized class. |
| 755 // A class equality check is only applicable with a dst type of a |
| 756 // non-parameterized class or with a raw dst type of a parameterized class. |
| 757 if (type_class.HasTypeArguments()) { |
| 758 return GenerateInstantiatedTypeWithArgumentsTest(cid, |
| 759 token_index, |
| 760 type, |
| 761 is_instance_lbl, |
| 762 is_not_instance_lbl); |
| 763 // Fall through to runtime call. |
| 764 } else { |
| 765 GenerateInstantiatedTypeNoArgumentsTest(cid, |
| 766 token_index, |
| 767 type, |
| 768 is_instance_lbl, |
| 769 is_not_instance_lbl); |
| 770 // If test non-conclusive so far, try the inlined type-test cache. |
| 771 // 'type' is known at compile time. |
| 772 return GenerateSubtype1TestCacheLookup( |
| 773 cid, token_index, type_class, |
| 774 is_instance_lbl, is_not_instance_lbl); |
| 775 } |
| 776 } else { |
| 777 return GenerateUninstantiatedTypeTest(cid, |
| 778 token_index, |
| 779 type, |
| 780 is_instance_lbl, |
| 781 is_not_instance_lbl); |
| 782 } |
| 783 return SubtypeTestCache::null(); |
| 784 } |
| 785 |
| 786 |
412 // If instanceof type test cannot be performed successfully at compile time and | 787 // If instanceof type test cannot be performed successfully at compile time and |
413 // therefore eliminated, optimize it by adding inlined tests for: | 788 // therefore eliminated, optimize it by adding inlined tests for: |
414 // - NULL -> return false. | 789 // - NULL -> return false. |
415 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 790 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
416 // - Class equality (only if class is not parameterized). | 791 // - Class equality (only if class is not parameterized). |
417 // Inputs: | 792 // Inputs: |
418 // - EAX: object. | 793 // - EAX: object. |
419 // - EDX: instantiator type arguments or raw_null. | 794 // - EDX: instantiator type arguments or raw_null. |
420 // - ECX: instantiator or raw_null. | 795 // - ECX: instantiator or raw_null. |
421 // Returns: | 796 // Returns: |
(...skipping 21 matching lines...) Expand all Loading... |
443 // instantiated). | 818 // instantiated). |
444 // We can only inline this null check if the type is instantiated at compile | 819 // We can only inline this null check if the type is instantiated at compile |
445 // time, since an uninstantiated type at compile time could be Object or | 820 // time, since an uninstantiated type at compile time could be Object or |
446 // Dynamic at run time. | 821 // Dynamic at run time. |
447 __ cmpl(EAX, raw_null); | 822 __ cmpl(EAX, raw_null); |
448 __ j(EQUAL, &is_not_instance); | 823 __ j(EQUAL, &is_not_instance); |
449 } | 824 } |
450 // TODO(srdjan): Enable inlined checks. | 825 // TODO(srdjan): Enable inlined checks. |
451 // Generate inline instanceof test. | 826 // Generate inline instanceof test. |
452 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 827 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
453 // test_cache = GenerateInlineInstanceof(cid, token_index, type, | 828 test_cache = GenerateInlineInstanceof(cid, token_index, type, |
454 // &is_instance, &is_not_instance); | 829 &is_instance, &is_not_instance); |
455 | 830 |
456 // Generate runtime call. | 831 // Generate runtime call. |
457 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 832 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
458 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 833 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
459 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 834 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
460 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 835 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
461 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. | 836 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. |
462 __ pushl(EAX); // Push the instance. | 837 __ pushl(EAX); // Push the instance. |
463 __ PushObject(type); // Push the type. | 838 __ PushObject(type); // Push the type. |
464 __ pushl(ECX); // TODO(srdjan): Pass instantiator instead of null. | 839 __ pushl(ECX); // TODO(srdjan): Pass instantiator instead of null. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
544 // We should never return here. | 919 // We should never return here. |
545 __ int3(); | 920 __ int3(); |
546 | 921 |
547 __ Bind(&is_assignable); // For a null object. | 922 __ Bind(&is_assignable); // For a null object. |
548 return; | 923 return; |
549 } | 924 } |
550 | 925 |
551 // TODO(srdjan): Enable subtype test cache. | 926 // TODO(srdjan): Enable subtype test cache. |
552 // Generate inline type check, linking to runtime call if not assignable. | 927 // Generate inline type check, linking to runtime call if not assignable. |
553 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 928 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
554 // test_cache = GenerateInlineInstanceof(cid, token_index, dst_type, | 929 test_cache = GenerateInlineInstanceof(cid, token_index, dst_type, |
555 // &is_assignable, &runtime_call); | 930 &is_assignable, &runtime_call); |
556 | 931 |
557 __ Bind(&runtime_call); | 932 __ Bind(&runtime_call); |
558 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 933 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
559 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 934 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
560 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 935 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
561 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 936 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
562 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. | 937 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. |
563 __ pushl(EAX); // Push the source object. | 938 __ pushl(EAX); // Push the source object. |
564 __ PushObject(dst_type); // Push the type of the destination. | 939 __ PushObject(dst_type); // Push the type of the destination. |
565 __ pushl(ECX); // Instantiator. | 940 __ pushl(ECX); // Instantiator. |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 } | 1017 } |
643 } | 1018 } |
644 } | 1019 } |
645 } | 1020 } |
646 | 1021 |
647 #undef __ | 1022 #undef __ |
648 | 1023 |
649 } // namespace dart | 1024 } // namespace dart |
650 | 1025 |
651 #endif // defined TARGET_ARCH_IA32 | 1026 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |