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