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

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

Issue 12529008: Collect type feedback for fields. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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_X64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
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 386 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 __ LoadObject(RAX, Bool::True()); 413 __ LoadObject(RAX, Bool::True());
413 __ jmp(&done, Assembler::kNearJump); 414 __ jmp(&done, Assembler::kNearJump);
414 __ Bind(&true_label); 415 __ Bind(&true_label);
415 __ LoadObject(RAX, Bool::False()); 416 __ LoadObject(RAX, Bool::False());
416 __ Bind(&done); 417 __ Bind(&done);
417 } 418 }
418 __ Bind(&equality_done); 419 __ Bind(&equality_done);
419 } 420 }
420 421
421 422
423 static void LoadValueCid(FlowGraphCompiler* compiler,
424 Register value_cid_reg,
425 Register value_reg,
426 Label* value_is_smi = NULL) {
427 Label done;
428 if (value_is_smi == NULL) {
429 __ movq(value_cid_reg, Immediate(kSmiCid));
430 }
431 __ testq(value_reg, Immediate(kSmiTagMask));
432 if (value_is_smi == NULL) {
433 __ j(ZERO, &done, Assembler::kNearJump);
434 } else {
435 __ j(ZERO, value_is_smi);
436 }
437 __ LoadClassId(value_cid_reg, value_reg);
438 __ Bind(&done);
439 }
440
441
422 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler, 442 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
423 const ICData& orig_ic_data, 443 const ICData& orig_ic_data,
424 LocationSummary* locs, 444 LocationSummary* locs,
425 BranchInstr* branch, 445 BranchInstr* branch,
426 Token::Kind kind, 446 Token::Kind kind,
427 intptr_t deopt_id, 447 intptr_t deopt_id,
428 intptr_t token_pos) { 448 intptr_t token_pos) {
429 ASSERT((kind == Token::kEQ) || (kind == Token::kNE)); 449 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
430 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks()); 450 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
431 ASSERT(ic_data.NumberOfChecks() > 0); 451 ASSERT(ic_data.NumberOfChecks() > 0);
432 ASSERT(ic_data.num_args_tested() == 1); 452 ASSERT(ic_data.num_args_tested() == 1);
433 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality); 453 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
434 Register left = locs->in(0).reg(); 454 Register left = locs->in(0).reg();
435 Register right = locs->in(1).reg(); 455 Register right = locs->in(1).reg();
436 __ testq(left, Immediate(kSmiTagMask));
437 Register temp = locs->temp(0).reg(); 456 Register temp = locs->temp(0).reg();
438 if (ic_data.GetReceiverClassIdAt(0) == kSmiCid) { 457 LoadValueCid(compiler, temp, left,
439 Label done, load_class_id; 458 (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
440 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
441 __ movq(temp, Immediate(kSmiCid));
442 __ jmp(&done, Assembler::kNearJump);
443 __ Bind(&load_class_id);
444 __ LoadClassId(temp, left);
445 __ Bind(&done);
446 } else {
447 __ j(ZERO, deopt); // Smi deopts.
448 __ LoadClassId(temp, left);
449 }
450 // 'temp' contains class-id of the left argument. 459 // 'temp' contains class-id of the left argument.
451 ObjectStore* object_store = Isolate::Current()->object_store(); 460 ObjectStore* object_store = Isolate::Current()->object_store();
452 Condition cond = TokenKindToSmiCondition(kind); 461 Condition cond = TokenKindToSmiCondition(kind);
453 Label done; 462 Label done;
454 const intptr_t len = ic_data.NumberOfChecks(); 463 const intptr_t len = ic_data.NumberOfChecks();
455 for (intptr_t i = 0; i < len; i++) { 464 for (intptr_t i = 0; i < len; i++) {
456 // Assert that the Smi is at position 0, if at all. 465 // Assert that the Smi is at position 0, if at all.
457 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); 466 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
458 Label next_test; 467 Label next_test;
459 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); 468 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 Register left = locs()->in(0).reg(); 820 Register left = locs()->in(0).reg();
812 Register right = locs()->in(1).reg(); 821 Register right = locs()->in(1).reg();
813 __ pushq(left); 822 __ pushq(left);
814 __ pushq(right); 823 __ pushq(right);
815 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 824 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
816 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptRelationalOp); 825 Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptRelationalOp);
817 826
818 // Load class into RDI. Since this is a call, any register except 827 // Load class into RDI. Since this is a call, any register except
819 // the fixed input registers would be ok. 828 // the fixed input registers would be ok.
820 ASSERT((left != RDI) && (right != RDI)); 829 ASSERT((left != RDI) && (right != RDI));
821 Label done; 830 LoadValueCid(compiler, RDI, left);
822 __ movq(RDI, Immediate(kSmiCid));
823 __ testq(left, Immediate(kSmiTagMask));
824 __ j(ZERO, &done);
825 __ LoadClassId(RDI, left);
826 __ Bind(&done);
827 const intptr_t kNumArguments = 2; 831 const intptr_t kNumArguments = 2;
828 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()), 832 compiler->EmitTestAndCall(ICData::Handle(ic_data()->AsUnaryClassChecks()),
829 RDI, // Class id register. 833 RDI, // Class id register.
830 kNumArguments, 834 kNumArguments,
831 Array::Handle(), // No named arguments. 835 Array::Handle(), // No named arguments.
832 deopt, // Deoptimize target. 836 deopt, // Deoptimize target.
833 deopt_id(), 837 deopt_id(),
834 token_pos(), 838 token_pos(),
835 locs()); 839 locs());
836 return; 840 return;
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
1325 break; 1329 break;
1326 case kFloat64ArrayCid: 1330 case kFloat64ArrayCid:
1327 __ movsd(element_address, locs()->in(2).fpu_reg()); 1331 __ movsd(element_address, locs()->in(2).fpu_reg());
1328 break; 1332 break;
1329 default: 1333 default:
1330 UNREACHABLE(); 1334 UNREACHABLE();
1331 } 1335 }
1332 } 1336 }
1333 1337
1334 1338
1339 LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
1340 const intptr_t kNumInputs = 1;
1341 LocationSummary* summary =
1342 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
1343 summary->set_in(0, Location::RequiresRegister());
1344 if ((value()->Type()->ToCid() == kDynamicCid) &&
1345 (field().guarded_cid() != kSmiCid)) {
1346 summary->AddTemp(Location::RequiresRegister());
1347 }
1348 if (field().guarded_cid() == kIllegalCid) {
1349 summary->AddTemp(Location::RequiresRegister());
1350 }
1351 return summary;
1352 }
1353
1354
1355 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1356 const intptr_t field_cid = field().guarded_cid();
1357 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
1358
1359 if (field_cid == kDynamicCid) {
1360 ASSERT(!compiler->is_optimizing());
1361 return; // Nothing to emit.
1362 }
1363
1364 const intptr_t value_cid = value()->Type()->ToCid();
1365
1366 Register value_reg = locs()->in(0).reg();
1367
1368 Register value_cid_reg = ((value_cid == kDynamicCid) &&
1369 (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister;
1370
1371 Register field_reg = (field_cid == kIllegalCid) ?
1372 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
1373
1374 Label ok, fail_label;
1375
1376 Label* deopt = compiler->is_optimizing() ?
1377 compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL;
1378
1379 Label* fail = (deopt != NULL) ? deopt : &fail_label;
1380
1381 const bool ok_is_fall_through = (deopt != NULL);
1382
1383 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
1384 if (!compiler->is_optimizing()) {
1385 // Currently we can't have different location summaries for optimized
1386 // and non-optimized code. So instead we manually pick up a register
1387 // that is known to be free because we know how non-optimizing compiler
1388 // allocates registers.
1389 field_reg = RBX;
1390 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg));
1391 }
1392
1393 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1394
1395 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
1396 FieldAddress field_nullability_operand(
1397 field_reg, Field::is_nullable_offset());
1398
1399 if (value_cid == kDynamicCid) {
1400 if (value_cid_reg == kNoRegister) {
1401 ASSERT(!compiler->is_optimizing());
1402 value_cid_reg = RDX;
1403 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1404 }
1405
1406 LoadValueCid(compiler, value_cid_reg, value_reg);
1407
1408 __ cmpq(value_cid_reg, field_cid_operand);
1409 __ j(EQUAL, &ok);
1410 __ cmpq(value_cid_reg, field_nullability_operand);
1411 } else if (value_cid == kNullCid) {
1412 __ cmpq(field_nullability_operand, Immediate(value_cid));
1413 } else {
1414 __ cmpq(field_cid_operand, Immediate(value_cid));
1415 }
1416 __ j(EQUAL, &ok);
1417
1418 __ cmpq(field_cid_operand, Immediate(kIllegalCid));
1419 __ j(NOT_EQUAL, fail);
1420
1421 if (value_cid == kDynamicCid) {
1422 __ movq(field_cid_operand, value_cid_reg);
1423 __ movq(field_nullability_operand, value_cid_reg);
1424 } else {
1425 __ movq(field_cid_operand, Immediate(value_cid));
1426 __ movq(field_nullability_operand, Immediate(value_cid));
1427 }
1428
1429 if (!ok_is_fall_through) {
1430 __ jmp(&ok);
1431 }
1432 } else {
1433 if (value_cid == kDynamicCid) {
1434 // Field's guarded class id is fixed but value's class id is not known.
1435 __ testq(value_reg, Immediate(kSmiTagMask));
1436
1437 if (field_cid != kSmiCid) {
1438 __ j(ZERO, fail);
1439 __ LoadClassId(value_cid_reg, value_reg);
1440 __ cmpq(value_cid_reg, Immediate(field_cid));
1441 }
1442
1443 if (field().is_nullable() && (field_cid != kNullCid)) {
1444 __ j(EQUAL, &ok);
1445 const Immediate& raw_null =
1446 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1447 __ cmpq(value_reg, raw_null);
1448 }
1449
1450 if (ok_is_fall_through) {
1451 __ j(NOT_EQUAL, fail);
1452 } else {
1453 __ j(EQUAL, &ok);
1454 }
1455 } else {
1456 // Both value's and field's class id is known.
1457 if ((value_cid != field_cid) && (value_cid != nullability)) {
1458 if (ok_is_fall_through) {
1459 __ jmp(fail);
1460 }
1461 } else {
1462 // Nothing to emit.
1463 ASSERT(!compiler->is_optimizing());
1464 return;
1465 }
1466 }
1467 }
1468
1469 if (deopt == NULL) {
1470 ASSERT(!compiler->is_optimizing());
1471 __ Bind(fail);
1472
1473 __ cmpq(FieldAddress(field_reg, Field::guarded_cid_offset()),
1474 Immediate(kDynamicCid));
1475 __ j(EQUAL, &ok);
1476
1477 __ pushq(field_reg);
1478 __ pushq(value_reg);
1479 __ CallRuntime(kUpdateFieldCidRuntimeEntry);
1480 __ Drop(2); // Drop the field and the value.
1481 }
1482
1483 __ Bind(&ok);
1484 }
1485
1486
1335 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { 1487 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
1336 const intptr_t kNumInputs = 2; 1488 const intptr_t kNumInputs = 2;
1337 const intptr_t num_temps = 0; 1489 const intptr_t num_temps = 0;
1338 LocationSummary* summary = 1490 LocationSummary* summary =
1339 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); 1491 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall);
1340 summary->set_in(0, Location::RequiresRegister()); 1492 summary->set_in(0, Location::RequiresRegister());
1341 summary->set_in(1, ShouldEmitStoreBarrier() 1493 summary->set_in(1, ShouldEmitStoreBarrier()
1342 ? Location::WritableRegister() 1494 ? Location::WritableRegister()
1343 : Location::RegisterOrConstant(value())); 1495 : Location::RegisterOrConstant(value()));
1344 return summary; 1496 return summary;
(...skipping 1293 matching lines...) Expand 10 before | Expand all | Expand 10 after
2638 target, 2790 target,
2639 instance_call()->ArgumentCount(), 2791 instance_call()->ArgumentCount(),
2640 instance_call()->argument_names(), 2792 instance_call()->argument_names(),
2641 locs()); 2793 locs());
2642 return; 2794 return;
2643 } 2795 }
2644 2796
2645 // Load receiver into RAX. 2797 // Load receiver into RAX.
2646 __ movq(RAX, 2798 __ movq(RAX,
2647 Address(RSP, (instance_call()->ArgumentCount() - 1) * kWordSize)); 2799 Address(RSP, (instance_call()->ArgumentCount() - 1) * kWordSize));
2648 Label done; 2800 LoadValueCid(compiler, RDI, RAX,
2649 if (ic_data().GetReceiverClassIdAt(0) == kSmiCid) { 2801 (ic_data().GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
2650 __ movq(RDI, Immediate(kSmiCid));
2651 __ testq(RAX, Immediate(kSmiTagMask));
2652 __ j(ZERO, &done, Assembler::kNearJump);
2653 } else {
2654 __ testq(RAX, Immediate(kSmiTagMask));
2655 __ j(ZERO, deopt);
2656 }
2657 __ LoadClassId(RDI, RAX);
2658 __ Bind(&done);
2659 compiler->EmitTestAndCall(ic_data(), 2802 compiler->EmitTestAndCall(ic_data(),
2660 RDI, // Class id register. 2803 RDI, // Class id register.
2661 instance_call()->ArgumentCount(), 2804 instance_call()->ArgumentCount(),
2662 instance_call()->argument_names(), 2805 instance_call()->argument_names(),
2663 deopt, 2806 deopt,
2664 instance_call()->deopt_id(), 2807 instance_call()->deopt_id(),
2665 instance_call()->token_pos(), 2808 instance_call()->token_pos(),
2666 locs()); 2809 locs());
2667 } 2810 }
2668 2811
2669 2812
2670 LocationSummary* BranchInstr::MakeLocationSummary() const { 2813 LocationSummary* BranchInstr::MakeLocationSummary() const {
2671 UNREACHABLE(); 2814 UNREACHABLE();
2672 return NULL; 2815 return NULL;
2673 } 2816 }
2674 2817
2675 2818
2676 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2819 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2677 comparison()->EmitBranchCode(compiler, this); 2820 comparison()->EmitBranchCode(compiler, this);
2678 } 2821 }
2679 2822
2680 2823
2681 LocationSummary* CheckClassInstr::MakeLocationSummary() const { 2824 LocationSummary* CheckClassInstr::MakeLocationSummary() const {
2682 const intptr_t kNumInputs = 1; 2825 const intptr_t kNumInputs = 1;
2683 const intptr_t kNumTemps = 1; 2826 const intptr_t kNumTemps = 0;
2684 LocationSummary* summary = 2827 LocationSummary* summary =
2685 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 2828 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
2686 summary->set_in(0, Location::RequiresRegister()); 2829 summary->set_in(0, Location::RequiresRegister());
2687 summary->set_temp(0, Location::RequiresRegister()); 2830 if (!null_check()) {
2831 summary->AddTemp(Location::RequiresRegister());
2832 }
2688 return summary; 2833 return summary;
2689 } 2834 }
2690 2835
2691 2836
2692 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 2837 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
2838 if (null_check()) {
2839 Label* deopt = compiler->AddDeoptStub(deopt_id(),
2840 kDeoptCheckClass);
2841 const Immediate& raw_null =
2842 Immediate(reinterpret_cast<intptr_t>(Object::null()));
2843 __ cmpq(locs()->in(0).reg(), raw_null);
2844 __ j(EQUAL, deopt);
2845 return;
2846 }
2847
2693 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || 2848 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) ||
2694 (unary_checks().NumberOfChecks() > 1)); 2849 (unary_checks().NumberOfChecks() > 1));
2695 Register value = locs()->in(0).reg(); 2850 Register value = locs()->in(0).reg();
2696 Register temp = locs()->temp(0).reg(); 2851 Register temp = locs()->temp(0).reg();
2697 Label* deopt = compiler->AddDeoptStub(deopt_id(), 2852 Label* deopt = compiler->AddDeoptStub(deopt_id(),
2698 kDeoptCheckClass); 2853 kDeoptCheckClass);
2699 Label is_ok; 2854 Label is_ok;
2700 intptr_t cix = 0; 2855 intptr_t cix = 0;
2701 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { 2856 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
2702 __ testq(value, Immediate(kSmiTagMask)); 2857 __ testq(value, Immediate(kSmiTagMask));
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after
3158 PcDescriptors::kOther, 3313 PcDescriptors::kOther,
3159 locs()); 3314 locs());
3160 __ Drop(2); // Discard type arguments and receiver. 3315 __ Drop(2); // Discard type arguments and receiver.
3161 } 3316 }
3162 3317
3163 } // namespace dart 3318 } // namespace dart
3164 3319
3165 #undef __ 3320 #undef __
3166 3321
3167 #endif // defined TARGET_ARCH_X64 3322 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698