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 4329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 |
OLD | NEW |