| 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 |