OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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_PPC | 7 #if V8_TARGET_ARCH_PPC |
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 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 // we enter the runtime system to make sure that indexing into string | 157 // we enter the runtime system to make sure that indexing into string |
158 // objects work as intended. | 158 // objects work as intended. |
159 DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 159 DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
160 __ lbz(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 160 __ lbz(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
161 __ cmpi(scratch, Operand(JS_OBJECT_TYPE)); | 161 __ cmpi(scratch, Operand(JS_OBJECT_TYPE)); |
162 __ blt(slow); | 162 __ blt(slow); |
163 } | 163 } |
164 | 164 |
165 | 165 |
166 // Loads an indexed element from a fast case array. | 166 // Loads an indexed element from a fast case array. |
167 // If not_fast_array is NULL, doesn't perform the elements map check. | |
168 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, | 167 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, |
169 Register key, Register elements, | 168 Register key, Register elements, |
170 Register scratch1, Register scratch2, | 169 Register scratch1, Register scratch2, |
171 Register result, Label* not_fast_array, | 170 Register result, Label* slow) { |
172 Label* out_of_range) { | |
173 // Register use: | 171 // Register use: |
174 // | 172 // |
175 // receiver - holds the receiver on entry. | 173 // receiver - holds the receiver on entry. |
176 // Unchanged unless 'result' is the same register. | 174 // Unchanged unless 'result' is the same register. |
177 // | 175 // |
178 // key - holds the smi key on entry. | 176 // key - holds the smi key on entry. |
179 // Unchanged unless 'result' is the same register. | 177 // Unchanged unless 'result' is the same register. |
180 // | 178 // |
181 // elements - holds the elements of the receiver on exit. | |
182 // | |
183 // result - holds the result on exit if the load succeeded. | 179 // result - holds the result on exit if the load succeeded. |
184 // Allowed to be the the same as 'receiver' or 'key'. | 180 // Allowed to be the the same as 'receiver' or 'key'. |
185 // Unchanged on bailout so 'receiver' and 'key' can be safely | 181 // Unchanged on bailout so 'receiver' and 'key' can be safely |
186 // used by further computation. | 182 // used by further computation. |
187 // | 183 // |
188 // Scratch registers: | 184 // Scratch registers: |
189 // | 185 // |
190 // scratch1 - used to hold elements map and elements length. | 186 // elements - holds the elements of the receiver and its protoypes. |
191 // Holds the elements map if not_fast_array branch is taken. | |
192 // | 187 // |
193 // scratch2 - used to hold the loaded value. | 188 // scratch1 - used to hold elements length, bit fields, base addresses. |
| 189 // |
| 190 // scratch2 - used to hold maps, prototypes, and the loaded value. |
| 191 Label check_prototypes, check_next_prototype; |
| 192 Label done, in_bounds, return_undefined; |
194 | 193 |
195 __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 194 __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
196 if (not_fast_array != NULL) { | 195 __ AssertFastElements(elements); |
197 // Check that the object is in fast mode and writable. | 196 |
198 __ LoadP(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset)); | |
199 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | |
200 __ cmp(scratch1, ip); | |
201 __ bne(not_fast_array); | |
202 } else { | |
203 __ AssertFastElements(elements); | |
204 } | |
205 // Check that the key (index) is within bounds. | 197 // Check that the key (index) is within bounds. |
206 __ LoadP(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); | 198 __ LoadP(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
207 __ cmpl(key, scratch1); | 199 __ cmpl(key, scratch1); |
208 __ bge(out_of_range); | 200 __ blt(&in_bounds); |
| 201 // Out-of-bounds. Check the prototype chain to see if we can just return |
| 202 // 'undefined'. |
| 203 __ cmpi(key, Operand::Zero()); |
| 204 __ blt(slow); // Negative keys can't take the fast OOB path. |
| 205 __ bind(&check_prototypes); |
| 206 __ LoadP(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 207 __ bind(&check_next_prototype); |
| 208 __ LoadP(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); |
| 209 // scratch2: current prototype |
| 210 __ CompareRoot(scratch2, Heap::kNullValueRootIndex); |
| 211 __ beq(&return_undefined); |
| 212 __ LoadP(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); |
| 213 __ LoadP(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); |
| 214 // elements: elements of current prototype |
| 215 // scratch2: map of current prototype |
| 216 __ CompareInstanceType(scratch2, scratch1, JS_OBJECT_TYPE); |
| 217 __ blt(slow); |
| 218 __ lbz(scratch1, FieldMemOperand(scratch2, Map::kBitFieldOffset)); |
| 219 __ andi(r0, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) | |
| 220 (1 << Map::kHasIndexedInterceptor))); |
| 221 __ bne(slow, cr0); |
| 222 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); |
| 223 __ bne(slow); |
| 224 __ jmp(&check_next_prototype); |
| 225 |
| 226 __ bind(&return_undefined); |
| 227 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); |
| 228 __ jmp(&done); |
| 229 |
| 230 __ bind(&in_bounds); |
209 // Fast case: Do the load. | 231 // Fast case: Do the load. |
210 __ addi(scratch1, elements, | 232 __ addi(scratch1, elements, |
211 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 233 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
212 // The key is a smi. | 234 // The key is a smi. |
213 __ SmiToPtrArrayOffset(scratch2, key); | 235 __ SmiToPtrArrayOffset(scratch2, key); |
214 __ LoadPX(scratch2, MemOperand(scratch2, scratch1)); | 236 __ LoadPX(scratch2, MemOperand(scratch2, scratch1)); |
215 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 237 __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex); |
216 __ cmp(scratch2, ip); | 238 // In case the loaded value is the_hole we have to check the prototype chain. |
217 // In case the loaded value is the_hole we have to consult GetProperty | 239 __ beq(&check_prototypes); |
218 // to ensure the prototype chain is searched. | |
219 __ beq(out_of_range); | |
220 __ mr(result, scratch2); | 240 __ mr(result, scratch2); |
| 241 __ bind(&done); |
221 } | 242 } |
222 | 243 |
223 | 244 |
224 // Checks whether a key is an array index string or a unique name. | 245 // Checks whether a key is an array index string or a unique name. |
225 // Falls through if a key is a unique name. | 246 // Falls through if a key is a unique name. |
226 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, | 247 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, |
227 Register map, Register hash, | 248 Register map, Register hash, |
228 Label* index_string, Label* not_unique) { | 249 Label* index_string, Label* not_unique) { |
229 // The key is not a smi. | 250 // The key is not a smi. |
230 Label unique; | 251 Label unique; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
268 // Dictionary load failed, go slow (but don't miss). | 289 // Dictionary load failed, go slow (but don't miss). |
269 __ bind(&slow); | 290 __ bind(&slow); |
270 GenerateRuntimeGetProperty(masm); | 291 GenerateRuntimeGetProperty(masm); |
271 } | 292 } |
272 | 293 |
273 | 294 |
274 // A register that isn't one of the parameters to the load ic. | 295 // A register that isn't one of the parameters to the load ic. |
275 static const Register LoadIC_TempRegister() { return r6; } | 296 static const Register LoadIC_TempRegister() { return r6; } |
276 | 297 |
277 | 298 |
| 299 static void LoadIC_PushArgs(MacroAssembler* masm) { |
| 300 Register receiver = LoadDescriptor::ReceiverRegister(); |
| 301 Register name = LoadDescriptor::NameRegister(); |
| 302 if (FLAG_vector_ics) { |
| 303 Register slot = VectorLoadICDescriptor::SlotRegister(); |
| 304 Register vector = VectorLoadICDescriptor::VectorRegister(); |
| 305 |
| 306 __ Push(receiver, name, slot, vector); |
| 307 } else { |
| 308 __ Push(receiver, name); |
| 309 } |
| 310 } |
| 311 |
| 312 |
278 void LoadIC::GenerateMiss(MacroAssembler* masm) { | 313 void LoadIC::GenerateMiss(MacroAssembler* masm) { |
279 // The return address is in lr. | 314 // The return address is in lr. |
280 Isolate* isolate = masm->isolate(); | 315 Isolate* isolate = masm->isolate(); |
281 | 316 |
282 __ IncrementCounter(isolate->counters()->load_miss(), 1, r6, r7); | 317 DCHECK(!FLAG_vector_ics || |
| 318 !AreAliased(r7, r8, VectorLoadICDescriptor::SlotRegister(), |
| 319 VectorLoadICDescriptor::VectorRegister())); |
| 320 __ IncrementCounter(isolate->counters()->load_miss(), 1, r7, r8); |
283 | 321 |
284 __ mr(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister()); | 322 LoadIC_PushArgs(masm); |
285 __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister()); | |
286 | 323 |
287 // Perform tail call to the entry. | 324 // Perform tail call to the entry. |
288 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate); | 325 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate); |
289 __ TailCallExternalReference(ref, 2, 1); | 326 int arg_count = FLAG_vector_ics ? 4 : 2; |
| 327 __ TailCallExternalReference(ref, arg_count, 1); |
290 } | 328 } |
291 | 329 |
292 | 330 |
293 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 331 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
294 // The return address is in lr. | 332 // The return address is in lr. |
295 | 333 |
296 __ mr(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister()); | 334 __ mr(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister()); |
297 __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister()); | 335 __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister()); |
298 | 336 |
299 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); | 337 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 __ Ret(); | 446 __ Ret(); |
409 __ bind(&slow); | 447 __ bind(&slow); |
410 GenerateMiss(masm); | 448 GenerateMiss(masm); |
411 } | 449 } |
412 | 450 |
413 | 451 |
414 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { | 452 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { |
415 // The return address is in lr. | 453 // The return address is in lr. |
416 Isolate* isolate = masm->isolate(); | 454 Isolate* isolate = masm->isolate(); |
417 | 455 |
418 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r6, r7); | 456 DCHECK(!FLAG_vector_ics || |
| 457 !AreAliased(r7, r8, VectorLoadICDescriptor::SlotRegister(), |
| 458 VectorLoadICDescriptor::VectorRegister())); |
| 459 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r7, r8); |
419 | 460 |
420 __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); | 461 LoadIC_PushArgs(masm); |
421 | 462 |
422 // Perform tail call to the entry. | 463 // Perform tail call to the entry. |
423 ExternalReference ref = | 464 ExternalReference ref = |
424 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate); | 465 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate); |
425 | 466 int arg_count = FLAG_vector_ics ? 4 : 2; |
426 __ TailCallExternalReference(ref, 2, 1); | 467 __ TailCallExternalReference(ref, arg_count, 1); |
427 } | 468 } |
428 | 469 |
429 | 470 |
430 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 471 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
431 // The return address is in lr. | 472 // The return address is in lr. |
432 | 473 |
433 __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); | 474 __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); |
434 | 475 |
435 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 476 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
436 } | 477 } |
437 | 478 |
438 | 479 |
439 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 480 void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { |
440 // The return address is in lr. | 481 // The return address is in lr. |
441 Label slow, check_name, index_smi, index_name, property_array_property; | 482 Label slow, check_name, index_smi, index_name, property_array_property; |
442 Label probe_dictionary, check_number_dictionary; | 483 Label probe_dictionary, check_number_dictionary; |
443 | 484 |
444 Register key = LoadDescriptor::NameRegister(); | 485 Register key = LoadDescriptor::NameRegister(); |
445 Register receiver = LoadDescriptor::ReceiverRegister(); | 486 Register receiver = LoadDescriptor::ReceiverRegister(); |
446 DCHECK(key.is(r5)); | 487 DCHECK(key.is(r5)); |
447 DCHECK(receiver.is(r4)); | 488 DCHECK(receiver.is(r4)); |
448 | 489 |
449 Isolate* isolate = masm->isolate(); | 490 Isolate* isolate = masm->isolate(); |
450 | 491 |
451 // Check that the key is a smi. | 492 // Check that the key is a smi. |
452 __ JumpIfNotSmi(key, &check_name); | 493 __ JumpIfNotSmi(key, &check_name); |
453 __ bind(&index_smi); | 494 __ bind(&index_smi); |
454 // Now the key is known to be a smi. This place is also jumped to from below | 495 // Now the key is known to be a smi. This place is also jumped to from below |
455 // where a numeric string is converted to a smi. | 496 // where a numeric string is converted to a smi. |
456 | 497 |
457 GenerateKeyedLoadReceiverCheck(masm, receiver, r3, r6, | 498 GenerateKeyedLoadReceiverCheck(masm, receiver, r3, r6, |
458 Map::kHasIndexedInterceptor, &slow); | 499 Map::kHasIndexedInterceptor, &slow); |
459 | 500 |
460 // Check the receiver's map to see if it has fast elements. | 501 // Check the receiver's map to see if it has fast elements. |
461 __ CheckFastElements(r3, r6, &check_number_dictionary); | 502 __ CheckFastElements(r3, r6, &check_number_dictionary); |
462 | 503 |
463 GenerateFastArrayLoad(masm, receiver, key, r3, r6, r7, r3, NULL, &slow); | 504 GenerateFastArrayLoad(masm, receiver, key, r3, r6, r7, r3, &slow); |
464 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r7, r6); | 505 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r7, r6); |
465 __ Ret(); | 506 __ Ret(); |
466 | 507 |
467 __ bind(&check_number_dictionary); | 508 __ bind(&check_number_dictionary); |
468 __ LoadP(r7, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 509 __ LoadP(r7, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
469 __ LoadP(r6, FieldMemOperand(r7, JSObject::kMapOffset)); | 510 __ LoadP(r6, FieldMemOperand(r7, JSObject::kMapOffset)); |
470 | 511 |
471 // Check whether the elements is a number dictionary. | 512 // Check whether the elements is a number dictionary. |
472 // r6: elements map | 513 // r6: elements map |
473 // r7: elements | 514 // r7: elements |
474 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 515 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
475 __ cmp(r6, ip); | 516 __ cmp(r6, ip); |
476 __ bne(&slow); | 517 __ bne(&slow); |
477 __ SmiUntag(r3, key); | 518 __ SmiUntag(r3, key); |
478 __ LoadFromNumberDictionary(&slow, r7, key, r3, r3, r6, r8); | 519 __ LoadFromNumberDictionary(&slow, r7, key, r3, r3, r6, r8); |
479 __ Ret(); | 520 __ Ret(); |
480 | 521 |
481 // Slow case, key and receiver still in r3 and r4. | 522 // Slow case, key and receiver still in r3 and r4. |
482 __ bind(&slow); | 523 __ bind(&slow); |
483 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, r7, | 524 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, r7, |
484 r6); | 525 r6); |
485 GenerateRuntimeGetProperty(masm); | 526 GenerateRuntimeGetProperty(masm); |
486 | 527 |
487 __ bind(&check_name); | 528 __ bind(&check_name); |
488 GenerateKeyNameCheck(masm, key, r3, r6, &index_name, &slow); | 529 GenerateKeyNameCheck(masm, key, r3, r6, &index_name, &slow); |
489 | 530 |
490 GenerateKeyedLoadReceiverCheck(masm, receiver, r3, r6, | 531 GenerateKeyedLoadReceiverCheck(masm, receiver, r3, r6, |
491 Map::kHasNamedInterceptor, &slow); | 532 Map::kHasNamedInterceptor, &slow); |
492 | 533 |
493 // If the receiver is a fast-case object, check the keyed lookup | 534 // If the receiver is a fast-case object, check the stub cache. Otherwise |
494 // cache. Otherwise probe the dictionary. | 535 // probe the dictionary. |
495 __ LoadP(r6, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 536 __ LoadP(r6, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
496 __ LoadP(r7, FieldMemOperand(r6, HeapObject::kMapOffset)); | 537 __ LoadP(r7, FieldMemOperand(r6, HeapObject::kMapOffset)); |
497 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 538 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
498 __ cmp(r7, ip); | 539 __ cmp(r7, ip); |
499 __ beq(&probe_dictionary); | 540 __ beq(&probe_dictionary); |
500 | 541 |
501 // Load the map of the receiver, compute the keyed lookup cache hash | |
502 // based on 32 bits of the map pointer and the name hash. | |
503 __ LoadP(r3, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
504 __ srawi(r6, r3, KeyedLookupCache::kMapHashShift); | |
505 __ lwz(r7, FieldMemOperand(key, Name::kHashFieldOffset)); | |
506 __ srawi(r7, r7, Name::kHashShift); | |
507 __ xor_(r6, r6, r7); | |
508 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask; | |
509 __ mov(r7, Operand(mask)); | |
510 __ and_(r6, r6, r7, LeaveRC); | |
511 | 542 |
512 // Load the key (consisting of map and unique name) from the cache and | 543 if (FLAG_vector_ics) { |
513 // check for match. | 544 // When vector ics are in use, the handlers in the stub cache expect a |
514 Label load_in_object_property; | 545 // vector and slot. Since we won't change the IC from any downstream |
515 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket; | 546 // misses, a dummy vector can be used. |
516 Label hit_on_nth_entry[kEntriesPerBucket]; | 547 Register vector = VectorLoadICDescriptor::VectorRegister(); |
517 ExternalReference cache_keys = | 548 Register slot = VectorLoadICDescriptor::SlotRegister(); |
518 ExternalReference::keyed_lookup_cache_keys(isolate); | 549 DCHECK(!AreAliased(vector, slot, r7, r8, r9, r10)); |
519 | 550 Handle<TypeFeedbackVector> dummy_vector = Handle<TypeFeedbackVector>::cast( |
520 __ mov(r7, Operand(cache_keys)); | 551 masm->isolate()->factory()->keyed_load_dummy_vector()); |
521 __ mr(r0, r5); | 552 int int_slot = dummy_vector->GetIndex(FeedbackVectorICSlot(0)); |
522 __ ShiftLeftImm(r5, r6, Operand(kPointerSizeLog2 + 1)); | 553 __ LoadRoot(vector, Heap::kKeyedLoadDummyVectorRootIndex); |
523 __ add(r7, r7, r5); | 554 __ LoadSmiLiteral(slot, Smi::FromInt(int_slot)); |
524 __ mr(r5, r0); | |
525 | |
526 for (int i = 0; i < kEntriesPerBucket - 1; i++) { | |
527 Label try_next_entry; | |
528 // Load map and move r7 to next entry. | |
529 __ LoadP(r8, MemOperand(r7)); | |
530 __ addi(r7, r7, Operand(kPointerSize * 2)); | |
531 __ cmp(r3, r8); | |
532 __ bne(&try_next_entry); | |
533 __ LoadP(r8, MemOperand(r7, -kPointerSize)); // Load name | |
534 __ cmp(key, r8); | |
535 __ beq(&hit_on_nth_entry[i]); | |
536 __ bind(&try_next_entry); | |
537 } | 555 } |
538 | 556 |
539 // Last entry: Load map and move r7 to name. | 557 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( |
540 __ LoadP(r8, MemOperand(r7)); | 558 Code::ComputeHandlerFlags(Code::LOAD_IC)); |
541 __ addi(r7, r7, Operand(kPointerSize)); | 559 masm->isolate()->stub_cache()->GenerateProbe( |
542 __ cmp(r3, r8); | 560 masm, Code::KEYED_LOAD_IC, flags, false, receiver, key, r7, r8, r9, r10); |
543 __ bne(&slow); | 561 // Cache miss. |
544 __ LoadP(r8, MemOperand(r7)); | 562 GenerateMiss(masm); |
545 __ cmp(key, r8); | |
546 __ bne(&slow); | |
547 | |
548 // Get field offset. | |
549 // r3 : receiver's map | |
550 // r6 : lookup cache index | |
551 ExternalReference cache_field_offsets = | |
552 ExternalReference::keyed_lookup_cache_field_offsets(isolate); | |
553 | |
554 // Hit on nth entry. | |
555 for (int i = kEntriesPerBucket - 1; i >= 0; i--) { | |
556 __ bind(&hit_on_nth_entry[i]); | |
557 __ mov(r7, Operand(cache_field_offsets)); | |
558 if (i != 0) { | |
559 __ addi(r6, r6, Operand(i)); | |
560 } | |
561 __ ShiftLeftImm(r8, r6, Operand(2)); | |
562 __ lwzx(r8, MemOperand(r8, r7)); | |
563 __ lbz(r9, FieldMemOperand(r3, Map::kInObjectPropertiesOffset)); | |
564 __ sub(r8, r8, r9); | |
565 __ cmpi(r8, Operand::Zero()); | |
566 __ bge(&property_array_property); | |
567 if (i != 0) { | |
568 __ b(&load_in_object_property); | |
569 } | |
570 } | |
571 | |
572 // Load in-object property. | |
573 __ bind(&load_in_object_property); | |
574 __ lbz(r9, FieldMemOperand(r3, Map::kInstanceSizeOffset)); | |
575 __ add(r9, r9, r8); // Index from start of object. | |
576 __ subi(receiver, receiver, Operand(kHeapObjectTag)); // Remove the heap tag. | |
577 __ ShiftLeftImm(r3, r9, Operand(kPointerSizeLog2)); | |
578 __ LoadPX(r3, MemOperand(r3, receiver)); | |
579 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1, | |
580 r7, r6); | |
581 __ Ret(); | |
582 | |
583 // Load property array property. | |
584 __ bind(&property_array_property); | |
585 __ LoadP(receiver, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | |
586 __ addi(receiver, receiver, | |
587 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
588 __ ShiftLeftImm(r3, r8, Operand(kPointerSizeLog2)); | |
589 __ LoadPX(r3, MemOperand(r3, receiver)); | |
590 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(), 1, | |
591 r7, r6); | |
592 __ Ret(); | |
593 | 563 |
594 // Do a quick inline probe of the receiver's dictionary, if it | 564 // Do a quick inline probe of the receiver's dictionary, if it |
595 // exists. | 565 // exists. |
596 __ bind(&probe_dictionary); | 566 __ bind(&probe_dictionary); |
597 // r6: elements | 567 // r6: elements |
598 __ LoadP(r3, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 568 __ LoadP(r3, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
599 __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); | 569 __ lbz(r3, FieldMemOperand(r3, Map::kInstanceTypeOffset)); |
600 GenerateGlobalInstanceTypeCheck(masm, r3, &slow); | 570 GenerateGlobalInstanceTypeCheck(masm, r3, &slow); |
601 // Load the property to r3. | 571 // Load the property to r3. |
602 GenerateDictionaryLoad(masm, &slow, r6, key, r3, r8, r7); | 572 GenerateDictionaryLoad(masm, &slow, r6, key, r3, r8, r7); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 receiver_map, r7, slow); | 733 receiver_map, r7, slow); |
764 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); | 734 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS); |
765 ElementsTransitionGenerator::GenerateDoubleToObject( | 735 ElementsTransitionGenerator::GenerateDoubleToObject( |
766 masm, receiver, key, value, receiver_map, mode, slow); | 736 masm, receiver, key, value, receiver_map, mode, slow); |
767 __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 737 __ LoadP(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
768 __ b(&finish_object_store); | 738 __ b(&finish_object_store); |
769 } | 739 } |
770 | 740 |
771 | 741 |
772 void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm, | 742 void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm, |
773 StrictMode strict_mode) { | 743 LanguageMode language_mode) { |
774 // ---------- S t a t e -------------- | 744 // ---------- S t a t e -------------- |
775 // -- r3 : value | 745 // -- r3 : value |
776 // -- r4 : key | 746 // -- r4 : key |
777 // -- r5 : receiver | 747 // -- r5 : receiver |
778 // -- lr : return address | 748 // -- lr : return address |
779 // ----------------------------------- | 749 // ----------------------------------- |
780 Label slow, fast_object, fast_object_grow; | 750 Label slow, fast_object, fast_object_grow; |
781 Label fast_double, fast_double_grow; | 751 Label fast_double, fast_double_grow; |
782 Label array, extra, check_if_double_array, maybe_name_key, miss; | 752 Label array, extra, check_if_double_array, maybe_name_key, miss; |
783 | 753 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
819 __ LoadP(ip, FieldMemOperand(elements, FixedArray::kLengthOffset)); | 789 __ LoadP(ip, FieldMemOperand(elements, FixedArray::kLengthOffset)); |
820 __ cmpl(key, ip); | 790 __ cmpl(key, ip); |
821 __ blt(&fast_object); | 791 __ blt(&fast_object); |
822 | 792 |
823 // Slow case, handle jump to runtime. | 793 // Slow case, handle jump to runtime. |
824 __ bind(&slow); | 794 __ bind(&slow); |
825 // Entry registers are intact. | 795 // Entry registers are intact. |
826 // r3: value. | 796 // r3: value. |
827 // r4: key. | 797 // r4: key. |
828 // r5: receiver. | 798 // r5: receiver. |
829 PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode); | 799 PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode); |
830 // Never returns to here. | 800 // Never returns to here. |
831 | 801 |
832 __ bind(&maybe_name_key); | 802 __ bind(&maybe_name_key); |
833 __ LoadP(r7, FieldMemOperand(key, HeapObject::kMapOffset)); | 803 __ LoadP(r7, FieldMemOperand(key, HeapObject::kMapOffset)); |
834 __ lbz(r7, FieldMemOperand(r7, Map::kInstanceTypeOffset)); | 804 __ lbz(r7, FieldMemOperand(r7, Map::kInstanceTypeOffset)); |
835 __ JumpIfNotUniqueNameInstanceType(r7, &slow); | 805 __ JumpIfNotUniqueNameInstanceType(r7, &slow); |
836 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( | 806 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( |
837 Code::ComputeHandlerFlags(Code::STORE_IC)); | 807 Code::ComputeHandlerFlags(Code::STORE_IC)); |
838 masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver, | 808 masm->isolate()->stub_cache()->GenerateProbe( |
839 key, r6, r7, r8, r9); | 809 masm, Code::STORE_IC, flags, false, receiver, key, r6, r7, r8, r9); |
840 // Cache miss. | 810 // Cache miss. |
841 __ b(&miss); | 811 __ b(&miss); |
842 | 812 |
843 // Extra capacity case: Check if there is extra capacity to | 813 // Extra capacity case: Check if there is extra capacity to |
844 // perform the store and update the length. Used for adding one | 814 // perform the store and update the length. Used for adding one |
845 // element to the array by writing to array[array.length]. | 815 // element to the array by writing to array[array.length]. |
846 __ bind(&extra); | 816 __ bind(&extra); |
847 // Condition code from comparing key and array length is still available. | 817 // Condition code from comparing key and array length is still available. |
848 __ bne(&slow); // Only support writing to writing to array[array.length]. | 818 __ bne(&slow); // Only support writing to writing to array[array.length]. |
849 // Check for room in the elements backing store. | 819 // Check for room in the elements backing store. |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
890 Register receiver = StoreDescriptor::ReceiverRegister(); | 860 Register receiver = StoreDescriptor::ReceiverRegister(); |
891 Register name = StoreDescriptor::NameRegister(); | 861 Register name = StoreDescriptor::NameRegister(); |
892 DCHECK(receiver.is(r4)); | 862 DCHECK(receiver.is(r4)); |
893 DCHECK(name.is(r5)); | 863 DCHECK(name.is(r5)); |
894 DCHECK(StoreDescriptor::ValueRegister().is(r3)); | 864 DCHECK(StoreDescriptor::ValueRegister().is(r3)); |
895 | 865 |
896 // Get the receiver from the stack and probe the stub cache. | 866 // Get the receiver from the stack and probe the stub cache. |
897 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( | 867 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags( |
898 Code::ComputeHandlerFlags(Code::STORE_IC)); | 868 Code::ComputeHandlerFlags(Code::STORE_IC)); |
899 | 869 |
900 masm->isolate()->stub_cache()->GenerateProbe(masm, flags, false, receiver, | 870 masm->isolate()->stub_cache()->GenerateProbe( |
901 name, r6, r7, r8, r9); | 871 masm, Code::STORE_IC, flags, false, receiver, name, r6, r7, r8, r9); |
902 | 872 |
903 // Cache miss: Jump to runtime. | 873 // Cache miss: Jump to runtime. |
904 GenerateMiss(masm); | 874 GenerateMiss(masm); |
905 } | 875 } |
906 | 876 |
907 | 877 |
908 void StoreIC::GenerateMiss(MacroAssembler* masm) { | 878 void StoreIC::GenerateMiss(MacroAssembler* masm) { |
909 __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(), | 879 __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(), |
910 StoreDescriptor::ValueRegister()); | 880 StoreDescriptor::ValueRegister()); |
911 | 881 |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1038 patcher.EmitCondition(ne); | 1008 patcher.EmitCondition(ne); |
1039 } else { | 1009 } else { |
1040 DCHECK(Assembler::GetCondition(branch_instr) == ne); | 1010 DCHECK(Assembler::GetCondition(branch_instr) == ne); |
1041 patcher.EmitCondition(eq); | 1011 patcher.EmitCondition(eq); |
1042 } | 1012 } |
1043 } | 1013 } |
1044 } | 1014 } |
1045 } // namespace v8::internal | 1015 } // namespace v8::internal |
1046 | 1016 |
1047 #endif // V8_TARGET_ARCH_PPC | 1017 #endif // V8_TARGET_ARCH_PPC |
OLD | NEW |