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 21 matching lines...) Expand all Loading... |
32 #include "code-stubs.h" | 32 #include "code-stubs.h" |
33 #include "codegen.h" | 33 #include "codegen.h" |
34 #include "compiler.h" | 34 #include "compiler.h" |
35 #include "debug.h" | 35 #include "debug.h" |
36 #include "full-codegen.h" | 36 #include "full-codegen.h" |
37 #include "parser.h" | 37 #include "parser.h" |
38 #include "scopes.h" | 38 #include "scopes.h" |
39 #include "stub-cache.h" | 39 #include "stub-cache.h" |
40 | 40 |
41 #include "arm/code-stubs-arm.h" | 41 #include "arm/code-stubs-arm.h" |
| 42 #include "arm/macro-assembler-arm.h" |
42 | 43 |
43 namespace v8 { | 44 namespace v8 { |
44 namespace internal { | 45 namespace internal { |
45 | 46 |
46 #define __ ACCESS_MASM(masm_) | 47 #define __ ACCESS_MASM(masm_) |
47 | 48 |
48 | 49 |
49 static unsigned GetPropertyId(Property* property) { | 50 static unsigned GetPropertyId(Property* property) { |
50 return property->id(); | 51 return property->id(); |
51 } | 52 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 if (info->is_strict_mode() || info->is_native()) { | 149 if (info->is_strict_mode() || info->is_native()) { |
149 Label ok; | 150 Label ok; |
150 __ cmp(r5, Operand(0)); | 151 __ cmp(r5, Operand(0)); |
151 __ b(eq, &ok); | 152 __ b(eq, &ok); |
152 int receiver_offset = info->scope()->num_parameters() * kPointerSize; | 153 int receiver_offset = info->scope()->num_parameters() * kPointerSize; |
153 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); | 154 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
154 __ str(r2, MemOperand(sp, receiver_offset)); | 155 __ str(r2, MemOperand(sp, receiver_offset)); |
155 __ bind(&ok); | 156 __ bind(&ok); |
156 } | 157 } |
157 | 158 |
| 159 // Open a frame scope to indicate that there is a frame on the stack. The |
| 160 // MANUAL indicates that the scope shouldn't actually generate code to set up |
| 161 // the frame (that is done below). |
| 162 FrameScope frame_scope(masm_, StackFrame::MANUAL); |
| 163 |
158 int locals_count = info->scope()->num_stack_slots(); | 164 int locals_count = info->scope()->num_stack_slots(); |
159 | 165 |
160 __ Push(lr, fp, cp, r1); | 166 __ Push(lr, fp, cp, r1); |
161 if (locals_count > 0) { | 167 if (locals_count > 0) { |
162 // Load undefined value here, so the value is ready for the loop | 168 // Load undefined value here, so the value is ready for the loop |
163 // below. | 169 // below. |
164 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 170 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
165 } | 171 } |
166 // Adjust fp to point to caller's fp. | 172 // Adjust fp to point to caller's fp. |
167 __ add(fp, sp, Operand(2 * kPointerSize)); | 173 __ add(fp, sp, Operand(2 * kPointerSize)); |
(...skipping 25 matching lines...) Expand all Loading... |
193 // Copy any necessary parameters into the context. | 199 // Copy any necessary parameters into the context. |
194 int num_parameters = info->scope()->num_parameters(); | 200 int num_parameters = info->scope()->num_parameters(); |
195 for (int i = 0; i < num_parameters; i++) { | 201 for (int i = 0; i < num_parameters; i++) { |
196 Variable* var = scope()->parameter(i); | 202 Variable* var = scope()->parameter(i); |
197 if (var->IsContextSlot()) { | 203 if (var->IsContextSlot()) { |
198 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 204 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
199 (num_parameters - 1 - i) * kPointerSize; | 205 (num_parameters - 1 - i) * kPointerSize; |
200 // Load parameter from stack. | 206 // Load parameter from stack. |
201 __ ldr(r0, MemOperand(fp, parameter_offset)); | 207 __ ldr(r0, MemOperand(fp, parameter_offset)); |
202 // Store it in the context. | 208 // Store it in the context. |
203 __ mov(r1, Operand(Context::SlotOffset(var->index()))); | 209 MemOperand target = ContextOperand(cp, var->index()); |
204 __ str(r0, MemOperand(cp, r1)); | 210 __ str(r0, target); |
205 // Update the write barrier. This clobbers all involved | 211 |
206 // registers, so we have to use two more registers to avoid | 212 // Update the write barrier. |
207 // clobbering cp. | 213 __ RecordWriteContextSlot( |
208 __ mov(r2, Operand(cp)); | 214 cp, target.offset(), r0, r3, kLRHasBeenSaved, kDontSaveFPRegs); |
209 __ RecordWrite(r2, Operand(r1), r3, r0); | |
210 } | 215 } |
211 } | 216 } |
212 } | 217 } |
213 | 218 |
214 Variable* arguments = scope()->arguments(); | 219 Variable* arguments = scope()->arguments(); |
215 if (arguments != NULL) { | 220 if (arguments != NULL) { |
216 // Function uses arguments object. | 221 // Function uses arguments object. |
217 Comment cmnt(masm_, "[ Allocate arguments object"); | 222 Comment cmnt(masm_, "[ Allocate arguments object"); |
218 if (!function_in_register) { | 223 if (!function_in_register) { |
219 // Load this again, if it's used by the local context below. | 224 // Load this again, if it's used by the local context below. |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
658 void FullCodeGenerator::SetVar(Variable* var, | 663 void FullCodeGenerator::SetVar(Variable* var, |
659 Register src, | 664 Register src, |
660 Register scratch0, | 665 Register scratch0, |
661 Register scratch1) { | 666 Register scratch1) { |
662 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); | 667 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
663 ASSERT(!scratch0.is(src)); | 668 ASSERT(!scratch0.is(src)); |
664 ASSERT(!scratch0.is(scratch1)); | 669 ASSERT(!scratch0.is(scratch1)); |
665 ASSERT(!scratch1.is(src)); | 670 ASSERT(!scratch1.is(src)); |
666 MemOperand location = VarOperand(var, scratch0); | 671 MemOperand location = VarOperand(var, scratch0); |
667 __ str(src, location); | 672 __ str(src, location); |
| 673 |
668 // Emit the write barrier code if the location is in the heap. | 674 // Emit the write barrier code if the location is in the heap. |
669 if (var->IsContextSlot()) { | 675 if (var->IsContextSlot()) { |
670 __ RecordWrite(scratch0, | 676 __ RecordWriteContextSlot(scratch0, |
671 Operand(Context::SlotOffset(var->index())), | 677 location.offset(), |
672 scratch1, | 678 src, |
673 src); | 679 scratch1, |
| 680 kLRHasBeenSaved, |
| 681 kDontSaveFPRegs); |
674 } | 682 } |
675 } | 683 } |
676 | 684 |
677 | 685 |
678 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 686 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
679 bool should_normalize, | 687 bool should_normalize, |
680 Label* if_true, | 688 Label* if_true, |
681 Label* if_false) { | 689 Label* if_false) { |
682 // Only prepare for bailouts before splits if we're in a test | 690 // Only prepare for bailouts before splits if we're in a test |
683 // context. Otherwise, we let the Visit function deal with the | 691 // context. Otherwise, we let the Visit function deal with the |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
739 __ Check(ne, "Declaration in with context."); | 747 __ Check(ne, "Declaration in with context."); |
740 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); | 748 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); |
741 __ Check(ne, "Declaration in catch context."); | 749 __ Check(ne, "Declaration in catch context."); |
742 } | 750 } |
743 if (function != NULL) { | 751 if (function != NULL) { |
744 Comment cmnt(masm_, "[ Declaration"); | 752 Comment cmnt(masm_, "[ Declaration"); |
745 VisitForAccumulatorValue(function); | 753 VisitForAccumulatorValue(function); |
746 __ str(result_register(), ContextOperand(cp, variable->index())); | 754 __ str(result_register(), ContextOperand(cp, variable->index())); |
747 int offset = Context::SlotOffset(variable->index()); | 755 int offset = Context::SlotOffset(variable->index()); |
748 // We know that we have written a function, which is not a smi. | 756 // We know that we have written a function, which is not a smi. |
749 __ mov(r1, Operand(cp)); | 757 __ RecordWriteContextSlot(cp, |
750 __ RecordWrite(r1, Operand(offset), r2, result_register()); | 758 offset, |
| 759 result_register(), |
| 760 r2, |
| 761 kLRHasBeenSaved, |
| 762 kDontSaveFPRegs, |
| 763 EMIT_REMEMBERED_SET, |
| 764 OMIT_SMI_CHECK); |
751 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 765 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
752 } else if (mode == Variable::CONST || mode == Variable::LET) { | 766 } else if (mode == Variable::CONST || mode == Variable::LET) { |
753 Comment cmnt(masm_, "[ Declaration"); | 767 Comment cmnt(masm_, "[ Declaration"); |
754 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 768 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
755 __ str(ip, ContextOperand(cp, variable->index())); | 769 __ str(ip, ContextOperand(cp, variable->index())); |
756 // No write barrier since the_hole_value is in old space. | 770 // No write barrier since the_hole_value is in old space. |
757 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 771 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
758 } | 772 } |
759 break; | 773 break; |
760 | 774 |
(...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1483 continue; | 1497 continue; |
1484 } | 1498 } |
1485 | 1499 |
1486 if (!result_saved) { | 1500 if (!result_saved) { |
1487 __ push(r0); | 1501 __ push(r0); |
1488 result_saved = true; | 1502 result_saved = true; |
1489 } | 1503 } |
1490 VisitForAccumulatorValue(subexpr); | 1504 VisitForAccumulatorValue(subexpr); |
1491 | 1505 |
1492 // Store the subexpression value in the array's elements. | 1506 // Store the subexpression value in the array's elements. |
1493 __ ldr(r1, MemOperand(sp)); // Copy of array literal. | 1507 __ ldr(r6, MemOperand(sp)); // Copy of array literal. |
1494 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); | 1508 __ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset)); |
1495 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1509 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1496 __ str(result_register(), FieldMemOperand(r1, offset)); | 1510 __ str(result_register(), FieldMemOperand(r1, offset)); |
1497 | 1511 |
| 1512 Label no_map_change; |
| 1513 __ JumpIfSmi(result_register(), &no_map_change); |
1498 // Update the write barrier for the array store with r0 as the scratch | 1514 // Update the write barrier for the array store with r0 as the scratch |
1499 // register. | 1515 // register. |
1500 __ RecordWrite(r1, Operand(offset), r2, result_register()); | 1516 __ RecordWriteField( |
| 1517 r1, offset, result_register(), r2, kLRHasBeenSaved, kDontSaveFPRegs, |
| 1518 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 1519 if (FLAG_smi_only_arrays) { |
| 1520 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 1521 __ CheckFastSmiOnlyElements(r3, r2, &no_map_change); |
| 1522 __ push(r6); // Copy of array literal. |
| 1523 __ CallRuntime(Runtime::kNonSmiElementStored, 1); |
| 1524 } |
| 1525 __ bind(&no_map_change); |
1501 | 1526 |
1502 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1527 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1503 } | 1528 } |
1504 | 1529 |
1505 if (result_saved) { | 1530 if (result_saved) { |
1506 context()->PlugTOS(); | 1531 context()->PlugTOS(); |
1507 } else { | 1532 } else { |
1508 context()->Plug(r0); | 1533 context()->Plug(r0); |
1509 } | 1534 } |
1510 } | 1535 } |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1862 __ mov(r3, Operand(var->name())); | 1887 __ mov(r3, Operand(var->name())); |
1863 __ push(r3); | 1888 __ push(r3); |
1864 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1889 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1865 // Perform the assignment. | 1890 // Perform the assignment. |
1866 __ bind(&assign); | 1891 __ bind(&assign); |
1867 __ str(result_register(), location); | 1892 __ str(result_register(), location); |
1868 if (var->IsContextSlot()) { | 1893 if (var->IsContextSlot()) { |
1869 // RecordWrite may destroy all its register arguments. | 1894 // RecordWrite may destroy all its register arguments. |
1870 __ mov(r3, result_register()); | 1895 __ mov(r3, result_register()); |
1871 int offset = Context::SlotOffset(var->index()); | 1896 int offset = Context::SlotOffset(var->index()); |
1872 __ RecordWrite(r1, Operand(offset), r2, r3); | 1897 __ RecordWriteContextSlot( |
| 1898 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); |
1873 } | 1899 } |
1874 } | 1900 } |
1875 | 1901 |
1876 } else if (var->mode() != Variable::CONST) { | 1902 } else if (var->mode() != Variable::CONST) { |
1877 // Assignment to var or initializing assignment to let. | 1903 // Assignment to var or initializing assignment to let. |
1878 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1904 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1879 MemOperand location = VarOperand(var, r1); | 1905 MemOperand location = VarOperand(var, r1); |
1880 if (FLAG_debug_code && op == Token::INIT_LET) { | 1906 if (FLAG_debug_code && op == Token::INIT_LET) { |
1881 // Check for an uninitialized let binding. | 1907 // Check for an uninitialized let binding. |
1882 __ ldr(r2, location); | 1908 __ ldr(r2, location); |
1883 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); | 1909 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
1884 __ Check(eq, "Let binding re-initialization."); | 1910 __ Check(eq, "Let binding re-initialization."); |
1885 } | 1911 } |
1886 // Perform the assignment. | 1912 // Perform the assignment. |
1887 __ str(r0, location); | 1913 __ str(r0, location); |
1888 if (var->IsContextSlot()) { | 1914 if (var->IsContextSlot()) { |
1889 __ mov(r3, r0); | 1915 __ mov(r3, r0); |
1890 __ RecordWrite(r1, Operand(Context::SlotOffset(var->index())), r2, r3); | 1916 int offset = Context::SlotOffset(var->index()); |
| 1917 __ RecordWriteContextSlot( |
| 1918 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); |
1891 } | 1919 } |
1892 } else { | 1920 } else { |
1893 ASSERT(var->IsLookupSlot()); | 1921 ASSERT(var->IsLookupSlot()); |
1894 __ push(r0); // Value. | 1922 __ push(r0); // Value. |
1895 __ mov(r1, Operand(var->name())); | 1923 __ mov(r1, Operand(var->name())); |
1896 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); | 1924 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); |
1897 __ Push(cp, r1, r0); // Context, name, strict mode. | 1925 __ Push(cp, r1, r0); // Context, name, strict mode. |
1898 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1926 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1899 } | 1927 } |
1900 } | 1928 } |
(...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2655 ASSERT(args->length() == 1); | 2683 ASSERT(args->length() == 1); |
2656 Label done, null, function, non_function_constructor; | 2684 Label done, null, function, non_function_constructor; |
2657 | 2685 |
2658 VisitForAccumulatorValue(args->at(0)); | 2686 VisitForAccumulatorValue(args->at(0)); |
2659 | 2687 |
2660 // If the object is a smi, we return null. | 2688 // If the object is a smi, we return null. |
2661 __ JumpIfSmi(r0, &null); | 2689 __ JumpIfSmi(r0, &null); |
2662 | 2690 |
2663 // Check that the object is a JS object but take special care of JS | 2691 // Check that the object is a JS object but take special care of JS |
2664 // functions to make sure they have 'Function' as their class. | 2692 // functions to make sure they have 'Function' as their class. |
| 2693 // Assume that there are only two callable types, and one of them is at |
| 2694 // either end of the type range for JS object types. Saves extra comparisons. |
| 2695 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
2665 __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE); | 2696 __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE); |
2666 // Map is now in r0. | 2697 // Map is now in r0. |
2667 __ b(lt, &null); | 2698 __ b(lt, &null); |
| 2699 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
| 2700 FIRST_SPEC_OBJECT_TYPE + 1); |
| 2701 __ b(eq, &function); |
2668 | 2702 |
2669 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and | 2703 __ cmp(r1, Operand(LAST_SPEC_OBJECT_TYPE)); |
2670 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after | 2704 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
2671 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. | 2705 LAST_SPEC_OBJECT_TYPE - 1); |
2672 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); | 2706 __ b(eq, &function); |
2673 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == | 2707 // Assume that there is no larger type. |
2674 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); | 2708 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); |
2675 __ cmp(r1, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE)); | |
2676 __ b(ge, &function); | |
2677 | 2709 |
2678 // Check if the constructor in the map is a function. | 2710 // Check if the constructor in the map is a JS function. |
2679 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset)); | 2711 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset)); |
2680 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); | 2712 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE); |
2681 __ b(ne, &non_function_constructor); | 2713 __ b(ne, &non_function_constructor); |
2682 | 2714 |
2683 // r0 now contains the constructor function. Grab the | 2715 // r0 now contains the constructor function. Grab the |
2684 // instance class name from there. | 2716 // instance class name from there. |
2685 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); | 2717 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset)); |
2686 __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset)); | 2718 __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset)); |
2687 __ b(&done); | 2719 __ b(&done); |
2688 | 2720 |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2846 __ JumpIfSmi(r1, &done); | 2878 __ JumpIfSmi(r1, &done); |
2847 | 2879 |
2848 // If the object is not a value type, return the value. | 2880 // If the object is not a value type, return the value. |
2849 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE); | 2881 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE); |
2850 __ b(ne, &done); | 2882 __ b(ne, &done); |
2851 | 2883 |
2852 // Store the value. | 2884 // Store the value. |
2853 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); | 2885 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); |
2854 // Update the write barrier. Save the value as it will be | 2886 // Update the write barrier. Save the value as it will be |
2855 // overwritten by the write barrier code and is needed afterward. | 2887 // overwritten by the write barrier code and is needed afterward. |
2856 __ RecordWrite(r1, Operand(JSValue::kValueOffset - kHeapObjectTag), r2, r3); | 2888 __ mov(r2, r0); |
| 2889 __ RecordWriteField( |
| 2890 r1, JSValue::kValueOffset, r2, r3, kLRHasBeenSaved, kDontSaveFPRegs); |
2857 | 2891 |
2858 __ bind(&done); | 2892 __ bind(&done); |
2859 context()->Plug(r0); | 2893 context()->Plug(r0); |
2860 } | 2894 } |
2861 | 2895 |
2862 | 2896 |
2863 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { | 2897 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { |
2864 ASSERT_EQ(args->length(), 1); | 2898 ASSERT_EQ(args->length(), 1); |
2865 | 2899 |
2866 // Load the argument on the stack and call the stub. | 2900 // Load the argument on the stack and call the stub. |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3134 __ add(index2, | 3168 __ add(index2, |
3135 scratch1, | 3169 scratch1, |
3136 Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize)); | 3170 Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize)); |
3137 | 3171 |
3138 // Swap elements. | 3172 // Swap elements. |
3139 __ ldr(scratch1, MemOperand(index1, 0)); | 3173 __ ldr(scratch1, MemOperand(index1, 0)); |
3140 __ ldr(scratch2, MemOperand(index2, 0)); | 3174 __ ldr(scratch2, MemOperand(index2, 0)); |
3141 __ str(scratch1, MemOperand(index2, 0)); | 3175 __ str(scratch1, MemOperand(index2, 0)); |
3142 __ str(scratch2, MemOperand(index1, 0)); | 3176 __ str(scratch2, MemOperand(index1, 0)); |
3143 | 3177 |
3144 Label new_space; | 3178 Label no_remembered_set; |
3145 __ InNewSpace(elements, scratch1, eq, &new_space); | 3179 __ CheckPageFlag(elements, |
| 3180 scratch1, |
| 3181 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 3182 ne, |
| 3183 &no_remembered_set); |
3146 // Possible optimization: do a check that both values are Smis | 3184 // Possible optimization: do a check that both values are Smis |
3147 // (or them and test against Smi mask.) | 3185 // (or them and test against Smi mask.) |
3148 | 3186 |
3149 __ mov(scratch1, elements); | 3187 // We are swapping two objects in an array and the incremental marker never |
3150 __ RecordWriteHelper(elements, index1, scratch2); | 3188 // pauses in the middle of scanning a single object. Therefore the |
3151 __ RecordWriteHelper(scratch1, index2, scratch2); // scratch1 holds elements. | 3189 // incremental marker is not disturbed, so we don't need to call the |
| 3190 // RecordWrite stub that notifies the incremental marker. |
| 3191 __ RememberedSetHelper(elements, |
| 3192 index1, |
| 3193 scratch2, |
| 3194 kDontSaveFPRegs, |
| 3195 MacroAssembler::kFallThroughAtEnd); |
| 3196 __ RememberedSetHelper(elements, |
| 3197 index2, |
| 3198 scratch2, |
| 3199 kDontSaveFPRegs, |
| 3200 MacroAssembler::kFallThroughAtEnd); |
3152 | 3201 |
3153 __ bind(&new_space); | 3202 __ bind(&no_remembered_set); |
3154 // We are done. Drop elements from the stack, and return undefined. | 3203 // We are done. Drop elements from the stack, and return undefined. |
3155 __ Drop(3); | 3204 __ Drop(3); |
3156 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 3205 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
3157 __ jmp(&done); | 3206 __ jmp(&done); |
3158 | 3207 |
3159 __ bind(&slow_case); | 3208 __ bind(&slow_case); |
3160 __ CallRuntime(Runtime::kSwapElements, 3); | 3209 __ CallRuntime(Runtime::kSwapElements, 3); |
3161 | 3210 |
3162 __ bind(&done); | 3211 __ bind(&done); |
3163 context()->Plug(r0); | 3212 context()->Plug(r0); |
(...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3891 | 3940 |
3892 context()->Plug(r0); | 3941 context()->Plug(r0); |
3893 } else { | 3942 } else { |
3894 // This expression cannot throw a reference error at the top level. | 3943 // This expression cannot throw a reference error at the top level. |
3895 VisitInCurrentContext(expr); | 3944 VisitInCurrentContext(expr); |
3896 } | 3945 } |
3897 } | 3946 } |
3898 | 3947 |
3899 | 3948 |
3900 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, | 3949 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
3901 Handle<String> check, | 3950 Handle<String> check) { |
3902 Label* if_true, | 3951 Label materialize_true, materialize_false; |
3903 Label* if_false, | 3952 Label* if_true = NULL; |
3904 Label* fall_through) { | 3953 Label* if_false = NULL; |
| 3954 Label* fall_through = NULL; |
| 3955 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3956 &if_true, &if_false, &fall_through); |
| 3957 |
3905 { AccumulatorValueContext context(this); | 3958 { AccumulatorValueContext context(this); |
3906 VisitForTypeofValue(expr); | 3959 VisitForTypeofValue(expr); |
3907 } | 3960 } |
3908 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3961 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
3909 | 3962 |
3910 if (check->Equals(isolate()->heap()->number_symbol())) { | 3963 if (check->Equals(isolate()->heap()->number_symbol())) { |
3911 __ JumpIfSmi(r0, if_true); | 3964 __ JumpIfSmi(r0, if_true); |
3912 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); | 3965 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); |
3913 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 3966 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
3914 __ cmp(r0, ip); | 3967 __ cmp(r0, ip); |
(...skipping 20 matching lines...) Expand all Loading... |
3935 __ b(eq, if_true); | 3988 __ b(eq, if_true); |
3936 __ JumpIfSmi(r0, if_false); | 3989 __ JumpIfSmi(r0, if_false); |
3937 // Check for undetectable objects => true. | 3990 // Check for undetectable objects => true. |
3938 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); | 3991 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); |
3939 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); | 3992 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); |
3940 __ tst(r1, Operand(1 << Map::kIsUndetectable)); | 3993 __ tst(r1, Operand(1 << Map::kIsUndetectable)); |
3941 Split(ne, if_true, if_false, fall_through); | 3994 Split(ne, if_true, if_false, fall_through); |
3942 | 3995 |
3943 } else if (check->Equals(isolate()->heap()->function_symbol())) { | 3996 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
3944 __ JumpIfSmi(r0, if_false); | 3997 __ JumpIfSmi(r0, if_false); |
3945 __ CompareObjectType(r0, r1, r0, FIRST_CALLABLE_SPEC_OBJECT_TYPE); | 3998 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
3946 Split(ge, if_true, if_false, fall_through); | 3999 __ CompareObjectType(r0, r0, r1, JS_FUNCTION_TYPE); |
3947 | 4000 __ b(eq, if_true); |
| 4001 __ cmp(r1, Operand(JS_FUNCTION_PROXY_TYPE)); |
| 4002 Split(eq, if_true, if_false, fall_through); |
3948 } else if (check->Equals(isolate()->heap()->object_symbol())) { | 4003 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
3949 __ JumpIfSmi(r0, if_false); | 4004 __ JumpIfSmi(r0, if_false); |
3950 if (!FLAG_harmony_typeof) { | 4005 if (!FLAG_harmony_typeof) { |
3951 __ CompareRoot(r0, Heap::kNullValueRootIndex); | 4006 __ CompareRoot(r0, Heap::kNullValueRootIndex); |
3952 __ b(eq, if_true); | 4007 __ b(eq, if_true); |
3953 } | 4008 } |
3954 // Check for JS objects => true. | 4009 // Check for JS objects => true. |
3955 __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4010 __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); |
3956 __ b(lt, if_false); | 4011 __ b(lt, if_false); |
3957 __ CompareInstanceType(r0, r1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); | 4012 __ CompareInstanceType(r0, r1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
3958 __ b(gt, if_false); | 4013 __ b(gt, if_false); |
3959 // Check for undetectable objects => false. | 4014 // Check for undetectable objects => false. |
3960 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); | 4015 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); |
3961 __ tst(r1, Operand(1 << Map::kIsUndetectable)); | 4016 __ tst(r1, Operand(1 << Map::kIsUndetectable)); |
3962 Split(eq, if_true, if_false, fall_through); | 4017 Split(eq, if_true, if_false, fall_through); |
3963 } else { | 4018 } else { |
3964 if (if_false != fall_through) __ jmp(if_false); | 4019 if (if_false != fall_through) __ jmp(if_false); |
3965 } | 4020 } |
3966 } | 4021 context()->Plug(if_true, if_false); |
3967 | |
3968 | |
3969 void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr, | |
3970 Label* if_true, | |
3971 Label* if_false, | |
3972 Label* fall_through) { | |
3973 VisitForAccumulatorValue(expr); | |
3974 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | |
3975 | |
3976 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); | |
3977 Split(eq, if_true, if_false, fall_through); | |
3978 } | 4022 } |
3979 | 4023 |
3980 | 4024 |
3981 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 4025 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
3982 Comment cmnt(masm_, "[ CompareOperation"); | 4026 Comment cmnt(masm_, "[ CompareOperation"); |
3983 SetSourcePosition(expr->position()); | 4027 SetSourcePosition(expr->position()); |
3984 | 4028 |
| 4029 // First we try a fast inlined version of the compare when one of |
| 4030 // the operands is a literal. |
| 4031 if (TryLiteralCompare(expr)) return; |
| 4032 |
3985 // Always perform the comparison for its control flow. Pack the result | 4033 // Always perform the comparison for its control flow. Pack the result |
3986 // into the expression's context after the comparison is performed. | 4034 // into the expression's context after the comparison is performed. |
3987 | |
3988 Label materialize_true, materialize_false; | 4035 Label materialize_true, materialize_false; |
3989 Label* if_true = NULL; | 4036 Label* if_true = NULL; |
3990 Label* if_false = NULL; | 4037 Label* if_false = NULL; |
3991 Label* fall_through = NULL; | 4038 Label* fall_through = NULL; |
3992 context()->PrepareTest(&materialize_true, &materialize_false, | 4039 context()->PrepareTest(&materialize_true, &materialize_false, |
3993 &if_true, &if_false, &fall_through); | 4040 &if_true, &if_false, &fall_through); |
3994 | 4041 |
3995 // First we try a fast inlined version of the compare when one of | |
3996 // the operands is a literal. | |
3997 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) { | |
3998 context()->Plug(if_true, if_false); | |
3999 return; | |
4000 } | |
4001 | |
4002 Token::Value op = expr->op(); | 4042 Token::Value op = expr->op(); |
4003 VisitForStackValue(expr->left()); | 4043 VisitForStackValue(expr->left()); |
4004 switch (op) { | 4044 switch (op) { |
4005 case Token::IN: | 4045 case Token::IN: |
4006 VisitForStackValue(expr->right()); | 4046 VisitForStackValue(expr->right()); |
4007 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 4047 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
4008 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 4048 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
4009 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 4049 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
4010 __ cmp(r0, ip); | 4050 __ cmp(r0, ip); |
4011 Split(eq, if_true, if_false, fall_through); | 4051 Split(eq, if_true, if_false, fall_through); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4078 Split(cond, if_true, if_false, fall_through); | 4118 Split(cond, if_true, if_false, fall_through); |
4079 } | 4119 } |
4080 } | 4120 } |
4081 | 4121 |
4082 // Convert the result of the comparison into one expected for this | 4122 // Convert the result of the comparison into one expected for this |
4083 // expression's context. | 4123 // expression's context. |
4084 context()->Plug(if_true, if_false); | 4124 context()->Plug(if_true, if_false); |
4085 } | 4125 } |
4086 | 4126 |
4087 | 4127 |
4088 void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) { | 4128 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr, |
4089 Comment cmnt(masm_, "[ CompareToNull"); | 4129 Expression* sub_expr, |
| 4130 NilValue nil) { |
4090 Label materialize_true, materialize_false; | 4131 Label materialize_true, materialize_false; |
4091 Label* if_true = NULL; | 4132 Label* if_true = NULL; |
4092 Label* if_false = NULL; | 4133 Label* if_false = NULL; |
4093 Label* fall_through = NULL; | 4134 Label* fall_through = NULL; |
4094 context()->PrepareTest(&materialize_true, &materialize_false, | 4135 context()->PrepareTest(&materialize_true, &materialize_false, |
4095 &if_true, &if_false, &fall_through); | 4136 &if_true, &if_false, &fall_through); |
4096 | 4137 |
4097 VisitForAccumulatorValue(expr->expression()); | 4138 VisitForAccumulatorValue(sub_expr); |
4098 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4139 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
4099 __ LoadRoot(r1, Heap::kNullValueRootIndex); | 4140 Heap::RootListIndex nil_value = nil == kNullValue ? |
| 4141 Heap::kNullValueRootIndex : |
| 4142 Heap::kUndefinedValueRootIndex; |
| 4143 __ LoadRoot(r1, nil_value); |
4100 __ cmp(r0, r1); | 4144 __ cmp(r0, r1); |
4101 if (expr->is_strict()) { | 4145 if (expr->op() == Token::EQ_STRICT) { |
4102 Split(eq, if_true, if_false, fall_through); | 4146 Split(eq, if_true, if_false, fall_through); |
4103 } else { | 4147 } else { |
| 4148 Heap::RootListIndex other_nil_value = nil == kNullValue ? |
| 4149 Heap::kUndefinedValueRootIndex : |
| 4150 Heap::kNullValueRootIndex; |
4104 __ b(eq, if_true); | 4151 __ b(eq, if_true); |
4105 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); | 4152 __ LoadRoot(r1, other_nil_value); |
4106 __ cmp(r0, r1); | 4153 __ cmp(r0, r1); |
4107 __ b(eq, if_true); | 4154 __ b(eq, if_true); |
4108 __ JumpIfSmi(r0, if_false); | 4155 __ JumpIfSmi(r0, if_false); |
4109 // It can be an undetectable object. | 4156 // It can be an undetectable object. |
4110 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 4157 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
4111 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); | 4158 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); |
4112 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); | 4159 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); |
4113 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); | 4160 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); |
4114 Split(eq, if_true, if_false, fall_through); | 4161 Split(eq, if_true, if_false, fall_through); |
4115 } | 4162 } |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4219 *context_length = 0; | 4266 *context_length = 0; |
4220 return previous_; | 4267 return previous_; |
4221 } | 4268 } |
4222 | 4269 |
4223 | 4270 |
4224 #undef __ | 4271 #undef __ |
4225 | 4272 |
4226 } } // namespace v8::internal | 4273 } } // namespace v8::internal |
4227 | 4274 |
4228 #endif // V8_TARGET_ARCH_ARM | 4275 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |