| 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 "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 LocationSummary* locs = | 349 LocationSummary* locs = |
| 350 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 350 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 351 locs->set_in(0, Location::RegisterLocation(R1)); | 351 locs->set_in(0, Location::RegisterLocation(R1)); |
| 352 locs->set_in(1, Location::RegisterLocation(R0)); | 352 locs->set_in(1, Location::RegisterLocation(R0)); |
| 353 locs->set_temp(0, Location::RegisterLocation(R5)); | 353 locs->set_temp(0, Location::RegisterLocation(R5)); |
| 354 locs->set_out(Location::RegisterLocation(R0)); | 354 locs->set_out(Location::RegisterLocation(R0)); |
| 355 return locs; | 355 return locs; |
| 356 } | 356 } |
| 357 | 357 |
| 358 | 358 |
| 359 // R1: left. | |
| 360 // R0: right. | |
| 361 // Uses R5 to load ic_call_data. | |
| 362 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, | 359 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler, |
| 363 intptr_t deopt_id, | 360 intptr_t deopt_id, |
| 364 intptr_t token_pos, | 361 intptr_t token_pos, |
| 365 Token::Kind kind, | 362 Token::Kind kind, |
| 366 LocationSummary* locs, | 363 LocationSummary* locs, |
| 367 const ICData& original_ic_data) { | 364 const ICData& original_ic_data) { |
| 368 if (!compiler->is_optimizing()) { | 365 if (!compiler->is_optimizing()) { |
| 369 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | 366 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 370 deopt_id, | 367 deopt_id, |
| 371 token_pos); | 368 token_pos); |
| 372 } | 369 } |
| 373 const int kNumberOfArguments = 2; | 370 const int kNumberOfArguments = 2; |
| 374 const Array& kNoArgumentNames = Array::Handle(); | 371 const Array& kNoArgumentNames = Array::Handle(); |
| 375 const int kNumArgumentsChecked = 2; | 372 const int kNumArgumentsChecked = 2; |
| 376 | 373 |
| 377 Label check_identity; | 374 Label check_identity; |
| 378 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); | 375 __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null())); |
| 376 __ ldm(IA, SP, (1 << R0) | (1 << R1)); |
| 379 __ cmp(R1, ShifterOperand(IP)); | 377 __ cmp(R1, ShifterOperand(IP)); |
| 380 __ b(&check_identity, EQ); | 378 __ b(&check_identity, EQ); |
| 381 __ cmp(R0, ShifterOperand(IP)); | 379 __ cmp(R0, ShifterOperand(IP)); |
| 382 __ b(&check_identity, EQ); | 380 __ b(&check_identity, EQ); |
| 383 | 381 |
| 384 ICData& equality_ic_data = ICData::ZoneHandle(); | 382 ICData& equality_ic_data = ICData::ZoneHandle(); |
| 385 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { | 383 if (compiler->is_optimizing() && FLAG_propagate_ic_data) { |
| 386 ASSERT(!original_ic_data.IsNull()); | 384 ASSERT(!original_ic_data.IsNull()); |
| 387 if (original_ic_data.NumberOfChecks() == 0) { | 385 if (original_ic_data.NumberOfChecks() == 0) { |
| 388 // IC call for reoptimization populates original ICData. | 386 // IC call for reoptimization populates original ICData. |
| 389 equality_ic_data = original_ic_data.raw(); | 387 equality_ic_data = original_ic_data.raw(); |
| 390 } else { | 388 } else { |
| 391 // Megamorphic call. | 389 // Megamorphic call. |
| 392 equality_ic_data = original_ic_data.AsUnaryClassChecks(); | 390 equality_ic_data = original_ic_data.AsUnaryClassChecks(); |
| 393 } | 391 } |
| 394 } else { | 392 } else { |
| 395 equality_ic_data = ICData::New(compiler->parsed_function().function(), | 393 equality_ic_data = ICData::New(compiler->parsed_function().function(), |
| 396 Symbols::EqualOperator(), | 394 Symbols::EqualOperator(), |
| 397 deopt_id, | 395 deopt_id, |
| 398 kNumArgumentsChecked); | 396 kNumArgumentsChecked); |
| 399 } | 397 } |
| 400 __ PushList((1 << R0) | (1 << R1)); | |
| 401 compiler->GenerateInstanceCall(deopt_id, | 398 compiler->GenerateInstanceCall(deopt_id, |
| 402 token_pos, | 399 token_pos, |
| 403 kNumberOfArguments, | 400 kNumberOfArguments, |
| 404 kNoArgumentNames, | 401 kNoArgumentNames, |
| 405 locs, | 402 locs, |
| 406 equality_ic_data); | 403 equality_ic_data); |
| 407 Label check_ne; | 404 Label check_ne; |
| 408 __ b(&check_ne); | 405 __ b(&check_ne); |
| 409 | 406 |
| 410 __ Bind(&check_identity); | 407 __ Bind(&check_identity); |
| 411 Label equality_done; | 408 Label equality_done; |
| 412 if (compiler->is_optimizing()) { | 409 if (compiler->is_optimizing()) { |
| 413 // No need to update IC data. | 410 // No need to update IC data. |
| 411 __ PopList((1 << R0) | (1 << R1)); |
| 414 __ cmp(R0, ShifterOperand(R1)); | 412 __ cmp(R0, ShifterOperand(R1)); |
| 415 __ LoadObject(R0, (kind == Token::kEQ) ? Bool::False() : Bool::True(), NE); | 413 __ LoadObject(R0, (kind == Token::kEQ) ? Bool::False() : Bool::True(), NE); |
| 416 __ LoadObject(R0, (kind == Token::kEQ) ? Bool::True() : Bool::False(), EQ); | 414 __ LoadObject(R0, (kind == Token::kEQ) ? Bool::True() : Bool::False(), EQ); |
| 417 if (kind == Token::kNE) { | 415 if (kind == Token::kNE) { |
| 418 // Skip not-equal result conversion. | 416 // Skip not-equal result conversion. |
| 419 __ b(&equality_done); | 417 __ b(&equality_done); |
| 420 } | 418 } |
| 421 } else { | 419 } else { |
| 422 // Call stub, load IC data in register. The stub will update ICData if | 420 // Call stub, load IC data in register. The stub will update ICData if |
| 423 // necessary. | 421 // necessary. |
| 424 Register ic_data_reg = locs->temp(0).reg(); | 422 Register ic_data_reg = locs->temp(0).reg(); |
| 425 ASSERT(ic_data_reg == R5); // Stub depends on it. | 423 ASSERT(ic_data_reg == R5); // Stub depends on it. |
| 426 __ LoadObject(ic_data_reg, equality_ic_data); | 424 __ LoadObject(ic_data_reg, equality_ic_data); |
| 427 // Pass left in R1 and right in R0. | 425 // Pass left in R1 and right in R0. |
| 428 compiler->GenerateCall(token_pos, | 426 compiler->GenerateCall(token_pos, |
| 429 &StubCode::EqualityWithNullArgLabel(), | 427 &StubCode::EqualityWithNullArgLabel(), |
| 430 PcDescriptors::kRuntimeCall, | 428 PcDescriptors::kRuntimeCall, |
| 431 locs); | 429 locs); |
| 430 __ Drop(2); |
| 432 } | 431 } |
| 433 __ Bind(&check_ne); | 432 __ Bind(&check_ne); |
| 434 if (kind == Token::kNE) { | 433 if (kind == Token::kNE) { |
| 435 // Negate the condition: true label returns false and vice versa. | 434 // Negate the condition: true label returns false and vice versa. |
| 436 __ CompareObject(R0, Bool::True()); | 435 __ CompareObject(R0, Bool::True()); |
| 437 __ LoadObject(R0, Bool::True(), NE); | 436 __ LoadObject(R0, Bool::True(), NE); |
| 438 __ LoadObject(R0, Bool::False(), EQ); | 437 __ LoadObject(R0, Bool::False(), EQ); |
| 439 } | 438 } |
| 440 __ Bind(&equality_done); | 439 __ Bind(&equality_done); |
| 441 } | 440 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 472 case LS: return HI; | 471 case LS: return HI; |
| 473 case HI: return LS; | 472 case HI: return LS; |
| 474 case CS: return CC; | 473 case CS: return CC; |
| 475 default: | 474 default: |
| 476 UNIMPLEMENTED(); | 475 UNIMPLEMENTED(); |
| 477 return EQ; | 476 return EQ; |
| 478 } | 477 } |
| 479 } | 478 } |
| 480 | 479 |
| 481 | 480 |
| 482 // R1: left. | 481 // R1: left, also on stack. |
| 483 // R0: right. | 482 // R0: right, also on stack. |
| 484 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, | 483 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, |
| 485 const ICData& orig_ic_data, | 484 const ICData& orig_ic_data, |
| 486 LocationSummary* locs, | 485 LocationSummary* locs, |
| 487 BranchInstr* branch, | 486 BranchInstr* branch, |
| 488 Token::Kind kind, | 487 Token::Kind kind, |
| 489 intptr_t deopt_id, | 488 intptr_t deopt_id, |
| 490 intptr_t token_pos) { | 489 intptr_t token_pos) { |
| 491 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); | 490 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); |
| 492 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); | 491 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); |
| 493 ASSERT(ic_data.NumberOfChecks() > 0); | 492 ASSERT(ic_data.NumberOfChecks() > 0); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 511 Label next_test; | 510 Label next_test; |
| 512 __ CompareImmediate(temp, ic_data.GetReceiverClassIdAt(i)); | 511 __ CompareImmediate(temp, ic_data.GetReceiverClassIdAt(i)); |
| 513 if (i < len - 1) { | 512 if (i < len - 1) { |
| 514 __ b(&next_test, NE); | 513 __ b(&next_test, NE); |
| 515 } else { | 514 } else { |
| 516 __ b(deopt, NE); | 515 __ b(deopt, NE); |
| 517 } | 516 } |
| 518 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); | 517 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); |
| 519 if (target.Owner() == object_store->object_class()) { | 518 if (target.Owner() == object_store->object_class()) { |
| 520 // Object.== is same as ===. | 519 // Object.== is same as ===. |
| 520 __ Drop(2); |
| 521 __ cmp(left, ShifterOperand(right)); | 521 __ cmp(left, ShifterOperand(right)); |
| 522 if (branch != NULL) { | 522 if (branch != NULL) { |
| 523 branch->EmitBranchOnCondition(compiler, cond); | 523 branch->EmitBranchOnCondition(compiler, cond); |
| 524 } else { | 524 } else { |
| 525 Register result = locs->out().reg(); | 525 Register result = locs->out().reg(); |
| 526 __ LoadObject(result, Bool::True(), cond); | 526 __ LoadObject(result, Bool::True(), cond); |
| 527 __ LoadObject(result, Bool::False(), NegateCondition(cond)); | 527 __ LoadObject(result, Bool::False(), NegateCondition(cond)); |
| 528 } | 528 } |
| 529 } else { | 529 } else { |
| 530 __ PushList((1 << R0) | (1 << R1)); | |
| 531 const int kNumberOfArguments = 2; | 530 const int kNumberOfArguments = 2; |
| 532 const Array& kNoArgumentNames = Array::Handle(); | 531 const Array& kNoArgumentNames = Array::Handle(); |
| 533 compiler->GenerateStaticCall(deopt_id, | 532 compiler->GenerateStaticCall(deopt_id, |
| 534 token_pos, | 533 token_pos, |
| 535 target, | 534 target, |
| 536 kNumberOfArguments, | 535 kNumberOfArguments, |
| 537 kNoArgumentNames, | 536 kNoArgumentNames, |
| 538 locs); | 537 locs); |
| 539 if (branch == NULL) { | 538 if (branch == NULL) { |
| 540 if (kind == Token::kNE) { | 539 if (kind == Token::kNE) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 __ b(&load_true, cond); | 601 __ b(&load_true, cond); |
| 603 __ LoadObject(result, Bool::False()); | 602 __ LoadObject(result, Bool::False()); |
| 604 __ b(&done); | 603 __ b(&done); |
| 605 __ Bind(&load_true); | 604 __ Bind(&load_true); |
| 606 __ LoadObject(result, Bool::True()); | 605 __ LoadObject(result, Bool::True()); |
| 607 } | 606 } |
| 608 __ b(&done); | 607 __ b(&done); |
| 609 __ Bind(&non_null_compare); // Receiver is not null. | 608 __ Bind(&non_null_compare); // Receiver is not null. |
| 610 ASSERT(left == R1); | 609 ASSERT(left == R1); |
| 611 ASSERT(right == R0); | 610 ASSERT(right == R0); |
| 611 __ PushList((1 << R0) | (1 << R1)); |
| 612 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, | 612 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind, |
| 613 deopt_id, token_pos); | 613 deopt_id, token_pos); |
| 614 __ Bind(&done); | 614 __ Bind(&done); |
| 615 } | 615 } |
| 616 | 616 |
| 617 | 617 |
| 618 static Condition FlipCondition(Condition condition) { | 618 static Condition FlipCondition(Condition condition) { |
| 619 switch (condition) { | 619 switch (condition) { |
| 620 case EQ: return EQ; | 620 case EQ: return EQ; |
| 621 case NE: return NE; | 621 case NE: return NE; |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 } | 711 } |
| 712 if (IsPolymorphic()) { | 712 if (IsPolymorphic()) { |
| 713 EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(), | 713 EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(), |
| 714 deopt_id(), token_pos()); | 714 deopt_id(), token_pos()); |
| 715 return; | 715 return; |
| 716 } | 716 } |
| 717 Register left = locs()->in(0).reg(); | 717 Register left = locs()->in(0).reg(); |
| 718 Register right = locs()->in(1).reg(); | 718 Register right = locs()->in(1).reg(); |
| 719 ASSERT(left == R1); | 719 ASSERT(left == R1); |
| 720 ASSERT(right == R0); | 720 ASSERT(right == R0); |
| 721 __ PushList((1 << R0) | (1 << R1)); |
| 721 EmitEqualityAsInstanceCall(compiler, | 722 EmitEqualityAsInstanceCall(compiler, |
| 722 deopt_id(), | 723 deopt_id(), |
| 723 token_pos(), | 724 token_pos(), |
| 724 kind(), | 725 kind(), |
| 725 locs(), | 726 locs(), |
| 726 *ic_data()); | 727 *ic_data()); |
| 727 ASSERT(locs()->out().reg() == R0); | 728 ASSERT(locs()->out().reg() == R0); |
| 728 } | 729 } |
| 729 | 730 |
| 730 | 731 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 753 } | 754 } |
| 754 if (IsPolymorphic()) { | 755 if (IsPolymorphic()) { |
| 755 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(), | 756 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(), |
| 756 deopt_id(), token_pos()); | 757 deopt_id(), token_pos()); |
| 757 return; | 758 return; |
| 758 } | 759 } |
| 759 Register left = locs()->in(0).reg(); | 760 Register left = locs()->in(0).reg(); |
| 760 Register right = locs()->in(1).reg(); | 761 Register right = locs()->in(1).reg(); |
| 761 ASSERT(left == R1); | 762 ASSERT(left == R1); |
| 762 ASSERT(right == R0); | 763 ASSERT(right == R0); |
| 764 __ PushList((1 << R0) | (1 << R1)); |
| 763 EmitEqualityAsInstanceCall(compiler, | 765 EmitEqualityAsInstanceCall(compiler, |
| 764 deopt_id(), | 766 deopt_id(), |
| 765 token_pos(), | 767 token_pos(), |
| 766 Token::kEQ, // kNE reverse occurs at branch. | 768 Token::kEQ, // kNE reverse occurs at branch. |
| 767 locs(), | 769 locs(), |
| 768 *ic_data()); | 770 *ic_data()); |
| 769 if (branch->is_checked()) { | 771 if (branch->is_checked()) { |
| 770 EmitAssertBoolean(R0, token_pos(), deopt_id(), locs(), compiler); | 772 EmitAssertBoolean(R0, token_pos(), deopt_id(), locs(), compiler); |
| 771 } | 773 } |
| 772 Condition branch_condition = (kind() == Token::kNE) ? NE : EQ; | 774 Condition branch_condition = (kind() == Token::kNE) ? NE : EQ; |
| (...skipping 2248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3021 compiler->GenerateCall(token_pos(), | 3023 compiler->GenerateCall(token_pos(), |
| 3022 &label, | 3024 &label, |
| 3023 PcDescriptors::kOther, | 3025 PcDescriptors::kOther, |
| 3024 locs()); | 3026 locs()); |
| 3025 __ Drop(2); // Discard type arguments and receiver. | 3027 __ Drop(2); // Discard type arguments and receiver. |
| 3026 } | 3028 } |
| 3027 | 3029 |
| 3028 } // namespace dart | 3030 } // namespace dart |
| 3029 | 3031 |
| 3030 #endif // defined TARGET_ARCH_ARM | 3032 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |