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" |
(...skipping 20 matching lines...) Expand all Loading... |
31 __ Bind(entry_label()); | 31 __ Bind(entry_label()); |
32 for (intptr_t i = 0; i < registers_.length(); i++) { | 32 for (intptr_t i = 0; i < registers_.length(); i++) { |
33 if (registers_[i] != kNoRegister) { | 33 if (registers_[i] != kNoRegister) { |
34 __ pushl(registers_[i]); | 34 __ pushl(registers_[i]); |
35 } | 35 } |
36 } | 36 } |
37 __ movl(EAX, Immediate(Smi::RawValue(reason_))); | 37 __ movl(EAX, Immediate(Smi::RawValue(reason_))); |
38 __ call(&StubCode::DeoptimizeLabel()); | 38 __ call(&StubCode::DeoptimizeLabel()); |
39 compiler->AddCurrentDescriptor(PcDescriptors::kOther, | 39 compiler->AddCurrentDescriptor(PcDescriptors::kOther, |
40 deopt_id_, | 40 deopt_id_, |
41 deopt_token_index_, | 41 deopt_token_pos_, |
42 try_index_); | 42 try_index_); |
43 #undef __ | 43 #undef __ |
44 } | 44 } |
45 | 45 |
46 | 46 |
47 | 47 |
48 #define __ assembler()-> | 48 #define __ assembler()-> |
49 | 49 |
50 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 50 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
51 // TOS: return address. | 51 // TOS: return address. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 __ Drop(1); | 89 __ Drop(1); |
90 __ jmp(done); | 90 __ jmp(done); |
91 __ Bind(&smi_to_double); | 91 __ Bind(&smi_to_double); |
92 __ SmiUntag(EAX); | 92 __ SmiUntag(EAX); |
93 __ cvtsi2sd(XMM1, EAX); | 93 __ cvtsi2sd(XMM1, EAX); |
94 __ jmp(&double_op); | 94 __ jmp(&double_op); |
95 __ Bind(&call_method); | 95 __ Bind(&call_method); |
96 } | 96 } |
97 | 97 |
98 | 98 |
99 void FlowGraphCompiler::GenerateCall(intptr_t token_index, | 99 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
100 intptr_t try_index, | 100 intptr_t try_index, |
101 const ExternalLabel* label, | 101 const ExternalLabel* label, |
102 PcDescriptors::Kind kind) { | 102 PcDescriptors::Kind kind) { |
103 ASSERT(frame_register_allocator()->IsSpilled()); | 103 ASSERT(frame_register_allocator()->IsSpilled()); |
104 __ call(label); | 104 __ call(label); |
105 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); | 105 AddCurrentDescriptor(kind, AstNode::kNoId, token_pos, try_index); |
106 } | 106 } |
107 | 107 |
108 | 108 |
109 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, | 109 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, |
110 intptr_t token_index, | 110 intptr_t token_pos, |
111 intptr_t try_index, | 111 intptr_t try_index, |
112 const RuntimeEntry& entry) { | 112 const RuntimeEntry& entry) { |
113 ASSERT(frame_register_allocator()->IsSpilled()); | 113 ASSERT(frame_register_allocator()->IsSpilled()); |
114 __ CallRuntime(entry); | 114 __ CallRuntime(entry); |
115 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index); | 115 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_pos, try_index); |
116 } | 116 } |
117 | 117 |
118 | 118 |
119 void FlowGraphCompiler::CopyParameters() { | 119 void FlowGraphCompiler::CopyParameters() { |
120 const Function& function = parsed_function().function(); | 120 const Function& function = parsed_function().function(); |
121 const bool is_native_instance_closure = | 121 const bool is_native_instance_closure = |
122 function.is_native() && function.IsImplicitInstanceClosureFunction(); | 122 function.is_native() && function.IsImplicitInstanceClosureFunction(); |
123 LocalScope* scope = parsed_function().node_sequence()->scope(); | 123 LocalScope* scope = parsed_function().node_sequence()->scope(); |
124 const int num_fixed_params = function.num_fixed_parameters(); | 124 const int num_fixed_params = function.num_fixed_parameters(); |
125 const int num_opt_params = function.num_optional_parameters(); | 125 const int num_opt_params = function.num_optional_parameters(); |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 #endif | 349 #endif |
350 if (check_arguments) { | 350 if (check_arguments) { |
351 // Check that num_fixed <= argc <= num_params. | 351 // Check that num_fixed <= argc <= num_params. |
352 Label argc_in_range; | 352 Label argc_in_range; |
353 // Total number of args is the first Smi in args descriptor array (EDX). | 353 // Total number of args is the first Smi in args descriptor array (EDX). |
354 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); | 354 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); |
355 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count))); | 355 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count))); |
356 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 356 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
357 if (function.IsClosureFunction()) { | 357 if (function.IsClosureFunction()) { |
358 GenerateCallRuntime(AstNode::kNoId, | 358 GenerateCallRuntime(AstNode::kNoId, |
359 function.token_index(), | 359 function.token_pos(), |
360 CatchClauseNode::kInvalidTryIndex, | 360 CatchClauseNode::kInvalidTryIndex, |
361 kClosureArgumentMismatchRuntimeEntry); | 361 kClosureArgumentMismatchRuntimeEntry); |
362 } else { | 362 } else { |
363 __ Stop("Wrong number of arguments"); | 363 __ Stop("Wrong number of arguments"); |
364 } | 364 } |
365 __ Bind(&argc_in_range); | 365 __ Bind(&argc_in_range); |
366 } | 366 } |
367 } else { | 367 } else { |
368 CopyParameters(); | 368 CopyParameters(); |
369 } | 369 } |
370 // Initialize (non-argument) stack allocated locals to null. | 370 // Initialize (non-argument) stack allocated locals to null. |
371 if (local_count > 0) { | 371 if (local_count > 0) { |
372 const Immediate raw_null = | 372 const Immediate raw_null = |
373 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 373 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
374 __ movl(EAX, raw_null); | 374 __ movl(EAX, raw_null); |
375 const int base = parsed_function().first_stack_local_index(); | 375 const int base = parsed_function().first_stack_local_index(); |
376 for (int i = 0; i < local_count; ++i) { | 376 for (int i = 0; i < local_count; ++i) { |
377 // Subtract index i (locals lie at lower addresses than EBP). | 377 // Subtract index i (locals lie at lower addresses than EBP). |
378 __ movl(Address(EBP, (base - i) * kWordSize), EAX); | 378 __ movl(Address(EBP, (base - i) * kWordSize), EAX); |
379 } | 379 } |
380 } | 380 } |
381 | 381 |
382 // Generate stack overflow check. | 382 // Generate stack overflow check. |
383 __ cmpl(ESP, | 383 __ cmpl(ESP, |
384 Address::Absolute(Isolate::Current()->stack_limit_address())); | 384 Address::Absolute(Isolate::Current()->stack_limit_address())); |
385 Label no_stack_overflow; | 385 Label no_stack_overflow; |
386 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); | 386 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); |
387 GenerateCallRuntime(AstNode::kNoId, | 387 GenerateCallRuntime(AstNode::kNoId, |
388 function.token_index(), | 388 function.token_pos(), |
389 CatchClauseNode::kInvalidTryIndex, | 389 CatchClauseNode::kInvalidTryIndex, |
390 kStackOverflowRuntimeEntry); | 390 kStackOverflowRuntimeEntry); |
391 __ Bind(&no_stack_overflow); | 391 __ Bind(&no_stack_overflow); |
392 | 392 |
393 if (FLAG_print_scopes) { | 393 if (FLAG_print_scopes) { |
394 // Print the function scope (again) after generating the prologue in order | 394 // Print the function scope (again) after generating the prologue in order |
395 // to see annotations such as allocation indices of locals. | 395 // to see annotations such as allocation indices of locals. |
396 if (FLAG_print_ast) { | 396 if (FLAG_print_ast) { |
397 // Second printing. | 397 // Second printing. |
398 OS::Print("Annotated "); | 398 OS::Print("Annotated "); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 } | 497 } |
498 | 498 |
499 | 499 |
500 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 500 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
501 // type test is conclusive, otherwise fallthrough if a type test could not | 501 // type test is conclusive, otherwise fallthrough if a type test could not |
502 // be completed. | 502 // be completed. |
503 // EAX: instance (must survive), clobbers ECX, EDI | 503 // EAX: instance (must survive), clobbers ECX, EDI |
504 RawSubtypeTestCache* | 504 RawSubtypeTestCache* |
505 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( | 505 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
506 intptr_t cid, | 506 intptr_t cid, |
507 intptr_t token_index, | 507 intptr_t token_pos, |
508 const AbstractType& type, | 508 const AbstractType& type, |
509 Label* is_instance_lbl, | 509 Label* is_instance_lbl, |
510 Label* is_not_instance_lbl) { | 510 Label* is_not_instance_lbl) { |
511 ASSERT(type.IsInstantiated()); | 511 ASSERT(type.IsInstantiated()); |
512 const Class& type_class = Class::ZoneHandle(type.type_class()); | 512 const Class& type_class = Class::ZoneHandle(type.type_class()); |
513 ASSERT(type_class.HasTypeArguments()); | 513 ASSERT(type_class.HasTypeArguments()); |
514 const Register kInstanceReg = EAX; | 514 const Register kInstanceReg = EAX; |
515 // A Smi object cannot be the instance of a parameterized class. | 515 // A Smi object cannot be the instance of a parameterized class. |
516 __ testl(kInstanceReg, Immediate(kSmiTagMask)); | 516 __ testl(kInstanceReg, Immediate(kSmiTagMask)); |
517 __ j(ZERO, is_not_instance_lbl); | 517 __ j(ZERO, is_not_instance_lbl); |
518 const AbstractTypeArguments& type_arguments = | 518 const AbstractTypeArguments& type_arguments = |
519 AbstractTypeArguments::ZoneHandle(type.arguments()); | 519 AbstractTypeArguments::ZoneHandle(type.arguments()); |
520 const bool is_raw_type = type_arguments.IsNull() || | 520 const bool is_raw_type = type_arguments.IsNull() || |
521 type_arguments.IsRaw(type_arguments.Length()); | 521 type_arguments.IsRaw(type_arguments.Length()); |
522 if (is_raw_type) { | 522 if (is_raw_type) { |
523 const Register kClassIdReg = ECX; | 523 const Register kClassIdReg = ECX; |
524 // Dynamic type argument, check only classes. | 524 // Dynamic type argument, check only classes. |
525 __ LoadClassId(kClassIdReg, kInstanceReg); | 525 __ LoadClassId(kClassIdReg, kInstanceReg); |
526 if (!type_class.is_interface()) { | 526 if (!type_class.is_interface()) { |
527 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 527 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
528 __ j(EQUAL, is_instance_lbl); | 528 __ j(EQUAL, is_instance_lbl); |
529 } | 529 } |
530 if (type.IsListInterface()) { | 530 if (type.IsListInterface()) { |
531 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); | 531 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); |
532 } | 532 } |
533 return GenerateSubtype1TestCacheLookup( | 533 return GenerateSubtype1TestCacheLookup( |
534 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); | 534 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
535 } | 535 } |
536 // If one type argument only, check if type argument is Object or Dynamic. | 536 // If one type argument only, check if type argument is Object or Dynamic. |
537 if (type_arguments.Length() == 1) { | 537 if (type_arguments.Length() == 1) { |
538 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 538 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
539 type_arguments.TypeAt(0)); | 539 type_arguments.TypeAt(0)); |
540 ASSERT(!tp_argument.IsMalformed()); | 540 ASSERT(!tp_argument.IsMalformed()); |
541 if (tp_argument.IsType()) { | 541 if (tp_argument.IsType()) { |
542 ASSERT(tp_argument.HasResolvedTypeClass()); | 542 ASSERT(tp_argument.HasResolvedTypeClass()); |
543 // Check if type argument is dynamic or Object. | 543 // Check if type argument is dynamic or Object. |
544 const Type& object_type = | 544 const Type& object_type = |
545 Type::Handle(Isolate::Current()->object_store()->object_type()); | 545 Type::Handle(Isolate::Current()->object_store()->object_type()); |
546 Error& malformed_error = Error::Handle(); | 546 Error& malformed_error = Error::Handle(); |
547 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { | 547 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { |
548 // Instance class test only necessary. | 548 // Instance class test only necessary. |
549 return GenerateSubtype1TestCacheLookup( | 549 return GenerateSubtype1TestCacheLookup( |
550 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); | 550 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
551 } | 551 } |
552 } | 552 } |
553 } | 553 } |
554 // Regular subtype test cache involving instance's type arguments. | 554 // Regular subtype test cache involving instance's type arguments. |
555 const Register kTypeArgumentsReg = kNoRegister; | 555 const Register kTypeArgumentsReg = kNoRegister; |
556 const Register kTempReg = EDI; | 556 const Register kTempReg = EDI; |
557 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, | 557 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, |
558 kInstanceReg, | 558 kInstanceReg, |
559 kTypeArgumentsReg, | 559 kTypeArgumentsReg, |
560 kTempReg, | 560 kTempReg, |
(...skipping 12 matching lines...) Expand all Loading... |
573 } | 573 } |
574 __ jmp(is_not_equal_lbl); | 574 __ jmp(is_not_equal_lbl); |
575 } | 575 } |
576 | 576 |
577 | 577 |
578 // Testing against an instantiated type with no arguments, without | 578 // Testing against an instantiated type with no arguments, without |
579 // SubtypeTestCache. | 579 // SubtypeTestCache. |
580 // EAX: instance to test against (preserved). Clobbers ECX, EDI. | 580 // EAX: instance to test against (preserved). Clobbers ECX, EDI. |
581 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 581 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
582 intptr_t cid, | 582 intptr_t cid, |
583 intptr_t token_index, | 583 intptr_t token_pos, |
584 const AbstractType& type, | 584 const AbstractType& type, |
585 Label* is_instance_lbl, | 585 Label* is_instance_lbl, |
586 Label* is_not_instance_lbl) { | 586 Label* is_not_instance_lbl) { |
587 ASSERT(type.IsInstantiated()); | 587 ASSERT(type.IsInstantiated()); |
588 const Class& type_class = Class::Handle(type.type_class()); | 588 const Class& type_class = Class::Handle(type.type_class()); |
589 ASSERT(!type_class.HasTypeArguments()); | 589 ASSERT(!type_class.HasTypeArguments()); |
590 | 590 |
591 const Register kInstanceReg = EAX; | 591 const Register kInstanceReg = EAX; |
592 Label compare_classes; | 592 Label compare_classes; |
593 __ testl(kInstanceReg, Immediate(kSmiTagMask)); | 593 __ testl(kInstanceReg, Immediate(kSmiTagMask)); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 644 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
645 return; | 645 return; |
646 } | 646 } |
647 } | 647 } |
648 | 648 |
649 | 649 |
650 // Generates inlined check if 'type' is a type parameter or type itsef | 650 // Generates inlined check if 'type' is a type parameter or type itsef |
651 // EAX: instance (preserved). Clobbers EDX, EDI, ECX. | 651 // EAX: instance (preserved). Clobbers EDX, EDI, ECX. |
652 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 652 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
653 intptr_t cid, | 653 intptr_t cid, |
654 intptr_t token_index, | 654 intptr_t token_pos, |
655 const AbstractType& type, | 655 const AbstractType& type, |
656 Label* is_instance_lbl, | 656 Label* is_instance_lbl, |
657 Label* is_not_instance_lbl) { | 657 Label* is_not_instance_lbl) { |
658 ASSERT(!type.IsInstantiated()); | 658 ASSERT(!type.IsInstantiated()); |
659 // Skip check if destination is a dynamic type. | 659 // Skip check if destination is a dynamic type. |
660 const Immediate raw_null = | 660 const Immediate raw_null = |
661 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 661 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
662 if (type.IsTypeParameter()) { | 662 if (type.IsTypeParameter()) { |
663 // Load instantiator (or null) and instantiator type arguments on stack. | 663 // Load instantiator (or null) and instantiator type arguments on stack. |
664 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 664 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
734 | 734 |
735 | 735 |
736 // Uses SubtypeTestCache to store instance class and result. | 736 // Uses SubtypeTestCache to store instance class and result. |
737 // EAX: instance to test. Clobbers EDI, ECX. | 737 // EAX: instance to test. Clobbers EDI, ECX. |
738 // Immediate class test already done. | 738 // Immediate class test already done. |
739 // TODO(srdjan): Implement a quicker subtype check, as type test | 739 // TODO(srdjan): Implement a quicker subtype check, as type test |
740 // arrays can grow too high, but they may be useful when optimizing | 740 // arrays can grow too high, but they may be useful when optimizing |
741 // code (type-feedback). | 741 // code (type-feedback). |
742 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 742 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
743 intptr_t cid, | 743 intptr_t cid, |
744 intptr_t token_index, | 744 intptr_t token_pos, |
745 const Class& type_class, | 745 const Class& type_class, |
746 Label* is_instance_lbl, | 746 Label* is_instance_lbl, |
747 Label* is_not_instance_lbl) { | 747 Label* is_not_instance_lbl) { |
748 const Register kInstanceReg = EAX; | 748 const Register kInstanceReg = EAX; |
749 __ LoadClass(ECX, kInstanceReg, EDI); | 749 __ LoadClass(ECX, kInstanceReg, EDI); |
750 // ECX: instance class. | 750 // ECX: instance class. |
751 // Check immediate superclass equality. | 751 // Check immediate superclass equality. |
752 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 752 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
753 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 753 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
754 __ CompareObject(EDI, type_class); | 754 __ CompareObject(EDI, type_class); |
(...skipping 13 matching lines...) Expand all Loading... |
768 // Inputs: | 768 // Inputs: |
769 // - EAX: instance to test against (preserved). | 769 // - EAX: instance to test against (preserved). |
770 // - EDX: optional instantiator type arguments (preserved). | 770 // - EDX: optional instantiator type arguments (preserved). |
771 // Returns: | 771 // Returns: |
772 // - preserved instance in EAX and optional instantiator type arguments in EDX. | 772 // - preserved instance in EAX and optional instantiator type arguments in EDX. |
773 // Note that this inlined code must be followed by the runtime_call code, as it | 773 // Note that this inlined code must be followed by the runtime_call code, as it |
774 // may fall through to it. Otherwise, this inline code will jump to the label | 774 // may fall through to it. Otherwise, this inline code will jump to the label |
775 // is_instance or to the label is_not_instance. | 775 // is_instance or to the label is_not_instance. |
776 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 776 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
777 intptr_t cid, | 777 intptr_t cid, |
778 intptr_t token_index, | 778 intptr_t token_pos, |
779 const AbstractType& type, | 779 const AbstractType& type, |
780 Label* is_instance_lbl, | 780 Label* is_instance_lbl, |
781 Label* is_not_instance_lbl) { | 781 Label* is_not_instance_lbl) { |
782 if (type.IsInstantiated()) { | 782 if (type.IsInstantiated()) { |
783 const Class& type_class = Class::ZoneHandle(type.type_class()); | 783 const Class& type_class = Class::ZoneHandle(type.type_class()); |
784 // A Smi object cannot be the instance of a parameterized class. | 784 // A Smi object cannot be the instance of a parameterized class. |
785 // A class equality check is only applicable with a dst type of a | 785 // A class equality check is only applicable with a dst type of a |
786 // non-parameterized class or with a raw dst type of a parameterized class. | 786 // non-parameterized class or with a raw dst type of a parameterized class. |
787 if (type_class.HasTypeArguments()) { | 787 if (type_class.HasTypeArguments()) { |
788 return GenerateInstantiatedTypeWithArgumentsTest(cid, | 788 return GenerateInstantiatedTypeWithArgumentsTest(cid, |
789 token_index, | 789 token_pos, |
790 type, | 790 type, |
791 is_instance_lbl, | 791 is_instance_lbl, |
792 is_not_instance_lbl); | 792 is_not_instance_lbl); |
793 // Fall through to runtime call. | 793 // Fall through to runtime call. |
794 } else { | 794 } else { |
795 GenerateInstantiatedTypeNoArgumentsTest(cid, | 795 GenerateInstantiatedTypeNoArgumentsTest(cid, |
796 token_index, | 796 token_pos, |
797 type, | 797 type, |
798 is_instance_lbl, | 798 is_instance_lbl, |
799 is_not_instance_lbl); | 799 is_not_instance_lbl); |
800 // If test non-conclusive so far, try the inlined type-test cache. | 800 // If test non-conclusive so far, try the inlined type-test cache. |
801 // 'type' is known at compile time. | 801 // 'type' is known at compile time. |
802 return GenerateSubtype1TestCacheLookup( | 802 return GenerateSubtype1TestCacheLookup( |
803 cid, token_index, type_class, | 803 cid, token_pos, type_class, |
804 is_instance_lbl, is_not_instance_lbl); | 804 is_instance_lbl, is_not_instance_lbl); |
805 } | 805 } |
806 } else { | 806 } else { |
807 return GenerateUninstantiatedTypeTest(cid, | 807 return GenerateUninstantiatedTypeTest(cid, |
808 token_index, | 808 token_pos, |
809 type, | 809 type, |
810 is_instance_lbl, | 810 is_instance_lbl, |
811 is_not_instance_lbl); | 811 is_not_instance_lbl); |
812 } | 812 } |
813 return SubtypeTestCache::null(); | 813 return SubtypeTestCache::null(); |
814 } | 814 } |
815 | 815 |
816 | 816 |
817 // If instanceof type test cannot be performed successfully at compile time and | 817 // If instanceof type test cannot be performed successfully at compile time and |
818 // therefore eliminated, optimize it by adding inlined tests for: | 818 // therefore eliminated, optimize it by adding inlined tests for: |
819 // - NULL -> return false. | 819 // - NULL -> return false. |
820 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 820 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
821 // - Class equality (only if class is not parameterized). | 821 // - Class equality (only if class is not parameterized). |
822 // Inputs: | 822 // Inputs: |
823 // - EAX: object. | 823 // - EAX: object. |
824 // - EDX: instantiator type arguments or raw_null. | 824 // - EDX: instantiator type arguments or raw_null. |
825 // - ECX: instantiator or raw_null. | 825 // - ECX: instantiator or raw_null. |
826 // Returns: | 826 // Returns: |
827 // - true or false in EAX. | 827 // - true or false in EAX. |
828 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, | 828 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, |
829 intptr_t token_index, | 829 intptr_t token_pos, |
830 intptr_t try_index, | 830 intptr_t try_index, |
831 const AbstractType& type, | 831 const AbstractType& type, |
832 bool negate_result) { | 832 bool negate_result) { |
833 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 833 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
834 | 834 |
835 const Immediate raw_null = | 835 const Immediate raw_null = |
836 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 836 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
837 Label is_instance, is_not_instance; | 837 Label is_instance, is_not_instance; |
838 __ pushl(ECX); // Store instantiator on stack. | 838 __ pushl(ECX); // Store instantiator on stack. |
839 __ pushl(EDX); // Store instantiator type arguments. | 839 __ pushl(EDX); // Store instantiator type arguments. |
840 // If type is instantiated and non-parameterized, we can inline code | 840 // If type is instantiated and non-parameterized, we can inline code |
841 // checking whether the tested instance is a Smi. | 841 // checking whether the tested instance is a Smi. |
842 if (type.IsInstantiated()) { | 842 if (type.IsInstantiated()) { |
843 // A null object is only an instance of Object and Dynamic, which has | 843 // A null object is only an instance of Object and Dynamic, which has |
844 // already been checked above (if the type is instantiated). So we can | 844 // already been checked above (if the type is instantiated). So we can |
845 // return false here if the instance is null (and if the type is | 845 // return false here if the instance is null (and if the type is |
846 // instantiated). | 846 // instantiated). |
847 // We can only inline this null check if the type is instantiated at compile | 847 // We can only inline this null check if the type is instantiated at compile |
848 // time, since an uninstantiated type at compile time could be Object or | 848 // time, since an uninstantiated type at compile time could be Object or |
849 // Dynamic at run time. | 849 // Dynamic at run time. |
850 __ cmpl(EAX, raw_null); | 850 __ cmpl(EAX, raw_null); |
851 __ j(EQUAL, &is_not_instance); | 851 __ j(EQUAL, &is_not_instance); |
852 } | 852 } |
853 // TODO(srdjan): Enable inlined checks. | 853 // TODO(srdjan): Enable inlined checks. |
854 // Generate inline instanceof test. | 854 // Generate inline instanceof test. |
855 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 855 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
856 test_cache = GenerateInlineInstanceof(cid, token_index, type, | 856 test_cache = GenerateInlineInstanceof(cid, token_pos, type, |
857 &is_instance, &is_not_instance); | 857 &is_instance, &is_not_instance); |
858 | 858 |
859 // Generate runtime call. | 859 // Generate runtime call. |
860 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 860 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
861 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 861 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
862 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 862 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
863 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 863 __ pushl(Immediate(Smi::RawValue(token_pos))); // Source location. |
864 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. | 864 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. |
865 __ pushl(EAX); // Push the instance. | 865 __ pushl(EAX); // Push the instance. |
866 __ PushObject(type); // Push the type. | 866 __ PushObject(type); // Push the type. |
867 __ pushl(ECX); // TODO(srdjan): Pass instantiator instead of null. | 867 __ pushl(ECX); // TODO(srdjan): Pass instantiator instead of null. |
868 __ pushl(EDX); // Instantiator type arguments. | 868 __ pushl(EDX); // Instantiator type arguments. |
869 __ LoadObject(EAX, test_cache); | 869 __ LoadObject(EAX, test_cache); |
870 __ pushl(EAX); | 870 __ pushl(EAX); |
871 GenerateCallRuntime(cid, token_index, try_index, kInstanceofRuntimeEntry); | 871 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry); |
872 // Pop the two parameters supplied to the runtime entry. The result of the | 872 // Pop the two parameters supplied to the runtime entry. The result of the |
873 // instanceof runtime call will be left as the result of the operation. | 873 // instanceof runtime call will be left as the result of the operation. |
874 __ Drop(7); | 874 __ Drop(7); |
875 Label done; | 875 Label done; |
876 if (negate_result) { | 876 if (negate_result) { |
877 __ popl(EDX); | 877 __ popl(EDX); |
878 __ LoadObject(EAX, bool_true()); | 878 __ LoadObject(EAX, bool_true()); |
879 __ cmpl(EDX, EAX); | 879 __ cmpl(EDX, EAX); |
880 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 880 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
881 __ LoadObject(EAX, bool_false()); | 881 __ LoadObject(EAX, bool_false()); |
(...skipping 20 matching lines...) Expand all Loading... |
902 // - Class equality (only if class is not parameterized). | 902 // - Class equality (only if class is not parameterized). |
903 // Inputs: | 903 // Inputs: |
904 // - EAX: object. | 904 // - EAX: object. |
905 // - EDX: instantiator type arguments or raw_null. | 905 // - EDX: instantiator type arguments or raw_null. |
906 // - ECX: instantiator or raw_null. | 906 // - ECX: instantiator or raw_null. |
907 // Returns: | 907 // Returns: |
908 // - object in EAX for successful assignable check (or throws TypeError). | 908 // - object in EAX for successful assignable check (or throws TypeError). |
909 // Performance notes: positive checks must be quick, negative checks can be slow | 909 // Performance notes: positive checks must be quick, negative checks can be slow |
910 // as they throw an exception. | 910 // as they throw an exception. |
911 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, | 911 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, |
912 intptr_t token_index, | 912 intptr_t token_pos, |
913 intptr_t try_index, | 913 intptr_t try_index, |
914 const AbstractType& dst_type, | 914 const AbstractType& dst_type, |
915 const String& dst_name) { | 915 const String& dst_name) { |
916 ASSERT(FLAG_enable_type_checks); | 916 ASSERT(FLAG_enable_type_checks); |
917 ASSERT(token_index >= 0); | 917 ASSERT(token_pos >= 0); |
918 ASSERT(!dst_type.IsNull()); | 918 ASSERT(!dst_type.IsNull()); |
919 ASSERT(dst_type.IsFinalized()); | 919 ASSERT(dst_type.IsFinalized()); |
920 // Assignable check is skipped in FlowGraphBuilder, not here. | 920 // Assignable check is skipped in FlowGraphBuilder, not here. |
921 ASSERT(dst_type.IsMalformed() || | 921 ASSERT(dst_type.IsMalformed() || |
922 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 922 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
923 ASSERT(!dst_type.IsVoidType()); | 923 ASSERT(!dst_type.IsVoidType()); |
924 __ pushl(ECX); // Store instantiator. | 924 __ pushl(ECX); // Store instantiator. |
925 __ pushl(EDX); // Store instantiator type arguments. | 925 __ pushl(EDX); // Store instantiator type arguments. |
926 // A null object is always assignable and is returned as result. | 926 // A null object is always assignable and is returned as result. |
927 const Immediate raw_null = | 927 const Immediate raw_null = |
928 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 928 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
929 Label is_assignable, runtime_call; | 929 Label is_assignable, runtime_call; |
930 __ cmpl(EAX, raw_null); | 930 __ cmpl(EAX, raw_null); |
931 __ j(EQUAL, &is_assignable); | 931 __ j(EQUAL, &is_assignable); |
932 | 932 |
933 // Generate throw new TypeError() if the type is malformed. | 933 // Generate throw new TypeError() if the type is malformed. |
934 if (dst_type.IsMalformed()) { | 934 if (dst_type.IsMalformed()) { |
935 const Error& error = Error::Handle(dst_type.malformed_error()); | 935 const Error& error = Error::Handle(dst_type.malformed_error()); |
936 const String& error_message = String::ZoneHandle( | 936 const String& error_message = String::ZoneHandle( |
937 String::NewSymbol(error.ToErrorCString())); | 937 String::NewSymbol(error.ToErrorCString())); |
938 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 938 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
939 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 939 __ pushl(Immediate(Smi::RawValue(token_pos))); // Source location. |
940 __ pushl(EAX); // Push the source object. | 940 __ pushl(EAX); // Push the source object. |
941 __ PushObject(dst_name); // Push the name of the destination. | 941 __ PushObject(dst_name); // Push the name of the destination. |
942 __ PushObject(error_message); | 942 __ PushObject(error_message); |
943 GenerateCallRuntime(cid, | 943 GenerateCallRuntime(cid, |
944 token_index, | 944 token_pos, |
945 try_index, | 945 try_index, |
946 kMalformedTypeErrorRuntimeEntry); | 946 kMalformedTypeErrorRuntimeEntry); |
947 // We should never return here. | 947 // We should never return here. |
948 __ int3(); | 948 __ int3(); |
949 | 949 |
950 __ Bind(&is_assignable); // For a null object. | 950 __ Bind(&is_assignable); // For a null object. |
951 return; | 951 return; |
952 } | 952 } |
953 | 953 |
954 // TODO(srdjan): Enable subtype test cache. | 954 // TODO(srdjan): Enable subtype test cache. |
955 // Generate inline type check, linking to runtime call if not assignable. | 955 // Generate inline type check, linking to runtime call if not assignable. |
956 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 956 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
957 test_cache = GenerateInlineInstanceof(cid, token_index, dst_type, | 957 test_cache = GenerateInlineInstanceof(cid, token_pos, dst_type, |
958 &is_assignable, &runtime_call); | 958 &is_assignable, &runtime_call); |
959 | 959 |
960 __ Bind(&runtime_call); | 960 __ Bind(&runtime_call); |
961 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 961 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
962 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 962 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
963 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 963 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
964 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 964 __ pushl(Immediate(Smi::RawValue(token_pos))); // Source location. |
965 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. | 965 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. |
966 __ pushl(EAX); // Push the source object. | 966 __ pushl(EAX); // Push the source object. |
967 __ PushObject(dst_type); // Push the type of the destination. | 967 __ PushObject(dst_type); // Push the type of the destination. |
968 __ pushl(ECX); // Instantiator. | 968 __ pushl(ECX); // Instantiator. |
969 __ pushl(EDX); // Instantiator type arguments. | 969 __ pushl(EDX); // Instantiator type arguments. |
970 __ PushObject(dst_name); // Push the name of the destination. | 970 __ PushObject(dst_name); // Push the name of the destination. |
971 __ LoadObject(EAX, test_cache); | 971 __ LoadObject(EAX, test_cache); |
972 __ pushl(EAX); | 972 __ pushl(EAX); |
973 GenerateCallRuntime(cid, | 973 GenerateCallRuntime(cid, |
974 token_index, | 974 token_pos, |
975 try_index, | 975 try_index, |
976 kTypeCheckRuntimeEntry); | 976 kTypeCheckRuntimeEntry); |
977 // Pop the parameters supplied to the runtime entry. The result of the | 977 // Pop the parameters supplied to the runtime entry. The result of the |
978 // type check runtime call is the checked value. | 978 // type check runtime call is the checked value. |
979 __ Drop(8); | 979 __ Drop(8); |
980 __ popl(EAX); | 980 __ popl(EAX); |
981 | 981 |
982 __ Bind(&is_assignable); | 982 __ Bind(&is_assignable); |
983 __ popl(EDX); // Remove pushed instantiator type arguments.. | 983 __ popl(EDX); // Remove pushed instantiator type arguments.. |
984 __ popl(ECX); // Remove pushed instantiator. | 984 __ popl(ECX); // Remove pushed instantiator. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1046 __ cvtsi2sd(result, temp); | 1046 __ cvtsi2sd(result, temp); |
1047 __ Bind(&done); | 1047 __ Bind(&done); |
1048 } | 1048 } |
1049 | 1049 |
1050 | 1050 |
1051 #undef __ | 1051 #undef __ |
1052 | 1052 |
1053 } // namespace dart | 1053 } // namespace dart |
1054 | 1054 |
1055 #endif // defined TARGET_ARCH_IA32 | 1055 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |