| 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 "vm/ast_printer.h" | 11 #include "vm/ast_printer.h" |
| 11 #include "vm/compiler_stats.h" | 12 #include "vm/compiler_stats.h" |
| 12 #include "vm/debugger.h" | 13 #include "vm/debugger.h" |
| 13 #include "vm/il_printer.h" | 14 #include "vm/il_printer.h" |
| 14 #include "vm/intrinsifier.h" | 15 #include "vm/intrinsifier.h" |
| 15 #include "vm/locations.h" | 16 #include "vm/locations.h" |
| 16 #include "vm/longjump.h" | 17 #include "vm/longjump.h" |
| 17 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 18 | 19 |
| 19 namespace dart { | 20 namespace dart { |
| (...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 | 499 |
| 499 void FlowGraphCompiler::GenerateCall(intptr_t token_index, | 500 void FlowGraphCompiler::GenerateCall(intptr_t token_index, |
| 500 intptr_t try_index, | 501 intptr_t try_index, |
| 501 const ExternalLabel* label, | 502 const ExternalLabel* label, |
| 502 PcDescriptors::Kind kind) { | 503 PcDescriptors::Kind kind) { |
| 503 __ call(label); | 504 __ call(label); |
| 504 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); | 505 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); |
| 505 } | 506 } |
| 506 | 507 |
| 507 | 508 |
| 509 // If instanceof type test cannot be performed successfully at compile time and |
| 510 // therefore eliminated, optimize it by adding inlined tests for: |
| 511 // - NULL -> return false. |
| 512 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 513 // - Class equality (only if class is not parameterized). |
| 514 // Inputs: |
| 515 // - EAX: object. |
| 516 // - EDX: instantiator type arguments or raw_null. |
| 517 // - ECX: instantiator or raw_null. |
| 518 // Returns: |
| 519 // - true or false in EAX. |
| 520 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, |
| 521 intptr_t token_index, |
| 522 intptr_t try_index, |
| 523 const AbstractType& type, |
| 524 bool negate_result) { |
| 525 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 526 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 527 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 528 |
| 529 const Immediate raw_null = |
| 530 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 531 Label is_instance, is_not_instance; |
| 532 __ pushl(ECX); // Store instantiator on stack. |
| 533 __ pushl(EDX); // Store instantiator type arguments. |
| 534 // If type is instantiated and non-parameterized, we can inline code |
| 535 // checking whether the tested instance is a Smi. |
| 536 if (type.IsInstantiated()) { |
| 537 // A null object is only an instance of Object and Dynamic, which has |
| 538 // already been checked above (if the type is instantiated). So we can |
| 539 // return false here if the instance is null (and if the type is |
| 540 // instantiated). |
| 541 // We can only inline this null check if the type is instantiated at compile |
| 542 // time, since an uninstantiated type at compile time could be Object or |
| 543 // Dynamic at run time. |
| 544 __ cmpl(EAX, raw_null); |
| 545 __ j(EQUAL, &is_not_instance); |
| 546 } |
| 547 // TODO(srdjan): Enable inlined checks. |
| 548 // Generate inline instanceof test. |
| 549 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 550 // test_cache = GenerateInlineInstanceof(cid, token_index, type, |
| 551 // &is_instance, &is_not_instance); |
| 552 |
| 553 // Generate runtime call. |
| 554 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 555 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
| 556 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 557 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 558 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. |
| 559 __ pushl(EAX); // Push the instance. |
| 560 __ PushObject(type); // Push the type. |
| 561 __ pushl(ECX); // TODO(srdjan): Pass instantiator instead of null. |
| 562 __ pushl(EDX); // Instantiator type arguments. |
| 563 __ LoadObject(EAX, test_cache); |
| 564 __ pushl(EAX); |
| 565 GenerateCallRuntime(cid, token_index, try_index, kInstanceofRuntimeEntry); |
| 566 // Pop the two parameters supplied to the runtime entry. The result of the |
| 567 // instanceof runtime call will be left as the result of the operation. |
| 568 __ Drop(7); |
| 569 Label done; |
| 570 if (negate_result) { |
| 571 __ popl(EDX); |
| 572 __ LoadObject(EAX, bool_true); |
| 573 __ cmpl(EDX, EAX); |
| 574 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 575 __ LoadObject(EAX, bool_false); |
| 576 } else { |
| 577 __ popl(EAX); |
| 578 } |
| 579 __ jmp(&done, Assembler::kNearJump); |
| 580 |
| 581 __ Bind(&is_not_instance); |
| 582 __ LoadObject(EAX, negate_result ? bool_true : bool_false); |
| 583 __ jmp(&done, Assembler::kNearJump); |
| 584 |
| 585 __ Bind(&is_instance); |
| 586 __ LoadObject(EAX, negate_result ? bool_false : bool_true); |
| 587 __ Bind(&done); |
| 588 __ popl(EDX); // Remove pushed instantiator type arguments. |
| 589 __ popl(ECX); // Remove pushed instantiator. |
| 590 } |
| 591 |
| 592 |
| 593 // Optimize assignable type check by adding inlined tests for: |
| 594 // - NULL -> return NULL. |
| 595 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 596 // - Class equality (only if class is not parameterized). |
| 597 // Inputs: |
| 598 // - EAX: object. |
| 599 // - EDX: instantiator type arguments or raw_null. |
| 600 // - ECX: instantiator or raw_null. |
| 601 // Returns: |
| 602 // - object in EAX for successful assignable check (or throws TypeError). |
| 603 // Performance notes: positive checks must be quick, negative checks can be slow |
| 604 // as they throw an exception. |
| 605 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, |
| 606 intptr_t token_index, |
| 607 intptr_t try_index, |
| 608 const AbstractType& dst_type, |
| 609 const String& dst_name) { |
| 610 ASSERT(FLAG_enable_type_checks); |
| 611 ASSERT(token_index >= 0); |
| 612 ASSERT(!dst_type.IsNull()); |
| 613 ASSERT(dst_type.IsFinalized()); |
| 614 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 615 ASSERT(dst_type.IsMalformed() || |
| 616 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 617 ASSERT(!dst_type.IsVoidType()); |
| 618 __ pushl(ECX); // Store instantiator. |
| 619 __ pushl(EDX); // Store instantiator type arguments. |
| 620 // A null object is always assignable and is returned as result. |
| 621 const Immediate raw_null = |
| 622 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 623 Label is_assignable, runtime_call; |
| 624 __ cmpl(EAX, raw_null); |
| 625 __ j(EQUAL, &is_assignable); |
| 626 |
| 627 // Generate throw new TypeError() if the type is malformed. |
| 628 if (dst_type.IsMalformed()) { |
| 629 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 630 const String& error_message = String::ZoneHandle( |
| 631 String::NewSymbol(error.ToErrorCString())); |
| 632 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 633 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 634 __ pushl(EAX); // Push the source object. |
| 635 __ PushObject(dst_name); // Push the name of the destination. |
| 636 __ PushObject(error_message); |
| 637 GenerateCallRuntime(cid, |
| 638 token_index, |
| 639 try_index, |
| 640 kMalformedTypeErrorRuntimeEntry); |
| 641 // We should never return here. |
| 642 __ int3(); |
| 643 |
| 644 __ Bind(&is_assignable); // For a null object. |
| 645 return; |
| 646 } |
| 647 |
| 648 // TODO(srdjan): Enable subtype test cache. |
| 649 // Generate inline type check, linking to runtime call if not assignable. |
| 650 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 651 // test_cache = GenerateInlineInstanceof(cid, token_index, dst_type, |
| 652 // &is_assignable, &runtime_call); |
| 653 |
| 654 __ Bind(&runtime_call); |
| 655 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 656 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
| 657 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 658 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 659 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. |
| 660 __ pushl(EAX); // Push the source object. |
| 661 __ PushObject(dst_type); // Push the type of the destination. |
| 662 __ pushl(ECX); // Instantiator. |
| 663 __ pushl(EDX); // Instantiator type arguments. |
| 664 __ PushObject(dst_name); // Push the name of the destination. |
| 665 __ LoadObject(EAX, test_cache); |
| 666 __ pushl(EAX); |
| 667 GenerateCallRuntime(cid, |
| 668 token_index, |
| 669 try_index, |
| 670 kTypeCheckRuntimeEntry); |
| 671 // Pop the parameters supplied to the runtime entry. The result of the |
| 672 // type check runtime call is the checked value. |
| 673 __ Drop(8); |
| 674 __ popl(EAX); |
| 675 |
| 676 __ Bind(&is_assignable); |
| 677 __ popl(EDX); // Remove pushed instantiator type arguments.. |
| 678 __ popl(ECX); // Remove pushed instantiator. |
| 679 } |
| 680 |
| 681 |
| 508 void FlowGraphCompiler::EmitComment(Instruction* instr) { | 682 void FlowGraphCompiler::EmitComment(Instruction* instr) { |
| 509 char buffer[80]; | 683 char buffer[80]; |
| 510 BufferFormatter f(buffer, sizeof(buffer)); | 684 BufferFormatter f(buffer, sizeof(buffer)); |
| 511 instr->PrintTo(&f); | 685 instr->PrintTo(&f); |
| 512 __ Comment("@%d: %s", instr->cid(), buffer); | 686 __ Comment("@%d: %s", instr->cid(), buffer); |
| 513 } | 687 } |
| 514 | 688 |
| 515 | 689 |
| 516 void FlowGraphCompiler::BailoutOnInstruction(Instruction* instr) { | 690 void FlowGraphCompiler::BailoutOnInstruction(Instruction* instr) { |
| 517 char buffer[80]; | 691 char buffer[80]; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 565 } | 739 } |
| 566 } | 740 } |
| 567 } | 741 } |
| 568 } | 742 } |
| 569 | 743 |
| 570 #undef __ | 744 #undef __ |
| 571 | 745 |
| 572 } // namespace dart | 746 } // namespace dart |
| 573 | 747 |
| 574 #endif // defined TARGET_ARCH_IA32 | 748 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |