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

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

Issue 27307005: Change == into an instance call to allow polymorphic inlining of ==. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: rebased, addressed comments Created 7 years, 1 month 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
« no previous file with comments | « runtime/vm/intermediate_language_arm.cc ('k') | runtime/vm/intermediate_language_mips.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_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 "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 locs->set_in(0, Location::RegisterOrConstant(left())); 257 locs->set_in(0, Location::RegisterOrConstant(left()));
258 // Only one input can be a constant operand. The case of two constant 258 // Only one input can be a constant operand. The case of two constant
259 // operands should be handled by constant propagation. 259 // operands should be handled by constant propagation.
260 // Only right can be a stack slot. 260 // Only right can be a stack slot.
261 locs->set_in(1, locs->in(0).IsConstant() 261 locs->set_in(1, locs->in(0).IsConstant()
262 ? Location::RequiresRegister() 262 ? Location::RequiresRegister()
263 : Location::RegisterOrConstant(right())); 263 : Location::RegisterOrConstant(right()));
264 locs->set_out(Location::RequiresRegister()); 264 locs->set_out(Location::RequiresRegister());
265 return locs; 265 return locs;
266 } 266 }
267 if (IsCheckedStrictEqual()) { 267 UNREACHABLE();
268 const intptr_t kNumTemps = 1; 268 return NULL;
269 LocationSummary* locs =
270 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
271 locs->set_in(0, Location::RequiresRegister());
272 locs->set_in(1, Location::RequiresRegister());
273 locs->set_temp(0, Location::RequiresRegister());
274 locs->set_out(Location::RequiresRegister());
275 return locs;
276 }
277 if (IsPolymorphic()) {
278 const intptr_t kNumTemps = 1;
279 LocationSummary* locs =
280 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
281 locs->set_in(0, Location::RegisterLocation(ECX));
282 locs->set_in(1, Location::RegisterLocation(EDX));
283 locs->set_temp(0, Location::RegisterLocation(EBX));
284 locs->set_out(Location::RegisterLocation(EAX));
285 return locs;
286 }
287 const intptr_t kNumTemps = 1;
288 LocationSummary* locs =
289 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
290 locs->set_in(0, Location::RegisterLocation(EBX));
291 locs->set_in(1, Location::RegisterLocation(EDX));
292 locs->set_temp(0, Location::RegisterLocation(ECX));
293 locs->set_out(Location::RegisterLocation(EAX));
294 return locs;
295 }
296
297
298 static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
299 intptr_t deopt_id,
300 intptr_t token_pos,
301 Token::Kind kind,
302 LocationSummary* locs,
303 const ICData& original_ic_data) {
304 if (!compiler->is_optimizing()) {
305 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt,
306 deopt_id,
307 token_pos);
308 }
309 const int kNumberOfArguments = 2;
310 const Array& kNoArgumentNames = Object::null_array();
311 const int kNumArgumentsChecked = 2;
312
313 ICData& equality_ic_data = ICData::ZoneHandle();
314 if (compiler->is_optimizing() && FLAG_propagate_ic_data) {
315 ASSERT(!original_ic_data.IsNull());
316 if (original_ic_data.NumberOfChecks() == 0) {
317 // IC call for reoptimization populates original ICData.
318 equality_ic_data = original_ic_data.raw();
319 } else {
320 // Megamorphic call.
321 equality_ic_data = original_ic_data.AsUnaryClassChecks();
322 }
323 } else {
324 const Array& arguments_descriptor =
325 Array::Handle(ArgumentsDescriptor::New(kNumberOfArguments,
326 kNoArgumentNames));
327 equality_ic_data = ICData::New(compiler->parsed_function().function(),
328 Symbols::EqualOperator(),
329 arguments_descriptor,
330 deopt_id,
331 kNumArgumentsChecked);
332 }
333 compiler->GenerateInstanceCall(deopt_id,
334 token_pos,
335 kNumberOfArguments,
336 kNoArgumentNames,
337 locs,
338 equality_ic_data);
339 if (kind == Token::kNE) {
340 Label true_label, done;
341 // Negate the condition: true label returns false and vice versa.
342 __ CompareObject(EAX, Bool::True());
343 __ j(EQUAL, &true_label, Assembler::kNearJump);
344 __ LoadObject(EAX, Bool::True());
345 __ jmp(&done, Assembler::kNearJump);
346 __ Bind(&true_label);
347 __ LoadObject(EAX, Bool::False());
348 __ Bind(&done);
349 }
350 } 269 }
351 270
352 271
353 static void LoadValueCid(FlowGraphCompiler* compiler, 272 static void LoadValueCid(FlowGraphCompiler* compiler,
354 Register value_cid_reg, 273 Register value_cid_reg,
355 Register value_reg, 274 Register value_reg,
356 Label* value_is_smi = NULL) { 275 Label* value_is_smi = NULL) {
357 Label done; 276 Label done;
358 if (value_is_smi == NULL) { 277 if (value_is_smi == NULL) {
359 __ movl(value_cid_reg, Immediate(kSmiCid)); 278 __ movl(value_cid_reg, Immediate(kSmiCid));
360 } 279 }
361 __ testl(value_reg, Immediate(kSmiTagMask)); 280 __ testl(value_reg, Immediate(kSmiTagMask));
362 if (value_is_smi == NULL) { 281 if (value_is_smi == NULL) {
363 __ j(ZERO, &done, Assembler::kNearJump); 282 __ j(ZERO, &done, Assembler::kNearJump);
364 } else { 283 } else {
365 __ j(ZERO, value_is_smi); 284 __ j(ZERO, value_is_smi);
366 } 285 }
367 __ LoadClassId(value_cid_reg, value_reg); 286 __ LoadClassId(value_cid_reg, value_reg);
368 __ Bind(&done); 287 __ Bind(&done);
369 } 288 }
370 289
371 290
372 static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
373 const ICData& orig_ic_data,
374 LocationSummary* locs,
375 BranchInstr* branch,
376 Token::Kind kind,
377 intptr_t deopt_id,
378 intptr_t token_pos) {
379 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
380 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
381 ASSERT(ic_data.NumberOfChecks() > 0);
382 ASSERT(ic_data.num_args_tested() == 1);
383 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
384 Register left = locs->in(0).reg();
385 Register right = locs->in(1).reg();
386 Register temp = locs->temp(0).reg();
387 LoadValueCid(compiler, temp, left,
388 (ic_data.GetReceiverClassIdAt(0) == kSmiCid) ? NULL : deopt);
389 // 'temp' contains class-id of the left argument.
390 ObjectStore* object_store = Isolate::Current()->object_store();
391 Condition cond = TokenKindToSmiCondition(kind);
392 Label done;
393 const intptr_t len = ic_data.NumberOfChecks();
394 for (intptr_t i = 0; i < len; i++) {
395 // Assert that the Smi is at position 0, if at all.
396 ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
397 Label next_test;
398 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
399 if (i < len - 1) {
400 __ j(NOT_EQUAL, &next_test);
401 } else {
402 __ j(NOT_EQUAL, deopt);
403 }
404 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
405 if (target.Owner() == object_store->object_class()) {
406 // Object.== is same as ===.
407 __ Drop(2);
408 __ cmpl(left, right);
409 if (branch != NULL) {
410 branch->EmitBranchOnCondition(compiler, cond);
411 } else {
412 Register result = locs->out().reg();
413 Label load_true;
414 __ j(cond, &load_true, Assembler::kNearJump);
415 __ LoadObject(result, Bool::False());
416 __ jmp(&done);
417 __ Bind(&load_true);
418 __ LoadObject(result, Bool::True());
419 }
420 } else {
421 const int kNumberOfArguments = 2;
422 const Array& kNoArgumentNames = Object::null_array();
423 compiler->GenerateStaticCall(deopt_id,
424 token_pos,
425 target,
426 kNumberOfArguments,
427 kNoArgumentNames,
428 locs);
429 if (branch == NULL) {
430 if (kind == Token::kNE) {
431 Label false_label;
432 __ CompareObject(EAX, Bool::True());
433 __ j(EQUAL, &false_label, Assembler::kNearJump);
434 __ LoadObject(EAX, Bool::True());
435 __ jmp(&done);
436 __ Bind(&false_label);
437 __ LoadObject(EAX, Bool::False());
438 }
439 } else {
440 if (branch->is_checked()) {
441 EmitAssertBoolean(EAX, token_pos, deopt_id, locs, compiler);
442 }
443 __ CompareObject(EAX, Bool::True());
444 branch->EmitBranchOnCondition(compiler, cond);
445 }
446 }
447 if (i < len - 1) {
448 __ jmp(&done);
449 __ Bind(&next_test);
450 }
451 }
452 __ Bind(&done);
453 }
454
455
456 // Emit code when ICData's targets are all Object == (which is ===).
457 static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
458 const ICData& orig_ic_data,
459 const LocationSummary& locs,
460 Token::Kind kind,
461 BranchInstr* branch,
462 intptr_t deopt_id) {
463 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
464 Register left = locs.in(0).reg();
465 Register right = locs.in(1).reg();
466 Register temp = locs.temp(0).reg();
467 Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
468 __ testl(left, Immediate(kSmiTagMask));
469 __ j(ZERO, deopt);
470 // 'left' is not Smi.
471 const Immediate& raw_null =
472 Immediate(reinterpret_cast<intptr_t>(Object::null()));
473 Label identity_compare;
474 __ cmpl(right, raw_null);
475 __ j(EQUAL, &identity_compare);
476 __ cmpl(left, raw_null);
477 __ j(EQUAL, &identity_compare);
478
479 __ LoadClassId(temp, left);
480 const ICData& ic_data = ICData::Handle(orig_ic_data.AsUnaryClassChecks());
481 const intptr_t len = ic_data.NumberOfChecks();
482 for (intptr_t i = 0; i < len; i++) {
483 __ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
484 if (i == (len - 1)) {
485 __ j(NOT_EQUAL, deopt);
486 } else {
487 __ j(EQUAL, &identity_compare);
488 }
489 }
490 __ Bind(&identity_compare);
491 __ cmpl(left, right);
492 if (branch == NULL) {
493 Label done, is_equal;
494 Register result = locs.out().reg();
495 __ j(EQUAL, &is_equal, Assembler::kNearJump);
496 // Not equal.
497 __ LoadObject(result, Bool::Get(kind != Token::kEQ));
498 __ jmp(&done, Assembler::kNearJump);
499 __ Bind(&is_equal);
500 __ LoadObject(result, Bool::Get(kind == Token::kEQ));
501 __ Bind(&done);
502 } else {
503 Condition cond = TokenKindToSmiCondition(kind);
504 branch->EmitBranchOnCondition(compiler, cond);
505 }
506 }
507
508
509 // First test if receiver is NULL, in which case === is applied.
510 // If type feedback was provided (lists of <class-id, target>), do a
511 // type by type check (either === or static call to the operator.
512 static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
513 LocationSummary* locs,
514 Token::Kind kind,
515 BranchInstr* branch,
516 const ICData& ic_data,
517 intptr_t deopt_id,
518 intptr_t token_pos) {
519 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
520 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0));
521 Register left = locs->in(0).reg();
522 Register right = locs->in(1).reg();
523 __ pushl(left);
524 __ pushl(right);
525 EmitEqualityAsPolymorphicCall(compiler, ic_data, locs, branch, kind,
526 deopt_id, token_pos);
527 }
528
529
530 static Condition FlipCondition(Condition condition) { 291 static Condition FlipCondition(Condition condition) {
531 switch (condition) { 292 switch (condition) {
532 case EQUAL: return EQUAL; 293 case EQUAL: return EQUAL;
533 case NOT_EQUAL: return NOT_EQUAL; 294 case NOT_EQUAL: return NOT_EQUAL;
534 case LESS: return GREATER; 295 case LESS: return GREATER;
535 case LESS_EQUAL: return GREATER_EQUAL; 296 case LESS_EQUAL: return GREATER_EQUAL;
536 case GREATER: return LESS; 297 case GREATER: return LESS;
537 case GREATER_EQUAL: return LESS_EQUAL; 298 case GREATER_EQUAL: return LESS_EQUAL;
538 case BELOW: return ABOVE; 299 case BELOW: return ABOVE;
539 case BELOW_EQUAL: return ABOVE_EQUAL; 300 case BELOW_EQUAL: return ABOVE_EQUAL;
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
759 return; 520 return;
760 } 521 }
761 if (operation_cid() == kMintCid) { 522 if (operation_cid() == kMintCid) {
762 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch); 523 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), kNoBranch);
763 return; 524 return;
764 } 525 }
765 if (operation_cid() == kDoubleCid) { 526 if (operation_cid() == kDoubleCid) {
766 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch); 527 EmitDoubleComparisonOp(compiler, *locs(), kind(), kNoBranch);
767 return; 528 return;
768 } 529 }
769 if (IsCheckedStrictEqual()) { 530 UNREACHABLE();
770 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), kNoBranch,
771 deopt_id());
772 return;
773 }
774 if (IsPolymorphic()) {
775 EmitGenericEqualityCompare(compiler, locs(), kind(), kNoBranch, *ic_data(),
776 deopt_id(), token_pos());
777 return;
778 }
779 Register left = locs()->in(0).reg();
780 Register right = locs()->in(1).reg();
781 __ pushl(left);
782 __ pushl(right);
783 EmitEqualityAsInstanceCall(compiler,
784 deopt_id(),
785 token_pos(),
786 kind(),
787 locs(),
788 *ic_data());
789 ASSERT(locs()->out().reg() == EAX);
790 } 531 }
791 532
792 533
793 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler, 534 void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
794 BranchInstr* branch) { 535 BranchInstr* branch) {
795 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ)); 536 ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
796 if (operation_cid() == kSmiCid) { 537 if (operation_cid() == kSmiCid) {
797 // Deoptimizes if both arguments not Smi. 538 // Deoptimizes if both arguments not Smi.
798 EmitSmiComparisonOp(compiler, *locs(), kind(), branch); 539 EmitSmiComparisonOp(compiler, *locs(), kind(), branch);
799 return; 540 return;
800 } 541 }
801 if (operation_cid() == kMintCid) { 542 if (operation_cid() == kMintCid) {
802 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch); 543 EmitUnboxedMintEqualityOp(compiler, *locs(), kind(), branch);
803 return; 544 return;
804 } 545 }
805 if (operation_cid() == kDoubleCid) { 546 if (operation_cid() == kDoubleCid) {
806 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch); 547 EmitDoubleComparisonOp(compiler, *locs(), kind(), branch);
807 return; 548 return;
808 } 549 }
809 if (IsCheckedStrictEqual()) { 550 UNREACHABLE();
810 EmitCheckedStrictEqual(compiler, *ic_data(), *locs(), kind(), branch,
811 deopt_id());
812 return;
813 }
814 if (IsPolymorphic()) {
815 EmitGenericEqualityCompare(compiler, locs(), kind(), branch, *ic_data(),
816 deopt_id(), token_pos());
817 return;
818 }
819 Register left = locs()->in(0).reg();
820 Register right = locs()->in(1).reg();
821 __ pushl(left);
822 __ pushl(right);
823 EmitEqualityAsInstanceCall(compiler,
824 deopt_id(),
825 token_pos(),
826 Token::kEQ, // kNE reverse occurs at branch.
827 locs(),
828 *ic_data());
829 if (branch->is_checked()) {
830 EmitAssertBoolean(EAX, token_pos(), deopt_id(), locs(), compiler);
831 }
832 Condition branch_condition = (kind() == Token::kNE) ? NOT_EQUAL : EQUAL;
833 __ CompareObject(EAX, Bool::True());
834 branch->EmitBranchOnCondition(compiler, branch_condition);
835 } 551 }
836 552
837 553
838 LocationSummary* RelationalOpInstr::MakeLocationSummary() const { 554 LocationSummary* RelationalOpInstr::MakeLocationSummary() const {
839 const intptr_t kNumInputs = 2; 555 const intptr_t kNumInputs = 2;
840 const intptr_t kNumTemps = 0; 556 const intptr_t kNumTemps = 0;
841 if (operation_cid() == kMintCid) { 557 if (operation_cid() == kMintCid) {
842 const intptr_t kNumTemps = 2; 558 const intptr_t kNumTemps = 2;
843 LocationSummary* locs = 559 LocationSummary* locs =
844 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); 560 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
(...skipping 4329 matching lines...) Expand 10 before | Expand all | Expand 10 after
5174 PcDescriptors::kOther, 4890 PcDescriptors::kOther,
5175 locs()); 4891 locs());
5176 __ Drop(2); // Discard type arguments and receiver. 4892 __ Drop(2); // Discard type arguments and receiver.
5177 } 4893 }
5178 4894
5179 } // namespace dart 4895 } // namespace dart
5180 4896
5181 #undef __ 4897 #undef __
5182 4898
5183 #endif // defined TARGET_ARCH_IA32 4899 #endif // defined TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language_arm.cc ('k') | runtime/vm/intermediate_language_mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698