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

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

Issue 10826285: Optimize equality for case when all targets are Object.equals. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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"
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 case Token::kGTE: return GREATER_EQUAL; 246 case Token::kGTE: return GREATER_EQUAL;
247 default: 247 default:
248 UNREACHABLE(); 248 UNREACHABLE();
249 return OVERFLOW; 249 return OVERFLOW;
250 } 250 }
251 } 251 }
252 252
253 253
254 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { 254 LocationSummary* EqualityCompareComp::MakeLocationSummary() const {
255 const intptr_t kNumInputs = 2; 255 const intptr_t kNumInputs = 2;
256 if (receiver_class_id() != kObjectCid) { 256 const bool is_checked_strict_equal =
257 ASSERT((receiver_class_id() == kSmiCid) || 257 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
258 (receiver_class_id() == kDoubleCid)); 258 if ((receiver_class_id() == kSmiCid) ||
259 (receiver_class_id() == kDoubleCid) ||
260 is_checked_strict_equal) {
259 const intptr_t kNumTemps = 1; 261 const intptr_t kNumTemps = 1;
260 LocationSummary* locs = 262 LocationSummary* locs =
261 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 263 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
262 locs->set_in(0, Location::RequiresRegister()); 264 locs->set_in(0, Location::RequiresRegister());
263 locs->set_in(1, Location::RequiresRegister()); 265 locs->set_in(1, Location::RequiresRegister());
264 locs->set_temp(0, Location::RequiresRegister()); 266 locs->set_temp(0, Location::RequiresRegister());
265 locs->set_out(Location::RequiresRegister()); 267 locs->set_out(Location::RequiresRegister());
266 return locs; 268 return locs;
267 } 269 }
268 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 270 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); 341 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
340 __ movq(temp, Immediate(kSmiCid)); 342 __ movq(temp, Immediate(kSmiCid));
341 __ jmp(&done, Assembler::kNearJump); 343 __ jmp(&done, Assembler::kNearJump);
342 __ Bind(&load_class_id); 344 __ Bind(&load_class_id);
343 __ LoadClassId(temp, left); 345 __ LoadClassId(temp, left);
344 __ Bind(&done); 346 __ Bind(&done);
345 } else { 347 } else {
346 __ j(ZERO, deopt); // Smi deopts. 348 __ j(ZERO, deopt); // Smi deopts.
347 __ LoadClassId(temp, left); 349 __ LoadClassId(temp, left);
348 } 350 }
351 // 'temp' contains class-id of the left argument.
352 ObjectStore* object_store = Isolate::Current()->object_store();
349 Condition cond = TokenKindToSmiCondition(kind); 353 Condition cond = TokenKindToSmiCondition(kind);
350 Label done; 354 Label done;
351 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { 355 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
356 // Assert that the Smi is at position 0, if at all.
352 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); 357 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
353 Label next_test; 358 Label next_test;
354 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); 359 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
355 __ j(NOT_EQUAL, &next_test); 360 __ j(NOT_EQUAL, &next_test);
356 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); 361 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
357 ObjectStore* object_store = Isolate::Current()->object_store();
358 if (target.owner() == object_store->object_class()) { 362 if (target.owner() == object_store->object_class()) {
359 // Object.== is same as ===. 363 // Object.== is same as ===.
360 __ Drop(2); 364 __ Drop(2);
361 __ cmpq(left, right); 365 __ cmpq(left, right);
362 if (branch != NULL) { 366 if (branch != NULL) {
363 branch->EmitBranchOnCondition(compiler, cond); 367 branch->EmitBranchOnCondition(compiler, cond);
364 } else { 368 } else {
365 // This case should be rare. 369 // This case should be rare.
366 Register result = locs.out().reg(); 370 Register result = locs.out().reg();
367 Label load_true; 371 Label load_true;
(...skipping 30 matching lines...) Expand all
398 } 402 }
399 __ jmp(&done); 403 __ jmp(&done);
400 __ Bind(&next_test); 404 __ Bind(&next_test);
401 } 405 }
402 // Fall through leads to deoptimization 406 // Fall through leads to deoptimization
403 __ jmp(deopt); 407 __ jmp(deopt);
404 __ Bind(&done); 408 __ Bind(&done);
405 } 409 }
406 410
407 411
412 // Emit code when ICData's targets are all Object == (which is ===).
413 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
414 const ICData& ic_data,
415 const LocationSummary& locs,
416 Token::Kind kind,
417 BranchInstr* branch,
418 intptr_t deopt_id,
419 intptr_t token_pos,
420 intptr_t try_index) {
421 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
422 Register left = locs.in(0).reg();
423 Register right = locs.in(1).reg();
424 Register temp = locs.temp(0).reg();
425 Label* deopt = compiler->AddDeoptStub(deopt_id,
426 try_index,
427 kDeoptEquality,
428 left,
429 right);
430 __ testq(left, Immediate(kSmiTagMask));
431 __ j(ZERO, deopt);
432 __ LoadClassId(temp, left);
433 Label done;
434 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
435 __ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
436 if (i == (ic_data.NumberOfChecks() - 1)) {
437 __ j(NOT_EQUAL, deopt);
438 } else {
439 __ j(EQUAL, &done);
440 }
441 }
442 __ Bind(&done);
443 __ cmpq(left, right);
444 if (branch == NULL) {
445 Label done, is_equal;
446 Register result = locs.out().reg();
447 __ j(EQUAL, &is_equal, Assembler::kNearJump);
448 // Not equal.
449 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_false()
450 : compiler->bool_true());
451 __ jmp(&done, Assembler::kNearJump);
452 __ Bind(&is_equal);
453 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_true()
454 : compiler->bool_false());
455 __ Bind(&done);
456 } else {
457 Condition cond = TokenKindToSmiCondition(kind);
458 branch->EmitBranchOnCondition(compiler, cond);
459 }
460 }
461
462
408 // First test if receiver is NULL, in which case === is applied. 463 // First test if receiver is NULL, in which case === is applied.
409 // If type feedback was provided (lists of <class-id, target>), do a 464 // If type feedback was provided (lists of <class-id, target>), do a
410 // type by type check (either === or static call to the operator. 465 // type by type check (either === or static call to the operator.
411 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, 466 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
412 const LocationSummary& locs, 467 const LocationSummary& locs,
413 Token::Kind kind, 468 Token::Kind kind,
414 BranchInstr* branch, 469 BranchInstr* branch,
415 const ICData& ic_data, 470 const ICData& ic_data,
416 intptr_t deopt_id, 471 intptr_t deopt_id,
417 intptr_t token_pos, 472 intptr_t token_pos,
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 if (receiver_class_id() == kSmiCid) { 603 if (receiver_class_id() == kSmiCid) {
549 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. 604 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch.
550 deopt_id(), token_pos(), try_index()); 605 deopt_id(), token_pos(), try_index());
551 return; 606 return;
552 } 607 }
553 if (receiver_class_id() == kDoubleCid) { 608 if (receiver_class_id() == kDoubleCid) {
554 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. 609 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch.
555 deopt_id(), token_pos(), try_index()); 610 deopt_id(), token_pos(), try_index());
556 return; 611 return;
557 } 612 }
613 const bool is_checked_strict_equal =
614 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
615 if (is_checked_strict_equal) {
616 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL,
617 deopt_id(), token_pos(), try_index());
618 return;
619 }
558 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 620 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
559 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(), 621 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(),
560 deopt_id(), token_pos(), try_index()); 622 deopt_id(), token_pos(), try_index());
561 } else { 623 } else {
562 Register left = locs()->in(0).reg(); 624 Register left = locs()->in(0).reg();
563 Register right = locs()->in(1).reg(); 625 Register right = locs()->in(1).reg();
564 __ pushq(left); 626 __ pushq(left);
565 __ pushq(right); 627 __ pushq(right);
566 EmitEqualityAsInstanceCall(compiler, this); 628 EmitEqualityAsInstanceCall(compiler, this);
567 } 629 }
568 } 630 }
569 631
570 632
571 LocationSummary* RelationalOpComp::MakeLocationSummary() const { 633 LocationSummary* RelationalOpComp::MakeLocationSummary() const {
572 if (operands_class_id() == kSmiCid || operands_class_id() == kDoubleCid) { 634 if (operands_class_id() == kSmiCid || operands_class_id() == kDoubleCid) {
573 const intptr_t kNumInputs = 2; 635 const intptr_t kNumInputs = 2;
574 const intptr_t kNumTemps = 1; 636 const intptr_t kNumTemps = 1;
575 LocationSummary* summary = 637 LocationSummary* summary =
576 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 638 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
577 summary->set_in(0, Location::RequiresRegister()); 639 summary->set_in(0, Location::RequiresRegister());
578 summary->set_in(1, Location::RequiresRegister()); 640 summary->set_in(1, Location::RequiresRegister());
579 summary->set_out(Location::RequiresRegister()); 641 summary->set_out(Location::RequiresRegister());
580 summary->set_temp(0, Location::RequiresRegister()); 642 summary->set_temp(0, Location::RequiresRegister());
581 return summary; 643 return summary;
582 } 644 }
583 ASSERT(operands_class_id() == kObjectCid);
584 return MakeCallSummary(); 645 return MakeCallSummary();
585 } 646 }
586 647
587 648
588 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { 649 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
589 if (operands_class_id() == kSmiCid) { 650 if (operands_class_id() == kSmiCid) {
590 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, 651 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL,
591 deopt_id(), token_pos(), try_index()); 652 deopt_id(), token_pos(), try_index());
592 return; 653 return;
593 } 654 }
(...skipping 1406 matching lines...) Expand 10 before | Expand all | Expand 10 after
2000 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { 2061 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) {
2001 if (ic_data.num_args_tested() != 2) return false; 2062 if (ic_data.num_args_tested() != 2) return false;
2002 if (ic_data.NumberOfChecks() != 1) return false; 2063 if (ic_data.NumberOfChecks() != 1) return false;
2003 Function& target = Function::Handle(); 2064 Function& target = Function::Handle();
2004 GrowableArray<intptr_t> class_ids; 2065 GrowableArray<intptr_t> class_ids;
2005 ic_data.GetCheckAt(0, &class_ids, &target); 2066 ic_data.GetCheckAt(0, &class_ids, &target);
2006 return (class_ids[0] == class_id) && (class_ids[1] == class_id); 2067 return (class_ids[0] == class_id) && (class_ids[1] == class_id);
2007 } 2068 }
2008 2069
2009 2070
2071 static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) {
2072 if ((kind == Token::kEQ) || (kind == Token::kNE)) {
2073 return ic_data.AllTargetsHaveSameOwner(kInstanceCid);
2074 }
2075 return false;
2076 }
2077
2078
2010 LocationSummary* BranchInstr::MakeLocationSummary() const { 2079 LocationSummary* BranchInstr::MakeLocationSummary() const {
2011 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) { 2080 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) {
2012 const int kNumInputs = 2; 2081 const int kNumInputs = 2;
2013 const int kNumTemps = 0; 2082 const int kNumTemps = 0;
2014 LocationSummary* locs = 2083 LocationSummary* locs =
2015 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 2084 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
2016 locs->set_in(0, Location::RequiresRegister()); 2085 locs->set_in(0, Location::RequiresRegister());
2017 locs->set_in(1, Location::RequiresRegister()); 2086 locs->set_in(1, Location::RequiresRegister());
2018 return locs; 2087 return locs;
2019 } 2088 }
2020 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 2089 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
2021 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) || 2090 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) ||
2022 ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { 2091 ICDataWithBothClassIds(*ic_data(), kDoubleCid) ||
2092 IsCheckedStrictEquals(*ic_data(), kind())) {
2023 const intptr_t kNumInputs = 2; 2093 const intptr_t kNumInputs = 2;
2024 const intptr_t kNumTemps = 1; 2094 const intptr_t kNumTemps = 1;
2025 LocationSummary* summary = 2095 LocationSummary* summary =
2026 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 2096 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
2027 summary->set_in(0, Location::RequiresRegister()); 2097 summary->set_in(0, Location::RequiresRegister());
2028 summary->set_in(1, Location::RequiresRegister()); 2098 summary->set_in(1, Location::RequiresRegister());
2029 summary->set_temp(0, Location::RequiresRegister()); 2099 summary->set_temp(0, Location::RequiresRegister());
2030 return summary; 2100 return summary;
2031 } 2101 }
2032 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { 2102 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2066 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) { 2136 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) {
2067 EmitSmiComparisonOp(compiler, *locs(), kind(), this, 2137 EmitSmiComparisonOp(compiler, *locs(), kind(), this,
2068 deopt_id(), token_pos(), try_index()); 2138 deopt_id(), token_pos(), try_index());
2069 return; 2139 return;
2070 } 2140 }
2071 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { 2141 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) {
2072 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, 2142 EmitDoubleComparisonOp(compiler, *locs(), kind(), this,
2073 deopt_id(), token_pos(), try_index()); 2143 deopt_id(), token_pos(), try_index());
2074 return; 2144 return;
2075 } 2145 }
2146 if (IsCheckedStrictEquals(*ic_data(), kind())) {
2147 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this,
2148 deopt_id(), token_pos(), try_index());
2149 return;
2150 }
2076 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. 2151 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons.
2077 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { 2152 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
2078 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), 2153 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(),
2079 deopt_id(), token_pos(), try_index()); 2154 deopt_id(), token_pos(), try_index());
2080 return; 2155 return;
2081 } 2156 }
2082 // Otherwise polymorphic dispatch? 2157 // Otherwise polymorphic dispatch?
2083 } 2158 }
2084 Register left = locs()->in(0).reg(); 2159 Register left = locs()->in(0).reg();
2085 Register right = locs()->in(1).reg(); 2160 Register right = locs()->in(1).reg();
(...skipping 19 matching lines...) Expand all
2105 kNumArgsChecked); 2180 kNumArgsChecked);
2106 __ CompareObject(RAX, compiler->bool_true()); 2181 __ CompareObject(RAX, compiler->bool_true());
2107 EmitBranchOnCondition(compiler, branch_condition); 2182 EmitBranchOnCondition(compiler, branch_condition);
2108 } 2183 }
2109 2184
2110 } // namespace dart 2185 } // namespace dart
2111 2186
2112 #undef __ 2187 #undef __
2113 2188
2114 #endif // defined TARGET_ARCH_X64 2189 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698