| OLD | NEW |
| 1 // Copyright (c) 2013, 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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 308 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 309 locs->set_in(0, Location::RegisterOrConstant(left())); | 309 locs->set_in(0, Location::RegisterOrConstant(left())); |
| 310 // Only one input can be a constant operand. The case of two constant | 310 // Only one input can be a constant operand. The case of two constant |
| 311 // operands should be handled by constant propagation. | 311 // operands should be handled by constant propagation. |
| 312 locs->set_in(1, locs->in(0).IsConstant() | 312 locs->set_in(1, locs->in(0).IsConstant() |
| 313 ? Location::RequiresRegister() | 313 ? Location::RequiresRegister() |
| 314 : Location::RegisterOrConstant(right())); | 314 : Location::RegisterOrConstant(right())); |
| 315 locs->set_out(Location::RequiresRegister()); | 315 locs->set_out(Location::RequiresRegister()); |
| 316 return locs; | 316 return locs; |
| 317 } | 317 } |
| 318 if (IsCheckedStrictEqual()) { | 318 UNREACHABLE(); |
| 319 const intptr_t kNumTemps = 1; | 319 return NULL; |
| 320 LocationSummary* locs = | |
| 321 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 322 locs->set_in(0, Location::RequiresRegister()); | |
| 323 locs->set_in(1, Location::RequiresRegister()); | |
| 324 locs->set_temp(0, Location::RequiresRegister()); | |
| 325 locs->set_out(Location::RequiresRegister()); | |
| 326 return locs; | |
| 327 } | |
| 328 if (IsPolymorphic()) { | |
| 329 const intptr_t kNumTemps = 1; | |
| 330 LocationSummary* locs = | |
| 331 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | |
| 332 locs->set_in(0, Location::RegisterLocation(R1)); | |
| 333 locs->set_in(1, Location::RegisterLocation(R0)); | |
| 334 locs->set_temp(0, Location::RegisterLocation(R5)); | |
| 335 locs->set_out(Location::RegisterLocation(R0)); | |
| 336 return locs; | |
| 337 } | |
| 338 const intptr_t kNumTemps = 1; | |
| 339 LocationSummary* locs = | |
| 340 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | |
| 341 locs->set_in(0, Location::RegisterLocation(R1)); | |
| 342 locs->set_in(1, Location::RegisterLocation(R0)); | |
| 343 locs->set_temp(0, Location::RegisterLocation(R5)); | |
| 344 locs->set_out(Location::RegisterLocation(R0)); | |
| 345 return locs; | |
| 346 } | |
| 347 | |
| 348 | |
| 349 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | |
| 350 intptr_t deopt_id, | |
| 351 intptr_t token_pos, | |
| 352 Token::Kind kind, | |
| 353 LocationSummary* locs, | |
| 354 const ICData& original_ic_data) { | |
| 355 if (!compiler->is_optimizing()) { | |
| 356 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | |
| 357 deopt_id, | |
| 358 token_pos); | |
| 359 } | |
| 360 const int kNumberOfArguments = 2; | |
| 361 const Array& kNoArgumentNames = Object::null_array(); | |
| 362 const int kNumArgumentsChecked = 2; | |
| 363 | |
| 364 ICData& equality_ic_data = ICData::ZoneHandle(); | |
| 365 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { | |
| 366 ASSERT(!original_ic_data.IsNull()); | |
| 367 if (original_ic_data.NumberOfChecks() == 0) { | |
| 368 // IC call for reoptimization populates original ICData. | |
| 369 equality_ic_data = original_ic_data.raw(); | |
| 370 } else { | |
| 371 // Megamorphic call. | |
| 372 equality_ic_data = original_ic_data.AsUnaryClassChecks(); | |
| 373 } | |
| 374 } else { | |
| 375 const Array& arguments_descriptor = | |
| 376 Array::Handle(ArgumentsDescriptor::New(kNumberOfArguments, | |
| 377 kNoArgumentNames)); | |
| 378 equality_ic_data = ICData::New(compiler->parsed_function().function(), | |
| 379 Symbols::EqualOperator(), | |
| 380 arguments_descriptor, | |
| 381 deopt_id, | |
| 382 kNumArgumentsChecked); | |
| 383 } | |
| 384 compiler->GenerateInstanceCall(deopt_id, | |
| 385 token_pos, | |
| 386 kNumberOfArguments, | |
| 387 kNoArgumentNames, | |
| 388 locs, | |
| 389 equality_ic_data); | |
| 390 if (kind == Token::kNE) { | |
| 391 // Negate the condition: true label returns false and vice versa. | |
| 392 __ CompareObject(R0, Bool::True()); | |
| 393 __ LoadObject(R0, Bool::True(), NE); | |
| 394 __ LoadObject(R0, Bool::False(), EQ); | |
| 395 } | |
| 396 } | 320 } |
| 397 | 321 |
| 398 | 322 |
| 399 static void LoadValueCid(FlowGraphCompiler* compiler, | 323 static void LoadValueCid(FlowGraphCompiler* compiler, |
| 400 Register value_cid_reg, | 324 Register value_cid_reg, |
| 401 Register value_reg, | 325 Register value_reg, |
| 402 Label* value_is_smi = NULL) { | 326 Label* value_is_smi = NULL) { |
| 403 Label done; | 327 Label done; |
| 404 if (value_is_smi == NULL) { | 328 if (value_is_smi == NULL) { |
| 405 __ mov(value_cid_reg, ShifterOperand(kSmiCid)); | 329 __ mov(value_cid_reg, ShifterOperand(kSmiCid)); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 427 case LS: return HI; | 351 case LS: return HI; |
| 428 case HI: return LS; | 352 case HI: return LS; |
| 429 case CS: return CC; | 353 case CS: return CC; |
| 430 default: | 354 default: |
| 431 UNREACHABLE(); | 355 UNREACHABLE(); |
| 432 return EQ; | 356 return EQ; |
| 433 } | 357 } |
| 434 } | 358 } |
| 435 | 359 |
| 436 | 360 |
| 437 // R1: left, also on stack. | |
| 438 // R0: right, also on stack. | |
| 439 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | |
| 440 const ICData& orig_ic_data, | |
| 441 LocationSummary* locs, | |
| 442 BranchInstr* branch, | |
| 443 Token::Kind kind, | |
| 444 intptr_t deopt_id, | |
| 445 intptr_t token_pos) { | |
| 446 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | |
| 447 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); | |
| 448 ASSERT(ic_data.NumberOfChecks() > 0); | |
| 449 ASSERT(ic_data.num_args_tested() == 1); | |
| 450 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); | |
| 451 Register left = locs->in(0).reg(); | |
| 452 Register right = locs->in(1).reg(); | |
| 453 ASSERT(left == R1); | |
| 454 ASSERT(right == R0); | |
| 455 Register temp = locs->temp(0).reg(); | |
| 456 LoadValueCid(compiler, temp, left, | |
| 457 (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt); | |
| 458 // 'temp' contains class-id of the left argument. | |
| 459 ObjectStore* object_store = Isolate::Current()->object_store(); | |
| 460 Condition cond = TokenKindToSmiCondition(kind); | |
| 461 Label done; | |
| 462 const intptr_t len = ic_data.NumberOfChecks(); | |
| 463 for (intptr_t i = 0; i < len; i++) { | |
| 464 // Assert that the Smi is at position 0, if at all. | |
| 465 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); | |
| 466 Label next_test; | |
| 467 __ CompareImmediate(temp, ic_data.GetReceiverClassIdAt(i)); | |
| 468 if (i < len - 1) { | |
| 469 __ b(&next_test, NE); | |
| 470 } else { | |
| 471 __ b(deopt, NE); | |
| 472 } | |
| 473 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); | |
| 474 if (target.Owner() == object_store->object_class()) { | |
| 475 // Object.== is same as ===. | |
| 476 __ Drop(2); | |
| 477 __ cmp(left, ShifterOperand(right)); | |
| 478 if (branch != NULL) { | |
| 479 branch->EmitBranchOnCondition(compiler, cond); | |
| 480 } else { | |
| 481 Register result = locs->out().reg(); | |
| 482 __ LoadObject(result, Bool::True(), cond); | |
| 483 __ LoadObject(result, Bool::False(), NegateCondition(cond)); | |
| 484 } | |
| 485 } else { | |
| 486 const int kNumberOfArguments = 2; | |
| 487 const Array& kNoArgumentNames = Object::null_array(); | |
| 488 compiler->GenerateStaticCall(deopt_id, | |
| 489 token_pos, | |
| 490 target, | |
| 491 kNumberOfArguments, | |
| 492 kNoArgumentNames, | |
| 493 locs); | |
| 494 if (branch == NULL) { | |
| 495 if (kind == Token::kNE) { | |
| 496 __ CompareObject(R0, Bool::True()); | |
| 497 __ LoadObject(R0, Bool::True(), NE); | |
| 498 __ LoadObject(R0, Bool::False(), EQ); | |
| 499 } | |
| 500 } else { | |
| 501 if (branch->is_checked()) { | |
| 502 EmitAssertBoolean(R0, token_pos, deopt_id, locs, compiler); | |
| 503 } | |
| 504 __ CompareObject(R0, Bool::True()); | |
| 505 branch->EmitBranchOnCondition(compiler, cond); | |
| 506 } | |
| 507 } | |
| 508 if (i < len - 1) { | |
| 509 __ b(&done); | |
| 510 __ Bind(&next_test); | |
| 511 } | |
| 512 } | |
| 513 __ Bind(&done); | |
| 514 } | |
| 515 | |
| 516 | |
| 517 // Emit code when ICData's targets are all Object == (which is ===). | |
| 518 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler, | |
| 519 const ICData& orig_ic_data, | |
| 520 const LocationSummary& locs, | |
| 521 Token::Kind kind, | |
| 522 BranchInstr* branch, | |
| 523 intptr_t deopt_id) { | |
| 524 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | |
| 525 Register left = locs.in(0).reg(); | |
| 526 Register right = locs.in(1).reg(); | |
| 527 Register temp = locs.temp(0).reg(); | |
| 528 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); | |
| 529 __ tst(left, ShifterOperand(kSmiTagMask)); | |
| 530 __ b(deopt, EQ); | |
| 531 // 'left' is not Smi. | |
| 532 Label identity_compare; | |
| 533 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); | |
| 534 __ cmp(right, ShifterOperand(IP)); | |
| 535 __ b(&identity_compare, EQ); | |
| 536 __ cmp(left, ShifterOperand(IP)); | |
| 537 __ b(&identity_compare, EQ); | |
| 538 | |
| 539 __ LoadClassId(temp, left); | |
| 540 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); | |
| 541 const intptr_t len = ic_data.NumberOfChecks(); | |
| 542 for (intptr_t i = 0; i < len; i++) { | |
| 543 __ CompareImmediate(temp, ic_data.GetReceiverClassIdAt(i)); | |
| 544 if (i == (len - 1)) { | |
| 545 __ b(deopt, NE); | |
| 546 } else { | |
| 547 __ b(&identity_compare, EQ); | |
| 548 } | |
| 549 } | |
| 550 __ Bind(&identity_compare); | |
| 551 __ cmp(left, ShifterOperand(right)); | |
| 552 if (branch == NULL) { | |
| 553 Register result = locs.out().reg(); | |
| 554 __ LoadObject(result, Bool::Get(kind == Token::kEQ), EQ); | |
| 555 __ LoadObject(result, Bool::Get(kind != Token::kEQ), NE); | |
| 556 } else { | |
| 557 Condition cond = TokenKindToSmiCondition(kind); | |
| 558 branch->EmitBranchOnCondition(compiler, cond); | |
| 559 } | |
| 560 } | |
| 561 | |
| 562 | |
| 563 // First test if receiver is NULL, in which case === is applied. | |
| 564 // If type feedback was provided (lists of <class-id, target>), do a | |
| 565 // type by type check (either === or static call to the operator. | |
| 566 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, | |
| 567 LocationSummary* locs, | |
| 568 Token::Kind kind, | |
| 569 BranchInstr* branch, | |
| 570 const ICData& ic_data, | |
| 571 intptr_t deopt_id, | |
| 572 intptr_t token_pos) { | |
| 573 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | |
| 574 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); | |
| 575 Register left = locs->in(0).reg(); | |
| 576 Register right = locs->in(1).reg(); | |
| 577 ASSERT(left == R1); | |
| 578 ASSERT(right == R0); | |
| 579 __ PushList((1 << R0) | (1 << R1)); | |
| 580 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, | |
| 581 deopt_id, token_pos); | |
| 582 } | |
| 583 | |
| 584 | |
| 585 static Condition FlipCondition(Condition condition) { | 361 static Condition FlipCondition(Condition condition) { |
| 586 switch (condition) { | 362 switch (condition) { |
| 587 case EQ: return EQ; | 363 case EQ: return EQ; |
| 588 case NE: return NE; | 364 case NE: return NE; |
| 589 case LT: return GT; | 365 case LT: return GT; |
| 590 case LE: return GE; | 366 case LE: return GE; |
| 591 case GT: return LT; | 367 case GT: return LT; |
| 592 case GE: return LE; | 368 case GE: return LE; |
| 593 case CC: return HI; | 369 case CC: return HI; |
| 594 case LS: return CS; | 370 case LS: return CS; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 return; | 463 return; |
| 688 } | 464 } |
| 689 if (operation_cid() == kMintCid) { | 465 if (operation_cid() == kMintCid) { |
| 690 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch); | 466 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch); |
| 691 return; | 467 return; |
| 692 } | 468 } |
| 693 if (operation_cid() == kDoubleCid) { | 469 if (operation_cid() == kDoubleCid) { |
| 694 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); | 470 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); |
| 695 return; | 471 return; |
| 696 } | 472 } |
| 697 if (IsCheckedStrictEqual()) { | 473 UNREACHABLE(); |
| 698 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch, | |
| 699 deopt_id()); | |
| 700 return; | |
| 701 } | |
| 702 if (IsPolymorphic()) { | |
| 703 EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(), | |
| 704 deopt_id(), token_pos()); | |
| 705 return; | |
| 706 } | |
| 707 Register left = locs()->in(0).reg(); | |
| 708 Register right = locs()->in(1).reg(); | |
| 709 ASSERT(left == R1); | |
| 710 ASSERT(right == R0); | |
| 711 __ PushList((1 << R0) | (1 << R1)); | |
| 712 EmitEqualityAsInstanceCall(compiler, | |
| 713 deopt_id(), | |
| 714 token_pos(), | |
| 715 kind(), | |
| 716 locs(), | |
| 717 *ic_data()); | |
| 718 ASSERT(locs()->out().reg() == R0); | |
| 719 } | 474 } |
| 720 | 475 |
| 721 | 476 |
| 722 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, | 477 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, |
| 723 BranchInstr* branch) { | 478 BranchInstr* branch) { |
| 724 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); | 479 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); |
| 725 if (operation_cid() == kSmiCid) { | 480 if (operation_cid() == kSmiCid) { |
| 726 // Deoptimizes if both arguments not Smi. | 481 // Deoptimizes if both arguments not Smi. |
| 727 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); | 482 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); |
| 728 return; | 483 return; |
| 729 } | 484 } |
| 730 if (operation_cid() == kMintCid) { | 485 if (operation_cid() == kMintCid) { |
| 731 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch); | 486 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch); |
| 732 return; | 487 return; |
| 733 } | 488 } |
| 734 if (operation_cid() == kDoubleCid) { | 489 if (operation_cid() == kDoubleCid) { |
| 735 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); | 490 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); |
| 736 return; | 491 return; |
| 737 } | 492 } |
| 738 if (IsCheckedStrictEqual()) { | 493 UNREACHABLE(); |
| 739 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch, | |
| 740 deopt_id()); | |
| 741 return; | |
| 742 } | |
| 743 if (IsPolymorphic()) { | |
| 744 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(), | |
| 745 deopt_id(), token_pos()); | |
| 746 return; | |
| 747 } | |
| 748 Register left = locs()->in(0).reg(); | |
| 749 Register right = locs()->in(1).reg(); | |
| 750 ASSERT(left == R1); | |
| 751 ASSERT(right == R0); | |
| 752 __ PushList((1 << R0) | (1 << R1)); | |
| 753 EmitEqualityAsInstanceCall(compiler, | |
| 754 deopt_id(), | |
| 755 token_pos(), | |
| 756 Token::kEQ, // kNE reverse occurs at branch. | |
| 757 locs(), | |
| 758 *ic_data()); | |
| 759 if (branch->is_checked()) { | |
| 760 EmitAssertBoolean(R0, token_pos(), deopt_id(), locs(), compiler); | |
| 761 } | |
| 762 Condition branch_condition = (kind() == Token::kNE) ? NE : EQ; | |
| 763 __ CompareObject(R0, Bool::True()); | |
| 764 branch->EmitBranchOnCondition(compiler, branch_condition); | |
| 765 } | 494 } |
| 766 | 495 |
| 767 | 496 |
| 768 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { | 497 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { |
| 769 const intptr_t kNumInputs = 2; | 498 const intptr_t kNumInputs = 2; |
| 770 const intptr_t kNumTemps = 0; | 499 const intptr_t kNumTemps = 0; |
| 771 if (operation_cid() == kMintCid) { | 500 if (operation_cid() == kMintCid) { |
| 772 const intptr_t kNumTemps = 2; | 501 const intptr_t kNumTemps = 2; |
| 773 LocationSummary* locs = | 502 LocationSummary* locs = |
| 774 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 503 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| (...skipping 3932 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4707 compiler->GenerateCall(token_pos(), | 4436 compiler->GenerateCall(token_pos(), |
| 4708 &label, | 4437 &label, |
| 4709 PcDescriptors::kOther, | 4438 PcDescriptors::kOther, |
| 4710 locs()); | 4439 locs()); |
| 4711 __ Drop(2); // Discard type arguments and receiver. | 4440 __ Drop(2); // Discard type arguments and receiver. |
| 4712 } | 4441 } |
| 4713 | 4442 |
| 4714 } // namespace dart | 4443 } // namespace dart |
| 4715 | 4444 |
| 4716 #endif // defined TARGET_ARCH_ARM | 4445 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |