| 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 |