Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: runtime/vm/intermediate_language_arm.cc

Issue 27307005: Change == into an instance call to allow polymorphic inlining of ==. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: rebased, addressed comments Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intermediate_language.cc ('k') | runtime/vm/intermediate_language_ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language.cc ('k') | runtime/vm/intermediate_language_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698