Chromium Code Reviews| Index: runtime/vm/assembler_arm.cc |
| =================================================================== |
| --- runtime/vm/assembler_arm.cc (revision 42713) |
| +++ runtime/vm/assembler_arm.cc (working copy) |
| @@ -1700,36 +1700,74 @@ |
| } |
| -void Assembler::VerifiedWrite(const Address& address, Register new_value) { |
| +void Assembler::VerifiedWrite(const Address& address, |
| + Register new_value, |
| + FieldContent old_content) { |
| +#if defined(DEBUG) |
| + ASSERT(address.mode() == Address::Offset || |
| + address.mode() == Address::NegOffset); |
| + // Allocate temporary registers (and check for register collisions). |
| + RegList used = 0; |
| + UseRegister(new_value, &used); |
| + Register base = UseRegister(address.rn(), &used); |
| + if (address.rm() != kNoRegister) UseRegister(address.rm(), &used); |
|
Ivan Posva
2015/01/16 06:34:48
{
}
koda
2015/01/16 16:24:32
Done.
|
| + Register old_value = AllocateRegister(&used); |
| + Register temp = AllocateRegister(&used); |
| + PushList(used); |
| + ldr(old_value, address); |
| + // First check that 'old_value' contains 'old_content'. |
| + // Smi test. |
| + tst(old_value, Operand(kHeapObjectTag)); |
| + Label ok; |
| + switch (old_content) { |
| + case kOnlySmi: |
| + b(&ok, EQ); // Smi is OK. |
| + Stop("Expected smi."); |
| + break; |
| + case kHeapObjectOrSmi: |
| + b(&ok, EQ); // Smi is OK. |
| + // Non-smi case: Verify object pointer is word-aligned when untagged. |
| + COMPILE_ASSERT(kHeapObjectTag == 1); |
| + tst(old_value, Operand((kWordSize - 1) - kHeapObjectTag)); |
| + b(&ok, EQ); |
| + Stop("Expected heap object or Smi"); |
| + break; |
| + case kEmptyOrSmiOrNull: |
| + b(&ok, EQ); // Smi is OK. |
| + // Non-smi case: Check for the special zap word or null. |
| + // Note: Cannot use CompareImmediate, since IP may be in use. |
| + LoadImmediate(temp, Heap::kZap32Bits); |
| + cmp(old_value, Operand(temp)); |
| + b(&ok, EQ); |
| + LoadImmediate(temp, reinterpret_cast<uint32_t>(Object::null())); |
| + cmp(old_value, Operand(temp)); |
| + b(&ok, EQ); |
| + Stop("Expected zapped, Smi or null"); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + Bind(&ok); |
| if (VerifiedMemory::enabled()) { |
| - ASSERT(address.mode() == Address::Offset || |
| - address.mode() == Address::NegOffset); |
| - // Allocate temporary registers (and check for register collisions). |
| - RegList used = 0; |
| - UseRegister(new_value, &used); |
| - Register base = UseRegister(address.rn(), &used); |
| - if (address.rm() != kNoRegister) UseRegister(address.rm(), &used); |
| - Register old_value = AllocateRegister(&used); |
| - Register shadow_value = AllocateRegister(&used); |
| - PushList(used); |
| - // Verify old value. |
| - ldr(old_value, address); |
| Operand shadow_offset(GetVerifiedMemoryShadow()); |
| + // Adjust the address to shadow. |
| add(base, base, shadow_offset); |
| - ldr(shadow_value, address); |
| - cmp(old_value, Operand(shadow_value)); |
| - Label ok; |
| - b(&ok); |
| + ldr(temp, address); |
| + cmp(old_value, Operand(temp)); |
| + Label match; |
| + b(&match, EQ); |
| Stop("Write barrier verification failed"); |
| - Bind(&ok); |
| - // Write new value. |
| + Bind(&match); |
| + // Write new value in shadow. |
| str(new_value, address); |
| + // Restore original address. |
| sub(base, base, shadow_offset); |
| - str(new_value, address); |
| - PopList(used); |
| - } else { |
| - str(new_value, address); |
| } |
| + str(new_value, address); |
| + PopList(used); |
| +#else |
| + str(new_value, address); |
| +#endif // DEBUG |
| } |
| @@ -1738,7 +1776,7 @@ |
| Register value, |
| bool can_value_be_smi) { |
| ASSERT(object != value); |
| - VerifiedWrite(dest, value); |
| + VerifiedWrite(dest, value, kHeapObjectOrSmi); |
| Label done; |
| if (can_value_be_smi) { |
| StoreIntoObjectFilter(object, value, &done); |
| @@ -1778,8 +1816,9 @@ |
| void Assembler::StoreIntoObjectNoBarrier(Register object, |
| const Address& dest, |
| - Register value) { |
| - VerifiedWrite(dest, value); |
| + Register value, |
| + FieldContent old_content) { |
| + VerifiedWrite(dest, value, old_content); |
| #if defined(DEBUG) |
| Label done; |
| StoreIntoObjectFilter(object, value, &done); |
| @@ -1792,13 +1831,15 @@ |
| void Assembler::StoreIntoObjectNoBarrierOffset(Register object, |
| int32_t offset, |
| - Register value) { |
| + Register value, |
| + FieldContent old_content) { |
| int32_t ignored = 0; |
| if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) { |
| - StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); |
| + StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, |
| + old_content); |
| } else { |
| AddImmediate(IP, object, offset - kHeapObjectTag); |
| - StoreIntoObjectNoBarrier(object, Address(IP), value); |
| + StoreIntoObjectNoBarrier(object, Address(IP), value, old_content); |
| } |
| } |
| @@ -1805,24 +1846,27 @@ |
| void Assembler::StoreIntoObjectNoBarrier(Register object, |
| const Address& dest, |
| - const Object& value) { |
| + const Object& value, |
| + FieldContent old_content) { |
| ASSERT(value.IsSmi() || value.InVMHeap() || |
| (value.IsOld() && value.IsNotTemporaryScopedHandle())); |
| // No store buffer update. |
| LoadObject(IP, value); |
| - VerifiedWrite(dest, IP); |
| + VerifiedWrite(dest, IP, old_content); |
| } |
| void Assembler::StoreIntoObjectNoBarrierOffset(Register object, |
| int32_t offset, |
| - const Object& value) { |
| + const Object& value, |
| + FieldContent old_content) { |
| int32_t ignored = 0; |
| if (Address::CanHoldStoreOffset(kWord, offset - kHeapObjectTag, &ignored)) { |
| - StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); |
| + StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value, |
| + old_content); |
| } else { |
| AddImmediate(IP, object, offset - kHeapObjectTag); |
| - StoreIntoObjectNoBarrier(object, Address(IP), value); |
| + StoreIntoObjectNoBarrier(object, Address(IP), value, old_content); |
| } |
| } |
| @@ -1879,15 +1923,14 @@ |
| void Assembler::StoreIntoSmiField(const Address& dest, Register value) { |
| - // TODO(koda): Verify previous value was Smi. |
| - VerifiedWrite(dest, value); |
| #if defined(DEBUG) |
| Label done; |
| tst(value, Operand(kHeapObjectTag)); |
| b(&done, EQ); |
| - Stop("Smi expected"); |
| + Stop("New value must be Smi."); |
| Bind(&done); |
| #endif // defined(DEBUG) |
| + VerifiedWrite(dest, value, kOnlySmi); |
| } |