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