OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
8 | 8 |
9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
10 #include "src/ic/ic.h" | 10 #include "src/ic/ic.h" |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 // we enter the runtime system to make sure that indexing into string | 151 // we enter the runtime system to make sure that indexing into string |
152 // objects work as intended. | 152 // objects work as intended. |
153 DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 153 DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
154 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 154 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
155 __ cmp(scratch, Operand(JS_OBJECT_TYPE)); | 155 __ cmp(scratch, Operand(JS_OBJECT_TYPE)); |
156 __ b(lt, slow); | 156 __ b(lt, slow); |
157 } | 157 } |
158 | 158 |
159 | 159 |
160 // Loads an indexed element from a fast case array. | 160 // Loads an indexed element from a fast case array. |
161 // If not_fast_array is NULL, doesn't perform the elements map check. | |
162 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, | 161 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, |
163 Register key, Register elements, | 162 Register key, Register elements, |
164 Register scratch1, Register scratch2, | 163 Register scratch1, Register scratch2, |
165 Register result, Label* not_fast_array, | 164 Register result, Label* slow) { |
166 Label* out_of_range) { | |
167 // Register use: | 165 // Register use: |
168 // | 166 // |
169 // receiver - holds the receiver on entry. | 167 // receiver - holds the receiver on entry. |
170 // Unchanged unless 'result' is the same register. | 168 // Unchanged unless 'result' is the same register. |
171 // | 169 // |
172 // key - holds the smi key on entry. | 170 // key - holds the smi key on entry. |
173 // Unchanged unless 'result' is the same register. | 171 // Unchanged unless 'result' is the same register. |
174 // | 172 // |
175 // elements - holds the elements of the receiver on exit. | |
176 // | |
177 // result - holds the result on exit if the load succeeded. | 173 // result - holds the result on exit if the load succeeded. |
178 // Allowed to be the the same as 'receiver' or 'key'. | 174 // Allowed to be the the same as 'receiver' or 'key'. |
179 // Unchanged on bailout so 'receiver' and 'key' can be safely | 175 // Unchanged on bailout so 'receiver' and 'key' can be safely |
180 // used by further computation. | 176 // used by further computation. |
181 // | 177 // |
182 // Scratch registers: | 178 // Scratch registers: |
183 // | 179 // |
184 // scratch1 - used to hold elements map and elements length. | 180 // elements - holds the elements of the receiver and its prototypes. |
185 // Holds the elements map if not_fast_array branch is taken. | |
186 // | 181 // |
187 // scratch2 - used to hold the loaded value. | 182 // scratch1 - used to hold elements length, bit fields, base addresses. |
| 183 // |
| 184 // scratch2 - used to hold maps, prototypes, and the loaded value. |
| 185 Label check_prototypes, check_next_prototype; |
| 186 Label done, in_bounds, return_undefined; |
188 | 187 |
189 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 188 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
190 if (not_fast_array != NULL) { | 189 __ AssertFastElements(elements); |
191 // Check that the object is in fast mode and writable. | 190 |
192 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); | |
193 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | |
194 __ cmp(scratch1, ip); | |
195 __ b(ne, not_fast_array); | |
196 } else { | |
197 __ AssertFastElements(elements); | |
198 } | |
199 // Check that the key (index) is within bounds. | 191 // Check that the key (index) is within bounds. |
200 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); | 192 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
201 __ cmp(key, Operand(scratch1)); | 193 __ cmp(key, Operand(scratch1)); |
202 __ b(hs, out_of_range); | 194 __ b(lo, &in_bounds); |
| 195 // Out-of-bounds. Check the prototype chain to see if we can just return |
| 196 // 'undefined'. |
| 197 __ cmp(key, Operand(0)); |
| 198 __ b(lt, slow); // Negative keys can't take the fast OOB path. |
| 199 __ bind(&check_prototypes); |
| 200 __ ldr(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 201 __ bind(&check_next_prototype); |
| 202 __ ldr(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); |
| 203 // scratch2: current prototype |
| 204 __ CompareRoot(scratch2, Heap::kNullValueRootIndex); |
| 205 __ b(eq, &return_undefined); |
| 206 __ ldr(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); |
| 207 __ ldr(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); |
| 208 // elements: elements of current prototype |
| 209 // scratch2: map of current prototype |
| 210 __ CompareInstanceType(scratch2, scratch1, JS_OBJECT_TYPE); |
| 211 __ b(lo, slow); |
| 212 __ ldrb(scratch1, FieldMemOperand(scratch2, Map::kBitFieldOffset)); |
| 213 __ tst(scratch1, Operand((1 << Map::kIsAccessCheckNeeded) | |
| 214 (1 << Map::kHasIndexedInterceptor))); |
| 215 __ b(ne, slow); |
| 216 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); |
| 217 __ b(ne, slow); |
| 218 __ jmp(&check_next_prototype); |
| 219 |
| 220 __ bind(&return_undefined); |
| 221 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); |
| 222 __ jmp(&done); |
| 223 |
| 224 __ bind(&in_bounds); |
203 // Fast case: Do the load. | 225 // Fast case: Do the load. |
204 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 226 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
205 __ ldr(scratch2, MemOperand::PointerAddressFromSmiKey(scratch1, key)); | 227 __ ldr(scratch2, MemOperand::PointerAddressFromSmiKey(scratch1, key)); |
206 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 228 __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex); |
207 __ cmp(scratch2, ip); | 229 // In case the loaded value is the_hole we have to check the prototype chain. |
208 // In case the loaded value is the_hole we have to consult GetProperty | 230 __ b(eq, &check_prototypes); |
209 // to ensure the prototype chain is searched. | |
210 __ b(eq, out_of_range); | |
211 __ mov(result, scratch2); | 231 __ mov(result, scratch2); |
| 232 __ bind(&done); |
212 } | 233 } |
213 | 234 |
214 | 235 |
215 // Checks whether a key is an array index string or a unique name. | 236 // Checks whether a key is an array index string or a unique name. |
216 // Falls through if a key is a unique name. | 237 // Falls through if a key is a unique name. |
217 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, | 238 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, |
218 Register map, Register hash, | 239 Register map, Register hash, |
219 Label* index_string, Label* not_unique) { | 240 Label* index_string, Label* not_unique) { |
220 // The key is not a smi. | 241 // The key is not a smi. |
221 Label unique; | 242 Label unique; |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
461 __ bind(&index_smi); | 482 __ bind(&index_smi); |
462 // Now the key is known to be a smi. This place is also jumped to from below | 483 // Now the key is known to be a smi. This place is also jumped to from below |
463 // where a numeric string is converted to a smi. | 484 // where a numeric string is converted to a smi. |
464 | 485 |
465 GenerateKeyedLoadReceiverCheck(masm, receiver, r0, r3, | 486 GenerateKeyedLoadReceiverCheck(masm, receiver, r0, r3, |
466 Map::kHasIndexedInterceptor, &slow); | 487 Map::kHasIndexedInterceptor, &slow); |
467 | 488 |
468 // Check the receiver's map to see if it has fast elements. | 489 // Check the receiver's map to see if it has fast elements. |
469 __ CheckFastElements(r0, r3, &check_number_dictionary); | 490 __ CheckFastElements(r0, r3, &check_number_dictionary); |
470 | 491 |
471 GenerateFastArrayLoad(masm, receiver, key, r0, r3, r4, r0, NULL, &slow); | 492 GenerateFastArrayLoad(masm, receiver, key, r0, r3, r4, r0, &slow); |
472 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r4, r3); | 493 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r4, r3); |
473 __ Ret(); | 494 __ Ret(); |
474 | 495 |
475 __ bind(&check_number_dictionary); | 496 __ bind(&check_number_dictionary); |
476 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 497 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
477 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset)); | 498 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset)); |
478 | 499 |
479 // Check whether the elements is a number dictionary. | 500 // Check whether the elements is a number dictionary. |
480 // r3: elements map | 501 // r3: elements map |
481 // r4: elements | 502 // r4: elements |
(...skipping 537 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1019 patcher.EmitCondition(ne); | 1040 patcher.EmitCondition(ne); |
1020 } else { | 1041 } else { |
1021 DCHECK(Assembler::GetCondition(branch_instr) == ne); | 1042 DCHECK(Assembler::GetCondition(branch_instr) == ne); |
1022 patcher.EmitCondition(eq); | 1043 patcher.EmitCondition(eq); |
1023 } | 1044 } |
1024 } | 1045 } |
1025 } | 1046 } |
1026 } // namespace v8::internal | 1047 } // namespace v8::internal |
1027 | 1048 |
1028 #endif // V8_TARGET_ARCH_ARM | 1049 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |