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

Side by Side Diff: src/x64/code-stubs-x64.cc

Issue 6826032: Remove code from the deprecated GenericBinaryOpStub. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 8 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
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 // Return 1/0 for true/false in rax. 274 // Return 1/0 for true/false in rax.
275 __ bind(&true_result); 275 __ bind(&true_result);
276 __ movq(rax, Immediate(1)); 276 __ movq(rax, Immediate(1));
277 __ ret(1 * kPointerSize); 277 __ ret(1 * kPointerSize);
278 __ bind(&false_result); 278 __ bind(&false_result);
279 __ Set(rax, 0); 279 __ Set(rax, 0);
280 __ ret(1 * kPointerSize); 280 __ ret(1 * kPointerSize);
281 } 281 }
282 282
283 283
284 const char* GenericBinaryOpStub::GetName() {
285 if (name_ != NULL) return name_;
286 const int kMaxNameLength = 100;
287 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray(
288 kMaxNameLength);
289 if (name_ == NULL) return "OOM";
290 const char* op_name = Token::Name(op_);
291 const char* overwrite_name;
292 switch (mode_) {
293 case NO_OVERWRITE: overwrite_name = "Alloc"; break;
294 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
295 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
296 default: overwrite_name = "UnknownOverwrite"; break;
297 }
298
299 OS::SNPrintF(Vector<char>(name_, kMaxNameLength),
300 "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s",
301 op_name,
302 overwrite_name,
303 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "",
304 args_in_registers_ ? "RegArgs" : "StackArgs",
305 args_reversed_ ? "_R" : "",
306 static_operands_type_.ToString(),
307 BinaryOpIC::GetName(runtime_operands_type_));
308 return name_;
309 }
310
311
312 void GenericBinaryOpStub::GenerateCall(
313 MacroAssembler* masm,
314 Register left,
315 Register right) {
316 if (!ArgsInRegistersSupported()) {
317 // Pass arguments on the stack.
318 __ push(left);
319 __ push(right);
320 } else {
321 // The calling convention with registers is left in rdx and right in rax.
322 Register left_arg = rdx;
323 Register right_arg = rax;
324 if (!(left.is(left_arg) && right.is(right_arg))) {
325 if (left.is(right_arg) && right.is(left_arg)) {
326 if (IsOperationCommutative()) {
327 SetArgsReversed();
328 } else {
329 __ xchg(left, right);
330 }
331 } else if (left.is(left_arg)) {
332 __ movq(right_arg, right);
333 } else if (right.is(right_arg)) {
334 __ movq(left_arg, left);
335 } else if (left.is(right_arg)) {
336 if (IsOperationCommutative()) {
337 __ movq(left_arg, right);
338 SetArgsReversed();
339 } else {
340 // Order of moves important to avoid destroying left argument.
341 __ movq(left_arg, left);
342 __ movq(right_arg, right);
343 }
344 } else if (right.is(left_arg)) {
345 if (IsOperationCommutative()) {
346 __ movq(right_arg, left);
347 SetArgsReversed();
348 } else {
349 // Order of moves important to avoid destroying right argument.
350 __ movq(right_arg, right);
351 __ movq(left_arg, left);
352 }
353 } else {
354 // Order of moves is not important.
355 __ movq(left_arg, left);
356 __ movq(right_arg, right);
357 }
358 }
359
360 // Update flags to indicate that arguments are in registers.
361 SetArgsInRegisters();
362 Counters* counters = masm->isolate()->counters();
363 __ IncrementCounter(counters->generic_binary_stub_calls_regs(), 1);
364 }
365
366 // Call the stub.
367 __ CallStub(this);
368 }
369
370
371 void GenericBinaryOpStub::GenerateCall(
372 MacroAssembler* masm,
373 Register left,
374 Smi* right) {
375 if (!ArgsInRegistersSupported()) {
376 // Pass arguments on the stack.
377 __ push(left);
378 __ Push(right);
379 } else {
380 // The calling convention with registers is left in rdx and right in rax.
381 Register left_arg = rdx;
382 Register right_arg = rax;
383 if (left.is(left_arg)) {
384 __ Move(right_arg, right);
385 } else if (left.is(right_arg) && IsOperationCommutative()) {
386 __ Move(left_arg, right);
387 SetArgsReversed();
388 } else {
389 // For non-commutative operations, left and right_arg might be
390 // the same register. Therefore, the order of the moves is
391 // important here in order to not overwrite left before moving
392 // it to left_arg.
393 __ movq(left_arg, left);
394 __ Move(right_arg, right);
395 }
396
397 // Update flags to indicate that arguments are in registers.
398 SetArgsInRegisters();
399 Counters* counters = masm->isolate()->counters();
400 __ IncrementCounter(counters->generic_binary_stub_calls_regs(), 1);
401 }
402
403 // Call the stub.
404 __ CallStub(this);
405 }
406
407
408 void GenericBinaryOpStub::GenerateCall(
409 MacroAssembler* masm,
410 Smi* left,
411 Register right) {
412 if (!ArgsInRegistersSupported()) {
413 // Pass arguments on the stack.
414 __ Push(left);
415 __ push(right);
416 } else {
417 // The calling convention with registers is left in rdx and right in rax.
418 Register left_arg = rdx;
419 Register right_arg = rax;
420 if (right.is(right_arg)) {
421 __ Move(left_arg, left);
422 } else if (right.is(left_arg) && IsOperationCommutative()) {
423 __ Move(right_arg, left);
424 SetArgsReversed();
425 } else {
426 // For non-commutative operations, right and left_arg might be
427 // the same register. Therefore, the order of the moves is
428 // important here in order to not overwrite right before moving
429 // it to right_arg.
430 __ movq(right_arg, right);
431 __ Move(left_arg, left);
432 }
433 // Update flags to indicate that arguments are in registers.
434 SetArgsInRegisters();
435 Counters* counters = masm->isolate()->counters();
436 __ IncrementCounter(counters->generic_binary_stub_calls_regs(), 1);
437 }
438
439 // Call the stub.
440 __ CallStub(this);
441 }
442
443
444 class FloatingPointHelper : public AllStatic { 284 class FloatingPointHelper : public AllStatic {
445 public: 285 public:
446 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. 286 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles.
447 // If the operands are not both numbers, jump to not_numbers. 287 // If the operands are not both numbers, jump to not_numbers.
448 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. 288 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis.
449 // NumberOperands assumes both are smis or heap numbers. 289 // NumberOperands assumes both are smis or heap numbers.
450 static void LoadSSE2SmiOperands(MacroAssembler* masm); 290 static void LoadSSE2SmiOperands(MacroAssembler* masm);
451 static void LoadSSE2NumberOperands(MacroAssembler* masm); 291 static void LoadSSE2NumberOperands(MacroAssembler* masm);
452 static void LoadSSE2UnknownOperands(MacroAssembler* masm, 292 static void LoadSSE2UnknownOperands(MacroAssembler* masm,
453 Label* not_numbers); 293 Label* not_numbers);
454 294
455 // Takes the operands in rdx and rax and loads them as integers in rax 295 // Takes the operands in rdx and rax and loads them as integers in rax
456 // and rcx. 296 // and rcx.
457 static void LoadAsIntegers(MacroAssembler* masm, 297 static void LoadAsIntegers(MacroAssembler* masm,
458 Label* operand_conversion_failure, 298 Label* operand_conversion_failure,
459 Register heap_number_map); 299 Register heap_number_map);
460 // As above, but we know the operands to be numbers. In that case, 300 // As above, but we know the operands to be numbers. In that case,
461 // conversion can't fail. 301 // conversion can't fail.
462 static void LoadNumbersAsIntegers(MacroAssembler* masm); 302 static void LoadNumbersAsIntegers(MacroAssembler* masm);
463 }; 303 };
464 304
465 305
466 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) {
467 // 1. Move arguments into rdx, rax except for DIV and MOD, which need the
468 // dividend in rax and rdx free for the division. Use rax, rbx for those.
469 Comment load_comment(masm, "-- Load arguments");
470 Register left = rdx;
471 Register right = rax;
472 if (op_ == Token::DIV || op_ == Token::MOD) {
473 left = rax;
474 right = rbx;
475 if (HasArgsInRegisters()) {
476 __ movq(rbx, rax);
477 __ movq(rax, rdx);
478 }
479 }
480 if (!HasArgsInRegisters()) {
481 __ movq(right, Operand(rsp, 1 * kPointerSize));
482 __ movq(left, Operand(rsp, 2 * kPointerSize));
483 }
484
485 Label not_smis;
486 // 2. Smi check both operands.
487 if (static_operands_type_.IsSmi()) {
488 // Skip smi check if we know that both arguments are smis.
489 if (FLAG_debug_code) {
490 __ AbortIfNotSmi(left);
491 __ AbortIfNotSmi(right);
492 }
493 if (op_ == Token::BIT_OR) {
494 // Handle OR here, since we do extra smi-checking in the or code below.
495 __ SmiOr(right, right, left);
496 GenerateReturn(masm);
497 return;
498 }
499 } else {
500 if (op_ != Token::BIT_OR) {
501 // Skip the check for OR as it is better combined with the
502 // actual operation.
503 Comment smi_check_comment(masm, "-- Smi check arguments");
504 __ JumpIfNotBothSmi(left, right, &not_smis);
505 }
506 }
507
508 // 3. Operands are both smis (except for OR), perform the operation leaving
509 // the result in rax and check the result if necessary.
510 Comment perform_smi(masm, "-- Perform smi operation");
511 Label use_fp_on_smis;
512 switch (op_) {
513 case Token::ADD: {
514 ASSERT(right.is(rax));
515 __ SmiAdd(right, right, left, &use_fp_on_smis); // ADD is commutative.
516 break;
517 }
518
519 case Token::SUB: {
520 __ SmiSub(left, left, right, &use_fp_on_smis);
521 __ movq(rax, left);
522 break;
523 }
524
525 case Token::MUL:
526 ASSERT(right.is(rax));
527 __ SmiMul(right, right, left, &use_fp_on_smis); // MUL is commutative.
528 break;
529
530 case Token::DIV:
531 ASSERT(left.is(rax));
532 __ SmiDiv(left, left, right, &use_fp_on_smis);
533 break;
534
535 case Token::MOD:
536 ASSERT(left.is(rax));
537 __ SmiMod(left, left, right, slow);
538 break;
539
540 case Token::BIT_OR:
541 ASSERT(right.is(rax));
542 __ movq(rcx, right); // Save the right operand.
543 __ SmiOr(right, right, left); // BIT_OR is commutative.
544 __ testb(right, Immediate(kSmiTagMask));
545 __ j(not_zero, &not_smis);
546 break;
547
548 case Token::BIT_AND:
549 ASSERT(right.is(rax));
550 __ SmiAnd(right, right, left); // BIT_AND is commutative.
551 break;
552
553 case Token::BIT_XOR:
554 ASSERT(right.is(rax));
555 __ SmiXor(right, right, left); // BIT_XOR is commutative.
556 break;
557
558 case Token::SHL:
559 case Token::SHR:
560 case Token::SAR:
561 switch (op_) {
562 case Token::SAR:
563 __ SmiShiftArithmeticRight(left, left, right);
564 break;
565 case Token::SHR:
566 __ SmiShiftLogicalRight(left, left, right, slow);
567 break;
568 case Token::SHL:
569 __ SmiShiftLeft(left, left, right);
570 break;
571 default:
572 UNREACHABLE();
573 }
574 __ movq(rax, left);
575 break;
576
577 default:
578 UNREACHABLE();
579 break;
580 }
581
582 // 4. Emit return of result in rax.
583 GenerateReturn(masm);
584
585 // 5. For some operations emit inline code to perform floating point
586 // operations on known smis (e.g., if the result of the operation
587 // overflowed the smi range).
588 switch (op_) {
589 case Token::ADD:
590 case Token::SUB:
591 case Token::MUL:
592 case Token::DIV: {
593 ASSERT(use_fp_on_smis.is_linked());
594 __ bind(&use_fp_on_smis);
595 if (op_ == Token::DIV) {
596 __ movq(rdx, rax);
597 __ movq(rax, rbx);
598 }
599 // left is rdx, right is rax.
600 __ AllocateHeapNumber(rbx, rcx, slow);
601 FloatingPointHelper::LoadSSE2SmiOperands(masm);
602 switch (op_) {
603 case Token::ADD: __ addsd(xmm0, xmm1); break;
604 case Token::SUB: __ subsd(xmm0, xmm1); break;
605 case Token::MUL: __ mulsd(xmm0, xmm1); break;
606 case Token::DIV: __ divsd(xmm0, xmm1); break;
607 default: UNREACHABLE();
608 }
609 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
610 __ movq(rax, rbx);
611 GenerateReturn(masm);
612 }
613 default:
614 break;
615 }
616
617 // 6. Non-smi operands, fall out to the non-smi code with the operands in
618 // rdx and rax.
619 Comment done_comment(masm, "-- Enter non-smi code");
620 __ bind(&not_smis);
621
622 switch (op_) {
623 case Token::DIV:
624 case Token::MOD:
625 // Operands are in rax, rbx at this point.
626 __ movq(rdx, rax);
627 __ movq(rax, rbx);
628 break;
629
630 case Token::BIT_OR:
631 // Right operand is saved in rcx and rax was destroyed by the smi
632 // operation.
633 __ movq(rax, rcx);
634 break;
635
636 default:
637 break;
638 }
639 }
640
641
642 void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
643 Label call_runtime;
644
645 if (ShouldGenerateSmiCode()) {
646 GenerateSmiCode(masm, &call_runtime);
647 } else if (op_ != Token::MOD) {
648 if (!HasArgsInRegisters()) {
649 GenerateLoadArguments(masm);
650 }
651 }
652 // Floating point case.
653 if (ShouldGenerateFPCode()) {
654 switch (op_) {
655 case Token::ADD:
656 case Token::SUB:
657 case Token::MUL:
658 case Token::DIV: {
659 if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
660 HasSmiCodeInStub()) {
661 // Execution reaches this point when the first non-smi argument occurs
662 // (and only if smi code is generated). This is the right moment to
663 // patch to HEAP_NUMBERS state. The transition is attempted only for
664 // the four basic operations. The stub stays in the DEFAULT state
665 // forever for all other operations (also if smi code is skipped).
666 GenerateTypeTransition(masm);
667 break;
668 }
669
670 Label not_floats;
671 // rax: y
672 // rdx: x
673 if (static_operands_type_.IsNumber()) {
674 if (FLAG_debug_code) {
675 // Assert at runtime that inputs are only numbers.
676 __ AbortIfNotNumber(rdx);
677 __ AbortIfNotNumber(rax);
678 }
679 FloatingPointHelper::LoadSSE2NumberOperands(masm);
680 } else {
681 FloatingPointHelper::LoadSSE2UnknownOperands(masm, &call_runtime);
682 }
683
684 switch (op_) {
685 case Token::ADD: __ addsd(xmm0, xmm1); break;
686 case Token::SUB: __ subsd(xmm0, xmm1); break;
687 case Token::MUL: __ mulsd(xmm0, xmm1); break;
688 case Token::DIV: __ divsd(xmm0, xmm1); break;
689 default: UNREACHABLE();
690 }
691 // Allocate a heap number, if needed.
692 Label skip_allocation;
693 OverwriteMode mode = mode_;
694 if (HasArgsReversed()) {
695 if (mode == OVERWRITE_RIGHT) {
696 mode = OVERWRITE_LEFT;
697 } else if (mode == OVERWRITE_LEFT) {
698 mode = OVERWRITE_RIGHT;
699 }
700 }
701 switch (mode) {
702 case OVERWRITE_LEFT:
703 __ JumpIfNotSmi(rdx, &skip_allocation);
704 __ AllocateHeapNumber(rbx, rcx, &call_runtime);
705 __ movq(rdx, rbx);
706 __ bind(&skip_allocation);
707 __ movq(rax, rdx);
708 break;
709 case OVERWRITE_RIGHT:
710 // If the argument in rax is already an object, we skip the
711 // allocation of a heap number.
712 __ JumpIfNotSmi(rax, &skip_allocation);
713 // Fall through!
714 case NO_OVERWRITE:
715 // Allocate a heap number for the result. Keep rax and rdx intact
716 // for the possible runtime call.
717 __ AllocateHeapNumber(rbx, rcx, &call_runtime);
718 __ movq(rax, rbx);
719 __ bind(&skip_allocation);
720 break;
721 default: UNREACHABLE();
722 }
723 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
724 GenerateReturn(masm);
725 __ bind(&not_floats);
726 if (runtime_operands_type_ == BinaryOpIC::DEFAULT &&
727 !HasSmiCodeInStub()) {
728 // Execution reaches this point when the first non-number argument
729 // occurs (and only if smi code is skipped from the stub, otherwise
730 // the patching has already been done earlier in this case branch).
731 // A perfect moment to try patching to STRINGS for ADD operation.
732 if (op_ == Token::ADD) {
733 GenerateTypeTransition(masm);
734 }
735 }
736 break;
737 }
738 case Token::MOD: {
739 // For MOD we go directly to runtime in the non-smi case.
740 break;
741 }
742 case Token::BIT_OR:
743 case Token::BIT_AND:
744 case Token::BIT_XOR:
745 case Token::SAR:
746 case Token::SHL:
747 case Token::SHR: {
748 Label skip_allocation, non_smi_shr_result;
749 Register heap_number_map = r9;
750 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
751 if (static_operands_type_.IsNumber()) {
752 if (FLAG_debug_code) {
753 // Assert at runtime that inputs are only numbers.
754 __ AbortIfNotNumber(rdx);
755 __ AbortIfNotNumber(rax);
756 }
757 FloatingPointHelper::LoadNumbersAsIntegers(masm);
758 } else {
759 FloatingPointHelper::LoadAsIntegers(masm,
760 &call_runtime,
761 heap_number_map);
762 }
763 switch (op_) {
764 case Token::BIT_OR: __ orl(rax, rcx); break;
765 case Token::BIT_AND: __ andl(rax, rcx); break;
766 case Token::BIT_XOR: __ xorl(rax, rcx); break;
767 case Token::SAR: __ sarl_cl(rax); break;
768 case Token::SHL: __ shll_cl(rax); break;
769 case Token::SHR: {
770 __ shrl_cl(rax);
771 // Check if result is negative. This can only happen for a shift
772 // by zero.
773 __ testl(rax, rax);
774 __ j(negative, &non_smi_shr_result);
775 break;
776 }
777 default: UNREACHABLE();
778 }
779
780 STATIC_ASSERT(kSmiValueSize == 32);
781 // Tag smi result and return.
782 __ Integer32ToSmi(rax, rax);
783 GenerateReturn(masm);
784
785 // All bit-ops except SHR return a signed int32 that can be
786 // returned immediately as a smi.
787 // We might need to allocate a HeapNumber if we shift a negative
788 // number right by zero (i.e., convert to UInt32).
789 if (op_ == Token::SHR) {
790 ASSERT(non_smi_shr_result.is_linked());
791 __ bind(&non_smi_shr_result);
792 // Allocate a heap number if needed.
793 __ movl(rbx, rax); // rbx holds result value (uint32 value as int64).
794 switch (mode_) {
795 case OVERWRITE_LEFT:
796 case OVERWRITE_RIGHT:
797 // If the operand was an object, we skip the
798 // allocation of a heap number.
799 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ?
800 1 * kPointerSize : 2 * kPointerSize));
801 __ JumpIfNotSmi(rax, &skip_allocation);
802 // Fall through!
803 case NO_OVERWRITE:
804 // Allocate heap number in new space.
805 // Not using AllocateHeapNumber macro in order to reuse
806 // already loaded heap_number_map.
807 __ AllocateInNewSpace(HeapNumber::kSize,
808 rax,
809 rcx,
810 no_reg,
811 &call_runtime,
812 TAG_OBJECT);
813 // Set the map.
814 if (FLAG_debug_code) {
815 __ AbortIfNotRootValue(heap_number_map,
816 Heap::kHeapNumberMapRootIndex,
817 "HeapNumberMap register clobbered.");
818 }
819 __ movq(FieldOperand(rax, HeapObject::kMapOffset),
820 heap_number_map);
821 __ bind(&skip_allocation);
822 break;
823 default: UNREACHABLE();
824 }
825 // Store the result in the HeapNumber and return.
826 __ cvtqsi2sd(xmm0, rbx);
827 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0);
828 GenerateReturn(masm);
829 }
830
831 break;
832 }
833 default: UNREACHABLE(); break;
834 }
835 }
836
837 // If all else fails, use the runtime system to get the correct
838 // result. If arguments was passed in registers now place them on the
839 // stack in the correct order below the return address.
840 __ bind(&call_runtime);
841
842 if (HasArgsInRegisters()) {
843 GenerateRegisterArgsPush(masm);
844 }
845
846 switch (op_) {
847 case Token::ADD: {
848 // Registers containing left and right operands respectively.
849 Register lhs, rhs;
850
851 if (HasArgsReversed()) {
852 lhs = rax;
853 rhs = rdx;
854 } else {
855 lhs = rdx;
856 rhs = rax;
857 }
858
859 // Test for string arguments before calling runtime.
860 Label not_strings, both_strings, not_string1, string1, string1_smi2;
861
862 // If this stub has already generated FP-specific code then the arguments
863 // are already in rdx and rax.
864 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) {
865 GenerateLoadArguments(masm);
866 }
867
868 Condition is_smi;
869 is_smi = masm->CheckSmi(lhs);
870 __ j(is_smi, &not_string1);
871 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, r8);
872 __ j(above_equal, &not_string1);
873
874 // First argument is a a string, test second.
875 is_smi = masm->CheckSmi(rhs);
876 __ j(is_smi, &string1_smi2);
877 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, r9);
878 __ j(above_equal, &string1);
879
880 // First and second argument are strings.
881 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
882 __ TailCallStub(&string_add_stub);
883
884 __ bind(&string1_smi2);
885 // First argument is a string, second is a smi. Try to lookup the number
886 // string for the smi in the number string cache.
887 NumberToStringStub::GenerateLookupNumberStringCache(
888 masm, rhs, rbx, rcx, r8, true, &string1);
889
890 // Replace second argument on stack and tailcall string add stub to make
891 // the result.
892 __ movq(Operand(rsp, 1 * kPointerSize), rbx);
893 __ TailCallStub(&string_add_stub);
894
895 // Only first argument is a string.
896 __ bind(&string1);
897 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION);
898
899 // First argument was not a string, test second.
900 __ bind(&not_string1);
901 is_smi = masm->CheckSmi(rhs);
902 __ j(is_smi, &not_strings);
903 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, rhs);
904 __ j(above_equal, &not_strings);
905
906 // Only second argument is a string.
907 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
908
909 __ bind(&not_strings);
910 // Neither argument is a string.
911 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION);
912 break;
913 }
914 case Token::SUB:
915 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
916 break;
917 case Token::MUL:
918 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
919 break;
920 case Token::DIV:
921 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
922 break;
923 case Token::MOD:
924 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
925 break;
926 case Token::BIT_OR:
927 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
928 break;
929 case Token::BIT_AND:
930 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
931 break;
932 case Token::BIT_XOR:
933 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
934 break;
935 case Token::SAR:
936 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
937 break;
938 case Token::SHL:
939 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
940 break;
941 case Token::SHR:
942 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
943 break;
944 default:
945 UNREACHABLE();
946 }
947 }
948
949
950 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) {
951 ASSERT(!HasArgsInRegisters());
952 __ movq(rax, Operand(rsp, 1 * kPointerSize));
953 __ movq(rdx, Operand(rsp, 2 * kPointerSize));
954 }
955
956
957 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) {
958 // If arguments are not passed in registers remove them from the stack before
959 // returning.
960 if (!HasArgsInRegisters()) {
961 __ ret(2 * kPointerSize); // Remove both operands
962 } else {
963 __ ret(0);
964 }
965 }
966
967
968 void GenericBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
969 ASSERT(HasArgsInRegisters());
970 __ pop(rcx);
971 if (HasArgsReversed()) {
972 __ push(rax);
973 __ push(rdx);
974 } else {
975 __ push(rdx);
976 __ push(rax);
977 }
978 __ push(rcx);
979 }
980
981
982 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
983 Label get_result;
984
985 // Ensure the operands are on the stack.
986 if (HasArgsInRegisters()) {
987 GenerateRegisterArgsPush(masm);
988 }
989
990 // Left and right arguments are already on stack.
991 __ pop(rcx); // Save the return address.
992
993 // Push this stub's key.
994 __ Push(Smi::FromInt(MinorKey()));
995
996 // Although the operation and the type info are encoded into the key,
997 // the encoding is opaque, so push them too.
998 __ Push(Smi::FromInt(op_));
999
1000 __ Push(Smi::FromInt(runtime_operands_type_));
1001
1002 __ push(rcx); // The return address.
1003
1004 // Perform patching to an appropriate fast case and return the result.
1005 __ TailCallExternalReference(
1006 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), masm->isolate()),
1007 5,
1008 1);
1009 }
1010
1011
1012 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
1013 GenericBinaryOpStub stub(key, type_info);
1014 return stub.GetCode();
1015 }
1016
1017
1018 Handle<Code> GetTypeRecordingBinaryOpStub(int key, 306 Handle<Code> GetTypeRecordingBinaryOpStub(int key,
1019 TRBinaryOpIC::TypeInfo type_info, 307 TRBinaryOpIC::TypeInfo type_info,
1020 TRBinaryOpIC::TypeInfo result_type_info) { 308 TRBinaryOpIC::TypeInfo result_type_info) {
1021 TypeRecordingBinaryOpStub stub(key, type_info, result_type_info); 309 TypeRecordingBinaryOpStub stub(key, type_info, result_type_info);
1022 return stub.GetCode(); 310 return stub.GetCode();
1023 } 311 }
1024 312
1025 313
1026 void TypeRecordingBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 314 void TypeRecordingBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
1027 __ pop(rcx); // Save return address. 315 __ pop(rcx); // Save return address.
(...skipping 4114 matching lines...) Expand 10 before | Expand all | Expand 10 after
5142 // Do a tail call to the rewritten stub. 4430 // Do a tail call to the rewritten stub.
5143 __ jmp(rdi); 4431 __ jmp(rdi);
5144 } 4432 }
5145 4433
5146 4434
5147 #undef __ 4435 #undef __
5148 4436
5149 } } // namespace v8::internal 4437 } } // namespace v8::internal
5150 4438
5151 #endif // V8_TARGET_ARCH_X64 4439 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/code-stubs-x64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698