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