| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 4332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5177 PcDescriptors::kOther, | 4893 PcDescriptors::kOther, |
| 5178 locs()); | 4894 locs()); |
| 5179 __ Drop(2); // Discard type arguments and receiver. | 4895 __ Drop(2); // Discard type arguments and receiver. |
| 5180 } | 4896 } |
| 5181 | 4897 |
| 5182 } // namespace dart | 4898 } // namespace dart |
| 5183 | 4899 |
| 5184 #undef __ | 4900 #undef __ |
| 5185 | 4901 |
| 5186 #endif // defined TARGET_ARCH_IA32 | 4902 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |