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 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 Label ok; | 140 Label ok; |
141 __ testq(rcx, rcx); | 141 __ testq(rcx, rcx); |
142 __ j(zero, &ok, Label::kNear); | 142 __ j(zero, &ok, Label::kNear); |
143 // +1 for return address. | 143 // +1 for return address. |
144 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; | 144 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; |
145 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); | 145 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); |
146 __ movq(Operand(rsp, receiver_offset), kScratchRegister); | 146 __ movq(Operand(rsp, receiver_offset), kScratchRegister); |
147 __ bind(&ok); | 147 __ bind(&ok); |
148 } | 148 } |
149 | 149 |
| 150 // Open a frame scope to indicate that there is a frame on the stack. The |
| 151 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 152 // the frame (that is done below). |
| 153 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 154 |
150 __ push(rbp); // Caller's frame pointer. | 155 __ push(rbp); // Caller's frame pointer. |
151 __ movq(rbp, rsp); | 156 __ movq(rbp, rsp); |
152 __ push(rsi); // Callee's context. | 157 __ push(rsi); // Callee's context. |
153 __ push(rdi); // Callee's JS Function. | 158 __ push(rdi); // Callee's JS Function. |
154 | 159 |
155 { Comment cmnt(masm_, "[ Allocate locals"); | 160 { Comment cmnt(masm_, "[ Allocate locals"); |
156 int locals_count = info->scope()->num_stack_slots(); | 161 int locals_count = info->scope()->num_stack_slots(); |
157 if (locals_count == 1) { | 162 if (locals_count == 1) { |
158 __ PushRoot(Heap::kUndefinedValueRootIndex); | 163 __ PushRoot(Heap::kUndefinedValueRootIndex); |
159 } else if (locals_count > 1) { | 164 } else if (locals_count > 1) { |
(...skipping 28 matching lines...) Expand all Loading... |
188 for (int i = 0; i < num_parameters; i++) { | 193 for (int i = 0; i < num_parameters; i++) { |
189 Variable* var = scope()->parameter(i); | 194 Variable* var = scope()->parameter(i); |
190 if (var->IsContextSlot()) { | 195 if (var->IsContextSlot()) { |
191 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 196 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
192 (num_parameters - 1 - i) * kPointerSize; | 197 (num_parameters - 1 - i) * kPointerSize; |
193 // Load parameter from stack. | 198 // Load parameter from stack. |
194 __ movq(rax, Operand(rbp, parameter_offset)); | 199 __ movq(rax, Operand(rbp, parameter_offset)); |
195 // Store it in the context. | 200 // Store it in the context. |
196 int context_offset = Context::SlotOffset(var->index()); | 201 int context_offset = Context::SlotOffset(var->index()); |
197 __ movq(Operand(rsi, context_offset), rax); | 202 __ movq(Operand(rsi, context_offset), rax); |
198 // Update the write barrier. This clobbers all involved | 203 // Update the write barrier. This clobbers rax and rbx. |
199 // registers, so we have use a third register to avoid | 204 __ RecordWriteContextSlot( |
200 // clobbering rsi. | 205 rsi, context_offset, rax, rbx, kDontSaveFPRegs); |
201 __ movq(rcx, rsi); | |
202 __ RecordWrite(rcx, context_offset, rax, rbx); | |
203 } | 206 } |
204 } | 207 } |
205 } | 208 } |
206 | 209 |
207 // Possibly allocate an arguments object. | 210 // Possibly allocate an arguments object. |
208 Variable* arguments = scope()->arguments(); | 211 Variable* arguments = scope()->arguments(); |
209 if (arguments != NULL) { | 212 if (arguments != NULL) { |
210 // Arguments object must be allocated after the context object, in | 213 // Arguments object must be allocated after the context object, in |
211 // case the "arguments" or ".arguments" variables are in the context. | 214 // case the "arguments" or ".arguments" variables are in the context. |
212 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... |
631 void FullCodeGenerator::SetVar(Variable* var, | 634 void FullCodeGenerator::SetVar(Variable* var, |
632 Register src, | 635 Register src, |
633 Register scratch0, | 636 Register scratch0, |
634 Register scratch1) { | 637 Register scratch1) { |
635 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); | 638 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
636 ASSERT(!scratch0.is(src)); | 639 ASSERT(!scratch0.is(src)); |
637 ASSERT(!scratch0.is(scratch1)); | 640 ASSERT(!scratch0.is(scratch1)); |
638 ASSERT(!scratch1.is(src)); | 641 ASSERT(!scratch1.is(src)); |
639 MemOperand location = VarOperand(var, scratch0); | 642 MemOperand location = VarOperand(var, scratch0); |
640 __ movq(location, src); | 643 __ movq(location, src); |
| 644 |
641 // 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. |
642 if (var->IsContextSlot()) { | 646 if (var->IsContextSlot()) { |
643 int offset = Context::SlotOffset(var->index()); | 647 int offset = Context::SlotOffset(var->index()); |
644 __ RecordWrite(scratch0, offset, src, scratch1); | 648 __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs); |
645 } | 649 } |
646 } | 650 } |
647 | 651 |
648 | 652 |
649 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 653 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
650 bool should_normalize, | 654 bool should_normalize, |
651 Label* if_true, | 655 Label* if_true, |
652 Label* if_false) { | 656 Label* if_false) { |
653 // 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 |
654 // 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... |
708 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); | 712 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); |
709 __ Check(not_equal, "Declaration in with context."); | 713 __ Check(not_equal, "Declaration in with context."); |
710 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); | 714 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); |
711 __ Check(not_equal, "Declaration in catch context."); | 715 __ Check(not_equal, "Declaration in catch context."); |
712 } | 716 } |
713 if (function != NULL) { | 717 if (function != NULL) { |
714 Comment cmnt(masm_, "[ Declaration"); | 718 Comment cmnt(masm_, "[ Declaration"); |
715 VisitForAccumulatorValue(function); | 719 VisitForAccumulatorValue(function); |
716 __ movq(ContextOperand(rsi, variable->index()), result_register()); | 720 __ movq(ContextOperand(rsi, variable->index()), result_register()); |
717 int offset = Context::SlotOffset(variable->index()); | 721 int offset = Context::SlotOffset(variable->index()); |
718 __ movq(rbx, rsi); | 722 // We know that we have written a function, which is not a smi. |
719 __ 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); |
720 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 730 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
721 } else if (mode == Variable::CONST || mode == Variable::LET) { | 731 } else if (mode == Variable::CONST || mode == Variable::LET) { |
722 Comment cmnt(masm_, "[ Declaration"); | 732 Comment cmnt(masm_, "[ Declaration"); |
723 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 733 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
724 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); | 734 __ movq(ContextOperand(rsi, variable->index()), kScratchRegister); |
725 // No write barrier since the hole value is in old space. | 735 // No write barrier since the hole value is in old space. |
726 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 736 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
727 } | 737 } |
728 break; | 738 break; |
729 | 739 |
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1438 continue; | 1448 continue; |
1439 } | 1449 } |
1440 | 1450 |
1441 if (!result_saved) { | 1451 if (!result_saved) { |
1442 __ push(rax); | 1452 __ push(rax); |
1443 result_saved = true; | 1453 result_saved = true; |
1444 } | 1454 } |
1445 VisitForAccumulatorValue(subexpr); | 1455 VisitForAccumulatorValue(subexpr); |
1446 | 1456 |
1447 // Store the subexpression value in the array's elements. | 1457 // Store the subexpression value in the array's elements. |
1448 __ movq(rbx, Operand(rsp, 0)); // Copy of array literal. | 1458 __ movq(r8, Operand(rsp, 0)); // Copy of array literal. |
1449 __ movq(rbx, FieldOperand(rbx, JSObject::kElementsOffset)); | 1459 __ movq(rbx, FieldOperand(r8, JSObject::kElementsOffset)); |
1450 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1460 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1451 __ movq(FieldOperand(rbx, offset), result_register()); | 1461 __ movq(FieldOperand(rbx, offset), result_register()); |
1452 | 1462 |
| 1463 Label no_map_change; |
| 1464 __ JumpIfSmi(result_register(), &no_map_change); |
1453 // Update the write barrier for the array store. | 1465 // Update the write barrier for the array store. |
1454 __ RecordWrite(rbx, offset, result_register(), rcx); | 1466 __ RecordWriteField(rbx, offset, result_register(), rcx, |
| 1467 kDontSaveFPRegs, |
| 1468 EMIT_REMEMBERED_SET, |
| 1469 OMIT_SMI_CHECK); |
| 1470 if (FLAG_smi_only_arrays) { |
| 1471 __ movq(rdi, FieldOperand(rbx, JSObject::kMapOffset)); |
| 1472 __ CheckFastSmiOnlyElements(rdi, &no_map_change, Label::kNear); |
| 1473 __ push(r8); |
| 1474 __ CallRuntime(Runtime::kNonSmiElementStored, 1); |
| 1475 } |
| 1476 __ bind(&no_map_change); |
1455 | 1477 |
1456 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1478 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1457 } | 1479 } |
1458 | 1480 |
1459 if (result_saved) { | 1481 if (result_saved) { |
1460 context()->PlugTOS(); | 1482 context()->PlugTOS(); |
1461 } else { | 1483 } else { |
1462 context()->Plug(rax); | 1484 context()->Plug(rax); |
1463 } | 1485 } |
1464 } | 1486 } |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1770 MemOperand location = VarOperand(var, rcx); | 1792 MemOperand location = VarOperand(var, rcx); |
1771 __ movq(rdx, location); | 1793 __ movq(rdx, location); |
1772 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1794 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
1773 __ j(not_equal, &assign, Label::kNear); | 1795 __ j(not_equal, &assign, Label::kNear); |
1774 __ Push(var->name()); | 1796 __ Push(var->name()); |
1775 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1797 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1776 __ bind(&assign); | 1798 __ bind(&assign); |
1777 __ movq(location, rax); | 1799 __ movq(location, rax); |
1778 if (var->IsContextSlot()) { | 1800 if (var->IsContextSlot()) { |
1779 __ movq(rdx, rax); | 1801 __ movq(rdx, rax); |
1780 __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx); | 1802 __ RecordWriteContextSlot( |
| 1803 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
1781 } | 1804 } |
1782 } | 1805 } |
1783 | 1806 |
1784 } else if (var->mode() != Variable::CONST) { | 1807 } else if (var->mode() != Variable::CONST) { |
1785 // Assignment to var or initializing assignment to let. | 1808 // Assignment to var or initializing assignment to let. |
1786 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1809 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1787 MemOperand location = VarOperand(var, rcx); | 1810 MemOperand location = VarOperand(var, rcx); |
1788 if (FLAG_debug_code && op == Token::INIT_LET) { | 1811 if (FLAG_debug_code && op == Token::INIT_LET) { |
1789 // Check for an uninitialized let binding. | 1812 // Check for an uninitialized let binding. |
1790 __ movq(rdx, location); | 1813 __ movq(rdx, location); |
1791 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1814 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
1792 __ Check(equal, "Let binding re-initialization."); | 1815 __ Check(equal, "Let binding re-initialization."); |
1793 } | 1816 } |
1794 // Perform the assignment. | 1817 // Perform the assignment. |
1795 __ movq(location, rax); | 1818 __ movq(location, rax); |
1796 if (var->IsContextSlot()) { | 1819 if (var->IsContextSlot()) { |
1797 __ movq(rdx, rax); | 1820 __ movq(rdx, rax); |
1798 __ RecordWrite(rcx, Context::SlotOffset(var->index()), rdx, rbx); | 1821 __ RecordWriteContextSlot( |
| 1822 rcx, Context::SlotOffset(var->index()), rdx, rbx, kDontSaveFPRegs); |
1799 } | 1823 } |
1800 } else { | 1824 } else { |
1801 ASSERT(var->IsLookupSlot()); | 1825 ASSERT(var->IsLookupSlot()); |
1802 __ push(rax); // Value. | 1826 __ push(rax); // Value. |
1803 __ push(rsi); // Context. | 1827 __ push(rsi); // Context. |
1804 __ Push(var->name()); | 1828 __ Push(var->name()); |
1805 __ Push(Smi::FromInt(strict_mode_flag())); | 1829 __ Push(Smi::FromInt(strict_mode_flag())); |
1806 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1830 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1807 } | 1831 } |
1808 } | 1832 } |
(...skipping 729 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2538 ASSERT(args->length() == 1); | 2562 ASSERT(args->length() == 1); |
2539 Label done, null, function, non_function_constructor; | 2563 Label done, null, function, non_function_constructor; |
2540 | 2564 |
2541 VisitForAccumulatorValue(args->at(0)); | 2565 VisitForAccumulatorValue(args->at(0)); |
2542 | 2566 |
2543 // If the object is a smi, we return null. | 2567 // If the object is a smi, we return null. |
2544 __ JumpIfSmi(rax, &null); | 2568 __ JumpIfSmi(rax, &null); |
2545 | 2569 |
2546 // Check that the object is a JS object but take special care of JS | 2570 // Check that the object is a JS object but take special care of JS |
2547 // functions to make sure they have 'Function' as their class. | 2571 // functions to make sure they have 'Function' as their class. |
| 2572 // Assume that there are only two callable types, and one of them is at |
| 2573 // either end of the type range for JS object types. Saves extra comparisons. |
| 2574 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
2548 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax); | 2575 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax); |
2549 // Map is now in rax. | 2576 // Map is now in rax. |
2550 __ j(below, &null); | 2577 __ j(below, &null); |
| 2578 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
| 2579 FIRST_SPEC_OBJECT_TYPE + 1); |
| 2580 __ j(equal, &function); |
2551 | 2581 |
2552 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and | 2582 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE); |
2553 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after | 2583 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
2554 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. | 2584 LAST_SPEC_OBJECT_TYPE - 1); |
2555 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); | 2585 __ j(equal, &function); |
2556 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == | 2586 // Assume that there is no larger type. |
2557 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); | 2587 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); |
2558 __ CmpInstanceType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE); | |
2559 __ j(above_equal, &function); | |
2560 | 2588 |
2561 // Check if the constructor in the map is a function. | 2589 // Check if the constructor in the map is a JS function. |
2562 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset)); | 2590 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset)); |
2563 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); | 2591 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
2564 __ j(not_equal, &non_function_constructor); | 2592 __ j(not_equal, &non_function_constructor); |
2565 | 2593 |
2566 // rax now contains the constructor function. Grab the | 2594 // rax now contains the constructor function. Grab the |
2567 // instance class name from there. | 2595 // instance class name from there. |
2568 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); | 2596 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); |
2569 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset)); | 2597 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset)); |
2570 __ jmp(&done); | 2598 __ jmp(&done); |
2571 | 2599 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2719 | 2747 |
2720 // If the object is not a value type, return the value. | 2748 // If the object is not a value type, return the value. |
2721 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx); | 2749 __ CmpObjectType(rbx, JS_VALUE_TYPE, rcx); |
2722 __ j(not_equal, &done); | 2750 __ j(not_equal, &done); |
2723 | 2751 |
2724 // Store the value. | 2752 // Store the value. |
2725 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax); | 2753 __ movq(FieldOperand(rbx, JSValue::kValueOffset), rax); |
2726 // Update the write barrier. Save the value as it will be | 2754 // Update the write barrier. Save the value as it will be |
2727 // overwritten by the write barrier code and is needed afterward. | 2755 // overwritten by the write barrier code and is needed afterward. |
2728 __ movq(rdx, rax); | 2756 __ movq(rdx, rax); |
2729 __ RecordWrite(rbx, JSValue::kValueOffset, rdx, rcx); | 2757 __ RecordWriteField(rbx, JSValue::kValueOffset, rdx, rcx, kDontSaveFPRegs); |
2730 | 2758 |
2731 __ bind(&done); | 2759 __ bind(&done); |
2732 context()->Plug(rax); | 2760 context()->Plug(rax); |
2733 } | 2761 } |
2734 | 2762 |
2735 | 2763 |
2736 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { | 2764 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { |
2737 ASSERT_EQ(args->length(), 1); | 2765 ASSERT_EQ(args->length(), 1); |
2738 | 2766 |
2739 // Load the argument on the stack and call the stub. | 2767 // Load the argument on the stack and call the stub. |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3003 FixedArray::kHeaderSize)); | 3031 FixedArray::kHeaderSize)); |
3004 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size, | 3032 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size, |
3005 FixedArray::kHeaderSize)); | 3033 FixedArray::kHeaderSize)); |
3006 | 3034 |
3007 // Swap elements. Use object and temp as scratch registers. | 3035 // Swap elements. Use object and temp as scratch registers. |
3008 __ movq(object, Operand(index_1, 0)); | 3036 __ movq(object, Operand(index_1, 0)); |
3009 __ movq(temp, Operand(index_2, 0)); | 3037 __ movq(temp, Operand(index_2, 0)); |
3010 __ movq(Operand(index_2, 0), object); | 3038 __ movq(Operand(index_2, 0), object); |
3011 __ movq(Operand(index_1, 0), temp); | 3039 __ movq(Operand(index_1, 0), temp); |
3012 | 3040 |
3013 Label new_space; | 3041 Label no_remembered_set; |
3014 __ InNewSpace(elements, temp, equal, &new_space); | 3042 __ CheckPageFlag(elements, |
| 3043 temp, |
| 3044 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 3045 not_zero, |
| 3046 &no_remembered_set, |
| 3047 Label::kNear); |
| 3048 // Possible optimization: do a check that both values are Smis |
| 3049 // (or them and test against Smi mask.) |
3015 | 3050 |
3016 __ movq(object, elements); | 3051 // We are swapping two objects in an array and the incremental marker never |
3017 __ RecordWriteHelper(object, index_1, temp); | 3052 // pauses in the middle of scanning a single object. Therefore the |
3018 __ RecordWriteHelper(elements, index_2, temp); | 3053 // incremental marker is not disturbed, so we don't need to call the |
| 3054 // RecordWrite stub that notifies the incremental marker. |
| 3055 __ RememberedSetHelper(elements, |
| 3056 index_1, |
| 3057 temp, |
| 3058 kDontSaveFPRegs, |
| 3059 MacroAssembler::kFallThroughAtEnd); |
| 3060 __ RememberedSetHelper(elements, |
| 3061 index_2, |
| 3062 temp, |
| 3063 kDontSaveFPRegs, |
| 3064 MacroAssembler::kFallThroughAtEnd); |
3019 | 3065 |
3020 __ bind(&new_space); | 3066 __ bind(&no_remembered_set); |
| 3067 |
3021 // We are done. Drop elements from the stack, and return undefined. | 3068 // We are done. Drop elements from the stack, and return undefined. |
3022 __ addq(rsp, Immediate(3 * kPointerSize)); | 3069 __ addq(rsp, Immediate(3 * kPointerSize)); |
3023 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 3070 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
3024 __ jmp(&done); | 3071 __ jmp(&done); |
3025 | 3072 |
3026 __ bind(&slow_case); | 3073 __ bind(&slow_case); |
3027 __ CallRuntime(Runtime::kSwapElements, 3); | 3074 __ CallRuntime(Runtime::kSwapElements, 3); |
3028 | 3075 |
3029 __ bind(&done); | 3076 __ bind(&done); |
3030 context()->Plug(rax); | 3077 context()->Plug(rax); |
(...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3826 | 3873 |
3827 context()->Plug(rax); | 3874 context()->Plug(rax); |
3828 } else { | 3875 } else { |
3829 // This expression cannot throw a reference error at the top level. | 3876 // This expression cannot throw a reference error at the top level. |
3830 VisitInCurrentContext(expr); | 3877 VisitInCurrentContext(expr); |
3831 } | 3878 } |
3832 } | 3879 } |
3833 | 3880 |
3834 | 3881 |
3835 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, | 3882 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
3836 Handle<String> check, | 3883 Handle<String> check) { |
3837 Label* if_true, | 3884 Label materialize_true, materialize_false; |
3838 Label* if_false, | 3885 Label* if_true = NULL; |
3839 Label* fall_through) { | 3886 Label* if_false = NULL; |
| 3887 Label* fall_through = NULL; |
| 3888 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3889 &if_true, &if_false, &fall_through); |
| 3890 |
3840 { AccumulatorValueContext context(this); | 3891 { AccumulatorValueContext context(this); |
3841 VisitForTypeofValue(expr); | 3892 VisitForTypeofValue(expr); |
3842 } | 3893 } |
3843 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3894 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3844 | 3895 |
3845 if (check->Equals(isolate()->heap()->number_symbol())) { | 3896 if (check->Equals(isolate()->heap()->number_symbol())) { |
3846 __ JumpIfSmi(rax, if_true); | 3897 __ JumpIfSmi(rax, if_true); |
3847 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3898 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
3848 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); | 3899 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
3849 Split(equal, if_true, if_false, fall_through); | 3900 Split(equal, if_true, if_false, fall_through); |
(...skipping 18 matching lines...) Expand all Loading... |
3868 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 3919 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
3869 __ j(equal, if_true); | 3920 __ j(equal, if_true); |
3870 __ JumpIfSmi(rax, if_false); | 3921 __ JumpIfSmi(rax, if_false); |
3871 // Check for undetectable objects => true. | 3922 // Check for undetectable objects => true. |
3872 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 3923 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
3873 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 3924 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
3874 Immediate(1 << Map::kIsUndetectable)); | 3925 Immediate(1 << Map::kIsUndetectable)); |
3875 Split(not_zero, if_true, if_false, fall_through); | 3926 Split(not_zero, if_true, if_false, fall_through); |
3876 } else if (check->Equals(isolate()->heap()->function_symbol())) { | 3927 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
3877 __ JumpIfSmi(rax, if_false); | 3928 __ JumpIfSmi(rax, if_false); |
3878 STATIC_ASSERT(LAST_CALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE); | 3929 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
3879 __ CmpObjectType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, rdx); | 3930 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx); |
3880 Split(above_equal, if_true, if_false, fall_through); | 3931 __ j(equal, if_true); |
| 3932 __ CmpInstanceType(rdx, JS_FUNCTION_PROXY_TYPE); |
| 3933 Split(equal, if_true, if_false, fall_through); |
3881 } else if (check->Equals(isolate()->heap()->object_symbol())) { | 3934 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
3882 __ JumpIfSmi(rax, if_false); | 3935 __ JumpIfSmi(rax, if_false); |
3883 if (!FLAG_harmony_typeof) { | 3936 if (!FLAG_harmony_typeof) { |
3884 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 3937 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
3885 __ j(equal, if_true); | 3938 __ j(equal, if_true); |
3886 } | 3939 } |
3887 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx); | 3940 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx); |
3888 __ j(below, if_false); | 3941 __ j(below, if_false); |
3889 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 3942 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
3890 __ j(above, if_false); | 3943 __ j(above, if_false); |
3891 // Check for undetectable objects => false. | 3944 // Check for undetectable objects => false. |
3892 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 3945 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
3893 Immediate(1 << Map::kIsUndetectable)); | 3946 Immediate(1 << Map::kIsUndetectable)); |
3894 Split(zero, if_true, if_false, fall_through); | 3947 Split(zero, if_true, if_false, fall_through); |
3895 } else { | 3948 } else { |
3896 if (if_false != fall_through) __ jmp(if_false); | 3949 if (if_false != fall_through) __ jmp(if_false); |
3897 } | 3950 } |
3898 } | 3951 context()->Plug(if_true, if_false); |
3899 | |
3900 | |
3901 void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr, | |
3902 Label* if_true, | |
3903 Label* if_false, | |
3904 Label* fall_through) { | |
3905 VisitForAccumulatorValue(expr); | |
3906 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | |
3907 | |
3908 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | |
3909 Split(equal, if_true, if_false, fall_through); | |
3910 } | 3952 } |
3911 | 3953 |
3912 | 3954 |
3913 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 3955 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
3914 Comment cmnt(masm_, "[ CompareOperation"); | 3956 Comment cmnt(masm_, "[ CompareOperation"); |
3915 SetSourcePosition(expr->position()); | 3957 SetSourcePosition(expr->position()); |
3916 | 3958 |
| 3959 // First we try a fast inlined version of the compare when one of |
| 3960 // the operands is a literal. |
| 3961 if (TryLiteralCompare(expr)) return; |
| 3962 |
3917 // Always perform the comparison for its control flow. Pack the result | 3963 // Always perform the comparison for its control flow. Pack the result |
3918 // into the expression's context after the comparison is performed. | 3964 // into the expression's context after the comparison is performed. |
3919 Label materialize_true, materialize_false; | 3965 Label materialize_true, materialize_false; |
3920 Label* if_true = NULL; | 3966 Label* if_true = NULL; |
3921 Label* if_false = NULL; | 3967 Label* if_false = NULL; |
3922 Label* fall_through = NULL; | 3968 Label* fall_through = NULL; |
3923 context()->PrepareTest(&materialize_true, &materialize_false, | 3969 context()->PrepareTest(&materialize_true, &materialize_false, |
3924 &if_true, &if_false, &fall_through); | 3970 &if_true, &if_false, &fall_through); |
3925 | 3971 |
3926 // First we try a fast inlined version of the compare when one of | |
3927 // the operands is a literal. | |
3928 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) { | |
3929 context()->Plug(if_true, if_false); | |
3930 return; | |
3931 } | |
3932 | |
3933 Token::Value op = expr->op(); | 3972 Token::Value op = expr->op(); |
3934 VisitForStackValue(expr->left()); | 3973 VisitForStackValue(expr->left()); |
3935 switch (op) { | 3974 switch (op) { |
3936 case Token::IN: | 3975 case Token::IN: |
3937 VisitForStackValue(expr->right()); | 3976 VisitForStackValue(expr->right()); |
3938 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 3977 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
3939 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 3978 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
3940 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 3979 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
3941 Split(equal, if_true, if_false, fall_through); | 3980 Split(equal, if_true, if_false, fall_through); |
3942 break; | 3981 break; |
3943 | 3982 |
3944 case Token::INSTANCEOF: { | 3983 case Token::INSTANCEOF: { |
3945 VisitForStackValue(expr->right()); | 3984 VisitForStackValue(expr->right()); |
3946 InstanceofStub stub(InstanceofStub::kNoFlags); | 3985 InstanceofStub stub(InstanceofStub::kNoFlags); |
3947 __ CallStub(&stub); | 3986 __ CallStub(&stub); |
3948 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3987 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3949 __ testq(rax, rax); | 3988 __ testq(rax, rax); |
3950 // The stub returns 0 for true. | 3989 // The stub returns 0 for true. |
3951 Split(zero, if_true, if_false, fall_through); | 3990 Split(zero, if_true, if_false, fall_through); |
3952 break; | 3991 break; |
3953 } | 3992 } |
3954 | 3993 |
3955 default: { | 3994 default: { |
3956 VisitForAccumulatorValue(expr->right()); | 3995 VisitForAccumulatorValue(expr->right()); |
3957 Condition cc = no_condition; | 3996 Condition cc = no_condition; |
3958 switch (op) { | 3997 switch (op) { |
3959 case Token::EQ_STRICT: | 3998 case Token::EQ_STRICT: |
3960 // Fall through. | |
3961 case Token::EQ: | 3999 case Token::EQ: |
3962 cc = equal; | 4000 cc = equal; |
3963 __ pop(rdx); | 4001 __ pop(rdx); |
3964 break; | 4002 break; |
3965 case Token::LT: | 4003 case Token::LT: |
3966 cc = less; | 4004 cc = less; |
3967 __ pop(rdx); | 4005 __ pop(rdx); |
3968 break; | 4006 break; |
3969 case Token::GT: | 4007 case Token::GT: |
3970 // Reverse left and right sizes to obtain ECMA-262 conversion order. | 4008 // Reverse left and right sizes to obtain ECMA-262 conversion order. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4011 Split(cc, if_true, if_false, fall_through); | 4049 Split(cc, if_true, if_false, fall_through); |
4012 } | 4050 } |
4013 } | 4051 } |
4014 | 4052 |
4015 // Convert the result of the comparison into one expected for this | 4053 // Convert the result of the comparison into one expected for this |
4016 // expression's context. | 4054 // expression's context. |
4017 context()->Plug(if_true, if_false); | 4055 context()->Plug(if_true, if_false); |
4018 } | 4056 } |
4019 | 4057 |
4020 | 4058 |
4021 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 4059 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, |
4022 Comment cmnt(masm_, "[ CompareToNull"); | 4060 Expression* sub_expr, |
| 4061 NilValue nil) { |
4023 Label materialize_true, materialize_false; | 4062 Label materialize_true, materialize_false; |
4024 Label* if_true = NULL; | 4063 Label* if_true = NULL; |
4025 Label* if_false = NULL; | 4064 Label* if_false = NULL; |
4026 Label* fall_through = NULL; | 4065 Label* fall_through = NULL; |
4027 context()->PrepareTest(&materialize_true, &materialize_false, | 4066 context()->PrepareTest(&materialize_true, &materialize_false, |
4028 &if_true, &if_false, &fall_through); | 4067 &if_true, &if_false, &fall_through); |
4029 | 4068 |
4030 VisitForAccumulatorValue(expr->expression()); | 4069 VisitForAccumulatorValue(sub_expr); |
4031 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4070 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
4032 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 4071 Heap::RootListIndex nil_value = nil == kNullValue ? |
4033 if (expr->is_strict()) { | 4072 Heap::kNullValueRootIndex : |
| 4073 Heap::kUndefinedValueRootIndex; |
| 4074 __ CompareRoot(rax, nil_value); |
| 4075 if (expr->op() == Token::EQ_STRICT) { |
4034 Split(equal, if_true, if_false, fall_through); | 4076 Split(equal, if_true, if_false, fall_through); |
4035 } else { | 4077 } else { |
| 4078 Heap::RootListIndex other_nil_value = nil == kNullValue ? |
| 4079 Heap::kUndefinedValueRootIndex : |
| 4080 Heap::kNullValueRootIndex; |
4036 __ j(equal, if_true); | 4081 __ j(equal, if_true); |
4037 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 4082 __ CompareRoot(rax, other_nil_value); |
4038 __ j(equal, if_true); | 4083 __ j(equal, if_true); |
4039 __ JumpIfSmi(rax, if_false); | 4084 __ JumpIfSmi(rax, if_false); |
4040 // It can be an undetectable object. | 4085 // It can be an undetectable object. |
4041 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 4086 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
4042 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 4087 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
4043 Immediate(1 << Map::kIsUndetectable)); | 4088 Immediate(1 << Map::kIsUndetectable)); |
4044 Split(not_zero, if_true, if_false, fall_through); | 4089 Split(not_zero, if_true, if_false, fall_through); |
4045 } | 4090 } |
4046 context()->Plug(if_true, if_false); | 4091 context()->Plug(if_true, if_false); |
4047 } | 4092 } |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4151 *context_length = 0; | 4196 *context_length = 0; |
4152 return previous_; | 4197 return previous_; |
4153 } | 4198 } |
4154 | 4199 |
4155 | 4200 |
4156 #undef __ | 4201 #undef __ |
4157 | 4202 |
4158 } } // namespace v8::internal | 4203 } } // namespace v8::internal |
4159 | 4204 |
4160 #endif // V8_TARGET_ARCH_X64 | 4205 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |