OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 __ Ret(); | 416 __ Ret(); |
417 } | 417 } |
418 | 418 |
419 | 419 |
420 // Generate StoreField code, value is passed in r0 register. | 420 // Generate StoreField code, value is passed in r0 register. |
421 // When leaving generated code after success, the receiver_reg and name_reg | 421 // When leaving generated code after success, the receiver_reg and name_reg |
422 // may be clobbered. Upon branch to miss_label, the receiver and name | 422 // may be clobbered. Upon branch to miss_label, the receiver and name |
423 // registers have their original values. | 423 // registers have their original values. |
424 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 424 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
425 Handle<JSObject> object, | 425 Handle<JSObject> object, |
426 int index, | 426 LookupResult* lookup, |
427 Handle<Map> transition, | 427 Handle<Map> transition, |
428 Handle<Name> name, | 428 Handle<Name> name, |
429 Register receiver_reg, | 429 Register receiver_reg, |
430 Register name_reg, | 430 Register name_reg, |
431 Register value_reg, | 431 Register value_reg, |
432 Register scratch1, | 432 Register scratch1, |
433 Register scratch2, | 433 Register scratch2, |
434 Label* miss_label, | 434 Label* miss_label, |
435 Label* miss_restore_name) { | 435 Label* miss_restore_name) { |
436 // r0 : value | 436 // r0 : value |
437 Label exit; | 437 Label exit; |
438 | 438 |
439 LookupResult lookup(masm->isolate()); | |
440 object->Lookup(*name, &lookup); | |
441 if (lookup.IsFound() && (lookup.IsReadOnly() || !lookup.IsCacheable())) { | |
442 // In sloppy mode, we could just return the value and be done. However, we | |
443 // might be in strict mode, where we have to throw. Since we cannot tell, | |
444 // go into slow case unconditionally. | |
445 __ jmp(miss_label); | |
446 return; | |
447 } | |
448 | |
449 // Check that the map of the object hasn't changed. | 439 // Check that the map of the object hasn't changed. |
450 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | 440 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS |
451 : REQUIRE_EXACT_MAP; | 441 : REQUIRE_EXACT_MAP; |
452 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, | 442 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, |
453 DO_SMI_CHECK, mode); | 443 DO_SMI_CHECK, mode); |
454 | 444 |
455 // Perform global security token check if needed. | 445 // Perform global security token check if needed. |
456 if (object->IsJSGlobalProxy()) { | 446 if (object->IsJSGlobalProxy()) { |
457 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | 447 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); |
458 } | 448 } |
459 | 449 |
460 // Check that we are allowed to write this. | 450 // Check that we are allowed to write this. |
461 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { | 451 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { |
462 JSObject* holder; | 452 JSObject* holder; |
463 if (lookup.IsFound()) { | 453 // holder == object indicates that no property was found. |
464 holder = lookup.holder(); | 454 if (lookup->holder() != *object) { |
| 455 holder = lookup->holder(); |
465 } else { | 456 } else { |
466 // Find the top object. | 457 // Find the top object. |
467 holder = *object; | 458 holder = *object; |
468 do { | 459 do { |
469 holder = JSObject::cast(holder->GetPrototype()); | 460 holder = JSObject::cast(holder->GetPrototype()); |
470 } while (holder->GetPrototype()->IsJSObject()); | 461 } while (holder->GetPrototype()->IsJSObject()); |
471 } | 462 } |
472 CheckPrototypes(object, receiver_reg, Handle<JSObject>(holder), name_reg, | 463 Register holder_reg = CheckPrototypes( |
473 scratch1, scratch2, name, miss_restore_name); | 464 object, receiver_reg, Handle<JSObject>(holder), name_reg, |
| 465 scratch1, scratch2, name, miss_restore_name); |
| 466 // If no property was found, and the holder (the last object in the |
| 467 // prototype chain) is in slow mode, we need to do a negative lookup on the |
| 468 // holder. |
| 469 if (lookup->holder() == *object && |
| 470 !holder->HasFastProperties() && |
| 471 !holder->IsJSGlobalProxy() && |
| 472 !holder->IsJSGlobalObject()) { |
| 473 GenerateDictionaryNegativeLookup( |
| 474 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); |
| 475 } |
474 } | 476 } |
475 | 477 |
476 // Stub never generated for non-global objects that require access | 478 // Stub never generated for non-global objects that require access |
477 // checks. | 479 // checks. |
478 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 480 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
479 | 481 |
480 // Perform map transition for the receiver if necessary. | 482 // Perform map transition for the receiver if necessary. |
481 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 483 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { |
482 // The properties must be extended before we can store the value. | 484 // The properties must be extended before we can store the value. |
483 // We jump to a runtime call that extends the properties array. | 485 // We jump to a runtime call that extends the properties array. |
484 __ push(receiver_reg); | 486 __ push(receiver_reg); |
485 __ mov(r2, Operand(transition)); | 487 __ mov(r2, Operand(transition)); |
486 __ Push(r2, r0); | 488 __ Push(r2, r0); |
487 __ TailCallExternalReference( | 489 __ TailCallExternalReference( |
488 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 490 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
489 masm->isolate()), | 491 masm->isolate()), |
490 3, | 492 3, |
491 1); | 493 1); |
492 return; | 494 return; |
493 } | 495 } |
494 | 496 |
| 497 int index; |
495 if (!transition.is_null()) { | 498 if (!transition.is_null()) { |
496 // Update the map of the object. | 499 // Update the map of the object. |
497 __ mov(scratch1, Operand(transition)); | 500 __ mov(scratch1, Operand(transition)); |
498 __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | 501 __ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
499 | 502 |
500 // Update the write barrier for the map field and pass the now unused | 503 // Update the write barrier for the map field and pass the now unused |
501 // name_reg as scratch register. | 504 // name_reg as scratch register. |
502 __ RecordWriteField(receiver_reg, | 505 __ RecordWriteField(receiver_reg, |
503 HeapObject::kMapOffset, | 506 HeapObject::kMapOffset, |
504 scratch1, | 507 scratch1, |
505 name_reg, | 508 name_reg, |
506 kLRHasNotBeenSaved, | 509 kLRHasNotBeenSaved, |
507 kDontSaveFPRegs, | 510 kDontSaveFPRegs, |
508 OMIT_REMEMBERED_SET, | 511 OMIT_REMEMBERED_SET, |
509 OMIT_SMI_CHECK); | 512 OMIT_SMI_CHECK); |
| 513 index = transition->instance_descriptors()->GetFieldIndex( |
| 514 transition->LastAdded()); |
| 515 } else { |
| 516 index = lookup->GetFieldIndex().field_index(); |
510 } | 517 } |
511 | 518 |
512 // Adjust for the number of properties stored in the object. Even in the | 519 // Adjust for the number of properties stored in the object. Even in the |
513 // face of a transition we can use the old map here because the size of the | 520 // face of a transition we can use the old map here because the size of the |
514 // object and the number of in-object properties is not going to change. | 521 // object and the number of in-object properties is not going to change. |
515 index -= object->map()->inobject_properties(); | 522 index -= object->map()->inobject_properties(); |
516 | 523 |
517 if (index < 0) { | 524 if (index < 0) { |
518 // Set the property straight into the object. | 525 // Set the property straight into the object. |
519 int offset = object->map()->instance_size() + (index * kPointerSize); | 526 int offset = object->map()->instance_size() + (index * kPointerSize); |
(...skipping 3322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3842 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | 3849 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
3843 } | 3850 } |
3844 } | 3851 } |
3845 | 3852 |
3846 | 3853 |
3847 #undef __ | 3854 #undef __ |
3848 | 3855 |
3849 } } // namespace v8::internal | 3856 } } // namespace v8::internal |
3850 | 3857 |
3851 #endif // V8_TARGET_ARCH_ARM | 3858 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |