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 |