Chromium Code Reviews| 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 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 GlobalObject::EnsurePropertyCell(global, name); | 422 GlobalObject::EnsurePropertyCell(global, name); |
| 423 ASSERT(cell->value()->IsTheHole()); | 423 ASSERT(cell->value()->IsTheHole()); |
| 424 __ li(scratch, Operand(cell)); | 424 __ li(scratch, Operand(cell)); |
| 425 __ lw(scratch, | 425 __ lw(scratch, |
| 426 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); | 426 FieldMemOperand(scratch, JSGlobalPropertyCell::kValueOffset)); |
| 427 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 427 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 428 __ Branch(miss, ne, scratch, Operand(at)); | 428 __ Branch(miss, ne, scratch, Operand(at)); |
| 429 } | 429 } |
| 430 | 430 |
| 431 | 431 |
| 432 // Generate StoreField code, value is passed in a0 register. | 432 // Generate StoreTransition code, value is passed in a0 register. |
| 433 // After executing generated code, the receiver_reg and name_reg | 433 // After executing generated code, the receiver_reg and name_reg |
| 434 // may be clobbered. | 434 // may be clobbered. |
| 435 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 435 void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, |
| 436 Handle<JSObject> object, | 436 Handle<JSObject> object, |
| 437 LookupResult* lookup, | 437 LookupResult* lookup, |
| 438 Handle<Map> transition, | 438 Handle<Map> transition, |
| 439 Handle<Name> name, | 439 Handle<Name> name, |
| 440 Register receiver_reg, | 440 Register receiver_reg, |
| 441 Register name_reg, | 441 Register name_reg, |
| 442 Register value_reg, | 442 Register value_reg, |
| 443 Register scratch1, | 443 Register scratch1, |
| 444 Register scratch2, | 444 Register scratch2, |
| 445 Label* miss_label, | 445 Label* miss_label, |
| 446 Label* miss_restore_name) { | 446 Label* miss_restore_name) { |
| 447 // a0 : value. | 447 // a0 : value. |
| 448 Label exit; | 448 Label exit; |
| 449 | 449 |
| 450 // Check that the map of the object hasn't changed. | 450 // Check that the map of the object hasn't changed. |
| 451 CompareMapMode mode = transition.is_null() ? ALLOW_ELEMENT_TRANSITION_MAPS | |
| 452 : REQUIRE_EXACT_MAP; | |
| 453 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, | 451 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, |
| 454 DO_SMI_CHECK, mode); | 452 DO_SMI_CHECK, REQUIRE_EXACT_MAP); |
| 455 | 453 |
| 456 // Perform global security token check if needed. | 454 // Perform global security token check if needed. |
| 457 if (object->IsJSGlobalProxy()) { | 455 if (object->IsJSGlobalProxy()) { |
| 458 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | 456 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); |
| 459 } | 457 } |
| 460 | 458 |
| 461 // Check that we are allowed to write this. | 459 // Check that we are allowed to write this. |
| 462 if (!transition.is_null() && object->GetPrototype()->IsJSObject()) { | 460 if (object->GetPrototype()->IsJSObject()) { |
| 463 JSObject* holder; | 461 JSObject* holder; |
| 464 // holder == object indicates that no property was found. | 462 // holder == object indicates that no property was found. |
| 465 if (lookup->holder() != *object) { | 463 if (lookup->holder() != *object) { |
| 466 holder = lookup->holder(); | 464 holder = lookup->holder(); |
| 467 } else { | 465 } else { |
| 468 // Find the top object. | 466 // Find the top object. |
| 469 holder = *object; | 467 holder = *object; |
| 470 do { | 468 do { |
| 471 holder = JSObject::cast(holder->GetPrototype()); | 469 holder = JSObject::cast(holder->GetPrototype()); |
| 472 } while (holder->GetPrototype()->IsJSObject()); | 470 } while (holder->GetPrototype()->IsJSObject()); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 490 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); | 488 masm, miss_restore_name, holder_reg, name, scratch1, scratch2); |
| 491 } | 489 } |
| 492 } | 490 } |
| 493 } | 491 } |
| 494 | 492 |
| 495 // Stub never generated for non-global objects that require access | 493 // Stub never generated for non-global objects that require access |
| 496 // checks. | 494 // checks. |
| 497 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 495 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 498 | 496 |
| 499 // Perform map transition for the receiver if necessary. | 497 // Perform map transition for the receiver if necessary. |
| 500 if (!transition.is_null() && (object->map()->unused_property_fields() == 0)) { | 498 if (object->map()->unused_property_fields() == 0) { |
| 501 // The properties must be extended before we can store the value. | 499 // The properties must be extended before we can store the value. |
| 502 // We jump to a runtime call that extends the properties array. | 500 // We jump to a runtime call that extends the properties array. |
| 503 __ push(receiver_reg); | 501 __ push(receiver_reg); |
| 504 __ li(a2, Operand(transition)); | 502 __ li(a2, Operand(transition)); |
| 505 __ Push(a2, a0); | 503 __ Push(a2, a0); |
| 506 __ TailCallExternalReference( | 504 __ TailCallExternalReference( |
| 507 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), | 505 ExternalReference(IC_Utility(IC::kSharedStoreIC_ExtendStorage), |
| 508 masm->isolate()), | 506 masm->isolate()), |
| 509 3, 1); | 507 3, 1); |
| 510 return; | 508 return; |
| 511 } | 509 } |
| 512 | 510 |
| 513 int index; | 511 // Update the map of the object. |
| 514 if (!transition.is_null()) { | 512 __ li(scratch1, Operand(transition)); |
| 515 // Update the map of the object. | 513 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
| 516 __ li(scratch1, Operand(transition)); | |
| 517 __ sw(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); | |
| 518 | 514 |
| 519 // Update the write barrier for the map field and pass the now unused | 515 // Update the write barrier for the map field and pass the now unused |
| 520 // name_reg as scratch register. | 516 // name_reg as scratch register. |
| 521 __ RecordWriteField(receiver_reg, | 517 __ RecordWriteField(receiver_reg, |
| 522 HeapObject::kMapOffset, | 518 HeapObject::kMapOffset, |
| 523 scratch1, | 519 scratch1, |
| 524 name_reg, | 520 name_reg, |
| 525 kRAHasNotBeenSaved, | 521 kRAHasNotBeenSaved, |
| 526 kDontSaveFPRegs, | 522 kDontSaveFPRegs, |
| 527 OMIT_REMEMBERED_SET, | 523 OMIT_REMEMBERED_SET, |
| 528 OMIT_SMI_CHECK); | 524 OMIT_SMI_CHECK); |
| 529 index = transition->instance_descriptors()->GetFieldIndex( | 525 |
| 530 transition->LastAdded()); | 526 int index = transition->instance_descriptors()->GetFieldIndex( |
| 531 } else { | 527 transition->LastAdded()); |
| 532 index = lookup->GetFieldIndex().field_index(); | |
| 533 } | |
| 534 | 528 |
| 535 // Adjust for the number of properties stored in the object. Even in the | 529 // Adjust for the number of properties stored in the object. Even in the |
| 536 // face of a transition we can use the old map here because the size of the | 530 // face of a transition we can use the old map here because the size of the |
| 537 // object and the number of in-object properties is not going to change. | 531 // object and the number of in-object properties is not going to change. |
| 538 index -= object->map()->inobject_properties(); | 532 index -= object->map()->inobject_properties(); |
| 539 | 533 |
| 534 // TODO(verwaest): Share this code as a code stub. | |
| 540 if (index < 0) { | 535 if (index < 0) { |
| 541 // Set the property straight into the object. | 536 // Set the property straight into the object. |
| 542 int offset = object->map()->instance_size() + (index * kPointerSize); | 537 int offset = object->map()->instance_size() + (index * kPointerSize); |
| 538 __ sw(value_reg, FieldMemOperand(receiver_reg, offset)); | |
| 539 | |
| 540 // Skip updating write barrier if storing a smi. | |
| 541 __ JumpIfSmi(value_reg, &exit); | |
| 542 | |
| 543 // Update the write barrier for the array address. | |
| 544 // Pass the now unused name_reg as a scratch register. | |
| 545 __ mov(name_reg, value_reg); | |
| 546 __ RecordWriteField(receiver_reg, | |
| 547 offset, | |
| 548 name_reg, | |
| 549 scratch1, | |
| 550 kRAHasNotBeenSaved, | |
| 551 kDontSaveFPRegs); | |
| 552 } else { | |
| 553 // Write to the properties array. | |
| 554 int offset = index * kPointerSize + FixedArray::kHeaderSize; | |
| 555 // Get the properties array | |
| 556 __ lw(scratch1, | |
| 557 FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); | |
| 558 __ sw(value_reg, FieldMemOperand(scratch1, offset)); | |
| 559 | |
| 560 // Skip updating write barrier if storing a smi. | |
| 561 __ JumpIfSmi(value_reg, &exit); | |
| 562 | |
| 563 // Update the write barrier for the array address. | |
| 564 // Ok to clobber receiver_reg and name_reg, since we return. | |
| 565 __ mov(name_reg, value_reg); | |
| 566 __ RecordWriteField(scratch1, | |
| 567 offset, | |
| 568 name_reg, | |
| 569 receiver_reg, | |
| 570 kRAHasNotBeenSaved, | |
| 571 kDontSaveFPRegs); | |
| 572 } | |
| 573 | |
| 574 // Return the value (register v0). | |
| 575 ASSERT(value_reg.is(a0)); | |
| 576 __ bind(&exit); | |
| 577 __ mov(v0, a0); | |
| 578 __ Ret(); | |
|
Paul Lind
2013/04/11 23:09:15
Please note (for the future) that this is a small
| |
| 579 } | |
| 580 | |
| 581 | |
| 582 // Generate StoreField code, value is passed in a0 register. | |
| 583 // When leaving generated code after success, the receiver_reg and name_reg | |
| 584 // may be clobbered. Upon branch to miss_label, the receiver and name | |
| 585 // registers have their original values. | |
| 586 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | |
| 587 Handle<JSObject> object, | |
| 588 LookupResult* lookup, | |
| 589 Register receiver_reg, | |
| 590 Register name_reg, | |
| 591 Register value_reg, | |
| 592 Register scratch1, | |
| 593 Register scratch2, | |
| 594 Label* miss_label) { | |
| 595 // a0 : value | |
| 596 Label exit; | |
| 597 | |
| 598 // Check that the map of the object hasn't changed. | |
| 599 __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label, | |
| 600 DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS); | |
| 601 | |
| 602 // Perform global security token check if needed. | |
| 603 if (object->IsJSGlobalProxy()) { | |
| 604 __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label); | |
| 605 } | |
| 606 | |
| 607 // Stub never generated for non-global objects that require access | |
| 608 // checks. | |
| 609 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | |
| 610 | |
| 611 int index = lookup->GetFieldIndex().field_index(); | |
| 612 | |
| 613 // Adjust for the number of properties stored in the object. Even in the | |
| 614 // face of a transition we can use the old map here because the size of the | |
| 615 // object and the number of in-object properties is not going to change. | |
| 616 index -= object->map()->inobject_properties(); | |
| 617 | |
| 618 // TODO(verwaest): Share this code as a code stub. | |
| 619 if (index < 0) { | |
| 620 // Set the property straight into the object. | |
| 621 int offset = object->map()->instance_size() + (index * kPointerSize); | |
| 543 __ sw(value_reg, FieldMemOperand(receiver_reg, offset)); | 622 __ sw(value_reg, FieldMemOperand(receiver_reg, offset)); |
| 544 | 623 |
| 545 // Skip updating write barrier if storing a smi. | 624 // Skip updating write barrier if storing a smi. |
| 546 __ JumpIfSmi(value_reg, &exit); | 625 __ JumpIfSmi(value_reg, &exit); |
| 547 | 626 |
| 548 // Update the write barrier for the array address. | 627 // Update the write barrier for the array address. |
| 549 // Pass the now unused name_reg as a scratch register. | 628 // Pass the now unused name_reg as a scratch register. |
| 550 __ mov(name_reg, value_reg); | 629 __ mov(name_reg, value_reg); |
| 551 __ RecordWriteField(receiver_reg, | 630 __ RecordWriteField(receiver_reg, |
| 552 offset, | 631 offset, |
| (...skipping 3396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3949 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); | 4028 TailCallBuiltin(masm, Builtins::kKeyedStoreIC_Slow); |
| 3950 } | 4029 } |
| 3951 } | 4030 } |
| 3952 | 4031 |
| 3953 | 4032 |
| 3954 #undef __ | 4033 #undef __ |
| 3955 | 4034 |
| 3956 } } // namespace v8::internal | 4035 } } // namespace v8::internal |
| 3957 | 4036 |
| 3958 #endif // V8_TARGET_ARCH_MIPS | 4037 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |