| 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 case Token::kGTE: return GREATER_EQUAL; | 237 case Token::kGTE: return GREATER_EQUAL; |
| 238 default: | 238 default: |
| 239 UNREACHABLE(); | 239 UNREACHABLE(); |
| 240 return OVERFLOW; | 240 return OVERFLOW; |
| 241 } | 241 } |
| 242 } | 242 } |
| 243 | 243 |
| 244 | 244 |
| 245 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { | 245 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { |
| 246 const intptr_t kNumInputs = 2; | 246 const intptr_t kNumInputs = 2; |
| 247 if (receiver_class_id() != kObjectCid) { | 247 const bool is_checked_strict_equal = |
| 248 ASSERT((receiver_class_id() == kSmiCid) || | 248 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 249 (receiver_class_id() == kDoubleCid)); | 249 if ((receiver_class_id() == kSmiCid) || |
| 250 (receiver_class_id() == kDoubleCid) || |
| 251 is_checked_strict_equal) { |
| 250 const intptr_t kNumTemps = 1; | 252 const intptr_t kNumTemps = 1; |
| 251 LocationSummary* locs = | 253 LocationSummary* locs = |
| 252 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 254 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 253 locs->set_in(0, Location::RequiresRegister()); | 255 locs->set_in(0, Location::RequiresRegister()); |
| 254 locs->set_in(1, Location::RequiresRegister()); | 256 locs->set_in(1, Location::RequiresRegister()); |
| 255 locs->set_temp(0, Location::RequiresRegister()); | 257 locs->set_temp(0, Location::RequiresRegister()); |
| 256 locs->set_out(Location::RequiresRegister()); | 258 locs->set_out(Location::RequiresRegister()); |
| 257 return locs; | 259 return locs; |
| 258 } | 260 } |
| 259 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 261 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); | 332 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); |
| 331 __ movl(temp, Immediate(kSmiCid)); | 333 __ movl(temp, Immediate(kSmiCid)); |
| 332 __ jmp(&done, Assembler::kNearJump); | 334 __ jmp(&done, Assembler::kNearJump); |
| 333 __ Bind(&load_class_id); | 335 __ Bind(&load_class_id); |
| 334 __ LoadClassId(temp, left); | 336 __ LoadClassId(temp, left); |
| 335 __ Bind(&done); | 337 __ Bind(&done); |
| 336 } else { | 338 } else { |
| 337 __ j(ZERO, deopt); // Smi deopts. | 339 __ j(ZERO, deopt); // Smi deopts. |
| 338 __ LoadClassId(temp, left); | 340 __ LoadClassId(temp, left); |
| 339 } | 341 } |
| 342 // 'temp' contains class-id of the left argument. |
| 343 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 340 Condition cond = TokenKindToSmiCondition(kind); | 344 Condition cond = TokenKindToSmiCondition(kind); |
| 341 Label done; | 345 Label done; |
| 342 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 346 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 347 // Assert that the Smi is at position 0, if at all. |
| 343 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); | 348 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); |
| 344 Label next_test; | 349 Label next_test; |
| 345 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); | 350 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); |
| 346 __ j(NOT_EQUAL, &next_test); | 351 __ j(NOT_EQUAL, &next_test); |
| 347 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); | 352 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); |
| 348 ObjectStore* object_store = Isolate::Current()->object_store(); | |
| 349 if (target.owner() == object_store->object_class()) { | 353 if (target.owner() == object_store->object_class()) { |
| 350 // Object.== is same as ===. | 354 // Object.== is same as ===. |
| 351 __ Drop(2); | 355 __ Drop(2); |
| 352 __ cmpl(left, right); | 356 __ cmpl(left, right); |
| 353 if (branch != NULL) { | 357 if (branch != NULL) { |
| 354 branch->EmitBranchOnCondition(compiler, cond); | 358 branch->EmitBranchOnCondition(compiler, cond); |
| 355 } else { | 359 } else { |
| 356 // This case should be rare. | |
| 357 Register result = locs.out().reg(); | 360 Register result = locs.out().reg(); |
| 358 Label load_true; | 361 Label load_true; |
| 359 __ j(cond, &load_true, Assembler::kNearJump); | 362 __ j(cond, &load_true, Assembler::kNearJump); |
| 360 __ LoadObject(result, compiler->bool_false()); | 363 __ LoadObject(result, compiler->bool_false()); |
| 361 __ jmp(&done); | 364 __ jmp(&done); |
| 362 __ Bind(&load_true); | 365 __ Bind(&load_true); |
| 363 __ LoadObject(result, compiler->bool_true()); | 366 __ LoadObject(result, compiler->bool_true()); |
| 364 } | 367 } |
| 365 } else { | 368 } else { |
| 366 const int kNumberOfArguments = 2; | 369 const int kNumberOfArguments = 2; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 389 } | 392 } |
| 390 __ jmp(&done); | 393 __ jmp(&done); |
| 391 __ Bind(&next_test); | 394 __ Bind(&next_test); |
| 392 } | 395 } |
| 393 // Fall through leads to deoptimization | 396 // Fall through leads to deoptimization |
| 394 __ jmp(deopt); | 397 __ jmp(deopt); |
| 395 __ Bind(&done); | 398 __ Bind(&done); |
| 396 } | 399 } |
| 397 | 400 |
| 398 | 401 |
| 402 // Emit code when ICData's targets are all Object == (which is ===). |
| 403 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler, |
| 404 const ICData& ic_data, |
| 405 const LocationSummary& locs, |
| 406 Token::Kind kind, |
| 407 BranchInstr* branch, |
| 408 intptr_t deopt_id, |
| 409 intptr_t token_pos, |
| 410 intptr_t try_index) { |
| 411 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 412 Register left = locs.in(0).reg(); |
| 413 Register right = locs.in(1).reg(); |
| 414 Register temp = locs.temp(0).reg(); |
| 415 Label* deopt = compiler->AddDeoptStub(deopt_id, |
| 416 try_index, |
| 417 kDeoptEquality, |
| 418 left, |
| 419 right); |
| 420 __ testl(left, Immediate(kSmiTagMask)); |
| 421 __ j(ZERO, deopt); |
| 422 __ LoadClassId(temp, left); |
| 423 Label done; |
| 424 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 425 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); |
| 426 if (i == (ic_data.NumberOfChecks() - 1)) { |
| 427 __ j(NOT_EQUAL, deopt); |
| 428 } else { |
| 429 __ j(EQUAL, &done); |
| 430 } |
| 431 } |
| 432 __ Bind(&done); |
| 433 __ cmpl(left, right); |
| 434 if (branch == NULL) { |
| 435 Label done, is_equal; |
| 436 Register result = locs.out().reg(); |
| 437 __ j(EQUAL, &is_equal, Assembler::kNearJump); |
| 438 // Not equal. |
| 439 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_false() |
| 440 : compiler->bool_true()); |
| 441 __ jmp(&done, Assembler::kNearJump); |
| 442 __ Bind(&is_equal); |
| 443 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_true() |
| 444 : compiler->bool_false()); |
| 445 __ Bind(&done); |
| 446 } else { |
| 447 Condition cond = TokenKindToSmiCondition(kind); |
| 448 branch->EmitBranchOnCondition(compiler, cond); |
| 449 } |
| 450 } |
| 451 |
| 452 |
| 399 // First test if receiver is NULL, in which case === is applied. | 453 // First test if receiver is NULL, in which case === is applied. |
| 400 // If type feedback was provided (lists of <class-id, target>), do a | 454 // If type feedback was provided (lists of <class-id, target>), do a |
| 401 // type by type check (either === or static call to the operator. | 455 // type by type check (either === or static call to the operator. |
| 402 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | 456 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, |
| 403 const LocationSummary& locs, | 457 const LocationSummary& locs, |
| 404 Token::Kind kind, | 458 Token::Kind kind, |
| 405 BranchInstr* branch, | 459 BranchInstr* branch, |
| 406 const ICData& ic_data, | 460 const ICData& ic_data, |
| 407 intptr_t deopt_id, | 461 intptr_t deopt_id, |
| 408 intptr_t token_pos, | 462 intptr_t token_pos, |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 if (receiver_class_id() == kSmiCid) { | 593 if (receiver_class_id() == kSmiCid) { |
| 540 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. | 594 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. |
| 541 deopt_id(), token_pos(), try_index()); | 595 deopt_id(), token_pos(), try_index()); |
| 542 return; | 596 return; |
| 543 } | 597 } |
| 544 if (receiver_class_id() == kDoubleCid) { | 598 if (receiver_class_id() == kDoubleCid) { |
| 545 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. | 599 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. |
| 546 deopt_id(), token_pos(), try_index()); | 600 deopt_id(), token_pos(), try_index()); |
| 547 return; | 601 return; |
| 548 } | 602 } |
| 603 const bool is_checked_strict_equal = |
| 604 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid); |
| 605 if (is_checked_strict_equal) { |
| 606 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL, |
| 607 deopt_id(), token_pos(), try_index()); |
| 608 return; |
| 609 } |
| 549 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 610 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 550 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(), | 611 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(), |
| 551 deopt_id(), token_pos(), try_index()); | 612 deopt_id(), token_pos(), try_index()); |
| 552 } else { | 613 } else { |
| 553 Register left = locs()->in(0).reg(); | 614 Register left = locs()->in(0).reg(); |
| 554 Register right = locs()->in(1).reg(); | 615 Register right = locs()->in(1).reg(); |
| 555 __ pushl(left); | 616 __ pushl(left); |
| 556 __ pushl(right); | 617 __ pushl(right); |
| 557 EmitEqualityAsInstanceCall(compiler, this); | 618 EmitEqualityAsInstanceCall(compiler, this); |
| 558 } | 619 } |
| 559 } | 620 } |
| 560 | 621 |
| 561 | 622 |
| 562 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 623 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
| 563 if ((operands_class_id() == kSmiCid) || (operands_class_id() == kDoubleCid)) { | 624 if ((operands_class_id() == kSmiCid) || (operands_class_id() == kDoubleCid)) { |
| 564 const intptr_t kNumInputs = 2; | 625 const intptr_t kNumInputs = 2; |
| 565 const intptr_t kNumTemps = 1; | 626 const intptr_t kNumTemps = 1; |
| 566 LocationSummary* summary = | 627 LocationSummary* summary = |
| 567 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 628 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 568 summary->set_in(0, Location::RequiresRegister()); | 629 summary->set_in(0, Location::RequiresRegister()); |
| 569 summary->set_in(1, Location::RequiresRegister()); | 630 summary->set_in(1, Location::RequiresRegister()); |
| 570 summary->set_out(Location::RequiresRegister()); | 631 summary->set_out(Location::RequiresRegister()); |
| 571 summary->set_temp(0, Location::RequiresRegister()); | 632 summary->set_temp(0, Location::RequiresRegister()); |
| 572 return summary; | 633 return summary; |
| 573 } | 634 } |
| 574 ASSERT(operands_class_id() == kObjectCid); | |
| 575 return MakeCallSummary(); | 635 return MakeCallSummary(); |
| 576 } | 636 } |
| 577 | 637 |
| 578 | 638 |
| 579 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 639 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 580 if (operands_class_id() == kSmiCid) { | 640 if (operands_class_id() == kSmiCid) { |
| 581 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, | 641 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, |
| 582 deopt_id(), token_pos(), try_index()); | 642 deopt_id(), token_pos(), try_index()); |
| 583 return; | 643 return; |
| 584 } | 644 } |
| (...skipping 1408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1993 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { | 2053 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { |
| 1994 if (ic_data.num_args_tested() != 2) return false; | 2054 if (ic_data.num_args_tested() != 2) return false; |
| 1995 if (ic_data.NumberOfChecks() != 1) return false; | 2055 if (ic_data.NumberOfChecks() != 1) return false; |
| 1996 Function& target = Function::Handle(); | 2056 Function& target = Function::Handle(); |
| 1997 GrowableArray<intptr_t> class_ids; | 2057 GrowableArray<intptr_t> class_ids; |
| 1998 ic_data.GetCheckAt(0, &class_ids, &target); | 2058 ic_data.GetCheckAt(0, &class_ids, &target); |
| 1999 return (class_ids[0] == class_id) && (class_ids[1] == class_id); | 2059 return (class_ids[0] == class_id) && (class_ids[1] == class_id); |
| 2000 } | 2060 } |
| 2001 | 2061 |
| 2002 | 2062 |
| 2063 static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) { |
| 2064 if ((kind == Token::kEQ) || (kind == Token::kNE)) { |
| 2065 return ic_data.AllTargetsHaveSameOwner(kInstanceCid); |
| 2066 } |
| 2067 return false; |
| 2068 } |
| 2069 |
| 2070 |
| 2003 LocationSummary* BranchInstr::MakeLocationSummary() const { | 2071 LocationSummary* BranchInstr::MakeLocationSummary() const { |
| 2004 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) { | 2072 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) { |
| 2005 const int kNumInputs = 2; | 2073 const int kNumInputs = 2; |
| 2006 const int kNumTemps = 0; | 2074 const int kNumTemps = 0; |
| 2007 LocationSummary* locs = | 2075 LocationSummary* locs = |
| 2008 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2076 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2009 locs->set_in(0, Location::RequiresRegister()); | 2077 locs->set_in(0, Location::RequiresRegister()); |
| 2010 locs->set_in(1, Location::RequiresRegister()); | 2078 locs->set_in(1, Location::RequiresRegister()); |
| 2011 return locs; | 2079 return locs; |
| 2012 } | 2080 } |
| 2013 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { | 2081 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { |
| 2014 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) || | 2082 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) || |
| 2015 ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { | 2083 ICDataWithBothClassIds(*ic_data(), kDoubleCid) || |
| 2084 IsCheckedStrictEquals(*ic_data(), kind())) { |
| 2016 const intptr_t kNumInputs = 2; | 2085 const intptr_t kNumInputs = 2; |
| 2017 const intptr_t kNumTemps = 1; | 2086 const intptr_t kNumTemps = 1; |
| 2018 LocationSummary* summary = | 2087 LocationSummary* summary = |
| 2019 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 2088 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2020 summary->set_in(0, Location::RequiresRegister()); | 2089 summary->set_in(0, Location::RequiresRegister()); |
| 2021 summary->set_in(1, Location::RequiresRegister()); | 2090 summary->set_in(1, Location::RequiresRegister()); |
| 2022 summary->set_temp(0, Location::RequiresRegister()); | 2091 summary->set_temp(0, Location::RequiresRegister()); |
| 2023 return summary; | 2092 return summary; |
| 2024 } | 2093 } |
| 2025 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | 2094 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2059 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) { | 2128 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) { |
| 2060 EmitSmiComparisonOp(compiler, *locs(), kind(), this, | 2129 EmitSmiComparisonOp(compiler, *locs(), kind(), this, |
| 2061 deopt_id(), token_pos(), try_index()); | 2130 deopt_id(), token_pos(), try_index()); |
| 2062 return; | 2131 return; |
| 2063 } | 2132 } |
| 2064 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { | 2133 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { |
| 2065 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, | 2134 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, |
| 2066 deopt_id(), token_pos(), try_index()); | 2135 deopt_id(), token_pos(), try_index()); |
| 2067 return; | 2136 return; |
| 2068 } | 2137 } |
| 2138 if (IsCheckedStrictEquals(*ic_data(), kind())) { |
| 2139 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this, |
| 2140 deopt_id(), token_pos(), try_index()); |
| 2141 return; |
| 2142 } |
| 2143 |
| 2069 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. | 2144 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. |
| 2070 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { | 2145 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { |
| 2071 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), | 2146 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), |
| 2072 deopt_id(), token_pos(), try_index()); | 2147 deopt_id(), token_pos(), try_index()); |
| 2073 return; | 2148 return; |
| 2074 } | 2149 } |
| 2075 // Otherwise polymorphic dispatch? | 2150 // Otherwise polymorphic dispatch? |
| 2076 } | 2151 } |
| 2077 Register left = locs()->in(0).reg(); | 2152 Register left = locs()->in(0).reg(); |
| 2078 Register right = locs()->in(1).reg(); | 2153 Register right = locs()->in(1).reg(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2098 kNumArgsChecked); | 2173 kNumArgsChecked); |
| 2099 __ CompareObject(EAX, compiler->bool_true()); | 2174 __ CompareObject(EAX, compiler->bool_true()); |
| 2100 EmitBranchOnCondition(compiler, branch_condition); | 2175 EmitBranchOnCondition(compiler, branch_condition); |
| 2101 } | 2176 } |
| 2102 | 2177 |
| 2103 } // namespace dart | 2178 } // namespace dart |
| 2104 | 2179 |
| 2105 #undef __ | 2180 #undef __ |
| 2106 | 2181 |
| 2107 #endif // defined TARGET_ARCH_X64 | 2182 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |