| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| 11 #include "vm/dart_entry.h" |
| 11 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/locations.h" | 13 #include "vm/locations.h" |
| 13 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 14 #include "vm/parser.h" | 15 #include "vm/parser.h" |
| 15 #include "vm/stub_code.h" | 16 #include "vm/stub_code.h" |
| 16 #include "vm/symbols.h" | 17 #include "vm/symbols.h" |
| 17 | 18 |
| 18 #define __ compiler->assembler()-> | 19 #define __ compiler->assembler()-> |
| 19 | 20 |
| 20 namespace dart { | 21 namespace dart { |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 | 261 |
| 261 | 262 |
| 262 LocationSummary* EqualityCompareInstr::MakeLocationSummary() const { | 263 LocationSummary* EqualityCompareInstr::MakeLocationSummary() const { |
| 263 const intptr_t kNumInputs = 2; | 264 const intptr_t kNumInputs = 2; |
| 264 const bool is_checked_strict_equal = | 265 const bool is_checked_strict_equal = |
| 265 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); | 266 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 266 if (receiver_class_id() == kMintCid) { | 267 if (receiver_class_id() == kMintCid) { |
| 267 const intptr_t kNumTemps = 1; | 268 const intptr_t kNumTemps = 1; |
| 268 LocationSummary* locs = | 269 LocationSummary* locs = |
| 269 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 270 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 270 locs->set_in(0, Location::RequiresXmmRegister()); | 271 locs->set_in(0, Location::RequiresFpuRegister()); |
| 271 locs->set_in(1, Location::RequiresXmmRegister()); | 272 locs->set_in(1, Location::RequiresFpuRegister()); |
| 272 locs->set_temp(0, Location::RequiresRegister()); | 273 locs->set_temp(0, Location::RequiresRegister()); |
| 273 locs->set_out(Location::RequiresRegister()); | 274 locs->set_out(Location::RequiresRegister()); |
| 274 return locs; | 275 return locs; |
| 275 } | 276 } |
| 276 if (receiver_class_id() == kDoubleCid) { | 277 if (receiver_class_id() == kDoubleCid) { |
| 277 const intptr_t kNumTemps = 0; | 278 const intptr_t kNumTemps = 0; |
| 278 LocationSummary* locs = | 279 LocationSummary* locs = |
| 279 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 280 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 280 locs->set_in(0, Location::RequiresXmmRegister()); | 281 locs->set_in(0, Location::RequiresFpuRegister()); |
| 281 locs->set_in(1, Location::RequiresXmmRegister()); | 282 locs->set_in(1, Location::RequiresFpuRegister()); |
| 282 locs->set_out(Location::RequiresRegister()); | 283 locs->set_out(Location::RequiresRegister()); |
| 283 return locs; | 284 return locs; |
| 284 } | 285 } |
| 285 if (receiver_class_id() == kSmiCid) { | 286 if (receiver_class_id() == kSmiCid) { |
| 286 const intptr_t kNumTemps = 0; | 287 const intptr_t kNumTemps = 0; |
| 287 LocationSummary* locs = | 288 LocationSummary* locs = |
| 288 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 289 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 289 locs->set_in(0, Location::RegisterOrConstant(left())); | 290 locs->set_in(0, Location::RegisterOrConstant(left())); |
| 290 // Only one input can be a constant operand. The case of two constant | 291 // Only one input can be a constant operand. The case of two constant |
| 291 // operands should be handled by constant propagation. | 292 // operands should be handled by constant propagation. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 const ICData& original_ic_data) { | 335 const ICData& original_ic_data) { |
| 335 if (!compiler->is_optimizing()) { | 336 if (!compiler->is_optimizing()) { |
| 336 compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore, | 337 compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore, |
| 337 deopt_id, | 338 deopt_id, |
| 338 token_pos); | 339 token_pos); |
| 339 } | 340 } |
| 340 const int kNumberOfArguments = 2; | 341 const int kNumberOfArguments = 2; |
| 341 const Array& kNoArgumentNames = Array::Handle(); | 342 const Array& kNoArgumentNames = Array::Handle(); |
| 342 const int kNumArgumentsChecked = 2; | 343 const int kNumArgumentsChecked = 2; |
| 343 | 344 |
| 344 const Immediate raw_null = | 345 const Immediate& raw_null = |
| 345 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 346 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 346 Label check_identity; | 347 Label check_identity; |
| 347 __ cmpl(Address(ESP, 0 * kWordSize), raw_null); | 348 __ cmpl(Address(ESP, 0 * kWordSize), raw_null); |
| 348 __ j(EQUAL, &check_identity); | 349 __ j(EQUAL, &check_identity); |
| 349 __ cmpl(Address(ESP, 1 * kWordSize), raw_null); | 350 __ cmpl(Address(ESP, 1 * kWordSize), raw_null); |
| 350 __ j(EQUAL, &check_identity); | 351 __ j(EQUAL, &check_identity); |
| 351 | 352 |
| 352 ICData& equality_ic_data = ICData::ZoneHandle(); | 353 ICData& equality_ic_data = ICData::ZoneHandle(); |
| 353 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { | 354 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { |
| 354 ASSERT(!original_ic_data.IsNull()); | 355 ASSERT(!original_ic_data.IsNull()); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 BranchInstr* branch, | 521 BranchInstr* branch, |
| 521 intptr_t deopt_id) { | 522 intptr_t deopt_id) { |
| 522 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | 523 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 523 Register left = locs.in(0).reg(); | 524 Register left = locs.in(0).reg(); |
| 524 Register right = locs.in(1).reg(); | 525 Register right = locs.in(1).reg(); |
| 525 Register temp = locs.temp(0).reg(); | 526 Register temp = locs.temp(0).reg(); |
| 526 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); | 527 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); |
| 527 __ testl(left, Immediate(kSmiTagMask)); | 528 __ testl(left, Immediate(kSmiTagMask)); |
| 528 __ j(ZERO, deopt); | 529 __ j(ZERO, deopt); |
| 529 // 'left' is not Smi. | 530 // 'left' is not Smi. |
| 530 const Immediate raw_null = | 531 const Immediate& raw_null = |
| 531 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 532 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 532 Label identity_compare; | 533 Label identity_compare; |
| 533 __ cmpl(right, raw_null); | 534 __ cmpl(right, raw_null); |
| 534 __ j(EQUAL, &identity_compare); | 535 __ j(EQUAL, &identity_compare); |
| 535 __ cmpl(left, raw_null); | 536 __ cmpl(left, raw_null); |
| 536 __ j(EQUAL, &identity_compare); | 537 __ j(EQUAL, &identity_compare); |
| 537 | 538 |
| 538 __ LoadClassId(temp, left); | 539 __ LoadClassId(temp, left); |
| 539 const intptr_t len = ic_data.NumberOfChecks(); | 540 const intptr_t len = ic_data.NumberOfChecks(); |
| 540 for (intptr_t i = 0; i < len; i++) { | 541 for (intptr_t i = 0; i < len; i++) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 571 LocationSummary* locs, | 572 LocationSummary* locs, |
| 572 Token::Kind kind, | 573 Token::Kind kind, |
| 573 BranchInstr* branch, | 574 BranchInstr* branch, |
| 574 const ICData& ic_data, | 575 const ICData& ic_data, |
| 575 intptr_t deopt_id, | 576 intptr_t deopt_id, |
| 576 intptr_t token_pos) { | 577 intptr_t token_pos) { |
| 577 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | 578 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 578 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); | 579 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 579 Register left = locs->in(0).reg(); | 580 Register left = locs->in(0).reg(); |
| 580 Register right = locs->in(1).reg(); | 581 Register right = locs->in(1).reg(); |
| 581 const Immediate raw_null = | 582 const Immediate& raw_null = |
| 582 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 583 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 583 Label done, identity_compare, non_null_compare; | 584 Label done, identity_compare, non_null_compare; |
| 584 __ cmpl(right, raw_null); | 585 __ cmpl(right, raw_null); |
| 585 __ j(EQUAL, &identity_compare, Assembler::kNearJump); | 586 __ j(EQUAL, &identity_compare, Assembler::kNearJump); |
| 586 __ cmpl(left, raw_null); | 587 __ cmpl(left, raw_null); |
| 587 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); | 588 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); |
| 588 // Comparison with NULL is "===". | 589 // Comparison with NULL is "===". |
| 589 __ Bind(&identity_compare); | 590 __ Bind(&identity_compare); |
| 590 __ cmpl(left, right); | 591 __ cmpl(left, right); |
| 591 Condition cond = TokenKindToSmiCondition(kind); | 592 Condition cond = TokenKindToSmiCondition(kind); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 return OVERFLOW; | 658 return OVERFLOW; |
| 658 } | 659 } |
| 659 } | 660 } |
| 660 | 661 |
| 661 | 662 |
| 662 static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, | 663 static void EmitUnboxedMintEqualityOp(FlowGraphCompiler* compiler, |
| 663 const LocationSummary& locs, | 664 const LocationSummary& locs, |
| 664 Token::Kind kind, | 665 Token::Kind kind, |
| 665 BranchInstr* branch) { | 666 BranchInstr* branch) { |
| 666 ASSERT(Token::IsEqualityOperator(kind)); | 667 ASSERT(Token::IsEqualityOperator(kind)); |
| 667 XmmRegister left = locs.in(0).xmm_reg(); | 668 XmmRegister left = locs.in(0).fpu_reg(); |
| 668 XmmRegister right = locs.in(1).xmm_reg(); | 669 XmmRegister right = locs.in(1).fpu_reg(); |
| 669 Register temp = locs.temp(0).reg(); | 670 Register temp = locs.temp(0).reg(); |
| 670 __ movaps(XMM0, left); | 671 __ movaps(XMM0, left); |
| 671 __ pcmpeqq(XMM0, right); | 672 __ pcmpeqq(XMM0, right); |
| 672 __ movd(temp, XMM0); | 673 __ movd(temp, XMM0); |
| 673 | 674 |
| 674 Condition true_condition = TokenKindToMintCondition(kind); | 675 Condition true_condition = TokenKindToMintCondition(kind); |
| 675 __ cmpl(temp, Immediate(-1)); | 676 __ cmpl(temp, Immediate(-1)); |
| 676 | 677 |
| 677 if (branch != NULL) { | 678 if (branch != NULL) { |
| 678 branch->EmitBranchOnCondition(compiler, true_condition); | 679 branch->EmitBranchOnCondition(compiler, true_condition); |
| 679 } else { | 680 } else { |
| 680 Register result = locs.out().reg(); | 681 Register result = locs.out().reg(); |
| 681 Label done, is_true; | 682 Label done, is_true; |
| 682 __ j(true_condition, &is_true); | 683 __ j(true_condition, &is_true); |
| 683 __ LoadObject(result, Bool::False()); | 684 __ LoadObject(result, Bool::False()); |
| 684 __ jmp(&done); | 685 __ jmp(&done); |
| 685 __ Bind(&is_true); | 686 __ Bind(&is_true); |
| 686 __ LoadObject(result, Bool::True()); | 687 __ LoadObject(result, Bool::True()); |
| 687 __ Bind(&done); | 688 __ Bind(&done); |
| 688 } | 689 } |
| 689 } | 690 } |
| 690 | 691 |
| 691 | 692 |
| 692 static void EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, | 693 static void EmitUnboxedMintComparisonOp(FlowGraphCompiler* compiler, |
| 693 const LocationSummary& locs, | 694 const LocationSummary& locs, |
| 694 Token::Kind kind, | 695 Token::Kind kind, |
| 695 BranchInstr* branch) { | 696 BranchInstr* branch) { |
| 696 XmmRegister left = locs.in(0).xmm_reg(); | 697 XmmRegister left = locs.in(0).fpu_reg(); |
| 697 XmmRegister right = locs.in(1).xmm_reg(); | 698 XmmRegister right = locs.in(1).fpu_reg(); |
| 698 Register left_tmp = locs.temp(0).reg(); | 699 Register left_tmp = locs.temp(0).reg(); |
| 699 Register right_tmp = locs.temp(1).reg(); | 700 Register right_tmp = locs.temp(1).reg(); |
| 700 Register result = branch == NULL ? locs.out().reg() : kNoRegister; | 701 Register result = branch == NULL ? locs.out().reg() : kNoRegister; |
| 701 | 702 |
| 702 Condition hi_cond = OVERFLOW, lo_cond = OVERFLOW; | 703 Condition hi_cond = OVERFLOW, lo_cond = OVERFLOW; |
| 703 switch (kind) { | 704 switch (kind) { |
| 704 case Token::kLT: | 705 case Token::kLT: |
| 705 hi_cond = LESS; | 706 hi_cond = LESS; |
| 706 lo_cond = BELOW; | 707 lo_cond = BELOW; |
| 707 break; | 708 break; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 766 UNREACHABLE(); | 767 UNREACHABLE(); |
| 767 return OVERFLOW; | 768 return OVERFLOW; |
| 768 } | 769 } |
| 769 } | 770 } |
| 770 | 771 |
| 771 | 772 |
| 772 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, | 773 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, |
| 773 const LocationSummary& locs, | 774 const LocationSummary& locs, |
| 774 Token::Kind kind, | 775 Token::Kind kind, |
| 775 BranchInstr* branch) { | 776 BranchInstr* branch) { |
| 776 XmmRegister left = locs.in(0).xmm_reg(); | 777 XmmRegister left = locs.in(0).fpu_reg(); |
| 777 XmmRegister right = locs.in(1).xmm_reg(); | 778 XmmRegister right = locs.in(1).fpu_reg(); |
| 778 | 779 |
| 779 Condition true_condition = TokenKindToDoubleCondition(kind); | 780 Condition true_condition = TokenKindToDoubleCondition(kind); |
| 780 if (branch != NULL) { | 781 if (branch != NULL) { |
| 781 compiler->EmitDoubleCompareBranch( | 782 compiler->EmitDoubleCompareBranch( |
| 782 true_condition, left, right, branch); | 783 true_condition, left, right, branch); |
| 783 } else { | 784 } else { |
| 784 compiler->EmitDoubleCompareBool( | 785 compiler->EmitDoubleCompareBool( |
| 785 true_condition, left, right, locs.out().reg()); | 786 true_condition, left, right, locs.out().reg()); |
| 786 } | 787 } |
| 787 } | 788 } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 876 } | 877 } |
| 877 | 878 |
| 878 | 879 |
| 879 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { | 880 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { |
| 880 const intptr_t kNumInputs = 2; | 881 const intptr_t kNumInputs = 2; |
| 881 const intptr_t kNumTemps = 0; | 882 const intptr_t kNumTemps = 0; |
| 882 if (operands_class_id() == kMintCid) { | 883 if (operands_class_id() == kMintCid) { |
| 883 const intptr_t kNumTemps = 2; | 884 const intptr_t kNumTemps = 2; |
| 884 LocationSummary* locs = | 885 LocationSummary* locs = |
| 885 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 886 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 886 locs->set_in(0, Location::RequiresXmmRegister()); | 887 locs->set_in(0, Location::RequiresFpuRegister()); |
| 887 locs->set_in(1, Location::RequiresXmmRegister()); | 888 locs->set_in(1, Location::RequiresFpuRegister()); |
| 888 locs->set_temp(0, Location::RequiresRegister()); | 889 locs->set_temp(0, Location::RequiresRegister()); |
| 889 locs->set_temp(1, Location::RequiresRegister()); | 890 locs->set_temp(1, Location::RequiresRegister()); |
| 890 locs->set_out(Location::RequiresRegister()); | 891 locs->set_out(Location::RequiresRegister()); |
| 891 return locs; | 892 return locs; |
| 892 } | 893 } |
| 893 if (operands_class_id() == kDoubleCid) { | 894 if (operands_class_id() == kDoubleCid) { |
| 894 LocationSummary* summary = | 895 LocationSummary* summary = |
| 895 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 896 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 896 summary->set_in(0, Location::RequiresXmmRegister()); | 897 summary->set_in(0, Location::RequiresFpuRegister()); |
| 897 summary->set_in(1, Location::RequiresXmmRegister()); | 898 summary->set_in(1, Location::RequiresFpuRegister()); |
| 898 summary->set_out(Location::RequiresRegister()); | 899 summary->set_out(Location::RequiresRegister()); |
| 899 return summary; | 900 return summary; |
| 900 } else if (operands_class_id() == kSmiCid) { | 901 } else if (operands_class_id() == kSmiCid) { |
| 901 LocationSummary* summary = | 902 LocationSummary* summary = |
| 902 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 903 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 903 summary->set_in(0, Location::RegisterOrConstant(left())); | 904 summary->set_in(0, Location::RegisterOrConstant(left())); |
| 904 // Only one input can be a constant operand. The case of two constant | 905 // Only one input can be a constant operand. The case of two constant |
| 905 // operands should be handled by constant propagation. | 906 // operands should be handled by constant propagation. |
| 906 summary->set_in(1, summary->in(0).IsConstant() | 907 summary->set_in(1, summary->in(0).IsConstant() |
| 907 ? Location::RequiresRegister() | 908 ? Location::RequiresRegister() |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1144 LocationSummary* locs = | 1145 LocationSummary* locs = |
| 1145 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 1146 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 1146 locs->set_in(0, Location::RequiresRegister()); | 1147 locs->set_in(0, Location::RequiresRegister()); |
| 1147 // The smi index is either untagged and tagged again at the end of the | 1148 // The smi index is either untagged and tagged again at the end of the |
| 1148 // operation (element size == 1), or it is left smi tagged (for all element | 1149 // operation (element size == 1), or it is left smi tagged (for all element |
| 1149 // sizes > 1). | 1150 // sizes > 1). |
| 1150 locs->set_in(1, CanBeImmediateIndex(index(), class_id()) | 1151 locs->set_in(1, CanBeImmediateIndex(index(), class_id()) |
| 1151 ? Location::RegisterOrSmiConstant(index()) | 1152 ? Location::RegisterOrSmiConstant(index()) |
| 1152 : Location::RequiresRegister()); | 1153 : Location::RequiresRegister()); |
| 1153 if (representation() == kUnboxedDouble) { | 1154 if (representation() == kUnboxedDouble) { |
| 1154 locs->set_out(Location::RequiresXmmRegister()); | 1155 locs->set_out(Location::RequiresFpuRegister()); |
| 1155 } else { | 1156 } else { |
| 1156 locs->set_out(Location::RequiresRegister()); | 1157 locs->set_out(Location::RequiresRegister()); |
| 1157 } | 1158 } |
| 1158 return locs; | 1159 return locs; |
| 1159 } | 1160 } |
| 1160 | 1161 |
| 1161 | 1162 |
| 1162 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1163 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1163 Register array = locs()->in(0).reg(); | 1164 Register array = locs()->in(0).reg(); |
| 1164 Location index = locs()->in(1); | 1165 Location index = locs()->in(1); |
| 1165 | 1166 |
| 1166 if (class_id() == kExternalUint8ArrayCid) { | 1167 if (class_id() == kExternalUint8ArrayCid) { |
| 1167 Register result = locs()->out().reg(); | 1168 Register result = locs()->out().reg(); |
| 1168 Address element_address = index.IsRegister() | 1169 const Address& element_address = index.IsRegister() |
| 1169 ? FlowGraphCompiler::ExternalElementAddressForRegIndex( | 1170 ? FlowGraphCompiler::ExternalElementAddressForRegIndex( |
| 1170 class_id(), result, index.reg()) | 1171 class_id(), result, index.reg()) |
| 1171 : FlowGraphCompiler::ExternalElementAddressForIntIndex( | 1172 : FlowGraphCompiler::ExternalElementAddressForIntIndex( |
| 1172 class_id(), result, Smi::Cast(index.constant()).Value()); | 1173 class_id(), result, Smi::Cast(index.constant()).Value()); |
| 1173 if (index.IsRegister()) { | 1174 if (index.IsRegister()) { |
| 1174 __ SmiUntag(index.reg()); | 1175 __ SmiUntag(index.reg()); |
| 1175 } | 1176 } |
| 1176 __ movl(result, | 1177 __ movl(result, |
| 1177 FieldAddress(array, ExternalUint8Array::external_data_offset())); | 1178 FieldAddress(array, ExternalUint8Array::external_data_offset())); |
| 1178 __ movl(result, | 1179 __ movl(result, |
| 1179 Address(result, ExternalByteArrayData<uint8_t>::data_offset())); | 1180 Address(result, ExternalByteArrayData<uint8_t>::data_offset())); |
| 1180 __ movzxb(result, element_address); | 1181 __ movzxb(result, element_address); |
| 1181 __ SmiTag(result); | 1182 __ SmiTag(result); |
| 1182 if (index.IsRegister()) { | 1183 if (index.IsRegister()) { |
| 1183 __ SmiTag(index.reg()); // Re-tag. | 1184 __ SmiTag(index.reg()); // Re-tag. |
| 1184 } | 1185 } |
| 1185 return; | 1186 return; |
| 1186 } | 1187 } |
| 1187 | 1188 |
| 1188 FieldAddress element_address = index.IsRegister() | 1189 FieldAddress element_address = index.IsRegister() |
| 1189 ? FlowGraphCompiler::ElementAddressForRegIndex( | 1190 ? FlowGraphCompiler::ElementAddressForRegIndex( |
| 1190 class_id(), array, index.reg()) | 1191 class_id(), array, index.reg()) |
| 1191 : FlowGraphCompiler::ElementAddressForIntIndex( | 1192 : FlowGraphCompiler::ElementAddressForIntIndex( |
| 1192 class_id(), array, Smi::Cast(index.constant()).Value()); | 1193 class_id(), array, Smi::Cast(index.constant()).Value()); |
| 1193 | 1194 |
| 1194 if (representation() == kUnboxedDouble) { | 1195 if (representation() == kUnboxedDouble) { |
| 1195 XmmRegister result = locs()->out().xmm_reg(); | 1196 XmmRegister result = locs()->out().fpu_reg(); |
| 1196 if (class_id() == kFloat32ArrayCid) { | 1197 if (class_id() == kFloat32ArrayCid) { |
| 1197 // Load single precision float. | 1198 // Load single precision float. |
| 1198 __ movss(result, element_address); | 1199 __ movss(result, element_address); |
| 1199 // Promote to double. | 1200 // Promote to double. |
| 1200 __ cvtss2sd(result, locs()->out().xmm_reg()); | 1201 __ cvtss2sd(result, locs()->out().fpu_reg()); |
| 1201 } else { | 1202 } else { |
| 1202 ASSERT(class_id() == kFloat64ArrayCid); | 1203 ASSERT(class_id() == kFloat64ArrayCid); |
| 1203 __ movsd(result, element_address); | 1204 __ movsd(result, element_address); |
| 1204 } | 1205 } |
| 1205 return; | 1206 return; |
| 1206 } | 1207 } |
| 1207 | 1208 |
| 1208 Register result = locs()->out().reg(); | 1209 Register result = locs()->out().reg(); |
| 1209 switch (class_id()) { | 1210 switch (class_id()) { |
| 1210 case kInt8ArrayCid: | 1211 case kInt8ArrayCid: |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1264 // EBX, ECX, EDX) instead of using a fixed register. | 1265 // EBX, ECX, EDX) instead of using a fixed register. |
| 1265 locs->set_in(2, Location::FixedRegisterOrSmiConstant(value(), EAX)); | 1266 locs->set_in(2, Location::FixedRegisterOrSmiConstant(value(), EAX)); |
| 1266 break; | 1267 break; |
| 1267 case kInt16ArrayCid: | 1268 case kInt16ArrayCid: |
| 1268 case kUint16ArrayCid: | 1269 case kUint16ArrayCid: |
| 1269 // Writable register because the value must be untagged before storing. | 1270 // Writable register because the value must be untagged before storing. |
| 1270 locs->set_in(2, Location::WritableRegister()); | 1271 locs->set_in(2, Location::WritableRegister()); |
| 1271 break; | 1272 break; |
| 1272 case kFloat32ArrayCid: | 1273 case kFloat32ArrayCid: |
| 1273 // Need temp register for float-to-double conversion. | 1274 // Need temp register for float-to-double conversion. |
| 1274 locs->AddTemp(Location::RequiresXmmRegister()); | 1275 locs->AddTemp(Location::RequiresFpuRegister()); |
| 1275 // Fall through. | 1276 // Fall through. |
| 1276 case kFloat64ArrayCid: | 1277 case kFloat64ArrayCid: |
| 1277 // TODO(srdjan): Support Float64 constants. | 1278 // TODO(srdjan): Support Float64 constants. |
| 1278 locs->set_in(2, Location::RequiresXmmRegister()); | 1279 locs->set_in(2, Location::RequiresFpuRegister()); |
| 1279 break; | 1280 break; |
| 1280 default: | 1281 default: |
| 1281 UNREACHABLE(); | 1282 UNREACHABLE(); |
| 1282 return NULL; | 1283 return NULL; |
| 1283 } | 1284 } |
| 1284 return locs; | 1285 return locs; |
| 1285 } | 1286 } |
| 1286 | 1287 |
| 1287 | 1288 |
| 1288 void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1289 void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1363 } | 1364 } |
| 1364 case kInt16ArrayCid: | 1365 case kInt16ArrayCid: |
| 1365 case kUint16ArrayCid: { | 1366 case kUint16ArrayCid: { |
| 1366 Register value = locs()->in(2).reg(); | 1367 Register value = locs()->in(2).reg(); |
| 1367 __ SmiUntag(value); | 1368 __ SmiUntag(value); |
| 1368 __ movw(element_address, value); | 1369 __ movw(element_address, value); |
| 1369 break; | 1370 break; |
| 1370 } | 1371 } |
| 1371 case kFloat32ArrayCid: | 1372 case kFloat32ArrayCid: |
| 1372 // Convert to single precision. | 1373 // Convert to single precision. |
| 1373 __ cvtsd2ss(locs()->temp(0).xmm_reg(), locs()->in(2).xmm_reg()); | 1374 __ cvtsd2ss(locs()->temp(0).fpu_reg(), locs()->in(2).fpu_reg()); |
| 1374 // Store. | 1375 // Store. |
| 1375 __ movss(element_address, locs()->temp(0).xmm_reg()); | 1376 __ movss(element_address, locs()->temp(0).fpu_reg()); |
| 1376 break; | 1377 break; |
| 1377 case kFloat64ArrayCid: | 1378 case kFloat64ArrayCid: |
| 1378 __ movsd(element_address, locs()->in(2).xmm_reg()); | 1379 __ movsd(element_address, locs()->in(2).fpu_reg()); |
| 1379 break; | 1380 break; |
| 1380 default: | 1381 default: |
| 1381 UNREACHABLE(); | 1382 UNREACHABLE(); |
| 1382 } | 1383 } |
| 1383 } | 1384 } |
| 1384 | 1385 |
| 1385 | 1386 |
| 1386 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { | 1387 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { |
| 1387 const intptr_t kNumInputs = 2; | 1388 const intptr_t kNumInputs = 2; |
| 1388 const intptr_t num_temps = 0; | 1389 const intptr_t num_temps = 0; |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1578 Register result_reg = locs()->out().reg(); | 1579 Register result_reg = locs()->out().reg(); |
| 1579 | 1580 |
| 1580 // 'instantiator_reg' is the instantiator AbstractTypeArguments object | 1581 // 'instantiator_reg' is the instantiator AbstractTypeArguments object |
| 1581 // (or null). | 1582 // (or null). |
| 1582 // If the instantiator is null and if the type argument vector | 1583 // If the instantiator is null and if the type argument vector |
| 1583 // instantiated from null becomes a vector of dynamic, then use null as | 1584 // instantiated from null becomes a vector of dynamic, then use null as |
| 1584 // the type arguments. | 1585 // the type arguments. |
| 1585 Label type_arguments_instantiated; | 1586 Label type_arguments_instantiated; |
| 1586 const intptr_t len = type_arguments().Length(); | 1587 const intptr_t len = type_arguments().Length(); |
| 1587 if (type_arguments().IsRawInstantiatedRaw(len)) { | 1588 if (type_arguments().IsRawInstantiatedRaw(len)) { |
| 1588 const Immediate raw_null = | 1589 const Immediate& raw_null = |
| 1589 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1590 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1590 __ cmpl(instantiator_reg, raw_null); | 1591 __ cmpl(instantiator_reg, raw_null); |
| 1591 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1592 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1592 } | 1593 } |
| 1593 // Instantiate non-null type arguments. | 1594 // Instantiate non-null type arguments. |
| 1594 if (type_arguments().IsUninstantiatedIdentity()) { | 1595 if (type_arguments().IsUninstantiatedIdentity()) { |
| 1595 // Check if the instantiator type argument vector is a TypeArguments of a | 1596 // Check if the instantiator type argument vector is a TypeArguments of a |
| 1596 // matching length and, if so, use it as the instantiated type_arguments. | 1597 // matching length and, if so, use it as the instantiated type_arguments. |
| 1597 // No need to check the instantiator ('instantiator_reg') for null here, | 1598 // No need to check the instantiator ('instantiator_reg') for null here, |
| 1598 // because a null instantiator will have the wrong class (Null instead of | 1599 // because a null instantiator will have the wrong class (Null instead of |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1641 Register temp_reg = locs()->temp(0).reg(); | 1642 Register temp_reg = locs()->temp(0).reg(); |
| 1642 | 1643 |
| 1643 // instantiator_reg is the instantiator type argument vector, i.e. an | 1644 // instantiator_reg is the instantiator type argument vector, i.e. an |
| 1644 // AbstractTypeArguments object (or null). | 1645 // AbstractTypeArguments object (or null). |
| 1645 // If the instantiator is null and if the type argument vector | 1646 // If the instantiator is null and if the type argument vector |
| 1646 // instantiated from null becomes a vector of dynamic, then use null as | 1647 // instantiated from null becomes a vector of dynamic, then use null as |
| 1647 // the type arguments. | 1648 // the type arguments. |
| 1648 Label type_arguments_instantiated; | 1649 Label type_arguments_instantiated; |
| 1649 const intptr_t len = type_arguments().Length(); | 1650 const intptr_t len = type_arguments().Length(); |
| 1650 if (type_arguments().IsRawInstantiatedRaw(len)) { | 1651 if (type_arguments().IsRawInstantiatedRaw(len)) { |
| 1651 const Immediate raw_null = | 1652 const Immediate& raw_null = |
| 1652 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1653 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1653 __ cmpl(instantiator_reg, raw_null); | 1654 __ cmpl(instantiator_reg, raw_null); |
| 1654 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1655 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1655 } | 1656 } |
| 1656 // Instantiate non-null type arguments. | 1657 // Instantiate non-null type arguments. |
| 1657 if (type_arguments().IsUninstantiatedIdentity()) { | 1658 if (type_arguments().IsUninstantiatedIdentity()) { |
| 1658 // Check if the instantiator type argument vector is a TypeArguments of a | 1659 // Check if the instantiator type argument vector is a TypeArguments of a |
| 1659 // matching length and, if so, use it as the instantiated type_arguments. | 1660 // matching length and, if so, use it as the instantiated type_arguments. |
| 1660 // No need to check instantiator_reg for null here, because a null | 1661 // No need to check instantiator_reg for null here, because a null |
| 1661 // instantiator will have the wrong class (Null instead of TypeArguments). | 1662 // instantiator will have the wrong class (Null instead of TypeArguments). |
| 1662 Label type_arguments_uninstantiated; | 1663 Label type_arguments_uninstantiated; |
| 1663 __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg); | 1664 __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg); |
| 1664 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); | 1665 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); |
| 1665 Immediate arguments_length = | 1666 const Immediate& arguments_length = |
| 1666 Immediate(Smi::RawValue(type_arguments().Length())); | 1667 Immediate(Smi::RawValue(type_arguments().Length())); |
| 1667 __ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()), | 1668 __ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()), |
| 1668 arguments_length); | 1669 arguments_length); |
| 1669 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1670 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1670 __ Bind(&type_arguments_uninstantiated); | 1671 __ Bind(&type_arguments_uninstantiated); |
| 1671 } | 1672 } |
| 1672 // In the non-factory case, we rely on the allocation stub to | 1673 // In the non-factory case, we rely on the allocation stub to |
| 1673 // instantiate the type arguments. | 1674 // instantiate the type arguments. |
| 1674 __ LoadObject(result_reg, type_arguments()); | 1675 __ LoadObject(result_reg, type_arguments()); |
| 1675 // result_reg: uninstantiated type arguments. | 1676 // result_reg: uninstantiated type arguments. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1697 ASSERT(locs()->out().reg() == instantiator_reg); | 1698 ASSERT(locs()->out().reg() == instantiator_reg); |
| 1698 Register temp_reg = locs()->temp(0).reg(); | 1699 Register temp_reg = locs()->temp(0).reg(); |
| 1699 | 1700 |
| 1700 // instantiator_reg is the instantiator AbstractTypeArguments object | 1701 // instantiator_reg is the instantiator AbstractTypeArguments object |
| 1701 // (or null). If the instantiator is null and if the type argument vector | 1702 // (or null). If the instantiator is null and if the type argument vector |
| 1702 // instantiated from null becomes a vector of dynamic, then use null as | 1703 // instantiated from null becomes a vector of dynamic, then use null as |
| 1703 // the type arguments and do not pass the instantiator. | 1704 // the type arguments and do not pass the instantiator. |
| 1704 Label done; | 1705 Label done; |
| 1705 const intptr_t len = type_arguments().Length(); | 1706 const intptr_t len = type_arguments().Length(); |
| 1706 if (type_arguments().IsRawInstantiatedRaw(len)) { | 1707 if (type_arguments().IsRawInstantiatedRaw(len)) { |
| 1707 const Immediate raw_null = | 1708 const Immediate& raw_null = |
| 1708 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1709 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1709 Label instantiator_not_null; | 1710 Label instantiator_not_null; |
| 1710 __ cmpl(instantiator_reg, raw_null); | 1711 __ cmpl(instantiator_reg, raw_null); |
| 1711 __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump); | 1712 __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump); |
| 1712 // Null was used in VisitExtractConstructorTypeArguments as the | 1713 // Null was used in VisitExtractConstructorTypeArguments as the |
| 1713 // instantiated type arguments, no proper instantiator needed. | 1714 // instantiated type arguments, no proper instantiator needed. |
| 1714 __ movl(instantiator_reg, | 1715 __ movl(instantiator_reg, |
| 1715 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); | 1716 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1716 __ jmp(&done); | 1717 __ jmp(&done); |
| 1717 __ Bind(&instantiator_not_null); | 1718 __ Bind(&instantiator_not_null); |
| 1718 } | 1719 } |
| 1719 // Instantiate non-null type arguments. | 1720 // Instantiate non-null type arguments. |
| 1720 if (type_arguments().IsUninstantiatedIdentity()) { | 1721 if (type_arguments().IsUninstantiatedIdentity()) { |
| 1721 // TODO(regis): The following emitted code is duplicated in | 1722 // TODO(regis): The following emitted code is duplicated in |
| 1722 // VisitExtractConstructorTypeArguments above. The reason is that the code | 1723 // VisitExtractConstructorTypeArguments above. The reason is that the code |
| 1723 // is split between two computations, so that each one produces a | 1724 // is split between two computations, so that each one produces a |
| 1724 // single value, rather than producing a pair of values. | 1725 // single value, rather than producing a pair of values. |
| 1725 // If this becomes an issue, we should expose these tests at the IL level. | 1726 // If this becomes an issue, we should expose these tests at the IL level. |
| 1726 | 1727 |
| 1727 // Check if the instantiator type argument vector is a TypeArguments of a | 1728 // Check if the instantiator type argument vector is a TypeArguments of a |
| 1728 // matching length and, if so, use it as the instantiated type_arguments. | 1729 // matching length and, if so, use it as the instantiated type_arguments. |
| 1729 // No need to check the instantiator (RAX) for null here, because a null | 1730 // No need to check the instantiator (RAX) for null here, because a null |
| 1730 // instantiator will have the wrong class (Null instead of TypeArguments). | 1731 // instantiator will have the wrong class (Null instead of TypeArguments). |
| 1731 __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg); | 1732 __ CompareClassId(instantiator_reg, kTypeArgumentsCid, temp_reg); |
| 1732 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 1733 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 1733 Immediate arguments_length = | 1734 const Immediate& arguments_length = |
| 1734 Immediate(Smi::RawValue(type_arguments().Length())); | 1735 Immediate(Smi::RawValue(type_arguments().Length())); |
| 1735 __ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()), | 1736 __ cmpl(FieldAddress(instantiator_reg, TypeArguments::length_offset()), |
| 1736 arguments_length); | 1737 arguments_length); |
| 1737 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 1738 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 1738 // The instantiator was used in VisitExtractConstructorTypeArguments as the | 1739 // The instantiator was used in VisitExtractConstructorTypeArguments as the |
| 1739 // instantiated type arguments, no proper instantiator needed. | 1740 // instantiated type arguments, no proper instantiator needed. |
| 1740 __ movl(instantiator_reg, | 1741 __ movl(instantiator_reg, |
| 1741 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); | 1742 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1742 } | 1743 } |
| 1743 __ Bind(&done); | 1744 __ Bind(&done); |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2157 } | 2158 } |
| 2158 | 2159 |
| 2159 | 2160 |
| 2160 LocationSummary* BoxDoubleInstr::MakeLocationSummary() const { | 2161 LocationSummary* BoxDoubleInstr::MakeLocationSummary() const { |
| 2161 const intptr_t kNumInputs = 1; | 2162 const intptr_t kNumInputs = 1; |
| 2162 const intptr_t kNumTemps = 0; | 2163 const intptr_t kNumTemps = 0; |
| 2163 LocationSummary* summary = | 2164 LocationSummary* summary = |
| 2164 new LocationSummary(kNumInputs, | 2165 new LocationSummary(kNumInputs, |
| 2165 kNumTemps, | 2166 kNumTemps, |
| 2166 LocationSummary::kCallOnSlowPath); | 2167 LocationSummary::kCallOnSlowPath); |
| 2167 summary->set_in(0, Location::RequiresXmmRegister()); | 2168 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2168 summary->set_out(Location::RequiresRegister()); | 2169 summary->set_out(Location::RequiresRegister()); |
| 2169 return summary; | 2170 return summary; |
| 2170 } | 2171 } |
| 2171 | 2172 |
| 2172 | 2173 |
| 2173 class BoxDoubleSlowPath : public SlowPathCode { | 2174 class BoxDoubleSlowPath : public SlowPathCode { |
| 2174 public: | 2175 public: |
| 2175 explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction) | 2176 explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction) |
| 2176 : instruction_(instruction) { } | 2177 : instruction_(instruction) { } |
| 2177 | 2178 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2200 private: | 2201 private: |
| 2201 BoxDoubleInstr* instruction_; | 2202 BoxDoubleInstr* instruction_; |
| 2202 }; | 2203 }; |
| 2203 | 2204 |
| 2204 | 2205 |
| 2205 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2206 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2206 BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this); | 2207 BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this); |
| 2207 compiler->AddSlowPathCode(slow_path); | 2208 compiler->AddSlowPathCode(slow_path); |
| 2208 | 2209 |
| 2209 Register out_reg = locs()->out().reg(); | 2210 Register out_reg = locs()->out().reg(); |
| 2210 XmmRegister value = locs()->in(0).xmm_reg(); | 2211 XmmRegister value = locs()->in(0).fpu_reg(); |
| 2211 | 2212 |
| 2212 AssemblerMacros::TryAllocate(compiler->assembler(), | 2213 AssemblerMacros::TryAllocate(compiler->assembler(), |
| 2213 compiler->double_class(), | 2214 compiler->double_class(), |
| 2214 slow_path->entry_label(), | 2215 slow_path->entry_label(), |
| 2215 Assembler::kFarJump, | 2216 Assembler::kFarJump, |
| 2216 out_reg); | 2217 out_reg); |
| 2217 __ Bind(slow_path->exit_label()); | 2218 __ Bind(slow_path->exit_label()); |
| 2218 __ movsd(FieldAddress(out_reg, Double::value_offset()), value); | 2219 __ movsd(FieldAddress(out_reg, Double::value_offset()), value); |
| 2219 } | 2220 } |
| 2220 | 2221 |
| 2221 | 2222 |
| 2222 LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const { | 2223 LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const { |
| 2223 const intptr_t kNumInputs = 1; | 2224 const intptr_t kNumInputs = 1; |
| 2224 const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; | 2225 const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; |
| 2225 LocationSummary* summary = | 2226 LocationSummary* summary = |
| 2226 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2227 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2227 summary->set_in(0, Location::RequiresRegister()); | 2228 summary->set_in(0, Location::RequiresRegister()); |
| 2228 if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister()); | 2229 if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister()); |
| 2229 summary->set_out(Location::RequiresXmmRegister()); | 2230 summary->set_out(Location::RequiresFpuRegister()); |
| 2230 return summary; | 2231 return summary; |
| 2231 } | 2232 } |
| 2232 | 2233 |
| 2233 | 2234 |
| 2234 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2235 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2235 const intptr_t value_cid = value()->ResultCid(); | 2236 const intptr_t value_cid = value()->ResultCid(); |
| 2236 const Register value = locs()->in(0).reg(); | 2237 const Register value = locs()->in(0).reg(); |
| 2237 const XmmRegister result = locs()->out().xmm_reg(); | 2238 const XmmRegister result = locs()->out().fpu_reg(); |
| 2238 | 2239 |
| 2239 if (value_cid == kDoubleCid) { | 2240 if (value_cid == kDoubleCid) { |
| 2240 __ movsd(result, FieldAddress(value, Double::value_offset())); | 2241 __ movsd(result, FieldAddress(value, Double::value_offset())); |
| 2241 } else if (value_cid == kSmiCid) { | 2242 } else if (value_cid == kSmiCid) { |
| 2242 __ SmiUntag(value); // Untag input before conversion. | 2243 __ SmiUntag(value); // Untag input before conversion. |
| 2243 __ cvtsi2sd(result, value); | 2244 __ cvtsi2sd(result, value); |
| 2244 __ SmiTag(value); // Restore input register. | 2245 __ SmiTag(value); // Restore input register. |
| 2245 } else { | 2246 } else { |
| 2246 Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp); | 2247 Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp); |
| 2247 compiler->LoadDoubleOrSmiToXmm(result, | 2248 compiler->LoadDoubleOrSmiToFpu(result, |
| 2248 value, | 2249 value, |
| 2249 locs()->temp(0).reg(), | 2250 locs()->temp(0).reg(), |
| 2250 deopt); | 2251 deopt); |
| 2251 } | 2252 } |
| 2252 } | 2253 } |
| 2253 | 2254 |
| 2254 | 2255 |
| 2255 LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const { | 2256 LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const { |
| 2256 const intptr_t kNumInputs = 2; | 2257 const intptr_t kNumInputs = 2; |
| 2257 const intptr_t kNumTemps = 0; | 2258 const intptr_t kNumTemps = 0; |
| 2258 LocationSummary* summary = | 2259 LocationSummary* summary = |
| 2259 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2260 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2260 summary->set_in(0, Location::RequiresXmmRegister()); | 2261 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2261 summary->set_in(1, Location::RequiresXmmRegister()); | 2262 summary->set_in(1, Location::RequiresFpuRegister()); |
| 2262 summary->set_out(Location::SameAsFirstInput()); | 2263 summary->set_out(Location::SameAsFirstInput()); |
| 2263 return summary; | 2264 return summary; |
| 2264 } | 2265 } |
| 2265 | 2266 |
| 2266 | 2267 |
| 2267 void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2268 void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2268 XmmRegister left = locs()->in(0).xmm_reg(); | 2269 XmmRegister left = locs()->in(0).fpu_reg(); |
| 2269 XmmRegister right = locs()->in(1).xmm_reg(); | 2270 XmmRegister right = locs()->in(1).fpu_reg(); |
| 2270 | 2271 |
| 2271 ASSERT(locs()->out().xmm_reg() == left); | 2272 ASSERT(locs()->out().fpu_reg() == left); |
| 2272 | 2273 |
| 2273 switch (op_kind()) { | 2274 switch (op_kind()) { |
| 2274 case Token::kADD: __ addsd(left, right); break; | 2275 case Token::kADD: __ addsd(left, right); break; |
| 2275 case Token::kSUB: __ subsd(left, right); break; | 2276 case Token::kSUB: __ subsd(left, right); break; |
| 2276 case Token::kMUL: __ mulsd(left, right); break; | 2277 case Token::kMUL: __ mulsd(left, right); break; |
| 2277 case Token::kDIV: __ divsd(left, right); break; | 2278 case Token::kDIV: __ divsd(left, right); break; |
| 2278 default: UNREACHABLE(); | 2279 default: UNREACHABLE(); |
| 2279 } | 2280 } |
| 2280 } | 2281 } |
| 2281 | 2282 |
| 2282 | 2283 |
| 2283 LocationSummary* MathSqrtInstr::MakeLocationSummary() const { | 2284 LocationSummary* MathSqrtInstr::MakeLocationSummary() const { |
| 2284 const intptr_t kNumInputs = 1; | 2285 const intptr_t kNumInputs = 1; |
| 2285 const intptr_t kNumTemps = 0; | 2286 const intptr_t kNumTemps = 0; |
| 2286 LocationSummary* summary = | 2287 LocationSummary* summary = |
| 2287 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2288 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2288 summary->set_in(0, Location::RequiresXmmRegister()); | 2289 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2289 summary->set_out(Location::RequiresXmmRegister()); | 2290 summary->set_out(Location::RequiresFpuRegister()); |
| 2290 return summary; | 2291 return summary; |
| 2291 } | 2292 } |
| 2292 | 2293 |
| 2293 | 2294 |
| 2294 void MathSqrtInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2295 void MathSqrtInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2295 __ sqrtsd(locs()->out().xmm_reg(), locs()->in(0).xmm_reg()); | 2296 __ sqrtsd(locs()->out().fpu_reg(), locs()->in(0).fpu_reg()); |
| 2296 } | 2297 } |
| 2297 | 2298 |
| 2298 | 2299 |
| 2299 LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const { | 2300 LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const { |
| 2300 const intptr_t kNumInputs = 1; | 2301 const intptr_t kNumInputs = 1; |
| 2301 const intptr_t kNumTemps = 0; | 2302 const intptr_t kNumTemps = 0; |
| 2302 LocationSummary* summary = | 2303 LocationSummary* summary = |
| 2303 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2304 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2304 summary->set_in(0, Location::RequiresRegister()); | 2305 summary->set_in(0, Location::RequiresRegister()); |
| 2305 summary->set_out(Location::SameAsFirstInput()); | 2306 summary->set_out(Location::SameAsFirstInput()); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2405 locs()); | 2406 locs()); |
| 2406 __ Bind(&done); | 2407 __ Bind(&done); |
| 2407 } | 2408 } |
| 2408 | 2409 |
| 2409 | 2410 |
| 2410 LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const { | 2411 LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const { |
| 2411 const intptr_t kNumInputs = 1; | 2412 const intptr_t kNumInputs = 1; |
| 2412 const intptr_t kNumTemps = 0; | 2413 const intptr_t kNumTemps = 0; |
| 2413 LocationSummary* result = new LocationSummary( | 2414 LocationSummary* result = new LocationSummary( |
| 2414 kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2415 kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2415 result->set_in(0, Location::RequiresXmmRegister()); | 2416 result->set_in(0, Location::RequiresFpuRegister()); |
| 2416 result->set_out(Location::RequiresRegister()); | 2417 result->set_out(Location::RequiresRegister()); |
| 2417 return result; | 2418 return result; |
| 2418 } | 2419 } |
| 2419 | 2420 |
| 2420 | 2421 |
| 2421 void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2422 void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2422 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptDoubleToSmi); | 2423 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptDoubleToSmi); |
| 2423 Register result = locs()->out().reg(); | 2424 Register result = locs()->out().reg(); |
| 2424 XmmRegister value = locs()->in(0).xmm_reg(); | 2425 XmmRegister value = locs()->in(0).fpu_reg(); |
| 2425 __ cvttsd2si(result, value); | 2426 __ cvttsd2si(result, value); |
| 2426 // Overflow is signalled with minint. | 2427 // Overflow is signalled with minint. |
| 2427 Label do_call, done; | 2428 Label do_call, done; |
| 2428 // Check for overflow and that it fits into Smi. | 2429 // Check for overflow and that it fits into Smi. |
| 2429 __ cmpl(result, Immediate(0xC0000000)); | 2430 __ cmpl(result, Immediate(0xC0000000)); |
| 2430 __ j(NEGATIVE, deopt); | 2431 __ j(NEGATIVE, deopt); |
| 2431 __ SmiTag(result); | 2432 __ SmiTag(result); |
| 2432 } | 2433 } |
| 2433 | 2434 |
| 2434 | 2435 |
| 2435 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { | 2436 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { |
| 2436 const intptr_t kNumInputs = 1; | 2437 const intptr_t kNumInputs = 1; |
| 2437 const intptr_t kNumTemps = | 2438 const intptr_t kNumTemps = |
| 2438 (recognized_kind() == MethodRecognizer::kDoubleRound) ? 1 : 0; | 2439 (recognized_kind() == MethodRecognizer::kDoubleRound) ? 1 : 0; |
| 2439 LocationSummary* result = | 2440 LocationSummary* result = |
| 2440 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2441 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2441 result->set_in(0, Location::RequiresXmmRegister()); | 2442 result->set_in(0, Location::RequiresFpuRegister()); |
| 2442 result->set_out(Location::RequiresXmmRegister()); | 2443 result->set_out(Location::RequiresFpuRegister()); |
| 2443 if (recognized_kind() == MethodRecognizer::kDoubleRound) { | 2444 if (recognized_kind() == MethodRecognizer::kDoubleRound) { |
| 2444 result->set_temp(0, Location::RequiresXmmRegister()); | 2445 result->set_temp(0, Location::RequiresFpuRegister()); |
| 2445 } | 2446 } |
| 2446 return result; | 2447 return result; |
| 2447 } | 2448 } |
| 2448 | 2449 |
| 2449 | 2450 |
| 2450 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2451 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2451 XmmRegister value = locs()->in(0).xmm_reg(); | 2452 XmmRegister value = locs()->in(0).fpu_reg(); |
| 2452 XmmRegister result = locs()->out().xmm_reg(); | 2453 XmmRegister result = locs()->out().fpu_reg(); |
| 2453 if (recognized_kind() == MethodRecognizer::kDoubleTruncate) { | 2454 if (recognized_kind() == MethodRecognizer::kDoubleTruncate) { |
| 2454 __ roundsd(result, value, Assembler::kRoundToZero); | 2455 __ roundsd(result, value, Assembler::kRoundToZero); |
| 2455 } else { | 2456 } else { |
| 2456 XmmRegister temp = locs()->temp(0).xmm_reg(); | 2457 XmmRegister temp = locs()->temp(0).fpu_reg(); |
| 2457 __ DoubleRound(result, value, temp); | 2458 __ DoubleRound(result, value, temp); |
| 2458 } | 2459 } |
| 2459 } | 2460 } |
| 2460 | 2461 |
| 2461 | 2462 |
| 2462 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const { | 2463 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const { |
| 2463 return MakeCallSummary(); | 2464 return MakeCallSummary(); |
| 2464 } | 2465 } |
| 2465 | 2466 |
| 2466 | 2467 |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2639 } | 2640 } |
| 2640 | 2641 |
| 2641 | 2642 |
| 2642 LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const { | 2643 LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const { |
| 2643 const intptr_t kNumInputs = 1; | 2644 const intptr_t kNumInputs = 1; |
| 2644 const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; | 2645 const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; |
| 2645 LocationSummary* summary = | 2646 LocationSummary* summary = |
| 2646 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2647 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2647 summary->set_in(0, Location::RequiresRegister()); | 2648 summary->set_in(0, Location::RequiresRegister()); |
| 2648 if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister()); | 2649 if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister()); |
| 2649 summary->set_out(Location::RequiresXmmRegister()); | 2650 summary->set_out(Location::RequiresFpuRegister()); |
| 2650 return summary; | 2651 return summary; |
| 2651 } | 2652 } |
| 2652 | 2653 |
| 2653 | 2654 |
| 2654 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2655 void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2655 const intptr_t value_cid = value()->ResultCid(); | 2656 const intptr_t value_cid = value()->ResultCid(); |
| 2656 const Register value = locs()->in(0).reg(); | 2657 const Register value = locs()->in(0).reg(); |
| 2657 const XmmRegister result = locs()->out().xmm_reg(); | 2658 const XmmRegister result = locs()->out().fpu_reg(); |
| 2658 | 2659 |
| 2659 if (value_cid == kMintCid) { | 2660 if (value_cid == kMintCid) { |
| 2660 __ movsd(result, FieldAddress(value, Mint::value_offset())); | 2661 __ movsd(result, FieldAddress(value, Mint::value_offset())); |
| 2661 } else if (value_cid == kSmiCid) { | 2662 } else if (value_cid == kSmiCid) { |
| 2662 __ SmiUntag(value); // Untag input before conversion. | 2663 __ SmiUntag(value); // Untag input before conversion. |
| 2663 __ movd(result, value); | 2664 __ movd(result, value); |
| 2664 __ pmovsxdq(result, result); | 2665 __ pmovsxdq(result, result); |
| 2665 __ SmiTag(value); // Restore input register. | 2666 __ SmiTag(value); // Restore input register. |
| 2666 } else { | 2667 } else { |
| 2667 Register temp = locs()->temp(0).reg(); | 2668 Register temp = locs()->temp(0).reg(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2683 } | 2684 } |
| 2684 | 2685 |
| 2685 | 2686 |
| 2686 LocationSummary* BoxIntegerInstr::MakeLocationSummary() const { | 2687 LocationSummary* BoxIntegerInstr::MakeLocationSummary() const { |
| 2687 const intptr_t kNumInputs = 1; | 2688 const intptr_t kNumInputs = 1; |
| 2688 const intptr_t kNumTemps = 2; | 2689 const intptr_t kNumTemps = 2; |
| 2689 LocationSummary* summary = | 2690 LocationSummary* summary = |
| 2690 new LocationSummary(kNumInputs, | 2691 new LocationSummary(kNumInputs, |
| 2691 kNumTemps, | 2692 kNumTemps, |
| 2692 LocationSummary::kCallOnSlowPath); | 2693 LocationSummary::kCallOnSlowPath); |
| 2693 summary->set_in(0, Location::RequiresXmmRegister()); | 2694 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2694 summary->set_temp(0, Location::RegisterLocation(EAX)); | 2695 summary->set_temp(0, Location::RegisterLocation(EAX)); |
| 2695 summary->set_temp(1, Location::RegisterLocation(EDX)); | 2696 summary->set_temp(1, Location::RegisterLocation(EDX)); |
| 2696 // TODO(fschneider): Save one temp by using result register as a temp. | 2697 // TODO(fschneider): Save one temp by using result register as a temp. |
| 2697 summary->set_out(Location::RequiresRegister()); | 2698 summary->set_out(Location::RequiresRegister()); |
| 2698 return summary; | 2699 return summary; |
| 2699 } | 2700 } |
| 2700 | 2701 |
| 2701 | 2702 |
| 2702 class BoxIntegerSlowPath : public SlowPathCode { | 2703 class BoxIntegerSlowPath : public SlowPathCode { |
| 2703 public: | 2704 public: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2730 private: | 2731 private: |
| 2731 BoxIntegerInstr* instruction_; | 2732 BoxIntegerInstr* instruction_; |
| 2732 }; | 2733 }; |
| 2733 | 2734 |
| 2734 | 2735 |
| 2735 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2736 void BoxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2736 BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); | 2737 BoxIntegerSlowPath* slow_path = new BoxIntegerSlowPath(this); |
| 2737 compiler->AddSlowPathCode(slow_path); | 2738 compiler->AddSlowPathCode(slow_path); |
| 2738 | 2739 |
| 2739 Register out_reg = locs()->out().reg(); | 2740 Register out_reg = locs()->out().reg(); |
| 2740 XmmRegister value = locs()->in(0).xmm_reg(); | 2741 XmmRegister value = locs()->in(0).fpu_reg(); |
| 2741 | 2742 |
| 2742 // Unboxed operations produce smis or mint-sized values. | 2743 // Unboxed operations produce smis or mint-sized values. |
| 2743 // Check if value fits into a smi. | 2744 // Check if value fits into a smi. |
| 2744 Label not_smi, done; | 2745 Label not_smi, done; |
| 2745 __ pextrd(EDX, value, Immediate(1)); // Upper half. | 2746 __ pextrd(EDX, value, Immediate(1)); // Upper half. |
| 2746 __ pextrd(EAX, value, Immediate(0)); // Lower half. | 2747 __ pextrd(EAX, value, Immediate(0)); // Lower half. |
| 2747 // 1. Compute (x + -kMinSmi) which has to be in the range | 2748 // 1. Compute (x + -kMinSmi) which has to be in the range |
| 2748 // 0 .. -kMinSmi+kMaxSmi for x to fit into a smi. | 2749 // 0 .. -kMinSmi+kMaxSmi for x to fit into a smi. |
| 2749 __ addl(EAX, Immediate(0x40000000)); | 2750 __ addl(EAX, Immediate(0x40000000)); |
| 2750 __ adcl(EDX, Immediate(0)); | 2751 __ adcl(EDX, Immediate(0)); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2774 | 2775 |
| 2775 LocationSummary* BinaryMintOpInstr::MakeLocationSummary() const { | 2776 LocationSummary* BinaryMintOpInstr::MakeLocationSummary() const { |
| 2776 const intptr_t kNumInputs = 2; | 2777 const intptr_t kNumInputs = 2; |
| 2777 switch (op_kind()) { | 2778 switch (op_kind()) { |
| 2778 case Token::kBIT_AND: | 2779 case Token::kBIT_AND: |
| 2779 case Token::kBIT_OR: | 2780 case Token::kBIT_OR: |
| 2780 case Token::kBIT_XOR: { | 2781 case Token::kBIT_XOR: { |
| 2781 const intptr_t kNumTemps = 0; | 2782 const intptr_t kNumTemps = 0; |
| 2782 LocationSummary* summary = | 2783 LocationSummary* summary = |
| 2783 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2784 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2784 summary->set_in(0, Location::RequiresXmmRegister()); | 2785 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2785 summary->set_in(1, Location::RequiresXmmRegister()); | 2786 summary->set_in(1, Location::RequiresFpuRegister()); |
| 2786 summary->set_out(Location::SameAsFirstInput()); | 2787 summary->set_out(Location::SameAsFirstInput()); |
| 2787 return summary; | 2788 return summary; |
| 2788 } | 2789 } |
| 2789 case Token::kADD: | 2790 case Token::kADD: |
| 2790 case Token::kSUB: { | 2791 case Token::kSUB: { |
| 2791 const intptr_t kNumTemps = 2; | 2792 const intptr_t kNumTemps = 2; |
| 2792 LocationSummary* summary = | 2793 LocationSummary* summary = |
| 2793 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2794 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2794 summary->set_in(0, Location::RequiresXmmRegister()); | 2795 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2795 summary->set_in(1, Location::RequiresXmmRegister()); | 2796 summary->set_in(1, Location::RequiresFpuRegister()); |
| 2796 summary->set_temp(0, Location::RequiresRegister()); | 2797 summary->set_temp(0, Location::RequiresRegister()); |
| 2797 summary->set_temp(1, Location::RequiresRegister()); | 2798 summary->set_temp(1, Location::RequiresRegister()); |
| 2798 summary->set_out(Location::SameAsFirstInput()); | 2799 summary->set_out(Location::SameAsFirstInput()); |
| 2799 return summary; | 2800 return summary; |
| 2800 } | 2801 } |
| 2801 default: | 2802 default: |
| 2802 UNREACHABLE(); | 2803 UNREACHABLE(); |
| 2803 return NULL; | 2804 return NULL; |
| 2804 } | 2805 } |
| 2805 } | 2806 } |
| 2806 | 2807 |
| 2807 | 2808 |
| 2808 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2809 void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2809 XmmRegister left = locs()->in(0).xmm_reg(); | 2810 XmmRegister left = locs()->in(0).fpu_reg(); |
| 2810 XmmRegister right = locs()->in(1).xmm_reg(); | 2811 XmmRegister right = locs()->in(1).fpu_reg(); |
| 2811 | 2812 |
| 2812 ASSERT(locs()->out().xmm_reg() == left); | 2813 ASSERT(locs()->out().fpu_reg() == left); |
| 2813 | 2814 |
| 2814 switch (op_kind()) { | 2815 switch (op_kind()) { |
| 2815 case Token::kBIT_AND: __ andpd(left, right); break; | 2816 case Token::kBIT_AND: __ andpd(left, right); break; |
| 2816 case Token::kBIT_OR: __ orpd(left, right); break; | 2817 case Token::kBIT_OR: __ orpd(left, right); break; |
| 2817 case Token::kBIT_XOR: __ xorpd(left, right); break; | 2818 case Token::kBIT_XOR: __ xorpd(left, right); break; |
| 2818 case Token::kADD: | 2819 case Token::kADD: |
| 2819 case Token::kSUB: { | 2820 case Token::kSUB: { |
| 2820 Register lo = locs()->temp(0).reg(); | 2821 Register lo = locs()->temp(0).reg(); |
| 2821 Register hi = locs()->temp(1).reg(); | 2822 Register hi = locs()->temp(1).reg(); |
| 2822 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 2823 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2846 default: UNREACHABLE(); | 2847 default: UNREACHABLE(); |
| 2847 } | 2848 } |
| 2848 } | 2849 } |
| 2849 | 2850 |
| 2850 | 2851 |
| 2851 LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const { | 2852 LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const { |
| 2852 const intptr_t kNumInputs = 2; | 2853 const intptr_t kNumInputs = 2; |
| 2853 const intptr_t kNumTemps = op_kind() == Token::kSHL ? 2 : 1; | 2854 const intptr_t kNumTemps = op_kind() == Token::kSHL ? 2 : 1; |
| 2854 LocationSummary* summary = | 2855 LocationSummary* summary = |
| 2855 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2856 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2856 summary->set_in(0, Location::RequiresXmmRegister()); | 2857 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2857 summary->set_in(1, Location::RegisterLocation(ECX)); | 2858 summary->set_in(1, Location::RegisterLocation(ECX)); |
| 2858 summary->set_temp(0, Location::RequiresRegister()); | 2859 summary->set_temp(0, Location::RequiresRegister()); |
| 2859 if (op_kind() == Token::kSHL) { | 2860 if (op_kind() == Token::kSHL) { |
| 2860 summary->set_temp(1, Location::RequiresRegister()); | 2861 summary->set_temp(1, Location::RequiresRegister()); |
| 2861 } | 2862 } |
| 2862 summary->set_out(Location::SameAsFirstInput()); | 2863 summary->set_out(Location::SameAsFirstInput()); |
| 2863 return summary; | 2864 return summary; |
| 2864 } | 2865 } |
| 2865 | 2866 |
| 2866 | 2867 |
| 2867 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2868 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2868 XmmRegister left = locs()->in(0).xmm_reg(); | 2869 XmmRegister left = locs()->in(0).fpu_reg(); |
| 2869 ASSERT(locs()->in(1).reg() == ECX); | 2870 ASSERT(locs()->in(1).reg() == ECX); |
| 2870 ASSERT(locs()->out().xmm_reg() == left); | 2871 ASSERT(locs()->out().fpu_reg() == left); |
| 2871 | 2872 |
| 2872 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 2873 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 2873 kDeoptShiftMintOp); | 2874 kDeoptShiftMintOp); |
| 2874 Label done; | 2875 Label done; |
| 2875 __ testl(ECX, ECX); | 2876 __ testl(ECX, ECX); |
| 2876 __ j(ZERO, &done); // Shift by 0 is a nop. | 2877 __ j(ZERO, &done); // Shift by 0 is a nop. |
| 2877 __ subl(ESP, Immediate(2 * kWordSize)); | 2878 __ subl(ESP, Immediate(2 * kWordSize)); |
| 2878 __ movq(Address(ESP, 0), left); | 2879 __ movq(Address(ESP, 0), left); |
| 2879 // Deoptimize if shift count is > 31. | 2880 // Deoptimize if shift count is > 31. |
| 2880 // sarl operation masks the count to 5 bits and | 2881 // sarl operation masks the count to 5 bits and |
| 2881 // shrd is undefined with count > operand size (32) | 2882 // shrd is undefined with count > operand size (32) |
| 2882 // TODO(fschneider): Support shift counts > 31 without deoptimization. | 2883 // TODO(fschneider): Support shift counts > 31 without deoptimization. |
| 2883 __ SmiUntag(ECX); | 2884 __ SmiUntag(ECX); |
| 2884 const Immediate kCountLimit = Immediate(31); | 2885 const Immediate& kCountLimit = Immediate(31); |
| 2885 __ cmpl(ECX, kCountLimit); | 2886 __ cmpl(ECX, kCountLimit); |
| 2886 __ j(ABOVE, deopt); | 2887 __ j(ABOVE, deopt); |
| 2887 switch (op_kind()) { | 2888 switch (op_kind()) { |
| 2888 case Token::kSHR: { | 2889 case Token::kSHR: { |
| 2889 Register temp = locs()->temp(0).reg(); | 2890 Register temp = locs()->temp(0).reg(); |
| 2890 __ movl(temp, Address(ESP, 1 * kWordSize)); // High half. | 2891 __ movl(temp, Address(ESP, 1 * kWordSize)); // High half. |
| 2891 __ shrd(Address(ESP, 0), temp); // Shift count in CL. | 2892 __ shrd(Address(ESP, 0), temp); // Shift count in CL. |
| 2892 __ sarl(Address(ESP, 1 * kWordSize), ECX); // Shift count in CL. | 2893 __ sarl(Address(ESP, 1 * kWordSize), ECX); // Shift count in CL. |
| 2893 break; | 2894 break; |
| 2894 } | 2895 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2916 __ addl(ESP, Immediate(2 * kWordSize)); | 2917 __ addl(ESP, Immediate(2 * kWordSize)); |
| 2917 __ Bind(&done); | 2918 __ Bind(&done); |
| 2918 } | 2919 } |
| 2919 | 2920 |
| 2920 | 2921 |
| 2921 LocationSummary* UnaryMintOpInstr::MakeLocationSummary() const { | 2922 LocationSummary* UnaryMintOpInstr::MakeLocationSummary() const { |
| 2922 const intptr_t kNumInputs = 1; | 2923 const intptr_t kNumInputs = 1; |
| 2923 const intptr_t kNumTemps = 0; | 2924 const intptr_t kNumTemps = 0; |
| 2924 LocationSummary* summary = | 2925 LocationSummary* summary = |
| 2925 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2926 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2926 summary->set_in(0, Location::RequiresXmmRegister()); | 2927 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2927 summary->set_out(Location::SameAsFirstInput()); | 2928 summary->set_out(Location::SameAsFirstInput()); |
| 2928 return summary; | 2929 return summary; |
| 2929 } | 2930 } |
| 2930 | 2931 |
| 2931 | 2932 |
| 2932 void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2933 void UnaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2933 ASSERT(op_kind() == Token::kBIT_NOT); | 2934 ASSERT(op_kind() == Token::kBIT_NOT); |
| 2934 XmmRegister value = locs()->in(0).xmm_reg(); | 2935 XmmRegister value = locs()->in(0).fpu_reg(); |
| 2935 ASSERT(value == locs()->out().xmm_reg()); | 2936 ASSERT(value == locs()->out().fpu_reg()); |
| 2936 __ pcmpeqq(XMM0, XMM0); // Generate all 1's. | 2937 __ pcmpeqq(XMM0, XMM0); // Generate all 1's. |
| 2937 __ pxor(value, XMM0); | 2938 __ pxor(value, XMM0); |
| 2938 } | 2939 } |
| 2939 | 2940 |
| 2940 | 2941 |
| 2942 LocationSummary* ThrowInstr::MakeLocationSummary() const { |
| 2943 return new LocationSummary(0, 0, LocationSummary::kCall); |
| 2944 } |
| 2945 |
| 2946 |
| 2947 |
| 2948 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2949 compiler->GenerateCallRuntime(token_pos(), |
| 2950 kThrowRuntimeEntry, |
| 2951 locs()); |
| 2952 __ int3(); |
| 2953 } |
| 2954 |
| 2955 |
| 2956 LocationSummary* ReThrowInstr::MakeLocationSummary() const { |
| 2957 return new LocationSummary(0, 0, LocationSummary::kCall); |
| 2958 } |
| 2959 |
| 2960 |
| 2961 void ReThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2962 compiler->GenerateCallRuntime(token_pos(), |
| 2963 kReThrowRuntimeEntry, |
| 2964 locs()); |
| 2965 __ int3(); |
| 2966 } |
| 2967 |
| 2968 |
| 2969 LocationSummary* GotoInstr::MakeLocationSummary() const { |
| 2970 return new LocationSummary(0, 0, LocationSummary::kNoCall); |
| 2971 } |
| 2972 |
| 2973 |
| 2974 void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2975 // Add deoptimization descriptor for deoptimizing instructions |
| 2976 // that may be inserted before this instruction. |
| 2977 if (!compiler->is_optimizing()) { |
| 2978 compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore, |
| 2979 GetDeoptId(), |
| 2980 0); // No token position. |
| 2981 } |
| 2982 |
| 2983 if (HasParallelMove()) { |
| 2984 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
| 2985 } |
| 2986 |
| 2987 // We can fall through if the successor is the next block in the list. |
| 2988 // Otherwise, we need a jump. |
| 2989 if (!compiler->IsNextBlock(successor())) { |
| 2990 __ jmp(compiler->GetBlockLabel(successor())); |
| 2991 } |
| 2992 } |
| 2993 |
| 2994 |
| 2995 static Condition NegateCondition(Condition condition) { |
| 2996 switch (condition) { |
| 2997 case EQUAL: return NOT_EQUAL; |
| 2998 case NOT_EQUAL: return EQUAL; |
| 2999 case LESS: return GREATER_EQUAL; |
| 3000 case LESS_EQUAL: return GREATER; |
| 3001 case GREATER: return LESS_EQUAL; |
| 3002 case GREATER_EQUAL: return LESS; |
| 3003 case BELOW: return ABOVE_EQUAL; |
| 3004 case BELOW_EQUAL: return ABOVE; |
| 3005 case ABOVE: return BELOW_EQUAL; |
| 3006 case ABOVE_EQUAL: return BELOW; |
| 3007 default: |
| 3008 OS::Print("Error %d\n", condition); |
| 3009 UNIMPLEMENTED(); |
| 3010 return EQUAL; |
| 3011 } |
| 3012 } |
| 3013 |
| 3014 |
| 3015 void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler, |
| 3016 bool value) { |
| 3017 if (value && compiler->IsNextBlock(false_successor())) { |
| 3018 __ jmp(compiler->GetBlockLabel(true_successor())); |
| 3019 } else if (!value && compiler->IsNextBlock(true_successor())) { |
| 3020 __ jmp(compiler->GetBlockLabel(false_successor())); |
| 3021 } |
| 3022 } |
| 3023 |
| 3024 |
| 3025 void ControlInstruction::EmitBranchOnCondition(FlowGraphCompiler* compiler, |
| 3026 Condition true_condition) { |
| 3027 if (compiler->IsNextBlock(false_successor())) { |
| 3028 // If the next block is the false successor we will fall through to it. |
| 3029 __ j(true_condition, compiler->GetBlockLabel(true_successor())); |
| 3030 } else { |
| 3031 // If the next block is the true successor we negate comparison and fall |
| 3032 // through to it. |
| 3033 ASSERT(compiler->IsNextBlock(true_successor())); |
| 3034 Condition false_condition = NegateCondition(true_condition); |
| 3035 __ j(false_condition, compiler->GetBlockLabel(false_successor())); |
| 3036 } |
| 3037 } |
| 3038 |
| 3039 |
| 3040 LocationSummary* CurrentContextInstr::MakeLocationSummary() const { |
| 3041 return LocationSummary::Make(0, |
| 3042 Location::RequiresRegister(), |
| 3043 LocationSummary::kNoCall); |
| 3044 } |
| 3045 |
| 3046 |
| 3047 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3048 __ MoveRegister(locs()->out().reg(), CTX); |
| 3049 } |
| 3050 |
| 3051 |
| 3052 LocationSummary* StrictCompareInstr::MakeLocationSummary() const { |
| 3053 const intptr_t kNumInputs = 2; |
| 3054 const intptr_t kNumTemps = 0; |
| 3055 LocationSummary* locs = |
| 3056 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3057 locs->set_in(0, Location::RegisterOrConstant(left())); |
| 3058 locs->set_in(1, Location::RegisterOrConstant(right())); |
| 3059 locs->set_out(Location::RequiresRegister()); |
| 3060 return locs; |
| 3061 } |
| 3062 |
| 3063 |
| 3064 // Special code for numbers (compare values instead of references.) |
| 3065 void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3066 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
| 3067 Location left = locs()->in(0); |
| 3068 Location right = locs()->in(1); |
| 3069 if (left.IsConstant() && right.IsConstant()) { |
| 3070 // TODO(vegorov): should be eliminated earlier by constant propagation. |
| 3071 const bool result = (kind() == Token::kEQ_STRICT) ? |
| 3072 left.constant().raw() == right.constant().raw() : |
| 3073 left.constant().raw() != right.constant().raw(); |
| 3074 __ LoadObject(locs()->out().reg(), result ? Bool::True() : Bool::False()); |
| 3075 return; |
| 3076 } |
| 3077 if (left.IsConstant()) { |
| 3078 compiler->EmitEqualityRegConstCompare(right.reg(), |
| 3079 left.constant(), |
| 3080 needs_number_check()); |
| 3081 } else if (right.IsConstant()) { |
| 3082 compiler->EmitEqualityRegConstCompare(left.reg(), |
| 3083 right.constant(), |
| 3084 needs_number_check()); |
| 3085 } else { |
| 3086 compiler->EmitEqualityRegRegCompare(left.reg(), |
| 3087 right.reg(), |
| 3088 needs_number_check()); |
| 3089 } |
| 3090 |
| 3091 Register result = locs()->out().reg(); |
| 3092 Label load_true, done; |
| 3093 Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; |
| 3094 __ j(true_condition, &load_true, Assembler::kNearJump); |
| 3095 __ LoadObject(result, Bool::False()); |
| 3096 __ jmp(&done, Assembler::kNearJump); |
| 3097 __ Bind(&load_true); |
| 3098 __ LoadObject(result, Bool::True()); |
| 3099 __ Bind(&done); |
| 3100 } |
| 3101 |
| 3102 |
| 3103 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 3104 BranchInstr* branch) { |
| 3105 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
| 3106 Location left = locs()->in(0); |
| 3107 Location right = locs()->in(1); |
| 3108 if (left.IsConstant() && right.IsConstant()) { |
| 3109 // TODO(vegorov): should be eliminated earlier by constant propagation. |
| 3110 const bool result = (kind() == Token::kEQ_STRICT) ? |
| 3111 left.constant().raw() == right.constant().raw() : |
| 3112 left.constant().raw() != right.constant().raw(); |
| 3113 branch->EmitBranchOnValue(compiler, result); |
| 3114 return; |
| 3115 } |
| 3116 if (left.IsConstant()) { |
| 3117 compiler->EmitEqualityRegConstCompare(right.reg(), |
| 3118 left.constant(), |
| 3119 needs_number_check()); |
| 3120 } else if (right.IsConstant()) { |
| 3121 compiler->EmitEqualityRegConstCompare(left.reg(), |
| 3122 right.constant(), |
| 3123 needs_number_check()); |
| 3124 } else { |
| 3125 compiler->EmitEqualityRegRegCompare(left.reg(), |
| 3126 right.reg(), |
| 3127 needs_number_check()); |
| 3128 } |
| 3129 |
| 3130 Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; |
| 3131 branch->EmitBranchOnCondition(compiler, true_condition); |
| 3132 } |
| 3133 |
| 3134 |
| 3135 void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3136 // The arguments to the stub include the closure, as does the arguments |
| 3137 // descriptor. |
| 3138 Register temp_reg = locs()->temp(0).reg(); |
| 3139 int argument_count = ArgumentCount(); |
| 3140 const Array& arguments_descriptor = |
| 3141 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
| 3142 argument_names())); |
| 3143 __ LoadObject(temp_reg, arguments_descriptor); |
| 3144 compiler->GenerateDartCall(deopt_id(), |
| 3145 token_pos(), |
| 3146 &StubCode::CallClosureFunctionLabel(), |
| 3147 PcDescriptors::kOther, |
| 3148 locs()); |
| 3149 __ Drop(argument_count); |
| 3150 } |
| 3151 |
| 3152 |
| 3153 LocationSummary* BooleanNegateInstr::MakeLocationSummary() const { |
| 3154 return LocationSummary::Make(1, |
| 3155 Location::RequiresRegister(), |
| 3156 LocationSummary::kNoCall); |
| 3157 } |
| 3158 |
| 3159 |
| 3160 void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3161 Register value = locs()->in(0).reg(); |
| 3162 Register result = locs()->out().reg(); |
| 3163 |
| 3164 Label done; |
| 3165 __ LoadObject(result, Bool::True()); |
| 3166 __ CompareRegisters(result, value); |
| 3167 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 3168 __ LoadObject(result, Bool::False()); |
| 3169 __ Bind(&done); |
| 3170 } |
| 3171 |
| 3172 |
| 3173 LocationSummary* ChainContextInstr::MakeLocationSummary() const { |
| 3174 return LocationSummary::Make(1, |
| 3175 Location::NoLocation(), |
| 3176 LocationSummary::kNoCall); |
| 3177 } |
| 3178 |
| 3179 |
| 3180 void ChainContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3181 Register context_value = locs()->in(0).reg(); |
| 3182 |
| 3183 // Chain the new context in context_value to its parent in CTX. |
| 3184 __ StoreIntoObject(context_value, |
| 3185 FieldAddress(context_value, Context::parent_offset()), |
| 3186 CTX); |
| 3187 // Set new context as current context. |
| 3188 __ MoveRegister(CTX, context_value); |
| 3189 } |
| 3190 |
| 3191 |
| 3192 LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const { |
| 3193 const intptr_t kNumInputs = 2; |
| 3194 const intptr_t kNumTemps = 0; |
| 3195 LocationSummary* locs = |
| 3196 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 3197 locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister() |
| 3198 : Location::RequiresRegister()); |
| 3199 locs->set_in(1, Location::RequiresRegister()); |
| 3200 return locs; |
| 3201 } |
| 3202 |
| 3203 |
| 3204 void StoreVMFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3205 Register value_reg = locs()->in(0).reg(); |
| 3206 Register dest_reg = locs()->in(1).reg(); |
| 3207 |
| 3208 if (value()->NeedsStoreBuffer()) { |
| 3209 __ StoreIntoObject(dest_reg, FieldAddress(dest_reg, offset_in_bytes()), |
| 3210 value_reg); |
| 3211 } else { |
| 3212 __ StoreIntoObjectNoBarrier( |
| 3213 dest_reg, FieldAddress(dest_reg, offset_in_bytes()), value_reg); |
| 3214 } |
| 3215 } |
| 3216 |
| 3217 |
| 3218 LocationSummary* AllocateObjectInstr::MakeLocationSummary() const { |
| 3219 return MakeCallSummary(); |
| 3220 } |
| 3221 |
| 3222 |
| 3223 void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3224 const Class& cls = Class::ZoneHandle(constructor().Owner()); |
| 3225 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); |
| 3226 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); |
| 3227 compiler->GenerateCall(token_pos(), |
| 3228 &label, |
| 3229 PcDescriptors::kOther, |
| 3230 locs()); |
| 3231 __ Drop(ArgumentCount()); // Discard arguments. |
| 3232 } |
| 3233 |
| 3234 |
| 3235 LocationSummary* CreateClosureInstr::MakeLocationSummary() const { |
| 3236 return MakeCallSummary(); |
| 3237 } |
| 3238 |
| 3239 |
| 3240 void CreateClosureInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3241 const Function& closure_function = function(); |
| 3242 ASSERT(!closure_function.IsImplicitStaticClosureFunction()); |
| 3243 const Code& stub = Code::Handle( |
| 3244 StubCode::GetAllocationStubForClosure(closure_function)); |
| 3245 const ExternalLabel label(closure_function.ToCString(), stub.EntryPoint()); |
| 3246 compiler->GenerateCall(token_pos(), |
| 3247 &label, |
| 3248 PcDescriptors::kOther, |
| 3249 locs()); |
| 3250 __ Drop(2); // Discard type arguments and receiver. |
| 3251 } |
| 3252 |
| 2941 } // namespace dart | 3253 } // namespace dart |
| 2942 | 3254 |
| 2943 #undef __ | 3255 #undef __ |
| 2944 | 3256 |
| 2945 #endif // defined TARGET_ARCH_X64 | 3257 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |