| Index: runtime/vm/assembler_arm.cc
|
| ===================================================================
|
| --- runtime/vm/assembler_arm.cc (revision 42190)
|
| +++ runtime/vm/assembler_arm.cc (working copy)
|
| @@ -2,7 +2,7 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -#include "vm/globals.h"
|
| +#include "vm/globals.h" // NOLINT
|
| #if defined(TARGET_ARCH_ARM)
|
|
|
| #include "vm/assembler.h"
|
| @@ -1641,12 +1641,104 @@
|
| }
|
|
|
|
|
| +Operand Assembler::GetVerifiedMemoryShadow() {
|
| + Operand offset;
|
| + if (!Operand::CanHold(VerifiedMemory::offset(), &offset)) {
|
| + FATAL1("Offset 0x%" Px " not representable", VerifiedMemory::offset());
|
| + }
|
| + return offset;
|
| +}
|
| +
|
| +
|
| +void Assembler::WriteShadowedField(Register base,
|
| + intptr_t offset,
|
| + Register value,
|
| + Condition cond) {
|
| + if (VerifiedMemory::enabled()) {
|
| + ASSERT(base != value);
|
| + Operand shadow(GetVerifiedMemoryShadow());
|
| + add(base, base, shadow, cond);
|
| + str(value, Address(base, offset), cond);
|
| + sub(base, base, shadow, cond);
|
| + }
|
| + str(value, Address(base, offset), cond);
|
| +}
|
| +
|
| +
|
| +void Assembler::WriteShadowedFieldPair(Register base,
|
| + intptr_t offset,
|
| + Register value_even,
|
| + Register value_odd,
|
| + Condition cond) {
|
| + ASSERT(value_odd == value_even + 1);
|
| + if (VerifiedMemory::enabled()) {
|
| + ASSERT(base != value_even);
|
| + ASSERT(base != value_odd);
|
| + Operand shadow(GetVerifiedMemoryShadow());
|
| + add(base, base, shadow, cond);
|
| + strd(value_even, Address(base, offset), cond);
|
| + sub(base, base, shadow, cond);
|
| + }
|
| + strd(value_even, Address(base, offset), cond);
|
| +}
|
| +
|
| +
|
| +Register UseRegister(Register reg, RegList* used) {
|
| + ASSERT(reg != SP);
|
| + ASSERT(reg != PC);
|
| + ASSERT((*used & (1 << reg)) == 0);
|
| + *used |= (1 << reg);
|
| + return reg;
|
| +}
|
| +
|
| +
|
| +Register AllocateRegister(RegList* used) {
|
| + const RegList free = ~*used;
|
| + return (free == 0) ?
|
| + kNoRegister :
|
| + UseRegister(static_cast<Register>(Utils::CountTrailingZeros(free)), used);
|
| +}
|
| +
|
| +
|
| +void Assembler::VerifiedWrite(const Address& address, Register new_value) {
|
| + 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());
|
| + add(base, base, shadow_offset);
|
| + ldr(shadow_value, address);
|
| + cmp(old_value, Operand(shadow_value));
|
| + Label ok;
|
| + b(&ok);
|
| + Stop("Write barrier verification failed");
|
| + Bind(&ok);
|
| + // Write new value.
|
| + str(new_value, address);
|
| + sub(base, base, shadow_offset);
|
| + str(new_value, address);
|
| + PopList(used);
|
| + } else {
|
| + str(new_value, address);
|
| + }
|
| +}
|
| +
|
| +
|
| void Assembler::StoreIntoObject(Register object,
|
| const Address& dest,
|
| Register value,
|
| bool can_value_be_smi) {
|
| ASSERT(object != value);
|
| - str(value, dest);
|
| + VerifiedWrite(dest, value);
|
| Label done;
|
| if (can_value_be_smi) {
|
| StoreIntoObjectFilter(object, value, &done);
|
| @@ -1687,7 +1779,7 @@
|
| void Assembler::StoreIntoObjectNoBarrier(Register object,
|
| const Address& dest,
|
| Register value) {
|
| - str(value, dest);
|
| + VerifiedWrite(dest, value);
|
| #if defined(DEBUG)
|
| Label done;
|
| StoreIntoObjectFilter(object, value, &done);
|
| @@ -1718,7 +1810,7 @@
|
| (value.IsOld() && value.IsNotTemporaryScopedHandle()));
|
| // No store buffer update.
|
| LoadObject(IP, value);
|
| - str(IP, dest);
|
| + VerifiedWrite(dest, IP);
|
| }
|
|
|
|
|
| @@ -1745,9 +1837,9 @@
|
| Bind(&init_loop);
|
| AddImmediate(begin, 2 * kWordSize);
|
| cmp(begin, Operand(end));
|
| - strd(value_even, Address(begin, -2 * kWordSize), LS);
|
| + WriteShadowedFieldPair(begin, -2 * kWordSize, value_even, value_odd, LS);
|
| b(&init_loop, CC);
|
| - str(value_even, Address(begin, -2 * kWordSize), HI);
|
| + WriteShadowedField(begin, -2 * kWordSize, value_even, HI);
|
| #if defined(DEBUG)
|
| Label done;
|
| StoreIntoObjectFilter(object, value_even, &done);
|
| @@ -1760,19 +1852,19 @@
|
|
|
|
|
| void Assembler::InitializeFieldsNoBarrierUnrolled(Register object,
|
| - Register begin,
|
| - intptr_t count,
|
| + Register base,
|
| + intptr_t begin_offset,
|
| + intptr_t end_offset,
|
| Register value_even,
|
| Register value_odd) {
|
| ASSERT(value_odd == value_even + 1);
|
| - intptr_t current_offset = 0;
|
| - const intptr_t end_offset = count * kWordSize;
|
| + intptr_t current_offset = begin_offset;
|
| while (current_offset + kWordSize < end_offset) {
|
| - strd(value_even, Address(begin, current_offset));
|
| + WriteShadowedFieldPair(base, current_offset, value_even, value_odd);
|
| current_offset += 2*kWordSize;
|
| }
|
| while (current_offset < end_offset) {
|
| - str(value_even, Address(begin, current_offset));
|
| + WriteShadowedField(base, current_offset, value_even);
|
| current_offset += kWordSize;
|
| }
|
| #if defined(DEBUG)
|
| @@ -1786,6 +1878,19 @@
|
| }
|
|
|
|
|
| +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");
|
| + Bind(&done);
|
| +#endif // defined(DEBUG)
|
| +}
|
| +
|
| +
|
| void Assembler::LoadClassId(Register result, Register object, Condition cond) {
|
| ASSERT(RawObject::kClassIdTagPos == 16);
|
| ASSERT(RawObject::kClassIdTagSize == 16);
|
|
|