| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| 11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/locations.h" | 12 #include "vm/locations.h" |
| 13 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 14 #include "vm/parser.h" | 14 #include "vm/parser.h" |
| 15 #include "vm/stub_code.h" | 15 #include "vm/stub_code.h" |
| 16 | 16 |
| 17 #define __ compiler->assembler()-> | 17 #define __ compiler->assembler()-> |
| 18 | 18 |
| 19 namespace dart { | 19 namespace dart { |
| 20 | 20 |
| 21 DECLARE_FLAG(int, optimization_counter_threshold); | 21 DECLARE_FLAG(int, optimization_counter_threshold); |
| 22 DECLARE_FLAG(bool, trace_functions); | 22 DECLARE_FLAG(bool, trace_functions); |
| 23 | 23 |
| 24 // Generic summary for call instructions that have all arguments pushed |
| 25 // on the stack and return the result in a fixed register RAX. |
| 26 LocationSummary* Computation::MakeCallSummary() { |
| 27 LocationSummary* result = new LocationSummary(0, 0, LocationSummary::kCall); |
| 28 result->set_out(Location::RegisterLocation(RAX)); |
| 29 return result; |
| 30 } |
| 31 |
| 32 |
| 24 void BindInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 33 void BindInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 25 computation()->EmitNativeCode(compiler); | 34 computation()->EmitNativeCode(compiler); |
| 26 if (locs()->out().kind() == Location::kRegister) { | 35 if (locs()->out().kind() == Location::kRegister) { |
| 27 // TODO(vegorov): this should really happen only for comparisons fused | 36 // TODO(vegorov): this should really happen only for comparisons fused |
| 28 // with branches. Currrently IR does not provide an easy way to remove | 37 // with branches. Currrently IR does not provide an easy way to remove |
| 29 // instructions from the graph so we just leave fused comparison in it | 38 // instructions from the graph so we just leave fused comparison in it |
| 30 // but change its result location to be NoLocation. | 39 // but change its result location to be NoLocation. |
| 31 compiler->frame_register_allocator()->Push(locs()->out().reg(), this); | 40 compiler->frame_register_allocator()->Push(locs()->out().reg(), this); |
| 32 } | 41 } |
| 33 } | 42 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 63 __ j(LESS_EQUAL, ¬_yet_hot, Assembler::kNearJump); | 72 __ j(LESS_EQUAL, ¬_yet_hot, Assembler::kNearJump); |
| 64 __ pushq(result); // Preserve result. | 73 __ pushq(result); // Preserve result. |
| 65 __ pushq(temp); // Argument for runtime: function to optimize. | 74 __ pushq(temp); // Argument for runtime: function to optimize. |
| 66 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); | 75 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); |
| 67 __ popq(temp); // Remove argument. | 76 __ popq(temp); // Remove argument. |
| 68 __ popq(result); // Restore result. | 77 __ popq(result); // Restore result. |
| 69 __ Bind(¬_yet_hot); | 78 __ Bind(¬_yet_hot); |
| 70 } | 79 } |
| 71 } | 80 } |
| 72 if (FLAG_trace_functions) { | 81 if (FLAG_trace_functions) { |
| 73 __ pushq(result); // Preserve result. | |
| 74 const Function& function = | 82 const Function& function = |
| 75 Function::ZoneHandle(compiler->parsed_function().function().raw()); | 83 Function::ZoneHandle(compiler->parsed_function().function().raw()); |
| 76 __ LoadObject(temp, function); | 84 __ LoadObject(temp, function); |
| 85 __ pushq(result); // Preserve result. |
| 77 __ pushq(temp); | 86 __ pushq(temp); |
| 78 compiler->GenerateCallRuntime(AstNode::kNoId, | 87 compiler->GenerateCallRuntime(AstNode::kNoId, |
| 79 0, | 88 0, |
| 80 CatchClauseNode::kInvalidTryIndex, | 89 CatchClauseNode::kInvalidTryIndex, |
| 81 kTraceFunctionExitRuntimeEntry); | 90 kTraceFunctionExitRuntimeEntry); |
| 82 __ popq(temp); // Remove argument. | 91 __ popq(temp); // Remove argument. |
| 83 __ popq(result); // Restore result. | 92 __ popq(result); // Restore result. |
| 84 } | 93 } |
| 85 __ LeaveFrame(); | 94 __ LeaveFrame(); |
| 86 __ ret(); | 95 __ ret(); |
| 87 | 96 |
| 88 // Generate 8 bytes of NOPs so that the debugger can patch the | 97 // Generate 8 bytes of NOPs so that the debugger can patch the |
| 89 // return pattern with a call to the debug stub. | 98 // return pattern with a call to the debug stub. |
| 99 // Note that the nop(8) byte pattern is not recognized by the debugger. |
| 90 __ nop(1); | 100 __ nop(1); |
| 91 __ nop(1); | 101 __ nop(1); |
| 92 __ nop(1); | 102 __ nop(1); |
| 93 __ nop(1); | 103 __ nop(1); |
| 94 __ nop(1); | 104 __ nop(1); |
| 95 __ nop(1); | 105 __ nop(1); |
| 96 __ nop(1); | 106 __ nop(1); |
| 97 __ nop(1); | 107 __ nop(1); |
| 98 compiler->AddCurrentDescriptor(PcDescriptors::kReturn, | 108 compiler->AddCurrentDescriptor(PcDescriptors::kReturn, |
| 99 cid(), | 109 cid(), |
| 100 token_index(), | 110 token_index(), |
| 101 CatchClauseNode::kInvalidTryIndex); | 111 CatchClauseNode::kInvalidTryIndex); |
| 102 } | 112 } |
| 103 | 113 |
| 104 | 114 |
| 105 // Generic summary for call instructions that have all arguments pushed | |
| 106 // on the stack and return the result in a fixed register RAX. | |
| 107 LocationSummary* Computation::MakeCallSummary() { | |
| 108 LocationSummary* result = new LocationSummary(0, 0, LocationSummary::kCall); | |
| 109 result->set_out(Location::RegisterLocation(RAX)); | |
| 110 return result; | |
| 111 } | |
| 112 | |
| 113 | |
| 114 LocationSummary* ClosureCallComp::MakeLocationSummary() const { | 115 LocationSummary* ClosureCallComp::MakeLocationSummary() const { |
| 115 const intptr_t kNumInputs = 0; | 116 const intptr_t kNumInputs = 0; |
| 116 const intptr_t kNumTemps = 1; | 117 const intptr_t kNumTemps = 1; |
| 117 LocationSummary* result = new LocationSummary(kNumInputs, | 118 LocationSummary* result = new LocationSummary(kNumInputs, |
| 118 kNumTemps, | 119 kNumTemps, |
| 119 LocationSummary::kCall); | 120 LocationSummary::kCall); |
| 120 result->set_out(Location::RegisterLocation(RAX)); | 121 result->set_out(Location::RegisterLocation(RAX)); |
| 121 result->set_temp(0, Location::RegisterLocation(R10)); // Arg. descriptor. | 122 result->set_temp(0, Location::RegisterLocation(R10)); // Arg. descriptor. |
| 122 return result; | 123 return result; |
| 123 } | 124 } |
| (...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 __ jmp(deopt); | 382 __ jmp(deopt); |
| 382 __ Bind(&done); | 383 __ Bind(&done); |
| 383 } | 384 } |
| 384 | 385 |
| 385 | 386 |
| 386 // First test if receiver is NULL, in which case === is applied. | 387 // First test if receiver is NULL, in which case === is applied. |
| 387 // If type feedback was provided (lists of <class-id, target>), do a | 388 // If type feedback was provided (lists of <class-id, target>), do a |
| 388 // type by type check (either === or static call to the operator. | 389 // type by type check (either === or static call to the operator. |
| 389 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | 390 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, |
| 390 EqualityCompareComp* comp) { | 391 EqualityCompareComp* comp) { |
| 391 const Immediate raw_null = | |
| 392 Immediate(reinterpret_cast<intptr_t>(Object::null())); | |
| 393 Register left = comp->locs()->in(0).reg(); | 392 Register left = comp->locs()->in(0).reg(); |
| 394 Register right = comp->locs()->in(1).reg(); | 393 Register right = comp->locs()->in(1).reg(); |
| 394 const Immediate raw_null = |
| 395 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 395 Label done, non_null_compare; | 396 Label done, non_null_compare; |
| 396 __ cmpq(left, raw_null); | 397 __ cmpq(left, raw_null); |
| 397 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); | 398 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); |
| 398 // Comparison with NULL is "===". | 399 // Comparison with NULL is "===". |
| 399 __ cmpq(left, right); | 400 __ cmpq(left, right); |
| 400 if (comp->is_fused_with_branch()) { | 401 if (comp->is_fused_with_branch()) { |
| 401 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); | 402 comp->fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 402 } else { | 403 } else { |
| 403 Register result = comp->locs()->out().reg(); | 404 Register result = comp->locs()->out().reg(); |
| 404 Label load_true; | 405 Label load_true; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 | 543 |
| 543 if (comp->is_fused_with_branch()) { | 544 if (comp->is_fused_with_branch()) { |
| 544 BranchInstr* branch = comp->fused_with_branch(); | 545 BranchInstr* branch = comp->fused_with_branch(); |
| 545 BlockEntryInstr* nan_result = branch->is_negated() ? | 546 BlockEntryInstr* nan_result = branch->is_negated() ? |
| 546 branch->true_successor() : branch->false_successor(); | 547 branch->true_successor() : branch->false_successor(); |
| 547 __ j(PARITY_EVEN, compiler->GetBlockLabel(nan_result)); | 548 __ j(PARITY_EVEN, compiler->GetBlockLabel(nan_result)); |
| 548 branch->EmitBranchOnCondition(compiler, true_condition); | 549 branch->EmitBranchOnCondition(compiler, true_condition); |
| 549 } else { | 550 } else { |
| 550 Register result = comp->locs()->out().reg(); | 551 Register result = comp->locs()->out().reg(); |
| 551 Label is_false, is_true, done; | 552 Label is_false, is_true, done; |
| 552 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); | 553 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; |
| 553 __ j(true_condition, &is_true, Assembler::kNearJump); | 554 __ j(true_condition, &is_true, Assembler::kNearJump); |
| 554 __ Bind(&is_false); | 555 __ Bind(&is_false); |
| 555 __ LoadObject(result, compiler->bool_false()); | 556 __ LoadObject(result, compiler->bool_false()); |
| 556 __ jmp(&done); | 557 __ jmp(&done); |
| 557 __ Bind(&is_true); | 558 __ Bind(&is_true); |
| 558 __ LoadObject(result, compiler->bool_true()); | 559 __ LoadObject(result, compiler->bool_true()); |
| 559 __ Bind(&done); | 560 __ Bind(&done); |
| 560 } | 561 } |
| 561 } | 562 } |
| 562 | 563 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 LocationSummary* LoadIndexedComp::MakeLocationSummary() const { | 636 LocationSummary* LoadIndexedComp::MakeLocationSummary() const { |
| 636 const intptr_t kNumInputs = 2; | 637 const intptr_t kNumInputs = 2; |
| 637 if (receiver_type() == kGrowableObjectArray) { | 638 if (receiver_type() == kGrowableObjectArray) { |
| 638 const intptr_t kNumTemps = 1; | 639 const intptr_t kNumTemps = 1; |
| 639 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | 640 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 640 locs->set_in(0, Location::RequiresRegister()); | 641 locs->set_in(0, Location::RequiresRegister()); |
| 641 locs->set_in(1, Location::RequiresRegister()); | 642 locs->set_in(1, Location::RequiresRegister()); |
| 642 locs->set_temp(0, Location::RequiresRegister()); | 643 locs->set_temp(0, Location::RequiresRegister()); |
| 643 locs->set_out(Location::RequiresRegister()); | 644 locs->set_out(Location::RequiresRegister()); |
| 644 return locs; | 645 return locs; |
| 645 } else if (receiver_type() == kArray || receiver_type() == kImmutableArray) { | 646 } else if ((receiver_type() == kArray) || |
| 647 (receiver_type() == kImmutableArray)) { |
| 646 return LocationSummary::Make(kNumInputs, Location::RequiresRegister()); | 648 return LocationSummary::Make(kNumInputs, Location::RequiresRegister()); |
| 647 } else { | 649 } else { |
| 648 ASSERT(receiver_type() == kIllegalObjectKind); | 650 ASSERT(receiver_type() == kIllegalObjectKind); |
| 649 return MakeCallSummary(); | 651 return MakeCallSummary(); |
| 650 } | 652 } |
| 651 } | 653 } |
| 652 | 654 |
| 653 | 655 |
| 654 static void EmitLoadIndexedPolymorphic(FlowGraphCompiler* compiler, | 656 static void EmitLoadIndexedPolymorphic(FlowGraphCompiler* compiler, |
| 655 LoadIndexedComp* comp) { | 657 LoadIndexedComp* comp) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 678 kNumArguments, | 680 kNumArguments, |
| 679 Array::Handle(), // No named arguments. | 681 Array::Handle(), // No named arguments. |
| 680 deopt, &done, // Labels. | 682 deopt, &done, // Labels. |
| 681 comp->cid(), | 683 comp->cid(), |
| 682 comp->token_index(), | 684 comp->token_index(), |
| 683 comp->try_index()); | 685 comp->try_index()); |
| 684 __ Bind(&done); | 686 __ Bind(&done); |
| 685 } | 687 } |
| 686 | 688 |
| 687 | 689 |
| 688 | |
| 689 void LoadIndexedComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 690 void LoadIndexedComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 690 if (receiver_type() == kIllegalObjectKind) { | 691 if (receiver_type() == kIllegalObjectKind) { |
| 691 if (HasICData()) { | 692 if (HasICData()) { |
| 692 EmitLoadIndexedPolymorphic(compiler, this); | 693 EmitLoadIndexedPolymorphic(compiler, this); |
| 693 } else { | 694 } else { |
| 694 compiler->EmitLoadIndexedGeneric(this); | 695 compiler->EmitLoadIndexedGeneric(this); |
| 695 } | 696 } |
| 696 ASSERT(locs()->out().reg() == RAX); | 697 ASSERT(locs()->out().reg() == RAX); |
| 697 return; | 698 return; |
| 698 } | 699 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 return locs; | 763 return locs; |
| 763 } else if (receiver_type() == kArray) { | 764 } else if (receiver_type() == kArray) { |
| 764 return LocationSummary::Make(kNumInputs, Location::NoLocation()); | 765 return LocationSummary::Make(kNumInputs, Location::NoLocation()); |
| 765 } else { | 766 } else { |
| 766 ASSERT(receiver_type() == kIllegalObjectKind); | 767 ASSERT(receiver_type() == kIllegalObjectKind); |
| 767 return MakeCallSummary(); | 768 return MakeCallSummary(); |
| 768 } | 769 } |
| 769 } | 770 } |
| 770 | 771 |
| 771 | 772 |
| 772 | |
| 773 static void EmitStoreIndexedGeneric(FlowGraphCompiler* compiler, | 773 static void EmitStoreIndexedGeneric(FlowGraphCompiler* compiler, |
| 774 StoreIndexedComp* comp) { | 774 StoreIndexedComp* comp) { |
| 775 const String& function_name = | 775 const String& function_name = |
| 776 String::ZoneHandle(String::NewSymbol(Token::Str(Token::kASSIGN_INDEX))); | 776 String::ZoneHandle(String::NewSymbol(Token::Str(Token::kASSIGN_INDEX))); |
| 777 | 777 |
| 778 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 778 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 779 comp->cid(), | 779 comp->cid(), |
| 780 comp->token_index(), | 780 comp->token_index(), |
| 781 comp->try_index()); | 781 comp->try_index()); |
| 782 | 782 |
| 783 const intptr_t kNumArguments = 3; | 783 const intptr_t kNumArguments = 3; |
| 784 const intptr_t kNumArgsChecked = 1; // Type-feedback. | 784 const intptr_t kNumArgsChecked = 1; // Type-feedback. |
| 785 compiler->GenerateInstanceCall(comp->cid(), | 785 compiler->GenerateInstanceCall(comp->cid(), |
| 786 comp->token_index(), | 786 comp->token_index(), |
| 787 comp->try_index(), | 787 comp->try_index(), |
| 788 function_name, | 788 function_name, |
| 789 kNumArguments, | 789 kNumArguments, |
| 790 Array::ZoneHandle(), // No names arguments. | 790 Array::ZoneHandle(), // No named arguments. |
| 791 kNumArgsChecked); | 791 kNumArgsChecked); |
| 792 } | 792 } |
| 793 | 793 |
| 794 | 794 |
| 795 static void EmitStoreIndexedPolymorphic(FlowGraphCompiler* compiler, | 795 static void EmitStoreIndexedPolymorphic(FlowGraphCompiler* compiler, |
| 796 StoreIndexedComp* comp) { | 796 StoreIndexedComp* comp) { |
| 797 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 797 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 798 comp->token_index(), | 798 comp->token_index(), |
| 799 comp->try_index(), | 799 comp->try_index(), |
| 800 kDeoptStoreIndexedPolymorphic); | 800 kDeoptStoreIndexedPolymorphic); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 833 } else { | 833 } else { |
| 834 EmitStoreIndexedGeneric(compiler, this); | 834 EmitStoreIndexedGeneric(compiler, this); |
| 835 } | 835 } |
| 836 return; | 836 return; |
| 837 } | 837 } |
| 838 | 838 |
| 839 Register receiver = locs()->in(0).reg(); | 839 Register receiver = locs()->in(0).reg(); |
| 840 Register index = locs()->in(1).reg(); | 840 Register index = locs()->in(1).reg(); |
| 841 Register value = locs()->in(2).reg(); | 841 Register value = locs()->in(2).reg(); |
| 842 | 842 |
| 843 const Class& receiver_class = | |
| 844 Class::ZoneHandle(Isolate::Current()->class_table()->At( | |
| 845 receiver_type())); | |
| 846 | |
| 847 Label* deopt = compiler->AddDeoptStub(cid(), | 843 Label* deopt = compiler->AddDeoptStub(cid(), |
| 848 token_index(), | 844 token_index(), |
| 849 try_index(), | 845 try_index(), |
| 850 kDeoptStoreIndexed, | 846 kDeoptStoreIndexed, |
| 851 receiver, | 847 receiver, |
| 852 index, | 848 index, |
| 853 value); | 849 value); |
| 854 | 850 |
| 855 __ testq(receiver, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 851 __ testq(receiver, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 856 __ j(ZERO, deopt); | 852 __ j(ZERO, deopt); |
| 857 __ CompareClassId(receiver, receiver_class.id()); | 853 __ CompareClassId(receiver, receiver_type()); |
| 858 __ j(NOT_EQUAL, deopt); | 854 __ j(NOT_EQUAL, deopt); |
| 859 | 855 |
| 860 __ testq(index, Immediate(kSmiTagMask)); | 856 __ testq(index, Immediate(kSmiTagMask)); |
| 861 __ j(NOT_ZERO, deopt); | 857 __ j(NOT_ZERO, deopt); |
| 862 | 858 |
| 863 switch (receiver_type()) { | 859 switch (receiver_type()) { |
| 864 case kArray: | 860 case kArray: |
| 865 case kImmutableArray: | 861 case kImmutableArray: |
| 866 __ cmpq(index, FieldAddress(receiver, Array::length_offset())); | 862 __ cmpq(index, FieldAddress(receiver, Array::length_offset())); |
| 867 __ j(ABOVE_EQUAL, deopt); | 863 __ j(ABOVE_EQUAL, deopt); |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1025 locs->set_temp(0, Location::RegisterLocation(R10)); | 1021 locs->set_temp(0, Location::RegisterLocation(R10)); |
| 1026 locs->set_out(Location::RegisterLocation(RAX)); | 1022 locs->set_out(Location::RegisterLocation(RAX)); |
| 1027 return locs; | 1023 return locs; |
| 1028 } | 1024 } |
| 1029 | 1025 |
| 1030 | 1026 |
| 1031 void CreateArrayComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1027 void CreateArrayComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1032 Register temp_reg = locs()->temp(0).reg(); | 1028 Register temp_reg = locs()->temp(0).reg(); |
| 1033 Register result_reg = locs()->out().reg(); | 1029 Register result_reg = locs()->out().reg(); |
| 1034 | 1030 |
| 1035 // 1. Allocate the array. R10 = length, RBX = element type. | 1031 // Allocate the array. R10 = length, RBX = element type. |
| 1036 ASSERT(temp_reg == R10); | 1032 ASSERT(temp_reg == R10); |
| 1037 ASSERT(locs()->in(0).reg() == RBX); | 1033 ASSERT(locs()->in(0).reg() == RBX); |
| 1038 __ movq(temp_reg, Immediate(Smi::RawValue(ElementCount()))); | 1034 __ movq(temp_reg, Immediate(Smi::RawValue(ElementCount()))); |
| 1039 compiler->GenerateCall(token_index(), | 1035 compiler->GenerateCall(token_index(), |
| 1040 try_index(), | 1036 try_index(), |
| 1041 &StubCode::AllocateArrayLabel(), | 1037 &StubCode::AllocateArrayLabel(), |
| 1042 PcDescriptors::kOther); | 1038 PcDescriptors::kOther); |
| 1043 ASSERT(result_reg == RAX); | 1039 ASSERT(result_reg == RAX); |
| 1044 // 2. Initialize the array in result_reg with the element values. | 1040 |
| 1041 // Pop the element values from the stack into the array. |
| 1045 __ leaq(temp_reg, FieldAddress(result_reg, Array::data_offset())); | 1042 __ leaq(temp_reg, FieldAddress(result_reg, Array::data_offset())); |
| 1046 for (int i = ElementCount() - 1; i >= 0; --i) { | 1043 for (int i = ElementCount() - 1; i >= 0; --i) { |
| 1047 ASSERT(ElementAt(i)->IsUse()); | 1044 ASSERT(ElementAt(i)->IsUse()); |
| 1048 __ popq(Address(temp_reg, i * kWordSize)); | 1045 __ popq(Address(temp_reg, i * kWordSize)); |
| 1049 } | 1046 } |
| 1050 } | 1047 } |
| 1051 | 1048 |
| 1052 | 1049 |
| 1053 LocationSummary* AllocateObjectWithBoundsCheckComp:: | 1050 LocationSummary* |
| 1054 MakeLocationSummary() const { | 1051 AllocateObjectWithBoundsCheckComp::MakeLocationSummary() const { |
| 1055 return LocationSummary::Make(2, | 1052 return LocationSummary::Make(2, |
| 1056 Location::RequiresRegister(), | 1053 Location::RequiresRegister(), |
| 1057 LocationSummary::kCall); | 1054 LocationSummary::kCall); |
| 1058 } | 1055 } |
| 1059 | 1056 |
| 1060 | 1057 |
| 1061 void AllocateObjectWithBoundsCheckComp::EmitNativeCode( | 1058 void AllocateObjectWithBoundsCheckComp::EmitNativeCode( |
| 1062 FlowGraphCompiler* compiler) { | 1059 FlowGraphCompiler* compiler) { |
| 1063 const Class& cls = Class::ZoneHandle(constructor().owner()); | 1060 const Class& cls = Class::ZoneHandle(constructor().owner()); |
| 1064 Register type_arguments = locs()->in(0).reg(); | 1061 Register type_arguments = locs()->in(0).reg(); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1133 Label type_arguments_instantiated; | 1130 Label type_arguments_instantiated; |
| 1134 const intptr_t len = type_arguments().Length(); | 1131 const intptr_t len = type_arguments().Length(); |
| 1135 if (type_arguments().IsRawInstantiatedRaw(len)) { | 1132 if (type_arguments().IsRawInstantiatedRaw(len)) { |
| 1136 const Immediate raw_null = | 1133 const Immediate raw_null = |
| 1137 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1134 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1138 __ cmpq(instantiator_reg, raw_null); | 1135 __ cmpq(instantiator_reg, raw_null); |
| 1139 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1136 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1140 } | 1137 } |
| 1141 // Instantiate non-null type arguments. | 1138 // Instantiate non-null type arguments. |
| 1142 if (type_arguments().IsUninstantiatedIdentity()) { | 1139 if (type_arguments().IsUninstantiatedIdentity()) { |
| 1143 Label type_arguments_uninstantiated; | |
| 1144 // Check if the instantiator type argument vector is a TypeArguments of a | 1140 // Check if the instantiator type argument vector is a TypeArguments of a |
| 1145 // matching length and, if so, use it as the instantiated type_arguments. | 1141 // matching length and, if so, use it as the instantiated type_arguments. |
| 1146 // No need to check the instantiator ('instantiator_reg') for null here, | 1142 // No need to check the instantiator ('instantiator_reg') for null here, |
| 1147 // because a null instantiator will have the wrong class (Null instead of | 1143 // because a null instantiator will have the wrong class (Null instead of |
| 1148 // TypeArguments). | 1144 // TypeArguments). |
| 1145 Label type_arguments_uninstantiated; |
| 1149 __ CompareClassId(instantiator_reg, kTypeArguments); | 1146 __ CompareClassId(instantiator_reg, kTypeArguments); |
| 1150 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); | 1147 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); |
| 1151 __ cmpq(FieldAddress(instantiator_reg, TypeArguments::length_offset()), | 1148 __ cmpq(FieldAddress(instantiator_reg, TypeArguments::length_offset()), |
| 1152 Immediate(Smi::RawValue(len))); | 1149 Immediate(Smi::RawValue(len))); |
| 1153 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1150 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1154 __ Bind(&type_arguments_uninstantiated); | 1151 __ Bind(&type_arguments_uninstantiated); |
| 1155 } | 1152 } |
| 1156 // A runtime call to instantiate the type arguments is required. | 1153 // A runtime call to instantiate the type arguments is required. |
| 1157 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1154 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1158 __ PushObject(type_arguments()); | 1155 __ PushObject(type_arguments()); |
| 1159 __ pushq(instantiator_reg); // Push instantiator type arguments. | 1156 __ pushq(instantiator_reg); // Push instantiator type arguments. |
| 1160 compiler->GenerateCallRuntime(cid(), | 1157 compiler->GenerateCallRuntime(cid(), |
| 1161 token_index(), | 1158 token_index(), |
| 1162 try_index(), | 1159 try_index(), |
| 1163 kInstantiateTypeArgumentsRuntimeEntry); | 1160 kInstantiateTypeArgumentsRuntimeEntry); |
| 1164 __ Drop(2); // Drop instantiator and uninstantiated type arguments. | 1161 __ Drop(2); // Drop instantiator and uninstantiated type arguments. |
| 1165 __ popq(result_reg); // Pop instantiated type arguments. | 1162 __ popq(result_reg); // Pop instantiated type arguments. |
| 1166 __ Bind(&type_arguments_instantiated); | 1163 __ Bind(&type_arguments_instantiated); |
| 1167 ASSERT(instantiator_reg == result_reg); | 1164 ASSERT(instantiator_reg == result_reg); |
| 1168 // 'result_reg': Instantiated type arguments. | 1165 // 'result_reg': Instantiated type arguments. |
| 1169 } | 1166 } |
| 1170 | 1167 |
| 1171 | 1168 |
| 1172 LocationSummary* ExtractConstructorTypeArgumentsComp:: | 1169 LocationSummary* |
| 1173 MakeLocationSummary() const { | 1170 ExtractConstructorTypeArgumentsComp::MakeLocationSummary() const { |
| 1174 const intptr_t kNumInputs = 1; | 1171 const intptr_t kNumInputs = 1; |
| 1175 const intptr_t kNumTemps = 0; | 1172 const intptr_t kNumTemps = 0; |
| 1176 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | 1173 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 1177 locs->set_in(0, Location::RequiresRegister()); | 1174 locs->set_in(0, Location::RequiresRegister()); |
| 1178 locs->set_out(Location::SameAsFirstInput()); | 1175 locs->set_out(Location::SameAsFirstInput()); |
| 1179 return locs; | 1176 return locs; |
| 1180 } | 1177 } |
| 1181 | 1178 |
| 1182 | 1179 |
| 1183 void ExtractConstructorTypeArgumentsComp::EmitNativeCode( | 1180 void ExtractConstructorTypeArgumentsComp::EmitNativeCode( |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1217 } | 1214 } |
| 1218 // In the non-factory case, we rely on the allocation stub to | 1215 // In the non-factory case, we rely on the allocation stub to |
| 1219 // instantiate the type arguments. | 1216 // instantiate the type arguments. |
| 1220 __ LoadObject(result_reg, type_arguments()); | 1217 __ LoadObject(result_reg, type_arguments()); |
| 1221 // result_reg: uninstantiated type arguments. | 1218 // result_reg: uninstantiated type arguments. |
| 1222 __ Bind(&type_arguments_instantiated); | 1219 __ Bind(&type_arguments_instantiated); |
| 1223 // result_reg: uninstantiated or instantiated type arguments. | 1220 // result_reg: uninstantiated or instantiated type arguments. |
| 1224 } | 1221 } |
| 1225 | 1222 |
| 1226 | 1223 |
| 1227 LocationSummary* ExtractConstructorInstantiatorComp:: | 1224 LocationSummary* |
| 1228 MakeLocationSummary() const { | 1225 ExtractConstructorInstantiatorComp::MakeLocationSummary() const { |
| 1229 const intptr_t kNumInputs = 1; | 1226 const intptr_t kNumInputs = 1; |
| 1230 const intptr_t kNumTemps = 0; | 1227 const intptr_t kNumTemps = 0; |
| 1231 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | 1228 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 1232 locs->set_in(0, Location::RequiresRegister()); | 1229 locs->set_in(0, Location::RequiresRegister()); |
| 1233 locs->set_out(Location::SameAsFirstInput()); | 1230 locs->set_out(Location::SameAsFirstInput()); |
| 1234 return locs; | 1231 return locs; |
| 1235 } | 1232 } |
| 1236 | 1233 |
| 1237 | 1234 |
| 1238 void ExtractConstructorInstantiatorComp::EmitNativeCode( | 1235 void ExtractConstructorInstantiatorComp::EmitNativeCode( |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 kNumTemps, | 1293 kNumTemps, |
| 1297 LocationSummary::kCall); | 1294 LocationSummary::kCall); |
| 1298 locs->set_temp(0, Location::RegisterLocation(R10)); | 1295 locs->set_temp(0, Location::RegisterLocation(R10)); |
| 1299 locs->set_out(Location::RegisterLocation(RAX)); | 1296 locs->set_out(Location::RegisterLocation(RAX)); |
| 1300 return locs; | 1297 return locs; |
| 1301 } | 1298 } |
| 1302 | 1299 |
| 1303 | 1300 |
| 1304 void AllocateContextComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1301 void AllocateContextComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1305 ASSERT(locs()->temp(0).reg() == R10); | 1302 ASSERT(locs()->temp(0).reg() == R10); |
| 1303 ASSERT(locs()->out().reg() == RAX); |
| 1306 | 1304 |
| 1307 __ movq(R10, Immediate(num_context_variables())); | 1305 __ movq(R10, Immediate(num_context_variables())); |
| 1308 const ExternalLabel label("alloc_context", | 1306 const ExternalLabel label("alloc_context", |
| 1309 StubCode::AllocateContextEntryPoint()); | 1307 StubCode::AllocateContextEntryPoint()); |
| 1310 compiler->GenerateCall(token_index(), | 1308 compiler->GenerateCall(token_index(), |
| 1311 try_index(), | 1309 try_index(), |
| 1312 &label, | 1310 &label, |
| 1313 PcDescriptors::kOther); | 1311 PcDescriptors::kOther); |
| 1314 } | 1312 } |
| 1315 | 1313 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1421 return summary; | 1419 return summary; |
| 1422 } else if (op_kind() == Token::kSHR) { | 1420 } else if (op_kind() == Token::kSHR) { |
| 1423 const intptr_t kNumTemps = 1; | 1421 const intptr_t kNumTemps = 1; |
| 1424 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 1422 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 1425 summary->set_in(0, Location::RequiresRegister()); | 1423 summary->set_in(0, Location::RequiresRegister()); |
| 1426 summary->set_in(1, Location::RegisterLocation(RCX)); | 1424 summary->set_in(1, Location::RegisterLocation(RCX)); |
| 1427 summary->set_out(Location::SameAsFirstInput()); | 1425 summary->set_out(Location::SameAsFirstInput()); |
| 1428 summary->set_temp(0, Location::RequiresRegister()); | 1426 summary->set_temp(0, Location::RequiresRegister()); |
| 1429 return summary; | 1427 return summary; |
| 1430 } else if (op_kind() == Token::kSHL) { | 1428 } else if (op_kind() == Token::kSHL) { |
| 1429 // Two Smi operands can easily overflow into Mint. |
| 1431 const intptr_t kNumTemps = 2; | 1430 const intptr_t kNumTemps = 2; |
| 1432 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 1431 LocationSummary* summary = |
| 1433 summary->set_in(0, Location::RequiresRegister()); | 1432 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 1433 summary->set_in(0, Location::RegisterLocation(RAX)); |
| 1434 summary->set_in(1, Location::RequiresRegister()); | 1434 summary->set_in(1, Location::RequiresRegister()); |
| 1435 summary->set_out(Location::SameAsFirstInput()); | 1435 summary->set_out(Location::SameAsFirstInput()); |
| 1436 summary->set_temp(0, Location::RequiresRegister()); | 1436 summary->set_temp(0, Location::RequiresRegister()); |
| 1437 summary->set_temp(1, Location::RegisterLocation(RCX)); | 1437 summary->set_temp(1, Location::RegisterLocation(RCX)); |
| 1438 return summary; | 1438 return summary; |
| 1439 } else { | 1439 } else { |
| 1440 const intptr_t kNumTemps = 1; | 1440 const intptr_t kNumTemps = 1; |
| 1441 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 1441 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 1442 summary->set_in(0, Location::RequiresRegister()); | 1442 summary->set_in(0, Location::RequiresRegister()); |
| 1443 summary->set_in(1, Location::RequiresRegister()); | 1443 summary->set_in(1, Location::RequiresRegister()); |
| 1444 summary->set_out(Location::SameAsFirstInput()); | 1444 summary->set_out(Location::SameAsFirstInput()); |
| 1445 summary->set_temp(0, Location::RequiresRegister()); | 1445 summary->set_temp(0, Location::RequiresRegister()); |
| 1446 return summary; | 1446 return summary; |
| 1447 } | 1447 } |
| 1448 } | 1448 } |
| 1449 | 1449 |
| 1450 | 1450 |
| 1451 static void EmitSmiBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) { | 1451 static void EmitSmiBinaryOp(FlowGraphCompiler* compiler, BinaryOpComp* comp) { |
| 1452 Register left = comp->locs()->in(0).reg(); | 1452 Register left = comp->locs()->in(0).reg(); |
| 1453 Register right = comp->locs()->in(1).reg(); | 1453 Register right = comp->locs()->in(1).reg(); |
| 1454 Register result = comp->locs()->out().reg(); | 1454 Register result = comp->locs()->out().reg(); |
| 1455 Register temp = comp->locs()->temp(0).reg(); | 1455 Register temp = comp->locs()->temp(0).reg(); |
| 1456 ASSERT(left == result); | 1456 ASSERT(left == result); |
| 1457 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), | 1457 Label* deopt = compiler->AddDeoptStub(comp->instance_call()->cid(), |
| 1458 comp->instance_call()->token_index(), | 1458 comp->instance_call()->token_index(), |
| 1459 comp->instance_call()->try_index(), | 1459 comp->instance_call()->try_index(), |
| 1460 kDeoptSmiBinaryOp, | 1460 kDeoptSmiBinaryOp, |
| 1461 temp, | 1461 temp, |
| 1462 right); | 1462 right); |
| 1463 // TODO(vegorov): for many binary operations this pattern can be rearranged |
| 1464 // to save one move. |
| 1463 __ movq(temp, left); | 1465 __ movq(temp, left); |
| 1464 __ orq(left, right); | 1466 __ orq(left, right); |
| 1465 __ testq(left, Immediate(kSmiTagMask)); | 1467 __ testq(left, Immediate(kSmiTagMask)); |
| 1466 __ j(NOT_ZERO, deopt); | 1468 __ j(NOT_ZERO, deopt); |
| 1467 __ movq(left, temp); | 1469 __ movq(left, temp); |
| 1468 switch (comp->op_kind()) { | 1470 switch (comp->op_kind()) { |
| 1469 case Token::kADD: { | 1471 case Token::kADD: { |
| 1470 __ addq(left, right); | 1472 __ addq(left, right); |
| 1471 __ j(OVERFLOW, deopt); | 1473 __ j(OVERFLOW, deopt); |
| 1472 break; | 1474 break; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1531 __ j(LESS, &count_ok, Assembler::kNearJump); | 1533 __ j(LESS, &count_ok, Assembler::kNearJump); |
| 1532 __ movq(right, kCountLimit); | 1534 __ movq(right, kCountLimit); |
| 1533 __ Bind(&count_ok); | 1535 __ Bind(&count_ok); |
| 1534 ASSERT(right == RCX); // Count must be in RCX | 1536 ASSERT(right == RCX); // Count must be in RCX |
| 1535 __ SmiUntag(left); | 1537 __ SmiUntag(left); |
| 1536 __ sarq(left, right); | 1538 __ sarq(left, right); |
| 1537 __ SmiTag(left); | 1539 __ SmiTag(left); |
| 1538 break; | 1540 break; |
| 1539 } | 1541 } |
| 1540 case Token::kSHL: { | 1542 case Token::kSHL: { |
| 1543 Label call_method, done; |
| 1541 // Check if count too large for handling it inlined. | 1544 // Check if count too large for handling it inlined. |
| 1542 __ cmpq(right, | 1545 __ cmpq(right, |
| 1543 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits)))); | 1546 Immediate(reinterpret_cast<int64_t>(Smi::New(Smi::kBits)))); |
| 1544 __ j(ABOVE_EQUAL, deopt); | 1547 __ j(ABOVE_EQUAL, &call_method, Assembler::kNearJump); |
| 1545 Register right_temp = comp->locs()->temp(1).reg(); | 1548 Register right_temp = comp->locs()->temp(1).reg(); |
| 1546 ASSERT(right_temp == RCX); // Count must be in RCX | 1549 ASSERT(right_temp == RCX); // Count must be in RCX |
| 1547 __ movq(right_temp, right); | 1550 __ movq(right_temp, right); |
| 1548 __ SmiUntag(right_temp); | 1551 __ SmiUntag(right_temp); |
| 1549 // Overflow test (preserve temp and right); | 1552 // Overflow test (preserve temp and right); |
| 1550 __ shlq(left, right_temp); | 1553 __ shlq(left, right_temp); |
| 1551 __ sarq(left, right_temp); | 1554 __ sarq(left, right_temp); |
| 1552 __ cmpq(left, temp); | 1555 __ cmpq(left, temp); |
| 1553 __ j(NOT_EQUAL, deopt); // Overflow. | 1556 __ j(NOT_EQUAL, &call_method, Assembler::kNearJump); // Overflow. |
| 1554 // Shift for result now we know there is no overflow. | 1557 // Shift for result now we know there is no overflow. |
| 1555 __ shlq(left, right_temp); | 1558 __ shlq(left, right_temp); |
| 1559 __ jmp(&done); |
| 1560 { |
| 1561 __ Bind(&call_method); |
| 1562 Function& target = Function::ZoneHandle( |
| 1563 comp->ic_data()->GetTargetForReceiverClassId(kSmi)); |
| 1564 ASSERT(!target.IsNull()); |
| 1565 const intptr_t kArgumentCount = 2; |
| 1566 __ pushq(temp); |
| 1567 __ pushq(right); |
| 1568 compiler->GenerateStaticCall(comp->instance_call()->cid(), |
| 1569 comp->instance_call()->token_index(), |
| 1570 comp->instance_call()->try_index(), |
| 1571 target, |
| 1572 kArgumentCount, |
| 1573 Array::Handle()); // No argument names. |
| 1574 ASSERT(result == RAX); |
| 1575 } |
| 1576 __ Bind(&done); |
| 1556 break; | 1577 break; |
| 1557 } | 1578 } |
| 1558 case Token::kDIV: { | 1579 case Token::kDIV: { |
| 1559 // Dispatches to 'Double./'. | 1580 // Dispatches to 'Double./'. |
| 1560 // TODO(srdjan): Implement as conversion to double and double division. | 1581 // TODO(srdjan): Implement as conversion to double and double division. |
| 1561 UNREACHABLE(); | 1582 UNREACHABLE(); |
| 1562 break; | 1583 break; |
| 1563 } | 1584 } |
| 1564 case Token::kMOD: { | 1585 case Token::kMOD: { |
| 1565 // TODO(srdjan): Implement. | 1586 // TODO(srdjan): Implement. |
| (...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1846 LocationSummary* ToDoubleComp::MakeLocationSummary() const { | 1867 LocationSummary* ToDoubleComp::MakeLocationSummary() const { |
| 1847 const intptr_t kNumInputs = 1; | 1868 const intptr_t kNumInputs = 1; |
| 1848 if (from() == kDouble) { | 1869 if (from() == kDouble) { |
| 1849 const intptr_t kNumTemps = 0; | 1870 const intptr_t kNumTemps = 0; |
| 1850 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | 1871 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 1851 locs->set_in(0, Location::RequiresRegister()); | 1872 locs->set_in(0, Location::RequiresRegister()); |
| 1852 locs->set_out(Location::SameAsFirstInput()); | 1873 locs->set_out(Location::SameAsFirstInput()); |
| 1853 return locs; | 1874 return locs; |
| 1854 } else { | 1875 } else { |
| 1855 ASSERT(from() == kSmi); | 1876 ASSERT(from() == kSmi); |
| 1856 return MakeCallSummary(); | 1877 return MakeCallSummary(); // Calls a stub to allocate result. |
| 1857 } | 1878 } |
| 1858 } | 1879 } |
| 1859 | 1880 |
| 1860 | 1881 |
| 1861 void ToDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1882 void ToDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1862 Register value = (from() == kDouble) ? locs()->in(0).reg() : RBX; | 1883 Register value = (from() == kDouble) ? locs()->in(0).reg() : RBX; |
| 1863 Register result = locs()->out().reg(); | 1884 Register result = locs()->out().reg(); |
| 1864 | 1885 |
| 1865 const DeoptReasonId deopt_reason = (from() == kDouble) ? | 1886 const DeoptReasonId deopt_reason = (from() == kDouble) ? |
| 1866 kDeoptDoubleToDouble : kDeoptIntegerToDouble; | 1887 kDeoptDoubleToDouble : kDeoptIntegerToDouble; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1879 return; | 1900 return; |
| 1880 } | 1901 } |
| 1881 | 1902 |
| 1882 ASSERT(from() == kSmi); | 1903 ASSERT(from() == kSmi); |
| 1883 | 1904 |
| 1884 const Class& double_class = compiler->double_class(); | 1905 const Class& double_class = compiler->double_class(); |
| 1885 const Code& stub = | 1906 const Code& stub = |
| 1886 Code::Handle(StubCode::GetAllocationStubForClass(double_class)); | 1907 Code::Handle(StubCode::GetAllocationStubForClass(double_class)); |
| 1887 const ExternalLabel label(double_class.ToCString(), stub.EntryPoint()); | 1908 const ExternalLabel label(double_class.ToCString(), stub.EntryPoint()); |
| 1888 | 1909 |
| 1889 // TODO(vegorov): allocate box in the driver loop to avoid pushing and poping. | 1910 // TODO(vegorov): allocate box in the driver loop to avoid spilling. |
| 1890 compiler->GenerateCall(instance_call()->token_index(), | 1911 compiler->GenerateCall(instance_call()->token_index(), |
| 1891 instance_call()->try_index(), | 1912 instance_call()->try_index(), |
| 1892 &label, | 1913 &label, |
| 1893 PcDescriptors::kOther); | 1914 PcDescriptors::kOther); |
| 1894 ASSERT(result == RAX); | 1915 ASSERT(result == RAX); |
| 1895 __ popq(value); | 1916 __ popq(value); |
| 1896 | 1917 |
| 1897 __ testq(value, Immediate(kSmiTagMask)); | 1918 __ testq(value, Immediate(kSmiTagMask)); |
| 1898 __ j(NOT_ZERO, deopt); // Deoptimize if not Smi. | 1919 __ j(NOT_ZERO, deopt); // Deoptimize if not Smi. |
| 1899 __ SmiUntag(value); | 1920 __ SmiUntag(value); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1915 kDeoptPolymorphicInstanceCallTestFail); | 1936 kDeoptPolymorphicInstanceCallTestFail); |
| 1916 if (!HasICData() || (ic_data()->NumberOfChecks() == 0)) { | 1937 if (!HasICData() || (ic_data()->NumberOfChecks() == 0)) { |
| 1917 __ jmp(deopt); | 1938 __ jmp(deopt); |
| 1918 return; | 1939 return; |
| 1919 } | 1940 } |
| 1920 ASSERT(HasICData()); | 1941 ASSERT(HasICData()); |
| 1921 ASSERT(ic_data()->num_args_tested() == 1); | 1942 ASSERT(ic_data()->num_args_tested() == 1); |
| 1922 Label handle_smi; | 1943 Label handle_smi; |
| 1923 Label* is_smi_label = | 1944 Label* is_smi_label = |
| 1924 ic_data()->GetReceiverClassIdAt(0) == kSmi ? &handle_smi : deopt; | 1945 ic_data()->GetReceiverClassIdAt(0) == kSmi ? &handle_smi : deopt; |
| 1946 |
| 1925 // Load receiver into RAX. | 1947 // Load receiver into RAX. |
| 1926 __ movq(RAX, | 1948 __ movq(RAX, |
| 1927 Address(RSP, (instance_call()->ArgumentCount() - 1) * kWordSize)); | 1949 Address(RSP, (instance_call()->ArgumentCount() - 1) * kWordSize)); |
| 1928 __ testq(RAX, Immediate(kSmiTagMask)); | 1950 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1929 __ j(ZERO, is_smi_label); | 1951 __ j(ZERO, is_smi_label); |
| 1930 Label done; | 1952 Label done; |
| 1931 __ LoadClassId(RDI, RAX); | 1953 __ LoadClassId(RDI, RAX); |
| 1932 compiler->EmitTestAndCall(*ic_data(), | 1954 compiler->EmitTestAndCall(*ic_data(), |
| 1933 RDI, // Class id register. | 1955 RDI, // Class id register. |
| 1934 instance_call()->ArgumentCount(), | 1956 instance_call()->ArgumentCount(), |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1949 instance_call()->argument_names()); | 1971 instance_call()->argument_names()); |
| 1950 } | 1972 } |
| 1951 __ Bind(&done); | 1973 __ Bind(&done); |
| 1952 } | 1974 } |
| 1953 | 1975 |
| 1954 } // namespace dart | 1976 } // namespace dart |
| 1955 | 1977 |
| 1956 #undef __ | 1978 #undef __ |
| 1957 | 1979 |
| 1958 #endif // defined TARGET_ARCH_X64 | 1980 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |