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 29 matching lines...) Expand all Loading... |
40 #include "code-stubs.h" | 40 #include "code-stubs.h" |
41 #include "codegen.h" | 41 #include "codegen.h" |
42 #include "compiler.h" | 42 #include "compiler.h" |
43 #include "debug.h" | 43 #include "debug.h" |
44 #include "full-codegen.h" | 44 #include "full-codegen.h" |
45 #include "parser.h" | 45 #include "parser.h" |
46 #include "scopes.h" | 46 #include "scopes.h" |
47 #include "stub-cache.h" | 47 #include "stub-cache.h" |
48 | 48 |
49 #include "mips/code-stubs-mips.h" | 49 #include "mips/code-stubs-mips.h" |
| 50 #include "mips/macro-assembler-mips.h" |
50 | 51 |
51 namespace v8 { | 52 namespace v8 { |
52 namespace internal { | 53 namespace internal { |
53 | 54 |
54 #define __ ACCESS_MASM(masm_) | 55 #define __ ACCESS_MASM(masm_) |
55 | 56 |
56 | 57 |
57 static unsigned GetPropertyId(Property* property) { | 58 static unsigned GetPropertyId(Property* property) { |
58 return property->id(); | 59 return property->id(); |
59 } | 60 } |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 // Copy any necessary parameters into the context. | 208 // Copy any necessary parameters into the context. |
208 int num_parameters = info->scope()->num_parameters(); | 209 int num_parameters = info->scope()->num_parameters(); |
209 for (int i = 0; i < num_parameters; i++) { | 210 for (int i = 0; i < num_parameters; i++) { |
210 Variable* var = scope()->parameter(i); | 211 Variable* var = scope()->parameter(i); |
211 if (var->IsContextSlot()) { | 212 if (var->IsContextSlot()) { |
212 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 213 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
213 (num_parameters - 1 - i) * kPointerSize; | 214 (num_parameters - 1 - i) * kPointerSize; |
214 // Load parameter from stack. | 215 // Load parameter from stack. |
215 __ lw(a0, MemOperand(fp, parameter_offset)); | 216 __ lw(a0, MemOperand(fp, parameter_offset)); |
216 // Store it in the context. | 217 // Store it in the context. |
217 __ li(a1, Operand(Context::SlotOffset(var->index()))); | 218 MemOperand target = ContextOperand(cp, var->index()); |
218 __ addu(a2, cp, a1); | 219 __ sw(a0, target); |
219 __ sw(a0, MemOperand(a2, 0)); | 220 |
220 // Update the write barrier. This clobbers all involved | 221 // Update the write barrier. |
221 // registers, so we have to use two more registers to avoid | 222 __ RecordWriteContextSlot( |
222 // clobbering cp. | 223 cp, target.offset(), a0, a3, kRAHasBeenSaved, kDontSaveFPRegs); |
223 __ mov(a2, cp); | |
224 __ RecordWrite(a2, a1, a3); | |
225 } | 224 } |
226 } | 225 } |
227 } | 226 } |
228 | 227 |
229 Variable* arguments = scope()->arguments(); | 228 Variable* arguments = scope()->arguments(); |
230 if (arguments != NULL) { | 229 if (arguments != NULL) { |
231 // Function uses arguments object. | 230 // Function uses arguments object. |
232 Comment cmnt(masm_, "[ Allocate arguments object"); | 231 Comment cmnt(masm_, "[ Allocate arguments object"); |
233 if (!function_in_register) { | 232 if (!function_in_register) { |
234 // Load this again, if it's used by the local context below. | 233 // Load this again, if it's used by the local context below. |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
678 Register scratch0, | 677 Register scratch0, |
679 Register scratch1) { | 678 Register scratch1) { |
680 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); | 679 ASSERT(var->IsContextSlot() || var->IsStackAllocated()); |
681 ASSERT(!scratch0.is(src)); | 680 ASSERT(!scratch0.is(src)); |
682 ASSERT(!scratch0.is(scratch1)); | 681 ASSERT(!scratch0.is(scratch1)); |
683 ASSERT(!scratch1.is(src)); | 682 ASSERT(!scratch1.is(src)); |
684 MemOperand location = VarOperand(var, scratch0); | 683 MemOperand location = VarOperand(var, scratch0); |
685 __ sw(src, location); | 684 __ sw(src, location); |
686 // Emit the write barrier code if the location is in the heap. | 685 // Emit the write barrier code if the location is in the heap. |
687 if (var->IsContextSlot()) { | 686 if (var->IsContextSlot()) { |
688 __ RecordWrite(scratch0, | 687 __ RecordWriteContextSlot(scratch0, |
689 Operand(Context::SlotOffset(var->index())), | 688 location.offset(), |
690 scratch1, | 689 src, |
691 src); | 690 scratch1, |
| 691 kRAHasBeenSaved, |
| 692 kDontSaveFPRegs); |
692 } | 693 } |
693 } | 694 } |
694 | 695 |
695 | 696 |
696 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, | 697 void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state, |
697 bool should_normalize, | 698 bool should_normalize, |
698 Label* if_true, | 699 Label* if_true, |
699 Label* if_false) { | 700 Label* if_false) { |
700 // Only prepare for bailouts before splits if we're in a test | 701 // Only prepare for bailouts before splits if we're in a test |
701 // context. Otherwise, we let the Visit function deal with the | 702 // context. Otherwise, we let the Visit function deal with the |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
758 __ LoadRoot(t0, Heap::kCatchContextMapRootIndex); | 759 __ LoadRoot(t0, Heap::kCatchContextMapRootIndex); |
759 __ Check(ne, "Declaration in catch context.", | 760 __ Check(ne, "Declaration in catch context.", |
760 a1, Operand(t0)); | 761 a1, Operand(t0)); |
761 } | 762 } |
762 if (function != NULL) { | 763 if (function != NULL) { |
763 Comment cmnt(masm_, "[ Declaration"); | 764 Comment cmnt(masm_, "[ Declaration"); |
764 VisitForAccumulatorValue(function); | 765 VisitForAccumulatorValue(function); |
765 __ sw(result_register(), ContextOperand(cp, variable->index())); | 766 __ sw(result_register(), ContextOperand(cp, variable->index())); |
766 int offset = Context::SlotOffset(variable->index()); | 767 int offset = Context::SlotOffset(variable->index()); |
767 // We know that we have written a function, which is not a smi. | 768 // We know that we have written a function, which is not a smi. |
768 __ mov(a1, cp); | 769 __ RecordWriteContextSlot(cp, |
769 __ RecordWrite(a1, Operand(offset), a2, result_register()); | 770 offset, |
| 771 result_register(), |
| 772 a2, |
| 773 kRAHasBeenSaved, |
| 774 kDontSaveFPRegs, |
| 775 EMIT_REMEMBERED_SET, |
| 776 OMIT_SMI_CHECK); |
770 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 777 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
771 } else if (mode == Variable::CONST || mode == Variable::LET) { | 778 } else if (mode == Variable::CONST || mode == Variable::LET) { |
772 Comment cmnt(masm_, "[ Declaration"); | 779 Comment cmnt(masm_, "[ Declaration"); |
773 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 780 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
774 __ sw(at, ContextOperand(cp, variable->index())); | 781 __ sw(at, ContextOperand(cp, variable->index())); |
775 // No write barrier since the_hole_value is in old space. | 782 // No write barrier since the_hole_value is in old space. |
776 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 783 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
777 } | 784 } |
778 break; | 785 break; |
779 | 786 |
(...skipping 726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1506 VisitForAccumulatorValue(subexpr); | 1513 VisitForAccumulatorValue(subexpr); |
1507 | 1514 |
1508 // Store the subexpression value in the array's elements. | 1515 // Store the subexpression value in the array's elements. |
1509 __ lw(a1, MemOperand(sp)); // Copy of array literal. | 1516 __ lw(a1, MemOperand(sp)); // Copy of array literal. |
1510 __ lw(a1, FieldMemOperand(a1, JSObject::kElementsOffset)); | 1517 __ lw(a1, FieldMemOperand(a1, JSObject::kElementsOffset)); |
1511 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1518 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1512 __ sw(result_register(), FieldMemOperand(a1, offset)); | 1519 __ sw(result_register(), FieldMemOperand(a1, offset)); |
1513 | 1520 |
1514 // Update the write barrier for the array store with v0 as the scratch | 1521 // Update the write barrier for the array store with v0 as the scratch |
1515 // register. | 1522 // register. |
1516 __ RecordWrite(a1, Operand(offset), a2, result_register()); | 1523 __ RecordWriteField( |
| 1524 a1, offset, result_register(), a2, kRAHasBeenSaved, kDontSaveFPRegs); |
1517 | 1525 |
1518 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1526 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1519 } | 1527 } |
1520 | 1528 |
1521 if (result_saved) { | 1529 if (result_saved) { |
1522 context()->PlugTOS(); | 1530 context()->PlugTOS(); |
1523 } else { | 1531 } else { |
1524 context()->Plug(v0); | 1532 context()->Plug(v0); |
1525 } | 1533 } |
1526 } | 1534 } |
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1883 __ li(a3, Operand(var->name())); | 1891 __ li(a3, Operand(var->name())); |
1884 __ push(a3); | 1892 __ push(a3); |
1885 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1893 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1886 // Perform the assignment. | 1894 // Perform the assignment. |
1887 __ bind(&assign); | 1895 __ bind(&assign); |
1888 __ sw(result_register(), location); | 1896 __ sw(result_register(), location); |
1889 if (var->IsContextSlot()) { | 1897 if (var->IsContextSlot()) { |
1890 // RecordWrite may destroy all its register arguments. | 1898 // RecordWrite may destroy all its register arguments. |
1891 __ mov(a3, result_register()); | 1899 __ mov(a3, result_register()); |
1892 int offset = Context::SlotOffset(var->index()); | 1900 int offset = Context::SlotOffset(var->index()); |
1893 __ RecordWrite(a1, Operand(offset), a2, a3); | 1901 __ RecordWriteContextSlot( |
| 1902 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
1894 } | 1903 } |
1895 } | 1904 } |
1896 | 1905 |
1897 } else if (var->mode() != Variable::CONST) { | 1906 } else if (var->mode() != Variable::CONST) { |
1898 // Assignment to var or initializing assignment to let. | 1907 // Assignment to var or initializing assignment to let. |
1899 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1908 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1900 MemOperand location = VarOperand(var, a1); | 1909 MemOperand location = VarOperand(var, a1); |
1901 if (FLAG_debug_code && op == Token::INIT_LET) { | 1910 if (FLAG_debug_code && op == Token::INIT_LET) { |
1902 // Check for an uninitialized let binding. | 1911 // Check for an uninitialized let binding. |
1903 __ lw(a2, location); | 1912 __ lw(a2, location); |
1904 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 1913 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
1905 __ Check(eq, "Let binding re-initialization.", a2, Operand(t0)); | 1914 __ Check(eq, "Let binding re-initialization.", a2, Operand(t0)); |
1906 } | 1915 } |
1907 // Perform the assignment. | 1916 // Perform the assignment. |
1908 __ sw(v0, location); | 1917 __ sw(v0, location); |
1909 if (var->IsContextSlot()) { | 1918 if (var->IsContextSlot()) { |
1910 __ mov(a3, v0); | 1919 __ mov(a3, v0); |
1911 __ RecordWrite(a1, Operand(Context::SlotOffset(var->index())), a2, a3); | 1920 int offset = Context::SlotOffset(var->index()); |
| 1921 __ RecordWriteContextSlot( |
| 1922 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
1912 } | 1923 } |
1913 } else { | 1924 } else { |
1914 ASSERT(var->IsLookupSlot()); | 1925 ASSERT(var->IsLookupSlot()); |
1915 __ push(v0); // Value. | 1926 __ push(v0); // Value. |
1916 __ li(a1, Operand(var->name())); | 1927 __ li(a1, Operand(var->name())); |
1917 __ li(a0, Operand(Smi::FromInt(strict_mode_flag()))); | 1928 __ li(a0, Operand(Smi::FromInt(strict_mode_flag()))); |
1918 __ Push(cp, a1, a0); // Context, name, strict mode. | 1929 __ Push(cp, a1, a0); // Context, name, strict mode. |
1919 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1930 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1920 } | 1931 } |
1921 } | 1932 } |
(...skipping 945 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2867 __ JumpIfSmi(a1, &done); | 2878 __ JumpIfSmi(a1, &done); |
2868 | 2879 |
2869 // If the object is not a value type, return the value. | 2880 // If the object is not a value type, return the value. |
2870 __ GetObjectType(a1, a2, a2); | 2881 __ GetObjectType(a1, a2, a2); |
2871 __ Branch(&done, ne, a2, Operand(JS_VALUE_TYPE)); | 2882 __ Branch(&done, ne, a2, Operand(JS_VALUE_TYPE)); |
2872 | 2883 |
2873 // Store the value. | 2884 // Store the value. |
2874 __ sw(v0, FieldMemOperand(a1, JSValue::kValueOffset)); | 2885 __ sw(v0, FieldMemOperand(a1, JSValue::kValueOffset)); |
2875 // Update the write barrier. Save the value as it will be | 2886 // Update the write barrier. Save the value as it will be |
2876 // overwritten by the write barrier code and is needed afterward. | 2887 // overwritten by the write barrier code and is needed afterward. |
2877 __ RecordWrite(a1, Operand(JSValue::kValueOffset - kHeapObjectTag), a2, a3); | 2888 __ mov(a2, v0); |
| 2889 __ RecordWriteField( |
| 2890 a1, JSValue::kValueOffset, a2, a3, kRAHasBeenSaved, kDontSaveFPRegs); |
2878 | 2891 |
2879 __ bind(&done); | 2892 __ bind(&done); |
2880 context()->Plug(v0); | 2893 context()->Plug(v0); |
2881 } | 2894 } |
2882 | 2895 |
2883 | 2896 |
2884 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { | 2897 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) { |
2885 ASSERT_EQ(args->length(), 1); | 2898 ASSERT_EQ(args->length(), 1); |
2886 | 2899 |
2887 // Load the argument on the stack and call the stub. | 2900 // Load the argument on the stack and call the stub. |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3160 __ Addu(index1, scratch1, index1); | 3173 __ Addu(index1, scratch1, index1); |
3161 __ sll(index2, index2, kPointerSizeLog2 - kSmiTagSize); | 3174 __ sll(index2, index2, kPointerSizeLog2 - kSmiTagSize); |
3162 __ Addu(index2, scratch1, index2); | 3175 __ Addu(index2, scratch1, index2); |
3163 | 3176 |
3164 // Swap elements. | 3177 // Swap elements. |
3165 __ lw(scratch1, MemOperand(index1, 0)); | 3178 __ lw(scratch1, MemOperand(index1, 0)); |
3166 __ lw(scratch2, MemOperand(index2, 0)); | 3179 __ lw(scratch2, MemOperand(index2, 0)); |
3167 __ sw(scratch1, MemOperand(index2, 0)); | 3180 __ sw(scratch1, MemOperand(index2, 0)); |
3168 __ sw(scratch2, MemOperand(index1, 0)); | 3181 __ sw(scratch2, MemOperand(index1, 0)); |
3169 | 3182 |
3170 Label new_space; | 3183 Label no_remembered_set; |
3171 __ InNewSpace(elements, scratch1, eq, &new_space); | 3184 __ CheckPageFlag(elements, |
| 3185 scratch1, |
| 3186 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 3187 ne, |
| 3188 &no_remembered_set); |
3172 // Possible optimization: do a check that both values are Smis | 3189 // Possible optimization: do a check that both values are Smis |
3173 // (or them and test against Smi mask). | 3190 // (or them and test against Smi mask). |
3174 | 3191 |
3175 __ mov(scratch1, elements); | 3192 // We are swapping two objects in an array and the incremental marker never |
3176 __ RecordWriteHelper(elements, index1, scratch2); | 3193 // pauses in the middle of scanning a single object. Therefore the |
3177 __ RecordWriteHelper(scratch1, index2, scratch2); // scratch1 holds elements. | 3194 // incremental marker is not disturbed, so we don't need to call the |
| 3195 // RecordWrite stub that notifies the incremental marker. |
| 3196 __ RememberedSetHelper( |
| 3197 index1, scratch2, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); |
| 3198 __ RememberedSetHelper( |
| 3199 index2, scratch2, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); |
3178 | 3200 |
3179 __ bind(&new_space); | 3201 __ bind(&no_remembered_set); |
3180 // We are done. Drop elements from the stack, and return undefined. | 3202 // We are done. Drop elements from the stack, and return undefined. |
3181 __ Drop(3); | 3203 __ Drop(3); |
3182 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); | 3204 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); |
3183 __ jmp(&done); | 3205 __ jmp(&done); |
3184 | 3206 |
3185 __ bind(&slow_case); | 3207 __ bind(&slow_case); |
3186 __ CallRuntime(Runtime::kSwapElements, 3); | 3208 __ CallRuntime(Runtime::kSwapElements, 3); |
3187 | 3209 |
3188 __ bind(&done); | 3210 __ bind(&done); |
3189 context()->Plug(v0); | 3211 context()->Plug(v0); |
(...skipping 1059 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4249 *context_length = 0; | 4271 *context_length = 0; |
4250 return previous_; | 4272 return previous_; |
4251 } | 4273 } |
4252 | 4274 |
4253 | 4275 |
4254 #undef __ | 4276 #undef __ |
4255 | 4277 |
4256 } } // namespace v8::internal | 4278 } } // namespace v8::internal |
4257 | 4279 |
4258 #endif // V8_TARGET_ARCH_MIPS | 4280 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |