| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 // CodeGenerator implementation | 105 // CodeGenerator implementation |
| 106 | 106 |
| 107 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 107 CodeGenerator::CodeGenerator(MacroAssembler* masm) |
| 108 : deferred_(8), | 108 : deferred_(8), |
| 109 masm_(masm), | 109 masm_(masm), |
| 110 info_(NULL), | 110 info_(NULL), |
| 111 frame_(NULL), | 111 frame_(NULL), |
| 112 allocator_(NULL), | 112 allocator_(NULL), |
| 113 state_(NULL), | 113 state_(NULL), |
| 114 loop_nesting_(0), | 114 loop_nesting_(0), |
| 115 in_safe_int32_mode_(false), |
| 116 safe_int32_mode_enabled_(true), |
| 115 function_return_is_shadowed_(false), | 117 function_return_is_shadowed_(false), |
| 116 in_spilled_code_(false) { | 118 in_spilled_code_(false) { |
| 117 } | 119 } |
| 118 | 120 |
| 119 | 121 |
| 120 // Calling conventions: | 122 // Calling conventions: |
| 121 // ebp: caller's frame pointer | 123 // ebp: caller's frame pointer |
| 122 // esp: stack pointer | 124 // esp: stack pointer |
| 123 // edi: called JS function | 125 // edi: called JS function |
| 124 // esi: callee's context | 126 // esi: callee's context |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 slow->Branch(not_equal, not_taken); | 432 slow->Branch(not_equal, not_taken); |
| 431 __ mov(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); | 433 __ mov(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 432 return ContextOperand(tmp.reg(), slot->index()); | 434 return ContextOperand(tmp.reg(), slot->index()); |
| 433 } | 435 } |
| 434 | 436 |
| 435 | 437 |
| 436 // Emit code to load the value of an expression to the top of the | 438 // Emit code to load the value of an expression to the top of the |
| 437 // frame. If the expression is boolean-valued it may be compiled (or | 439 // frame. If the expression is boolean-valued it may be compiled (or |
| 438 // partially compiled) into control flow to the control destination. | 440 // partially compiled) into control flow to the control destination. |
| 439 // If force_control is true, control flow is forced. | 441 // If force_control is true, control flow is forced. |
| 440 void CodeGenerator::LoadCondition(Expression* x, | 442 void CodeGenerator::LoadCondition(Expression* expr, |
| 441 ControlDestination* dest, | 443 ControlDestination* dest, |
| 442 bool force_control) { | 444 bool force_control) { |
| 443 ASSERT(!in_spilled_code()); | 445 ASSERT(!in_spilled_code()); |
| 444 int original_height = frame_->height(); | 446 int original_height = frame_->height(); |
| 445 | 447 |
| 446 { CodeGenState new_state(this, dest); | 448 { CodeGenState new_state(this, dest); |
| 447 Visit(x); | 449 Visit(expr); |
| 448 | 450 |
| 449 // If we hit a stack overflow, we may not have actually visited | 451 // If we hit a stack overflow, we may not have actually visited |
| 450 // the expression. In that case, we ensure that we have a | 452 // the expression. In that case, we ensure that we have a |
| 451 // valid-looking frame state because we will continue to generate | 453 // valid-looking frame state because we will continue to generate |
| 452 // code as we unwind the C++ stack. | 454 // code as we unwind the C++ stack. |
| 453 // | 455 // |
| 454 // It's possible to have both a stack overflow and a valid frame | 456 // It's possible to have both a stack overflow and a valid frame |
| 455 // state (eg, a subexpression overflowed, visiting it returned | 457 // state (eg, a subexpression overflowed, visiting it returned |
| 456 // with a dummied frame state, and visiting this expression | 458 // with a dummied frame state, and visiting this expression |
| 457 // returned with a normal-looking state). | 459 // returned with a normal-looking state). |
| (...skipping 16 matching lines...) Expand all Loading... |
| 474 | 476 |
| 475 void CodeGenerator::LoadAndSpill(Expression* expression) { | 477 void CodeGenerator::LoadAndSpill(Expression* expression) { |
| 476 ASSERT(in_spilled_code()); | 478 ASSERT(in_spilled_code()); |
| 477 set_in_spilled_code(false); | 479 set_in_spilled_code(false); |
| 478 Load(expression); | 480 Load(expression); |
| 479 frame_->SpillAll(); | 481 frame_->SpillAll(); |
| 480 set_in_spilled_code(true); | 482 set_in_spilled_code(true); |
| 481 } | 483 } |
| 482 | 484 |
| 483 | 485 |
| 486 void CodeGenerator::LoadInSafeInt32Mode(Expression* expr, |
| 487 BreakTarget* unsafe_bailout) { |
| 488 set_unsafe_bailout(unsafe_bailout); |
| 489 set_in_safe_int32_mode(true); |
| 490 Load(expr); |
| 491 Result value = frame_->Pop(); |
| 492 ASSERT(frame_->HasNoUntaggedInt32Elements()); |
| 493 ConvertInt32ResultToNumber(&value); |
| 494 set_in_safe_int32_mode(false); |
| 495 set_unsafe_bailout(NULL); |
| 496 frame_->Push(&value); |
| 497 } |
| 498 |
| 499 |
| 500 void CodeGenerator::LoadWithSafeInt32ModeDisabled(Expression* expr) { |
| 501 set_safe_int32_mode_enabled(false); |
| 502 Load(expr); |
| 503 set_safe_int32_mode_enabled(true); |
| 504 } |
| 505 |
| 506 |
| 507 void CodeGenerator::ConvertInt32ResultToNumber(Result* value) { |
| 508 ASSERT(value->is_untagged_int32()); |
| 509 if (value->is_register()) { |
| 510 Register val = value->reg(); |
| 511 JumpTarget done; |
| 512 __ add(val, Operand(val)); |
| 513 done.Branch(no_overflow, value); |
| 514 __ sar(val, 1); |
| 515 // If there was an overflow, bits 30 and 31 of the original number disagree. |
| 516 __ xor_(val, 0x80000000u); |
| 517 if (CpuFeatures::IsSupported(SSE2)) { |
| 518 CpuFeatures::Scope fscope(SSE2); |
| 519 __ cvtsi2sd(xmm0, Operand(val)); |
| 520 } else { |
| 521 // Move val to ST[0] in the FPU |
| 522 // Push and pop are safe with respect to the virtual frame because |
| 523 // all synced elements are below the actual stack pointer. |
| 524 __ push(val); |
| 525 __ fild_s(Operand(esp, 0)); |
| 526 __ pop(val); |
| 527 } |
| 528 Result scratch = allocator_->Allocate(); |
| 529 ASSERT(scratch.is_register()); |
| 530 Label allocation_failed; |
| 531 __ AllocateHeapNumber(val, scratch.reg(), |
| 532 no_reg, &allocation_failed); |
| 533 VirtualFrame* clone = new VirtualFrame(frame_); |
| 534 scratch.Unuse(); |
| 535 if (CpuFeatures::IsSupported(SSE2)) { |
| 536 CpuFeatures::Scope fscope(SSE2); |
| 537 __ movdbl(FieldOperand(val, HeapNumber::kValueOffset), xmm0); |
| 538 } else { |
| 539 __ fstp_d(FieldOperand(val, HeapNumber::kValueOffset)); |
| 540 } |
| 541 done.Jump(value); |
| 542 |
| 543 // Establish the virtual frame, cloned from where AllocateHeapNumber |
| 544 // jumped to allocation_failed. |
| 545 RegisterFile empty_regs; |
| 546 SetFrame(clone, &empty_regs); |
| 547 __ bind(&allocation_failed); |
| 548 unsafe_bailout_->Jump(); |
| 549 |
| 550 done.Bind(value); |
| 551 } else { |
| 552 ASSERT(value->is_constant()); |
| 553 } |
| 554 value->set_untagged_int32(false); |
| 555 } |
| 556 |
| 557 |
| 484 void CodeGenerator::Load(Expression* expr) { | 558 void CodeGenerator::Load(Expression* expr) { |
| 485 #ifdef DEBUG | 559 #ifdef DEBUG |
| 486 int original_height = frame_->height(); | 560 int original_height = frame_->height(); |
| 487 #endif | 561 #endif |
| 488 ASSERT(!in_spilled_code()); | 562 ASSERT(!in_spilled_code()); |
| 489 JumpTarget true_target; | |
| 490 JumpTarget false_target; | |
| 491 ControlDestination dest(&true_target, &false_target, true); | |
| 492 LoadCondition(expr, &dest, false); | |
| 493 | 563 |
| 494 if (dest.false_was_fall_through()) { | 564 // If the expression should be a side-effect-free 32-bit int computation, |
| 495 // The false target was just bound. | 565 // compile that SafeInt32 path, and a bailout path. |
| 496 JumpTarget loaded; | 566 if (!in_safe_int32_mode() && |
| 497 frame_->Push(Factory::false_value()); | 567 safe_int32_mode_enabled() && |
| 498 // There may be dangling jumps to the true target. | 568 expr->side_effect_free() && |
| 499 if (true_target.is_linked()) { | 569 expr->num_bit_ops() > 2 && |
| 500 loaded.Jump(); | 570 CpuFeatures::IsSupported(SSE2)) { |
| 501 true_target.Bind(); | 571 BreakTarget unsafe_bailout; |
| 502 frame_->Push(Factory::true_value()); | 572 JumpTarget done; |
| 503 loaded.Bind(); | 573 unsafe_bailout.set_expected_height(frame_->height()); |
| 574 LoadInSafeInt32Mode(expr, &unsafe_bailout); |
| 575 done.Jump(); |
| 576 |
| 577 if (unsafe_bailout.is_linked()) { |
| 578 unsafe_bailout.Bind(); |
| 579 LoadWithSafeInt32ModeDisabled(expr); |
| 504 } | 580 } |
| 581 done.Bind(); |
| 582 } else { |
| 583 JumpTarget true_target; |
| 584 JumpTarget false_target; |
| 505 | 585 |
| 506 } else if (dest.is_used()) { | 586 ControlDestination dest(&true_target, &false_target, true); |
| 507 // There is true, and possibly false, control flow (with true as | 587 LoadCondition(expr, &dest, false); |
| 508 // the fall through). | 588 |
| 509 JumpTarget loaded; | 589 if (dest.false_was_fall_through()) { |
| 510 frame_->Push(Factory::true_value()); | 590 // The false target was just bound. |
| 511 if (false_target.is_linked()) { | 591 JumpTarget loaded; |
| 512 loaded.Jump(); | |
| 513 false_target.Bind(); | |
| 514 frame_->Push(Factory::false_value()); | 592 frame_->Push(Factory::false_value()); |
| 515 loaded.Bind(); | 593 // There may be dangling jumps to the true target. |
| 516 } | |
| 517 | |
| 518 } else { | |
| 519 // We have a valid value on top of the frame, but we still may | |
| 520 // have dangling jumps to the true and false targets from nested | |
| 521 // subexpressions (eg, the left subexpressions of the | |
| 522 // short-circuited boolean operators). | |
| 523 ASSERT(has_valid_frame()); | |
| 524 if (true_target.is_linked() || false_target.is_linked()) { | |
| 525 JumpTarget loaded; | |
| 526 loaded.Jump(); // Don't lose the current TOS. | |
| 527 if (true_target.is_linked()) { | 594 if (true_target.is_linked()) { |
| 595 loaded.Jump(); |
| 528 true_target.Bind(); | 596 true_target.Bind(); |
| 529 frame_->Push(Factory::true_value()); | 597 frame_->Push(Factory::true_value()); |
| 530 if (false_target.is_linked()) { | 598 loaded.Bind(); |
| 531 loaded.Jump(); | |
| 532 } | |
| 533 } | 599 } |
| 600 |
| 601 } else if (dest.is_used()) { |
| 602 // There is true, and possibly false, control flow (with true as |
| 603 // the fall through). |
| 604 JumpTarget loaded; |
| 605 frame_->Push(Factory::true_value()); |
| 534 if (false_target.is_linked()) { | 606 if (false_target.is_linked()) { |
| 607 loaded.Jump(); |
| 535 false_target.Bind(); | 608 false_target.Bind(); |
| 536 frame_->Push(Factory::false_value()); | 609 frame_->Push(Factory::false_value()); |
| 610 loaded.Bind(); |
| 537 } | 611 } |
| 538 loaded.Bind(); | 612 |
| 613 } else { |
| 614 // We have a valid value on top of the frame, but we still may |
| 615 // have dangling jumps to the true and false targets from nested |
| 616 // subexpressions (eg, the left subexpressions of the |
| 617 // short-circuited boolean operators). |
| 618 ASSERT(has_valid_frame()); |
| 619 if (true_target.is_linked() || false_target.is_linked()) { |
| 620 JumpTarget loaded; |
| 621 loaded.Jump(); // Don't lose the current TOS. |
| 622 if (true_target.is_linked()) { |
| 623 true_target.Bind(); |
| 624 frame_->Push(Factory::true_value()); |
| 625 if (false_target.is_linked()) { |
| 626 loaded.Jump(); |
| 627 } |
| 628 } |
| 629 if (false_target.is_linked()) { |
| 630 false_target.Bind(); |
| 631 frame_->Push(Factory::false_value()); |
| 632 } |
| 633 loaded.Bind(); |
| 634 } |
| 539 } | 635 } |
| 540 } | 636 } |
| 541 | |
| 542 ASSERT(has_valid_frame()); | 637 ASSERT(has_valid_frame()); |
| 543 ASSERT(frame_->height() == original_height + 1); | 638 ASSERT(frame_->height() == original_height + 1); |
| 544 } | 639 } |
| 545 | 640 |
| 546 | 641 |
| 547 void CodeGenerator::LoadGlobal() { | 642 void CodeGenerator::LoadGlobal() { |
| 548 if (in_spilled_code()) { | 643 if (in_spilled_code()) { |
| 549 frame_->EmitPush(GlobalObject()); | 644 frame_->EmitPush(GlobalObject()); |
| 550 } else { | 645 } else { |
| 551 Result temp = allocator_->Allocate(); | 646 Result temp = allocator_->Allocate(); |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 730 Comment cmnt(masm_, "[ ToBoolean"); | 825 Comment cmnt(masm_, "[ ToBoolean"); |
| 731 | 826 |
| 732 // The value to convert should be popped from the frame. | 827 // The value to convert should be popped from the frame. |
| 733 Result value = frame_->Pop(); | 828 Result value = frame_->Pop(); |
| 734 value.ToRegister(); | 829 value.ToRegister(); |
| 735 | 830 |
| 736 if (value.is_integer32()) { // Also takes Smi case. | 831 if (value.is_integer32()) { // Also takes Smi case. |
| 737 Comment cmnt(masm_, "ONLY_INTEGER_32"); | 832 Comment cmnt(masm_, "ONLY_INTEGER_32"); |
| 738 if (FLAG_debug_code) { | 833 if (FLAG_debug_code) { |
| 739 Label ok; | 834 Label ok; |
| 740 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); | 835 __ AbortIfNotNumber(value.reg()); |
| 741 __ test(value.reg(), Immediate(kSmiTagMask)); | 836 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 742 __ j(zero, &ok); | 837 __ j(zero, &ok); |
| 743 __ fldz(); | 838 __ fldz(); |
| 744 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); | 839 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
| 745 __ FCmp(); | 840 __ FCmp(); |
| 746 __ j(not_zero, &ok); | 841 __ j(not_zero, &ok); |
| 747 __ Abort("Smi was wrapped in HeapNumber in output from bitop"); | 842 __ Abort("Smi was wrapped in HeapNumber in output from bitop"); |
| 748 __ bind(&ok); | 843 __ bind(&ok); |
| 749 } | 844 } |
| 750 // In the integer32 case there are no Smis hidden in heap numbers, so we | 845 // In the integer32 case there are no Smis hidden in heap numbers, so we |
| 751 // need only test for Smi zero. | 846 // need only test for Smi zero. |
| 752 __ test(value.reg(), Operand(value.reg())); | 847 __ test(value.reg(), Operand(value.reg())); |
| 753 dest->false_target()->Branch(zero); | 848 dest->false_target()->Branch(zero); |
| 754 value.Unuse(); | 849 value.Unuse(); |
| 755 dest->Split(not_zero); | 850 dest->Split(not_zero); |
| 756 } else if (value.is_number()) { | 851 } else if (value.is_number()) { |
| 757 Comment cmnt(masm_, "ONLY_NUMBER"); | 852 Comment cmnt(masm_, "ONLY_NUMBER"); |
| 758 // Fast case if NumberInfo indicates only numbers. | 853 // Fast case if NumberInfo indicates only numbers. |
| 759 if (FLAG_debug_code) { | 854 if (FLAG_debug_code) { |
| 760 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); | 855 __ AbortIfNotNumber(value.reg()); |
| 761 } | 856 } |
| 762 // Smi => false iff zero. | 857 // Smi => false iff zero. |
| 763 ASSERT(kSmiTag == 0); | 858 ASSERT(kSmiTag == 0); |
| 764 __ test(value.reg(), Operand(value.reg())); | 859 __ test(value.reg(), Operand(value.reg())); |
| 765 dest->false_target()->Branch(zero); | 860 dest->false_target()->Branch(zero); |
| 766 __ test(value.reg(), Immediate(kSmiTagMask)); | 861 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 767 dest->true_target()->Branch(zero); | 862 dest->true_target()->Branch(zero); |
| 768 __ fldz(); | 863 __ fldz(); |
| 769 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); | 864 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
| 770 __ FCmp(); | 865 __ FCmp(); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 936 Factory::heap_number_map()); | 1031 Factory::heap_number_map()); |
| 937 __ j(not_equal, &call_runtime); | 1032 __ j(not_equal, &call_runtime); |
| 938 } | 1033 } |
| 939 __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); | 1034 __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); |
| 940 if (mode_ == OVERWRITE_LEFT) { | 1035 if (mode_ == OVERWRITE_LEFT) { |
| 941 __ mov(dst_, left_); | 1036 __ mov(dst_, left_); |
| 942 } | 1037 } |
| 943 __ jmp(&load_right); | 1038 __ jmp(&load_right); |
| 944 | 1039 |
| 945 __ bind(&left_smi); | 1040 __ bind(&left_smi); |
| 1041 } else { |
| 1042 if (FLAG_debug_code) __ AbortIfNotSmi(left_); |
| 946 } | 1043 } |
| 947 __ SmiUntag(left_); | 1044 __ SmiUntag(left_); |
| 948 __ cvtsi2sd(xmm0, Operand(left_)); | 1045 __ cvtsi2sd(xmm0, Operand(left_)); |
| 949 __ SmiTag(left_); | 1046 __ SmiTag(left_); |
| 950 if (mode_ == OVERWRITE_LEFT) { | 1047 if (mode_ == OVERWRITE_LEFT) { |
| 951 Label alloc_failure; | 1048 Label alloc_failure; |
| 952 __ push(left_); | 1049 __ push(left_); |
| 953 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 1050 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
| 954 __ pop(left_); | 1051 __ pop(left_); |
| 955 } | 1052 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 968 __ mov(dst_, right_); | 1065 __ mov(dst_, right_); |
| 969 } else if (mode_ == NO_OVERWRITE) { | 1066 } else if (mode_ == NO_OVERWRITE) { |
| 970 Label alloc_failure; | 1067 Label alloc_failure; |
| 971 __ push(left_); | 1068 __ push(left_); |
| 972 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 1069 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
| 973 __ pop(left_); | 1070 __ pop(left_); |
| 974 } | 1071 } |
| 975 __ jmp(&do_op); | 1072 __ jmp(&do_op); |
| 976 | 1073 |
| 977 __ bind(&right_smi); | 1074 __ bind(&right_smi); |
| 1075 } else { |
| 1076 if (FLAG_debug_code) __ AbortIfNotSmi(right_); |
| 978 } | 1077 } |
| 979 __ SmiUntag(right_); | 1078 __ SmiUntag(right_); |
| 980 __ cvtsi2sd(xmm1, Operand(right_)); | 1079 __ cvtsi2sd(xmm1, Operand(right_)); |
| 981 __ SmiTag(right_); | 1080 __ SmiTag(right_); |
| 982 if (mode_ == OVERWRITE_RIGHT || mode_ == NO_OVERWRITE) { | 1081 if (mode_ == OVERWRITE_RIGHT || mode_ == NO_OVERWRITE) { |
| 983 Label alloc_failure; | 1082 Label alloc_failure; |
| 984 __ push(left_); | 1083 __ push(left_); |
| 985 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 1084 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
| 986 __ pop(left_); | 1085 __ pop(left_); |
| 987 } | 1086 } |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1095 default: | 1194 default: |
| 1096 UNREACHABLE(); | 1195 UNREACHABLE(); |
| 1097 } | 1196 } |
| 1098 UNREACHABLE(); | 1197 UNREACHABLE(); |
| 1099 return NumberInfo::Unknown(); | 1198 return NumberInfo::Unknown(); |
| 1100 } | 1199 } |
| 1101 | 1200 |
| 1102 | 1201 |
| 1103 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 1202 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 1104 StaticType* type, | 1203 StaticType* type, |
| 1105 OverwriteMode overwrite_mode) { | 1204 OverwriteMode overwrite_mode, |
| 1205 bool no_negative_zero) { |
| 1106 Comment cmnt(masm_, "[ BinaryOperation"); | 1206 Comment cmnt(masm_, "[ BinaryOperation"); |
| 1107 Comment cmnt_token(masm_, Token::String(op)); | 1207 Comment cmnt_token(masm_, Token::String(op)); |
| 1108 | 1208 |
| 1109 if (op == Token::COMMA) { | 1209 if (op == Token::COMMA) { |
| 1110 // Simply discard left value. | 1210 // Simply discard left value. |
| 1111 frame_->Nip(1); | 1211 frame_->Nip(1); |
| 1112 return; | 1212 return; |
| 1113 } | 1213 } |
| 1114 | 1214 |
| 1115 Result right = frame_->Pop(); | 1215 Result right = frame_->Pop(); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1163 Result answer; | 1263 Result answer; |
| 1164 if (left_is_non_smi_constant || right_is_non_smi_constant) { | 1264 if (left_is_non_smi_constant || right_is_non_smi_constant) { |
| 1165 // Go straight to the slow case, with no smi code. | 1265 // Go straight to the slow case, with no smi code. |
| 1166 GenericBinaryOpStub stub(op, | 1266 GenericBinaryOpStub stub(op, |
| 1167 overwrite_mode, | 1267 overwrite_mode, |
| 1168 NO_SMI_CODE_IN_STUB, | 1268 NO_SMI_CODE_IN_STUB, |
| 1169 operands_type); | 1269 operands_type); |
| 1170 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1270 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 1171 } else if (right_is_smi_constant) { | 1271 } else if (right_is_smi_constant) { |
| 1172 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), | 1272 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
| 1173 type, false, overwrite_mode); | 1273 type, false, overwrite_mode, |
| 1274 no_negative_zero); |
| 1174 } else if (left_is_smi_constant) { | 1275 } else if (left_is_smi_constant) { |
| 1175 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), | 1276 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), |
| 1176 type, true, overwrite_mode); | 1277 type, true, overwrite_mode, |
| 1278 no_negative_zero); |
| 1177 } else { | 1279 } else { |
| 1178 // Set the flags based on the operation, type and loop nesting level. | 1280 // Set the flags based on the operation, type and loop nesting level. |
| 1179 // Bit operations always assume they likely operate on Smis. Still only | 1281 // Bit operations always assume they likely operate on Smis. Still only |
| 1180 // generate the inline Smi check code if this operation is part of a loop. | 1282 // generate the inline Smi check code if this operation is part of a loop. |
| 1181 // For all other operations only inline the Smi check code for likely smis | 1283 // For all other operations only inline the Smi check code for likely smis |
| 1182 // if the operation is part of a loop. | 1284 // if the operation is part of a loop. |
| 1183 if (loop_nesting() > 0 && | 1285 if (loop_nesting() > 0 && |
| 1184 (Token::IsBitOp(op) || | 1286 (Token::IsBitOp(op) || |
| 1185 operands_type.IsInteger32() || | 1287 operands_type.IsInteger32() || |
| 1186 type->IsLikelySmi())) { | 1288 type->IsLikelySmi())) { |
| 1187 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | 1289 answer = LikelySmiBinaryOperation(op, &left, &right, |
| 1290 overwrite_mode, no_negative_zero); |
| 1188 } else { | 1291 } else { |
| 1189 GenericBinaryOpStub stub(op, | 1292 GenericBinaryOpStub stub(op, |
| 1190 overwrite_mode, | 1293 overwrite_mode, |
| 1191 NO_GENERIC_BINARY_FLAGS, | 1294 NO_GENERIC_BINARY_FLAGS, |
| 1192 operands_type); | 1295 operands_type); |
| 1193 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1296 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 1194 } | 1297 } |
| 1195 } | 1298 } |
| 1196 | 1299 |
| 1197 answer.set_number_info(result_type); | 1300 answer.set_number_info(result_type); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1284 Register left, Register right, Register scratch, | 1387 Register left, Register right, Register scratch, |
| 1285 NumberInfo left_info, NumberInfo right_info, | 1388 NumberInfo left_info, NumberInfo right_info, |
| 1286 DeferredInlineBinaryOperation* deferred); | 1389 DeferredInlineBinaryOperation* deferred); |
| 1287 | 1390 |
| 1288 | 1391 |
| 1289 // Implements a binary operation using a deferred code object and some | 1392 // Implements a binary operation using a deferred code object and some |
| 1290 // inline code to operate on smis quickly. | 1393 // inline code to operate on smis quickly. |
| 1291 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | 1394 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
| 1292 Result* left, | 1395 Result* left, |
| 1293 Result* right, | 1396 Result* right, |
| 1294 OverwriteMode overwrite_mode) { | 1397 OverwriteMode overwrite_mode, |
| 1398 bool no_negative_zero) { |
| 1295 Result answer; | 1399 Result answer; |
| 1296 // Special handling of div and mod because they use fixed registers. | 1400 // Special handling of div and mod because they use fixed registers. |
| 1297 if (op == Token::DIV || op == Token::MOD) { | 1401 if (op == Token::DIV || op == Token::MOD) { |
| 1298 // We need eax as the quotient register, edx as the remainder | 1402 // We need eax as the quotient register, edx as the remainder |
| 1299 // register, neither left nor right in eax or edx, and left copied | 1403 // register, neither left nor right in eax or edx, and left copied |
| 1300 // to eax. | 1404 // to eax. |
| 1301 Result quotient; | 1405 Result quotient; |
| 1302 Result remainder; | 1406 Result remainder; |
| 1303 bool left_is_in_eax = false; | 1407 bool left_is_in_eax = false; |
| 1304 // Step 1: get eax for quotient. | 1408 // Step 1: get eax for quotient. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 __ test(right->reg(), Operand(right->reg())); | 1492 __ test(right->reg(), Operand(right->reg())); |
| 1389 deferred->Branch(zero); | 1493 deferred->Branch(zero); |
| 1390 // Divide edx:eax by the right operand. | 1494 // Divide edx:eax by the right operand. |
| 1391 __ idiv(right->reg()); | 1495 __ idiv(right->reg()); |
| 1392 | 1496 |
| 1393 // Complete the operation. | 1497 // Complete the operation. |
| 1394 if (op == Token::DIV) { | 1498 if (op == Token::DIV) { |
| 1395 // Check for negative zero result. If result is zero, and divisor | 1499 // Check for negative zero result. If result is zero, and divisor |
| 1396 // is negative, return a floating point negative zero. The | 1500 // is negative, return a floating point negative zero. The |
| 1397 // virtual frame is unchanged in this block, so local control flow | 1501 // virtual frame is unchanged in this block, so local control flow |
| 1398 // can use a Label rather than a JumpTarget. | 1502 // can use a Label rather than a JumpTarget. If the context of this |
| 1399 Label non_zero_result; | 1503 // expression will treat -0 like 0, do not do this test. |
| 1400 __ test(left->reg(), Operand(left->reg())); | 1504 if (!no_negative_zero) { |
| 1401 __ j(not_zero, &non_zero_result); | 1505 Label non_zero_result; |
| 1402 __ test(right->reg(), Operand(right->reg())); | 1506 __ test(left->reg(), Operand(left->reg())); |
| 1403 deferred->Branch(negative); | 1507 __ j(not_zero, &non_zero_result); |
| 1404 __ bind(&non_zero_result); | 1508 __ test(right->reg(), Operand(right->reg())); |
| 1509 deferred->Branch(negative); |
| 1510 __ bind(&non_zero_result); |
| 1511 } |
| 1405 // Check for the corner case of dividing the most negative smi by | 1512 // Check for the corner case of dividing the most negative smi by |
| 1406 // -1. We cannot use the overflow flag, since it is not set by | 1513 // -1. We cannot use the overflow flag, since it is not set by |
| 1407 // idiv instruction. | 1514 // idiv instruction. |
| 1408 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 1515 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
| 1409 __ cmp(eax, 0x40000000); | 1516 __ cmp(eax, 0x40000000); |
| 1410 deferred->Branch(equal); | 1517 deferred->Branch(equal); |
| 1411 // Check that the remainder is zero. | 1518 // Check that the remainder is zero. |
| 1412 __ test(edx, Operand(edx)); | 1519 __ test(edx, Operand(edx)); |
| 1413 deferred->Branch(not_zero); | 1520 deferred->Branch(not_zero); |
| 1414 // Tag the result and store it in the quotient register. | 1521 // Tag the result and store it in the quotient register. |
| 1415 __ SmiTag(eax); | 1522 __ SmiTag(eax); |
| 1416 deferred->BindExit(); | 1523 deferred->BindExit(); |
| 1417 left->Unuse(); | 1524 left->Unuse(); |
| 1418 right->Unuse(); | 1525 right->Unuse(); |
| 1419 answer = quotient; | 1526 answer = quotient; |
| 1420 } else { | 1527 } else { |
| 1421 ASSERT(op == Token::MOD); | 1528 ASSERT(op == Token::MOD); |
| 1422 // Check for a negative zero result. If the result is zero, and | 1529 // Check for a negative zero result. If the result is zero, and |
| 1423 // the dividend is negative, return a floating point negative | 1530 // the dividend is negative, return a floating point negative |
| 1424 // zero. The frame is unchanged in this block, so local control | 1531 // zero. The frame is unchanged in this block, so local control |
| 1425 // flow can use a Label rather than a JumpTarget. | 1532 // flow can use a Label rather than a JumpTarget. |
| 1426 Label non_zero_result; | 1533 if (!no_negative_zero) { |
| 1427 __ test(edx, Operand(edx)); | 1534 Label non_zero_result; |
| 1428 __ j(not_zero, &non_zero_result, taken); | 1535 __ test(edx, Operand(edx)); |
| 1429 __ test(left->reg(), Operand(left->reg())); | 1536 __ j(not_zero, &non_zero_result, taken); |
| 1430 deferred->Branch(negative); | 1537 __ test(left->reg(), Operand(left->reg())); |
| 1431 __ bind(&non_zero_result); | 1538 deferred->Branch(negative); |
| 1539 __ bind(&non_zero_result); |
| 1540 } |
| 1432 deferred->BindExit(); | 1541 deferred->BindExit(); |
| 1433 left->Unuse(); | 1542 left->Unuse(); |
| 1434 right->Unuse(); | 1543 right->Unuse(); |
| 1435 answer = remainder; | 1544 answer = remainder; |
| 1436 } | 1545 } |
| 1437 ASSERT(answer.is_valid()); | 1546 ASSERT(answer.is_valid()); |
| 1438 return answer; | 1547 return answer; |
| 1439 } | 1548 } |
| 1440 | 1549 |
| 1441 // Special handling of shift operations because they use fixed | 1550 // Special handling of shift operations because they use fixed |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1461 // Check that both operands are smis using the answer register as a | 1570 // Check that both operands are smis using the answer register as a |
| 1462 // temporary. | 1571 // temporary. |
| 1463 DeferredInlineBinaryOperation* deferred = | 1572 DeferredInlineBinaryOperation* deferred = |
| 1464 new DeferredInlineBinaryOperation(op, | 1573 new DeferredInlineBinaryOperation(op, |
| 1465 answer.reg(), | 1574 answer.reg(), |
| 1466 left->reg(), | 1575 left->reg(), |
| 1467 ecx, | 1576 ecx, |
| 1468 left->number_info(), | 1577 left->number_info(), |
| 1469 right->number_info(), | 1578 right->number_info(), |
| 1470 overwrite_mode); | 1579 overwrite_mode); |
| 1471 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), | |
| 1472 left->number_info(), right->number_info(), deferred); | |
| 1473 | 1580 |
| 1474 // Untag both operands. | 1581 Label do_op, left_nonsmi; |
| 1475 __ mov(answer.reg(), left->reg()); | 1582 // If right is a smi we make a fast case if left is either a smi |
| 1476 __ SmiUntag(answer.reg()); | 1583 // or a heapnumber. |
| 1584 if (CpuFeatures::IsSupported(SSE2) && right->number_info().IsSmi()) { |
| 1585 CpuFeatures::Scope use_sse2(SSE2); |
| 1586 __ mov(answer.reg(), left->reg()); |
| 1587 // Fast case - both are actually smis. |
| 1588 if (!left->number_info().IsSmi()) { |
| 1589 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 1590 __ j(not_zero, &left_nonsmi); |
| 1591 } else { |
| 1592 if (FLAG_debug_code) __ AbortIfNotSmi(left->reg()); |
| 1593 } |
| 1594 if (FLAG_debug_code) __ AbortIfNotSmi(right->reg()); |
| 1595 __ SmiUntag(answer.reg()); |
| 1596 __ jmp(&do_op); |
| 1597 |
| 1598 __ bind(&left_nonsmi); |
| 1599 // Branch if not a heapnumber. |
| 1600 __ cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset), |
| 1601 Factory::heap_number_map()); |
| 1602 deferred->Branch(not_equal); |
| 1603 |
| 1604 // Load integer value into answer register using truncation. |
| 1605 __ cvttsd2si(answer.reg(), |
| 1606 FieldOperand(answer.reg(), HeapNumber::kValueOffset)); |
| 1607 // Branch if we do not fit in a smi. |
| 1608 __ cmp(answer.reg(), 0xc0000000); |
| 1609 deferred->Branch(negative); |
| 1610 } else { |
| 1611 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), |
| 1612 left->number_info(), right->number_info(), deferred); |
| 1613 |
| 1614 // Untag both operands. |
| 1615 __ mov(answer.reg(), left->reg()); |
| 1616 __ SmiUntag(answer.reg()); |
| 1617 } |
| 1618 |
| 1619 __ bind(&do_op); |
| 1477 __ SmiUntag(ecx); | 1620 __ SmiUntag(ecx); |
| 1478 // Perform the operation. | 1621 // Perform the operation. |
| 1479 switch (op) { | 1622 switch (op) { |
| 1480 case Token::SAR: | 1623 case Token::SAR: |
| 1481 __ sar_cl(answer.reg()); | 1624 __ sar_cl(answer.reg()); |
| 1482 // No checks of result necessary | 1625 // No checks of result necessary |
| 1483 break; | 1626 break; |
| 1484 case Token::SHR: { | 1627 case Token::SHR: { |
| 1485 Label result_ok; | 1628 Label result_ok; |
| 1486 __ shr_cl(answer.reg()); | 1629 __ shr_cl(answer.reg()); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1564 // Left-hand operand has been copied into answer. | 1707 // Left-hand operand has been copied into answer. |
| 1565 __ SmiUntag(answer.reg()); | 1708 __ SmiUntag(answer.reg()); |
| 1566 // Do multiplication of smis, leaving result in answer. | 1709 // Do multiplication of smis, leaving result in answer. |
| 1567 __ imul(answer.reg(), Operand(right->reg())); | 1710 __ imul(answer.reg(), Operand(right->reg())); |
| 1568 // Go slow on overflows. | 1711 // Go slow on overflows. |
| 1569 deferred->Branch(overflow); | 1712 deferred->Branch(overflow); |
| 1570 // Check for negative zero result. If product is zero, and one | 1713 // Check for negative zero result. If product is zero, and one |
| 1571 // argument is negative, go to slow case. The frame is unchanged | 1714 // argument is negative, go to slow case. The frame is unchanged |
| 1572 // in this block, so local control flow can use a Label rather | 1715 // in this block, so local control flow can use a Label rather |
| 1573 // than a JumpTarget. | 1716 // than a JumpTarget. |
| 1574 Label non_zero_result; | 1717 if (!no_negative_zero) { |
| 1575 __ test(answer.reg(), Operand(answer.reg())); | 1718 Label non_zero_result; |
| 1576 __ j(not_zero, &non_zero_result, taken); | 1719 __ test(answer.reg(), Operand(answer.reg())); |
| 1577 __ mov(answer.reg(), left->reg()); | 1720 __ j(not_zero, &non_zero_result, taken); |
| 1578 __ or_(answer.reg(), Operand(right->reg())); | 1721 __ mov(answer.reg(), left->reg()); |
| 1579 deferred->Branch(negative); | 1722 __ or_(answer.reg(), Operand(right->reg())); |
| 1580 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct. | 1723 deferred->Branch(negative); |
| 1581 __ bind(&non_zero_result); | 1724 __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct. |
| 1725 __ bind(&non_zero_result); |
| 1726 } |
| 1582 break; | 1727 break; |
| 1583 } | 1728 } |
| 1584 | 1729 |
| 1585 case Token::BIT_OR: | 1730 case Token::BIT_OR: |
| 1586 __ or_(answer.reg(), Operand(right->reg())); | 1731 __ or_(answer.reg(), Operand(right->reg())); |
| 1587 break; | 1732 break; |
| 1588 | 1733 |
| 1589 case Token::BIT_AND: | 1734 case Token::BIT_AND: |
| 1590 __ and_(answer.reg(), Operand(right->reg())); | 1735 __ and_(answer.reg(), Operand(right->reg())); |
| 1591 break; | 1736 break; |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1810 igostub.GenerateCall(masm_, dst_, value_); | 1955 igostub.GenerateCall(masm_, dst_, value_); |
| 1811 if (!dst_.is(eax)) __ mov(dst_, eax); | 1956 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1812 } | 1957 } |
| 1813 | 1958 |
| 1814 | 1959 |
| 1815 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, | 1960 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| 1816 Result* operand, | 1961 Result* operand, |
| 1817 Handle<Object> value, | 1962 Handle<Object> value, |
| 1818 StaticType* type, | 1963 StaticType* type, |
| 1819 bool reversed, | 1964 bool reversed, |
| 1820 OverwriteMode overwrite_mode) { | 1965 OverwriteMode overwrite_mode, |
| 1966 bool no_negative_zero) { |
| 1821 // NOTE: This is an attempt to inline (a bit) more of the code for | 1967 // NOTE: This is an attempt to inline (a bit) more of the code for |
| 1822 // some possible smi operations (like + and -) when (at least) one | 1968 // some possible smi operations (like + and -) when (at least) one |
| 1823 // of the operands is a constant smi. | 1969 // of the operands is a constant smi. |
| 1824 // Consumes the argument "operand". | 1970 // Consumes the argument "operand". |
| 1825 // TODO(199): Optimize some special cases of operations involving a | 1971 // TODO(199): Optimize some special cases of operations involving a |
| 1826 // smi literal (multiply by 2, shift by 0, etc.). | 1972 // smi literal (multiply by 2, shift by 0, etc.). |
| 1827 if (IsUnsafeSmi(value)) { | 1973 if (IsUnsafeSmi(value)) { |
| 1828 Result unsafe_operand(value); | 1974 Result unsafe_operand(value); |
| 1829 if (reversed) { | 1975 if (reversed) { |
| 1830 return LikelySmiBinaryOperation(op, &unsafe_operand, operand, | 1976 return LikelySmiBinaryOperation(op, &unsafe_operand, operand, |
| 1831 overwrite_mode); | 1977 overwrite_mode, no_negative_zero); |
| 1832 } else { | 1978 } else { |
| 1833 return LikelySmiBinaryOperation(op, operand, &unsafe_operand, | 1979 return LikelySmiBinaryOperation(op, operand, &unsafe_operand, |
| 1834 overwrite_mode); | 1980 overwrite_mode, no_negative_zero); |
| 1835 } | 1981 } |
| 1836 } | 1982 } |
| 1837 | 1983 |
| 1838 // Get the literal value. | 1984 // Get the literal value. |
| 1839 Smi* smi_value = Smi::cast(*value); | 1985 Smi* smi_value = Smi::cast(*value); |
| 1840 int int_value = smi_value->value(); | 1986 int int_value = smi_value->value(); |
| 1841 | 1987 |
| 1842 Result answer; | 1988 Result answer; |
| 1843 switch (op) { | 1989 switch (op) { |
| 1844 case Token::ADD: { | 1990 case Token::ADD: { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1857 deferred = new DeferredInlineSmiAdd(operand->reg(), | 2003 deferred = new DeferredInlineSmiAdd(operand->reg(), |
| 1858 operand->number_info(), | 2004 operand->number_info(), |
| 1859 smi_value, | 2005 smi_value, |
| 1860 overwrite_mode); | 2006 overwrite_mode); |
| 1861 } | 2007 } |
| 1862 __ add(Operand(operand->reg()), Immediate(value)); | 2008 __ add(Operand(operand->reg()), Immediate(value)); |
| 1863 deferred->Branch(overflow); | 2009 deferred->Branch(overflow); |
| 1864 if (!operand->number_info().IsSmi()) { | 2010 if (!operand->number_info().IsSmi()) { |
| 1865 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2011 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1866 deferred->Branch(not_zero); | 2012 deferred->Branch(not_zero); |
| 2013 } else { |
| 2014 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 1867 } | 2015 } |
| 1868 deferred->BindExit(); | 2016 deferred->BindExit(); |
| 1869 answer = *operand; | 2017 answer = *operand; |
| 1870 break; | 2018 break; |
| 1871 } | 2019 } |
| 1872 | 2020 |
| 1873 case Token::SUB: { | 2021 case Token::SUB: { |
| 1874 DeferredCode* deferred = NULL; | 2022 DeferredCode* deferred = NULL; |
| 1875 if (reversed) { | 2023 if (reversed) { |
| 1876 // The reversed case is only hit when the right operand is not a | 2024 // The reversed case is only hit when the right operand is not a |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1894 deferred = new DeferredInlineSmiSub(operand->reg(), | 2042 deferred = new DeferredInlineSmiSub(operand->reg(), |
| 1895 operand->number_info(), | 2043 operand->number_info(), |
| 1896 smi_value, | 2044 smi_value, |
| 1897 overwrite_mode); | 2045 overwrite_mode); |
| 1898 __ sub(Operand(operand->reg()), Immediate(value)); | 2046 __ sub(Operand(operand->reg()), Immediate(value)); |
| 1899 } | 2047 } |
| 1900 deferred->Branch(overflow); | 2048 deferred->Branch(overflow); |
| 1901 if (!operand->number_info().IsSmi()) { | 2049 if (!operand->number_info().IsSmi()) { |
| 1902 __ test(answer.reg(), Immediate(kSmiTagMask)); | 2050 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 1903 deferred->Branch(not_zero); | 2051 deferred->Branch(not_zero); |
| 2052 } else { |
| 2053 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 1904 } | 2054 } |
| 1905 deferred->BindExit(); | 2055 deferred->BindExit(); |
| 1906 operand->Unuse(); | 2056 operand->Unuse(); |
| 1907 break; | 2057 break; |
| 1908 } | 2058 } |
| 1909 | 2059 |
| 1910 case Token::SAR: | 2060 case Token::SAR: |
| 1911 if (reversed) { | 2061 if (reversed) { |
| 1912 Result constant_operand(value); | 2062 Result constant_operand(value); |
| 1913 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 2063 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1914 overwrite_mode); | 2064 overwrite_mode, no_negative_zero); |
| 1915 } else { | 2065 } else { |
| 1916 // Only the least significant 5 bits of the shift value are used. | 2066 // Only the least significant 5 bits of the shift value are used. |
| 1917 // In the slow case, this masking is done inside the runtime call. | 2067 // In the slow case, this masking is done inside the runtime call. |
| 1918 int shift_value = int_value & 0x1f; | 2068 int shift_value = int_value & 0x1f; |
| 1919 operand->ToRegister(); | 2069 operand->ToRegister(); |
| 1920 frame_->Spill(operand->reg()); | 2070 frame_->Spill(operand->reg()); |
| 1921 if (!operand->number_info().IsSmi()) { | 2071 if (!operand->number_info().IsSmi()) { |
| 1922 DeferredInlineSmiOperation* deferred = | 2072 DeferredInlineSmiOperation* deferred = |
| 1923 new DeferredInlineSmiOperation(op, | 2073 new DeferredInlineSmiOperation(op, |
| 1924 operand->reg(), | 2074 operand->reg(), |
| 1925 operand->reg(), | 2075 operand->reg(), |
| 1926 operand->number_info(), | 2076 operand->number_info(), |
| 1927 smi_value, | 2077 smi_value, |
| 1928 overwrite_mode); | 2078 overwrite_mode); |
| 1929 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2079 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1930 deferred->Branch(not_zero); | 2080 deferred->Branch(not_zero); |
| 1931 if (shift_value > 0) { | 2081 if (shift_value > 0) { |
| 1932 __ sar(operand->reg(), shift_value); | 2082 __ sar(operand->reg(), shift_value); |
| 1933 __ and_(operand->reg(), ~kSmiTagMask); | 2083 __ and_(operand->reg(), ~kSmiTagMask); |
| 1934 } | 2084 } |
| 1935 deferred->BindExit(); | 2085 deferred->BindExit(); |
| 1936 } else { | 2086 } else { |
| 2087 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 1937 if (shift_value > 0) { | 2088 if (shift_value > 0) { |
| 1938 __ sar(operand->reg(), shift_value); | 2089 __ sar(operand->reg(), shift_value); |
| 1939 __ and_(operand->reg(), ~kSmiTagMask); | 2090 __ and_(operand->reg(), ~kSmiTagMask); |
| 1940 } | 2091 } |
| 1941 } | 2092 } |
| 1942 answer = *operand; | 2093 answer = *operand; |
| 1943 } | 2094 } |
| 1944 break; | 2095 break; |
| 1945 | 2096 |
| 1946 case Token::SHR: | 2097 case Token::SHR: |
| 1947 if (reversed) { | 2098 if (reversed) { |
| 1948 Result constant_operand(value); | 2099 Result constant_operand(value); |
| 1949 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 2100 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1950 overwrite_mode); | 2101 overwrite_mode, no_negative_zero); |
| 1951 } else { | 2102 } else { |
| 1952 // Only the least significant 5 bits of the shift value are used. | 2103 // Only the least significant 5 bits of the shift value are used. |
| 1953 // In the slow case, this masking is done inside the runtime call. | 2104 // In the slow case, this masking is done inside the runtime call. |
| 1954 int shift_value = int_value & 0x1f; | 2105 int shift_value = int_value & 0x1f; |
| 1955 operand->ToRegister(); | 2106 operand->ToRegister(); |
| 1956 answer = allocator()->Allocate(); | 2107 answer = allocator()->Allocate(); |
| 1957 ASSERT(answer.is_valid()); | 2108 ASSERT(answer.is_valid()); |
| 1958 DeferredInlineSmiOperation* deferred = | 2109 DeferredInlineSmiOperation* deferred = |
| 1959 new DeferredInlineSmiOperation(op, | 2110 new DeferredInlineSmiOperation(op, |
| 1960 answer.reg(), | 2111 answer.reg(), |
| 1961 operand->reg(), | 2112 operand->reg(), |
| 1962 operand->number_info(), | 2113 operand->number_info(), |
| 1963 smi_value, | 2114 smi_value, |
| 1964 overwrite_mode); | 2115 overwrite_mode); |
| 1965 if (!operand->number_info().IsSmi()) { | 2116 if (!operand->number_info().IsSmi()) { |
| 1966 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2117 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1967 deferred->Branch(not_zero); | 2118 deferred->Branch(not_zero); |
| 2119 } else { |
| 2120 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 1968 } | 2121 } |
| 1969 __ mov(answer.reg(), operand->reg()); | 2122 __ mov(answer.reg(), operand->reg()); |
| 1970 __ SmiUntag(answer.reg()); | 2123 __ SmiUntag(answer.reg()); |
| 1971 __ shr(answer.reg(), shift_value); | 2124 __ shr(answer.reg(), shift_value); |
| 1972 // A negative Smi shifted right two is in the positive Smi range. | 2125 // A negative Smi shifted right two is in the positive Smi range. |
| 1973 if (shift_value < 2) { | 2126 if (shift_value < 2) { |
| 1974 __ test(answer.reg(), Immediate(0xc0000000)); | 2127 __ test(answer.reg(), Immediate(0xc0000000)); |
| 1975 deferred->Branch(not_zero); | 2128 deferred->Branch(not_zero); |
| 1976 } | 2129 } |
| 1977 operand->Unuse(); | 2130 operand->Unuse(); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2006 new DeferredInlineSmiOperationReversed(op, | 2159 new DeferredInlineSmiOperationReversed(op, |
| 2007 answer.reg(), | 2160 answer.reg(), |
| 2008 smi_value, | 2161 smi_value, |
| 2009 right.reg(), | 2162 right.reg(), |
| 2010 right.number_info(), | 2163 right.number_info(), |
| 2011 overwrite_mode); | 2164 overwrite_mode); |
| 2012 __ mov(answer.reg(), Immediate(int_value)); | 2165 __ mov(answer.reg(), Immediate(int_value)); |
| 2013 __ sar(ecx, kSmiTagSize); | 2166 __ sar(ecx, kSmiTagSize); |
| 2014 if (!right.number_info().IsSmi()) { | 2167 if (!right.number_info().IsSmi()) { |
| 2015 deferred->Branch(carry); | 2168 deferred->Branch(carry); |
| 2169 } else { |
| 2170 if (FLAG_debug_code) __ AbortIfNotSmi(right.reg()); |
| 2016 } | 2171 } |
| 2017 __ shl_cl(answer.reg()); | 2172 __ shl_cl(answer.reg()); |
| 2018 __ cmp(answer.reg(), 0xc0000000); | 2173 __ cmp(answer.reg(), 0xc0000000); |
| 2019 deferred->Branch(sign); | 2174 deferred->Branch(sign); |
| 2020 __ SmiTag(answer.reg()); | 2175 __ SmiTag(answer.reg()); |
| 2021 | 2176 |
| 2022 deferred->BindExit(); | 2177 deferred->BindExit(); |
| 2023 } else { | 2178 } else { |
| 2024 // Only the least significant 5 bits of the shift value are used. | 2179 // Only the least significant 5 bits of the shift value are used. |
| 2025 // In the slow case, this masking is done inside the runtime call. | 2180 // In the slow case, this masking is done inside the runtime call. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2046 DeferredInlineSmiOperation* deferred = | 2201 DeferredInlineSmiOperation* deferred = |
| 2047 new DeferredInlineSmiOperation(op, | 2202 new DeferredInlineSmiOperation(op, |
| 2048 answer.reg(), | 2203 answer.reg(), |
| 2049 operand->reg(), | 2204 operand->reg(), |
| 2050 operand->number_info(), | 2205 operand->number_info(), |
| 2051 smi_value, | 2206 smi_value, |
| 2052 overwrite_mode); | 2207 overwrite_mode); |
| 2053 if (!operand->number_info().IsSmi()) { | 2208 if (!operand->number_info().IsSmi()) { |
| 2054 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2209 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2055 deferred->Branch(not_zero); | 2210 deferred->Branch(not_zero); |
| 2211 } else { |
| 2212 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 2056 } | 2213 } |
| 2057 __ mov(answer.reg(), operand->reg()); | 2214 __ mov(answer.reg(), operand->reg()); |
| 2058 ASSERT(kSmiTag == 0); // adjust code if not the case | 2215 ASSERT(kSmiTag == 0); // adjust code if not the case |
| 2059 // We do no shifts, only the Smi conversion, if shift_value is 1. | 2216 // We do no shifts, only the Smi conversion, if shift_value is 1. |
| 2060 if (shift_value > 1) { | 2217 if (shift_value > 1) { |
| 2061 __ shl(answer.reg(), shift_value - 1); | 2218 __ shl(answer.reg(), shift_value - 1); |
| 2062 } | 2219 } |
| 2063 // Convert int result to Smi, checking that it is in int range. | 2220 // Convert int result to Smi, checking that it is in int range. |
| 2064 ASSERT(kSmiTagSize == 1); // adjust code if not the case | 2221 ASSERT(kSmiTagSize == 1); // adjust code if not the case |
| 2065 __ add(answer.reg(), Operand(answer.reg())); | 2222 __ add(answer.reg(), Operand(answer.reg())); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2088 deferred = new DeferredInlineSmiOperation(op, | 2245 deferred = new DeferredInlineSmiOperation(op, |
| 2089 operand->reg(), | 2246 operand->reg(), |
| 2090 operand->reg(), | 2247 operand->reg(), |
| 2091 operand->number_info(), | 2248 operand->number_info(), |
| 2092 smi_value, | 2249 smi_value, |
| 2093 overwrite_mode); | 2250 overwrite_mode); |
| 2094 } | 2251 } |
| 2095 if (!operand->number_info().IsSmi()) { | 2252 if (!operand->number_info().IsSmi()) { |
| 2096 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2253 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2097 deferred->Branch(not_zero); | 2254 deferred->Branch(not_zero); |
| 2255 } else { |
| 2256 if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg()); |
| 2098 } | 2257 } |
| 2099 if (op == Token::BIT_AND) { | 2258 if (op == Token::BIT_AND) { |
| 2100 __ and_(Operand(operand->reg()), Immediate(value)); | 2259 __ and_(Operand(operand->reg()), Immediate(value)); |
| 2101 } else if (op == Token::BIT_XOR) { | 2260 } else if (op == Token::BIT_XOR) { |
| 2102 if (int_value != 0) { | 2261 if (int_value != 0) { |
| 2103 __ xor_(Operand(operand->reg()), Immediate(value)); | 2262 __ xor_(Operand(operand->reg()), Immediate(value)); |
| 2104 } | 2263 } |
| 2105 } else { | 2264 } else { |
| 2106 ASSERT(op == Token::BIT_OR); | 2265 ASSERT(op == Token::BIT_OR); |
| 2107 if (int_value != 0) { | 2266 if (int_value != 0) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2133 deferred->Branch(not_zero); // Branch if non-smi or odd smi. | 2292 deferred->Branch(not_zero); // Branch if non-smi or odd smi. |
| 2134 __ sar(operand->reg(), 1); | 2293 __ sar(operand->reg(), 1); |
| 2135 deferred->BindExit(); | 2294 deferred->BindExit(); |
| 2136 answer = *operand; | 2295 answer = *operand; |
| 2137 } else { | 2296 } else { |
| 2138 // Cannot fall through MOD to default case, so we duplicate the | 2297 // Cannot fall through MOD to default case, so we duplicate the |
| 2139 // default case here. | 2298 // default case here. |
| 2140 Result constant_operand(value); | 2299 Result constant_operand(value); |
| 2141 if (reversed) { | 2300 if (reversed) { |
| 2142 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 2301 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 2143 overwrite_mode); | 2302 overwrite_mode, no_negative_zero); |
| 2144 } else { | 2303 } else { |
| 2145 answer = LikelySmiBinaryOperation(op, operand, &constant_operand, | 2304 answer = LikelySmiBinaryOperation(op, operand, &constant_operand, |
| 2146 overwrite_mode); | 2305 overwrite_mode, no_negative_zero); |
| 2147 } | 2306 } |
| 2148 } | 2307 } |
| 2149 break; | 2308 break; |
| 2150 // Generate inline code for mod of powers of 2 and negative powers of 2. | 2309 // Generate inline code for mod of powers of 2 and negative powers of 2. |
| 2151 case Token::MOD: | 2310 case Token::MOD: |
| 2152 if (!reversed && | 2311 if (!reversed && |
| 2153 int_value != 0 && | 2312 int_value != 0 && |
| 2154 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { | 2313 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { |
| 2155 operand->ToRegister(); | 2314 operand->ToRegister(); |
| 2156 frame_->Spill(operand->reg()); | 2315 frame_->Spill(operand->reg()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2173 deferred->BindExit(); | 2332 deferred->BindExit(); |
| 2174 answer = *operand; | 2333 answer = *operand; |
| 2175 break; | 2334 break; |
| 2176 } | 2335 } |
| 2177 // Fall through if we did not find a power of 2 on the right hand side! | 2336 // Fall through if we did not find a power of 2 on the right hand side! |
| 2178 | 2337 |
| 2179 default: { | 2338 default: { |
| 2180 Result constant_operand(value); | 2339 Result constant_operand(value); |
| 2181 if (reversed) { | 2340 if (reversed) { |
| 2182 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 2341 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 2183 overwrite_mode); | 2342 overwrite_mode, no_negative_zero); |
| 2184 } else { | 2343 } else { |
| 2185 answer = LikelySmiBinaryOperation(op, operand, &constant_operand, | 2344 answer = LikelySmiBinaryOperation(op, operand, &constant_operand, |
| 2186 overwrite_mode); | 2345 overwrite_mode, no_negative_zero); |
| 2187 } | 2346 } |
| 2188 break; | 2347 break; |
| 2189 } | 2348 } |
| 2190 } | 2349 } |
| 2191 ASSERT(answer.is_valid()); | 2350 ASSERT(answer.is_valid()); |
| 2192 return answer; | 2351 return answer; |
| 2193 } | 2352 } |
| 2194 | 2353 |
| 2195 | 2354 |
| 2196 static bool CouldBeNaN(const Result& result) { | 2355 static bool CouldBeNaN(const Result& result) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2279 // where both sides are Smis. | 2438 // where both sides are Smis. |
| 2280 left_side.ToRegister(); | 2439 left_side.ToRegister(); |
| 2281 Register left_reg = left_side.reg(); | 2440 Register left_reg = left_side.reg(); |
| 2282 Handle<Object> right_val = right_side.handle(); | 2441 Handle<Object> right_val = right_side.handle(); |
| 2283 | 2442 |
| 2284 // Here we split control flow to the stub call and inlined cases | 2443 // Here we split control flow to the stub call and inlined cases |
| 2285 // before finally splitting it to the control destination. We use | 2444 // before finally splitting it to the control destination. We use |
| 2286 // a jump target and branching to duplicate the virtual frame at | 2445 // a jump target and branching to duplicate the virtual frame at |
| 2287 // the first split. We manually handle the off-frame references | 2446 // the first split. We manually handle the off-frame references |
| 2288 // by reconstituting them on the non-fall-through path. | 2447 // by reconstituting them on the non-fall-through path. |
| 2289 JumpTarget is_smi; | |
| 2290 __ test(left_side.reg(), Immediate(kSmiTagMask)); | |
| 2291 is_smi.Branch(zero, taken); | |
| 2292 | 2448 |
| 2293 bool is_for_loop_compare = (node->AsCompareOperation() != NULL) | 2449 if (left_side.is_smi()) { |
| 2294 && node->AsCompareOperation()->is_for_loop_condition(); | 2450 if (FLAG_debug_code) __ AbortIfNotSmi(left_side.reg()); |
| 2295 if (!is_for_loop_compare | 2451 } else { |
| 2296 && CpuFeatures::IsSupported(SSE2) | 2452 JumpTarget is_smi; |
| 2297 && right_val->IsSmi()) { | 2453 __ test(left_side.reg(), Immediate(kSmiTagMask)); |
| 2298 // Right side is a constant smi and left side has been checked | 2454 is_smi.Branch(zero, taken); |
| 2299 // not to be a smi. | 2455 |
| 2300 CpuFeatures::Scope use_sse2(SSE2); | 2456 bool is_for_loop_compare = (node->AsCompareOperation() != NULL) |
| 2301 JumpTarget not_number; | 2457 && node->AsCompareOperation()->is_for_loop_condition(); |
| 2302 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), | 2458 if (!is_for_loop_compare |
| 2303 Immediate(Factory::heap_number_map())); | 2459 && CpuFeatures::IsSupported(SSE2) |
| 2304 not_number.Branch(not_equal, &left_side); | 2460 && right_val->IsSmi()) { |
| 2305 __ movdbl(xmm1, | 2461 // Right side is a constant smi and left side has been checked |
| 2306 FieldOperand(left_reg, HeapNumber::kValueOffset)); | 2462 // not to be a smi. |
| 2307 int value = Smi::cast(*right_val)->value(); | 2463 CpuFeatures::Scope use_sse2(SSE2); |
| 2308 if (value == 0) { | 2464 JumpTarget not_number; |
| 2309 __ xorpd(xmm0, xmm0); | 2465 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), |
| 2310 } else { | 2466 Immediate(Factory::heap_number_map())); |
| 2311 Result temp = allocator()->Allocate(); | 2467 not_number.Branch(not_equal, &left_side); |
| 2312 __ mov(temp.reg(), Immediate(value)); | 2468 __ movdbl(xmm1, |
| 2313 __ cvtsi2sd(xmm0, Operand(temp.reg())); | 2469 FieldOperand(left_reg, HeapNumber::kValueOffset)); |
| 2314 temp.Unuse(); | 2470 int value = Smi::cast(*right_val)->value(); |
| 2471 if (value == 0) { |
| 2472 __ xorpd(xmm0, xmm0); |
| 2473 } else { |
| 2474 Result temp = allocator()->Allocate(); |
| 2475 __ mov(temp.reg(), Immediate(value)); |
| 2476 __ cvtsi2sd(xmm0, Operand(temp.reg())); |
| 2477 temp.Unuse(); |
| 2478 } |
| 2479 __ comisd(xmm1, xmm0); |
| 2480 // Jump to builtin for NaN. |
| 2481 not_number.Branch(parity_even, &left_side); |
| 2482 left_side.Unuse(); |
| 2483 Condition double_cc = cc; |
| 2484 switch (cc) { |
| 2485 case less: double_cc = below; break; |
| 2486 case equal: double_cc = equal; break; |
| 2487 case less_equal: double_cc = below_equal; break; |
| 2488 case greater: double_cc = above; break; |
| 2489 case greater_equal: double_cc = above_equal; break; |
| 2490 default: UNREACHABLE(); |
| 2491 } |
| 2492 dest->true_target()->Branch(double_cc); |
| 2493 dest->false_target()->Jump(); |
| 2494 not_number.Bind(&left_side); |
| 2315 } | 2495 } |
| 2316 __ comisd(xmm1, xmm0); | 2496 |
| 2317 // Jump to builtin for NaN. | 2497 // Setup and call the compare stub. |
| 2318 not_number.Branch(parity_even, &left_side); | 2498 CompareStub stub(cc, strict, kCantBothBeNaN); |
| 2319 left_side.Unuse(); | 2499 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
| 2320 Condition double_cc = cc; | 2500 result.ToRegister(); |
| 2321 switch (cc) { | 2501 __ cmp(result.reg(), 0); |
| 2322 case less: double_cc = below; break; | 2502 result.Unuse(); |
| 2323 case equal: double_cc = equal; break; | 2503 dest->true_target()->Branch(cc); |
| 2324 case less_equal: double_cc = below_equal; break; | |
| 2325 case greater: double_cc = above; break; | |
| 2326 case greater_equal: double_cc = above_equal; break; | |
| 2327 default: UNREACHABLE(); | |
| 2328 } | |
| 2329 dest->true_target()->Branch(double_cc); | |
| 2330 dest->false_target()->Jump(); | 2504 dest->false_target()->Jump(); |
| 2331 not_number.Bind(&left_side); | 2505 |
| 2506 is_smi.Bind(); |
| 2332 } | 2507 } |
| 2333 | 2508 |
| 2334 // Setup and call the compare stub. | |
| 2335 CompareStub stub(cc, strict, kCantBothBeNaN); | |
| 2336 Result result = frame_->CallStub(&stub, &left_side, &right_side); | |
| 2337 result.ToRegister(); | |
| 2338 __ cmp(result.reg(), 0); | |
| 2339 result.Unuse(); | |
| 2340 dest->true_target()->Branch(cc); | |
| 2341 dest->false_target()->Jump(); | |
| 2342 | |
| 2343 is_smi.Bind(); | |
| 2344 left_side = Result(left_reg); | 2509 left_side = Result(left_reg); |
| 2345 right_side = Result(right_val); | 2510 right_side = Result(right_val); |
| 2346 // Test smi equality and comparison by signed int comparison. | 2511 // Test smi equality and comparison by signed int comparison. |
| 2347 if (IsUnsafeSmi(right_side.handle())) { | 2512 if (IsUnsafeSmi(right_side.handle())) { |
| 2348 right_side.ToRegister(); | 2513 right_side.ToRegister(); |
| 2349 __ cmp(left_side.reg(), Operand(right_side.reg())); | 2514 __ cmp(left_side.reg(), Operand(right_side.reg())); |
| 2350 } else { | 2515 } else { |
| 2351 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle())); | 2516 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle())); |
| 2352 } | 2517 } |
| 2353 left_side.Unuse(); | 2518 left_side.Unuse(); |
| (...skipping 1126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3480 | 3645 |
| 3481 // The break target may be already bound (by the condition), or there | 3646 // The break target may be already bound (by the condition), or there |
| 3482 // may not be a valid frame. Bind it only if needed. | 3647 // may not be a valid frame. Bind it only if needed. |
| 3483 if (node->break_target()->is_linked()) { | 3648 if (node->break_target()->is_linked()) { |
| 3484 node->break_target()->Bind(); | 3649 node->break_target()->Bind(); |
| 3485 } | 3650 } |
| 3486 DecrementLoopNesting(); | 3651 DecrementLoopNesting(); |
| 3487 } | 3652 } |
| 3488 | 3653 |
| 3489 | 3654 |
| 3655 void CodeGenerator::SetTypeForStackSlot(Slot* slot, NumberInfo info) { |
| 3656 ASSERT(slot->type() == Slot::LOCAL || slot->type() == Slot::PARAMETER); |
| 3657 if (slot->type() == Slot::LOCAL) { |
| 3658 frame_->SetTypeForLocalAt(slot->index(), info); |
| 3659 } else { |
| 3660 frame_->SetTypeForParamAt(slot->index(), info); |
| 3661 } |
| 3662 if (FLAG_debug_code && info.IsSmi()) { |
| 3663 if (slot->type() == Slot::LOCAL) { |
| 3664 frame_->PushLocalAt(slot->index()); |
| 3665 } else { |
| 3666 frame_->PushParameterAt(slot->index()); |
| 3667 } |
| 3668 Result var = frame_->Pop(); |
| 3669 var.ToRegister(); |
| 3670 __ AbortIfNotSmi(var.reg()); |
| 3671 } |
| 3672 } |
| 3673 |
| 3674 |
| 3490 void CodeGenerator::VisitForStatement(ForStatement* node) { | 3675 void CodeGenerator::VisitForStatement(ForStatement* node) { |
| 3491 ASSERT(!in_spilled_code()); | 3676 ASSERT(!in_spilled_code()); |
| 3492 Comment cmnt(masm_, "[ ForStatement"); | 3677 Comment cmnt(masm_, "[ ForStatement"); |
| 3493 CodeForStatementPosition(node); | 3678 CodeForStatementPosition(node); |
| 3494 | 3679 |
| 3495 // Compile the init expression if present. | 3680 // Compile the init expression if present. |
| 3496 if (node->init() != NULL) { | 3681 if (node->init() != NULL) { |
| 3497 Visit(node->init()); | 3682 Visit(node->init()); |
| 3498 } | 3683 } |
| 3499 | 3684 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3572 body.Bind(); | 3757 body.Bind(); |
| 3573 } | 3758 } |
| 3574 break; | 3759 break; |
| 3575 } | 3760 } |
| 3576 case ALWAYS_FALSE: | 3761 case ALWAYS_FALSE: |
| 3577 UNREACHABLE(); | 3762 UNREACHABLE(); |
| 3578 break; | 3763 break; |
| 3579 } | 3764 } |
| 3580 | 3765 |
| 3581 CheckStack(); // TODO(1222600): ignore if body contains calls. | 3766 CheckStack(); // TODO(1222600): ignore if body contains calls. |
| 3767 |
| 3768 // We know that the loop index is a smi if it is not modified in the |
| 3769 // loop body and it is checked against a constant limit in the loop |
| 3770 // condition. In this case, we reset the static type information of the |
| 3771 // loop index to smi before compiling the body, the update expression, and |
| 3772 // the bottom check of the loop condition. |
| 3773 if (node->is_fast_smi_loop()) { |
| 3774 // Set number type of the loop variable to smi. |
| 3775 SetTypeForStackSlot(node->loop_variable()->slot(), NumberInfo::Smi()); |
| 3776 } |
| 3777 |
| 3582 Visit(node->body()); | 3778 Visit(node->body()); |
| 3583 | 3779 |
| 3584 // If there is an update expression, compile it if necessary. | 3780 // If there is an update expression, compile it if necessary. |
| 3585 if (node->next() != NULL) { | 3781 if (node->next() != NULL) { |
| 3586 if (node->continue_target()->is_linked()) { | 3782 if (node->continue_target()->is_linked()) { |
| 3587 node->continue_target()->Bind(); | 3783 node->continue_target()->Bind(); |
| 3588 } | 3784 } |
| 3589 | 3785 |
| 3590 // Control can reach the update by falling out of the body or by a | 3786 // Control can reach the update by falling out of the body or by a |
| 3591 // continue. | 3787 // continue. |
| 3592 if (has_valid_frame()) { | 3788 if (has_valid_frame()) { |
| 3593 // Record the source position of the statement as this code which | 3789 // Record the source position of the statement as this code which |
| 3594 // is after the code for the body actually belongs to the loop | 3790 // is after the code for the body actually belongs to the loop |
| 3595 // statement and not the body. | 3791 // statement and not the body. |
| 3596 CodeForStatementPosition(node); | 3792 CodeForStatementPosition(node); |
| 3597 Visit(node->next()); | 3793 Visit(node->next()); |
| 3598 } | 3794 } |
| 3599 } | 3795 } |
| 3600 | 3796 |
| 3797 // Set the type of the loop variable to smi before compiling the test |
| 3798 // expression if we are in a fast smi loop condition. |
| 3799 if (node->is_fast_smi_loop() && has_valid_frame()) { |
| 3800 // Set number type of the loop variable to smi. |
| 3801 SetTypeForStackSlot(node->loop_variable()->slot(), NumberInfo::Smi()); |
| 3802 } |
| 3803 |
| 3601 // Based on the condition analysis, compile the backward jump as | 3804 // Based on the condition analysis, compile the backward jump as |
| 3602 // necessary. | 3805 // necessary. |
| 3603 switch (info) { | 3806 switch (info) { |
| 3604 case ALWAYS_TRUE: | 3807 case ALWAYS_TRUE: |
| 3605 if (has_valid_frame()) { | 3808 if (has_valid_frame()) { |
| 3606 if (node->next() == NULL) { | 3809 if (node->next() == NULL) { |
| 3607 node->continue_target()->Jump(); | 3810 node->continue_target()->Jump(); |
| 3608 } else { | 3811 } else { |
| 3609 loop.Jump(); | 3812 loop.Jump(); |
| 3610 } | 3813 } |
| (...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4237 // object. | 4440 // object. |
| 4238 frame()->EmitPush(esi); | 4441 frame()->EmitPush(esi); |
| 4239 frame()->EmitPush(Immediate(boilerplate)); | 4442 frame()->EmitPush(Immediate(boilerplate)); |
| 4240 return frame()->CallRuntime(Runtime::kNewClosure, 2); | 4443 return frame()->CallRuntime(Runtime::kNewClosure, 2); |
| 4241 } | 4444 } |
| 4242 } | 4445 } |
| 4243 | 4446 |
| 4244 | 4447 |
| 4245 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 4448 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
| 4246 Comment cmnt(masm_, "[ FunctionLiteral"); | 4449 Comment cmnt(masm_, "[ FunctionLiteral"); |
| 4247 | 4450 ASSERT(!in_safe_int32_mode()); |
| 4248 // Build the function boilerplate and instantiate it. | 4451 // Build the function boilerplate and instantiate it. |
| 4249 Handle<JSFunction> boilerplate = | 4452 Handle<JSFunction> boilerplate = |
| 4250 Compiler::BuildBoilerplate(node, script(), this); | 4453 Compiler::BuildBoilerplate(node, script(), this); |
| 4251 // Check for stack-overflow exception. | 4454 // Check for stack-overflow exception. |
| 4252 if (HasStackOverflow()) return; | 4455 if (HasStackOverflow()) return; |
| 4253 Result result = InstantiateBoilerplate(boilerplate); | 4456 Result result = InstantiateBoilerplate(boilerplate); |
| 4254 frame()->Push(&result); | 4457 frame()->Push(&result); |
| 4255 } | 4458 } |
| 4256 | 4459 |
| 4257 | 4460 |
| 4258 void CodeGenerator::VisitFunctionBoilerplateLiteral( | 4461 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
| 4259 FunctionBoilerplateLiteral* node) { | 4462 FunctionBoilerplateLiteral* node) { |
| 4463 ASSERT(!in_safe_int32_mode()); |
| 4260 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 4464 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
| 4261 Result result = InstantiateBoilerplate(node->boilerplate()); | 4465 Result result = InstantiateBoilerplate(node->boilerplate()); |
| 4262 frame()->Push(&result); | 4466 frame()->Push(&result); |
| 4263 } | 4467 } |
| 4264 | 4468 |
| 4265 | 4469 |
| 4266 void CodeGenerator::VisitConditional(Conditional* node) { | 4470 void CodeGenerator::VisitConditional(Conditional* node) { |
| 4267 Comment cmnt(masm_, "[ Conditional"); | 4471 Comment cmnt(masm_, "[ Conditional"); |
| 4472 ASSERT(!in_safe_int32_mode()); |
| 4268 JumpTarget then; | 4473 JumpTarget then; |
| 4269 JumpTarget else_; | 4474 JumpTarget else_; |
| 4270 JumpTarget exit; | 4475 JumpTarget exit; |
| 4271 ControlDestination dest(&then, &else_, true); | 4476 ControlDestination dest(&then, &else_, true); |
| 4272 LoadCondition(node->condition(), &dest, true); | 4477 LoadCondition(node->condition(), &dest, true); |
| 4273 | 4478 |
| 4274 if (dest.false_was_fall_through()) { | 4479 if (dest.false_was_fall_through()) { |
| 4275 // The else target was bound, so we compile the else part first. | 4480 // The else target was bound, so we compile the else part first. |
| 4276 Load(node->else_expression()); | 4481 Load(node->else_expression()); |
| 4277 | 4482 |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4428 result = StoreArgumentsObject(false); | 4633 result = StoreArgumentsObject(false); |
| 4429 exit.Bind(&result); | 4634 exit.Bind(&result); |
| 4430 return result; | 4635 return result; |
| 4431 } | 4636 } |
| 4432 | 4637 |
| 4433 | 4638 |
| 4434 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( | 4639 Result CodeGenerator::LoadFromGlobalSlotCheckExtensions( |
| 4435 Slot* slot, | 4640 Slot* slot, |
| 4436 TypeofState typeof_state, | 4641 TypeofState typeof_state, |
| 4437 JumpTarget* slow) { | 4642 JumpTarget* slow) { |
| 4643 ASSERT(!in_safe_int32_mode()); |
| 4438 // Check that no extension objects have been created by calls to | 4644 // Check that no extension objects have been created by calls to |
| 4439 // eval from the current scope to the global scope. | 4645 // eval from the current scope to the global scope. |
| 4440 Register context = esi; | 4646 Register context = esi; |
| 4441 Result tmp = allocator_->Allocate(); | 4647 Result tmp = allocator_->Allocate(); |
| 4442 ASSERT(tmp.is_valid()); // All non-reserved registers were available. | 4648 ASSERT(tmp.is_valid()); // All non-reserved registers were available. |
| 4443 | 4649 |
| 4444 Scope* s = scope(); | 4650 Scope* s = scope(); |
| 4445 while (s != NULL) { | 4651 while (s != NULL) { |
| 4446 if (s->num_heap_slots() > 0) { | 4652 if (s->num_heap_slots() > 0) { |
| 4447 if (s->calls_eval()) { | 4653 if (s->calls_eval()) { |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4596 __ RecordWrite(start.reg(), offset, value.reg(), temp.reg()); | 4802 __ RecordWrite(start.reg(), offset, value.reg(), temp.reg()); |
| 4597 // The results start, value, and temp are unused by going out of | 4803 // The results start, value, and temp are unused by going out of |
| 4598 // scope. | 4804 // scope. |
| 4599 } | 4805 } |
| 4600 | 4806 |
| 4601 exit.Bind(); | 4807 exit.Bind(); |
| 4602 } | 4808 } |
| 4603 } | 4809 } |
| 4604 | 4810 |
| 4605 | 4811 |
| 4606 void CodeGenerator::VisitSlot(Slot* node) { | 4812 void CodeGenerator::VisitSlot(Slot* slot) { |
| 4607 Comment cmnt(masm_, "[ Slot"); | 4813 Comment cmnt(masm_, "[ Slot"); |
| 4608 Result result = LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF); | 4814 if (in_safe_int32_mode()) { |
| 4609 frame()->Push(&result); | 4815 if ((slot->type() == Slot::LOCAL && !slot->is_arguments())) { |
| 4816 frame()->UntaggedPushLocalAt(slot->index()); |
| 4817 } else if (slot->type() == Slot::PARAMETER) { |
| 4818 frame()->UntaggedPushParameterAt(slot->index()); |
| 4819 } else { |
| 4820 UNREACHABLE(); |
| 4821 } |
| 4822 } else { |
| 4823 Result result = LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); |
| 4824 frame()->Push(&result); |
| 4825 } |
| 4610 } | 4826 } |
| 4611 | 4827 |
| 4612 | 4828 |
| 4613 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 4829 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
| 4614 Comment cmnt(masm_, "[ VariableProxy"); | 4830 Comment cmnt(masm_, "[ VariableProxy"); |
| 4615 Variable* var = node->var(); | 4831 Variable* var = node->var(); |
| 4616 Expression* expr = var->rewrite(); | 4832 Expression* expr = var->rewrite(); |
| 4617 if (expr != NULL) { | 4833 if (expr != NULL) { |
| 4618 Visit(expr); | 4834 Visit(expr); |
| 4619 } else { | 4835 } else { |
| 4620 ASSERT(var->is_global()); | 4836 ASSERT(var->is_global()); |
| 4837 ASSERT(!in_safe_int32_mode()); |
| 4621 Reference ref(this, node); | 4838 Reference ref(this, node); |
| 4622 ref.GetValue(); | 4839 ref.GetValue(); |
| 4623 } | 4840 } |
| 4624 } | 4841 } |
| 4625 | 4842 |
| 4626 | 4843 |
| 4627 void CodeGenerator::VisitLiteral(Literal* node) { | 4844 void CodeGenerator::VisitLiteral(Literal* node) { |
| 4628 Comment cmnt(masm_, "[ Literal"); | 4845 Comment cmnt(masm_, "[ Literal"); |
| 4629 frame_->Push(node->handle()); | 4846 if (in_safe_int32_mode()) { |
| 4847 frame_->PushUntaggedElement(node->handle()); |
| 4848 } else { |
| 4849 frame_->Push(node->handle()); |
| 4850 } |
| 4630 } | 4851 } |
| 4631 | 4852 |
| 4632 | 4853 |
| 4633 void CodeGenerator::PushUnsafeSmi(Handle<Object> value) { | 4854 void CodeGenerator::PushUnsafeSmi(Handle<Object> value) { |
| 4634 ASSERT(value->IsSmi()); | 4855 ASSERT(value->IsSmi()); |
| 4635 int bits = reinterpret_cast<int>(*value); | 4856 int bits = reinterpret_cast<int>(*value); |
| 4636 __ push(Immediate(bits & 0x0000FFFF)); | 4857 __ push(Immediate(bits & 0x0000FFFF)); |
| 4637 __ or_(Operand(esp, 0), Immediate(bits & 0xFFFF0000)); | 4858 __ or_(Operand(esp, 0), Immediate(bits & 0xFFFF0000)); |
| 4638 } | 4859 } |
| 4639 | 4860 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4693 // RegExp pattern (2). | 4914 // RegExp pattern (2). |
| 4694 __ push(Immediate(node_->pattern())); | 4915 __ push(Immediate(node_->pattern())); |
| 4695 // RegExp flags (3). | 4916 // RegExp flags (3). |
| 4696 __ push(Immediate(node_->flags())); | 4917 __ push(Immediate(node_->flags())); |
| 4697 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 4918 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| 4698 if (!boilerplate_.is(eax)) __ mov(boilerplate_, eax); | 4919 if (!boilerplate_.is(eax)) __ mov(boilerplate_, eax); |
| 4699 } | 4920 } |
| 4700 | 4921 |
| 4701 | 4922 |
| 4702 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 4923 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
| 4924 ASSERT(!in_safe_int32_mode()); |
| 4703 Comment cmnt(masm_, "[ RegExp Literal"); | 4925 Comment cmnt(masm_, "[ RegExp Literal"); |
| 4704 | 4926 |
| 4705 // Retrieve the literals array and check the allocated entry. Begin | 4927 // Retrieve the literals array and check the allocated entry. Begin |
| 4706 // with a writable copy of the function of this activation in a | 4928 // with a writable copy of the function of this activation in a |
| 4707 // register. | 4929 // register. |
| 4708 frame_->PushFunction(); | 4930 frame_->PushFunction(); |
| 4709 Result literals = frame_->Pop(); | 4931 Result literals = frame_->Pop(); |
| 4710 literals.ToRegister(); | 4932 literals.ToRegister(); |
| 4711 frame_->Spill(literals.reg()); | 4933 frame_->Spill(literals.reg()); |
| 4712 | 4934 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 4729 deferred->Branch(equal); | 4951 deferred->Branch(equal); |
| 4730 deferred->BindExit(); | 4952 deferred->BindExit(); |
| 4731 literals.Unuse(); | 4953 literals.Unuse(); |
| 4732 | 4954 |
| 4733 // Push the boilerplate object. | 4955 // Push the boilerplate object. |
| 4734 frame_->Push(&boilerplate); | 4956 frame_->Push(&boilerplate); |
| 4735 } | 4957 } |
| 4736 | 4958 |
| 4737 | 4959 |
| 4738 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 4960 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
| 4961 ASSERT(!in_safe_int32_mode()); |
| 4739 Comment cmnt(masm_, "[ ObjectLiteral"); | 4962 Comment cmnt(masm_, "[ ObjectLiteral"); |
| 4740 | 4963 |
| 4741 // Load a writable copy of the function of this activation in a | 4964 // Load a writable copy of the function of this activation in a |
| 4742 // register. | 4965 // register. |
| 4743 frame_->PushFunction(); | 4966 frame_->PushFunction(); |
| 4744 Result literals = frame_->Pop(); | 4967 Result literals = frame_->Pop(); |
| 4745 literals.ToRegister(); | 4968 literals.ToRegister(); |
| 4746 frame_->Spill(literals.reg()); | 4969 frame_->Spill(literals.reg()); |
| 4747 | 4970 |
| 4748 // Load the literals array of the function. | 4971 // Load the literals array of the function. |
| 4749 __ mov(literals.reg(), | 4972 __ mov(literals.reg(), |
| 4750 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); | 4973 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); |
| 4751 // Literal array. | 4974 // Literal array. |
| 4752 frame_->Push(&literals); | 4975 frame_->Push(&literals); |
| 4753 // Literal index. | 4976 // Literal index. |
| 4754 frame_->Push(Smi::FromInt(node->literal_index())); | 4977 frame_->Push(Smi::FromInt(node->literal_index())); |
| 4755 // Constant properties. | 4978 // Constant properties. |
| 4756 frame_->Push(node->constant_properties()); | 4979 frame_->Push(node->constant_properties()); |
| 4980 // Should the object literal have fast elements? |
| 4981 frame_->Push(Smi::FromInt(node->fast_elements() ? 1 : 0)); |
| 4757 Result clone; | 4982 Result clone; |
| 4758 if (node->depth() > 1) { | 4983 if (node->depth() > 1) { |
| 4759 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3); | 4984 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4); |
| 4760 } else { | 4985 } else { |
| 4761 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3); | 4986 clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4); |
| 4762 } | 4987 } |
| 4763 frame_->Push(&clone); | 4988 frame_->Push(&clone); |
| 4764 | 4989 |
| 4765 for (int i = 0; i < node->properties()->length(); i++) { | 4990 for (int i = 0; i < node->properties()->length(); i++) { |
| 4766 ObjectLiteral::Property* property = node->properties()->at(i); | 4991 ObjectLiteral::Property* property = node->properties()->at(i); |
| 4767 switch (property->kind()) { | 4992 switch (property->kind()) { |
| 4768 case ObjectLiteral::Property::CONSTANT: | 4993 case ObjectLiteral::Property::CONSTANT: |
| 4769 break; | 4994 break; |
| 4770 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 4995 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 4771 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; | 4996 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4811 // Ignore the result. | 5036 // Ignore the result. |
| 4812 break; | 5037 break; |
| 4813 } | 5038 } |
| 4814 default: UNREACHABLE(); | 5039 default: UNREACHABLE(); |
| 4815 } | 5040 } |
| 4816 } | 5041 } |
| 4817 } | 5042 } |
| 4818 | 5043 |
| 4819 | 5044 |
| 4820 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 5045 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
| 5046 ASSERT(!in_safe_int32_mode()); |
| 4821 Comment cmnt(masm_, "[ ArrayLiteral"); | 5047 Comment cmnt(masm_, "[ ArrayLiteral"); |
| 4822 | 5048 |
| 4823 // Load a writable copy of the function of this activation in a | 5049 // Load a writable copy of the function of this activation in a |
| 4824 // register. | 5050 // register. |
| 4825 frame_->PushFunction(); | 5051 frame_->PushFunction(); |
| 4826 Result literals = frame_->Pop(); | 5052 Result literals = frame_->Pop(); |
| 4827 literals.ToRegister(); | 5053 literals.ToRegister(); |
| 4828 frame_->Spill(literals.reg()); | 5054 frame_->Spill(literals.reg()); |
| 4829 | 5055 |
| 4830 // Load the literals array of the function. | 5056 // Load the literals array of the function. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4882 // Update the write barrier for the array address. | 5108 // Update the write barrier for the array address. |
| 4883 frame_->Spill(prop_value.reg()); // Overwritten by the write barrier. | 5109 frame_->Spill(prop_value.reg()); // Overwritten by the write barrier. |
| 4884 Result scratch = allocator_->Allocate(); | 5110 Result scratch = allocator_->Allocate(); |
| 4885 ASSERT(scratch.is_valid()); | 5111 ASSERT(scratch.is_valid()); |
| 4886 __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg()); | 5112 __ RecordWrite(elements.reg(), offset, prop_value.reg(), scratch.reg()); |
| 4887 } | 5113 } |
| 4888 } | 5114 } |
| 4889 | 5115 |
| 4890 | 5116 |
| 4891 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { | 5117 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { |
| 5118 ASSERT(!in_safe_int32_mode()); |
| 4892 ASSERT(!in_spilled_code()); | 5119 ASSERT(!in_spilled_code()); |
| 4893 // Call runtime routine to allocate the catch extension object and | 5120 // Call runtime routine to allocate the catch extension object and |
| 4894 // assign the exception value to the catch variable. | 5121 // assign the exception value to the catch variable. |
| 4895 Comment cmnt(masm_, "[ CatchExtensionObject"); | 5122 Comment cmnt(masm_, "[ CatchExtensionObject"); |
| 4896 Load(node->key()); | 5123 Load(node->key()); |
| 4897 Load(node->value()); | 5124 Load(node->value()); |
| 4898 Result result = | 5125 Result result = |
| 4899 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); | 5126 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); |
| 4900 frame_->Push(&result); | 5127 frame_->Push(&result); |
| 4901 } | 5128 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4915 if (node->is_compound()) { | 5142 if (node->is_compound()) { |
| 4916 Result result = LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); | 5143 Result result = LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF); |
| 4917 frame()->Push(&result); | 5144 frame()->Push(&result); |
| 4918 Load(node->value()); | 5145 Load(node->value()); |
| 4919 | 5146 |
| 4920 bool overwrite_value = | 5147 bool overwrite_value = |
| 4921 (node->value()->AsBinaryOperation() != NULL && | 5148 (node->value()->AsBinaryOperation() != NULL && |
| 4922 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5149 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 4923 GenericBinaryOperation(node->binary_op(), | 5150 GenericBinaryOperation(node->binary_op(), |
| 4924 node->type(), | 5151 node->type(), |
| 4925 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 5152 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, |
| 5153 node->no_negative_zero()); |
| 4926 } else { | 5154 } else { |
| 4927 Load(node->value()); | 5155 Load(node->value()); |
| 4928 } | 5156 } |
| 4929 | 5157 |
| 4930 // Perform the assignment. | 5158 // Perform the assignment. |
| 4931 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { | 5159 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { |
| 4932 CodeForSourcePosition(node->position()); | 5160 CodeForSourcePosition(node->position()); |
| 4933 StoreToSlot(slot, | 5161 StoreToSlot(slot, |
| 4934 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); | 5162 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); |
| 4935 } | 5163 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4992 } | 5220 } |
| 4993 Result value = EmitNamedLoad(name, var != NULL); | 5221 Result value = EmitNamedLoad(name, var != NULL); |
| 4994 frame()->Push(&value); | 5222 frame()->Push(&value); |
| 4995 Load(node->value()); | 5223 Load(node->value()); |
| 4996 | 5224 |
| 4997 bool overwrite_value = | 5225 bool overwrite_value = |
| 4998 (node->value()->AsBinaryOperation() != NULL && | 5226 (node->value()->AsBinaryOperation() != NULL && |
| 4999 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5227 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 5000 GenericBinaryOperation(node->binary_op(), | 5228 GenericBinaryOperation(node->binary_op(), |
| 5001 node->type(), | 5229 node->type(), |
| 5002 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 5230 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, |
| 5231 node->no_negative_zero()); |
| 5003 } else { | 5232 } else { |
| 5004 Load(node->value()); | 5233 Load(node->value()); |
| 5005 } | 5234 } |
| 5006 | 5235 |
| 5007 // Perform the assignment. It is safe to ignore constants here. | 5236 // Perform the assignment. It is safe to ignore constants here. |
| 5008 ASSERT(var == NULL || var->mode() != Variable::CONST); | 5237 ASSERT(var == NULL || var->mode() != Variable::CONST); |
| 5009 ASSERT_NE(Token::INIT_CONST, node->op()); | 5238 ASSERT_NE(Token::INIT_CONST, node->op()); |
| 5010 if (is_trivial_receiver) { | 5239 if (is_trivial_receiver) { |
| 5011 Result value = frame()->Pop(); | 5240 Result value = frame()->Pop(); |
| 5012 frame()->Push(prop->obj()); | 5241 frame()->Push(prop->obj()); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5071 frame()->PushElementAt(1); | 5300 frame()->PushElementAt(1); |
| 5072 Result value = EmitKeyedLoad(); | 5301 Result value = EmitKeyedLoad(); |
| 5073 frame()->Push(&value); | 5302 frame()->Push(&value); |
| 5074 Load(node->value()); | 5303 Load(node->value()); |
| 5075 | 5304 |
| 5076 bool overwrite_value = | 5305 bool overwrite_value = |
| 5077 (node->value()->AsBinaryOperation() != NULL && | 5306 (node->value()->AsBinaryOperation() != NULL && |
| 5078 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5307 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 5079 GenericBinaryOperation(node->binary_op(), | 5308 GenericBinaryOperation(node->binary_op(), |
| 5080 node->type(), | 5309 node->type(), |
| 5081 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 5310 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, |
| 5311 node->no_negative_zero()); |
| 5082 } else { | 5312 } else { |
| 5083 Load(node->value()); | 5313 Load(node->value()); |
| 5084 } | 5314 } |
| 5085 | 5315 |
| 5086 // Perform the assignment. It is safe to ignore constants here. | 5316 // Perform the assignment. It is safe to ignore constants here. |
| 5087 ASSERT(node->op() != Token::INIT_CONST); | 5317 ASSERT(node->op() != Token::INIT_CONST); |
| 5088 CodeForSourcePosition(node->position()); | 5318 CodeForSourcePosition(node->position()); |
| 5089 Result answer = EmitKeyedStore(prop->key()->type()); | 5319 Result answer = EmitKeyedStore(prop->key()->type()); |
| 5090 frame()->Push(&answer); | 5320 frame()->Push(&answer); |
| 5091 | 5321 |
| 5092 if (node->ends_initialization_block()) { | 5322 if (node->ends_initialization_block()) { |
| 5093 // The argument to the runtime call is the extra copy of the receiver, | 5323 // The argument to the runtime call is the extra copy of the receiver, |
| 5094 // which is below the value of the assignment. Swap the receiver and | 5324 // which is below the value of the assignment. Swap the receiver and |
| 5095 // the value of the assignment expression. | 5325 // the value of the assignment expression. |
| 5096 Result result = frame()->Pop(); | 5326 Result result = frame()->Pop(); |
| 5097 Result receiver = frame()->Pop(); | 5327 Result receiver = frame()->Pop(); |
| 5098 frame()->Push(&result); | 5328 frame()->Push(&result); |
| 5099 frame()->Push(&receiver); | 5329 frame()->Push(&receiver); |
| 5100 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); | 5330 Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
| 5101 } | 5331 } |
| 5102 | 5332 |
| 5103 ASSERT(frame()->height() == original_height + 1); | 5333 ASSERT(frame()->height() == original_height + 1); |
| 5104 } | 5334 } |
| 5105 | 5335 |
| 5106 | 5336 |
| 5107 void CodeGenerator::VisitAssignment(Assignment* node) { | 5337 void CodeGenerator::VisitAssignment(Assignment* node) { |
| 5338 ASSERT(!in_safe_int32_mode()); |
| 5108 #ifdef DEBUG | 5339 #ifdef DEBUG |
| 5109 int original_height = frame()->height(); | 5340 int original_height = frame()->height(); |
| 5110 #endif | 5341 #endif |
| 5111 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 5342 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
| 5112 Property* prop = node->target()->AsProperty(); | 5343 Property* prop = node->target()->AsProperty(); |
| 5113 | 5344 |
| 5114 if (var != NULL && !var->is_global()) { | 5345 if (var != NULL && !var->is_global()) { |
| 5115 EmitSlotAssignment(node); | 5346 EmitSlotAssignment(node); |
| 5116 | 5347 |
| 5117 } else if ((prop != NULL && prop->key()->IsPropertyName()) || | 5348 } else if ((prop != NULL && prop->key()->IsPropertyName()) || |
| (...skipping 15 matching lines...) Expand all Loading... |
| 5133 // The runtime call doesn't actually return but the code generator will | 5364 // The runtime call doesn't actually return but the code generator will |
| 5134 // still generate code and expects a certain frame height. | 5365 // still generate code and expects a certain frame height. |
| 5135 frame()->Push(&result); | 5366 frame()->Push(&result); |
| 5136 } | 5367 } |
| 5137 | 5368 |
| 5138 ASSERT(frame()->height() == original_height + 1); | 5369 ASSERT(frame()->height() == original_height + 1); |
| 5139 } | 5370 } |
| 5140 | 5371 |
| 5141 | 5372 |
| 5142 void CodeGenerator::VisitThrow(Throw* node) { | 5373 void CodeGenerator::VisitThrow(Throw* node) { |
| 5374 ASSERT(!in_safe_int32_mode()); |
| 5143 Comment cmnt(masm_, "[ Throw"); | 5375 Comment cmnt(masm_, "[ Throw"); |
| 5144 Load(node->exception()); | 5376 Load(node->exception()); |
| 5145 Result result = frame_->CallRuntime(Runtime::kThrow, 1); | 5377 Result result = frame_->CallRuntime(Runtime::kThrow, 1); |
| 5146 frame_->Push(&result); | 5378 frame_->Push(&result); |
| 5147 } | 5379 } |
| 5148 | 5380 |
| 5149 | 5381 |
| 5150 void CodeGenerator::VisitProperty(Property* node) { | 5382 void CodeGenerator::VisitProperty(Property* node) { |
| 5383 ASSERT(!in_safe_int32_mode()); |
| 5151 Comment cmnt(masm_, "[ Property"); | 5384 Comment cmnt(masm_, "[ Property"); |
| 5152 Reference property(this, node); | 5385 Reference property(this, node); |
| 5153 property.GetValue(); | 5386 property.GetValue(); |
| 5154 } | 5387 } |
| 5155 | 5388 |
| 5156 | 5389 |
| 5157 void CodeGenerator::VisitCall(Call* node) { | 5390 void CodeGenerator::VisitCall(Call* node) { |
| 5391 ASSERT(!in_safe_int32_mode()); |
| 5158 Comment cmnt(masm_, "[ Call"); | 5392 Comment cmnt(masm_, "[ Call"); |
| 5159 | 5393 |
| 5160 Expression* function = node->expression(); | 5394 Expression* function = node->expression(); |
| 5161 ZoneList<Expression*>* args = node->arguments(); | 5395 ZoneList<Expression*>* args = node->arguments(); |
| 5162 | 5396 |
| 5163 // Check if the function is a variable or a property. | 5397 // Check if the function is a variable or a property. |
| 5164 Variable* var = function->AsVariableProxy()->AsVariable(); | 5398 Variable* var = function->AsVariableProxy()->AsVariable(); |
| 5165 Property* property = function->AsProperty(); | 5399 Property* property = function->AsProperty(); |
| 5166 | 5400 |
| 5167 // ------------------------------------------------------------------------ | 5401 // ------------------------------------------------------------------------ |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5363 // Pass the global proxy as the receiver. | 5597 // Pass the global proxy as the receiver. |
| 5364 LoadGlobalReceiver(); | 5598 LoadGlobalReceiver(); |
| 5365 | 5599 |
| 5366 // Call the function. | 5600 // Call the function. |
| 5367 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); | 5601 CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position()); |
| 5368 } | 5602 } |
| 5369 } | 5603 } |
| 5370 | 5604 |
| 5371 | 5605 |
| 5372 void CodeGenerator::VisitCallNew(CallNew* node) { | 5606 void CodeGenerator::VisitCallNew(CallNew* node) { |
| 5607 ASSERT(!in_safe_int32_mode()); |
| 5373 Comment cmnt(masm_, "[ CallNew"); | 5608 Comment cmnt(masm_, "[ CallNew"); |
| 5374 | 5609 |
| 5375 // According to ECMA-262, section 11.2.2, page 44, the function | 5610 // According to ECMA-262, section 11.2.2, page 44, the function |
| 5376 // expression in new calls must be evaluated before the | 5611 // expression in new calls must be evaluated before the |
| 5377 // arguments. This is different from ordinary calls, where the | 5612 // arguments. This is different from ordinary calls, where the |
| 5378 // actual function to call is resolved after the arguments have been | 5613 // actual function to call is resolved after the arguments have been |
| 5379 // evaluated. | 5614 // evaluated. |
| 5380 | 5615 |
| 5381 // Compute function to call and use the global object as the | 5616 // Compute function to call and use the global object as the |
| 5382 // receiver. There is no need to use the global proxy here because | 5617 // receiver. There is no need to use the global proxy here because |
| (...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5905 object.Unuse(); | 6140 object.Unuse(); |
| 5906 scratch.Unuse(); | 6141 scratch.Unuse(); |
| 5907 duplicate_value.Unuse(); | 6142 duplicate_value.Unuse(); |
| 5908 | 6143 |
| 5909 // Leave. | 6144 // Leave. |
| 5910 leave.Bind(&value); | 6145 leave.Bind(&value); |
| 5911 frame_->Push(&value); | 6146 frame_->Push(&value); |
| 5912 } | 6147 } |
| 5913 | 6148 |
| 5914 | 6149 |
| 5915 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 6150 void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) { |
| 5916 ASSERT(args->length() == 1); | 6151 ASSERT(args->length() == 1); |
| 5917 | 6152 |
| 5918 // ArgumentsAccessStub expects the key in edx and the formal | 6153 // ArgumentsAccessStub expects the key in edx and the formal |
| 5919 // parameter count in eax. | 6154 // parameter count in eax. |
| 5920 Load(args->at(0)); | 6155 Load(args->at(0)); |
| 5921 Result key = frame_->Pop(); | 6156 Result key = frame_->Pop(); |
| 5922 // Explicitly create a constant result. | 6157 // Explicitly create a constant result. |
| 5923 Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters()))); | 6158 Result count(Handle<Smi>(Smi::FromInt(scope()->num_parameters()))); |
| 5924 // Call the shared stub to get to arguments[key]. | 6159 // Call the shared stub to get to arguments[key]. |
| 5925 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 6160 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6290 __ bind(&runtime); | 6525 __ bind(&runtime); |
| 6291 result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); | 6526 result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
| 6292 | 6527 |
| 6293 end.Bind(&result); | 6528 end.Bind(&result); |
| 6294 frame()->Push(&result); | 6529 frame()->Push(&result); |
| 6295 } | 6530 } |
| 6296 } | 6531 } |
| 6297 | 6532 |
| 6298 | 6533 |
| 6299 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 6534 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 6535 ASSERT(!in_safe_int32_mode()); |
| 6300 if (CheckForInlineRuntimeCall(node)) { | 6536 if (CheckForInlineRuntimeCall(node)) { |
| 6301 return; | 6537 return; |
| 6302 } | 6538 } |
| 6303 | 6539 |
| 6304 ZoneList<Expression*>* args = node->arguments(); | 6540 ZoneList<Expression*>* args = node->arguments(); |
| 6305 Comment cmnt(masm_, "[ CallRuntime"); | 6541 Comment cmnt(masm_, "[ CallRuntime"); |
| 6306 Runtime::Function* function = node->function(); | 6542 Runtime::Function* function = node->function(); |
| 6307 | 6543 |
| 6308 if (function == NULL) { | 6544 if (function == NULL) { |
| 6309 // Push the builtins object found in the current global object. | 6545 // Push the builtins object found in the current global object. |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6416 expression->AsLiteral()->IsNull())) { | 6652 expression->AsLiteral()->IsNull())) { |
| 6417 // Omit evaluating the value of the primitive literal. | 6653 // Omit evaluating the value of the primitive literal. |
| 6418 // It will be discarded anyway, and can have no side effect. | 6654 // It will be discarded anyway, and can have no side effect. |
| 6419 frame_->Push(Factory::undefined_value()); | 6655 frame_->Push(Factory::undefined_value()); |
| 6420 } else { | 6656 } else { |
| 6421 Load(node->expression()); | 6657 Load(node->expression()); |
| 6422 frame_->SetElementAt(0, Factory::undefined_value()); | 6658 frame_->SetElementAt(0, Factory::undefined_value()); |
| 6423 } | 6659 } |
| 6424 | 6660 |
| 6425 } else { | 6661 } else { |
| 6426 Load(node->expression()); | 6662 if (in_safe_int32_mode()) { |
| 6427 bool overwrite = | 6663 Visit(node->expression()); |
| 6428 (node->expression()->AsBinaryOperation() != NULL && | 6664 Result value = frame_->Pop(); |
| 6429 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); | 6665 ASSERT(value.is_untagged_int32()); |
| 6430 switch (op) { | 6666 // Registers containing an int32 value are not multiply used. |
| 6431 case Token::SUB: { | 6667 ASSERT(!value.is_register() || !frame_->is_used(value.reg())); |
| 6432 GenericUnaryOpStub stub(Token::SUB, overwrite); | 6668 value.ToRegister(); |
| 6433 Result operand = frame_->Pop(); | 6669 switch (op) { |
| 6434 Result answer = frame_->CallStub(&stub, &operand); | 6670 case Token::SUB: { |
| 6435 frame_->Push(&answer); | 6671 __ neg(value.reg()); |
| 6436 break; | 6672 if (node->no_negative_zero()) { |
| 6673 // -MIN_INT is MIN_INT with the overflow flag set. |
| 6674 unsafe_bailout_->Branch(overflow); |
| 6675 } else { |
| 6676 // MIN_INT and 0 both have bad negations. They both have 31 zeros. |
| 6677 __ test(value.reg(), Immediate(0x7FFFFFFF)); |
| 6678 unsafe_bailout_->Branch(zero); |
| 6679 } |
| 6680 break; |
| 6681 } |
| 6682 case Token::BIT_NOT: { |
| 6683 __ not_(value.reg()); |
| 6684 break; |
| 6685 } |
| 6686 case Token::ADD: { |
| 6687 // Unary plus has no effect on int32 values. |
| 6688 break; |
| 6689 } |
| 6690 default: |
| 6691 UNREACHABLE(); |
| 6692 break; |
| 6437 } | 6693 } |
| 6694 frame_->Push(&value); |
| 6695 } else { |
| 6696 Load(node->expression()); |
| 6697 bool overwrite = |
| 6698 (node->expression()->AsBinaryOperation() != NULL && |
| 6699 node->expression()->AsBinaryOperation()->ResultOverwriteAllowed()); |
| 6700 switch (op) { |
| 6701 case Token::SUB: { |
| 6702 GenericUnaryOpStub stub(Token::SUB, overwrite); |
| 6703 Result operand = frame_->Pop(); |
| 6704 Result answer = frame_->CallStub(&stub, &operand); |
| 6705 answer.set_number_info(NumberInfo::Number()); |
| 6706 frame_->Push(&answer); |
| 6707 break; |
| 6708 } |
| 6709 case Token::BIT_NOT: { |
| 6710 // Smi check. |
| 6711 JumpTarget smi_label; |
| 6712 JumpTarget continue_label; |
| 6713 Result operand = frame_->Pop(); |
| 6714 NumberInfo operand_info = operand.number_info(); |
| 6715 operand.ToRegister(); |
| 6716 if (operand_info.IsSmi()) { |
| 6717 if (FLAG_debug_code) __ AbortIfNotSmi(operand.reg()); |
| 6718 frame_->Spill(operand.reg()); |
| 6719 // Set smi tag bit. It will be reset by the not operation. |
| 6720 __ lea(operand.reg(), Operand(operand.reg(), kSmiTagMask)); |
| 6721 __ not_(operand.reg()); |
| 6722 Result answer = operand; |
| 6723 answer.set_number_info(NumberInfo::Smi()); |
| 6724 frame_->Push(&answer); |
| 6725 } else { |
| 6726 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 6727 smi_label.Branch(zero, &operand, taken); |
| 6438 | 6728 |
| 6439 case Token::BIT_NOT: { | 6729 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); |
| 6440 // Smi check. | 6730 Result answer = frame_->CallStub(&stub, &operand); |
| 6441 JumpTarget smi_label; | 6731 continue_label.Jump(&answer); |
| 6442 JumpTarget continue_label; | |
| 6443 Result operand = frame_->Pop(); | |
| 6444 operand.ToRegister(); | |
| 6445 __ test(operand.reg(), Immediate(kSmiTagMask)); | |
| 6446 smi_label.Branch(zero, &operand, taken); | |
| 6447 | 6732 |
| 6448 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); | 6733 smi_label.Bind(&answer); |
| 6449 Result answer = frame_->CallStub(&stub, &operand); | 6734 answer.ToRegister(); |
| 6450 continue_label.Jump(&answer); | 6735 frame_->Spill(answer.reg()); |
| 6736 // Set smi tag bit. It will be reset by the not operation. |
| 6737 __ lea(answer.reg(), Operand(answer.reg(), kSmiTagMask)); |
| 6738 __ not_(answer.reg()); |
| 6451 | 6739 |
| 6452 smi_label.Bind(&answer); | 6740 continue_label.Bind(&answer); |
| 6453 answer.ToRegister(); | 6741 if (operand_info.IsInteger32()) { |
| 6454 frame_->Spill(answer.reg()); | 6742 answer.set_number_info(NumberInfo::Integer32()); |
| 6455 __ not_(answer.reg()); | 6743 } else { |
| 6456 __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag. | 6744 answer.set_number_info(NumberInfo::Number()); |
| 6745 } |
| 6746 frame_->Push(&answer); |
| 6747 } |
| 6748 break; |
| 6749 } |
| 6750 case Token::ADD: { |
| 6751 // Smi check. |
| 6752 JumpTarget continue_label; |
| 6753 Result operand = frame_->Pop(); |
| 6754 NumberInfo operand_info = operand.number_info(); |
| 6755 operand.ToRegister(); |
| 6756 __ test(operand.reg(), Immediate(kSmiTagMask)); |
| 6757 continue_label.Branch(zero, &operand, taken); |
| 6457 | 6758 |
| 6458 continue_label.Bind(&answer); | 6759 frame_->Push(&operand); |
| 6459 frame_->Push(&answer); | 6760 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, |
| 6460 break; | |
| 6461 } | |
| 6462 | |
| 6463 case Token::ADD: { | |
| 6464 // Smi check. | |
| 6465 JumpTarget continue_label; | |
| 6466 Result operand = frame_->Pop(); | |
| 6467 operand.ToRegister(); | |
| 6468 __ test(operand.reg(), Immediate(kSmiTagMask)); | |
| 6469 continue_label.Branch(zero, &operand, taken); | |
| 6470 | |
| 6471 frame_->Push(&operand); | |
| 6472 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, | |
| 6473 CALL_FUNCTION, 1); | 6761 CALL_FUNCTION, 1); |
| 6474 | 6762 |
| 6475 continue_label.Bind(&answer); | 6763 continue_label.Bind(&answer); |
| 6476 frame_->Push(&answer); | 6764 if (operand_info.IsSmi()) { |
| 6477 break; | 6765 answer.set_number_info(NumberInfo::Smi()); |
| 6766 } else if (operand_info.IsInteger32()) { |
| 6767 answer.set_number_info(NumberInfo::Integer32()); |
| 6768 } else { |
| 6769 answer.set_number_info(NumberInfo::Number()); |
| 6770 } |
| 6771 frame_->Push(&answer); |
| 6772 break; |
| 6773 } |
| 6774 default: |
| 6775 // NOT, DELETE, TYPEOF, and VOID are handled outside the |
| 6776 // switch. |
| 6777 UNREACHABLE(); |
| 6478 } | 6778 } |
| 6479 | |
| 6480 default: | |
| 6481 // NOT, DELETE, TYPEOF, and VOID are handled outside the | |
| 6482 // switch. | |
| 6483 UNREACHABLE(); | |
| 6484 } | 6779 } |
| 6485 } | 6780 } |
| 6486 } | 6781 } |
| 6487 | 6782 |
| 6488 | 6783 |
| 6489 // The value in dst was optimistically incremented or decremented. The | 6784 // The value in dst was optimistically incremented or decremented. The |
| 6490 // result overflowed or was not smi tagged. Undo the operation, call | 6785 // result overflowed or was not smi tagged. Undo the operation, call |
| 6491 // into the runtime to convert the argument to a number, and call the | 6786 // into the runtime to convert the argument to a number, and call the |
| 6492 // specialized add or subtract stub. The result is left in dst. | 6787 // specialized add or subtract stub. The result is left in dst. |
| 6493 class DeferredPrefixCountOperation: public DeferredCode { | 6788 class DeferredPrefixCountOperation: public DeferredCode { |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6566 __ CallRuntime(Runtime::kNumberAdd, 2); | 6861 __ CallRuntime(Runtime::kNumberAdd, 2); |
| 6567 } else { | 6862 } else { |
| 6568 __ CallRuntime(Runtime::kNumberSub, 2); | 6863 __ CallRuntime(Runtime::kNumberSub, 2); |
| 6569 } | 6864 } |
| 6570 if (!dst_.is(eax)) __ mov(dst_, eax); | 6865 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 6571 __ pop(old_); | 6866 __ pop(old_); |
| 6572 } | 6867 } |
| 6573 | 6868 |
| 6574 | 6869 |
| 6575 void CodeGenerator::VisitCountOperation(CountOperation* node) { | 6870 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
| 6871 ASSERT(!in_safe_int32_mode()); |
| 6576 Comment cmnt(masm_, "[ CountOperation"); | 6872 Comment cmnt(masm_, "[ CountOperation"); |
| 6577 | 6873 |
| 6578 bool is_postfix = node->is_postfix(); | 6874 bool is_postfix = node->is_postfix(); |
| 6579 bool is_increment = node->op() == Token::INC; | 6875 bool is_increment = node->op() == Token::INC; |
| 6580 | 6876 |
| 6581 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 6877 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
| 6582 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 6878 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
| 6583 | 6879 |
| 6584 // Postfix operations need a stack slot under the reference to hold | 6880 // Postfix operations need a stack slot under the reference to hold |
| 6585 // the old value while the new value is being stored. This is so that | 6881 // the old value while the new value is being stored. This is so that |
| (...skipping 14 matching lines...) Expand all Loading... |
| 6600 | 6896 |
| 6601 Result new_value = frame_->Pop(); | 6897 Result new_value = frame_->Pop(); |
| 6602 new_value.ToRegister(); | 6898 new_value.ToRegister(); |
| 6603 | 6899 |
| 6604 Result old_value; // Only allocated in the postfix case. | 6900 Result old_value; // Only allocated in the postfix case. |
| 6605 if (is_postfix) { | 6901 if (is_postfix) { |
| 6606 // Allocate a temporary to preserve the old value. | 6902 // Allocate a temporary to preserve the old value. |
| 6607 old_value = allocator_->Allocate(); | 6903 old_value = allocator_->Allocate(); |
| 6608 ASSERT(old_value.is_valid()); | 6904 ASSERT(old_value.is_valid()); |
| 6609 __ mov(old_value.reg(), new_value.reg()); | 6905 __ mov(old_value.reg(), new_value.reg()); |
| 6906 |
| 6907 // The return value for postfix operations is the |
| 6908 // same as the input, and has the same number info. |
| 6909 old_value.set_number_info(new_value.number_info()); |
| 6610 } | 6910 } |
| 6911 |
| 6611 // Ensure the new value is writable. | 6912 // Ensure the new value is writable. |
| 6612 frame_->Spill(new_value.reg()); | 6913 frame_->Spill(new_value.reg()); |
| 6613 | 6914 |
| 6614 // In order to combine the overflow and the smi tag check, we need | 6915 Result tmp; |
| 6615 // to be able to allocate a byte register. We attempt to do so | 6916 if (new_value.is_smi()) { |
| 6616 // without spilling. If we fail, we will generate separate overflow | 6917 if (FLAG_debug_code) __ AbortIfNotSmi(new_value.reg()); |
| 6617 // and smi tag checks. | 6918 } else { |
| 6618 // | 6919 // We don't know statically if the input is a smi. |
| 6619 // We allocate and clear the temporary byte register before | 6920 // In order to combine the overflow and the smi tag check, we need |
| 6620 // performing the count operation since clearing the register using | 6921 // to be able to allocate a byte register. We attempt to do so |
| 6621 // xor will clear the overflow flag. | 6922 // without spilling. If we fail, we will generate separate overflow |
| 6622 Result tmp = allocator_->AllocateByteRegisterWithoutSpilling(); | 6923 // and smi tag checks. |
| 6623 if (tmp.is_valid()) { | 6924 // We allocate and clear a temporary byte register before performing |
| 6624 __ Set(tmp.reg(), Immediate(0)); | 6925 // the count operation since clearing the register using xor will clear |
| 6926 // the overflow flag. |
| 6927 tmp = allocator_->AllocateByteRegisterWithoutSpilling(); |
| 6928 if (tmp.is_valid()) { |
| 6929 __ Set(tmp.reg(), Immediate(0)); |
| 6930 } |
| 6931 } |
| 6932 |
| 6933 if (is_increment) { |
| 6934 __ add(Operand(new_value.reg()), Immediate(Smi::FromInt(1))); |
| 6935 } else { |
| 6936 __ sub(Operand(new_value.reg()), Immediate(Smi::FromInt(1))); |
| 6625 } | 6937 } |
| 6626 | 6938 |
| 6627 DeferredCode* deferred = NULL; | 6939 DeferredCode* deferred = NULL; |
| 6628 if (is_postfix) { | 6940 if (is_postfix) { |
| 6629 deferred = new DeferredPostfixCountOperation(new_value.reg(), | 6941 deferred = new DeferredPostfixCountOperation(new_value.reg(), |
| 6630 old_value.reg(), | 6942 old_value.reg(), |
| 6631 is_increment); | 6943 is_increment); |
| 6632 } else { | 6944 } else { |
| 6633 deferred = new DeferredPrefixCountOperation(new_value.reg(), | 6945 deferred = new DeferredPrefixCountOperation(new_value.reg(), |
| 6634 is_increment); | 6946 is_increment); |
| 6635 } | 6947 } |
| 6636 | 6948 |
| 6637 if (is_increment) { | 6949 if (new_value.is_smi()) { |
| 6638 __ add(Operand(new_value.reg()), Immediate(Smi::FromInt(1))); | 6950 // In case we have a smi as input just check for overflow. |
| 6951 deferred->Branch(overflow); |
| 6639 } else { | 6952 } else { |
| 6640 __ sub(Operand(new_value.reg()), Immediate(Smi::FromInt(1))); | 6953 // If the count operation didn't overflow and the result is a valid |
| 6641 } | 6954 // smi, we're done. Otherwise, we jump to the deferred slow-case |
| 6642 | 6955 // code. |
| 6643 // If the count operation didn't overflow and the result is a valid | |
| 6644 // smi, we're done. Otherwise, we jump to the deferred slow-case | |
| 6645 // code. | |
| 6646 if (tmp.is_valid()) { | |
| 6647 // We combine the overflow and the smi tag check if we could | 6956 // We combine the overflow and the smi tag check if we could |
| 6648 // successfully allocate a temporary byte register. | 6957 // successfully allocate a temporary byte register. |
| 6649 __ setcc(overflow, tmp.reg()); | 6958 if (tmp.is_valid()) { |
| 6650 __ or_(Operand(tmp.reg()), new_value.reg()); | 6959 __ setcc(overflow, tmp.reg()); |
| 6651 __ test(tmp.reg(), Immediate(kSmiTagMask)); | 6960 __ or_(Operand(tmp.reg()), new_value.reg()); |
| 6652 tmp.Unuse(); | 6961 __ test(tmp.reg(), Immediate(kSmiTagMask)); |
| 6653 deferred->Branch(not_zero); | 6962 tmp.Unuse(); |
| 6654 } else { | 6963 deferred->Branch(not_zero); |
| 6655 // Otherwise we test separately for overflow and smi tag. | 6964 } else { |
| 6656 deferred->Branch(overflow); | 6965 // Otherwise we test separately for overflow and smi tag. |
| 6657 __ test(new_value.reg(), Immediate(kSmiTagMask)); | 6966 deferred->Branch(overflow); |
| 6658 deferred->Branch(not_zero); | 6967 __ test(new_value.reg(), Immediate(kSmiTagMask)); |
| 6968 deferred->Branch(not_zero); |
| 6969 } |
| 6659 } | 6970 } |
| 6660 deferred->BindExit(); | 6971 deferred->BindExit(); |
| 6661 | 6972 |
| 6973 // The result of ++ or -- is an Integer32 if the |
| 6974 // input is a smi. Otherwise it is a number. |
| 6975 if (new_value.is_smi()) { |
| 6976 new_value.set_number_info(NumberInfo::Integer32()); |
| 6977 } else { |
| 6978 new_value.set_number_info(NumberInfo::Number()); |
| 6979 } |
| 6980 |
| 6662 // Postfix: store the old value in the allocated slot under the | 6981 // Postfix: store the old value in the allocated slot under the |
| 6663 // reference. | 6982 // reference. |
| 6664 if (is_postfix) frame_->SetElementAt(target.size(), &old_value); | 6983 if (is_postfix) frame_->SetElementAt(target.size(), &old_value); |
| 6665 | 6984 |
| 6666 frame_->Push(&new_value); | 6985 frame_->Push(&new_value); |
| 6667 // Non-constant: update the reference. | 6986 // Non-constant: update the reference. |
| 6668 if (!is_const) target.SetValue(NOT_CONST_INIT); | 6987 if (!is_const) target.SetValue(NOT_CONST_INIT); |
| 6669 } | 6988 } |
| 6670 | 6989 |
| 6671 // Postfix: drop the new value and use the old. | 6990 // Postfix: drop the new value and use the old. |
| 6672 if (is_postfix) frame_->Drop(); | 6991 if (is_postfix) frame_->Drop(); |
| 6673 } | 6992 } |
| 6674 | 6993 |
| 6675 | 6994 |
| 6995 void CodeGenerator::Int32BinaryOperation(BinaryOperation* node) { |
| 6996 Token::Value op = node->op(); |
| 6997 Comment cmnt(masm_, "[ Int32BinaryOperation"); |
| 6998 ASSERT(in_safe_int32_mode()); |
| 6999 ASSERT(safe_int32_mode_enabled()); |
| 7000 ASSERT(FLAG_safe_int32_compiler); |
| 7001 |
| 7002 if (op == Token::COMMA) { |
| 7003 // Discard left value. |
| 7004 frame_->Nip(1); |
| 7005 return; |
| 7006 } |
| 7007 |
| 7008 Result right = frame_->Pop(); |
| 7009 Result left = frame_->Pop(); |
| 7010 |
| 7011 ASSERT(right.is_untagged_int32()); |
| 7012 ASSERT(left.is_untagged_int32()); |
| 7013 // Registers containing an int32 value are not multiply used. |
| 7014 ASSERT(!left.is_register() || !frame_->is_used(left.reg())); |
| 7015 ASSERT(!right.is_register() || !frame_->is_used(right.reg())); |
| 7016 |
| 7017 switch (op) { |
| 7018 case Token::COMMA: |
| 7019 case Token::OR: |
| 7020 case Token::AND: |
| 7021 UNREACHABLE(); |
| 7022 break; |
| 7023 case Token::BIT_OR: |
| 7024 case Token::BIT_XOR: |
| 7025 case Token::BIT_AND: |
| 7026 left.ToRegister(); |
| 7027 right.ToRegister(); |
| 7028 if (op == Token::BIT_OR) { |
| 7029 __ or_(left.reg(), Operand(right.reg())); |
| 7030 } else if (op == Token::BIT_XOR) { |
| 7031 __ xor_(left.reg(), Operand(right.reg())); |
| 7032 } else { |
| 7033 ASSERT(op == Token::BIT_AND); |
| 7034 __ and_(left.reg(), Operand(right.reg())); |
| 7035 } |
| 7036 frame_->Push(&left); |
| 7037 right.Unuse(); |
| 7038 break; |
| 7039 case Token::SAR: |
| 7040 case Token::SHL: |
| 7041 case Token::SHR: { |
| 7042 bool test_shr_overflow = false; |
| 7043 left.ToRegister(); |
| 7044 if (right.is_constant()) { |
| 7045 ASSERT(right.handle()->IsSmi() || right.handle()->IsHeapNumber()); |
| 7046 int shift_amount = NumberToInt32(*right.handle()) & 0x1F; |
| 7047 if (op == Token::SAR) { |
| 7048 __ sar(left.reg(), shift_amount); |
| 7049 } else if (op == Token::SHL) { |
| 7050 __ shl(left.reg(), shift_amount); |
| 7051 } else { |
| 7052 ASSERT(op == Token::SHR); |
| 7053 __ shr(left.reg(), shift_amount); |
| 7054 if (shift_amount == 0) test_shr_overflow = true; |
| 7055 } |
| 7056 } else { |
| 7057 // Move right to ecx |
| 7058 if (left.is_register() && left.reg().is(ecx)) { |
| 7059 right.ToRegister(); |
| 7060 __ xchg(left.reg(), right.reg()); |
| 7061 left = right; // Left is unused here, copy of right unused by Push. |
| 7062 } else { |
| 7063 right.ToRegister(ecx); |
| 7064 left.ToRegister(); |
| 7065 } |
| 7066 if (op == Token::SAR) { |
| 7067 __ sar_cl(left.reg()); |
| 7068 } else if (op == Token::SHL) { |
| 7069 __ shl_cl(left.reg()); |
| 7070 } else { |
| 7071 ASSERT(op == Token::SHR); |
| 7072 __ shr_cl(left.reg()); |
| 7073 test_shr_overflow = true; |
| 7074 } |
| 7075 } |
| 7076 { |
| 7077 Register left_reg = left.reg(); |
| 7078 frame_->Push(&left); |
| 7079 right.Unuse(); |
| 7080 if (test_shr_overflow && !node->to_int32()) { |
| 7081 // Uint32 results with top bit set are not Int32 values. |
| 7082 // If they will be forced to Int32, skip the test. |
| 7083 // Test is needed because shr with shift amount 0 does not set flags. |
| 7084 __ test(left_reg, Operand(left_reg)); |
| 7085 unsafe_bailout_->Branch(sign); |
| 7086 } |
| 7087 } |
| 7088 break; |
| 7089 } |
| 7090 case Token::ADD: |
| 7091 case Token::SUB: |
| 7092 case Token::MUL: |
| 7093 left.ToRegister(); |
| 7094 right.ToRegister(); |
| 7095 if (op == Token::ADD) { |
| 7096 __ add(left.reg(), Operand(right.reg())); |
| 7097 } else if (op == Token::SUB) { |
| 7098 __ sub(left.reg(), Operand(right.reg())); |
| 7099 } else { |
| 7100 ASSERT(op == Token::MUL); |
| 7101 // We have statically verified that a negative zero can be ignored. |
| 7102 __ imul(left.reg(), Operand(right.reg())); |
| 7103 } |
| 7104 right.Unuse(); |
| 7105 frame_->Push(&left); |
| 7106 if (!node->to_int32()) { |
| 7107 // If ToInt32 is called on the result of ADD, SUB, or MUL, we don't |
| 7108 // care about overflows. |
| 7109 unsafe_bailout_->Branch(overflow); |
| 7110 } |
| 7111 break; |
| 7112 case Token::DIV: |
| 7113 case Token::MOD: { |
| 7114 if (right.is_register() && (right.reg().is(eax) || right.reg().is(edx))) { |
| 7115 if (left.is_register() && left.reg().is(edi)) { |
| 7116 right.ToRegister(ebx); |
| 7117 } else { |
| 7118 right.ToRegister(edi); |
| 7119 } |
| 7120 } |
| 7121 left.ToRegister(eax); |
| 7122 Result edx_reg = allocator_->Allocate(edx); |
| 7123 right.ToRegister(); |
| 7124 // The results are unused here because BreakTarget::Branch cannot handle |
| 7125 // live results. |
| 7126 Register right_reg = right.reg(); |
| 7127 left.Unuse(); |
| 7128 right.Unuse(); |
| 7129 edx_reg.Unuse(); |
| 7130 __ cmp(right_reg, 0); |
| 7131 // Ensure divisor is positive: no chance of non-int32 or -0 result. |
| 7132 unsafe_bailout_->Branch(less_equal); |
| 7133 __ cdq(); // Sign-extend eax into edx:eax |
| 7134 __ idiv(right_reg); |
| 7135 if (op == Token::MOD) { |
| 7136 Result edx_result(edx, NumberInfo::Integer32()); |
| 7137 edx_result.set_untagged_int32(true); |
| 7138 frame_->Push(&edx_result); |
| 7139 } else { |
| 7140 ASSERT(op == Token::DIV); |
| 7141 __ test(edx, Operand(edx)); |
| 7142 unsafe_bailout_->Branch(not_equal); |
| 7143 Result eax_result(eax, NumberInfo::Integer32()); |
| 7144 eax_result.set_untagged_int32(true); |
| 7145 frame_->Push(&eax_result); |
| 7146 } |
| 7147 break; |
| 7148 } |
| 7149 default: |
| 7150 UNREACHABLE(); |
| 7151 break; |
| 7152 } |
| 7153 } |
| 7154 |
| 6676 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 7155 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 6677 Comment cmnt(masm_, "[ BinaryOperation"); | 7156 Comment cmnt(masm_, "[ BinaryOperation"); |
| 6678 Token::Value op = node->op(); | 7157 Token::Value op = node->op(); |
| 6679 | 7158 |
| 6680 // According to ECMA-262 section 11.11, page 58, the binary logical | 7159 // According to ECMA-262 section 11.11, page 58, the binary logical |
| 6681 // operators must yield the result of one of the two expressions | 7160 // operators must yield the result of one of the two expressions |
| 6682 // before any ToBoolean() conversions. This means that the value | 7161 // before any ToBoolean() conversions. This means that the value |
| 6683 // produced by a && or || operator is not necessarily a boolean. | 7162 // produced by a && or || operator is not necessarily a boolean. |
| 6684 | 7163 |
| 6685 // NOTE: If the left hand side produces a materialized value (not | 7164 // NOTE: If the left hand side produces a materialized value (not |
| 6686 // control flow), we force the right hand side to do the same. This | 7165 // control flow), we force the right hand side to do the same. This |
| 6687 // is necessary because we assume that if we get control flow on the | 7166 // is necessary because we assume that if we get control flow on the |
| 6688 // last path out of an expression we got it on all paths. | 7167 // last path out of an expression we got it on all paths. |
| 6689 if (op == Token::AND) { | 7168 if (op == Token::AND) { |
| 7169 ASSERT(!in_safe_int32_mode()); |
| 6690 JumpTarget is_true; | 7170 JumpTarget is_true; |
| 6691 ControlDestination dest(&is_true, destination()->false_target(), true); | 7171 ControlDestination dest(&is_true, destination()->false_target(), true); |
| 6692 LoadCondition(node->left(), &dest, false); | 7172 LoadCondition(node->left(), &dest, false); |
| 6693 | 7173 |
| 6694 if (dest.false_was_fall_through()) { | 7174 if (dest.false_was_fall_through()) { |
| 6695 // The current false target was used as the fall-through. If | 7175 // The current false target was used as the fall-through. If |
| 6696 // there are no dangling jumps to is_true then the left | 7176 // there are no dangling jumps to is_true then the left |
| 6697 // subexpression was unconditionally false. Otherwise we have | 7177 // subexpression was unconditionally false. Otherwise we have |
| 6698 // paths where we do have to evaluate the right subexpression. | 7178 // paths where we do have to evaluate the right subexpression. |
| 6699 if (is_true.is_linked()) { | 7179 if (is_true.is_linked()) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6743 | 7223 |
| 6744 // Compile right side expression. | 7224 // Compile right side expression. |
| 6745 is_true.Bind(); | 7225 is_true.Bind(); |
| 6746 Load(node->right()); | 7226 Load(node->right()); |
| 6747 | 7227 |
| 6748 // Exit (always with a materialized value). | 7228 // Exit (always with a materialized value). |
| 6749 exit.Bind(); | 7229 exit.Bind(); |
| 6750 } | 7230 } |
| 6751 | 7231 |
| 6752 } else if (op == Token::OR) { | 7232 } else if (op == Token::OR) { |
| 7233 ASSERT(!in_safe_int32_mode()); |
| 6753 JumpTarget is_false; | 7234 JumpTarget is_false; |
| 6754 ControlDestination dest(destination()->true_target(), &is_false, false); | 7235 ControlDestination dest(destination()->true_target(), &is_false, false); |
| 6755 LoadCondition(node->left(), &dest, false); | 7236 LoadCondition(node->left(), &dest, false); |
| 6756 | 7237 |
| 6757 if (dest.true_was_fall_through()) { | 7238 if (dest.true_was_fall_through()) { |
| 6758 // The current true target was used as the fall-through. If | 7239 // The current true target was used as the fall-through. If |
| 6759 // there are no dangling jumps to is_false then the left | 7240 // there are no dangling jumps to is_false then the left |
| 6760 // subexpression was unconditionally true. Otherwise we have | 7241 // subexpression was unconditionally true. Otherwise we have |
| 6761 // paths where we do have to evaluate the right subexpression. | 7242 // paths where we do have to evaluate the right subexpression. |
| 6762 if (is_false.is_linked()) { | 7243 if (is_false.is_linked()) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6804 frame_->Drop(); | 7285 frame_->Drop(); |
| 6805 | 7286 |
| 6806 // Compile right side expression. | 7287 // Compile right side expression. |
| 6807 is_false.Bind(); | 7288 is_false.Bind(); |
| 6808 Load(node->right()); | 7289 Load(node->right()); |
| 6809 | 7290 |
| 6810 // Exit (always with a materialized value). | 7291 // Exit (always with a materialized value). |
| 6811 exit.Bind(); | 7292 exit.Bind(); |
| 6812 } | 7293 } |
| 6813 | 7294 |
| 7295 } else if (in_safe_int32_mode()) { |
| 7296 Visit(node->left()); |
| 7297 Visit(node->right()); |
| 7298 Int32BinaryOperation(node); |
| 6814 } else { | 7299 } else { |
| 6815 // NOTE: The code below assumes that the slow cases (calls to runtime) | 7300 // NOTE: The code below assumes that the slow cases (calls to runtime) |
| 6816 // never return a constant/immutable object. | 7301 // never return a constant/immutable object. |
| 6817 OverwriteMode overwrite_mode = NO_OVERWRITE; | 7302 OverwriteMode overwrite_mode = NO_OVERWRITE; |
| 6818 if (node->left()->AsBinaryOperation() != NULL && | 7303 if (node->left()->AsBinaryOperation() != NULL && |
| 6819 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 7304 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 6820 overwrite_mode = OVERWRITE_LEFT; | 7305 overwrite_mode = OVERWRITE_LEFT; |
| 6821 } else if (node->right()->AsBinaryOperation() != NULL && | 7306 } else if (node->right()->AsBinaryOperation() != NULL && |
| 6822 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { | 7307 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()) { |
| 6823 overwrite_mode = OVERWRITE_RIGHT; | 7308 overwrite_mode = OVERWRITE_RIGHT; |
| 6824 } | 7309 } |
| 6825 | 7310 |
| 6826 Load(node->left()); | 7311 if (node->left()->IsTrivial()) { |
| 6827 Load(node->right()); | 7312 Load(node->right()); |
| 6828 GenericBinaryOperation(node->op(), node->type(), overwrite_mode); | 7313 Result right = frame_->Pop(); |
| 7314 frame_->Push(node->left()); |
| 7315 frame_->Push(&right); |
| 7316 } else { |
| 7317 Load(node->left()); |
| 7318 Load(node->right()); |
| 7319 } |
| 7320 GenericBinaryOperation(node->op(), node->type(), |
| 7321 overwrite_mode, node->no_negative_zero()); |
| 6829 } | 7322 } |
| 6830 } | 7323 } |
| 6831 | 7324 |
| 6832 | 7325 |
| 6833 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 7326 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| 7327 ASSERT(!in_safe_int32_mode()); |
| 6834 frame_->PushFunction(); | 7328 frame_->PushFunction(); |
| 6835 } | 7329 } |
| 6836 | 7330 |
| 6837 | 7331 |
| 6838 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 7332 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
| 7333 ASSERT(!in_safe_int32_mode()); |
| 6839 Comment cmnt(masm_, "[ CompareOperation"); | 7334 Comment cmnt(masm_, "[ CompareOperation"); |
| 6840 | 7335 |
| 6841 bool left_already_loaded = false; | 7336 bool left_already_loaded = false; |
| 6842 | 7337 |
| 6843 // Get the expressions from the node. | 7338 // Get the expressions from the node. |
| 6844 Expression* left = node->left(); | 7339 Expression* left = node->left(); |
| 6845 Expression* right = node->right(); | 7340 Expression* right = node->right(); |
| 6846 Token::Value op = node->op(); | 7341 Token::Value op = node->op(); |
| 6847 // To make typeof testing for natives implemented in JavaScript really | 7342 // To make typeof testing for natives implemented in JavaScript really |
| 6848 // efficient, we generate special code for expressions of the form: | 7343 // efficient, we generate special code for expressions of the form: |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7017 Result answer = frame_->CallStub(&stub, 2); | 7512 Result answer = frame_->CallStub(&stub, 2); |
| 7018 answer.ToRegister(); | 7513 answer.ToRegister(); |
| 7019 __ test(answer.reg(), Operand(answer.reg())); | 7514 __ test(answer.reg(), Operand(answer.reg())); |
| 7020 answer.Unuse(); | 7515 answer.Unuse(); |
| 7021 destination()->Split(zero); | 7516 destination()->Split(zero); |
| 7022 return; | 7517 return; |
| 7023 } | 7518 } |
| 7024 default: | 7519 default: |
| 7025 UNREACHABLE(); | 7520 UNREACHABLE(); |
| 7026 } | 7521 } |
| 7027 if (!left_already_loaded) Load(left); | 7522 |
| 7028 Load(right); | 7523 if (left->IsTrivial()) { |
| 7524 if (!left_already_loaded) { |
| 7525 Load(right); |
| 7526 Result right_result = frame_->Pop(); |
| 7527 frame_->Push(left); |
| 7528 frame_->Push(&right_result); |
| 7529 } else { |
| 7530 Load(right); |
| 7531 } |
| 7532 } else { |
| 7533 if (!left_already_loaded) Load(left); |
| 7534 Load(right); |
| 7535 } |
| 7029 Comparison(node, cc, strict, destination()); | 7536 Comparison(node, cc, strict, destination()); |
| 7030 } | 7537 } |
| 7031 | 7538 |
| 7032 | 7539 |
| 7033 #ifdef DEBUG | 7540 #ifdef DEBUG |
| 7034 bool CodeGenerator::HasValidEntryRegisters() { | 7541 bool CodeGenerator::HasValidEntryRegisters() { |
| 7035 return (allocator()->count(eax) == (frame()->is_used(eax) ? 1 : 0)) | 7542 return (allocator()->count(eax) == (frame()->is_used(eax) ? 1 : 0)) |
| 7036 && (allocator()->count(ebx) == (frame()->is_used(ebx) ? 1 : 0)) | 7543 && (allocator()->count(ebx) == (frame()->is_used(ebx) ? 1 : 0)) |
| 7037 && (allocator()->count(ecx) == (frame()->is_used(ecx) ? 1 : 0)) | 7544 && (allocator()->count(ecx) == (frame()->is_used(ecx) ? 1 : 0)) |
| 7038 && (allocator()->count(edx) == (frame()->is_used(edx) ? 1 : 0)) | 7545 && (allocator()->count(edx) == (frame()->is_used(edx) ? 1 : 0)) |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7364 // Use masm-> here instead of the double underscore macro since extra | 7871 // Use masm-> here instead of the double underscore macro since extra |
| 7365 // coverage code can interfere with the patching. | 7872 // coverage code can interfere with the patching. |
| 7366 masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 7873 masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
| 7367 Immediate(Factory::null_value())); | 7874 Immediate(Factory::null_value())); |
| 7368 deferred->Branch(not_equal); | 7875 deferred->Branch(not_equal); |
| 7369 | 7876 |
| 7370 // Check that the key is a smi. | 7877 // Check that the key is a smi. |
| 7371 if (!key.is_smi()) { | 7878 if (!key.is_smi()) { |
| 7372 __ test(key.reg(), Immediate(kSmiTagMask)); | 7879 __ test(key.reg(), Immediate(kSmiTagMask)); |
| 7373 deferred->Branch(not_zero); | 7880 deferred->Branch(not_zero); |
| 7881 } else { |
| 7882 if (FLAG_debug_code) __ AbortIfNotSmi(key.reg()); |
| 7374 } | 7883 } |
| 7375 | 7884 |
| 7376 // Get the elements array from the receiver and check that it | 7885 // Get the elements array from the receiver and check that it |
| 7377 // is not a dictionary. | 7886 // is not a dictionary. |
| 7378 __ mov(elements.reg(), | 7887 __ mov(elements.reg(), |
| 7379 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); | 7888 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); |
| 7380 __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset), | 7889 __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset), |
| 7381 Immediate(Factory::fixed_array_map())); | 7890 Immediate(Factory::fixed_array_map())); |
| 7382 deferred->Branch(not_equal); | 7891 deferred->Branch(not_equal); |
| 7383 | 7892 |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7517 | 8026 |
| 7518 | 8027 |
| 7519 static void CheckTwoForSminess(MacroAssembler* masm, | 8028 static void CheckTwoForSminess(MacroAssembler* masm, |
| 7520 Register left, Register right, Register scratch, | 8029 Register left, Register right, Register scratch, |
| 7521 NumberInfo left_info, NumberInfo right_info, | 8030 NumberInfo left_info, NumberInfo right_info, |
| 7522 DeferredInlineBinaryOperation* deferred) { | 8031 DeferredInlineBinaryOperation* deferred) { |
| 7523 if (left.is(right)) { | 8032 if (left.is(right)) { |
| 7524 if (!left_info.IsSmi()) { | 8033 if (!left_info.IsSmi()) { |
| 7525 __ test(left, Immediate(kSmiTagMask)); | 8034 __ test(left, Immediate(kSmiTagMask)); |
| 7526 deferred->Branch(not_zero); | 8035 deferred->Branch(not_zero); |
| 8036 } else { |
| 8037 if (FLAG_debug_code) __ AbortIfNotSmi(left); |
| 7527 } | 8038 } |
| 7528 } else if (!left_info.IsSmi()) { | 8039 } else if (!left_info.IsSmi()) { |
| 7529 if (!right_info.IsSmi()) { | 8040 if (!right_info.IsSmi()) { |
| 7530 __ mov(scratch, left); | 8041 __ mov(scratch, left); |
| 7531 __ or_(scratch, Operand(right)); | 8042 __ or_(scratch, Operand(right)); |
| 7532 __ test(scratch, Immediate(kSmiTagMask)); | 8043 __ test(scratch, Immediate(kSmiTagMask)); |
| 7533 deferred->Branch(not_zero); | 8044 deferred->Branch(not_zero); |
| 7534 } else { | 8045 } else { |
| 7535 __ test(left, Immediate(kSmiTagMask)); | 8046 __ test(left, Immediate(kSmiTagMask)); |
| 7536 deferred->Branch(not_zero); | 8047 deferred->Branch(not_zero); |
| 8048 if (FLAG_debug_code) __ AbortIfNotSmi(right); |
| 7537 } | 8049 } |
| 7538 } else { | 8050 } else { |
| 8051 if (FLAG_debug_code) __ AbortIfNotSmi(left); |
| 7539 if (!right_info.IsSmi()) { | 8052 if (!right_info.IsSmi()) { |
| 7540 __ test(right, Immediate(kSmiTagMask)); | 8053 __ test(right, Immediate(kSmiTagMask)); |
| 7541 deferred->Branch(not_zero); | 8054 deferred->Branch(not_zero); |
| 8055 } else { |
| 8056 if (FLAG_debug_code) __ AbortIfNotSmi(right); |
| 7542 } | 8057 } |
| 7543 } | 8058 } |
| 7544 } | 8059 } |
| 7545 | 8060 |
| 7546 | 8061 |
| 7547 Handle<String> Reference::GetName() { | 8062 Handle<String> Reference::GetName() { |
| 7548 ASSERT(type_ == NAMED); | 8063 ASSERT(type_ == NAMED); |
| 7549 Property* property = expression_->AsProperty(); | 8064 Property* property = expression_->AsProperty(); |
| 7550 if (property == NULL) { | 8065 if (property == NULL) { |
| 7551 // Global variable reference treated as a named property reference. | 8066 // Global variable reference treated as a named property reference. |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8038 __ mov(ebx, eax); | 8553 __ mov(ebx, eax); |
| 8039 __ mov(eax, edx); | 8554 __ mov(eax, edx); |
| 8040 } | 8555 } |
| 8041 } | 8556 } |
| 8042 if (!HasArgsInRegisters()) { | 8557 if (!HasArgsInRegisters()) { |
| 8043 __ mov(right, Operand(esp, 1 * kPointerSize)); | 8558 __ mov(right, Operand(esp, 1 * kPointerSize)); |
| 8044 __ mov(left, Operand(esp, 2 * kPointerSize)); | 8559 __ mov(left, Operand(esp, 2 * kPointerSize)); |
| 8045 } | 8560 } |
| 8046 | 8561 |
| 8047 if (static_operands_type_.IsSmi()) { | 8562 if (static_operands_type_.IsSmi()) { |
| 8563 if (FLAG_debug_code) { |
| 8564 __ AbortIfNotSmi(left); |
| 8565 __ AbortIfNotSmi(right); |
| 8566 } |
| 8048 if (op_ == Token::BIT_OR) { | 8567 if (op_ == Token::BIT_OR) { |
| 8049 __ or_(right, Operand(left)); | 8568 __ or_(right, Operand(left)); |
| 8050 GenerateReturn(masm); | 8569 GenerateReturn(masm); |
| 8051 return; | 8570 return; |
| 8052 } else if (op_ == Token::BIT_AND) { | 8571 } else if (op_ == Token::BIT_AND) { |
| 8053 __ and_(right, Operand(left)); | 8572 __ and_(right, Operand(left)); |
| 8054 GenerateReturn(masm); | 8573 GenerateReturn(masm); |
| 8055 return; | 8574 return; |
| 8056 } else if (op_ == Token::BIT_XOR) { | 8575 } else if (op_ == Token::BIT_XOR) { |
| 8057 __ xor_(right, Operand(left)); | 8576 __ xor_(right, Operand(left)); |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8392 // forever for all other operations (also if smi code is skipped). | 8911 // forever for all other operations (also if smi code is skipped). |
| 8393 GenerateTypeTransition(masm); | 8912 GenerateTypeTransition(masm); |
| 8394 } | 8913 } |
| 8395 | 8914 |
| 8396 Label not_floats; | 8915 Label not_floats; |
| 8397 if (CpuFeatures::IsSupported(SSE2)) { | 8916 if (CpuFeatures::IsSupported(SSE2)) { |
| 8398 CpuFeatures::Scope use_sse2(SSE2); | 8917 CpuFeatures::Scope use_sse2(SSE2); |
| 8399 if (static_operands_type_.IsNumber()) { | 8918 if (static_operands_type_.IsNumber()) { |
| 8400 if (FLAG_debug_code) { | 8919 if (FLAG_debug_code) { |
| 8401 // Assert at runtime that inputs are only numbers. | 8920 // Assert at runtime that inputs are only numbers. |
| 8402 __ AbortIfNotNumber(edx, | 8921 __ AbortIfNotNumber(edx); |
| 8403 "GenericBinaryOpStub operand not a number."); | 8922 __ AbortIfNotNumber(eax); |
| 8404 __ AbortIfNotNumber(eax, | |
| 8405 "GenericBinaryOpStub operand not a number."); | |
| 8406 } | 8923 } |
| 8407 if (static_operands_type_.IsSmi()) { | 8924 if (static_operands_type_.IsSmi()) { |
| 8925 if (FLAG_debug_code) { |
| 8926 __ AbortIfNotSmi(edx); |
| 8927 __ AbortIfNotSmi(eax); |
| 8928 } |
| 8408 FloatingPointHelper::LoadSSE2Smis(masm, ecx); | 8929 FloatingPointHelper::LoadSSE2Smis(masm, ecx); |
| 8409 } else { | 8930 } else { |
| 8410 FloatingPointHelper::LoadSSE2Operands(masm); | 8931 FloatingPointHelper::LoadSSE2Operands(masm); |
| 8411 } | 8932 } |
| 8412 } else { | 8933 } else { |
| 8413 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); | 8934 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); |
| 8414 } | 8935 } |
| 8415 | 8936 |
| 8416 switch (op_) { | 8937 switch (op_) { |
| 8417 case Token::ADD: __ addsd(xmm0, xmm1); break; | 8938 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 8418 case Token::SUB: __ subsd(xmm0, xmm1); break; | 8939 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 8419 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 8940 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 8420 case Token::DIV: __ divsd(xmm0, xmm1); break; | 8941 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 8421 default: UNREACHABLE(); | 8942 default: UNREACHABLE(); |
| 8422 } | 8943 } |
| 8423 GenerateHeapResultAllocation(masm, &call_runtime); | 8944 GenerateHeapResultAllocation(masm, &call_runtime); |
| 8424 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 8945 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 8425 GenerateReturn(masm); | 8946 GenerateReturn(masm); |
| 8426 } else { // SSE2 not available, use FPU. | 8947 } else { // SSE2 not available, use FPU. |
| 8427 if (static_operands_type_.IsNumber()) { | 8948 if (static_operands_type_.IsNumber()) { |
| 8428 if (FLAG_debug_code) { | 8949 if (FLAG_debug_code) { |
| 8429 // Assert at runtime that inputs are only numbers. | 8950 // Assert at runtime that inputs are only numbers. |
| 8430 __ AbortIfNotNumber(edx, | 8951 __ AbortIfNotNumber(edx); |
| 8431 "GenericBinaryOpStub operand not a number."); | 8952 __ AbortIfNotNumber(eax); |
| 8432 __ AbortIfNotNumber(eax, | |
| 8433 "GenericBinaryOpStub operand not a number."); | |
| 8434 } | 8953 } |
| 8435 } else { | 8954 } else { |
| 8436 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 8955 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
| 8437 } | 8956 } |
| 8438 FloatingPointHelper::LoadFloatOperands( | 8957 FloatingPointHelper::LoadFloatOperands( |
| 8439 masm, | 8958 masm, |
| 8440 ecx, | 8959 ecx, |
| 8441 FloatingPointHelper::ARGS_IN_REGISTERS); | 8960 FloatingPointHelper::ARGS_IN_REGISTERS); |
| 8442 switch (op_) { | 8961 switch (op_) { |
| 8443 case Token::ADD: __ faddp(1); break; | 8962 case Token::ADD: __ faddp(1); break; |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8785 __ TailCallExternalReference( | 9304 __ TailCallExternalReference( |
| 8786 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), | 9305 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), |
| 8787 6, | 9306 6, |
| 8788 1); | 9307 1); |
| 8789 | 9308 |
| 8790 // The entry point for the result calculation is assumed to be immediately | 9309 // The entry point for the result calculation is assumed to be immediately |
| 8791 // after this sequence. | 9310 // after this sequence. |
| 8792 __ bind(&get_result); | 9311 __ bind(&get_result); |
| 8793 } | 9312 } |
| 8794 | 9313 |
| 9314 |
| 8795 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { | 9315 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
| 8796 GenericBinaryOpStub stub(key, type_info); | 9316 GenericBinaryOpStub stub(key, type_info); |
| 8797 HandleScope scope; | |
| 8798 return stub.GetCode(); | 9317 return stub.GetCode(); |
| 8799 } | 9318 } |
| 8800 | 9319 |
| 8801 | 9320 |
| 8802 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 9321 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| 8803 // Input on stack: | 9322 // Input on stack: |
| 8804 // esp[4]: argument (should be number). | 9323 // esp[4]: argument (should be number). |
| 8805 // esp[0]: return address. | 9324 // esp[0]: return address. |
| 8806 // Test that eax is a number. | 9325 // Test that eax is a number. |
| 8807 Label runtime_call; | 9326 Label runtime_call; |
| (...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9153 Label* conversion_failure) { | 9672 Label* conversion_failure) { |
| 9154 // Check float operands. | 9673 // Check float operands. |
| 9155 Label arg1_is_object, check_undefined_arg1; | 9674 Label arg1_is_object, check_undefined_arg1; |
| 9156 Label arg2_is_object, check_undefined_arg2; | 9675 Label arg2_is_object, check_undefined_arg2; |
| 9157 Label load_arg2, done; | 9676 Label load_arg2, done; |
| 9158 | 9677 |
| 9159 if (!number_info.IsHeapNumber()) { | 9678 if (!number_info.IsHeapNumber()) { |
| 9160 if (!number_info.IsSmi()) { | 9679 if (!number_info.IsSmi()) { |
| 9161 __ test(edx, Immediate(kSmiTagMask)); | 9680 __ test(edx, Immediate(kSmiTagMask)); |
| 9162 __ j(not_zero, &arg1_is_object); | 9681 __ j(not_zero, &arg1_is_object); |
| 9682 } else { |
| 9683 if (FLAG_debug_code) __ AbortIfNotSmi(edx); |
| 9163 } | 9684 } |
| 9164 __ SmiUntag(edx); | 9685 __ SmiUntag(edx); |
| 9165 __ jmp(&load_arg2); | 9686 __ jmp(&load_arg2); |
| 9166 } | 9687 } |
| 9167 | 9688 |
| 9168 __ bind(&arg1_is_object); | 9689 __ bind(&arg1_is_object); |
| 9169 | 9690 |
| 9170 // Get the untagged integer version of the edx heap number in ecx. | 9691 // Get the untagged integer version of the edx heap number in ecx. |
| 9171 IntegerConvert(masm, edx, number_info, use_sse3, conversion_failure); | 9692 IntegerConvert(masm, edx, number_info, use_sse3, conversion_failure); |
| 9172 __ mov(edx, ecx); | 9693 __ mov(edx, ecx); |
| 9173 | 9694 |
| 9174 // Here edx has the untagged integer, eax has a Smi or a heap number. | 9695 // Here edx has the untagged integer, eax has a Smi or a heap number. |
| 9175 __ bind(&load_arg2); | 9696 __ bind(&load_arg2); |
| 9176 if (!number_info.IsHeapNumber()) { | 9697 if (!number_info.IsHeapNumber()) { |
| 9177 // Test if arg2 is a Smi. | 9698 // Test if arg2 is a Smi. |
| 9178 if (!number_info.IsSmi()) { | 9699 if (!number_info.IsSmi()) { |
| 9179 __ test(eax, Immediate(kSmiTagMask)); | 9700 __ test(eax, Immediate(kSmiTagMask)); |
| 9180 __ j(not_zero, &arg2_is_object); | 9701 __ j(not_zero, &arg2_is_object); |
| 9702 } else { |
| 9703 if (FLAG_debug_code) __ AbortIfNotSmi(eax); |
| 9181 } | 9704 } |
| 9182 __ SmiUntag(eax); | 9705 __ SmiUntag(eax); |
| 9183 __ mov(ecx, eax); | 9706 __ mov(ecx, eax); |
| 9184 __ jmp(&done); | 9707 __ jmp(&done); |
| 9185 } | 9708 } |
| 9186 | 9709 |
| 9187 __ bind(&arg2_is_object); | 9710 __ bind(&arg2_is_object); |
| 9188 | 9711 |
| 9189 // Get the untagged integer version of the eax heap number in ecx. | 9712 // Get the untagged integer version of the eax heap number in ecx. |
| 9190 IntegerConvert(masm, eax, number_info, use_sse3, conversion_failure); | 9713 IntegerConvert(masm, eax, number_info, use_sse3, conversion_failure); |
| (...skipping 867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10058 // edx: number of capture registers | 10581 // edx: number of capture registers |
| 10059 Label next_capture, done; | 10582 Label next_capture, done; |
| 10060 __ mov(eax, Operand(esp, kPreviousIndexOffset)); | 10583 __ mov(eax, Operand(esp, kPreviousIndexOffset)); |
| 10061 // Capture register counter starts from number of capture registers and | 10584 // Capture register counter starts from number of capture registers and |
| 10062 // counts down until wraping after zero. | 10585 // counts down until wraping after zero. |
| 10063 __ bind(&next_capture); | 10586 __ bind(&next_capture); |
| 10064 __ sub(Operand(edx), Immediate(1)); | 10587 __ sub(Operand(edx), Immediate(1)); |
| 10065 __ j(negative, &done); | 10588 __ j(negative, &done); |
| 10066 // Read the value from the static offsets vector buffer. | 10589 // Read the value from the static offsets vector buffer. |
| 10067 __ mov(edi, Operand(ecx, edx, times_int_size, 0)); | 10590 __ mov(edi, Operand(ecx, edx, times_int_size, 0)); |
| 10068 // Perform explicit shift | 10591 __ SmiTag(edi); |
| 10069 ASSERT_EQ(0, kSmiTag); | |
| 10070 __ shl(edi, kSmiTagSize); | |
| 10071 // Add previous index (from its stack slot) if value is not negative. | |
| 10072 Label capture_negative; | |
| 10073 // Carry flag set by shift above. | |
| 10074 __ j(negative, &capture_negative, not_taken); | |
| 10075 __ add(edi, Operand(eax)); // Add previous index (adding smi to smi). | |
| 10076 __ bind(&capture_negative); | |
| 10077 // Store the smi value in the last match info. | 10592 // Store the smi value in the last match info. |
| 10078 __ mov(FieldOperand(ebx, | 10593 __ mov(FieldOperand(ebx, |
| 10079 edx, | 10594 edx, |
| 10080 times_pointer_size, | 10595 times_pointer_size, |
| 10081 RegExpImpl::kFirstCaptureOffset), | 10596 RegExpImpl::kFirstCaptureOffset), |
| 10082 edi); | 10597 edi); |
| 10083 __ jmp(&next_capture); | 10598 __ jmp(&next_capture); |
| 10084 __ bind(&done); | 10599 __ bind(&done); |
| 10085 | 10600 |
| 10086 // Return last match info. | 10601 // Return last match info. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10155 // Generate code to lookup number in the number string cache. | 10670 // Generate code to lookup number in the number string cache. |
| 10156 GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); | 10671 GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); |
| 10157 __ ret(1 * kPointerSize); | 10672 __ ret(1 * kPointerSize); |
| 10158 | 10673 |
| 10159 __ bind(&runtime); | 10674 __ bind(&runtime); |
| 10160 // Handle number to string in the runtime system if not found in the cache. | 10675 // Handle number to string in the runtime system if not found in the cache. |
| 10161 __ TailCallRuntime(Runtime::kNumberToString, 1, 1); | 10676 __ TailCallRuntime(Runtime::kNumberToString, 1, 1); |
| 10162 } | 10677 } |
| 10163 | 10678 |
| 10164 | 10679 |
| 10680 void RecordWriteStub::Generate(MacroAssembler* masm) { |
| 10681 masm->RecordWriteHelper(object_, addr_, scratch_); |
| 10682 masm->ret(0); |
| 10683 } |
| 10684 |
| 10685 |
| 10165 void CompareStub::Generate(MacroAssembler* masm) { | 10686 void CompareStub::Generate(MacroAssembler* masm) { |
| 10166 Label call_builtin, done; | 10687 Label call_builtin, done; |
| 10167 | 10688 |
| 10168 // NOTICE! This code is only reached after a smi-fast-case check, so | 10689 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 10169 // it is certain that at least one operand isn't a smi. | 10690 // it is certain that at least one operand isn't a smi. |
| 10170 | 10691 |
| 10171 if (cc_ == equal) { // Both strict and non-strict. | 10692 if (cc_ == equal) { // Both strict and non-strict. |
| 10172 Label slow; // Fallthrough label. | 10693 Label slow; // Fallthrough label. |
| 10173 // Equality is almost reflexive (everything but NaN), so start by testing | 10694 // Equality is almost reflexive (everything but NaN), so start by testing |
| 10174 // for "identity and not NaN". | 10695 // for "identity and not NaN". |
| (...skipping 1578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11753 | 12274 |
| 11754 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12275 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 11755 // tagged as a small integer. | 12276 // tagged as a small integer. |
| 11756 __ bind(&runtime); | 12277 __ bind(&runtime); |
| 11757 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12278 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 11758 } | 12279 } |
| 11759 | 12280 |
| 11760 #undef __ | 12281 #undef __ |
| 11761 | 12282 |
| 11762 } } // namespace v8::internal | 12283 } } // namespace v8::internal |
| OLD | NEW |