OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 for (int i = 0; i < num_parameters; i++) { | 193 for (int i = 0; i < num_parameters; i++) { |
194 Variable* var = scope()->parameter(i); | 194 Variable* var = scope()->parameter(i); |
195 if (var->IsContextSlot()) { | 195 if (var->IsContextSlot()) { |
196 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 196 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
197 (num_parameters - 1 - i) * kPointerSize; | 197 (num_parameters - 1 - i) * kPointerSize; |
198 // Load parameter from stack. | 198 // Load parameter from stack. |
199 __ movq(rax, Operand(rbp, parameter_offset)); | 199 __ movq(rax, Operand(rbp, parameter_offset)); |
200 // Store it in the context. | 200 // Store it in the context. |
201 int context_offset = Context::SlotOffset(var->index()); | 201 int context_offset = Context::SlotOffset(var->index()); |
202 __ movq(Operand(rsi, context_offset), rax); | 202 __ movq(Operand(rsi, context_offset), rax); |
203 // Update the write barrier. This clobbers all involved | 203 // Update the write barrier. This clobbers rax and rbx. |
204 // registers, so we have use a third register to avoid | 204 __ RecordWriteContextSlot( |
205 // clobbering rsi. | 205 rsi, context_offset, rax, rbx, kDontSaveFPRegs); |
206 __ movq(rcx, rsi); | |
207 __ RecordWrite(rcx, context_offset, rax, rbx); | |
208 } | 206 } |
209 } | 207 } |
210 } | 208 } |
211 | 209 |
212 // Possibly allocate an arguments object. | 210 // Possibly allocate an arguments object. |
213 Variable* arguments = scope()->arguments(); | 211 Variable* arguments = scope()->arguments(); |
214 if (arguments != NULL) { | 212 if (arguments != NULL) { |
215 // Arguments object must be allocated after the context object, in | 213 // Arguments object must be allocated after the context object, in |
216 // case the "arguments" or ".arguments" variables are in the context. | 214 // case the "arguments" or ".arguments" variables are in the context. |
217 Comment cmnt(masm_, "[ Allocate arguments object"); | 215 Comment cmnt(masm_, "[ Allocate arguments object"); |
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 void FullCodeGenerator::SetVar(Variable* var, | 634 void FullCodeGenerator::SetVar(Variable* var, |
637 Register src, | 635 Register src, |
638 Register scratch0, | 636 Register scratch0, |
639 Register scratch1) { | 637 Register scratch1) { |
640 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); | 638 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
641 ASSERT(!scratch0.is(src)); | 639 ASSERT(!scratch0.is(src)); |
642 ASSERT(!scratch0.is(scratch1)); | 640 ASSERT(!scratch0.is(scratch1)); |
643 ASSERT(!scratch1.is(src)); | 641 ASSERT(!scratch1.is(src)); |
644 MemOperand location = VarOperand(var, scratch0); | 642 MemOperand location = VarOperand(var, scratch0); |
645 __ movq(location, src); | 643 __ movq(location, src); |
| 644 |
646 // Emit the write barrier code if the location is in the heap. | 645 // Emit the write barrier code if the location is in the heap. |
647 if (var->IsContextSlot()) { | 646 if (var->IsContextSlot()) { |
648 int offset = Context::SlotOffset(var->index()); | 647 int offset = Context::SlotOffset(var->index()); |
649 __ RecordWrite(scratch0, offset, src, scratch1); | 648 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs); |
650 } | 649 } |
651 } | 650 } |
652 | 651 |
653 | 652 |
654 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 653 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
655 bool should_normalize, | 654 bool should_normalize, |
656 Label* if_true, | 655 Label* if_true, |
657 Label* if_false) { | 656 Label* if_false) { |
658 // Only prepare for bailouts before splits if we're in a test | 657 // Only prepare for bailouts before splits if we're in a test |
659 // context. Otherwise, we let the Visit function deal with the | 658 // context. Otherwise, we let the Visit function deal with the |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); | 712 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); |
714 __ Check(not_equal, "Declaration in with context."); | 713 __ Check(not_equal, "Declaration in with context."); |
715 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); | 714 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); |
716 __ Check(not_equal, "Declaration in catch context."); | 715 __ Check(not_equal, "Declaration in catch context."); |
717 } | 716 } |
718 if (function != NULL) { | 717 if (function != NULL) { |
719 Comment cmnt(masm_, "[ Declaration"); | 718 Comment cmnt(masm_, "[ Declaration"); |
720 VisitForAccumulatorValue(function); | 719 VisitForAccumulatorValue(function); |
721 __ movq(ContextOperand(rsi, variable->index()), result_register()); | 720 __ movq(ContextOperand(rsi, variable->index()), result_register()); |
722 int offset = Context::SlotOffset(variable->index()); | 721 int offset = Context::SlotOffset(variable->index()); |
723 __ movq(rbx, rsi); | 722 // We know that we have written a function, which is not a smi. |
724 __ RecordWrite(rbx, offset, result_register(), rcx); | 723 __ RecordWriteContextSlot(rsi, |
| 724 offset, |
| 725 result_register(), |
| 726 rcx, |
| 727 kDontSaveFPRegs, |
| 728 EMIT_REMEMBERED_SET, |
| 729 OMIT_SMI_CHECK); |
725 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 730 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
726 } else if (mode == Variable::CONST || mode == Variable::LET) { | 731 } else if (mode == Variable::CONST || mode == Variable::LET) { |
727 Comment cmnt(masm_, "[ Declaration"); | 732 Comment cmnt(masm_, "[ Declaration"); |
728 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 733 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
729 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); | 734 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); |
730 // No write barrier since the hole value is in old space. | 735 // No write barrier since the hole value is in old space. |
731 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 736 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
732 } | 737 } |
733 break; | 738 break; |
734 | 739 |
(...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1449 } | 1454 } |
1450 VisitForAccumulatorValue(subexpr); | 1455 VisitForAccumulatorValue(subexpr); |
1451 | 1456 |
1452 // Store the subexpression value in the array's elements. | 1457 // Store the subexpression value in the array's elements. |
1453 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 1458 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. |
1454 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 1459 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); |
1455 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1460 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1456 __ movq(FieldOperand(rbx, offset), result_register()); | 1461 __ movq(FieldOperand(rbx, offset), result_register()); |
1457 | 1462 |
1458 // Update the write barrier for the array store. | 1463 // Update the write barrier for the array store. |
1459 __ RecordWrite(rbx, offset, result_register(), rcx); | 1464 __ RecordWriteField(rbx, offset, result_register(), rcx, kDontSaveFPRegs); |
1460 | 1465 |
1461 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1466 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1462 } | 1467 } |
1463 | 1468 |
1464 if (result_saved) { | 1469 if (result_saved) { |
1465 context()->PlugTOS(); | 1470 context()->PlugTOS(); |
1466 } else { | 1471 } else { |
1467 context()->Plug(rax); | 1472 context()->Plug(rax); |
1468 } | 1473 } |
1469 } | 1474 } |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1775 MemOperand location = VarOperand(var, rcx); | 1780 MemOperand location = VarOperand(var, rcx); |
1776 __ movq(rdx, location); | 1781 __ movq(rdx, location); |
1777 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1782 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
1778 __ j(not_equal, &assign, Label::kNear); | 1783 __ j(not_equal, &assign, Label::kNear); |
1779 __ Push(var->name()); | 1784 __ Push(var->name()); |
1780 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1785 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1781 __ bind(&assign); | 1786 __ bind(&assign); |
1782 __ movq(location, rax); | 1787 __ movq(location, rax); |
1783 if (var->IsContextSlot()) { | 1788 if (var->IsContextSlot()) { |
1784 __ movq(rdx, rax); | 1789 __ movq(rdx, rax); |
1785 __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx); | 1790 __ RecordWriteContextSlot( |
| 1791 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
1786 } | 1792 } |
1787 } | 1793 } |
1788 | 1794 |
1789 } else if (var->mode() != Variable::CONST) { | 1795 } else if (var->mode() != Variable::CONST) { |
1790 // Assignment to var or initializing assignment to let. | 1796 // Assignment to var or initializing assignment to let. |
1791 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1797 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1792 MemOperand location = VarOperand(var, rcx); | 1798 MemOperand location = VarOperand(var, rcx); |
1793 if (FLAG_debug_code && op == Token::INIT_LET) { | 1799 if (FLAG_debug_code && op == Token::INIT_LET) { |
1794 // Check for an uninitialized let binding. | 1800 // Check for an uninitialized let binding. |
1795 __ movq(rdx, location); | 1801 __ movq(rdx, location); |
1796 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1802 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
1797 __ Check(equal, "Let binding re-initialization."); | 1803 __ Check(equal, "Let binding re-initialization."); |
1798 } | 1804 } |
1799 // Perform the assignment. | 1805 // Perform the assignment. |
1800 __ movq(location, rax); | 1806 __ movq(location, rax); |
1801 if (var->IsContextSlot()) { | 1807 if (var->IsContextSlot()) { |
1802 __ movq(rdx, rax); | 1808 __ movq(rdx, rax); |
1803 __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx); | 1809 __ RecordWriteContextSlot( |
| 1810 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
1804 } | 1811 } |
1805 } else { | 1812 } else { |
1806 ASSERT(var->IsLookupSlot()); | 1813 ASSERT(var->IsLookupSlot()); |
1807 __ push(rax); // Value. | 1814 __ push(rax); // Value. |
1808 __ push(rsi); // Context. | 1815 __ push(rsi); // Context. |
1809 __ Push(var->name()); | 1816 __ Push(var->name()); |
1810 __ Push(Smi::FromInt(strict_mode_flag())); | 1817 __ Push(Smi::FromInt(strict_mode_flag())); |
1811 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1818 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1812 } | 1819 } |
1813 } | 1820 } |
(...skipping 910 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2724 | 2731 |
2725 // If the object is not a value type, return the value. | 2732 // If the object is not a value type, return the value. |
2726 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx); | 2733 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx); |
2727 __ j(not_equal, &done); | 2734 __ j(not_equal, &done); |
2728 | 2735 |
2729 // Store the value. | 2736 // Store the value. |
2730 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax); | 2737 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax); |
2731 // Update the write barrier. Save the value as it will be | 2738 // Update the write barrier. Save the value as it will be |
2732 // overwritten by the write barrier code and is needed afterward. | 2739 // overwritten by the write barrier code and is needed afterward. |
2733 __ movq(rdx, rax); | 2740 __ movq(rdx, rax); |
2734 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx); | 2741 __ RecordWriteField(rbx, JSValue::kValueOffset, rdx, rcx, kDontSaveFPRegs); |
2735 | 2742 |
2736 __ bind(&done); | 2743 __ bind(&done); |
2737 context()->Plug(rax); | 2744 context()->Plug(rax); |
2738 } | 2745 } |
2739 | 2746 |
2740 | 2747 |
2741 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { | 2748 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { |
2742 ASSERT_EQ(args->length(), 1); | 2749 ASSERT_EQ(args->length(), 1); |
2743 | 2750 |
2744 // Load the argument on the stack and call the stub. | 2751 // Load the argument on the stack and call the stub. |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3008 FixedArray::kHeaderSize)); | 3015 FixedArray::kHeaderSize)); |
3009 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size, | 3016 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size, |
3010 FixedArray::kHeaderSize)); | 3017 FixedArray::kHeaderSize)); |
3011 | 3018 |
3012 // Swap elements. Use object and temp as scratch registers. | 3019 // Swap elements. Use object and temp as scratch registers. |
3013 __ movq(object, Operand(index_1, 0)); | 3020 __ movq(object, Operand(index_1, 0)); |
3014 __ movq(temp, Operand(index_2, 0)); | 3021 __ movq(temp, Operand(index_2, 0)); |
3015 __ movq(Operand(index_2, 0), object); | 3022 __ movq(Operand(index_2, 0), object); |
3016 __ movq(Operand(index_1, 0), temp); | 3023 __ movq(Operand(index_1, 0), temp); |
3017 | 3024 |
3018 Label new_space; | 3025 Label no_remembered_set; |
3019 __ InNewSpace(elements, temp, equal, &new_space); | 3026 __ CheckPageFlag(elements, |
| 3027 temp, |
| 3028 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 3029 not_zero, |
| 3030 &no_remembered_set, |
| 3031 Label::kNear); |
| 3032 // Possible optimization: do a check that both values are Smis |
| 3033 // (or them and test against Smi mask.) |
3020 | 3034 |
3021 __ movq(object, elements); | 3035 // We are swapping two objects in an array and the incremental marker never |
3022 __ RecordWriteHelper(object, index_1, temp); | 3036 // pauses in the middle of scanning a single object. Therefore the |
3023 __ RecordWriteHelper(elements, index_2, temp); | 3037 // incremental marker is not disturbed, so we don't need to call the |
| 3038 // RecordWrite stub that notifies the incremental marker. |
| 3039 __ RememberedSetHelper( |
| 3040 index_1, temp, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); |
| 3041 __ RememberedSetHelper( |
| 3042 index_2, temp, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); |
3024 | 3043 |
3025 __ bind(&new_space); | 3044 __ bind(&no_remembered_set); |
| 3045 |
3026 // We are done. Drop elements from the stack, and return undefined. | 3046 // We are done. Drop elements from the stack, and return undefined. |
3027 __ addq(rsp, Immediate(3 * kPointerSize)); | 3047 __ addq(rsp, Immediate(3 * kPointerSize)); |
3028 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 3048 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
3029 __ jmp(&done); | 3049 __ jmp(&done); |
3030 | 3050 |
3031 __ bind(&slow_case); | 3051 __ bind(&slow_case); |
3032 __ CallRuntime(Runtime::kSwapElements, 3); | 3052 __ CallRuntime(Runtime::kSwapElements, 3); |
3033 | 3053 |
3034 __ bind(&done); | 3054 __ bind(&done); |
3035 context()->Plug(rax); | 3055 context()->Plug(rax); |
(...skipping 1117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4153 *context_length = 0; | 4173 *context_length = 0; |
4154 return previous_; | 4174 return previous_; |
4155 } | 4175 } |
4156 | 4176 |
4157 | 4177 |
4158 #undef __ | 4178 #undef __ |
4159 | 4179 |
4160 } } // namespace v8::internal | 4180 } } // namespace v8::internal |
4161 | 4181 |
4162 #endif // V8_TARGET_ARCH_X64 | 4182 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |