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

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

Issue 12529008: Collect type feedback for fields. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: ensure that not-null constraints are recomputed correctly Created 7 years, 9 months 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
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_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"
11 #include "vm/dart_entry.h" 11 #include "vm/dart_entry.h"
12 #include "vm/flow_graph_compiler.h" 12 #include "vm/flow_graph_compiler.h"
13 #include "vm/locations.h" 13 #include "vm/locations.h"
14 #include "vm/object_store.h" 14 #include "vm/object_store.h"
15 #include "vm/parser.h" 15 #include "vm/parser.h"
16 #include "vm/stack_frame.h"
16 #include "vm/stub_code.h" 17 #include "vm/stub_code.h"
17 #include "vm/symbols.h" 18 #include "vm/symbols.h"
18 19
19 #define __ compiler->assembler()-> 20 #define __ compiler->assembler()->
20 21
21 namespace dart { 22 namespace dart {
22 23
23 DECLARE_FLAG(int, optimization_counter_threshold); 24 DECLARE_FLAG(int, optimization_counter_threshold);
24 DECLARE_FLAG(bool, propagate_ic_data); 25 DECLARE_FLAG(bool, propagate_ic_data);
25 26
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 __ LoadObject(EAX, Bool::True()); 416 __ LoadObject(EAX, Bool::True());
416 __ jmp(&done, Assembler::kNearJump); 417 __ jmp(&done, Assembler::kNearJump);
417 __ Bind(&true_label); 418 __ Bind(&true_label);
418 __ LoadObject(EAX, Bool::False()); 419 __ LoadObject(EAX, Bool::False());
419 __ Bind(&done); 420 __ Bind(&done);
420 } 421 }
421 __ Bind(&equality_done); 422 __ Bind(&equality_done);
422 } 423 }
423 424
424 425
426 static void LoadValueCid(FlowGraphCompiler* compiler,
427 Register value_cid_reg,
428 Register value_reg,
429 Label* value_is_smi = NULL) {
430 Label done;
431 if (value_is_smi == NULL) {
432 __ movl(value_cid_reg, Immediate(kSmiCid));
433 }
434 __ testl(value_reg, Immediate(kSmiTagMask));
435 if (value_is_smi == NULL) {
436 __ j(ZERO, &done, Assembler::kNearJump);
437 } else {
438 __ j(ZERO, value_is_smi);
439 }
440 __ LoadClassId(value_cid_reg, value_reg);
441 __ Bind(&done);
442 }
443
444
425 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, 445 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
426 const ICData& orig_ic_data, 446 const ICData& orig_ic_data,
427 LocationSummary* locs, 447 LocationSummary* locs,
428 BranchInstr* branch, 448 BranchInstr* branch,
429 Token::Kind kind, 449 Token::Kind kind,
430 intptr_t deopt_id, 450 intptr_t deopt_id,
431 intptr_t token_pos) { 451 intptr_t token_pos) {
432 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); 452 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
433 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); 453 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
434 ASSERT(ic_data.NumberOfChecks() > 0); 454 ASSERT(ic_data.NumberOfChecks() > 0);
435 ASSERT(ic_data.num_args_tested() == 1); 455 ASSERT(ic_data.num_args_tested() == 1);
436 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); 456 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
437 Register left = locs->in(0).reg(); 457 Register left = locs->in(0).reg();
438 Register right = locs->in(1).reg(); 458 Register right = locs->in(1).reg();
439 __ testl(left, Immediate(kSmiTagMask));
440 Register temp = locs->temp(0).reg(); 459 Register temp = locs->temp(0).reg();
441 if (ic_data.GetReceiverClassIdAt(0) == kSmiCid) { 460 LoadValueCid(compiler, temp, left,
442 Label done, load_class_id; 461 (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
443 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
444 __ movl(temp, Immediate(kSmiCid));
445 __ jmp(&done, Assembler::kNearJump);
446 __ Bind(&load_class_id);
447 __ LoadClassId(temp, left);
448 __ Bind(&done);
449 } else {
450 __ j(ZERO, deopt); // Smi deopts.
451 __ LoadClassId(temp, left);
452 }
453 // 'temp' contains class-id of the left argument. 462 // 'temp' contains class-id of the left argument.
454 ObjectStore* object_store = Isolate::Current()->object_store(); 463 ObjectStore* object_store = Isolate::Current()->object_store();
455 Condition cond = TokenKindToSmiCondition(kind); 464 Condition cond = TokenKindToSmiCondition(kind);
456 Label done; 465 Label done;
457 const intptr_t len = ic_data.NumberOfChecks(); 466 const intptr_t len = ic_data.NumberOfChecks();
458 for (intptr_t i = 0; i < len; i++) { 467 for (intptr_t i = 0; i < len; i++) {
459 // Assert that the Smi is at position 0, if at all. 468 // Assert that the Smi is at position 0, if at all.
460 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); 469 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
461 Label next_test; 470 Label next_test;
462 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); 471 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after
942 // explicitly pushing arguments to the call here. 951 // explicitly pushing arguments to the call here.
943 Register left = locs()->in(0).reg(); 952 Register left = locs()->in(0).reg();
944 Register right = locs()->in(1).reg(); 953 Register right = locs()->in(1).reg();
945 __ pushl(left); 954 __ pushl(left);
946 __ pushl(right); 955 __ pushl(right);
947 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 956 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
948 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptRelationalOp); 957 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptRelationalOp);
949 // Load class into EDI. Since this is a call, any register except 958 // Load class into EDI. Since this is a call, any register except
950 // the fixed input registers would be ok. 959 // the fixed input registers would be ok.
951 ASSERT((left != EDI) && (right != EDI)); 960 ASSERT((left != EDI) && (right != EDI));
952 Label done;
953 const intptr_t kNumArguments = 2; 961 const intptr_t kNumArguments = 2;
954 __ movl(EDI, Immediate(kSmiCid)); 962 LoadValueCid(compiler, EDI, left);
955 __ testl(left, Immediate(kSmiTagMask));
956 __ j(ZERO, &done);
957 __ LoadClassId(EDI, left);
958 __ Bind(&done);
959 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()), 963 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()),
960 EDI, // Class id register. 964 EDI, // Class id register.
961 kNumArguments, 965 kNumArguments,
962 Array::Handle(), // No named arguments. 966 Array::Handle(), // No named arguments.
963 deopt, // Deoptimize target. 967 deopt, // Deoptimize target.
964 deopt_id(), 968 deopt_id(),
965 token_pos(), 969 token_pos(),
966 locs()); 970 locs());
967 return; 971 return;
968 } 972 }
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after
1501 break; 1505 break;
1502 case kFloat64ArrayCid: 1506 case kFloat64ArrayCid:
1503 __ movsd(element_address, locs()->in(2).fpu_reg()); 1507 __ movsd(element_address, locs()->in(2).fpu_reg());
1504 break; 1508 break;
1505 default: 1509 default:
1506 UNREACHABLE(); 1510 UNREACHABLE();
1507 } 1511 }
1508 } 1512 }
1509 1513
1510 1514
1515 LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
1516 const intptr_t kNumInputs = 1;
1517 LocationSummary* summary =
1518 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
1519 summary->set_in(0, Location::RequiresRegister());
1520 if ((value()->Type()->ToCid() == kDynamicCid) &&
1521 (field().guarded_cid() != kSmiCid)) {
1522 summary->AddTemp(Location::RequiresRegister());
1523 }
1524 if (field().guarded_cid() == kIllegalCid) {
1525 summary->AddTemp(Location::RequiresRegister());
1526 }
1527 return summary;
1528 }
1529
1530
1531 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1532 const intptr_t field_cid = field().guarded_cid();
1533 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
1534
1535 if (field_cid == kDynamicCid) {
1536 ASSERT(!compiler->is_optimizing());
1537 return; // Nothing to emit.
1538 }
1539
1540 const intptr_t value_cid = value()->Type()->ToCid();
1541
1542 Register value_reg = locs()->in(0).reg();
1543
1544 Register value_cid_reg = ((value_cid == kDynamicCid) &&
1545 (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
1546
1547 Register field_reg = (field_cid == kIllegalCid) ?
1548 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
1549
1550 Label ok, fail_label;
1551
1552 Label* deopt = compiler->is_optimizing() ?
1553 compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL;
1554
1555 Label* fail = (deopt != NULL) ? deopt : &fail_label;
1556
1557 const bool ok_is_fall_through = (deopt != NULL);
1558
1559 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
1560 if (!compiler->is_optimizing()) {
1561 // Currently we can't have different location summaries for optimized
1562 // and non-optimized code. So instead we manually pick up a register
1563 // that is known to be free because we know how non-optimizing compiler
1564 // allocates registers.
1565 field_reg = EBX;
1566 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg));
1567 }
1568
1569 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1570
1571 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
1572 FieldAddress field_nullability_operand(
1573 field_reg, Field::is_nullable_offset());
1574
1575 if (value_cid == kDynamicCid) {
1576 if (value_cid_reg == kNoRegister) {
1577 ASSERT(!compiler->is_optimizing());
1578 value_cid_reg = EDX;
1579 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1580 }
1581
1582 LoadValueCid(compiler, value_cid_reg, value_reg);
1583
1584 __ cmpl(value_cid_reg, field_cid_operand);
1585 __ j(EQUAL, &ok);
1586 __ cmpl(value_cid_reg, field_nullability_operand);
1587 } else if (value_cid == kNullCid) {
1588 __ cmpl(field_nullability_operand, Immediate(value_cid));
1589 } else {
1590 __ cmpl(field_cid_operand, Immediate(value_cid));
1591 }
1592 __ j(EQUAL, &ok);
1593
1594 __ cmpl(field_cid_operand, Immediate(kIllegalCid));
1595 __ j(NOT_EQUAL, fail);
1596
1597 if (value_cid == kDynamicCid) {
1598 __ movl(field_cid_operand, value_cid_reg);
1599 __ movl(field_nullability_operand, value_cid_reg);
1600 } else {
1601 __ movl(field_cid_operand, Immediate(value_cid));
1602 __ movl(field_nullability_operand, Immediate(value_cid));
1603 }
1604
1605 if (!ok_is_fall_through) {
1606 __ jmp(&ok);
1607 }
1608 } else {
1609 if (value_cid == kDynamicCid) {
1610 // Field's guarded class id is fixed by value's class id is not known.
1611 __ testl(value_reg, Immediate(kSmiTagMask));
1612
1613 if (field_cid != kSmiCid) {
1614 __ j(ZERO, fail);
1615 __ LoadClassId(value_cid_reg, value_reg);
1616 __ cmpl(value_cid_reg, Immediate(field_cid));
1617 }
1618
1619 if (field().is_nullable() && (field_cid != kNullCid)) {
1620 __ j(EQUAL, &ok);
1621 const Immediate& raw_null =
1622 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1623 __ cmpl(value_reg, raw_null);
1624 }
1625
1626 if (ok_is_fall_through) {
1627 __ j(NOT_EQUAL, fail);
1628 } else {
1629 __ j(EQUAL, &ok);
1630 }
1631 } else {
1632 // Both value's and field's class id is known.
1633 if ((value_cid != field_cid) && (value_cid != nullability)) {
1634 if (ok_is_fall_through) {
1635 __ jmp(fail);
1636 }
1637 } else {
1638 // Nothing to emit.
1639 ASSERT(!compiler->is_optimizing());
1640 return;
1641 }
1642 }
1643 }
1644
1645 if (deopt == NULL) {
1646 ASSERT(!compiler->is_optimizing());
1647 __ Bind(fail);
1648
1649 __ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
1650 Immediate(kDynamicCid));
1651 __ j(EQUAL, &ok);
1652
1653 __ pushl(field_reg);
1654 __ pushl(value_reg);
1655 __ CallRuntime(kUpdateFieldCidRuntimeEntry);
1656 __ Drop(2); // Drop the field and the value.
1657 }
1658
1659 __ Bind(&ok);
1660 }
1661
1662
1511 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { 1663 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
1512 const intptr_t kNumInputs = 2; 1664 const intptr_t kNumInputs = 2;
1513 const intptr_t num_temps = 0; 1665 const intptr_t num_temps = 0;
1514 LocationSummary* summary = 1666 LocationSummary* summary =
1515 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); 1667 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
1516 summary->set_in(0, Location::RequiresRegister()); 1668 summary->set_in(0, Location::RequiresRegister());
1517 summary->set_in(1, ShouldEmitStoreBarrier() 1669 summary->set_in(1, ShouldEmitStoreBarrier()
1518 ? Location::WritableRegister() 1670 ? Location::WritableRegister()
1519 : Location::RegisterOrConstant(value())); 1671 : Location::RegisterOrConstant(value()));
1520 return summary; 1672 return summary;
(...skipping 1264 matching lines...) Expand 10 before | Expand all | Expand 10 after
2785 instance_call()->ArgumentCount(), 2937 instance_call()->ArgumentCount(),
2786 instance_call()->argument_names(), 2938 instance_call()->argument_names(),
2787 locs()); 2939 locs());
2788 return; 2940 return;
2789 } 2941 }
2790 2942
2791 // Load receiver into EAX. 2943 // Load receiver into EAX.
2792 __ movl(EAX, 2944 __ movl(EAX,
2793 Address(ESP, (instance_call()->ArgumentCount() - 1) * kWordSize)); 2945 Address(ESP, (instance_call()->ArgumentCount() - 1) * kWordSize));
2794 2946
2795 Label done; 2947 LoadValueCid(compiler, EDI, EAX,
2796 if (ic_data().GetReceiverClassIdAt(0) == kSmiCid) { 2948 (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
2797 __ movl(EDI, Immediate(kSmiCid));
2798 __ testl(EAX, Immediate(kSmiTagMask));
2799 __ j(ZERO, &done, Assembler::kNearJump);
2800 } else {
2801 __ testl(EAX, Immediate(kSmiTagMask));
2802 __ j(ZERO, deopt);
2803 }
2804 __ LoadClassId(EDI, EAX);
2805 __ Bind(&done);
2806 2949
2807 compiler->EmitTestAndCall(ic_data(), 2950 compiler->EmitTestAndCall(ic_data(),
2808 EDI, // Class id register. 2951 EDI, // Class id register.
2809 instance_call()->ArgumentCount(), 2952 instance_call()->ArgumentCount(),
2810 instance_call()->argument_names(), 2953 instance_call()->argument_names(),
2811 deopt, 2954 deopt,
2812 instance_call()->deopt_id(), 2955 instance_call()->deopt_id(),
2813 instance_call()->token_pos(), 2956 instance_call()->token_pos(),
2814 locs()); 2957 locs());
2815 } 2958 }
2816 2959
2817 2960
2818 LocationSummary* BranchInstr::MakeLocationSummary() const { 2961 LocationSummary* BranchInstr::MakeLocationSummary() const {
2819 UNREACHABLE(); 2962 UNREACHABLE();
2820 return NULL; 2963 return NULL;
2821 } 2964 }
2822 2965
2823 2966
2824 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2967 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2825 comparison()->EmitBranchCode(compiler, this); 2968 comparison()->EmitBranchCode(compiler, this);
2826 } 2969 }
2827 2970
2828 2971
2829 LocationSummary* CheckClassInstr::MakeLocationSummary() const { 2972 LocationSummary* CheckClassInstr::MakeLocationSummary() const {
2830 const intptr_t kNumInputs = 1; 2973 const intptr_t kNumInputs = 1;
2831 const intptr_t kNumTemps = 1; 2974 const intptr_t kNumTemps = 0;
2832 LocationSummary* summary = 2975 LocationSummary* summary =
2833 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 2976 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
2834 summary->set_in(0, Location::RequiresRegister()); 2977 summary->set_in(0, Location::RequiresRegister());
2835 summary->set_temp(0, Location::RequiresRegister()); 2978 if (!null_check()) {
2979 summary->AddTemp(Location::RequiresRegister());
2980 }
2836 return summary; 2981 return summary;
2837 } 2982 }
2838 2983
2839 2984
2840 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2985 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2986 if (null_check()) {
2987 Label* deopt = compiler->AddDeoptStub(deopt_id(),
2988 kDeoptCheckClass);
2989 const Immediate& raw_null =
2990 Immediate(reinterpret_cast<intptr_t>(Object::null()));
2991 __ cmpl(locs()->in(0).reg(), raw_null);
2992 __ j(EQUAL, deopt);
2993 return;
2994 }
2995
2841 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || 2996 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) ||
2842 (unary_checks().NumberOfChecks() > 1)); 2997 (unary_checks().NumberOfChecks() > 1));
2843 Register value = locs()->in(0).reg(); 2998 Register value = locs()->in(0).reg();
2844 Register temp = locs()->temp(0).reg(); 2999 Register temp = locs()->temp(0).reg();
2845 Label* deopt = compiler->AddDeoptStub(deopt_id(), 3000 Label* deopt = compiler->AddDeoptStub(deopt_id(),
2846 kDeoptCheckClass); 3001 kDeoptCheckClass);
2847 Label is_ok; 3002 Label is_ok;
2848 intptr_t cix = 0; 3003 intptr_t cix = 0;
2849 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { 3004 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
2850 __ testl(value, Immediate(kSmiTagMask)); 3005 __ testl(value, Immediate(kSmiTagMask));
(...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after
3554 PcDescriptors::kOther, 3709 PcDescriptors::kOther,
3555 locs()); 3710 locs());
3556 __ Drop(2); // Discard type arguments and receiver. 3711 __ Drop(2); // Discard type arguments and receiver.
3557 } 3712 }
3558 3713
3559 } // namespace dart 3714 } // namespace dart
3560 3715
3561 #undef __ 3716 #undef __
3562 3717
3563 #endif // defined TARGET_ARCH_IA32 3718 #endif // defined TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698