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

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

Powered by Google App Engine
This is Rietveld 408576698