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 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 // Copy any necessary parameters into the context. | 199 // Copy any necessary parameters into the context. |
199 int num_parameters = info->scope()->num_parameters(); | 200 int num_parameters = info->scope()->num_parameters(); |
200 for (int i = 0; i < num_parameters; i++) { | 201 for (int i = 0; i < num_parameters; i++) { |
201 Variable* var = scope()->parameter(i); | 202 Variable* var = scope()->parameter(i); |
202 if (var->IsContextSlot()) { | 203 if (var->IsContextSlot()) { |
203 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 204 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
204 (num_parameters - 1 - i) * kPointerSize; | 205 (num_parameters - 1 - i) * kPointerSize; |
205 // Load parameter from stack. | 206 // Load parameter from stack. |
206 __ ldr(r0, MemOperand(fp, parameter_offset)); | 207 __ ldr(r0, MemOperand(fp, parameter_offset)); |
207 // Store it in the context. | 208 // Store it in the context. |
208 __ mov(r1, Operand(Context::SlotOffset(var->index()))); | 209 MemOperand target = ContextOperand(cp, var->index()); |
209 __ str(r0, MemOperand(cp, r1)); | 210 __ str(r0, target); |
210 // Update the write barrier. This clobbers all involved | 211 |
211 // registers, so we have to use two more registers to avoid | 212 // Update the write barrier. |
212 // clobbering cp. | 213 __ RecordWriteContextSlot( |
213 __ mov(r2, Operand(cp)); | 214 cp, target.offset(), r0, r3, kLRHasBeenSaved, kDontSaveFPRegs); |
214 __ RecordWrite(r2, Operand(r1), r3, r0); | |
215 } | 215 } |
216 } | 216 } |
217 } | 217 } |
218 | 218 |
219 Variable* arguments = scope()->arguments(); | 219 Variable* arguments = scope()->arguments(); |
220 if (arguments != NULL) { | 220 if (arguments != NULL) { |
221 // Function uses arguments object. | 221 // Function uses arguments object. |
222 Comment cmnt(masm_, "[ Allocate arguments object"); | 222 Comment cmnt(masm_, "[ Allocate arguments object"); |
223 if (!function_in_register) { | 223 if (!function_in_register) { |
224 // 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... |
663 void FullCodeGenerator::SetVar(Variable* var, | 663 void FullCodeGenerator::SetVar(Variable* var, |
664 Register src, | 664 Register src, |
665 Register scratch0, | 665 Register scratch0, |
666 Register scratch1) { | 666 Register scratch1) { |
667 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); | 667 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
668 ASSERT(!scratch0.is(src)); | 668 ASSERT(!scratch0.is(src)); |
669 ASSERT(!scratch0.is(scratch1)); | 669 ASSERT(!scratch0.is(scratch1)); |
670 ASSERT(!scratch1.is(src)); | 670 ASSERT(!scratch1.is(src)); |
671 MemOperand location = VarOperand(var, scratch0); | 671 MemOperand location = VarOperand(var, scratch0); |
672 __ str(src, location); | 672 __ str(src, location); |
| 673 |
673 // 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. |
674 if (var->IsContextSlot()) { | 675 if (var->IsContextSlot()) { |
675 __ RecordWrite(scratch0, | 676 __ RecordWriteContextSlot(scratch0, |
676 Operand(Context::SlotOffset(var->index())), | 677 location.offset(), |
677 scratch1, | 678 src, |
678 src); | 679 scratch1, |
| 680 kLRHasBeenSaved, |
| 681 kDontSaveFPRegs); |
679 } | 682 } |
680 } | 683 } |
681 | 684 |
682 | 685 |
683 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 686 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
684 bool should_normalize, | 687 bool should_normalize, |
685 Label* if_true, | 688 Label* if_true, |
686 Label* if_false) { | 689 Label* if_false) { |
687 // 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 |
688 // 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... |
744 __ Check(ne, "Declaration in with context."); | 747 __ Check(ne, "Declaration in with context."); |
745 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); | 748 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex); |
746 __ Check(ne, "Declaration in catch context."); | 749 __ Check(ne, "Declaration in catch context."); |
747 } | 750 } |
748 if (function != NULL) { | 751 if (function != NULL) { |
749 Comment cmnt(masm_, "[ Declaration"); | 752 Comment cmnt(masm_, "[ Declaration"); |
750 VisitForAccumulatorValue(function); | 753 VisitForAccumulatorValue(function); |
751 __ str(result_register(), ContextOperand(cp, variable->index())); | 754 __ str(result_register(), ContextOperand(cp, variable->index())); |
752 int offset = Context::SlotOffset(variable->index()); | 755 int offset = Context::SlotOffset(variable->index()); |
753 // 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. |
754 __ mov(r1, Operand(cp)); | 757 __ RecordWriteContextSlot(cp, |
755 __ 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); |
756 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 765 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
757 } else if (mode == Variable::CONST || mode == Variable::LET) { | 766 } else if (mode == Variable::CONST || mode == Variable::LET) { |
758 Comment cmnt(masm_, "[ Declaration"); | 767 Comment cmnt(masm_, "[ Declaration"); |
759 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 768 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
760 __ str(ip, ContextOperand(cp, variable->index())); | 769 __ str(ip, ContextOperand(cp, variable->index())); |
761 // No write barrier since the_hole_value is in old space. | 770 // No write barrier since the_hole_value is in old space. |
762 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 771 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
763 } | 772 } |
764 break; | 773 break; |
765 | 774 |
(...skipping 729 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1495 VisitForAccumulatorValue(subexpr); | 1504 VisitForAccumulatorValue(subexpr); |
1496 | 1505 |
1497 // Store the subexpression value in the array's elements. | 1506 // Store the subexpression value in the array's elements. |
1498 __ ldr(r1, MemOperand(sp)); // Copy of array literal. | 1507 __ ldr(r1, MemOperand(sp)); // Copy of array literal. |
1499 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); | 1508 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); |
1500 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1509 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1501 __ str(result_register(), FieldMemOperand(r1, offset)); | 1510 __ str(result_register(), FieldMemOperand(r1, offset)); |
1502 | 1511 |
1503 // Update the write barrier for the array store with r0 as the scratch | 1512 // Update the write barrier for the array store with r0 as the scratch |
1504 // register. | 1513 // register. |
1505 __ RecordWrite(r1, Operand(offset), r2, result_register()); | 1514 __ RecordWriteField( |
| 1515 r1, offset, result_register(), r2, kLRHasBeenSaved, kDontSaveFPRegs); |
1506 | 1516 |
1507 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1517 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1508 } | 1518 } |
1509 | 1519 |
1510 if (result_saved) { | 1520 if (result_saved) { |
1511 context()->PlugTOS(); | 1521 context()->PlugTOS(); |
1512 } else { | 1522 } else { |
1513 context()->Plug(r0); | 1523 context()->Plug(r0); |
1514 } | 1524 } |
1515 } | 1525 } |
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1867 __ mov(r3, Operand(var->name())); | 1877 __ mov(r3, Operand(var->name())); |
1868 __ push(r3); | 1878 __ push(r3); |
1869 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1879 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1870 // Perform the assignment. | 1880 // Perform the assignment. |
1871 __ bind(&assign); | 1881 __ bind(&assign); |
1872 __ str(result_register(), location); | 1882 __ str(result_register(), location); |
1873 if (var->IsContextSlot()) { | 1883 if (var->IsContextSlot()) { |
1874 // RecordWrite may destroy all its register arguments. | 1884 // RecordWrite may destroy all its register arguments. |
1875 __ mov(r3, result_register()); | 1885 __ mov(r3, result_register()); |
1876 int offset = Context::SlotOffset(var->index()); | 1886 int offset = Context::SlotOffset(var->index()); |
1877 __ RecordWrite(r1, Operand(offset), r2, r3); | 1887 __ RecordWriteContextSlot( |
| 1888 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); |
1878 } | 1889 } |
1879 } | 1890 } |
1880 | 1891 |
1881 } else if (var->mode() != Variable::CONST) { | 1892 } else if (var->mode() != Variable::CONST) { |
1882 // Assignment to var or initializing assignment to let. | 1893 // Assignment to var or initializing assignment to let. |
1883 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1894 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1884 MemOperand location = VarOperand(var, r1); | 1895 MemOperand location = VarOperand(var, r1); |
1885 if (FLAG_debug_code && op == Token::INIT_LET) { | 1896 if (FLAG_debug_code && op == Token::INIT_LET) { |
1886 // Check for an uninitialized let binding. | 1897 // Check for an uninitialized let binding. |
1887 __ ldr(r2, location); | 1898 __ ldr(r2, location); |
1888 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); | 1899 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
1889 __ Check(eq, "Let binding re-initialization."); | 1900 __ Check(eq, "Let binding re-initialization."); |
1890 } | 1901 } |
1891 // Perform the assignment. | 1902 // Perform the assignment. |
1892 __ str(r0, location); | 1903 __ str(r0, location); |
1893 if (var->IsContextSlot()) { | 1904 if (var->IsContextSlot()) { |
1894 __ mov(r3, r0); | 1905 __ mov(r3, r0); |
1895 __ RecordWrite(r1, Operand(Context::SlotOffset(var->index())), r2, r3); | 1906 int offset = Context::SlotOffset(var->index()); |
| 1907 __ RecordWriteContextSlot( |
| 1908 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); |
1896 } | 1909 } |
1897 } else { | 1910 } else { |
1898 ASSERT(var->IsLookupSlot()); | 1911 ASSERT(var->IsLookupSlot()); |
1899 __ push(r0); // Value. | 1912 __ push(r0); // Value. |
1900 __ mov(r1, Operand(var->name())); | 1913 __ mov(r1, Operand(var->name())); |
1901 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); | 1914 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag()))); |
1902 __ Push(cp, r1, r0); // Context, name, strict mode. | 1915 __ Push(cp, r1, r0); // Context, name, strict mode. |
1903 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1916 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1904 } | 1917 } |
1905 } | 1918 } |
(...skipping 945 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2851 __ JumpIfSmi(r1, &done); | 2864 __ JumpIfSmi(r1, &done); |
2852 | 2865 |
2853 // If the object is not a value type, return the value. | 2866 // If the object is not a value type, return the value. |
2854 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE); | 2867 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE); |
2855 __ b(ne, &done); | 2868 __ b(ne, &done); |
2856 | 2869 |
2857 // Store the value. | 2870 // Store the value. |
2858 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); | 2871 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); |
2859 // Update the write barrier. Save the value as it will be | 2872 // Update the write barrier. Save the value as it will be |
2860 // overwritten by the write barrier code and is needed afterward. | 2873 // overwritten by the write barrier code and is needed afterward. |
2861 __ RecordWrite(r1, Operand(JSValue::kValueOffset - kHeapObjectTag), r2, r3); | 2874 __ mov(r2, r0); |
| 2875 __ RecordWriteField( |
| 2876 r1, JSValue::kValueOffset, r2, r3, kLRHasBeenSaved, kDontSaveFPRegs); |
2862 | 2877 |
2863 __ bind(&done); | 2878 __ bind(&done); |
2864 context()->Plug(r0); | 2879 context()->Plug(r0); |
2865 } | 2880 } |
2866 | 2881 |
2867 | 2882 |
2868 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { | 2883 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { |
2869 ASSERT_EQ(args->length(), 1); | 2884 ASSERT_EQ(args->length(), 1); |
2870 | 2885 |
2871 // Load the argument on the stack and call the stub. | 2886 // Load the argument on the stack and call the stub. |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3139 __ add(index2, | 3154 __ add(index2, |
3140 scratch1, | 3155 scratch1, |
3141 Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize)); | 3156 Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize)); |
3142 | 3157 |
3143 // Swap elements. | 3158 // Swap elements. |
3144 __ ldr(scratch1, MemOperand(index1, 0)); | 3159 __ ldr(scratch1, MemOperand(index1, 0)); |
3145 __ ldr(scratch2, MemOperand(index2, 0)); | 3160 __ ldr(scratch2, MemOperand(index2, 0)); |
3146 __ str(scratch1, MemOperand(index2, 0)); | 3161 __ str(scratch1, MemOperand(index2, 0)); |
3147 __ str(scratch2, MemOperand(index1, 0)); | 3162 __ str(scratch2, MemOperand(index1, 0)); |
3148 | 3163 |
3149 Label new_space; | 3164 Label no_remembered_set; |
3150 __ InNewSpace(elements, scratch1, eq, &new_space); | 3165 __ CheckPageFlag(elements, |
| 3166 scratch1, |
| 3167 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 3168 ne, |
| 3169 &no_remembered_set); |
3151 // Possible optimization: do a check that both values are Smis | 3170 // Possible optimization: do a check that both values are Smis |
3152 // (or them and test against Smi mask.) | 3171 // (or them and test against Smi mask.) |
3153 | 3172 |
3154 __ mov(scratch1, elements); | 3173 // We are swapping two objects in an array and the incremental marker never |
3155 __ RecordWriteHelper(elements, index1, scratch2); | 3174 // pauses in the middle of scanning a single object. Therefore the |
3156 __ RecordWriteHelper(scratch1, index2, scratch2); // scratch1 holds elements. | 3175 // incremental marker is not disturbed, so we don't need to call the |
| 3176 // RecordWrite stub that notifies the incremental marker. |
| 3177 __ RememberedSetHelper( |
| 3178 index1, scratch2, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); |
| 3179 __ RememberedSetHelper( |
| 3180 index2, scratch2, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); |
3157 | 3181 |
3158 __ bind(&new_space); | 3182 __ bind(&no_remembered_set); |
3159 // We are done. Drop elements from the stack, and return undefined. | 3183 // We are done. Drop elements from the stack, and return undefined. |
3160 __ Drop(3); | 3184 __ Drop(3); |
3161 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 3185 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
3162 __ jmp(&done); | 3186 __ jmp(&done); |
3163 | 3187 |
3164 __ bind(&slow_case); | 3188 __ bind(&slow_case); |
3165 __ CallRuntime(Runtime::kSwapElements, 3); | 3189 __ CallRuntime(Runtime::kSwapElements, 3); |
3166 | 3190 |
3167 __ bind(&done); | 3191 __ bind(&done); |
3168 context()->Plug(r0); | 3192 context()->Plug(r0); |
(...skipping 1051 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4220 *context_length = 0; | 4244 *context_length = 0; |
4221 return previous_; | 4245 return previous_; |
4222 } | 4246 } |
4223 | 4247 |
4224 | 4248 |
4225 #undef __ | 4249 #undef __ |
4226 | 4250 |
4227 } } // namespace v8::internal | 4251 } } // namespace v8::internal |
4228 | 4252 |
4229 #endif // V8_TARGET_ARCH_ARM | 4253 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |