| 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_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/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 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 | 268 |
| 268 | 269 |
| 269 LocationSummary* EqualityCompareInstr::MakeLocationSummary() const { | 270 LocationSummary* EqualityCompareInstr::MakeLocationSummary() const { |
| 270 const intptr_t kNumInputs = 2; | 271 const intptr_t kNumInputs = 2; |
| 271 const bool is_checked_strict_equal = | 272 const bool is_checked_strict_equal = |
| 272 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); | 273 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 273 if (receiver_class_id() == kDoubleCid) { | 274 if (receiver_class_id() == kDoubleCid) { |
| 274 const intptr_t kNumTemps = 0; | 275 const intptr_t kNumTemps = 0; |
| 275 LocationSummary* locs = | 276 LocationSummary* locs = |
| 276 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 277 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 277 locs->set_in(0, Location::RequiresXmmRegister()); | 278 locs->set_in(0, Location::RequiresFpuRegister()); |
| 278 locs->set_in(1, Location::RequiresXmmRegister()); | 279 locs->set_in(1, Location::RequiresFpuRegister()); |
| 279 locs->set_out(Location::RequiresRegister()); | 280 locs->set_out(Location::RequiresRegister()); |
| 280 return locs; | 281 return locs; |
| 281 } | 282 } |
| 282 if (receiver_class_id() == kSmiCid) { | 283 if (receiver_class_id() == kSmiCid) { |
| 283 const intptr_t kNumTemps = 0; | 284 const intptr_t kNumTemps = 0; |
| 284 LocationSummary* locs = | 285 LocationSummary* locs = |
| 285 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 286 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 286 locs->set_in(0, Location::RegisterOrConstant(left())); | 287 locs->set_in(0, Location::RegisterOrConstant(left())); |
| 287 // Only one input can be a constant operand. The case of two constant | 288 // Only one input can be a constant operand. The case of two constant |
| 288 // operands should be handled by constant propagation. | 289 // operands should be handled by constant propagation. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 const ICData& original_ic_data) { | 332 const ICData& original_ic_data) { |
| 332 if (!compiler->is_optimizing()) { | 333 if (!compiler->is_optimizing()) { |
| 333 compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore, | 334 compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore, |
| 334 deopt_id, | 335 deopt_id, |
| 335 token_pos); | 336 token_pos); |
| 336 } | 337 } |
| 337 const int kNumberOfArguments = 2; | 338 const int kNumberOfArguments = 2; |
| 338 const Array& kNoArgumentNames = Array::Handle(); | 339 const Array& kNoArgumentNames = Array::Handle(); |
| 339 const int kNumArgumentsChecked = 2; | 340 const int kNumArgumentsChecked = 2; |
| 340 | 341 |
| 341 const Immediate raw_null = | 342 const Immediate& raw_null = |
| 342 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 343 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 343 Label check_identity; | 344 Label check_identity; |
| 344 __ cmpq(Address(RSP, 0 * kWordSize), raw_null); | 345 __ cmpq(Address(RSP, 0 * kWordSize), raw_null); |
| 345 __ j(EQUAL, &check_identity); | 346 __ j(EQUAL, &check_identity); |
| 346 __ cmpq(Address(RSP, 1 * kWordSize), raw_null); | 347 __ cmpq(Address(RSP, 1 * kWordSize), raw_null); |
| 347 __ j(EQUAL, &check_identity); | 348 __ j(EQUAL, &check_identity); |
| 348 | 349 |
| 349 ICData& equality_ic_data = ICData::ZoneHandle(original_ic_data.raw()); | 350 ICData& equality_ic_data = ICData::ZoneHandle(original_ic_data.raw()); |
| 350 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { | 351 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { |
| 351 ASSERT(!original_ic_data.IsNull()); | 352 ASSERT(!original_ic_data.IsNull()); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 BranchInstr* branch, | 519 BranchInstr* branch, |
| 519 intptr_t deopt_id) { | 520 intptr_t deopt_id) { |
| 520 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | 521 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 521 Register left = locs.in(0).reg(); | 522 Register left = locs.in(0).reg(); |
| 522 Register right = locs.in(1).reg(); | 523 Register right = locs.in(1).reg(); |
| 523 Register temp = locs.temp(0).reg(); | 524 Register temp = locs.temp(0).reg(); |
| 524 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); | 525 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); |
| 525 __ testq(left, Immediate(kSmiTagMask)); | 526 __ testq(left, Immediate(kSmiTagMask)); |
| 526 __ j(ZERO, deopt); | 527 __ j(ZERO, deopt); |
| 527 // 'left' is not Smi. | 528 // 'left' is not Smi. |
| 528 const Immediate raw_null = | 529 const Immediate& raw_null = |
| 529 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 530 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 530 Label identity_compare; | 531 Label identity_compare; |
| 531 __ cmpq(right, raw_null); | 532 __ cmpq(right, raw_null); |
| 532 __ j(EQUAL, &identity_compare); | 533 __ j(EQUAL, &identity_compare); |
| 533 __ cmpq(left, raw_null); | 534 __ cmpq(left, raw_null); |
| 534 __ j(EQUAL, &identity_compare); | 535 __ j(EQUAL, &identity_compare); |
| 535 | 536 |
| 536 __ LoadClassId(temp, left); | 537 __ LoadClassId(temp, left); |
| 537 const intptr_t len = ic_data.NumberOfChecks(); | 538 const intptr_t len = ic_data.NumberOfChecks(); |
| 538 for (intptr_t i = 0; i < len; i++) { | 539 for (intptr_t i = 0; i < len; i++) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 569 LocationSummary* locs, | 570 LocationSummary* locs, |
| 570 Token::Kind kind, | 571 Token::Kind kind, |
| 571 BranchInstr* branch, | 572 BranchInstr* branch, |
| 572 const ICData& ic_data, | 573 const ICData& ic_data, |
| 573 intptr_t deopt_id, | 574 intptr_t deopt_id, |
| 574 intptr_t token_pos) { | 575 intptr_t token_pos) { |
| 575 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | 576 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 576 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); | 577 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 577 Register left = locs->in(0).reg(); | 578 Register left = locs->in(0).reg(); |
| 578 Register right = locs->in(1).reg(); | 579 Register right = locs->in(1).reg(); |
| 579 const Immediate raw_null = | 580 const Immediate& raw_null = |
| 580 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 581 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 581 Label done, identity_compare, non_null_compare; | 582 Label done, identity_compare, non_null_compare; |
| 582 __ cmpq(right, raw_null); | 583 __ cmpq(right, raw_null); |
| 583 __ j(EQUAL, &identity_compare, Assembler::kNearJump); | 584 __ j(EQUAL, &identity_compare, Assembler::kNearJump); |
| 584 __ cmpq(left, raw_null); | 585 __ cmpq(left, raw_null); |
| 585 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); | 586 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); |
| 586 // Comparison with NULL is "===". | 587 // Comparison with NULL is "===". |
| 587 __ Bind(&identity_compare); | 588 __ Bind(&identity_compare); |
| 588 __ cmpq(left, right); | 589 __ cmpq(left, right); |
| 589 Condition cond = TokenKindToSmiCondition(kind); | 590 Condition cond = TokenKindToSmiCondition(kind); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 654 UNREACHABLE(); | 655 UNREACHABLE(); |
| 655 return OVERFLOW; | 656 return OVERFLOW; |
| 656 } | 657 } |
| 657 } | 658 } |
| 658 | 659 |
| 659 | 660 |
| 660 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, | 661 static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler, |
| 661 const LocationSummary& locs, | 662 const LocationSummary& locs, |
| 662 Token::Kind kind, | 663 Token::Kind kind, |
| 663 BranchInstr* branch) { | 664 BranchInstr* branch) { |
| 664 XmmRegister left = locs.in(0).xmm_reg(); | 665 XmmRegister left = locs.in(0).fpu_reg(); |
| 665 XmmRegister right = locs.in(1).xmm_reg(); | 666 XmmRegister right = locs.in(1).fpu_reg(); |
| 666 | 667 |
| 667 Condition true_condition = TokenKindToDoubleCondition(kind); | 668 Condition true_condition = TokenKindToDoubleCondition(kind); |
| 668 if (branch != NULL) { | 669 if (branch != NULL) { |
| 669 compiler->EmitDoubleCompareBranch( | 670 compiler->EmitDoubleCompareBranch( |
| 670 true_condition, left, right, branch); | 671 true_condition, left, right, branch); |
| 671 } else { | 672 } else { |
| 672 compiler->EmitDoubleCompareBool( | 673 compiler->EmitDoubleCompareBool( |
| 673 true_condition, left, right, locs.out().reg()); | 674 true_condition, left, right, locs.out().reg()); |
| 674 } | 675 } |
| 675 } | 676 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 757 branch->EmitBranchOnCondition(compiler, branch_condition); | 758 branch->EmitBranchOnCondition(compiler, branch_condition); |
| 758 } | 759 } |
| 759 | 760 |
| 760 | 761 |
| 761 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { | 762 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { |
| 762 const intptr_t kNumInputs = 2; | 763 const intptr_t kNumInputs = 2; |
| 763 const intptr_t kNumTemps = 0; | 764 const intptr_t kNumTemps = 0; |
| 764 if (operands_class_id() == kDoubleCid) { | 765 if (operands_class_id() == kDoubleCid) { |
| 765 LocationSummary* summary = | 766 LocationSummary* summary = |
| 766 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 767 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 767 summary->set_in(0, Location::RequiresXmmRegister()); | 768 summary->set_in(0, Location::RequiresFpuRegister()); |
| 768 summary->set_in(1, Location::RequiresXmmRegister()); | 769 summary->set_in(1, Location::RequiresFpuRegister()); |
| 769 summary->set_out(Location::RequiresRegister()); | 770 summary->set_out(Location::RequiresRegister()); |
| 770 return summary; | 771 return summary; |
| 771 } else if (operands_class_id() == kSmiCid) { | 772 } else if (operands_class_id() == kSmiCid) { |
| 772 LocationSummary* summary = | 773 LocationSummary* summary = |
| 773 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 774 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 774 summary->set_in(0, Location::RegisterOrConstant(left())); | 775 summary->set_in(0, Location::RegisterOrConstant(left())); |
| 775 // Only one input can be a constant operand. The case of two constant | 776 // Only one input can be a constant operand. The case of two constant |
| 776 // operands should be handled by constant propagation. | 777 // operands should be handled by constant propagation. |
| 777 summary->set_in(1, summary->in(0).IsConstant() | 778 summary->set_in(1, summary->in(0).IsConstant() |
| 778 ? Location::RequiresRegister() | 779 ? Location::RequiresRegister() |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1002 LocationSummary* LoadIndexedInstr::MakeLocationSummary() const { | 1003 LocationSummary* LoadIndexedInstr::MakeLocationSummary() const { |
| 1003 const intptr_t kNumInputs = 2; | 1004 const intptr_t kNumInputs = 2; |
| 1004 const intptr_t kNumTemps = 0; | 1005 const intptr_t kNumTemps = 0; |
| 1005 LocationSummary* locs = | 1006 LocationSummary* locs = |
| 1006 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 1007 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 1007 locs->set_in(0, Location::RequiresRegister()); | 1008 locs->set_in(0, Location::RequiresRegister()); |
| 1008 locs->set_in(1, CanBeImmediateIndex(index(), class_id()) | 1009 locs->set_in(1, CanBeImmediateIndex(index(), class_id()) |
| 1009 ? Location::RegisterOrSmiConstant(index()) | 1010 ? Location::RegisterOrSmiConstant(index()) |
| 1010 : Location::RequiresRegister()); | 1011 : Location::RequiresRegister()); |
| 1011 if (representation() == kUnboxedDouble) { | 1012 if (representation() == kUnboxedDouble) { |
| 1012 locs->set_out(Location::RequiresXmmRegister()); | 1013 locs->set_out(Location::RequiresFpuRegister()); |
| 1013 } else { | 1014 } else { |
| 1014 locs->set_out(Location::RequiresRegister()); | 1015 locs->set_out(Location::RequiresRegister()); |
| 1015 } | 1016 } |
| 1016 return locs; | 1017 return locs; |
| 1017 } | 1018 } |
| 1018 | 1019 |
| 1019 | 1020 |
| 1020 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1021 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1021 Register array = locs()->in(0).reg(); | 1022 Register array = locs()->in(0).reg(); |
| 1022 Location index = locs()->in(1); | 1023 Location index = locs()->in(1); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1041 return; | 1042 return; |
| 1042 } | 1043 } |
| 1043 | 1044 |
| 1044 FieldAddress element_address = index.IsRegister() ? | 1045 FieldAddress element_address = index.IsRegister() ? |
| 1045 FlowGraphCompiler::ElementAddressForRegIndex( | 1046 FlowGraphCompiler::ElementAddressForRegIndex( |
| 1046 class_id(), array, index.reg()) : | 1047 class_id(), array, index.reg()) : |
| 1047 FlowGraphCompiler::ElementAddressForIntIndex( | 1048 FlowGraphCompiler::ElementAddressForIntIndex( |
| 1048 class_id(), array, Smi::Cast(index.constant()).Value()); | 1049 class_id(), array, Smi::Cast(index.constant()).Value()); |
| 1049 | 1050 |
| 1050 if (representation() == kUnboxedDouble) { | 1051 if (representation() == kUnboxedDouble) { |
| 1051 XmmRegister result = locs()->out().xmm_reg(); | 1052 XmmRegister result = locs()->out().fpu_reg(); |
| 1052 if (class_id() == kFloat32ArrayCid) { | 1053 if (class_id() == kFloat32ArrayCid) { |
| 1053 // Load single precision float. | 1054 // Load single precision float. |
| 1054 __ movss(result, element_address); | 1055 __ movss(result, element_address); |
| 1055 // Promote to double. | 1056 // Promote to double. |
| 1056 __ cvtss2sd(result, locs()->out().xmm_reg()); | 1057 __ cvtss2sd(result, locs()->out().fpu_reg()); |
| 1057 } else { | 1058 } else { |
| 1058 ASSERT(class_id() == kFloat64ArrayCid); | 1059 ASSERT(class_id() == kFloat64ArrayCid); |
| 1059 __ movsd(result, element_address); | 1060 __ movsd(result, element_address); |
| 1060 } | 1061 } |
| 1061 return; | 1062 return; |
| 1062 } | 1063 } |
| 1063 | 1064 |
| 1064 Register result = locs()->out().reg(); | 1065 Register result = locs()->out().reg(); |
| 1065 if ((class_id() == kUint8ArrayCid) || | 1066 if ((class_id() == kUint8ArrayCid) || |
| 1066 (class_id() == kUint8ClampedArrayCid)) { | 1067 (class_id() == kUint8ClampedArrayCid)) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1095 ? Location::WritableRegister() | 1096 ? Location::WritableRegister() |
| 1096 : Location::RegisterOrConstant(value())); | 1097 : Location::RegisterOrConstant(value())); |
| 1097 break; | 1098 break; |
| 1098 case kUint8ArrayCid: | 1099 case kUint8ArrayCid: |
| 1099 // TODO(fschneider): Add location constraint for byte registers (RAX, | 1100 // TODO(fschneider): Add location constraint for byte registers (RAX, |
| 1100 // RBX, RCX, RDX) instead of using a fixed register. | 1101 // RBX, RCX, RDX) instead of using a fixed register. |
| 1101 locs->set_in(2, Location::FixedRegisterOrSmiConstant(value(), RAX)); | 1102 locs->set_in(2, Location::FixedRegisterOrSmiConstant(value(), RAX)); |
| 1102 break; | 1103 break; |
| 1103 case kFloat32ArrayCid: | 1104 case kFloat32ArrayCid: |
| 1104 // Need temp register for float-to-double conversion. | 1105 // Need temp register for float-to-double conversion. |
| 1105 locs->AddTemp(Location::RequiresXmmRegister()); | 1106 locs->AddTemp(Location::RequiresFpuRegister()); |
| 1106 // Fall through. | 1107 // Fall through. |
| 1107 case kFloat64ArrayCid: | 1108 case kFloat64ArrayCid: |
| 1108 // TODO(srdjan): Support Float64 constants. | 1109 // TODO(srdjan): Support Float64 constants. |
| 1109 locs->set_in(2, Location::RequiresXmmRegister()); | 1110 locs->set_in(2, Location::RequiresFpuRegister()); |
| 1110 break; | 1111 break; |
| 1111 default: | 1112 default: |
| 1112 UNREACHABLE(); | 1113 UNREACHABLE(); |
| 1113 return NULL; | 1114 return NULL; |
| 1114 } | 1115 } |
| 1115 return locs; | 1116 return locs; |
| 1116 } | 1117 } |
| 1117 | 1118 |
| 1118 | 1119 |
| 1119 void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1120 void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1151 ASSERT(locs()->in(2).reg() == RAX); | 1152 ASSERT(locs()->in(2).reg() == RAX); |
| 1152 __ SmiUntag(RAX); | 1153 __ SmiUntag(RAX); |
| 1153 __ movb(element_address, RAX); | 1154 __ movb(element_address, RAX); |
| 1154 } | 1155 } |
| 1155 if (index.IsRegister()) { | 1156 if (index.IsRegister()) { |
| 1156 __ SmiTag(index.reg()); // Re-tag. | 1157 __ SmiTag(index.reg()); // Re-tag. |
| 1157 } | 1158 } |
| 1158 break; | 1159 break; |
| 1159 case kFloat32ArrayCid: | 1160 case kFloat32ArrayCid: |
| 1160 // Convert to single precision. | 1161 // Convert to single precision. |
| 1161 __ cvtsd2ss(locs()->temp(0).xmm_reg(), locs()->in(2).xmm_reg()); | 1162 __ cvtsd2ss(locs()->temp(0).fpu_reg(), locs()->in(2).fpu_reg()); |
| 1162 // Store. | 1163 // Store. |
| 1163 __ movss(element_address, locs()->temp(0).xmm_reg()); | 1164 __ movss(element_address, locs()->temp(0).fpu_reg()); |
| 1164 break; | 1165 break; |
| 1165 case kFloat64ArrayCid: | 1166 case kFloat64ArrayCid: |
| 1166 __ movsd(element_address, locs()->in(2).xmm_reg()); | 1167 __ movsd(element_address, locs()->in(2).fpu_reg()); |
| 1167 break; | 1168 break; |
| 1168 default: | 1169 default: |
| 1169 UNREACHABLE(); | 1170 UNREACHABLE(); |
| 1170 } | 1171 } |
| 1171 } | 1172 } |
| 1172 | 1173 |
| 1173 | 1174 |
| 1174 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { | 1175 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { |
| 1175 const intptr_t kNumInputs = 2; | 1176 const intptr_t kNumInputs = 2; |
| 1176 const intptr_t num_temps = 0; | 1177 const intptr_t num_temps = 0; |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1361 Register result_reg = locs()->out().reg(); | 1362 Register result_reg = locs()->out().reg(); |
| 1362 | 1363 |
| 1363 // 'instantiator_reg' is the instantiator AbstractTypeArguments object | 1364 // 'instantiator_reg' is the instantiator AbstractTypeArguments object |
| 1364 // (or null). | 1365 // (or null). |
| 1365 // If the instantiator is null and if the type argument vector | 1366 // If the instantiator is null and if the type argument vector |
| 1366 // instantiated from null becomes a vector of dynamic, then use null as | 1367 // instantiated from null becomes a vector of dynamic, then use null as |
| 1367 // the type arguments. | 1368 // the type arguments. |
| 1368 Label type_arguments_instantiated; | 1369 Label type_arguments_instantiated; |
| 1369 const intptr_t len = type_arguments().Length(); | 1370 const intptr_t len = type_arguments().Length(); |
| 1370 if (type_arguments().IsRawInstantiatedRaw(len)) { | 1371 if (type_arguments().IsRawInstantiatedRaw(len)) { |
| 1371 const Immediate raw_null = | 1372 const Immediate& raw_null = |
| 1372 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1373 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1373 __ cmpq(instantiator_reg, raw_null); | 1374 __ cmpq(instantiator_reg, raw_null); |
| 1374 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1375 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1375 } | 1376 } |
| 1376 // Instantiate non-null type arguments. | 1377 // Instantiate non-null type arguments. |
| 1377 if (type_arguments().IsUninstantiatedIdentity()) { | 1378 if (type_arguments().IsUninstantiatedIdentity()) { |
| 1378 // Check if the instantiator type argument vector is a TypeArguments of a | 1379 // Check if the instantiator type argument vector is a TypeArguments of a |
| 1379 // matching length and, if so, use it as the instantiated type_arguments. | 1380 // matching length and, if so, use it as the instantiated type_arguments. |
| 1380 // No need to check the instantiator ('instantiator_reg') for null here, | 1381 // No need to check the instantiator ('instantiator_reg') for null here, |
| 1381 // because a null instantiator will have the wrong class (Null instead of | 1382 // because a null instantiator will have the wrong class (Null instead of |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1422 ASSERT(instantiator_reg == result_reg); | 1423 ASSERT(instantiator_reg == result_reg); |
| 1423 | 1424 |
| 1424 // instantiator_reg is the instantiator type argument vector, i.e. an | 1425 // instantiator_reg is the instantiator type argument vector, i.e. an |
| 1425 // AbstractTypeArguments object (or null). | 1426 // AbstractTypeArguments object (or null). |
| 1426 // If the instantiator is null and if the type argument vector | 1427 // If the instantiator is null and if the type argument vector |
| 1427 // instantiated from null becomes a vector of dynamic, then use null as | 1428 // instantiated from null becomes a vector of dynamic, then use null as |
| 1428 // the type arguments. | 1429 // the type arguments. |
| 1429 Label type_arguments_instantiated; | 1430 Label type_arguments_instantiated; |
| 1430 const intptr_t len = type_arguments().Length(); | 1431 const intptr_t len = type_arguments().Length(); |
| 1431 if (type_arguments().IsRawInstantiatedRaw(len)) { | 1432 if (type_arguments().IsRawInstantiatedRaw(len)) { |
| 1432 const Immediate raw_null = | 1433 const Immediate& raw_null = |
| 1433 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1434 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1434 __ cmpq(instantiator_reg, raw_null); | 1435 __ cmpq(instantiator_reg, raw_null); |
| 1435 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1436 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1436 } | 1437 } |
| 1437 // Instantiate non-null type arguments. | 1438 // Instantiate non-null type arguments. |
| 1438 if (type_arguments().IsUninstantiatedIdentity()) { | 1439 if (type_arguments().IsUninstantiatedIdentity()) { |
| 1439 // Check if the instantiator type argument vector is a TypeArguments of a | 1440 // Check if the instantiator type argument vector is a TypeArguments of a |
| 1440 // matching length and, if so, use it as the instantiated type_arguments. | 1441 // matching length and, if so, use it as the instantiated type_arguments. |
| 1441 // No need to check instantiator_reg for null here, because a null | 1442 // No need to check instantiator_reg for null here, because a null |
| 1442 // instantiator will have the wrong class (Null instead of TypeArguments). | 1443 // instantiator will have the wrong class (Null instead of TypeArguments). |
| 1443 Label type_arguments_uninstantiated; | 1444 Label type_arguments_uninstantiated; |
| 1444 __ CompareClassId(instantiator_reg, kTypeArgumentsCid); | 1445 __ CompareClassId(instantiator_reg, kTypeArgumentsCid); |
| 1445 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); | 1446 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); |
| 1446 Immediate arguments_length = | 1447 const Immediate& arguments_length = |
| 1447 Immediate(Smi::RawValue(type_arguments().Length())); | 1448 Immediate(Smi::RawValue(type_arguments().Length())); |
| 1448 __ cmpq(FieldAddress(instantiator_reg, TypeArguments::length_offset()), | 1449 __ cmpq(FieldAddress(instantiator_reg, TypeArguments::length_offset()), |
| 1449 arguments_length); | 1450 arguments_length); |
| 1450 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 1451 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 1451 __ Bind(&type_arguments_uninstantiated); | 1452 __ Bind(&type_arguments_uninstantiated); |
| 1452 } | 1453 } |
| 1453 // In the non-factory case, we rely on the allocation stub to | 1454 // In the non-factory case, we rely on the allocation stub to |
| 1454 // instantiate the type arguments. | 1455 // instantiate the type arguments. |
| 1455 __ LoadObject(result_reg, type_arguments()); | 1456 __ LoadObject(result_reg, type_arguments()); |
| 1456 // result_reg: uninstantiated type arguments. | 1457 // result_reg: uninstantiated type arguments. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1476 Register instantiator_reg = locs()->in(0).reg(); | 1477 Register instantiator_reg = locs()->in(0).reg(); |
| 1477 ASSERT(locs()->out().reg() == instantiator_reg); | 1478 ASSERT(locs()->out().reg() == instantiator_reg); |
| 1478 | 1479 |
| 1479 // instantiator_reg is the instantiator AbstractTypeArguments object | 1480 // instantiator_reg is the instantiator AbstractTypeArguments object |
| 1480 // (or null). If the instantiator is null and if the type argument vector | 1481 // (or null). If the instantiator is null and if the type argument vector |
| 1481 // instantiated from null becomes a vector of dynamic, then use null as | 1482 // instantiated from null becomes a vector of dynamic, then use null as |
| 1482 // the type arguments and do not pass the instantiator. | 1483 // the type arguments and do not pass the instantiator. |
| 1483 Label done; | 1484 Label done; |
| 1484 const intptr_t len = type_arguments().Length(); | 1485 const intptr_t len = type_arguments().Length(); |
| 1485 if (type_arguments().IsRawInstantiatedRaw(len)) { | 1486 if (type_arguments().IsRawInstantiatedRaw(len)) { |
| 1486 const Immediate raw_null = | 1487 const Immediate& raw_null = |
| 1487 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1488 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1488 Label instantiator_not_null; | 1489 Label instantiator_not_null; |
| 1489 __ cmpq(instantiator_reg, raw_null); | 1490 __ cmpq(instantiator_reg, raw_null); |
| 1490 __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump); | 1491 __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump); |
| 1491 // Null was used in VisitExtractConstructorTypeArguments as the | 1492 // Null was used in VisitExtractConstructorTypeArguments as the |
| 1492 // instantiated type arguments, no proper instantiator needed. | 1493 // instantiated type arguments, no proper instantiator needed. |
| 1493 __ movq(instantiator_reg, | 1494 __ movq(instantiator_reg, |
| 1494 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); | 1495 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1495 __ jmp(&done); | 1496 __ jmp(&done); |
| 1496 __ Bind(&instantiator_not_null); | 1497 __ Bind(&instantiator_not_null); |
| 1497 } | 1498 } |
| 1498 // Instantiate non-null type arguments. | 1499 // Instantiate non-null type arguments. |
| 1499 if (type_arguments().IsUninstantiatedIdentity()) { | 1500 if (type_arguments().IsUninstantiatedIdentity()) { |
| 1500 // TODO(regis): The following emitted code is duplicated in | 1501 // TODO(regis): The following emitted code is duplicated in |
| 1501 // VisitExtractConstructorTypeArguments above. The reason is that the code | 1502 // VisitExtractConstructorTypeArguments above. The reason is that the code |
| 1502 // is split between two computations, so that each one produces a | 1503 // is split between two computations, so that each one produces a |
| 1503 // single value, rather than producing a pair of values. | 1504 // single value, rather than producing a pair of values. |
| 1504 // If this becomes an issue, we should expose these tests at the IL level. | 1505 // If this becomes an issue, we should expose these tests at the IL level. |
| 1505 | 1506 |
| 1506 // Check if the instantiator type argument vector is a TypeArguments of a | 1507 // Check if the instantiator type argument vector is a TypeArguments of a |
| 1507 // matching length and, if so, use it as the instantiated type_arguments. | 1508 // matching length and, if so, use it as the instantiated type_arguments. |
| 1508 // No need to check the instantiator (RAX) for null here, because a null | 1509 // No need to check the instantiator (RAX) for null here, because a null |
| 1509 // instantiator will have the wrong class (Null instead of TypeArguments). | 1510 // instantiator will have the wrong class (Null instead of TypeArguments). |
| 1510 __ CompareClassId(instantiator_reg, kTypeArgumentsCid); | 1511 __ CompareClassId(instantiator_reg, kTypeArgumentsCid); |
| 1511 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 1512 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 1512 Immediate arguments_length = | 1513 const Immediate& arguments_length = |
| 1513 Immediate(Smi::RawValue(type_arguments().Length())); | 1514 Immediate(Smi::RawValue(type_arguments().Length())); |
| 1514 __ cmpq(FieldAddress(instantiator_reg, TypeArguments::length_offset()), | 1515 __ cmpq(FieldAddress(instantiator_reg, TypeArguments::length_offset()), |
| 1515 arguments_length); | 1516 arguments_length); |
| 1516 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 1517 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 1517 // The instantiator was used in VisitExtractConstructorTypeArguments as the | 1518 // The instantiator was used in VisitExtractConstructorTypeArguments as the |
| 1518 // instantiated type arguments, no proper instantiator needed. | 1519 // instantiated type arguments, no proper instantiator needed. |
| 1519 __ movq(instantiator_reg, | 1520 __ movq(instantiator_reg, |
| 1520 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); | 1521 Immediate(Smi::RawValue(StubCode::kNoInstantiator))); |
| 1521 } | 1522 } |
| 1522 __ Bind(&done); | 1523 __ Bind(&done); |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1962 } | 1963 } |
| 1963 | 1964 |
| 1964 | 1965 |
| 1965 LocationSummary* BoxDoubleInstr::MakeLocationSummary() const { | 1966 LocationSummary* BoxDoubleInstr::MakeLocationSummary() const { |
| 1966 const intptr_t kNumInputs = 1; | 1967 const intptr_t kNumInputs = 1; |
| 1967 const intptr_t kNumTemps = 0; | 1968 const intptr_t kNumTemps = 0; |
| 1968 LocationSummary* summary = | 1969 LocationSummary* summary = |
| 1969 new LocationSummary(kNumInputs, | 1970 new LocationSummary(kNumInputs, |
| 1970 kNumTemps, | 1971 kNumTemps, |
| 1971 LocationSummary::kCallOnSlowPath); | 1972 LocationSummary::kCallOnSlowPath); |
| 1972 summary->set_in(0, Location::RequiresXmmRegister()); | 1973 summary->set_in(0, Location::RequiresFpuRegister()); |
| 1973 summary->set_out(Location::RequiresRegister()); | 1974 summary->set_out(Location::RequiresRegister()); |
| 1974 return summary; | 1975 return summary; |
| 1975 } | 1976 } |
| 1976 | 1977 |
| 1977 | 1978 |
| 1978 class BoxDoubleSlowPath : public SlowPathCode { | 1979 class BoxDoubleSlowPath : public SlowPathCode { |
| 1979 public: | 1980 public: |
| 1980 explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction) | 1981 explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction) |
| 1981 : instruction_(instruction) { } | 1982 : instruction_(instruction) { } |
| 1982 | 1983 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2005 private: | 2006 private: |
| 2006 BoxDoubleInstr* instruction_; | 2007 BoxDoubleInstr* instruction_; |
| 2007 }; | 2008 }; |
| 2008 | 2009 |
| 2009 | 2010 |
| 2010 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2011 void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2011 BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this); | 2012 BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this); |
| 2012 compiler->AddSlowPathCode(slow_path); | 2013 compiler->AddSlowPathCode(slow_path); |
| 2013 | 2014 |
| 2014 Register out_reg = locs()->out().reg(); | 2015 Register out_reg = locs()->out().reg(); |
| 2015 XmmRegister value = locs()->in(0).xmm_reg(); | 2016 XmmRegister value = locs()->in(0).fpu_reg(); |
| 2016 | 2017 |
| 2017 AssemblerMacros::TryAllocate(compiler->assembler(), | 2018 AssemblerMacros::TryAllocate(compiler->assembler(), |
| 2018 compiler->double_class(), | 2019 compiler->double_class(), |
| 2019 slow_path->entry_label(), | 2020 slow_path->entry_label(), |
| 2020 Assembler::kFarJump, | 2021 Assembler::kFarJump, |
| 2021 out_reg); | 2022 out_reg); |
| 2022 __ Bind(slow_path->exit_label()); | 2023 __ Bind(slow_path->exit_label()); |
| 2023 __ movsd(FieldAddress(out_reg, Double::value_offset()), value); | 2024 __ movsd(FieldAddress(out_reg, Double::value_offset()), value); |
| 2024 } | 2025 } |
| 2025 | 2026 |
| 2026 | 2027 |
| 2027 LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const { | 2028 LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const { |
| 2028 const intptr_t kNumInputs = 1; | 2029 const intptr_t kNumInputs = 1; |
| 2029 const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; | 2030 const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0; |
| 2030 LocationSummary* summary = | 2031 LocationSummary* summary = |
| 2031 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2032 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2032 summary->set_in(0, Location::RequiresRegister()); | 2033 summary->set_in(0, Location::RequiresRegister()); |
| 2033 if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister()); | 2034 if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister()); |
| 2034 summary->set_out(Location::RequiresXmmRegister()); | 2035 summary->set_out(Location::RequiresFpuRegister()); |
| 2035 return summary; | 2036 return summary; |
| 2036 } | 2037 } |
| 2037 | 2038 |
| 2038 | 2039 |
| 2039 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2040 void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2040 const intptr_t value_cid = value()->ResultCid(); | 2041 const intptr_t value_cid = value()->ResultCid(); |
| 2041 const Register value = locs()->in(0).reg(); | 2042 const Register value = locs()->in(0).reg(); |
| 2042 const XmmRegister result = locs()->out().xmm_reg(); | 2043 const XmmRegister result = locs()->out().fpu_reg(); |
| 2043 | 2044 |
| 2044 if (value_cid == kDoubleCid) { | 2045 if (value_cid == kDoubleCid) { |
| 2045 __ movsd(result, FieldAddress(value, Double::value_offset())); | 2046 __ movsd(result, FieldAddress(value, Double::value_offset())); |
| 2046 } else if (value_cid == kSmiCid) { | 2047 } else if (value_cid == kSmiCid) { |
| 2047 __ SmiUntag(value); // Untag input before conversion. | 2048 __ SmiUntag(value); // Untag input before conversion. |
| 2048 __ cvtsi2sd(result, value); | 2049 __ cvtsi2sd(result, value); |
| 2049 __ SmiTag(value); // Restore input register. | 2050 __ SmiTag(value); // Restore input register. |
| 2050 } else { | 2051 } else { |
| 2051 Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp); | 2052 Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp); |
| 2052 compiler->LoadDoubleOrSmiToXmm(result, | 2053 compiler->LoadDoubleOrSmiToFpu(result, |
| 2053 value, | 2054 value, |
| 2054 locs()->temp(0).reg(), | 2055 locs()->temp(0).reg(), |
| 2055 deopt); | 2056 deopt); |
| 2056 } | 2057 } |
| 2057 } | 2058 } |
| 2058 | 2059 |
| 2059 | 2060 |
| 2060 LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const { | 2061 LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const { |
| 2061 const intptr_t kNumInputs = 2; | 2062 const intptr_t kNumInputs = 2; |
| 2062 const intptr_t kNumTemps = 0; | 2063 const intptr_t kNumTemps = 0; |
| 2063 LocationSummary* summary = | 2064 LocationSummary* summary = |
| 2064 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2065 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2065 summary->set_in(0, Location::RequiresXmmRegister()); | 2066 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2066 summary->set_in(1, Location::RequiresXmmRegister()); | 2067 summary->set_in(1, Location::RequiresFpuRegister()); |
| 2067 summary->set_out(Location::SameAsFirstInput()); | 2068 summary->set_out(Location::SameAsFirstInput()); |
| 2068 return summary; | 2069 return summary; |
| 2069 } | 2070 } |
| 2070 | 2071 |
| 2071 | 2072 |
| 2072 void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2073 void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2073 XmmRegister left = locs()->in(0).xmm_reg(); | 2074 XmmRegister left = locs()->in(0).fpu_reg(); |
| 2074 XmmRegister right = locs()->in(1).xmm_reg(); | 2075 XmmRegister right = locs()->in(1).fpu_reg(); |
| 2075 | 2076 |
| 2076 ASSERT(locs()->out().xmm_reg() == left); | 2077 ASSERT(locs()->out().fpu_reg() == left); |
| 2077 | 2078 |
| 2078 switch (op_kind()) { | 2079 switch (op_kind()) { |
| 2079 case Token::kADD: __ addsd(left, right); break; | 2080 case Token::kADD: __ addsd(left, right); break; |
| 2080 case Token::kSUB: __ subsd(left, right); break; | 2081 case Token::kSUB: __ subsd(left, right); break; |
| 2081 case Token::kMUL: __ mulsd(left, right); break; | 2082 case Token::kMUL: __ mulsd(left, right); break; |
| 2082 case Token::kDIV: __ divsd(left, right); break; | 2083 case Token::kDIV: __ divsd(left, right); break; |
| 2083 default: UNREACHABLE(); | 2084 default: UNREACHABLE(); |
| 2084 } | 2085 } |
| 2085 } | 2086 } |
| 2086 | 2087 |
| 2087 | 2088 |
| 2088 LocationSummary* MathSqrtInstr::MakeLocationSummary() const { | 2089 LocationSummary* MathSqrtInstr::MakeLocationSummary() const { |
| 2089 const intptr_t kNumInputs = 1; | 2090 const intptr_t kNumInputs = 1; |
| 2090 const intptr_t kNumTemps = 0; | 2091 const intptr_t kNumTemps = 0; |
| 2091 LocationSummary* summary = | 2092 LocationSummary* summary = |
| 2092 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2093 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2093 summary->set_in(0, Location::RequiresXmmRegister()); | 2094 summary->set_in(0, Location::RequiresFpuRegister()); |
| 2094 summary->set_out(Location::RequiresXmmRegister()); | 2095 summary->set_out(Location::RequiresFpuRegister()); |
| 2095 return summary; | 2096 return summary; |
| 2096 } | 2097 } |
| 2097 | 2098 |
| 2098 | 2099 |
| 2099 void MathSqrtInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2100 void MathSqrtInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2100 __ sqrtsd(locs()->out().xmm_reg(), locs()->in(0).xmm_reg()); | 2101 __ sqrtsd(locs()->out().fpu_reg(), locs()->in(0).fpu_reg()); |
| 2101 } | 2102 } |
| 2102 | 2103 |
| 2103 | 2104 |
| 2104 LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const { | 2105 LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const { |
| 2105 const intptr_t kNumInputs = 1; | 2106 const intptr_t kNumInputs = 1; |
| 2106 const intptr_t kNumTemps = 0; | 2107 const intptr_t kNumTemps = 0; |
| 2107 LocationSummary* summary = | 2108 LocationSummary* summary = |
| 2108 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2109 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2109 summary->set_in(0, Location::RequiresRegister()); | 2110 summary->set_in(0, Location::RequiresRegister()); |
| 2110 summary->set_out(Location::SameAsFirstInput()); | 2111 summary->set_out(Location::SameAsFirstInput()); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2215 locs()); | 2216 locs()); |
| 2216 __ Bind(&done); | 2217 __ Bind(&done); |
| 2217 } | 2218 } |
| 2218 | 2219 |
| 2219 | 2220 |
| 2220 LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const { | 2221 LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const { |
| 2221 const intptr_t kNumInputs = 1; | 2222 const intptr_t kNumInputs = 1; |
| 2222 const intptr_t kNumTemps = 1; | 2223 const intptr_t kNumTemps = 1; |
| 2223 LocationSummary* result = new LocationSummary( | 2224 LocationSummary* result = new LocationSummary( |
| 2224 kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2225 kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2225 result->set_in(0, Location::RequiresXmmRegister()); | 2226 result->set_in(0, Location::RequiresFpuRegister()); |
| 2226 result->set_out(Location:: Location::RequiresRegister()); | 2227 result->set_out(Location:: Location::RequiresRegister()); |
| 2227 result->set_temp(0, Location::RequiresRegister()); | 2228 result->set_temp(0, Location::RequiresRegister()); |
| 2228 return result; | 2229 return result; |
| 2229 } | 2230 } |
| 2230 | 2231 |
| 2231 | 2232 |
| 2232 void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2233 void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2233 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptDoubleToSmi); | 2234 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptDoubleToSmi); |
| 2234 Register result = locs()->out().reg(); | 2235 Register result = locs()->out().reg(); |
| 2235 XmmRegister value = locs()->in(0).xmm_reg(); | 2236 XmmRegister value = locs()->in(0).fpu_reg(); |
| 2236 Register temp = locs()->temp(0).reg(); | 2237 Register temp = locs()->temp(0).reg(); |
| 2237 | 2238 |
| 2238 __ cvttsd2siq(result, value); | 2239 __ cvttsd2siq(result, value); |
| 2239 // Overflow is signalled with minint. | 2240 // Overflow is signalled with minint. |
| 2240 Label do_call, done; | 2241 Label do_call, done; |
| 2241 // Check for overflow and that it fits into Smi. | 2242 // Check for overflow and that it fits into Smi. |
| 2242 __ movq(temp, result); | 2243 __ movq(temp, result); |
| 2243 __ shlq(temp, Immediate(1)); | 2244 __ shlq(temp, Immediate(1)); |
| 2244 __ j(OVERFLOW, deopt); | 2245 __ j(OVERFLOW, deopt); |
| 2245 __ SmiTag(result); | 2246 __ SmiTag(result); |
| 2246 } | 2247 } |
| 2247 | 2248 |
| 2248 | 2249 |
| 2249 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { | 2250 LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const { |
| 2250 const intptr_t kNumInputs = 1; | 2251 const intptr_t kNumInputs = 1; |
| 2251 const intptr_t kNumTemps = | 2252 const intptr_t kNumTemps = |
| 2252 (recognized_kind() == MethodRecognizer::kDoubleRound) ? 1 : 0; | 2253 (recognized_kind() == MethodRecognizer::kDoubleRound) ? 1 : 0; |
| 2253 LocationSummary* result = | 2254 LocationSummary* result = |
| 2254 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2255 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2255 result->set_in(0, Location::RequiresXmmRegister()); | 2256 result->set_in(0, Location::RequiresFpuRegister()); |
| 2256 result->set_out(Location::RequiresXmmRegister()); | 2257 result->set_out(Location::RequiresFpuRegister()); |
| 2257 if (recognized_kind() == MethodRecognizer::kDoubleRound) { | 2258 if (recognized_kind() == MethodRecognizer::kDoubleRound) { |
| 2258 result->set_temp(0, Location::RequiresXmmRegister()); | 2259 result->set_temp(0, Location::RequiresFpuRegister()); |
| 2259 } | 2260 } |
| 2260 return result; | 2261 return result; |
| 2261 } | 2262 } |
| 2262 | 2263 |
| 2263 | 2264 |
| 2264 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2265 void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2265 XmmRegister value = locs()->in(0).xmm_reg(); | 2266 XmmRegister value = locs()->in(0).fpu_reg(); |
| 2266 XmmRegister result = locs()->out().xmm_reg(); | 2267 XmmRegister result = locs()->out().fpu_reg(); |
| 2267 if (recognized_kind() == MethodRecognizer::kDoubleTruncate) { | 2268 if (recognized_kind() == MethodRecognizer::kDoubleTruncate) { |
| 2268 __ roundsd(result, value, Assembler::kRoundToZero); | 2269 __ roundsd(result, value, Assembler::kRoundToZero); |
| 2269 } else { | 2270 } else { |
| 2270 XmmRegister temp = locs()->temp(0).xmm_reg(); | 2271 XmmRegister temp = locs()->temp(0).fpu_reg(); |
| 2271 __ DoubleRound(result, value, temp); | 2272 __ DoubleRound(result, value, temp); |
| 2272 } | 2273 } |
| 2273 } | 2274 } |
| 2274 | 2275 |
| 2275 | 2276 |
| 2276 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const { | 2277 LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const { |
| 2277 return MakeCallSummary(); | 2278 return MakeCallSummary(); |
| 2278 } | 2279 } |
| 2279 | 2280 |
| 2280 | 2281 |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2499 LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const { | 2500 LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const { |
| 2500 UNIMPLEMENTED(); | 2501 UNIMPLEMENTED(); |
| 2501 return NULL; | 2502 return NULL; |
| 2502 } | 2503 } |
| 2503 | 2504 |
| 2504 | 2505 |
| 2505 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2506 void ShiftMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2506 UNIMPLEMENTED(); | 2507 UNIMPLEMENTED(); |
| 2507 } | 2508 } |
| 2508 | 2509 |
| 2510 |
| 2511 LocationSummary* ThrowInstr::MakeLocationSummary() const { |
| 2512 return new LocationSummary(0, 0, LocationSummary::kCall); |
| 2513 } |
| 2514 |
| 2515 |
| 2516 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2517 compiler->GenerateCallRuntime(token_pos(), |
| 2518 kThrowRuntimeEntry, |
| 2519 locs()); |
| 2520 __ int3(); |
| 2521 } |
| 2522 |
| 2523 |
| 2524 LocationSummary* ReThrowInstr::MakeLocationSummary() const { |
| 2525 return new LocationSummary(0, 0, LocationSummary::kCall); |
| 2526 } |
| 2527 |
| 2528 |
| 2529 void ReThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2530 compiler->GenerateCallRuntime(token_pos(), |
| 2531 kReThrowRuntimeEntry, |
| 2532 locs()); |
| 2533 __ int3(); |
| 2534 } |
| 2535 |
| 2536 |
| 2537 LocationSummary* GotoInstr::MakeLocationSummary() const { |
| 2538 return new LocationSummary(0, 0, LocationSummary::kNoCall); |
| 2539 } |
| 2540 |
| 2541 |
| 2542 void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2543 // Add deoptimization descriptor for deoptimizing instructions |
| 2544 // that may be inserted before this instruction. |
| 2545 if (!compiler->is_optimizing()) { |
| 2546 compiler->AddCurrentDescriptor(PcDescriptors::kDeoptBefore, |
| 2547 GetDeoptId(), |
| 2548 0); // No token position. |
| 2549 } |
| 2550 |
| 2551 if (HasParallelMove()) { |
| 2552 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
| 2553 } |
| 2554 |
| 2555 // We can fall through if the successor is the next block in the list. |
| 2556 // Otherwise, we need a jump. |
| 2557 if (!compiler->IsNextBlock(successor())) { |
| 2558 __ jmp(compiler->GetBlockLabel(successor())); |
| 2559 } |
| 2560 } |
| 2561 |
| 2562 |
| 2563 static Condition NegateCondition(Condition condition) { |
| 2564 switch (condition) { |
| 2565 case EQUAL: return NOT_EQUAL; |
| 2566 case NOT_EQUAL: return EQUAL; |
| 2567 case LESS: return GREATER_EQUAL; |
| 2568 case LESS_EQUAL: return GREATER; |
| 2569 case GREATER: return LESS_EQUAL; |
| 2570 case GREATER_EQUAL: return LESS; |
| 2571 case BELOW: return ABOVE_EQUAL; |
| 2572 case BELOW_EQUAL: return ABOVE; |
| 2573 case ABOVE: return BELOW_EQUAL; |
| 2574 case ABOVE_EQUAL: return BELOW; |
| 2575 default: |
| 2576 OS::Print("Error %d\n", condition); |
| 2577 UNIMPLEMENTED(); |
| 2578 return EQUAL; |
| 2579 } |
| 2580 } |
| 2581 |
| 2582 |
| 2583 void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler, |
| 2584 bool value) { |
| 2585 if (value && compiler->IsNextBlock(false_successor())) { |
| 2586 __ jmp(compiler->GetBlockLabel(true_successor())); |
| 2587 } else if (!value && compiler->IsNextBlock(true_successor())) { |
| 2588 __ jmp(compiler->GetBlockLabel(false_successor())); |
| 2589 } |
| 2590 } |
| 2591 |
| 2592 |
| 2593 void ControlInstruction::EmitBranchOnCondition(FlowGraphCompiler* compiler, |
| 2594 Condition true_condition) { |
| 2595 if (compiler->IsNextBlock(false_successor())) { |
| 2596 // If the next block is the false successor we will fall through to it. |
| 2597 __ j(true_condition, compiler->GetBlockLabel(true_successor())); |
| 2598 } else { |
| 2599 // If the next block is the true successor we negate comparison and fall |
| 2600 // through to it. |
| 2601 ASSERT(compiler->IsNextBlock(true_successor())); |
| 2602 Condition false_condition = NegateCondition(true_condition); |
| 2603 __ j(false_condition, compiler->GetBlockLabel(false_successor())); |
| 2604 } |
| 2605 } |
| 2606 |
| 2607 |
| 2608 LocationSummary* CurrentContextInstr::MakeLocationSummary() const { |
| 2609 return LocationSummary::Make(0, |
| 2610 Location::RequiresRegister(), |
| 2611 LocationSummary::kNoCall); |
| 2612 } |
| 2613 |
| 2614 |
| 2615 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2616 __ MoveRegister(locs()->out().reg(), CTX); |
| 2617 } |
| 2618 |
| 2619 |
| 2620 LocationSummary* StrictCompareInstr::MakeLocationSummary() const { |
| 2621 const intptr_t kNumInputs = 2; |
| 2622 const intptr_t kNumTemps = 0; |
| 2623 LocationSummary* locs = |
| 2624 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2625 locs->set_in(0, Location::RegisterOrConstant(left())); |
| 2626 locs->set_in(1, Location::RegisterOrConstant(right())); |
| 2627 locs->set_out(Location::RequiresRegister()); |
| 2628 return locs; |
| 2629 } |
| 2630 |
| 2631 |
| 2632 // Special code for numbers (compare values instead of references.) |
| 2633 void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2634 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
| 2635 Location left = locs()->in(0); |
| 2636 Location right = locs()->in(1); |
| 2637 if (left.IsConstant() && right.IsConstant()) { |
| 2638 // TODO(vegorov): should be eliminated earlier by constant propagation. |
| 2639 const bool result = (kind() == Token::kEQ_STRICT) ? |
| 2640 left.constant().raw() == right.constant().raw() : |
| 2641 left.constant().raw() != right.constant().raw(); |
| 2642 __ LoadObject(locs()->out().reg(), result ? Bool::True() : Bool::False()); |
| 2643 return; |
| 2644 } |
| 2645 if (left.IsConstant()) { |
| 2646 compiler->EmitEqualityRegConstCompare(right.reg(), |
| 2647 left.constant(), |
| 2648 needs_number_check()); |
| 2649 } else if (right.IsConstant()) { |
| 2650 compiler->EmitEqualityRegConstCompare(left.reg(), |
| 2651 right.constant(), |
| 2652 needs_number_check()); |
| 2653 } else { |
| 2654 compiler->EmitEqualityRegRegCompare(left.reg(), |
| 2655 right.reg(), |
| 2656 needs_number_check()); |
| 2657 } |
| 2658 |
| 2659 Register result = locs()->out().reg(); |
| 2660 Label load_true, done; |
| 2661 Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; |
| 2662 __ j(true_condition, &load_true, Assembler::kNearJump); |
| 2663 __ LoadObject(result, Bool::False()); |
| 2664 __ jmp(&done, Assembler::kNearJump); |
| 2665 __ Bind(&load_true); |
| 2666 __ LoadObject(result, Bool::True()); |
| 2667 __ Bind(&done); |
| 2668 } |
| 2669 |
| 2670 |
| 2671 void StrictCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 2672 BranchInstr* branch) { |
| 2673 ASSERT(kind() == Token::kEQ_STRICT || kind() == Token::kNE_STRICT); |
| 2674 Location left = locs()->in(0); |
| 2675 Location right = locs()->in(1); |
| 2676 if (left.IsConstant() && right.IsConstant()) { |
| 2677 // TODO(vegorov): should be eliminated earlier by constant propagation. |
| 2678 const bool result = (kind() == Token::kEQ_STRICT) ? |
| 2679 left.constant().raw() == right.constant().raw() : |
| 2680 left.constant().raw() != right.constant().raw(); |
| 2681 branch->EmitBranchOnValue(compiler, result); |
| 2682 return; |
| 2683 } |
| 2684 if (left.IsConstant()) { |
| 2685 compiler->EmitEqualityRegConstCompare(right.reg(), |
| 2686 left.constant(), |
| 2687 needs_number_check()); |
| 2688 } else if (right.IsConstant()) { |
| 2689 compiler->EmitEqualityRegConstCompare(left.reg(), |
| 2690 right.constant(), |
| 2691 needs_number_check()); |
| 2692 } else { |
| 2693 compiler->EmitEqualityRegRegCompare(left.reg(), |
| 2694 right.reg(), |
| 2695 needs_number_check()); |
| 2696 } |
| 2697 |
| 2698 Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL; |
| 2699 branch->EmitBranchOnCondition(compiler, true_condition); |
| 2700 } |
| 2701 |
| 2702 |
| 2703 void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2704 // The arguments to the stub include the closure, as does the arguments |
| 2705 // descriptor. |
| 2706 Register temp_reg = locs()->temp(0).reg(); |
| 2707 int argument_count = ArgumentCount(); |
| 2708 const Array& arguments_descriptor = |
| 2709 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
| 2710 argument_names())); |
| 2711 __ LoadObject(temp_reg, arguments_descriptor); |
| 2712 compiler->GenerateDartCall(deopt_id(), |
| 2713 token_pos(), |
| 2714 &StubCode::CallClosureFunctionLabel(), |
| 2715 PcDescriptors::kOther, |
| 2716 locs()); |
| 2717 __ Drop(argument_count); |
| 2718 } |
| 2719 |
| 2720 |
| 2721 LocationSummary* BooleanNegateInstr::MakeLocationSummary() const { |
| 2722 return LocationSummary::Make(1, |
| 2723 Location::RequiresRegister(), |
| 2724 LocationSummary::kNoCall); |
| 2725 } |
| 2726 |
| 2727 |
| 2728 void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2729 Register value = locs()->in(0).reg(); |
| 2730 Register result = locs()->out().reg(); |
| 2731 |
| 2732 Label done; |
| 2733 __ LoadObject(result, Bool::True()); |
| 2734 __ CompareRegisters(result, value); |
| 2735 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 2736 __ LoadObject(result, Bool::False()); |
| 2737 __ Bind(&done); |
| 2738 } |
| 2739 |
| 2740 |
| 2741 LocationSummary* ChainContextInstr::MakeLocationSummary() const { |
| 2742 return LocationSummary::Make(1, |
| 2743 Location::NoLocation(), |
| 2744 LocationSummary::kNoCall); |
| 2745 } |
| 2746 |
| 2747 |
| 2748 void ChainContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2749 Register context_value = locs()->in(0).reg(); |
| 2750 |
| 2751 // Chain the new context in context_value to its parent in CTX. |
| 2752 __ StoreIntoObject(context_value, |
| 2753 FieldAddress(context_value, Context::parent_offset()), |
| 2754 CTX); |
| 2755 // Set new context as current context. |
| 2756 __ MoveRegister(CTX, context_value); |
| 2757 } |
| 2758 |
| 2759 |
| 2760 LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const { |
| 2761 const intptr_t kNumInputs = 2; |
| 2762 const intptr_t kNumTemps = 0; |
| 2763 LocationSummary* locs = |
| 2764 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2765 locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister() |
| 2766 : Location::RequiresRegister()); |
| 2767 locs->set_in(1, Location::RequiresRegister()); |
| 2768 return locs; |
| 2769 } |
| 2770 |
| 2771 |
| 2772 void StoreVMFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2773 Register value_reg = locs()->in(0).reg(); |
| 2774 Register dest_reg = locs()->in(1).reg(); |
| 2775 |
| 2776 if (value()->NeedsStoreBuffer()) { |
| 2777 __ StoreIntoObject(dest_reg, FieldAddress(dest_reg, offset_in_bytes()), |
| 2778 value_reg); |
| 2779 } else { |
| 2780 __ StoreIntoObjectNoBarrier( |
| 2781 dest_reg, FieldAddress(dest_reg, offset_in_bytes()), value_reg); |
| 2782 } |
| 2783 } |
| 2784 |
| 2785 |
| 2786 LocationSummary* AllocateObjectInstr::MakeLocationSummary() const { |
| 2787 return MakeCallSummary(); |
| 2788 } |
| 2789 |
| 2790 |
| 2791 void AllocateObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2792 const Class& cls = Class::ZoneHandle(constructor().Owner()); |
| 2793 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); |
| 2794 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); |
| 2795 compiler->GenerateCall(token_pos(), |
| 2796 &label, |
| 2797 PcDescriptors::kOther, |
| 2798 locs()); |
| 2799 __ Drop(ArgumentCount()); // Discard arguments. |
| 2800 } |
| 2801 |
| 2802 |
| 2803 LocationSummary* CreateClosureInstr::MakeLocationSummary() const { |
| 2804 return MakeCallSummary(); |
| 2805 } |
| 2806 |
| 2807 |
| 2808 void CreateClosureInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2809 const Function& closure_function = function(); |
| 2810 ASSERT(!closure_function.IsImplicitStaticClosureFunction()); |
| 2811 const Code& stub = Code::Handle( |
| 2812 StubCode::GetAllocationStubForClosure(closure_function)); |
| 2813 const ExternalLabel label(closure_function.ToCString(), stub.EntryPoint()); |
| 2814 compiler->GenerateCall(token_pos(), |
| 2815 &label, |
| 2816 PcDescriptors::kOther, |
| 2817 locs()); |
| 2818 __ Drop(2); // Discard type arguments and receiver. |
| 2819 } |
| 2820 |
| 2509 } // namespace dart | 2821 } // namespace dart |
| 2510 | 2822 |
| 2511 #undef __ | 2823 #undef __ |
| 2512 | 2824 |
| 2513 #endif // defined TARGET_ARCH_X64 | 2825 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |