| 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 | 5 |
| 6 #include "src/v8.h" | 6 #include "src/v8.h" |
| 7 | 7 |
| 8 #if V8_TARGET_ARCH_MIPS | 8 #if V8_TARGET_ARCH_MIPS |
| 9 | 9 |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 // In the case that the object is a value-wrapper object, | 153 // In the case that the object is a value-wrapper object, |
| 154 // we enter the runtime system to make sure that indexing into string | 154 // we enter the runtime system to make sure that indexing into string |
| 155 // objects work as intended. | 155 // objects work as intended. |
| 156 DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 156 DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
| 157 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 157 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 158 __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE)); | 158 __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE)); |
| 159 } | 159 } |
| 160 | 160 |
| 161 | 161 |
| 162 // Loads an indexed element from a fast case array. | 162 // Loads an indexed element from a fast case array. |
| 163 // If not_fast_array is NULL, doesn't perform the elements map check. | |
| 164 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, | 163 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, |
| 165 Register key, Register elements, | 164 Register key, Register elements, |
| 166 Register scratch1, Register scratch2, | 165 Register scratch1, Register scratch2, |
| 167 Register result, Label* not_fast_array, | 166 Register result, Label* slow) { |
| 168 Label* out_of_range) { | |
| 169 // Register use: | 167 // Register use: |
| 170 // | 168 // |
| 171 // receiver - holds the receiver on entry. | 169 // receiver - holds the receiver on entry. |
| 172 // Unchanged unless 'result' is the same register. | 170 // Unchanged unless 'result' is the same register. |
| 173 // | 171 // |
| 174 // key - holds the smi key on entry. | 172 // key - holds the smi key on entry. |
| 175 // Unchanged unless 'result' is the same register. | 173 // Unchanged unless 'result' is the same register. |
| 176 // | 174 // |
| 177 // elements - holds the elements of the receiver on exit. | |
| 178 // | |
| 179 // result - holds the result on exit if the load succeeded. | 175 // result - holds the result on exit if the load succeeded. |
| 180 // Allowed to be the the same as 'receiver' or 'key'. | 176 // Allowed to be the the same as 'receiver' or 'key'. |
| 181 // Unchanged on bailout so 'receiver' and 'key' can be safely | 177 // Unchanged on bailout so 'receiver' and 'key' can be safely |
| 182 // used by further computation. | 178 // used by further computation. |
| 183 // | 179 // |
| 184 // Scratch registers: | 180 // Scratch registers: |
| 185 // | 181 // |
| 186 // scratch1 - used to hold elements map and elements length. | 182 // elements - holds the elements of the receiver and its prototypes. |
| 187 // Holds the elements map if not_fast_array branch is taken. | |
| 188 // | 183 // |
| 189 // scratch2 - used to hold the loaded value. | 184 // scratch1 - used to hold elements length, bit fields, base addresses. |
| 185 // |
| 186 // scratch2 - used to hold maps, prototypes, and the loaded value. |
| 187 Label check_prototypes, check_next_prototype; |
| 188 Label done, in_bounds, return_undefined; |
| 190 | 189 |
| 191 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 190 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 192 if (not_fast_array != NULL) { | 191 __ AssertFastElements(elements); |
| 193 // Check that the object is in fast mode (not dictionary). | |
| 194 __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); | |
| 195 __ LoadRoot(at, Heap::kFixedArrayMapRootIndex); | |
| 196 __ Branch(not_fast_array, ne, scratch1, Operand(at)); | |
| 197 } else { | |
| 198 __ AssertFastElements(elements); | |
| 199 } | |
| 200 | 192 |
| 201 // Check that the key (index) is within bounds. | 193 // Check that the key (index) is within bounds. |
| 202 __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); | 194 __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
| 203 __ Branch(out_of_range, hs, key, Operand(scratch1)); | 195 __ Branch(&in_bounds, lo, key, Operand(scratch1)); |
| 196 // Out-of-bounds. Check the prototype chain to see if we can just return |
| 197 // 'undefined'. |
| 198 // Negative keys can't take the fast OOB path. |
| 199 __ Branch(slow, lt, key, Operand(zero_reg)); |
| 200 __ bind(&check_prototypes); |
| 201 __ lw(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 202 __ bind(&check_next_prototype); |
| 203 __ lw(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); |
| 204 // scratch2: current prototype |
| 205 __ LoadRoot(at, Heap::kNullValueRootIndex); |
| 206 __ Branch(&return_undefined, eq, scratch2, Operand(at)); |
| 207 __ lw(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); |
| 208 __ lw(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); |
| 209 // elements: elements of current prototype |
| 210 // scratch2: map of current prototype |
| 211 __ lbu(scratch1, FieldMemOperand(scratch2, Map::kInstanceTypeOffset)); |
| 212 __ Branch(slow, lo, scratch1, Operand(JS_OBJECT_TYPE)); |
| 213 __ lbu(scratch1, FieldMemOperand(scratch2, Map::kBitFieldOffset)); |
| 214 __ And(at, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) | |
| 215 (1 << Map::kHasIndexedInterceptor))); |
| 216 __ Branch(slow, ne, at, Operand(zero_reg)); |
| 217 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex); |
| 218 __ Branch(slow, ne, elements, Operand(at)); |
| 219 __ Branch(&check_next_prototype); |
| 204 | 220 |
| 221 __ bind(&return_undefined); |
| 222 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); |
| 223 __ Branch(&done); |
| 224 |
| 225 __ bind(&in_bounds); |
| 205 // Fast case: Do the load. | 226 // Fast case: Do the load. |
| 206 __ Addu(scratch1, elements, | 227 __ Addu(scratch1, elements, |
| 207 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 228 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 208 // The key is a smi. | 229 // The key is a smi. |
| 209 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | 230 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
| 210 __ sll(at, key, kPointerSizeLog2 - kSmiTagSize); | 231 __ sll(at, key, kPointerSizeLog2 - kSmiTagSize); |
| 211 __ addu(at, at, scratch1); | 232 __ addu(at, at, scratch1); |
| 212 __ lw(scratch2, MemOperand(at)); | 233 __ lw(scratch2, MemOperand(at)); |
| 213 | 234 |
| 214 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 235 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 215 // In case the loaded value is the_hole we have to consult GetProperty | 236 // In case the loaded value is the_hole we have to check the prototype chain. |
| 216 // to ensure the prototype chain is searched. | 237 __ Branch(&check_prototypes, eq, scratch2, Operand(at)); |
| 217 __ Branch(out_of_range, eq, scratch2, Operand(at)); | 238 __ Move(result, scratch2); |
| 218 __ mov(result, scratch2); | 239 __ bind(&done); |
| 219 } | 240 } |
| 220 | 241 |
| 221 | 242 |
| 222 // Checks whether a key is an array index string or a unique name. | 243 // Checks whether a key is an array index string or a unique name. |
| 223 // Falls through if a key is a unique name. | 244 // Falls through if a key is a unique name. |
| 224 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, | 245 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, |
| 225 Register map, Register hash, | 246 Register map, Register hash, |
| 226 Label* index_string, Label* not_unique) { | 247 Label* index_string, Label* not_unique) { |
| 227 // The key is not a smi. | 248 // The key is not a smi. |
| 228 Label unique; | 249 Label unique; |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 __ bind(&index_smi); | 492 __ bind(&index_smi); |
| 472 // Now the key is known to be a smi. This place is also jumped to from below | 493 // Now the key is known to be a smi. This place is also jumped to from below |
| 473 // where a numeric string is converted to a smi. | 494 // where a numeric string is converted to a smi. |
| 474 | 495 |
| 475 GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3, | 496 GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3, |
| 476 Map::kHasIndexedInterceptor, &slow); | 497 Map::kHasIndexedInterceptor, &slow); |
| 477 | 498 |
| 478 // Check the receiver's map to see if it has fast elements. | 499 // Check the receiver's map to see if it has fast elements. |
| 479 __ CheckFastElements(a0, a3, &check_number_dictionary); | 500 __ CheckFastElements(a0, a3, &check_number_dictionary); |
| 480 | 501 |
| 481 GenerateFastArrayLoad(masm, receiver, key, a0, a3, t0, v0, NULL, &slow); | 502 GenerateFastArrayLoad(masm, receiver, key, a0, a3, t0, v0, &slow); |
| 482 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, t0, a3); | 503 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, t0, a3); |
| 483 __ Ret(); | 504 __ Ret(); |
| 484 | 505 |
| 485 __ bind(&check_number_dictionary); | 506 __ bind(&check_number_dictionary); |
| 486 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 507 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
| 487 __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset)); | 508 __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset)); |
| 488 | 509 |
| 489 // Check whether the elements is a number dictionary. | 510 // Check whether the elements is a number dictionary. |
| 490 // a3: elements map | 511 // a3: elements map |
| 491 // t0: elements | 512 // t0: elements |
| (...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1025 patcher.ChangeBranchCondition(ne); | 1046 patcher.ChangeBranchCondition(ne); |
| 1026 } else { | 1047 } else { |
| 1027 DCHECK(Assembler::IsBne(branch_instr)); | 1048 DCHECK(Assembler::IsBne(branch_instr)); |
| 1028 patcher.ChangeBranchCondition(eq); | 1049 patcher.ChangeBranchCondition(eq); |
| 1029 } | 1050 } |
| 1030 } | 1051 } |
| 1031 } | 1052 } |
| 1032 } // namespace v8::internal | 1053 } // namespace v8::internal |
| 1033 | 1054 |
| 1034 #endif // V8_TARGET_ARCH_MIPS | 1055 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |