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

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

Powered by Google App Engine
This is Rietveld 408576698