| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 case Token::kGTE: return GREATER_EQUAL; | 246 case Token::kGTE: return GREATER_EQUAL; |
| 247 default: | 247 default: |
| 248 UNREACHABLE(); | 248 UNREACHABLE(); |
| 249 return OVERFLOW; | 249 return OVERFLOW; |
| 250 } | 250 } |
| 251 } | 251 } |
| 252 | 252 |
| 253 | 253 |
| 254 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { | 254 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { |
| 255 const intptr_t kNumInputs = 2; | 255 const intptr_t kNumInputs = 2; |
| 256 if (receiver_class_id() != kObjectCid) { | 256 const bool is_checked_strict_equal = |
| 257 ASSERT((receiver_class_id() == kSmiCid) || | 257 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 258 (receiver_class_id() == kDoubleCid)); | 258 if ((receiver_class_id() == kSmiCid) || |
| 259 (receiver_class_id() == kDoubleCid) || |
| 260 is_checked_strict_equal) { |
| 259 const intptr_t kNumTemps = 1; | 261 const intptr_t kNumTemps = 1; |
| 260 LocationSummary* locs = | 262 LocationSummary* locs = |
| 261 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 263 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 262 locs->set_in(0, Location::RequiresRegister()); | 264 locs->set_in(0, Location::RequiresRegister()); |
| 263 locs->set_in(1, Location::RequiresRegister()); | 265 locs->set_in(1, Location::RequiresRegister()); |
| 264 locs->set_temp(0, Location::RequiresRegister()); | 266 locs->set_temp(0, Location::RequiresRegister()); |
| 265 locs->set_out(Location::RequiresRegister()); | 267 locs->set_out(Location::RequiresRegister()); |
| 266 return locs; | 268 return locs; |
| 267 } | 269 } |
| 268 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 270 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); | 341 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); |
| 340 __ movq(temp, Immediate(kSmiCid)); | 342 __ movq(temp, Immediate(kSmiCid)); |
| 341 __ jmp(&done, Assembler::kNearJump); | 343 __ jmp(&done, Assembler::kNearJump); |
| 342 __ Bind(&load_class_id); | 344 __ Bind(&load_class_id); |
| 343 __ LoadClassId(temp, left); | 345 __ LoadClassId(temp, left); |
| 344 __ Bind(&done); | 346 __ Bind(&done); |
| 345 } else { | 347 } else { |
| 346 __ j(ZERO, deopt); // Smi deopts. | 348 __ j(ZERO, deopt); // Smi deopts. |
| 347 __ LoadClassId(temp, left); | 349 __ LoadClassId(temp, left); |
| 348 } | 350 } |
| 351 // 'temp' contains class-id of the left argument. |
| 352 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 349 Condition cond = TokenKindToSmiCondition(kind); | 353 Condition cond = TokenKindToSmiCondition(kind); |
| 350 Label done; | 354 Label done; |
| 351 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 355 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 356 // Assert that the Smi is at position 0, if at all. |
| 352 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); | 357 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); |
| 353 Label next_test; | 358 Label next_test; |
| 354 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); | 359 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); |
| 355 __ j(NOT_EQUAL, &next_test); | 360 __ j(NOT_EQUAL, &next_test); |
| 356 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); | 361 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); |
| 357 ObjectStore* object_store = Isolate::Current()->object_store(); | |
| 358 if (target.owner() == object_store->object_class()) { | 362 if (target.owner() == object_store->object_class()) { |
| 359 // Object.== is same as ===. | 363 // Object.== is same as ===. |
| 360 __ Drop(2); | 364 __ Drop(2); |
| 361 __ cmpq(left, right); | 365 __ cmpq(left, right); |
| 362 if (branch != NULL) { | 366 if (branch != NULL) { |
| 363 branch->EmitBranchOnCondition(compiler, cond); | 367 branch->EmitBranchOnCondition(compiler, cond); |
| 364 } else { | 368 } else { |
| 365 // This case should be rare. | 369 // This case should be rare. |
| 366 Register result = locs.out().reg(); | 370 Register result = locs.out().reg(); |
| 367 Label load_true; | 371 Label load_true; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 398 } | 402 } |
| 399 __ jmp(&done); | 403 __ jmp(&done); |
| 400 __ Bind(&next_test); | 404 __ Bind(&next_test); |
| 401 } | 405 } |
| 402 // Fall through leads to deoptimization | 406 // Fall through leads to deoptimization |
| 403 __ jmp(deopt); | 407 __ jmp(deopt); |
| 404 __ Bind(&done); | 408 __ Bind(&done); |
| 405 } | 409 } |
| 406 | 410 |
| 407 | 411 |
| 412 // Emit code when ICData's targets are all Object == (which is ===). |
| 413 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler, |
| 414 const ICData& ic_data, |
| 415 const LocationSummary& locs, |
| 416 Token::Kind kind, |
| 417 BranchInstr* branch, |
| 418 intptr_t deopt_id, |
| 419 intptr_t token_pos, |
| 420 intptr_t try_index) { |
| 421 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 422 Register left = locs.in(0).reg(); |
| 423 Register right = locs.in(1).reg(); |
| 424 Register temp = locs.temp(0).reg(); |
| 425 Label* deopt = compiler->AddDeoptStub(deopt_id, |
| 426 try_index, |
| 427 kDeoptEquality, |
| 428 left, |
| 429 right); |
| 430 __ testq(left, Immediate(kSmiTagMask)); |
| 431 __ j(ZERO, deopt); |
| 432 __ LoadClassId(temp, left); |
| 433 Label done; |
| 434 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 435 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); |
| 436 if (i == (ic_data.NumberOfChecks() - 1)) { |
| 437 __ j(NOT_EQUAL, deopt); |
| 438 } else { |
| 439 __ j(EQUAL, &done); |
| 440 } |
| 441 } |
| 442 __ Bind(&done); |
| 443 __ cmpq(left, right); |
| 444 if (branch == NULL) { |
| 445 Label done, is_equal; |
| 446 Register result = locs.out().reg(); |
| 447 __ j(EQUAL, &is_equal, Assembler::kNearJump); |
| 448 // Not equal. |
| 449 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_false() |
| 450 : compiler->bool_true()); |
| 451 __ jmp(&done, Assembler::kNearJump); |
| 452 __ Bind(&is_equal); |
| 453 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_true() |
| 454 : compiler->bool_false()); |
| 455 __ Bind(&done); |
| 456 } else { |
| 457 Condition cond = TokenKindToSmiCondition(kind); |
| 458 branch->EmitBranchOnCondition(compiler, cond); |
| 459 } |
| 460 } |
| 461 |
| 462 |
| 408 // First test if receiver is NULL, in which case === is applied. | 463 // First test if receiver is NULL, in which case === is applied. |
| 409 // If type feedback was provided (lists of <class-id, target>), do a | 464 // If type feedback was provided (lists of <class-id, target>), do a |
| 410 // type by type check (either === or static call to the operator. | 465 // type by type check (either === or static call to the operator. |
| 411 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | 466 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, |
| 412 const LocationSummary& locs, | 467 const LocationSummary& locs, |
| 413 Token::Kind kind, | 468 Token::Kind kind, |
| 414 BranchInstr* branch, | 469 BranchInstr* branch, |
| 415 const ICData& ic_data, | 470 const ICData& ic_data, |
| 416 intptr_t deopt_id, | 471 intptr_t deopt_id, |
| 417 intptr_t token_pos, | 472 intptr_t token_pos, |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 548 if (receiver_class_id() == kSmiCid) { | 603 if (receiver_class_id() == kSmiCid) { |
| 549 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. | 604 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. |
| 550 deopt_id(), token_pos(), try_index()); | 605 deopt_id(), token_pos(), try_index()); |
| 551 return; | 606 return; |
| 552 } | 607 } |
| 553 if (receiver_class_id() == kDoubleCid) { | 608 if (receiver_class_id() == kDoubleCid) { |
| 554 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. | 609 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. |
| 555 deopt_id(), token_pos(), try_index()); | 610 deopt_id(), token_pos(), try_index()); |
| 556 return; | 611 return; |
| 557 } | 612 } |
| 613 const bool is_checked_strict_equal = |
| 614 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 615 if (is_checked_strict_equal) { |
| 616 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL, |
| 617 deopt_id(), token_pos(), try_index()); |
| 618 return; |
| 619 } |
| 558 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 620 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 559 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(), | 621 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(), |
| 560 deopt_id(), token_pos(), try_index()); | 622 deopt_id(), token_pos(), try_index()); |
| 561 } else { | 623 } else { |
| 562 Register left = locs()->in(0).reg(); | 624 Register left = locs()->in(0).reg(); |
| 563 Register right = locs()->in(1).reg(); | 625 Register right = locs()->in(1).reg(); |
| 564 __ pushq(left); | 626 __ pushq(left); |
| 565 __ pushq(right); | 627 __ pushq(right); |
| 566 EmitEqualityAsInstanceCall(compiler, this); | 628 EmitEqualityAsInstanceCall(compiler, this); |
| 567 } | 629 } |
| 568 } | 630 } |
| 569 | 631 |
| 570 | 632 |
| 571 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 633 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
| 572 if (operands_class_id() == kSmiCid || operands_class_id() == kDoubleCid) { | 634 if (operands_class_id() == kSmiCid || operands_class_id() == kDoubleCid) { |
| 573 const intptr_t kNumInputs = 2; | 635 const intptr_t kNumInputs = 2; |
| 574 const intptr_t kNumTemps = 1; | 636 const intptr_t kNumTemps = 1; |
| 575 LocationSummary* summary = | 637 LocationSummary* summary = |
| 576 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 638 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 577 summary->set_in(0, Location::RequiresRegister()); | 639 summary->set_in(0, Location::RequiresRegister()); |
| 578 summary->set_in(1, Location::RequiresRegister()); | 640 summary->set_in(1, Location::RequiresRegister()); |
| 579 summary->set_out(Location::RequiresRegister()); | 641 summary->set_out(Location::RequiresRegister()); |
| 580 summary->set_temp(0, Location::RequiresRegister()); | 642 summary->set_temp(0, Location::RequiresRegister()); |
| 581 return summary; | 643 return summary; |
| 582 } | 644 } |
| 583 ASSERT(operands_class_id() == kObjectCid); | |
| 584 return MakeCallSummary(); | 645 return MakeCallSummary(); |
| 585 } | 646 } |
| 586 | 647 |
| 587 | 648 |
| 588 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 649 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 589 if (operands_class_id() == kSmiCid) { | 650 if (operands_class_id() == kSmiCid) { |
| 590 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, | 651 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, |
| 591 deopt_id(), token_pos(), try_index()); | 652 deopt_id(), token_pos(), try_index()); |
| 592 return; | 653 return; |
| 593 } | 654 } |
| (...skipping 1406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2000 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { | 2061 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { |
| 2001 if (ic_data.num_args_tested() != 2) return false; | 2062 if (ic_data.num_args_tested() != 2) return false; |
| 2002 if (ic_data.NumberOfChecks() != 1) return false; | 2063 if (ic_data.NumberOfChecks() != 1) return false; |
| 2003 Function& target = Function::Handle(); | 2064 Function& target = Function::Handle(); |
| 2004 GrowableArray<intptr_t> class_ids; | 2065 GrowableArray<intptr_t> class_ids; |
| 2005 ic_data.GetCheckAt(0, &class_ids, &target); | 2066 ic_data.GetCheckAt(0, &class_ids, &target); |
| 2006 return (class_ids[0] == class_id) && (class_ids[1] == class_id); | 2067 return (class_ids[0] == class_id) && (class_ids[1] == class_id); |
| 2007 } | 2068 } |
| 2008 | 2069 |
| 2009 | 2070 |
| 2071 static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) { |
| 2072 if ((kind == Token::kEQ) || (kind == Token::kNE)) { |
| 2073 return ic_data.AllTargetsHaveSameOwner(kInstanceCid); |
| 2074 } |
| 2075 return false; |
| 2076 } |
| 2077 |
| 2078 |
| 2010 LocationSummary* BranchInstr::MakeLocationSummary() const { | 2079 LocationSummary* BranchInstr::MakeLocationSummary() const { |
| 2011 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) { | 2080 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) { |
| 2012 const int kNumInputs = 2; | 2081 const int kNumInputs = 2; |
| 2013 const int kNumTemps = 0; | 2082 const int kNumTemps = 0; |
| 2014 LocationSummary* locs = | 2083 LocationSummary* locs = |
| 2015 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2084 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2016 locs->set_in(0, Location::RequiresRegister()); | 2085 locs->set_in(0, Location::RequiresRegister()); |
| 2017 locs->set_in(1, Location::RequiresRegister()); | 2086 locs->set_in(1, Location::RequiresRegister()); |
| 2018 return locs; | 2087 return locs; |
| 2019 } | 2088 } |
| 2020 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 2089 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 2021 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) || | 2090 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) || |
| 2022 ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { | 2091 ICDataWithBothClassIds(*ic_data(), kDoubleCid) || |
| 2092 IsCheckedStrictEquals(*ic_data(), kind())) { |
| 2023 const intptr_t kNumInputs = 2; | 2093 const intptr_t kNumInputs = 2; |
| 2024 const intptr_t kNumTemps = 1; | 2094 const intptr_t kNumTemps = 1; |
| 2025 LocationSummary* summary = | 2095 LocationSummary* summary = |
| 2026 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2096 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2027 summary->set_in(0, Location::RequiresRegister()); | 2097 summary->set_in(0, Location::RequiresRegister()); |
| 2028 summary->set_in(1, Location::RequiresRegister()); | 2098 summary->set_in(1, Location::RequiresRegister()); |
| 2029 summary->set_temp(0, Location::RequiresRegister()); | 2099 summary->set_temp(0, Location::RequiresRegister()); |
| 2030 return summary; | 2100 return summary; |
| 2031 } | 2101 } |
| 2032 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | 2102 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2066 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) { | 2136 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) { |
| 2067 EmitSmiComparisonOp(compiler, *locs(), kind(), this, | 2137 EmitSmiComparisonOp(compiler, *locs(), kind(), this, |
| 2068 deopt_id(), token_pos(), try_index()); | 2138 deopt_id(), token_pos(), try_index()); |
| 2069 return; | 2139 return; |
| 2070 } | 2140 } |
| 2071 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { | 2141 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { |
| 2072 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, | 2142 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, |
| 2073 deopt_id(), token_pos(), try_index()); | 2143 deopt_id(), token_pos(), try_index()); |
| 2074 return; | 2144 return; |
| 2075 } | 2145 } |
| 2146 if (IsCheckedStrictEquals(*ic_data(), kind())) { |
| 2147 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this, |
| 2148 deopt_id(), token_pos(), try_index()); |
| 2149 return; |
| 2150 } |
| 2076 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. | 2151 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. |
| 2077 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | 2152 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { |
| 2078 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), | 2153 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), |
| 2079 deopt_id(), token_pos(), try_index()); | 2154 deopt_id(), token_pos(), try_index()); |
| 2080 return; | 2155 return; |
| 2081 } | 2156 } |
| 2082 // Otherwise polymorphic dispatch? | 2157 // Otherwise polymorphic dispatch? |
| 2083 } | 2158 } |
| 2084 Register left = locs()->in(0).reg(); | 2159 Register left = locs()->in(0).reg(); |
| 2085 Register right = locs()->in(1).reg(); | 2160 Register right = locs()->in(1).reg(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2105 kNumArgsChecked); | 2180 kNumArgsChecked); |
| 2106 __ CompareObject(RAX, compiler->bool_true()); | 2181 __ CompareObject(RAX, compiler->bool_true()); |
| 2107 EmitBranchOnCondition(compiler, branch_condition); | 2182 EmitBranchOnCondition(compiler, branch_condition); |
| 2108 } | 2183 } |
| 2109 | 2184 |
| 2110 } // namespace dart | 2185 } // namespace dart |
| 2111 | 2186 |
| 2112 #undef __ | 2187 #undef __ |
| 2113 | 2188 |
| 2114 #endif // defined TARGET_ARCH_X64 | 2189 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |