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

Side by Side Diff: runtime/vm/intermediate_language_ia32.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_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"
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 case Token::kGTE: return GREATER_EQUAL; 237 case Token::kGTE: return GREATER_EQUAL;
238 default: 238 default:
239 UNREACHABLE(); 239 UNREACHABLE();
240 return OVERFLOW; 240 return OVERFLOW;
241 } 241 }
242 } 242 }
243 243
244 244
245 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { 245 LocationSummary* EqualityCompareComp::MakeLocationSummary() const {
246 const intptr_t kNumInputs = 2; 246 const intptr_t kNumInputs = 2;
247 if (receiver_class_id() != kObjectCid) { 247 const bool is_checked_strict_equal =
248 ASSERT((receiver_class_id() == kSmiCid) || 248 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
249 (receiver_class_id() == kDoubleCid)); 249 if ((receiver_class_id() == kSmiCid) ||
250 (receiver_class_id() == kDoubleCid) ||
251 is_checked_strict_equal) {
250 const intptr_t kNumTemps = 1; 252 const intptr_t kNumTemps = 1;
251 LocationSummary* locs = 253 LocationSummary* locs =
252 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 254 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
253 locs->set_in(0, Location::RequiresRegister()); 255 locs->set_in(0, Location::RequiresRegister());
254 locs->set_in(1, Location::RequiresRegister()); 256 locs->set_in(1, Location::RequiresRegister());
255 locs->set_temp(0, Location::RequiresRegister()); 257 locs->set_temp(0, Location::RequiresRegister());
256 locs->set_out(Location::RequiresRegister()); 258 locs->set_out(Location::RequiresRegister());
257 return locs; 259 return locs;
258 } 260 }
259 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 261 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump); 332 __ j(NOT_ZERO, &load_class_id, Assembler::kNearJump);
331 __ movl(temp, Immediate(kSmiCid)); 333 __ movl(temp, Immediate(kSmiCid));
332 __ jmp(&done, Assembler::kNearJump); 334 __ jmp(&done, Assembler::kNearJump);
333 __ Bind(&load_class_id); 335 __ Bind(&load_class_id);
334 __ LoadClassId(temp, left); 336 __ LoadClassId(temp, left);
335 __ Bind(&done); 337 __ Bind(&done);
336 } else { 338 } else {
337 __ j(ZERO, deopt); // Smi deopts. 339 __ j(ZERO, deopt); // Smi deopts.
338 __ LoadClassId(temp, left); 340 __ LoadClassId(temp, left);
339 } 341 }
342 // 'temp' contains class-id of the left argument.
343 ObjectStore* object_store = Isolate::Current()->object_store();
340 Condition cond = TokenKindToSmiCondition(kind); 344 Condition cond = TokenKindToSmiCondition(kind);
341 Label done; 345 Label done;
342 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { 346 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
347 // Assert that the Smi is at position 0, if at all.
343 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0)); 348 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
344 Label next_test; 349 Label next_test;
345 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i))); 350 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
346 __ j(NOT_EQUAL, &next_test); 351 __ j(NOT_EQUAL, &next_test);
347 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); 352 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
348 ObjectStore* object_store = Isolate::Current()->object_store();
349 if (target.owner() == object_store->object_class()) { 353 if (target.owner() == object_store->object_class()) {
350 // Object.== is same as ===. 354 // Object.== is same as ===.
351 __ Drop(2); 355 __ Drop(2);
352 __ cmpl(left, right); 356 __ cmpl(left, right);
353 if (branch != NULL) { 357 if (branch != NULL) {
354 branch->EmitBranchOnCondition(compiler, cond); 358 branch->EmitBranchOnCondition(compiler, cond);
355 } else { 359 } else {
356 // This case should be rare.
357 Register result = locs.out().reg(); 360 Register result = locs.out().reg();
358 Label load_true; 361 Label load_true;
359 __ j(cond, &load_true, Assembler::kNearJump); 362 __ j(cond, &load_true, Assembler::kNearJump);
360 __ LoadObject(result, compiler->bool_false()); 363 __ LoadObject(result, compiler->bool_false());
361 __ jmp(&done); 364 __ jmp(&done);
362 __ Bind(&load_true); 365 __ Bind(&load_true);
363 __ LoadObject(result, compiler->bool_true()); 366 __ LoadObject(result, compiler->bool_true());
364 } 367 }
365 } else { 368 } else {
366 const int kNumberOfArguments = 2; 369 const int kNumberOfArguments = 2;
(...skipping 22 matching lines...) Expand all
389 } 392 }
390 __ jmp(&done); 393 __ jmp(&done);
391 __ Bind(&next_test); 394 __ Bind(&next_test);
392 } 395 }
393 // Fall through leads to deoptimization 396 // Fall through leads to deoptimization
394 __ jmp(deopt); 397 __ jmp(deopt);
395 __ Bind(&done); 398 __ Bind(&done);
396 } 399 }
397 400
398 401
402 // Emit code when ICData's targets are all Object == (which is ===).
403 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
404 const ICData& ic_data,
405 const LocationSummary& locs,
406 Token::Kind kind,
407 BranchInstr* branch,
408 intptr_t deopt_id,
409 intptr_t token_pos,
410 intptr_t try_index) {
411 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
412 Register left = locs.in(0).reg();
413 Register right = locs.in(1).reg();
414 Register temp = locs.temp(0).reg();
415 Label* deopt = compiler->AddDeoptStub(deopt_id,
416 try_index,
417 kDeoptEquality,
418 left,
419 right);
420 __ testl(left, Immediate(kSmiTagMask));
421 __ j(ZERO, deopt);
422 __ LoadClassId(temp, left);
423 Label done;
424 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
425 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
426 if (i == (ic_data.NumberOfChecks() - 1)) {
427 __ j(NOT_EQUAL, deopt);
428 } else {
429 __ j(EQUAL, &done);
430 }
431 }
432 __ Bind(&done);
433 __ cmpl(left, right);
434 if (branch == NULL) {
435 Label done, is_equal;
436 Register result = locs.out().reg();
437 __ j(EQUAL, &is_equal, Assembler::kNearJump);
438 // Not equal.
439 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_false()
440 : compiler->bool_true());
441 __ jmp(&done, Assembler::kNearJump);
442 __ Bind(&is_equal);
443 __ LoadObject(result, (kind == Token::kEQ) ? compiler->bool_true()
444 : compiler->bool_false());
445 __ Bind(&done);
446 } else {
447 Condition cond = TokenKindToSmiCondition(kind);
448 branch->EmitBranchOnCondition(compiler, cond);
449 }
450 }
451
452
399 // First test if receiver is NULL, in which case === is applied. 453 // First test if receiver is NULL, in which case === is applied.
400 // If type feedback was provided (lists of <class-id, target>), do a 454 // If type feedback was provided (lists of <class-id, target>), do a
401 // type by type check (either === or static call to the operator. 455 // type by type check (either === or static call to the operator.
402 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler, 456 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
403 const LocationSummary& locs, 457 const LocationSummary& locs,
404 Token::Kind kind, 458 Token::Kind kind,
405 BranchInstr* branch, 459 BranchInstr* branch,
406 const ICData& ic_data, 460 const ICData& ic_data,
407 intptr_t deopt_id, 461 intptr_t deopt_id,
408 intptr_t token_pos, 462 intptr_t token_pos,
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 if (receiver_class_id() == kSmiCid) { 593 if (receiver_class_id() == kSmiCid) {
540 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch. 594 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, // No branch.
541 deopt_id(), token_pos(), try_index()); 595 deopt_id(), token_pos(), try_index());
542 return; 596 return;
543 } 597 }
544 if (receiver_class_id() == kDoubleCid) { 598 if (receiver_class_id() == kDoubleCid) {
545 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch. 599 EmitDoubleComparisonOp(compiler, *locs(), kind(), NULL, // No branch.
546 deopt_id(), token_pos(), try_index()); 600 deopt_id(), token_pos(), try_index());
547 return; 601 return;
548 } 602 }
603 const bool is_checked_strict_equal =
604 HasICData() && ic_data()->AllTargetsHaveSameOwner(kInstanceCid);
605 if (is_checked_strict_equal) {
606 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), NULL,
607 deopt_id(), token_pos(), try_index());
608 return;
609 }
549 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 610 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
550 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(), 611 EmitGenericEqualityCompare(compiler, *locs(), kind(), NULL, *ic_data(),
551 deopt_id(), token_pos(), try_index()); 612 deopt_id(), token_pos(), try_index());
552 } else { 613 } else {
553 Register left = locs()->in(0).reg(); 614 Register left = locs()->in(0).reg();
554 Register right = locs()->in(1).reg(); 615 Register right = locs()->in(1).reg();
555 __ pushl(left); 616 __ pushl(left);
556 __ pushl(right); 617 __ pushl(right);
557 EmitEqualityAsInstanceCall(compiler, this); 618 EmitEqualityAsInstanceCall(compiler, this);
558 } 619 }
559 } 620 }
560 621
561 622
562 LocationSummary* RelationalOpComp::MakeLocationSummary() const { 623 LocationSummary* RelationalOpComp::MakeLocationSummary() const {
563 if ((operands_class_id() == kSmiCid) || (operands_class_id() == kDoubleCid)) { 624 if ((operands_class_id() == kSmiCid) || (operands_class_id() == kDoubleCid)) {
564 const intptr_t kNumInputs = 2; 625 const intptr_t kNumInputs = 2;
565 const intptr_t kNumTemps = 1; 626 const intptr_t kNumTemps = 1;
566 LocationSummary* summary = 627 LocationSummary* summary =
567 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 628 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
568 summary->set_in(0, Location::RequiresRegister()); 629 summary->set_in(0, Location::RequiresRegister());
569 summary->set_in(1, Location::RequiresRegister()); 630 summary->set_in(1, Location::RequiresRegister());
570 summary->set_out(Location::RequiresRegister()); 631 summary->set_out(Location::RequiresRegister());
571 summary->set_temp(0, Location::RequiresRegister()); 632 summary->set_temp(0, Location::RequiresRegister());
572 return summary; 633 return summary;
573 } 634 }
574 ASSERT(operands_class_id() == kObjectCid);
575 return MakeCallSummary(); 635 return MakeCallSummary();
576 } 636 }
577 637
578 638
579 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { 639 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) {
580 if (operands_class_id() == kSmiCid) { 640 if (operands_class_id() == kSmiCid) {
581 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL, 641 EmitSmiComparisonOp(compiler, *locs(), kind(), NULL,
582 deopt_id(), token_pos(), try_index()); 642 deopt_id(), token_pos(), try_index());
583 return; 643 return;
584 } 644 }
(...skipping 1408 matching lines...) Expand 10 before | Expand all | Expand 10 after
1993 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) { 2053 static bool ICDataWithBothClassIds(const ICData& ic_data, intptr_t class_id) {
1994 if (ic_data.num_args_tested() != 2) return false; 2054 if (ic_data.num_args_tested() != 2) return false;
1995 if (ic_data.NumberOfChecks() != 1) return false; 2055 if (ic_data.NumberOfChecks() != 1) return false;
1996 Function& target = Function::Handle(); 2056 Function& target = Function::Handle();
1997 GrowableArray<intptr_t> class_ids; 2057 GrowableArray<intptr_t> class_ids;
1998 ic_data.GetCheckAt(0, &class_ids, &target); 2058 ic_data.GetCheckAt(0, &class_ids, &target);
1999 return (class_ids[0] == class_id) && (class_ids[1] == class_id); 2059 return (class_ids[0] == class_id) && (class_ids[1] == class_id);
2000 } 2060 }
2001 2061
2002 2062
2063 static bool IsCheckedStrictEquals(const ICData& ic_data, Token::Kind kind) {
2064 if ((kind == Token::kEQ) || (kind == Token::kNE)) {
2065 return ic_data.AllTargetsHaveSameOwner(kInstanceCid);
2066 }
2067 return false;
2068 }
2069
2070
2003 LocationSummary* BranchInstr::MakeLocationSummary() const { 2071 LocationSummary* BranchInstr::MakeLocationSummary() const {
2004 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) { 2072 if ((kind() == Token::kEQ_STRICT) || (kind() == Token::kNE_STRICT)) {
2005 const int kNumInputs = 2; 2073 const int kNumInputs = 2;
2006 const int kNumTemps = 0; 2074 const int kNumTemps = 0;
2007 LocationSummary* locs = 2075 LocationSummary* locs =
2008 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 2076 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
2009 locs->set_in(0, Location::RequiresRegister()); 2077 locs->set_in(0, Location::RequiresRegister());
2010 locs->set_in(1, Location::RequiresRegister()); 2078 locs->set_in(1, Location::RequiresRegister());
2011 return locs; 2079 return locs;
2012 } 2080 }
2013 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) { 2081 if (HasICData() && (ic_data()->NumberOfChecks() > 0)) {
2014 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) || 2082 if (ICDataWithBothClassIds(*ic_data(), kSmiCid) ||
2015 ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { 2083 ICDataWithBothClassIds(*ic_data(), kDoubleCid) ||
2084 IsCheckedStrictEquals(*ic_data(), kind())) {
2016 const intptr_t kNumInputs = 2; 2085 const intptr_t kNumInputs = 2;
2017 const intptr_t kNumTemps = 1; 2086 const intptr_t kNumTemps = 1;
2018 LocationSummary* summary = 2087 LocationSummary* summary =
2019 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 2088 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
2020 summary->set_in(0, Location::RequiresRegister()); 2089 summary->set_in(0, Location::RequiresRegister());
2021 summary->set_in(1, Location::RequiresRegister()); 2090 summary->set_in(1, Location::RequiresRegister());
2022 summary->set_temp(0, Location::RequiresRegister()); 2091 summary->set_temp(0, Location::RequiresRegister());
2023 return summary; 2092 return summary;
2024 } 2093 }
2025 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { 2094 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2059 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) { 2128 if (ICDataWithBothClassIds(*ic_data(), kSmiCid)) {
2060 EmitSmiComparisonOp(compiler, *locs(), kind(), this, 2129 EmitSmiComparisonOp(compiler, *locs(), kind(), this,
2061 deopt_id(), token_pos(), try_index()); 2130 deopt_id(), token_pos(), try_index());
2062 return; 2131 return;
2063 } 2132 }
2064 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) { 2133 if (ICDataWithBothClassIds(*ic_data(), kDoubleCid)) {
2065 EmitDoubleComparisonOp(compiler, *locs(), kind(), this, 2134 EmitDoubleComparisonOp(compiler, *locs(), kind(), this,
2066 deopt_id(), token_pos(), try_index()); 2135 deopt_id(), token_pos(), try_index());
2067 return; 2136 return;
2068 } 2137 }
2138 if (IsCheckedStrictEquals(*ic_data(), kind())) {
2139 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), this,
2140 deopt_id(), token_pos(), try_index());
2141 return;
2142 }
2143
2069 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons. 2144 // TODO(srdjan): Add Smi/Double, Double/Smi comparisons.
2070 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) { 2145 if ((kind() == Token::kEQ) || (kind() == Token::kNE)) {
2071 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(), 2146 EmitGenericEqualityCompare(compiler, *locs(), kind(), this, *ic_data(),
2072 deopt_id(), token_pos(), try_index()); 2147 deopt_id(), token_pos(), try_index());
2073 return; 2148 return;
2074 } 2149 }
2075 // Otherwise polymorphic dispatch? 2150 // Otherwise polymorphic dispatch?
2076 } 2151 }
2077 Register left = locs()->in(0).reg(); 2152 Register left = locs()->in(0).reg();
2078 Register right = locs()->in(1).reg(); 2153 Register right = locs()->in(1).reg();
(...skipping 19 matching lines...) Expand all
2098 kNumArgsChecked); 2173 kNumArgsChecked);
2099 __ CompareObject(EAX, compiler->bool_true()); 2174 __ CompareObject(EAX, compiler->bool_true());
2100 EmitBranchOnCondition(compiler, branch_condition); 2175 EmitBranchOnCondition(compiler, branch_condition);
2101 } 2176 }
2102 2177
2103 } // namespace dart 2178 } // namespace dart
2104 2179
2105 #undef __ 2180 #undef __
2106 2181
2107 #endif // defined TARGET_ARCH_X64 2182 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698